From: Maxious Date: Wed, 02 Jan 2013 03:44:09 +0000 Subject: tgids table X-Git-Url: https://maxious.lambdacomplex.org/git/?p=scannr.git&a=commitdiff&h=ade04528d6af20ebe38f62ff7146c048c2732f0a --- tgids table --- --- /dev/null +++ b/.gitattributes @@ -1,1 +1,1 @@ - +* text=auto --- /dev/null +++ b/.gitignore @@ -1,1 +1,19 @@ +*.wav +*.pyc +/nbproject/private/ +/output.txt +bin +gen +target +.settings +.classpath +.project +*.keystore +*.swp +*.orig +*.log +*.properties +seed.txt +map.txt + --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,7 @@ [submodule "pynma"] path = pynma url = git://github.com/uskr/pynma.git +[submodule "js/flotr2"] + path = js/flotr2 + url = https://github.com/HumbleSoftware/Flotr2.git --- /dev/null +++ b/.htaccess @@ -1,1 +1,541 @@ - +# Apache configuration file +# httpd.apache.org/docs/2.2/mod/quickreference.html + +# Note .htaccess files are an overhead, this logic should be in your Apache +# config if possible: httpd.apache.org/docs/2.2/howto/htaccess.html + +# Techniques in here adapted from all over, including: +# Kroc Camen: camendesign.com/.htaccess +# perishablepress.com/press/2006/01/10/stupid-htaccess-tricks/ +# Sample .htaccess file of CMS MODx: modxcms.com + + +# ---------------------------------------------------------------------- +# Better website experience for IE users +# ---------------------------------------------------------------------- + +# Force the latest IE version, in various cases when it may fall back to IE7 mode +# github.com/rails/rails/commit/123eb25#commitcomment-118920 +# Use ChromeFrame if it's installed for a better experience for the poor IE folk + + + Header set X-UA-Compatible "IE=Edge,chrome=1" + # mod_headers can't match by content-type, but we don't want to send this header on *everything*... + + Header unset X-UA-Compatible + + + + +# ---------------------------------------------------------------------- +# Cross-domain AJAX requests +# ---------------------------------------------------------------------- + +# Serve cross-domain Ajax requests, disabled by default. +# enable-cors.org +# code.google.com/p/html5security/wiki/CrossOriginRequestSecurity + +# +# Header set Access-Control-Allow-Origin "*" +# + + +# ---------------------------------------------------------------------- +# CORS-enabled images (@crossorigin) +# ---------------------------------------------------------------------- + +# Send CORS headers if browsers request them; enabled by default for images. +# developer.mozilla.org/en/CORS_Enabled_Image +# blog.chromium.org/2011/07/using-cross-domain-images-in-webgl-and.html +# hacks.mozilla.org/2011/11/using-cors-to-load-webgl-textures-from-cross-domain-images/ +# wiki.mozilla.org/Security/Reviews/crossoriginAttribute + + + + # mod_headers, y u no match by Content-Type?! + + SetEnvIf Origin ":" IS_CORS + Header set Access-Control-Allow-Origin "*" env=IS_CORS + + + + + +# ---------------------------------------------------------------------- +# Webfont access +# ---------------------------------------------------------------------- + +# Allow access from all domains for webfonts. +# Alternatively you could only whitelist your +# subdomains like "subdomain.example.com". + + + + Header set Access-Control-Allow-Origin "*" + + + + +# ---------------------------------------------------------------------- +# Proper MIME type for all files +# ---------------------------------------------------------------------- + +# JavaScript +# Normalize to standard type (it's sniffed in IE anyways) +# tools.ietf.org/html/rfc4329#section-7.2 +AddType application/javascript js jsonp +AddType application/json json + +# Audio +AddType audio/ogg oga ogg +AddType audio/mp4 m4a f4a f4b + +# Video +AddType video/ogg ogv +AddType video/mp4 mp4 m4v f4v f4p +AddType video/webm webm +AddType video/x-flv flv + +# SVG +# Required for svg webfonts on iPad +# twitter.com/FontSquirrel/status/14855840545 +AddType image/svg+xml svg svgz +AddEncoding gzip svgz + +# Webfonts +AddType application/vnd.ms-fontobject eot +AddType application/x-font-ttf ttf ttc +AddType font/opentype otf +AddType application/x-font-woff woff + +# Assorted types +AddType image/x-icon ico +AddType image/webp webp +AddType text/cache-manifest appcache manifest +AddType text/x-component htc +AddType application/xml rss atom xml rdf +AddType application/x-chrome-extension crx +AddType application/x-opera-extension oex +AddType application/x-xpinstall xpi +AddType application/octet-stream safariextz +AddType application/x-web-app-manifest+json webapp +AddType text/x-vcard vcf +AddType application/x-shockwave-flash swf +AddType text/vtt vtt + + +# ---------------------------------------------------------------------- +# Allow concatenation from within specific js and css files +# ---------------------------------------------------------------------- + +# e.g. Inside of script.combined.js you could have +# +# +# and they would be included into this single file. + +# This is not in use in the boilerplate as it stands. You may +# choose to use this technique if you do not have a build process. + +# +# Options +Includes +# AddOutputFilterByType INCLUDES application/javascript application/json +# SetOutputFilter INCLUDES +# + +# +# Options +Includes +# AddOutputFilterByType INCLUDES text/css +# SetOutputFilter INCLUDES +# + + +# ---------------------------------------------------------------------- +# Gzip compression +# ---------------------------------------------------------------------- + + + + # Force deflate for mangled headers developer.yahoo.com/blogs/ydn/posts/2010/12/pushing-beyond-gzipping/ + + + SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding + RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding + + + + # Compress all output labeled with one of the following MIME-types + + AddOutputFilterByType DEFLATE application/atom+xml \ + application/javascript \ + application/json \ + application/rss+xml \ + application/vnd.ms-fontobject \ + application/x-font-ttf \ + application/xhtml+xml \ + application/xml \ + font/opentype \ + image/svg+xml \ + image/x-icon \ + text/css \ + text/html \ + text/plain \ + text/x-component \ + text/xml + + + + + +# ---------------------------------------------------------------------- +# Expires headers (for better cache control) +# ---------------------------------------------------------------------- + +# These are pretty far-future expires headers. +# They assume you control versioning with filename-based cache busting +# Additionally, consider that outdated proxies may miscache +# www.stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring/ + +# If you don't use filenames to version, lower the CSS and JS to something like +# "access plus 1 week". + + + ExpiresActive on + +# Perhaps better to whitelist expires rules? Perhaps. + ExpiresDefault "access plus 1 month" + +# cache.appcache needs re-requests in FF 3.6 (thanks Remy ~Introducing HTML5) + ExpiresByType text/cache-manifest "access plus 0 seconds" + +# Your document html + ExpiresByType text/html "access plus 0 seconds" + +# Data + ExpiresByType text/xml "access plus 0 seconds" + ExpiresByType application/xml "access plus 0 seconds" + ExpiresByType application/json "access plus 0 seconds" + +# Feed + ExpiresByType application/rss+xml "access plus 1 hour" + ExpiresByType application/atom+xml "access plus 1 hour" + +# Favicon (cannot be renamed) + ExpiresByType image/x-icon "access plus 1 week" + +# Media: images, video, audio + ExpiresByType image/gif "access plus 1 month" + ExpiresByType image/png "access plus 1 month" + ExpiresByType image/jpeg "access plus 1 month" + ExpiresByType video/ogg "access plus 1 month" + ExpiresByType audio/ogg "access plus 1 month" + ExpiresByType video/mp4 "access plus 1 month" + ExpiresByType video/webm "access plus 1 month" + +# HTC files (css3pie) + ExpiresByType text/x-component "access plus 1 month" + +# Webfonts + ExpiresByType application/x-font-ttf "access plus 1 month" + ExpiresByType font/opentype "access plus 1 month" + ExpiresByType application/x-font-woff "access plus 1 month" + ExpiresByType image/svg+xml "access plus 1 month" + ExpiresByType application/vnd.ms-fontobject "access plus 1 month" + +# CSS and JavaScript + ExpiresByType text/css "access plus 1 year" + ExpiresByType application/javascript "access plus 1 year" + + + + +# ---------------------------------------------------------------------- +# Prevent mobile network providers from modifying your site +# ---------------------------------------------------------------------- + +# The following header prevents modification of your code over 3G on some +# European providers. +# This is the official 'bypass' suggested by O2 in the UK. + +# +# Header set Cache-Control "no-transform" +# + + +# ---------------------------------------------------------------------- +# ETag removal +# ---------------------------------------------------------------------- + +# FileETag None is not enough for every server. + + Header unset ETag + + +# Since we're sending far-future expires, we don't need ETags for +# static content. +# developer.yahoo.com/performance/rules.html#etags +FileETag None + + +# ---------------------------------------------------------------------- +# Stop screen flicker in IE on CSS rollovers +# ---------------------------------------------------------------------- + +# The following directives stop screen flicker in IE on CSS rollovers - in +# combination with the "ExpiresByType" rules for images (see above). + +# BrowserMatch "MSIE" brokenvary=1 +# BrowserMatch "Mozilla/4.[0-9]{2}" brokenvary=1 +# BrowserMatch "Opera" !brokenvary +# SetEnvIf brokenvary 1 force-no-vary + + +# ---------------------------------------------------------------------- +# Set Keep-Alive Header +# ---------------------------------------------------------------------- + +# Keep-Alive allows the server to send multiple requests through one +# TCP-connection. Be aware of possible disadvantages of this setting. Turn on +# if you serve a lot of static content. + +# +# Header set Connection Keep-Alive +# + + +# ---------------------------------------------------------------------- +# Cookie setting from iframes +# ---------------------------------------------------------------------- + +# Allow cookies to be set from iframes (for IE only) +# If needed, specify a path or regex in the Location directive. + +# +# Header set P3P "policyref=\"/w3c/p3p.xml\", CP=\"IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT\"" +# + + +# ---------------------------------------------------------------------- +# Start rewrite engine +# ---------------------------------------------------------------------- + +# Turning on the rewrite engine is necessary for the following rules and +# features. FollowSymLinks must be enabled for this to work. + +# Some cloud hosting services require RewriteBase to be set: goo.gl/HOcPN +# If using the h5bp in a subdirectory, use `RewriteBase /foo` instead where +# 'foo' is your directory. + +# If your web host doesn't allow the FollowSymlinks option, you may need to +# comment it out and use `Options +SymLinksOfOwnerMatch`, but be aware of the +# performance impact: http://goo.gl/Mluzd + + + Options +FollowSymlinks +# Options +SymLinksIfOwnerMatch + RewriteEngine On +# RewriteBase / + + + +# ---------------------------------------------------------------------- +# Suppress or force the "www." at the beginning of URLs +# ---------------------------------------------------------------------- + +# The same content should never be available under two different URLs - +# especially not with and without "www." at the beginning, since this can cause +# SEO problems (duplicate content). That's why you should choose one of the +# alternatives and redirect the other one. + +# By default option 1 (no "www.") is activated. +# no-www.org/faq.php?q=class_b + +# If you'd prefer to use option 2, just comment out all option 1 lines +# and uncomment option 2. + +# IMPORTANT: NEVER USE BOTH RULES AT THE SAME TIME! + +# ---------------------------------------------------------------------- + +# Option 1: +# Rewrite "www.example.com -> example.com". + + + RewriteCond %{HTTPS} !=on + RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC] + RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L] + + +# ---------------------------------------------------------------------- + +# Option 2: +# Rewrite "example.com -> www.example.com". +# Be aware that the following rule might not be a good idea if you use "real" +# subdomains for certain parts of your website. + +# +# RewriteCond %{HTTPS} !=on +# RewriteCond %{HTTP_HOST} !^www\..+$ [NC] +# RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L] +# + + +# ---------------------------------------------------------------------- +# Built-in filename-based cache busting +# ---------------------------------------------------------------------- + +# If you're not using the build script to manage your filename version revving, +# you might want to consider enabling this, which will route requests for +# /css/style.20110203.css to /css/style.css + +# To understand why this is important and a better idea than all.css?v1231, +# read: github.com/h5bp/html5-boilerplate/wiki/cachebusting + +# +# RewriteCond %{REQUEST_FILENAME} !-f +# RewriteCond %{REQUEST_FILENAME} !-d +# RewriteRule ^(.+)\.(\d+)\.(js|css|png|jpg|gif)$ $1.$3 [L] +# + + +# ---------------------------------------------------------------------- +# Prevent SSL cert warnings +# ---------------------------------------------------------------------- + +# Rewrite secure requests properly to prevent SSL cert warnings, e.g. prevent +# https://www.example.com when your cert only allows https://secure.example.com + +# +# RewriteCond %{SERVER_PORT} !^443 +# RewriteRule ^ https://example-domain-please-change-me.com%{REQUEST_URI} [R=301,L] +# + + +# ---------------------------------------------------------------------- +# Prevent 404 errors for non-existing redirected folders +# ---------------------------------------------------------------------- + +# without -MultiViews, Apache will give a 404 for a rewrite if a folder of the +# same name does not exist. +# webmasterworld.com/apache/3808792.htm + +Options -MultiViews + + +# ---------------------------------------------------------------------- +# Custom 404 page +# ---------------------------------------------------------------------- + +# You can add custom pages to handle 500 or 403 pretty easily, if you like. +# If you are hosting your site in subdirectory, adjust this accordingly +# e.g. ErrorDocument 404 /subdir/404.html +ErrorDocument 404 /404.html + + +# ---------------------------------------------------------------------- +# UTF-8 encoding +# ---------------------------------------------------------------------- + +# Use UTF-8 encoding for anything served text/plain or text/html +AddDefaultCharset utf-8 + +# Force UTF-8 for a number of file formats +AddCharset utf-8 .atom .css .js .json .rss .vtt .xml + + +# ---------------------------------------------------------------------- +# A little more security +# ---------------------------------------------------------------------- + +# To avoid displaying the exact version number of Apache being used, add the +# following to httpd.conf (it will not work in .htaccess): +# ServerTokens Prod + +# "-Indexes" will have Apache block users from browsing folders without a +# default document Usually you should leave this activated, because you +# shouldn't allow everybody to surf through every folder on your server (which +# includes rather private places like CMS system folders). + + Options -Indexes + + +# Block access to "hidden" directories or files whose names begin with a +# period. This includes directories used by version control systems such as +# Subversion or Git. + + RewriteCond %{SCRIPT_FILENAME} -d [OR] + RewriteCond %{SCRIPT_FILENAME} -f + RewriteRule "(^|/)\." - [F] + + +# Block access to backup and source files. These files may be left by some +# text/html editors and pose a great security danger, when anyone can access +# them. + + Order allow,deny + Deny from all + Satisfy All + + +# If your server is not already configured as such, the following directive +# should be uncommented in order to set PHP's register_globals option to OFF. +# This closes a major security hole that is abused by most XSS (cross-site +# scripting) attacks. For more information: http://php.net/register_globals +# +# IF REGISTER_GLOBALS DIRECTIVE CAUSES 500 INTERNAL SERVER ERRORS: +# +# Your server does not allow PHP directives to be set via .htaccess. In that +# case you must make this change in your php.ini file instead. If you are +# using a commercial web host, contact the administrators for assistance in +# doing this. Not all servers allow local php.ini files, and they should +# include all PHP configurations (not just this one), or you will effectively +# reset everything to PHP defaults. Consult www.php.net for more detailed +# information about setting PHP directives. + +# php_flag register_globals Off + +# Rename session cookie to something else, than PHPSESSID +# php_value session.name sid + +# Disable magic quotes (This feature has been DEPRECATED as of PHP 5.3.0 and REMOVED as of PHP 5.4.0.) +# php_flag magic_quotes_gpc Off + +# Do not show you are using PHP +# Note: Move this line to php.ini since it won't work in .htaccess +# php_flag expose_php Off + +# Level of log detail - log all errors +# php_value error_reporting -1 + +# Write errors to log file +# php_flag log_errors On + +# Do not display errors in browser (production - Off, development - On) +# php_flag display_errors Off + +# Do not display startup errors (production - Off, development - On) +# php_flag display_startup_errors Off + +# Format errors in plain text +# Note: Leave this setting 'On' for xdebug's var_dump() output +# php_flag html_errors Off + +# Show multiple occurrence of error +# php_flag ignore_repeated_errors Off + +# Show same errors from different sources +# php_flag ignore_repeated_source Off + +# Size limit for error messages +# php_value log_errors_max_len 1024 + +# Don't precede error with string (doesn't accept empty string, use whitespace if you need) +# php_value error_prepend_string " " + +# Don't prepend to error (doesn't accept empty string, use whitespace if you need) +# php_value error_append_string " " + +# Increase cookie security + + php_value session.cookie_httponly true + + --- /dev/null +++ b/.idea/.name @@ -1,1 +1,1 @@ - +scannr --- /dev/null +++ b/.idea/compiler.xml @@ -1,1 +1,24 @@ + + + + + + --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -1,1 +1,5 @@ - + + + + + --- /dev/null +++ b/.idea/dictionaries/Madoka.xml @@ -1,1 +1,10 @@ - + + + + tgid + timefrom + timeto + tzoffset + + + --- /dev/null +++ b/.idea/encodings.xml @@ -1,1 +1,6 @@ + + + + + --- /dev/null +++ b/.idea/misc.xml @@ -1,1 +1,9 @@ + + + + jar:file:\C:\Program Files (x86)\JetBrains\PhpStorm 5.0.2\lib\webide.jar!\resources\html5-schema\html5.rnc + + + + --- /dev/null +++ b/.idea/modules.xml @@ -1,1 +1,10 @@ + + + + + + + + + --- /dev/null +++ b/.idea/scannr.iml @@ -1,1 +1,15 @@ + + + + + + + + + + + + + + --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -1,1 +1,5 @@ - + + + + --- /dev/null +++ b/.idea/uiDesigner.xml @@ -1,1 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + --- /dev/null +++ b/.idea/vcs.xml @@ -1,1 +1,10 @@ + + + + + + + + + --- /dev/null +++ b/.idea/workspace.xml @@ -1,1 +1,497 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1350026709905 + 1350026709905 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + --- /dev/null +++ b/404.html @@ -1,1 +1,160 @@ + + + + + Page Not Found :( + + + +
+

Not found :(

+ +

Sorry, but the page you were trying to view does not exist.

+ +

It looks like this was the result of either:

+ + + +
+ + + --- /dev/null +++ b/CHANGELOG.md @@ -1,1 +1,88 @@ +### HEAD +### 4.0.0 (28 August, 2012) + +* Improve the Apache compression configuration ([#1012](https://github.com/h5bp/html5-boilerplate/issues/1012), [#1173](https://github.com/h5bp/html5-boilerplate/issues/1173)). +* Add a HiDPI example media query ([#1127](https://github.com/h5bp/html5-boilerplate/issues/1127)). +* Add bundled docs ([#1154](https://github.com/h5bp/html5-boilerplate/issues/1154)). +* Add MIT license ([#1139](https://github.com/h5bp/html5-boilerplate/issues/1139)). +* Update to Normalize.css 1.0.1. +* Separate Normalize.css from the rest of the CSS ([#1160](https://github.com/h5bp/html5-boilerplate/issues/1160)). +* Improve `console.log` protection ([#1107](https://github.com/h5bp/html5-boilerplate/issues/1107)). +* Replace hot pink text selection color with a neutral color. +* Change image replacement technique ([#1149](https://github.com/h5bp/html5-boilerplate/issues/1149)). +* Code format and consistency changes ([#1112](https://github.com/h5bp/html5-boilerplate/issues/1112)). +* Rename CSS file and rename JS files and subdirectories. +* Update to jQuery 1.8 ([#1161](https://github.com/h5bp/html5-boilerplate/issues/1161)). +* Update to Modernizr 2.6.1 ([#1086](https://github.com/h5bp/html5-boilerplate/issues/1086)). +* Remove uncompressed jQuery ([#1153](https://github.com/h5bp/html5-boilerplate/issues/1153)). +* Remove superfluous inline comments ([#1150](https://github.com/h5bp/html5-boilerplate/issues/1150)). + +### 3.0.2 (February 19, 2012) + +* Update to Modernizr 2.5.3. + +### 3.0.1 (February 08, 2012). + +* Update to Modernizr 2.5.2 (includes html5shiv 3.3). + +### 3.0.0 (February 06, 2012) + +* Improvements to `.htaccess`. +* Improve 404 design. +* Simplify JS folder structure. +* Change `html` IE class names changed to target ranges rather than specific versions of IE. +* Update CSS to include latest normalize.css changes and better typographic defaults ([#825](https://github.com/h5bp/html5-boilerplate/issues/825)). +* Update to Modernizr 2.5 (includes yepnope 1.5 and html5shiv 3.2). +* Update to jQuery 1.7.1. +* Revert to async snippet for the Google Analytics script. +* Remove the ant build script ([#826](https://github.com/h5bp/html5-boilerplate/issues/826)). +* Remove Respond.js ([#816](https://github.com/h5bp/html5-boilerplate/issues/816)). +* Remove the `demo/` directory ([#808](https://github.com/h5bp/html5-boilerplate/issues/808)). +* Remove the `test/` directory ([#808](https://github.com/h5bp/html5-boilerplate/issues/808)). +* Remove Google Chrome Frame script for IE6 users; replace with links to Chrome Frame and options for alternative browsers. +* Remove `initial-scale=1` from the viewport `meta` ([#824](https://github.com/h5bp/html5-boilerplate/issues/824)). +* Remove `defer` from all scripts to avoid legacy IE bugs. +* Remove explicit Site Speed tracking for Google Analytics. It's now enabled by default. + +### 2.0.0 (August 10, 2011) + +* Change starting CSS to be based on normalize.css instead of reset.css ([#500](https://github.com/h5bp/html5-boilerplate/issues/500)). +* Add Respond.js media query polyfill. +* Add Google Chrome Frame script prompt for IE6 users. +* Simplify the `html` conditional comments for modern browsers and add an `oldie` class. +* Update clearfix to use "micro clearfix". +* Add placeholder CSS MQs for mobile-first approach. +* Add `textarea { resize: vertical; }` to only allow vertical resizing. +* Add `img { max-width: 100%; }` to the print styles; prevents images being truncated. +* Add Site Speed tracking for Google Analytics. +* Update to jQuery 1.6.2 (and use minified by default). +* Update to Modernizr 2.0 Complete, Production minified (includes yepnope, html5shiv, and Respond.js). +* Use `Modernizr.load()` to load the Google Analytics script. +* Much faster build process. +* Add build script options for CSSLint, JSLint, JSHint tools. +* Build script now compresses all images in subfolders. +* Build script now versions files by SHA hash. +* Many `.htaccess` improvements including: disable directory browsing, improved support for all versions of Apache, more robust and extensive HTTP compression rules. +* Remove `handheld.css` as it has very poor device support. +* Remove touch-icon `link` elements from the HTML and include improved touch-icon support. +* Remove the cache-busting query paramaters from files references in the HTML. +* Remove IE6 PNGFix. + +### 1.0.0 (March 21, 2011) + +* Rewrite build script to make it more customizable and flexible. +* Add a humans.txt. +* Numerous `.htaccess` improvements (including inline documentation). +* Move the alternative server configurations to the H5BP server configs repo. +* Use a protocol-relative url to reference jQuery and prevent mixed content warnings. +* Optimize the Google Analytics snippet. +* Use Eric Meyer's recent CSS reset update and the HTML5 Doctor reset. +* More robust `sub`/`sup` CSS styles. +* Add keyboard `.focusable` helper class that extends `.visuallyhidden`. +* Print styles no longer print hash or JavaScript links. +* Add a print reset for IE's proprietary filters. +* Remove IE9-specific conditional class on the `html` element. +* Remove margins from lists within `nav` elements. +* Remove YUI profiling. + --- /dev/null +++ b/LICENSE.md @@ -1,1 +1,20 @@ +Copyright (c) HTML5 Boilerplate +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + --- /dev/null +++ b/README.md @@ -1,1 +1,64 @@ +# [HTML5 Boilerplate](http://html5boilerplate.com) +HTML5 Boilerplate is a professional front-end template for building fast, +robust, and adaptable web apps or sites. + +This project is the product of many years of iterative development and combined +community knowledge. It does not impose a specific development philosophy or +framework, so you're free to architect your code in the way that you want. + +* Source: [https://github.com/h5bp/html5-boilerplate](https://github.com/h5bp/html5-boilerplate) +* Homepage: [http://html5boilerplate.com](http://html5boilerplate.com) +* Twitter: [@h5bp](http://twitter.com/h5bp) + + +## Quick start + +Choose one of the following options: + +1. Download the latest stable release from + [html5boilerplate.com](http://html5boilerplate.com/) or a custom build from + [Initializr](http://www.initializr.com). +2. Clone the git repo — `git clone + https://github.com/h5bp/html5-boilerplate.git` - and checkout the tagged + release you'd like to use. + + +## Features + +* HTML5 ready. Use the new elements with confidence. +* Cross-browser compatible (Chrome, Opera, Safari, Firefox 3.6+, IE6+). +* Designed with progressive enhancement in mind. +* Includes [Normalize.css](http://necolas.github.com/normalize.css/) for CSS + normalizations and common bug fixes. +* The latest [jQuery](http://jquery.com/) via CDN, with a local fallback. +* The latest [Modernizr](http://modernizr.com/) build for feature detection. +* IE-specific classes for easier cross-browser control. +* Placeholder CSS Media Queries. +* Useful CSS helpers. +* Default print CSS, performance optimized. +* Protection against any stray `console.log` causing JavaScript errors in + IE6/7. +* An optimized Google Analytics snippet. +* Apache server caching, compression, and other configuration defaults for + Grade-A performance. +* Cross-domain Ajax and Flash. +* "Delete-key friendly." Easy to strip out parts you don't need. +* Extensive inline and accompanying documentation. + + +## Documentation + +Take a look at the [documentation table of +contents](/h5bp/html5-boilerplate/blob/master/doc/README.md). This +documentation is bundled with the project, which makes it readily available for +offline reading and provides a useful starting point for any documentation +you want to write about your project. + + +## Contributing + +Anyone and everyone is welcome to +[contribute](/h5bp/html5-boilerplate/blob/master/doc/contribute.md). Hundreds +of developers have helped make the HTML5 Boilerplate what it is today. + --- /dev/null +++ b/README.txt @@ -1,1 +1,1 @@ - +ffmpeg from http://ffmpeg.zeranoe.com/builds/ --- /dev/null +++ b/calllog.php @@ -1,1 +1,21 @@ +prepare('select * from recordings + order by call_timestamp desc limit 1000'); +$sth->execute(Array()); + +$row = 0; +echo ""; +foreach ($sth->fetchAll() as $data) { + + + echo ""; + for ($c = 0; $c < count($data); $c++) { + echo '\n"; + } + echo ""; +} +$row++; +echo "
' . $data[$c] . "
"; + --- /dev/null +++ b/calls.json.php @@ -1,1 +1,105 @@ +prepare('select tgid, min(call_timestamp) as time, count(*), min(length), max(length), avg(length), stddev(length) from recordings +where call_timestamp between to_timestamp(?) and to_timestamp(?) + group by tgid, date_trunc(\'hour\', call_timestamp) order by time'); + $sth->execute(Array($timeFrom, $timeTo)); + return $sth->fetchAll(PDO::FETCH_ASSOC); + + +} + +function getTGIDValuesByDay($TGID, $dayFrom, $dayTo) +{ + global $conn; + $sth = $conn->prepare('select min(time) as time, min(value), max(value), avg(value), stddev(value) from sensor_values where sensor_id = ? + group by sensor_id, date_trunc(\'day\', time) order by time'); + + $sth->execute(Array($TGID)); + return $sth->fetchAll(PDO::FETCH_ASSOC); +} +function getTGIDDataYears($TGID, $timeFrom, $timeTo) +{ + global $conn; + $sth = $conn->prepare("select distinct extract('year' from call_timestamp) as year from recordings where tgid = ? order by year"); + + $sth->execute(Array($TGID)); + return $sth->fetchAll(PDO::FETCH_ASSOC); +} + +function getTGIDDataMonths($TGID, $timeFrom, $timeTo) +{ + global $conn; + $sth = $conn->prepare("select distinct extract('month' from call_timestamp) as month, extract('year' from call_timestamp) as year from recordings where tgid = ? order by year, month"); + + $sth->execute(Array($TGID)); + return $sth->fetchAll(PDO::FETCH_ASSOC); +} + +function getTGIDDataDays($TGID, $timeFrom, $timeTo) +{ + global $conn; + $sth = $conn->prepare("select distinct extract('day' from call_timestamp) as day, extract('month' from call_timestamp) as month, extract('year' from call_timestamp) as year from recordings where tgid = ? order by year,month,day"); + + + $sth->execute(Array($TGID)); + return $sth->fetchAll(PDO::FETCH_ASSOC); +} +$action = (isset($_REQUEST['action']) ? $_REQUEST['action'] : ''); +$TGID = (isset($_REQUEST['tgid']) ? $_REQUEST['tgid'] : ''); +$timefrom = (isset($_REQUEST['from']) ? $_REQUEST['from'] : ''); +$timeto = (isset($_REQUEST['to']) ? $_REQUEST['to'] : ''); + +if ($action == "data") { +$sth = $conn->prepare('select * from recordings + order by call_timestamp desc limit 100'); + +$sth->execute(Array()); + +echo json_encode ($sth->fetchAll(PDO::FETCH_ASSOC)); +} +if ($action == "data_description") { + $timefrom = strtotime($timefrom); + $timeto = strtotime($timeto); + $years = getTGIDDataYears($TGID, $timefrom, $timeto); + + $months = getTGIDDataMonths($TGID, $timefrom, $timeto); + $days = getTGIDDataDays($TGID, $timefrom, $timeto); + + echo json_encode(Array("years" => $years, "months" => $months, "days" => $days + )); +} + + +if (strpos($action, "graph") !== false) { + $values = getTGIDValuesByHour($TGID, $timefrom, $timeto); + $label = $TGID; + $data = Array(); + $tzoffset = get_timezone_offset("UTC"); + foreach ($values as $value) { + if ($action == "graphlength") { + $data[$value['tgid']][] = Array((strtotime($value['time']) + $tzoffset) * 1000, intval($value['avg'])); + } else if ($action == "graphcount") { + $data[$value['tgid']][] = Array((strtotime($value['time']) + $tzoffset) * 1000, intval($value['count'])); + } + } + echo json_encode(Array("label" => $label, "data" => $data, + "previous" => Array( + "from" => $timefrom - (24 * 60 * 60), + "to" => $timefrom) + , + "next" => Array( + "to" => $timeto + (24 * 60 * 60), + "from" => $timeto) + ) + ); +} + + + +?> + --- /dev/null +++ b/common.inc.php @@ -1,1 +1,103 @@ +setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); +} catch (PDOException $e) { + die('Unable to connect to database server.'); +} +catch (Exception $e) { + die('Unknown error in ' . __FILE__ . '.'); +} +$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING); +$basePath = ""; +$DATA_DIR = "./data"; +/** Returns the offset from the origin timezone to the remote timezone, in seconds. + * @param $remote_tz; + * @param $origin_tz; If null the servers current timezone is used as the origin. + * @return int; + */ +function get_timezone_offset($remote_tz, $origin_tz = null) +{ + if ($origin_tz === null) { + if (!is_string($origin_tz = date_default_timezone_get())) { + return false; // A UTC timestamp was returned -- bail out! + } + } + $origin_dtz = new DateTimeZone($origin_tz); + $remote_dtz = new DateTimeZone($remote_tz); + $origin_dt = new DateTime("now", $origin_dtz); + $remote_dt = new DateTime("now", $remote_dtz); + $offset = $origin_dtz->getOffset($origin_dt) - $remote_dtz->getOffset($remote_dt); + return $offset; +} + + +function include_header($title) +{ + global $basePath; + ?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + --- /dev/null +++ b/crossdomain.xml @@ -1,1 +1,16 @@ + + + + + + + + + + + --- /dev/null +++ b/css/main.css @@ -1,1 +1,299 @@ - +/* + * HTML5 Boilerplate + * + * What follows is the result of much research on cross-browser styling. + * Credit left inline and big thanks to Nicolas Gallagher, Jonathan Neal, + * Kroc Camen, and the H5BP dev community and team. + */ + +/* ========================================================================== + Base styles: opinionated defaults + ========================================================================== */ + +html, +button, +input, +select, +textarea { + color: #222; +} + +body { + font-size: 1em; + line-height: 1.4; +} + +/* + * Remove text-shadow in selection highlight: h5bp.com/i + * These selection declarations have to be separate. + * Customize the background color to match your design. + */ + +::-moz-selection { + background: #b3d4fc; + text-shadow: none; +} + +::selection { + background: #b3d4fc; + text-shadow: none; +} + +/* + * A better looking default horizontal rule + */ + +hr { + display: block; + height: 1px; + border: 0; + border-top: 1px solid #ccc; + margin: 1em 0; + padding: 0; +} + +/* + * Remove the gap between images and the bottom of their containers: h5bp.com/i/440 + */ + +img { + vertical-align: middle; +} + +/* + * Remove default fieldset styles. + */ + +fieldset { + border: 0; + margin: 0; + padding: 0; +} + +/* + * Allow only vertical resizing of textareas. + */ + +textarea { + resize: vertical; +} + +/* ========================================================================== + Chrome Frame prompt + ========================================================================== */ + +.chromeframe { + margin: 0.2em 0; + background: #ccc; + color: #000; + padding: 0.2em 0; +} + +/* ========================================================================== + Author's custom styles + ========================================================================== */ + + + + + + + + + + + + + + + + + +/* ========================================================================== + Helper classes + ========================================================================== */ + +/* + * Image replacement + */ + +.ir { + background-color: transparent; + border: 0; + overflow: hidden; + /* IE 6/7 fallback */ + *text-indent: -9999px; +} + +.ir:before { + content: ""; + display: block; + width: 0; + height: 100%; +} + +/* + * Hide from both screenreaders and browsers: h5bp.com/u + */ + +.hidden { + display: none !important; + visibility: hidden; +} + +/* + * Hide only visually, but have it available for screenreaders: h5bp.com/v + */ + +.visuallyhidden { + border: 0; + clip: rect(0 0 0 0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; +} + +/* + * Extends the .visuallyhidden class to allow the element to be focusable + * when navigated to via the keyboard: h5bp.com/p + */ + +.visuallyhidden.focusable:active, +.visuallyhidden.focusable:focus { + clip: auto; + height: auto; + margin: 0; + overflow: visible; + position: static; + width: auto; +} + +/* + * Hide visually and from screenreaders, but maintain layout + */ + +.invisible { + visibility: hidden; +} + +/* + * Clearfix: contain floats + * + * For modern browsers + * 1. The space content is one way to avoid an Opera bug when the + * `contenteditable` attribute is included anywhere else in the document. + * Otherwise it causes space to appear at the top and bottom of elements + * that receive the `clearfix` class. + * 2. The use of `table` rather than `block` is only necessary if using + * `:before` to contain the top-margins of child elements. + */ + +.clearfix:before, +.clearfix:after { + content: " "; /* 1 */ + display: table; /* 2 */ +} + +.clearfix:after { + clear: both; +} + +/* + * For IE 6/7 only + * Include this rule to trigger hasLayout and contain floats. + */ + +.clearfix { + *zoom: 1; +} + +/* ========================================================================== + EXAMPLE Media Queries for Responsive Design. + Theses examples override the primary ('mobile first') styles. + Modify as content requires. + ========================================================================== */ + +@media only screen and (min-width: 35em) { + /* Style adjustments for viewports that meet the condition */ +} + +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (min-resolution: 144dpi) { + /* Style adjustments for high resolution devices */ +} + +/* ========================================================================== + Print styles. + Inlined to avoid required HTTP connection: h5bp.com/r + ========================================================================== */ + +@media print { + * { + background: transparent !important; + color: #000 !important; /* Black prints faster: h5bp.com/s */ + box-shadow:none !important; + text-shadow: none !important; + } + + a, + a:visited { + text-decoration: underline; + } + + a[href]:after { + content: " (" attr(href) ")"; + } + + abbr[title]:after { + content: " (" attr(title) ")"; + } + + /* + * Don't show links for images, or javascript/internal links + */ + + .ir a:after, + a[href^="javascript:"]:after, + a[href^="#"]:after { + content: ""; + } + + pre, + blockquote { + border: 1px solid #999; + page-break-inside: avoid; + } + + thead { + display: table-header-group; /* h5bp.com/t */ + } + + tr, + img { + page-break-inside: avoid; + } + + img { + max-width: 100% !important; + } + + @page { + margin: 0.5cm; + } + + p, + h2, + h3 { + orphans: 3; + widows: 3; + } + + h2, + h3 { + page-break-after: avoid; + } +} + --- /dev/null +++ b/css/normalize.css @@ -1,1 +1,505 @@ - +/*! normalize.css v1.0.1 | MIT License | git.io/normalize */ + +/* ========================================================================== + HTML5 display definitions + ========================================================================== */ + +/* + * Corrects `block` display not defined in IE 6/7/8/9 and Firefox 3. + */ + +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +nav, +section, +summary { + display: block; +} + +/* + * Corrects `inline-block` display not defined in IE 6/7/8/9 and Firefox 3. + */ + +audio, +canvas, +video { + display: inline-block; + *display: inline; + *zoom: 1; +} + +/* + * Prevents modern browsers from displaying `audio` without controls. + * Remove excess height in iOS 5 devices. + */ + +audio:not([controls]) { + display: none; + height: 0; +} + +/* + * Addresses styling for `hidden` attribute not present in IE 7/8/9, Firefox 3, + * and Safari 4. + * Known issue: no IE 6 support. + */ + +[hidden] { + display: none; +} + +/* ========================================================================== + Base + ========================================================================== */ + +/* + * 1. Corrects text resizing oddly in IE 6/7 when body `font-size` is set using + * `em` units. + * 2. Prevents iOS text size adjust after orientation change, without disabling + * user zoom. + */ + +html { + font-size: 100%; /* 1 */ + -webkit-text-size-adjust: 100%; /* 2 */ + -ms-text-size-adjust: 100%; /* 2 */ +} + +/* + * Addresses `font-family` inconsistency between `textarea` and other form + * elements. + */ + +html, +button, +input, +select, +textarea { + font-family: sans-serif; +} + +/* + * Addresses margins handled incorrectly in IE 6/7. + */ + +body { + margin: 0; +} + +/* ========================================================================== + Links + ========================================================================== */ + +/* + * Addresses `outline` inconsistency between Chrome and other browsers. + */ + +a:focus { + outline: thin dotted; +} + +/* + * Improves readability when focused and also mouse hovered in all browsers. + */ + +a:active, +a:hover { + outline: 0; +} + +/* ========================================================================== + Typography + ========================================================================== */ + +/* + * Addresses font sizes and margins set differently in IE 6/7. + * Addresses font sizes within `section` and `article` in Firefox 4+, Safari 5, + * and Chrome. + */ + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +h2 { + font-size: 1.5em; + margin: 0.83em 0; +} + +h3 { + font-size: 1.17em; + margin: 1em 0; +} + +h4 { + font-size: 1em; + margin: 1.33em 0; +} + +h5 { + font-size: 0.83em; + margin: 1.67em 0; +} + +h6 { + font-size: 0.75em; + margin: 2.33em 0; +} + +/* + * Addresses styling not present in IE 7/8/9, Safari 5, and Chrome. + */ + +abbr[title] { + border-bottom: 1px dotted; +} + +/* + * Addresses style set to `bolder` in Firefox 3+, Safari 4/5, and Chrome. + */ + +b, +strong { + font-weight: bold; +} + +blockquote { + margin: 1em 40px; +} + +/* + * Addresses styling not present in Safari 5 and Chrome. + */ + +dfn { + font-style: italic; +} + +/* + * Addresses styling not present in IE 6/7/8/9. + */ + +mark { + background: #ff0; + color: #000; +} + +/* + * Addresses margins set differently in IE 6/7. + */ + +p, +pre { + margin: 1em 0; +} + +/* + * Corrects font family set oddly in IE 6, Safari 4/5, and Chrome. + */ + +code, +kbd, +pre, +samp { + font-family: monospace, serif; + _font-family: 'courier new', monospace; + font-size: 1em; +} + +/* + * Improves readability of pre-formatted text in all browsers. + */ + +pre { + white-space: pre; + white-space: pre-wrap; + word-wrap: break-word; +} + +/* + * Addresses CSS quotes not supported in IE 6/7. + */ + +q { + quotes: none; +} + +/* + * Addresses `quotes` property not supported in Safari 4. + */ + +q:before, +q:after { + content: ''; + content: none; +} + +/* + * Addresses inconsistent and variable font size in all browsers. + */ + +small { + font-size: 80%; +} + +/* + * Prevents `sub` and `sup` affecting `line-height` in all browsers. + */ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +/* ========================================================================== + Lists + ========================================================================== */ + +/* + * Addresses margins set differently in IE 6/7. + */ + +dl, +menu, +ol, +ul { + margin: 1em 0; +} + +dd { + margin: 0 0 0 40px; +} + +/* + * Addresses paddings set differently in IE 6/7. + */ + +menu, +ol, +ul { + padding: 0 0 0 40px; +} + +/* + * Corrects list images handled incorrectly in IE 7. + */ + +nav ul, +nav ol { + list-style: none; + list-style-image: none; +} + +/* ========================================================================== + Embedded content + ========================================================================== */ + +/* + * 1. Removes border when inside `a` element in IE 6/7/8/9 and Firefox 3. + * 2. Improves image quality when scaled in IE 7. + */ + +img { + border: 0; /* 1 */ + -ms-interpolation-mode: bicubic; /* 2 */ +} + +/* + * Corrects overflow displayed oddly in IE 9. + */ + +svg:not(:root) { + overflow: hidden; +} + +/* ========================================================================== + Figures + ========================================================================== */ + +/* + * Addresses margin not present in IE 6/7/8/9, Safari 5, and Opera 11. + */ + +figure { + margin: 0; +} + +/* ========================================================================== + Forms + ========================================================================== */ + +/* + * Corrects margin displayed oddly in IE 6/7. + */ + +form { + margin: 0; +} + +/* + * Define consistent border, margin, and padding. + */ + +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; +} + +/* + * 1. Corrects color not being inherited in IE 6/7/8/9. + * 2. Corrects text not wrapping in Firefox 3. + * 3. Corrects alignment displayed oddly in IE 6/7. + */ + +legend { + border: 0; /* 1 */ + padding: 0; + white-space: normal; /* 2 */ + *margin-left: -7px; /* 3 */ +} + +/* + * 1. Corrects font size not being inherited in all browsers. + * 2. Addresses margins set differently in IE 6/7, Firefox 3+, Safari 5, + * and Chrome. + * 3. Improves appearance and consistency in all browsers. + */ + +button, +input, +select, +textarea { + font-size: 100%; /* 1 */ + margin: 0; /* 2 */ + vertical-align: baseline; /* 3 */ + *vertical-align: middle; /* 3 */ +} + +/* + * Addresses Firefox 3+ setting `line-height` on `input` using `!important` in + * the UA stylesheet. + */ + +button, +input { + line-height: normal; +} + +/* + * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` + * and `video` controls. + * 2. Corrects inability to style clickable `input` types in iOS. + * 3. Improves usability and consistency of cursor style between image-type + * `input` and others. + * 4. Removes inner spacing in IE 7 without affecting normal text inputs. + * Known issue: inner spacing remains in IE 6. + */ + +button, +html input[type="button"], /* 1 */ +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; /* 2 */ + cursor: pointer; /* 3 */ + *overflow: visible; /* 4 */ +} + +/* + * Re-set default cursor for disabled elements. + */ + +button[disabled], +input[disabled] { + cursor: default; +} + +/* + * 1. Addresses box sizing set to content-box in IE 8/9. + * 2. Removes excess padding in IE 8/9. + * 3. Removes excess padding in IE 7. + * Known issue: excess padding remains in IE 6. + */ + +input[type="checkbox"], +input[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ + *height: 13px; /* 3 */ + *width: 13px; /* 3 */ +} + +/* + * 1. Addresses `appearance` set to `searchfield` in Safari 5 and Chrome. + * 2. Addresses `box-sizing` set to `border-box` in Safari 5 and Chrome + * (include `-moz` to future-proof). + */ + +input[type="search"] { + -webkit-appearance: textfield; /* 1 */ + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box; /* 2 */ + box-sizing: content-box; +} + +/* + * Removes inner padding and search cancel button in Safari 5 and Chrome + * on OS X. + */ + +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +/* + * Removes inner padding and border in Firefox 3+. + */ + +button::-moz-focus-inner, +input::-moz-focus-inner { + border: 0; + padding: 0; +} + +/* + * 1. Removes default vertical scrollbar in IE 6/7/8/9. + * 2. Improves readability and alignment in all browsers. + */ + +textarea { + overflow: auto; /* 1 */ + vertical-align: top; /* 2 */ +} + +/* ========================================================================== + Tables + ========================================================================== */ + +/* + * Remove most spacing between table cells. + */ + +table { + border-collapse: collapse; + border-spacing: 0; +} + --- /dev/null +++ b/db.sql @@ -1,1 +1,94 @@ +-- /usr/pgsql-9.1/bin/pg_dump --schema-only scannr +-- +-- PostgreSQL database dump +-- +SET statement_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SET check_function_bodies = false; +SET client_min_messages = warning; + +-- +-- Name: plpgsql; Type: EXTENSION; Schema: -; Owner: +-- + +CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog; + + +-- +-- Name: EXTENSION plpgsql; Type: COMMENT; Schema: -; Owner: +-- + +COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language'; + + +SET search_path = public, pg_catalog; + +SET default_tablespace = ''; + +SET default_with_oids = false; + +-- +-- Name: recordings; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE recordings ( + filename text NOT NULL, + tgid text, + tgname text, + sitename text, + call_timestamp timestamp with time zone DEFAULT now(), + length integer +); + + +ALTER TABLE public.recordings OWNER TO postgres; + +-- +-- Name: tgids; Type: TABLE; Schema: public; Owner: postgres; Tablespace: +-- + +CREATE TABLE tgids ( + tgid text NOT NULL, + subfleet smallint, + mode character(1) DEFAULT 'D'::bpchar NOT NULL, + alpha_tag text NOT NULL, + service_tag text, + category smallint +); + + +ALTER TABLE public.tgids OWNER TO postgres; + +-- +-- Name: recordings_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY recordings + ADD CONSTRAINT recordings_pkey PRIMARY KEY (filename); + + +-- +-- Name: tgids_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: +-- + +ALTER TABLE ONLY tgids + ADD CONSTRAINT tgids_pkey PRIMARY KEY (tgid); + + +-- +-- Name: public; Type: ACL; Schema: -; Owner: postgres +-- + +REVOKE ALL ON SCHEMA public FROM PUBLIC; +REVOKE ALL ON SCHEMA public FROM postgres; +GRANT ALL ON SCHEMA public TO postgres; +GRANT ALL ON SCHEMA public TO PUBLIC; + + +-- +-- PostgreSQL database dump complete +-- + + --- /dev/null +++ b/ffmpeg.exe --- /dev/null +++ b/generateConvos.php @@ -1,1 +1,36 @@ +prepare('select * from recordings limit 100;'); +$sth->execute(); +$recordings = $sth->fetchAll(); +$convos = Array(); +$convo = Array(); +foreach ($recordings as $i => $recording) { + + if (count($convo) > 0) { + echo "
" . strcasecmp($convos[count($convos) - 1][0]['call_timestamp'], $recording['call_timestamp']); + if (abs(strcasecmp($convos[count($convos) - 1][0]['call_timestamp'], $recording['call_timestamp'])) > 2) { + echo " " . $convos[count($convos) - 1][0]['call_timestamp'] . " " . $recording['call_timestamp']; + } + if (strcasecmp($convos[count($convos) - 1][0]['tgid'], $recording['tgid']) != 0) { + $convos[] = $convo; + $convo = Array(); + } + } + ; + //print_r($recording); + $convo[] = $recording; + //print_r($convo); + //echo "
\n"; +} +foreach ($convos as $i => $convo) { + foreach ($convo as $recording) { + echo $recording['filename'] . " , "; + } + echo "

\n"; +} +?> + + --- /dev/null +++ b/generateHourlys.php @@ -1,1 +1,33 @@ +&1'; + //print_r($hourly); + exec ( $cmd,$output,$returncode ); + echo $cmd."
\n"; + if ($returncode != 10) { + //print_r($output); + //die(); + } + } +} +$sth = $conn->prepare("select tgid, extract(hour from call_timestamp) ahour, date_trunc('day', call_timestamp) aday, count(filename), array_to_string(array_agg(filename order by call_timestamp), ',') filenames from recordings group by tgid, ahour, aday order by aday DESC, ahour, tgid;"); + +$sth->execute(); +$hourlies = $sth->fetchAll(PDO::FETCH_ASSOC); +foreach($hourlies as $hourly) { + //processHourly($hourly); +} +$sth = $conn->prepare("select 'hour' as tgid, extract(hour from call_timestamp) ahour, date_trunc('day', call_timestamp) aday, count(filename), array_to_string(array_agg(filename order by call_timestamp), ',') filenames from recordings group by ahour, aday order by aday DESC, ahour;"); + +$sth->execute(); +$hourlies = $sth->fetchAll(PDO::FETCH_ASSOC); +foreach($hourlies as $hourly) { + processHourly($hourly); +} + --- /dev/null +++ b/getfile.php @@ -1,1 +1,20 @@ + + --- /dev/null +++ b/humans.txt @@ -1,1 +1,16 @@ +# humanstxt.org/ +# The humans responsible & technology colophon +# TEAM + + -- -- + +# THANKS + + + +# TECHNOLOGY COLOPHON + + HTML5, CSS3 + jQuery, Modernizr + --- /dev/null +++ b/img/.gitignore --- /dev/null +++ b/js/flotr2/.gitignore @@ -1,1 +1,10 @@ +build +.vimrc +*.swp +*.swm +*.swo +*.vim +.jhw-cache +node_modules +dev --- /dev/null +++ b/js/flotr2/LICENSE @@ -1,1 +1,20 @@ +Copyright (c) 2012 Carl Sutherland +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + --- /dev/null +++ b/js/flotr2/Makefile @@ -1,1 +1,40 @@ +all: test flotr2 +test: + cd spec; jasmine-headless-webkit -j jasmine.yml -c + +libraries: + smoosh make/lib.json + cat ./build/bean.js > build/lib.js + cat ./build/underscore.js >> build/lib.js + cat ./build/bean.min.js > build/lib.min.js + echo ";" >> build/lib.min.js + cat ./build/underscore.min.js >> build/lib.min.js + echo ";" >> build/lib.min.js + +ie: + smoosh make/ie.json + +flotr2: libraries ie + smoosh make/flotr2.json + cat build/lib.js build/flotr2.js > flotr2.js + cat build/lib.min.js > flotr2.min.js + cat build/flotr2.min.js >> flotr2.min.js + echo ';' >> flotr2.min.js + cp build/ie.min.js flotr2.ie.min.js + +flotr2-basic: libraries ie + smoosh make/basic.json + cat build/lib.min.js > flotr2-basic.min.js + cat build/flotr2-basic.min.js >> flotr2-basic.min.js + +flotr-examples: + smoosh make/examples.json + cp build/examples.min.js flotr2.examples.min.js + cp build/examples-types.js flotr2.examples.types.js + +flotr-amd: flotr2 + cat js/amd/pre.js > flotr2.amd.js + cat build/flotr2.js >> flotr2.amd.js + cat js/amd/post.js >> flotr2.amd.js + --- /dev/null +++ b/js/flotr2/README.md @@ -1,1 +1,90 @@ +Flotr2 +====== +The Canvas graphing library. + +![Google Groups](http://groups.google.com/intl/en/images/logos/groups_logo_sm.gif) + +http://groups.google.com/group/flotr2/ + +Please fork http://jsfiddle.net/cesutherland/ZFBj5/ with your question or bug reproduction case. + + +API +--- + +The API consists of a primary draw method which accepts a configuration object, helper methods, and several microlibs. + +### Example + +```javascript + var + // Container div: + container = document.getElementById("flotr-example-graph"), + // First data series: + d1 = [[0, 3], [4, 8], [8, 5], [9, 13]], + // Second data series: + d2 = [], + // A couple flotr configuration options: + options = { + xaxis: { + minorTickFreq: 4 + }, + grid: { + minorVerticalLines: true + } + }, + i, graph; + + // Generated second data set: + for (i = 0; i < 14; i += 0.5) { + d2.push([i, Math.sin(i)]); + } + + // Draw the graph: + graph = Flotr.draw( + container, // Container element + [ d1, d2 ], // Array of data series + options // Configuration options + ); +``` + +### Microlibs + +* [underscore.js](http://documentcloud.github.com/underscore/) +* [bean.js](https://github.com/fat/bean) + +Extending +--------- + +Flotr may be extended by adding new plugins and graph types. + +### Graph Types + +Graph types define how a particular chart is rendered. Examples include line, bar, pie. + +Existing graph types are found in `js/types/`. + +### Plugins + +Plugins extend the core of flotr with new functionality. They can add interactions, new decorations, etc. Examples +include titles, labels and selection. + +The plugins included are found in `js/plugins/`. + +Development +----------- + +This project uses [smoosh](https://github.com/fat/smoosh) to build and [jasmine](http://pivotal.github.com/jasmine/) +with [js-imagediff](https://github.com/HumbleSoftware/js-imagediff) to test. Tests may be executed by +[jasmine-headless-webkit](http://johnbintz.github.com/jasmine-headless-webkit/) with +`cd spec; jasmine-headless-webkit -j jasmine.yml -c` or by a browser by navigating to +`flotr2/spec/SpecRunner.html`. + +Shoutouts +--------- + +Thanks to Bas Wenneker, Fabien Ménager and others for all the work on the original Flotr. +Thanks to Jochen Berger and Jordan Santell for their contributions to Flotr2. + + --- /dev/null +++ b/js/flotr2/dev/notes.txt @@ -1,1 +1,87 @@ +Flotr 2 Architecture Notes + +Global: +====== + +Flotr.js - + versioning information + browser detection + extension (plugins, graph types) + draw + clone / merge + tick size + tick formatter + engineering notation + magnitude + rad, pixel, floor + drawText + measureText + getBestTextAlign + align map + compatibility + + +Graph Architecture: +=================== + +Axis - + all series + orientation + ticks (major, minor) + scale (d2p, p2d, logarithmic) + notion of stacks + +Series - + per 'data' + notion of range (x, y, min, max) + +Graph - + DOM constructon + event attachment + options initialization + data range calculations + canvas spacing calculations + event normalization + draw methods + DOM cleanup + event cleanup + + +Utilities: +========== + +Color + build colors + parse textual color data + convert colors + clone colors + +Text + calculate text size + canvas size + html size + +Date + formatting + constants + + +Spacing Calculation +=================== + +Flotr + calculate data + calculate margins + +Chart + calculate Data Ranges - Explicit or auto data minimum, maximums + calculate Data Range Extensions - By chart type, extend data range with needs of chart type (ie. stacked bars, stacked lines) + add Chart Padding - By chart type + +Text + use explicit margins + calculate label margins + calculate title margins + + --- /dev/null +++ b/js/flotr2/examples/dev.html @@ -1,1 +1,26 @@ + + + + + Flotr Example Index Page + + + + + + +
+
+
+
+
+
+
+ + + + + + + --- /dev/null +++ b/js/flotr2/examples/editor.css @@ -1,1 +1,73 @@ +/* Editor */ +.editor { + position: relative; +} +.editor .render { + height: 240px; + width: 320px; + margin: 8px auto; +} +.editor .source { + border: 1px solid #ddd; + border-radius: 3px; +} +.editor .controls { + position: absolute;; + z-index: 100; + right: 8px; + margin-top: -12px; +} +.editor .controls button { + float: right; +} +.editor .errors { + color: #ee0000; + padding: 8px; + font-size: 12px; + background: #fee; + border-bottom: 1px solid #eee; +} +.editor .errors .error { + font-weight: bold +} +.editor .errors .message { + font-style: italic; +} +.editor .errors .position { + display: block; + margin-top: 4px; +} +.editor.no-run .controls, +.editor.no-run .render { + display: none; +} +/* html type */ +.editor.html .render { + height: 400px; + width: 800px; + text-align: center; +} +.editor.html .render iframe { + height: 100%; + width: 100%; + border: none; +} + +/* CodeMirror */ +.CodeMirror { + background: #fafafa; +} +.CodeMirror.CodeMirror-focused { +} +.CodeMirror-scroll { + height: auto; + overflow: visible; + overflow-x: auto; +} +.CodeMirror-lines pre, +.CodeMirror-gutter pre { + line-height: 16px; +} + + --- /dev/null +++ b/js/flotr2/examples/examples.css @@ -1,1 +1,213 @@ - +body { + font-family : sans-serif; + padding: 0px; + margin: 0px; +} + +/* Example */ + +.flotr-example { + display: none; + margin: 0px auto 48px auto; + position: relative; +} +.flotr-example-label { + font-size: 18px; + padding: 14px 0px; +} +.flotr-example-editor .editor .render { + width: 600px; + height: 400px; + margin: 12px auto 18px auto; +} +.flotr-example-editor .editor .source { + width: 720px; +} + +/* Chart no-select */ + +.flotr-example-editor .editor .render, +.flotr-examples-thumb { + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -o-user-select: none; + user-select: none; +} + + +/* Examples */ + +.flotr-examples-thumbs { + text-align: center; +} +.flotr-examples-reset { + z-index: 100; + cursor: pointer; + text-decoration: underline; + position: absolute; + top: 260px; + right: 24px; + display: none; +} +.flotr-examples-collapsed .flotr-examples-reset { + display: block; +} +.flotr-examples-thumb { + display: inline-block; + font-size : 11px; + width : 300px; + height : 200px; + margin: 10px 15px; + border: 2px solid transparent; +} +.flotr-examples-thumb.flotr-examples-highlight{ + font-size : 12px; + width : 330px; + height : 220px; + margin: 0px 0px; +} +.flotr-examples-thumb .flotr-legend, +.flotr-examples-thumb .flotr-mouse-value { + display : none; +} + +.flotr-examples-collapsed .flotr-examples-container { + margin-top: 20px; + position: relative; + margin: 0px auto; +} + +.flotr-examples-collapsed .flotr-examples-thumbs { + position: relative; + overflow-x: auto; + white-space: nowrap; +} + + +/* Flotr Styles */ + +.flotr-datagrid-container { + border: 1px solid #999; + border-bottom: none; + background: #fff; +} +.flotr-datagrid { + border-collapse: collapse; + border-spacing: 0; +} +.flotr-datagrid td, .flotr-datagrid th { + border: 1px solid #ccc; + padding: 1px 3px; + min-width: 2em; +} +.flotr-datagrid tr:hover, .flotr-datagrid col.hover { + background: #f3f3f3; +} +.flotr-datagrid tr:hover th, .flotr-datagrid th.hover { + background: #999; + color: #fff; +} +.flotr-datagrid th { + text-align: left; + background: #e3e3e3; + border: 2px outset #fff; +} +.flotr-datagrid-toolbar { + padding: 1px; + border-bottom: 1px solid #ccc; + background: #f9f9f9; +} +.flotr-datagrid td:hover { + background: #ccc; +} +.flotr-datagrid .first-row th { + text-align: center; +} +.flotr-canvas { + margin-bottom: -3px; + padding-bottom: 1px; +} +.flotr-tabs-group { + border-top: 1px solid #999; +} +.flotr-tab { + border: 1px solid #666; + border-top: none; + margin: 0 3px; + padding: 1px 4px; + cursor: pointer; + -moz-border-radius: 0 0 4px 4px; + -webkit-border-bottom-left-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + border-radius: 0 0 4px 4px; + opacity: 0.5; + -moz-opacity: 0.5; +} +.flotr-tab.selected { + background: #ddd; + opacity: 1; + -moz-opacity: 1; +} +.flotr-tab:hover { + background: #ccc; +} + +/* Large */ +.flotr-examples-large .flotr-example { + width: 1360px; + margin: 0px auto; + position: relative; +} +.flotr-examples-large .flotr-example-editor .editor .render { + margin-left: 0px; + margin-right: 0px; +} +.flotr-examples-large .flotr-example-editor .controls { + top: 0px; +} +.flotr-examples-large .flotr-example-editor .source { + position: absolute; + top: 0px; + right: 0px; +} + +/* Veritical Thumbs */ + +.flotr-examples-large.flotr-examples-collapsed .flotr-examples-reset, +.flotr-examples-medium.flotr-examples-collapsed .flotr-examples-reset { + top: 16px; +} + +.flotr-examples-large.flotr-examples-collapsed .flotr-examples-thumbs, +.flotr-examples-medium.flotr-examples-collapsed .flotr-examples-thumbs { + position: fixed; + width: 400px; + left: 0px; + top: 0px; + overflow-y: auto; + background: #fff; +} +.flotr-examples-large.flotr-examples-collapsed .flotr-examples-thumb, +.flotr-examples-medium.flotr-examples-collapsed .flotr-examples-thumb { + display: block; + float: center; + margin: 10px auto; +} + +.flotr-examples-large.flotr-examples-collapsed .flotr-examples-container, +.flotr-examples-medium.flotr-examples-collapsed .flotr-examples-container { + margin-left: 400px; +} + +/* Vertical Example */ + +.flotr-examples-small .flotr-example, +.flotr-examples-medium .flotr-example { + width: 720px; +} +.flotr-examples-small .flotr-example-editor .source, +.flotr-examples-medium .flotr-example-editor .source { + position: relative; +} + --- /dev/null +++ b/js/flotr2/examples/index.html @@ -1,1 +1,26 @@ + + + + + Flotr Example Index Page + + + + + + +
+
+
+
+
+
+
+ + + + + + + --- /dev/null +++ b/js/flotr2/examples/js/Editor.js @@ -1,1 +1,279 @@ - +(function () { + + var + ONERROR = window.onerror, + COUNT = 0, + TYPES = {}, + + T_CONTROLS = + '
' + + '' + + '' + + '
', + T_EDITOR = '
', + T_SOURCE = '
', + T_ERRORS = '
', + T_RENDER = '
', + T_IFRAME = ''; + + + // Javascript type: + TYPES.javascript = function Javascript (o) { + this.onerror = o.onerror; + }; + TYPES.javascript.prototype = { + codeMirrorType : 'javascript', + example : function (o) { + + var + example = o.example, + render = o.render, + renderId = $(render).attr('id'), + args = o.args ? ',' + o.args.toString() : ''; + + return '(' + example + ')(document.getElementById("' + renderId+ '")' + + args + ');'; + }, + render : function (o) { + eval(o.example); + } + }; + + // HTML Type: + TYPES.html = function Html (o) { + this.onerror = o.onerror; + }; + TYPES.html.prototype = { + codeMirrorType : 'htmlmixed', + example : function (o) { + return $.trim(o.example); + }, + render : function (o) { + + var + example = o.example, + render = o.render, + iframe = $(T_IFRAME), + that = this, + win, doc; + + render.html(iframe); + + win = iframe[0].contentWindow; + + doc = win.document; + doc.open(); + + // Error + win.onerror = iframe.onerror = function () { + that.onerror.apply(null, arguments); + } + + doc.write(example); + doc.close(); + } + }; + + // Editor + function Editor (container, o) { + + var + type = o.type || 'javascript', + example = o.example || '', + noRun = o.noRun || false, + teardown = o.teardown || false, + controls = $(T_CONTROLS), + render = $(T_RENDER), + errors = $(T_ERRORS), + source = $(T_SOURCE), + node = $(T_EDITOR), + renderId = 'editor-render-' + COUNT, + api, + render, + codeMirror; + + api = new TYPES[type]({ + onerror : onerror + }); + if (!api) throw 'Invalid type: API not found for type `' + type + '`.'; + + render + .attr('id', renderId); + + errors + .hide(); + + node + .append(render) + .append(controls) + .append(source) + .addClass(type) + .addClass(noRun ? 'no-run' : ''); + + container = $(container); + container + .append(node); + + source + .append(errors) + + example = api.example({ + args : o.args, + example : example, + render : render + }); + + codeMirror = CodeMirror(source[0], { + value : example, + readOnly : noRun, + lineNumbers : true, + mode : api.codeMirrorType + }); + + if (!noRun) { + controls.delegate('.run', 'click', function () { + example = codeMirror.getValue(); + execute(); + }); + + execute(); + } + + controls.delegate('.fiddle', 'click', function () { + fiddle(); + }); + + // Error handling: + window.onerror = function (message, url, line) { + + onerror(message, url, line); + console.log(message); + + if (ONERROR && $.isFunction(ONERROR)) { + return ONERROR(message, url, line); + } else { + return false; + } + } + + // Helpers + + function execute () { + errors.hide(); + if (teardown) { + teardown.call(); + } + api.render({ + example : example, + render : render + }); + } + + function onerror (message, url, line) { + // @TODO Find some js error normalizing lib + + var + doThatSexyThang = false, + html = 'Error: ', + error, stack; + + /* + // Native error type handling: + if (typeof (message) !== 'string') { + error = message; + message = error.message; + stack = error.stack; + + //if (stack) { + console.log(stack); + //} + + //console.log(message); + + } + + */ + + html += '' + message + ''; + if (typeof (line) !== "undefined") { + html += ''; + html += 'Line ' + line + ''; + console.log(url); + if (url) { + html += ' of '; + if (url == window.location) { + html += 'script'; + if (doThatSexyThang) { + //codeMirror.setMarker(line, '•'); + } + } else { + html += '' + url + ''; + } + } + html += '.'; + } + + errors.show(); + errors.html(html); + } + + function fiddle () { + var + url = 'http://jsfiddle.net/api/post/jquery/1.7/', + form = $('
'), + input; + + // Resources + resources = [ + 'https://raw.github.com/HumbleSoftware/Flotr2/master/flotr2.min.js', + 'https://raw.github.com/HumbleSoftware/Flotr2/master/examples/examples.css' + ]; + input = $('') + .attr('value', resources.join(',')); + form.append(input); + + // HTML + input = $('') + .attr('value', '
'); + form.append(input); + + // CSS + input = $('') + form.append(input); + input = $('') + .attr('value', + '#'+renderId+' {\n width: 340px;\n height: 220px;' + + '\n margin: 24px auto;\n}' + ); + form.append(input); + + // JS + input = $('') + .attr('value', '$(function () {\n' + example + '\n});'); + + form.append(input); + + // Submit + form.append(input); + $(document.body).append(form); + form.submit(); + } + + COUNT++; + + this.setExample = function (source, args) { + example = api.example({ + args : args, + example : source, + render : render + }); + codeMirror.setValue(example); + codeMirror.refresh(); + execute(); + } + } + + if (typeof Flotr.Examples === 'undefined') Flotr.Examples = {}; + Flotr.Examples.Editor = Editor; +})(); + --- /dev/null +++ b/js/flotr2/examples/js/Example.js @@ -1,1 +1,100 @@ +(function () { +var + _ = Flotr._, + + DOT = '.', + + CN_EXAMPLE = 'flotr-example', + CN_LABEL = 'flotr-example-label', + CN_TITLE = 'flotr-example-title', + CN_MARKUP = 'flotr-example-description', + CN_EDITOR = 'flotr-example-editor', + + ID_GRAPH = 'flotr-example-graph', + + TEMPLATE = '' + + '
' + + '
' + + '
' + + '
' + + '
', + +Example = function (o) { + + this.options = o; + this.example = null; + + this._initNodes(); +}; + +Example.prototype = { + + setExample : function (example) { + + var + source = this.getSource(example), + editorNode = this._editorNode; + + this.example = example; + + Math.seedrandom(example.key); + this._exampleNode.css({ display: 'block' }); + this._titleNode.html(example.name || ''); + this._markupNode.html(example.description || ''); + + if (!this._editor) { + this._editor = new Flotr.Examples.Editor(editorNode, { + args : example.args, + example : source, + teardown : function () { + // Unbind event listeners from previous examples + Flotr.EventAdapter.stopObserving($(editorNode).find('.render')[0]); + $(editorNode).find('canvas').each(function (index, canvas) { + Flotr.EventAdapter.stopObserving(canvas); + }); + } + }); + } else { + this._editor.setExample(source, example.args); + } + }, + + getSource : function (example) { + + var + source = example.callback.toString(); + + // Hack for FF code style + if (navigator.userAgent.search(/firefox/i) !== -1) + source = js_beautify(source); + + return source; + }, + + executeCallback : function (example, node) { + if (!_.isElement(node)) node = node[0]; + var args = (example.args ? [node].concat(example.args) : [node]); + Math.seedrandom(example.key); + return example.callback.apply(this, args); + }, + + _initNodes : function () { + + var + node = this.options.node, + example = $(TEMPLATE); + + this._titleNode = example.find(DOT + CN_TITLE); + this._markupNode = example.find(DOT + CN_MARKUP); + this._editorNode = example.find(DOT + CN_EDITOR); + this._exampleNode = example; + + node.append(example); + } +}; + +Flotr.Examples.Example = Example; + +})(); + --- /dev/null +++ b/js/flotr2/examples/js/ExampleList.js @@ -1,1 +1,30 @@ +(function () { +var ExampleList = function () { + + // Map of examples. + this.examples = {}; + +}; + +ExampleList.prototype = { + + add : function (example) { + this.examples[example.key] = example; + }, + + get : function (key) { + return key ? (this.examples[key] || null) : this.examples; + }, + + getType : function (type) { + return Flotr._.select(this.examples, function (example) { + return (example.type === type); + }); + } +} + +Flotr.ExampleList = new ExampleList(); + +})(); + --- /dev/null +++ b/js/flotr2/examples/js/Examples.js @@ -1,1 +1,292 @@ - +(function () { + +var + E = Flotr.EventAdapter, + _ = Flotr._, + + CLICK = 'click', + EXAMPLE = 'example', + MOUSEENTER = 'mouseenter', + MOUSELEAVE = 'mouseleave', + + DOT = '.', + + CN_EXAMPLES = 'flotr-examples', + CN_CONTAINER = 'flotr-examples-container', + CN_RESET = 'flotr-examples-reset', + CN_THUMBS = 'flotr-examples-thumbs', + CN_THUMB = 'flotr-examples-thumb', + CN_COLLAPSED = 'flotr-examples-collapsed', + CN_HIGHLIGHT = 'flotr-examples-highlight', + CN_LARGE = 'flotr-examples-large', + CN_MEDIUM = 'flotr-examples-medium', + CN_SMALL = 'flotr-examples-small', + CN_MOBILE = 'flotr-examples-mobile', + + T_THUMB = '
', + + TEMPLATE = '' + + '
' + + '
View All
' + + '
' + + '
' + + '
' + +Examples = function (o) { + + if (_.isUndefined(Flotr.ExampleList)) throw "Flotr.ExampleList not defined."; + + this.options = o; + this.list = Flotr.ExampleList; + this.current = null; + this.single = false; + + this._initNodes(); + this._example = new Flotr.Examples.Example({ + node : this._exampleNode + }); + + //console.time(EXAMPLE); + //console.profile(); + this._initExamples(); + //console.profileEnd(); + //console.timeEnd(EXAMPLE); +}; + +Examples.prototype = { + + examples : function () { + + var + styles = {cursor : 'pointer'}, + thumbsNode = this._thumbsNode, + list = this.list.get(), + that = this; + + var + order = [ + "basic", + "basic-axis", + "basic-bars", + "basic-bars-horizontal", + "basic-bar-stacked", + "basic-stacked-horizontal", + "basic-pie", + "basic-radar", + "basic-bubble", + "basic-candle", + "basic-legend", + "mouse-tracking", + "mouse-zoom", + "mouse-drag", + "basic-time", + "negative-values", + "click-example", + "download-image", + "download-data", + "advanced-titles", + "color-gradients", + "basic-timeline", + "advanced-markers" + ]; + + (function runner () { + var + key = order.shift(), + example = list[key]; + + if (example.type === 'profile' || example.type === 'test') return; + var node = $(T_THUMB); + node.data('example', example); + thumbsNode.append(node); + that._example.executeCallback(example, node); + node.click(function () {that._loadExample(example)}); + + if (order.length) setTimeout(runner, 20); + })(); + + function zoomHandler (e) { + var + node = $(e.currentTarget), + example = node.data('example'), + orientation = e.data.orientation; + if (orientation ^ node.hasClass(CN_HIGHLIGHT)) { + node.toggleClass(CN_HIGHLIGHT).css(styles); + that._example.executeCallback(example, node); + } + } + + thumbsNode.delegate(DOT + CN_THUMB, 'mouseenter', {orientation : true}, zoomHandler); + thumbsNode.delegate(DOT + CN_THUMB, 'mouseleave', {orientation : false}, zoomHandler); + + if ($(window).hashchange) { + $(window).hashchange(function () { + that._loadHash(); + }); + } + }, + + _loadExample : function (example) { + if (example) { + if (this._currentExample !== example) { + this._currentExample = example; + } else { + return; + } + + window.location.hash = '!'+(this.single ? 'single/' : '')+example.key; + + if (!scroller) { + this._thumbsNode.css({ + position: 'absolute', + height: '0px', + overflow: 'hidden', + width: '0px' + }); + this._resetNode.css({ + top: '16px' + }); + } + + this._examplesNode.addClass(CN_COLLAPSED); + this._exampleNode.show(); + this._example.setExample(example); + this._resize(); + $(document).scrollTop(0); + } + }, + + _reset : function () { + window.location.hash = ''; + + if (!scroller) { + this._thumbsNode.css({ + position: '', + height: '', + overflow: '', + width: '' + }); + } + + this._examplesNode.removeClass(CN_COLLAPSED); + this._thumbsNode.height(''); + this._exampleNode.hide(); + }, + + _initNodes : function () { + + var + node = $(this.options.node), + that = this, + examplesNode = $(TEMPLATE); + + that._resetNode = examplesNode.find(DOT+CN_RESET); + that._exampleNode = examplesNode.find(DOT+CN_CONTAINER); + that._thumbsNode = examplesNode.find(DOT+CN_THUMBS); + that._examplesNode = examplesNode; + + that._resetNode.click(function () { + that._reset(); + }); + + node.append(examplesNode); + + this._initResizer(); + }, + + _initResizer : function () { + + var + that = this, + node = that._examplesNode, + page = $(window), + currentClass; + + $(window).resize(applySize); + applySize(); + + function applySize () { + + var + height = page.height() - (that.options.thumbPadding || 0), + width = page.width(), + newClass; + + if (width > 1760) { + newClass = CN_LARGE; + that._thumbsNode.height(height); + } else if (width > 1140) { + newClass = CN_MEDIUM; + that._thumbsNode.height(height); + } else { + newClass = CN_SMALL; + that._thumbsNode.height(''); + } + + if (currentClass !== newClass) { + if (currentClass) + that._examplesNode.removeClass(currentClass); + that._examplesNode.addClass(newClass); + currentClass = newClass; + } + } + + this._resize = applySize; + }, + _initExamples : function () { + var + hash = window.location.hash, + example, params; + + hash = hash.substring(2); + params = hash.split('/'); + + if (params.length == 1) { + this.examples(); + if (hash) { + this._loadHash(); + } + } + else { + if (params[0] == 'single') { + this.single = true; + this._loadExample( + this.list.get(params[1]) + ); + } + } + }, + _loadHash : function () { + + var + hash = window.location.hash, + example; + + hash = hash.substring(2); + if (hash) { + example = this.list.get(hash); + this._loadExample(example); + } else { + this._reset(); + } + } +} + +var scroller = (function () { + + var + mobile = !!( + navigator.userAgent.match(/Android/i) || + navigator.userAgent.match(/webOS/i) || + navigator.userAgent.match(/iPhone/i) || + navigator.userAgent.match(/iPod/i) + ), + mozilla = !!$.browser.mozilla; + + return (!mobile || mozilla); +})(); + +Flotr.Examples = Examples; + +})(); + --- /dev/null +++ b/js/flotr2/examples/js/Profile.js @@ -1,1 +1,73 @@ +(function () { +var + D = Flotr.DOM, + E = Flotr.EventAdapter, + _ = Flotr._, + CLICK = 'click', + + ID_EXAMPLE_PROFILE = 'example-profile', + ID_EXAMPLES = 'examples', + +Profile = function (o) { + + if (_.isUndefined(Flotr.ExampleList)) throw "Flotr.ExampleList not defined."; + + this.editMode = 'off'; + this.list = Flotr.ExampleList; + this.current = null; + this.single = false; + + this.init(); +}; + +Profile.prototype = _.extend({}, Flotr.Examples.prototype, { + + examples : function () { + var + examplesNode = document.getElementById(ID_EXAMPLES), + listNode = D.node('
    '), + profileNode; + + _.each(this.list.getType('profile'), function (example) { + profileNode = D.node('
  • ' + example.name + '
  • '); + D.insert(listNode, profileNode); + E.observe(profileNode, CLICK, _.bind(function () { + this.example(example); + }, this)); + }, this); + + D.insert(examplesNode, listNode); + }, + + example : function (example) { + this._renderSource(example); + this.profileStart(example); + setTimeout(_.bind(function () { + this._renderGraph(example); + this.profileEnd(); + }, this), 50); + }, + + profileStart : function (example) { + var profileNode = document.getElementById(ID_EXAMPLE_PROFILE); + this._startTime = new Date(); + profileNode.innerHTML = '
    Profile started for "'+example.name+'"...
    '; + }, + + profileEnd : function (example) { + var + profileNode = document.getElementById(ID_EXAMPLE_PROFILE); + profileTime = (new Date()) - this._startTime; + + this._startTime = null; + + profileNode.innerHTML += '
    Profile complete: '+profileTime+'ms
    '; + } + +}); + +Flotr.Profile = Profile; + +})(); + --- /dev/null +++ b/js/flotr2/examples/js/examples/advanced-markers.js @@ -1,1 +1,76 @@ +(function () { +Flotr.ExampleList.add({ + key : 'advanced-markers', + name : 'Advanced Markers', + callback : advanced_markers, + timeout : 150 +}); + +function advanced_markers (container) { + + var + xmark = new Image(), + checkmark = new Image(), + bars = { + data: [], + bars: { + show: true, + barWidth: 0.6, + lineWidth: 0, + fillOpacity: 0.8 + } + }, markers = { + data: [], + markers: { + show: true, + position: 'ct', + labelFormatter: function (o) { + return (o.y >= 5) ? checkmark : xmark; + } + } + }, + flotr = Flotr, + point, + graph, + i; + + + for (i = 0; i < 8; i++) { + point = [i, Math.ceil(Math.random() * 10)]; + bars.data.push(point); + markers.data.push(point); + } + + var runner = function () { + if (!xmark.complete || !checkmark.complete) { + setTimeout(runner, 50); + return; + } + + graph = flotr.draw( + container, + [bars, markers], { + yaxis: { + min: 0, + max: 11 + }, + xaxis: { + min: -0.5, + max: 7.5 + }, + grid: { + verticalLines: false + } + } + ); + } + + xmark.onload = runner; + xmark.src = 'images/xmark.png'; + checkmark.src = 'images/checkmark.png'; +}; + +})(); + + --- /dev/null +++ b/js/flotr2/examples/js/examples/advanced-titles.js @@ -1,1 +1,67 @@ +(function () { +Flotr.ExampleList.add({ + key : 'advanced-titles', + name : 'Advanced Titles', + callback : advanced_titles +}); + +function advanced_titles (container) { + + var + d1 = [], + d2 = [], + d3 = [], + d4 = [], + d5 = [], + graph, + i; + + for (i = 0; i <= 10; i += 0.1) { + d1.push([i, 4 + Math.pow(i,1.5)]); + d2.push([i, Math.pow(i,3)]); + d3.push([i, i*5+3*Math.sin(i*4)]); + d4.push([i, i]); + if (i.toFixed(1)%1 == 0) { + d5.push([i, 2*i]); + } + } + + // Draw the graph. + graph = Flotr.draw( + container,[ + { data : d1, label : 'y = 4 + x^(1.5)', lines : { fill : true } }, + { data : d2, label : 'y = x^3', yaxis : 2 }, + { data : d3, label : 'y = 5x + 3sin(4x)' }, + { data : d4, label : 'y = x' }, + { data : d5, label : 'y = 2x', lines : { show : true }, points : { show : true } } + ], { + title : 'Advanced Titles Example', + subtitle : 'You can save me as an image', + xaxis : { + noTicks : 7, + tickFormatter : function (n) { return '('+n+')'; }, + min : 1, + max : 7.5, + labelsAngle : 45, + title : 'x Axis' + }, + yaxis : { + ticks : [[0, "Lower"], 10, 20, 30, [40, "Upper"]], + max : 40, + title : 'y = f(x)' + }, + y2axis : { color : '#FF0000', max : 500, title : 'y = x^3' }, + grid : { + verticalLines : false, + backgroundColor : 'white' + }, + HtmlText : false, + legend : { + position : 'nw' + } + }); +}; + +})(); + --- /dev/null +++ b/js/flotr2/examples/js/examples/basic-axis.js @@ -1,1 +1,69 @@ +(function () { +Flotr.ExampleList.add({ + key : 'basic-axis', + name : 'Basic Axis', + callback : basic_axis +}); + +function basic_axis (container) { + + var + d1 = [], + d2 = [], + d3 = [], + d4 = [], + d5 = [], // Data + ticks = [[ 0, "Lower"], 10, 20, 30, [40, "Upper"]], // Ticks for the Y-Axis + graph; + + for(var i = 0; i <= 10; i += 0.1){ + d1.push([i, 4 + Math.pow(i,1.5)]); + d2.push([i, Math.pow(i,3)]); + d3.push([i, i*5+3*Math.sin(i*4)]); + d4.push([i, i]); + if( i.toFixed(1)%1 == 0 ){ + d5.push([i, 2*i]); + } + } + + d3[30][1] = null; + d3[31][1] = null; + + function ticksFn (n) { return '('+n+')'; } + + graph = Flotr.draw(container, [ + { data : d1, label : 'y = 4 + x^(1.5)', lines : { fill : true } }, + { data : d2, label : 'y = x^3'}, + { data : d3, label : 'y = 5x + 3sin(4x)'}, + { data : d4, label : 'y = x'}, + { data : d5, label : 'y = 2x', lines : { show : true }, points : { show : true } } + ], { + xaxis : { + noTicks : 7, // Display 7 ticks. + tickFormatter : ticksFn, // Displays tick values between brackets. + min : 1, // Part of the series is not displayed. + max : 7.5 // Part of the series is not displayed. + }, + yaxis : { + ticks : ticks, // Set Y-Axis ticks + max : 40 // Maximum value along Y-Axis + }, + grid : { + verticalLines : false, + backgroundColor : { + colors : [[0,'#fff'], [1,'#ccc']], + start : 'top', + end : 'bottom' + } + }, + legend : { + position : 'nw' + }, + title : 'Basic Axis example', + subtitle : 'This is a subtitle' + }); +} + +})(); + --- /dev/null +++ b/js/flotr2/examples/js/examples/basic-bars-stacked.js @@ -1,1 +1,61 @@ +(function () { +Flotr.ExampleList.add({ + key : 'basic-bar-stacked', + name : 'Stacked Bars', + callback : bars_stacked +}); + +Flotr.ExampleList.add({ + key : 'basic-stacked-horizontal', + name : 'Stacked Horizontal Bars', + args : [true], + callback : bars_stacked, + tolerance : 5 +}); + +function bars_stacked (container, horizontal) { + + var + d1 = [], + d2 = [], + d3 = [], + graph, i; + + for (i = -10; i < 10; i++) { + if (horizontal) { + d1.push([Math.random(), i]); + d2.push([Math.random(), i]); + d3.push([Math.random(), i]); + } else { + d1.push([i, Math.random()]); + d2.push([i, Math.random()]); + d3.push([i, Math.random()]); + } + } + + graph = Flotr.draw(container,[ + { data : d1, label : 'Serie 1' }, + { data : d2, label : 'Serie 2' }, + { data : d3, label : 'Serie 3' } + ], { + legend : { + backgroundColor : '#D2E8FF' // Light blue + }, + bars : { + show : true, + stacked : true, + horizontal : horizontal, + barWidth : 0.6, + lineWidth : 1, + shadowSize : 0 + }, + grid : { + verticalLines : horizontal, + horizontalLines : !horizontal + } + }); +} + +})(); + --- /dev/null +++ b/js/flotr2/examples/js/examples/basic-bars.js @@ -1,1 +1,69 @@ +(function () { +Flotr.ExampleList.add({ + key : 'basic-bars', + name : 'Basic Bars', + callback : basic_bars +}); + +Flotr.ExampleList.add({ + key : 'basic-bars-horizontal', + name : 'Horizontal Bars', + args : [true], + callback : basic_bars, + tolerance : 5 +}); + +function basic_bars (container, horizontal) { + + var + horizontal = (horizontal ? true : false), // Show horizontal bars + d1 = [], // First data series + d2 = [], // Second data series + point, // Data point variable declaration + i; + + for (i = 0; i < 4; i++) { + + if (horizontal) { + point = [Math.ceil(Math.random()*10), i]; + } else { + point = [i, Math.ceil(Math.random()*10)]; + } + + d1.push(point); + + if (horizontal) { + point = [Math.ceil(Math.random()*10), i+0.5]; + } else { + point = [i+0.5, Math.ceil(Math.random()*10)]; + } + + d2.push(point); + }; + + // Draw the graph + Flotr.draw( + container, + [d1, d2], + { + bars : { + show : true, + horizontal : horizontal, + shadowSize : 0, + barWidth : 0.5 + }, + mouse : { + track : true, + relative : true + }, + yaxis : { + min : 0, + autoscaleMargin : 1 + } + } + ); +} + +})(); + --- /dev/null +++ b/js/flotr2/examples/js/examples/basic-bubble.js @@ -1,1 +1,33 @@ +(function () { +Flotr.ExampleList.add({ + key : 'basic-bubble', + name : 'Basic Bubble', + callback : basic_bubble +}); + +function basic_bubble (container) { + + var + d1 = [], + d2 = [], + point, graph, i; + + for (i = 0; i < 10; i++ ){ + point = [i, Math.ceil(Math.random()*10), Math.ceil(Math.random()*10)]; + d1.push(point); + + point = [i, Math.ceil(Math.random()*10), Math.ceil(Math.random()*10)]; + d2.push(point); + } + + // Draw the graph + graph = Flotr.draw(container, [d1, d2], { + bubbles : { show : true, baseRadius : 5 }, + xaxis : { min : -4, max : 14 }, + yaxis : { min : -4, max : 14 } + }); +} + +})(); + --- /dev/null +++ b/js/flotr2/examples/js/examples/basic-candle.js @@ -1,1 +1,34 @@ +(function () { +Flotr.ExampleList.add({ + key : 'basic-candle', + name : 'Basic Candle', + callback : basic_candle +}); + +function basic_candle (container) { + + var + d1 = [], + price = 3.206, + graph, + i, a, b, c; + + for (i = 0; i < 50; i++) { + a = Math.random(); + b = Math.random(); + c = (Math.random() * (a + b)) - b; + d1.push([i, price, price + a, price - b, price + c]); + price = price + c; + } + + // Graph + graph = Flotr.draw(container, [ d1 ], { + candles : { show : true, candleWidth : 0.6 }, + xaxis : { noTicks : 10 } + }); +} + +})(); + + --- /dev/null +++ b/js/flotr2/examples/js/examples/basic-legend.js @@ -1,1 +1,49 @@ +(function () { +Flotr.ExampleList.add({ + key : 'basic-legend', + name : 'Basic Legend', + callback : basic_legend +}); + +function basic_legend (container) { + + var + d1 = [], + d2 = [], + d3 = [], + data, + graph, i; + + // Data Generation + for (i = 0; i < 15; i += 0.5) { + d1.push([i, i + Math.sin(i+Math.PI)]); + d2.push([i, i]); + d3.push([i, 15-Math.cos(i)]); + } + + data = [ + { data : d1, label :'x + sin(x+π)' }, + { data : d2, label :'x' }, + { data : d3, label :'15 - cos(x)' } + ]; + + + // This function prepend each label with 'y = ' + function labelFn (label) { + return 'y = ' + label; + } + + // Draw graph + graph = Flotr.draw(container, data, { + legend : { + position : 'se', // Position the legend 'south-east'. + labelFormatter : labelFn, // Format the labels. + backgroundColor : '#D2E8FF' // A light blue background color. + }, + HtmlText : false + }); +} + +})(); + --- /dev/null +++ b/js/flotr2/examples/js/examples/basic-pie.js @@ -1,1 +1,48 @@ +(function () { +Flotr.ExampleList.add({ + key : 'basic-pie', + name : 'Basic Pie', + callback : basic_pie +}); + +function basic_pie (container) { + + var + d1 = [[0, 4]], + d2 = [[0, 3]], + d3 = [[0, 1.03]], + d4 = [[0, 3.5]], + graph; + + graph = Flotr.draw(container, [ + { data : d1, label : 'Comedy' }, + { data : d2, label : 'Action' }, + { data : d3, label : 'Romance', + pie : { + explode : 50 + } + }, + { data : d4, label : 'Drama' } + ], { + HtmlText : false, + grid : { + verticalLines : false, + horizontalLines : false + }, + xaxis : { showLabels : false }, + yaxis : { showLabels : false }, + pie : { + show : true, + explode : 6 + }, + mouse : { track : true }, + legend : { + position : 'se', + backgroundColor : '#D2E8FF' + } + }); +} + +})(); + --- /dev/null +++ b/js/flotr2/examples/js/examples/basic-radar.js @@ -1,1 +1,37 @@ +(function () { +Flotr.ExampleList.add({ + key : 'basic-radar', + name : 'Basic Radar', + callback : basic_radar +}); + +function basic_radar (container) { + + // Fill series s1 and s2. + var + s1 = { label : 'Actual', data : [[0, 3], [1, 8], [2, 5], [3, 5], [4, 3], [5, 9]] }, + s2 = { label : 'Target', data : [[0, 8], [1, 7], [2, 8], [3, 2], [4, 4], [5, 7]] }, + graph, ticks; + + // Radar Labels + ticks = [ + [0, "Statutory"], + [1, "External"], + [2, "Videos"], + [3, "Yippy"], + [4, "Management"], + [5, "oops"] + ]; + + // Draw the graph. + graph = Flotr.draw(container, [ s1, s2 ], { + radar : { show : true}, + grid : { circular : true, minorHorizontalLines : true}, + yaxis : { min : 0, max : 10, minorTickFreq : 2}, + xaxis : { ticks : ticks} + }); +} + +})(); + --- /dev/null +++ b/js/flotr2/examples/js/examples/basic-stacked.js @@ -1,1 +1,33 @@ +(function () { +Flotr.ExampleList.add({ + key : 'basic-stacked', + name : 'Basic Stacked', + callback : basic_stacked, + type : 'test' +}); + +function basic_stacked (container) { + + var + d1 = [[0, 3], [4, 8], [8, 2], [9, 3]], // First data series + d2 = [[0, 2], [4, 3], [8, 8], [9, 4]], // Second data series + i, graph; + + // Draw Graph + graph = Flotr.draw(container, [ d1, d2 ], { + lines: { + show : true, + stacked: true + }, + xaxis: { + minorTickFreq: 4 + }, + grid: { + minorVerticalLines: true + } + }); +} + +})(); + --- /dev/null +++ b/js/flotr2/examples/js/examples/basic-stepped.js @@ -1,1 +1,45 @@ +(function () { +Flotr.ExampleList.add({ + key : 'basic-stepped', + name : 'Basic Stepped', + callback : basic_stepped, + type : 'test' +}); + +function basic_stepped (container) { + + var + d1 = [[0, 3], [4, 8], [8, 5], [9, 13]], // First data series + d2 = [], // Second data series + i, graph; + + // Generate first data set + for (i = 0; i < 14; i += 0.5) { + d2.push([i, Math.sin(i)]); + } + + // Draw Graph + graph = Flotr.draw(container, [ d1, d2 ], { + lines: { + steps : true, + show : true + }, + xaxis: { + minorTickFreq: 4 + }, + yaxis: { + autoscale: true + }, + grid: { + minorVerticalLines: true + }, + mouse : { + track : true, + relative : true + } + }); +} + +})(); + --- /dev/null +++ b/js/flotr2/examples/js/examples/basic-time.js @@ -1,1 +1,65 @@ +(function () { +Flotr.ExampleList.add({ + key : 'basic-time', + name : 'Basic Time', + callback : basic_time, + description : "

    Select an area of the graph to zoom. Click to reset the chart.

    " +}); + +function basic_time (container) { + + var + d1 = [], + start = new Date("2009/01/01 01:00").getTime(), + options, + graph, + i, x, o; + + for (i = 0; i < 100; i++) { + x = start+(i*1000*3600*24*36.5); + d1.push([x, i+Math.random()*30+Math.sin(i/20+Math.random()*2)*20+Math.sin(i/10+Math.random())*10]); + } + + options = { + xaxis : { + mode : 'time', + labelsAngle : 45 + }, + selection : { + mode : 'x' + }, + HtmlText : false, + title : 'Time' + }; + + // Draw graph with default options, overwriting with passed options + function drawGraph (opts) { + + // Clone the options, so the 'options' variable always keeps intact. + o = Flotr._.extend(Flotr._.clone(options), opts || {}); + + // Return a new graph. + return Flotr.draw( + container, + [ d1 ], + o + ); + } + + graph = drawGraph(); + + Flotr.EventAdapter.observe(container, 'flotr:select', function(area){ + // Draw selected area + graph = drawGraph({ + xaxis : { min : area.x1, max : area.x2, mode : 'time', labelsAngle : 45 }, + yaxis : { min : area.y1, max : area.y2 } + }); + }); + + // When graph is clicked, draw the graph with default area. + Flotr.EventAdapter.observe(container, 'flotr:click', function () { graph = drawGraph(); }); +}; + +})(); + --- /dev/null +++ b/js/flotr2/examples/js/examples/basic-timeline.js @@ -1,1 +1,67 @@ +(function () { +Flotr.ExampleList.add({ + key : 'basic-timeline', + name : 'Basic Timeline', + callback : basic_timeline +}); + +function basic_timeline (container) { + + var + d1 = [[1, 4, 5]], + d2 = [[3.2, 3, 4]], + d3 = [[1.9, 2, 2], [5, 2, 3.3]], + d4 = [[1.55, 1, 9]], + d5 = [[5, 0, 2.3]], + data = [], + timeline = { show : true, barWidth : .5 }, + markers = [], + labels = ['Obama', 'Bush', 'Clinton', 'Palin', 'McCain'], + i, graph, point; + + // Timeline + Flotr._.each([d1, d2, d3, d4, d5], function (d) { + data.push({ + data : d, + timeline : Flotr._.clone(timeline) + }); + }); + + // Markers + Flotr._.each([d1, d2, d3, d4, d5], function (d) { + point = d[0]; + markers.push([point[0], point[1]]); + }); + data.push({ + data: markers, + markers: { + show: true, + position: 'rm', + fontSize: 11, + labelFormatter : function (o) { return labels[o.index]; } + } + }); + + // Draw Graph + graph = Flotr.draw(container, data, { + xaxis: { + noTicks: 3, + tickFormatter: function (x) { + var + x = parseInt(x), + months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; + return months[(x-1)%12]; + } + }, + yaxis: { + showLabels : false + }, + grid: { + horizontalLines : false + } + }); +} + +})(); + --- /dev/null +++ b/js/flotr2/examples/js/examples/basic.js @@ -1,1 +1,33 @@ +(function () { +Flotr.ExampleList.add({ + key : 'basic', + name : 'Basic', + callback : basic +}); + +function basic (container) { + + var + d1 = [[0, 3], [4, 8], [8, 5], [9, 13]], // First data series + d2 = [], // Second data series + i, graph; + + // Generate first data set + for (i = 0; i < 14; i += 0.5) { + d2.push([i, Math.sin(i)]); + } + + // Draw Graph + graph = Flotr.draw(container, [ d1, d2 ], { + xaxis: { + minorTickFreq: 4 + }, + grid: { + minorVerticalLines: true + } + }); +} + +})(); + --- /dev/null +++ b/js/flotr2/examples/js/examples/click-example.js @@ -1,1 +1,42 @@ +(function () { +Flotr.ExampleList.add({ + key : 'click-example', + name : 'Click Example', + callback : click_example +}); + +function click_example (container) { + + var + d1 = [[0,0]], // Point at origin + options, + graph; + + options = { + xaxis: {min: 0, max: 15}, + yaxis: {min: 0, max: 15}, + lines: {show: true}, + points: {show: true}, + mouse: {track:true}, + title: 'Click Example' + }; + + graph = Flotr.draw(container, [d1], options); + + // Add a point to the series and redraw the graph + Flotr.EventAdapter.observe(container, 'flotr:click', function(position){ + + // Add a point to the series at the location of the click + d1.push([position.x, position.y]); + + // Sort the series. + d1 = d1.sort(function (a, b) { return a[0] - b[0]; }); + + // Redraw the graph, with the new series. + graph = Flotr.draw(container, [d1], options); + }); +}; + +})(); + --- /dev/null +++ b/js/flotr2/examples/js/examples/color-gradients.js @@ -1,1 +1,75 @@ +(function () { +Flotr.ExampleList.add({ + key : 'color-gradients', + name : 'Color Gradients', + callback : color_gradients +}); + +function color_gradients (container) { + + var + bars = { + data: [], + bars: { + show: true, + barWidth: 0.8, + lineWidth: 0, + fillColor: { + colors: ['#CB4B4B', '#fff'], + start: 'top', + end: 'bottom' + }, + fillOpacity: 0.8 + } + }, markers = { + data: [], + markers: { + show: true, + position: 'ct' + } + }, lines = { + data: [], + lines: { + show: true, + fillColor: ['#00A8F0', '#fff'], + fill: true, + fillOpacity: 1 + } + }, + point, + graph, + i; + + for (i = 0; i < 8; i++) { + point = [i, Math.ceil(Math.random() * 10)]; + bars.data.push(point); + markers.data.push(point); + } + + for (i = -1; i < 9; i += 0.01){ + lines.data.push([i, i*i/8+2]); + } + + graph = Flotr.draw( + container, + [lines, bars, markers], { + yaxis: { + min: 0, + max: 11 + }, + xaxis: { + min: -0.5, + max: 7.5 + }, + grid: { + verticalLines: false, + backgroundColor: ['#fff', '#ccc'] + } + } + ); +}; + +})(); + + --- /dev/null +++ b/js/flotr2/examples/js/examples/download-data.js @@ -1,1 +1,65 @@ +(function () { +Flotr.ExampleList.add({ + key : 'download-data', + name : 'Download Data', + callback : download_data +}); + +function download_data (container) { + + var + d1 = [], + d2 = [], + d3 = [], + d4 = [], + d5 = [], + graph, + i,x; + + for (i = 0; i <= 100; i += 1) { + x = i / 10; + d1.push([x, 4 + Math.pow(x,1.5)]); + d2.push([x, Math.pow(x,3)]); + d3.push([x, i*5+3*Math.sin(x*4)]); + d4.push([x, x]); + if(x%1 === 0 ){ + d5.push([x, 2*x]); + } + } + + // Draw the graph. + graph = Flotr.draw( + container, [ + { data : d1, label : 'y = 4 + x^(1.5)', lines : { fill : true } }, + { data : d2, label : 'y = x^3' }, + { data : d3, label : 'y = 5x + 3sin(4x)' }, + { data : d4, label : 'y = x' }, + { data : d5, label : 'y = 2x', lines : { show : true }, points : { show : true } } + ],{ + xaxis : { + noTicks : 7, + tickFormatter : function (n) { return '('+n+')'; }, + min: 1, // Part of the series is not displayed. + max: 7.5 + }, + yaxis : { + ticks : [[ 0, "Lower"], 10, 20, 30, [40, "Upper"]], + max : 40 + }, + grid : { + verticalLines : false, + backgroundColor : 'white' + }, + legend : { + position : 'nw' + }, + spreadsheet : { + show : true, + tickFormatter : function (e) { return e+''; } + } + }); +}; + +})(); + --- /dev/null +++ b/js/flotr2/examples/js/examples/download-image.js @@ -1,1 +1,98 @@ +(function () { +Flotr.ExampleList.add({ + key : 'download-image', + name : 'Download Image', + callback : download_image, + description : '' + + '
    ' + + '' + + '' + + + '' + + '' + + '' + + '
    ' +}); + +function download_image (container) { + + var + d1 = [], + d2 = [], + d3 = [], + d4 = [], + d5 = [], + graph, + i; + + for (i = 0; i <= 10; i += 0.1) { + d1.push([i, 4 + Math.pow(i,1.5)]); + d2.push([i, Math.pow(i,3)]); + d3.push([i, i*5+3*Math.sin(i*4)]); + d4.push([i, i]); + if( i.toFixed(1)%1 == 0 ){ + d5.push([i, 2*i]); + } + } + + // Draw the graph + graph = Flotr.draw( + container,[ + {data:d1, label:'y = 4 + x^(1.5)', lines:{fill:true}}, + {data:d2, label:'y = x^3', yaxis:2}, + {data:d3, label:'y = 5x + 3sin(4x)'}, + {data:d4, label:'y = x'}, + {data:d5, label:'y = 2x', lines: {show: true}, points: {show: true}} + ],{ + title: 'Download Image Example', + subtitle: 'You can save me as an image', + xaxis:{ + noTicks: 7, // Display 7 ticks. + tickFormatter: function(n){ return '('+n+')'; }, // => displays tick values between brackets. + min: 1, // => part of the series is not displayed. + max: 7.5, // => part of the series is not displayed. + labelsAngle: 45, + title: 'x Axis' + }, + yaxis:{ + ticks: [[0, "Lower"], 10, 20, 30, [40, "Upper"]], + max: 40, + title: 'y = f(x)' + }, + y2axis:{color:'#FF0000', max: 500, title: 'y = x^3'}, + grid:{ + verticalLines: false, + backgroundColor: 'white' + }, + HtmlText: false, + legend: { + position: 'nw' + } + }); + + this.CurrentExample = function (operation) { + + var + format = $('#image-download input:radio[name=format]:checked').val(); + if (Flotr.isIE && Flotr.isIE < 9) { + alert( + "Your browser doesn't allow you to get a bitmap image from the plot, " + + "you can only get a VML image that you can use in Microsoft Office.
    " + ); + } + + if (operation == 'to-image') { + graph.download.saveImage(format, null, null, true) + } else if (operation == 'download') { + graph.download.saveImage(format); + } else if (operation == 'reset') { + graph.download.restoreCanvas(); + } + }; + + return graph; +}; + +})(); + --- /dev/null +++ b/js/flotr2/examples/js/examples/mouse-drag.js @@ -1,1 +1,78 @@ +(function () { +Flotr.ExampleList.add({ + key : 'mouse-drag', + name : 'Mouse Drag', + callback : mouse_drag +}); + +function mouse_drag (container) { + + var + d1 = [], + d2 = [], + d3 = [], + options, + graph, + start, + i; + + for (i = -40; i < 40; i += 0.5) { + d1.push([i, Math.sin(i)+3*Math.cos(i)]); + d2.push([i, Math.pow(1.1, i)]); + d3.push([i, 40 - i+Math.random()*10]); + } + + options = { + xaxis: {min: 0, max: 20}, + title : 'Mouse Drag' + }; + + // Draw graph with default options, overwriting with passed options + function drawGraph (opts) { + + // Clone the options, so the 'options' variable always keeps intact. + var o = Flotr._.extend(Flotr._.clone(options), opts || {}); + + // Return a new graph. + return Flotr.draw( + container, + [ d1, d2, d3 ], + o + ); + } + + graph = drawGraph(); + + function initializeDrag (e) { + start = graph.getEventPosition(e); + Flotr.EventAdapter.observe(document, 'mousemove', move); + Flotr.EventAdapter.observe(document, 'mouseup', stopDrag); + } + + function move (e) { + var + end = graph.getEventPosition(e), + xaxis = graph.axes.x, + offset = start.x - end.x; + + graph = drawGraph({ + xaxis : { + min : xaxis.min + offset, + max : xaxis.max + offset + } + }); + // @todo: refector initEvents in order not to remove other observed events + Flotr.EventAdapter.observe(graph.overlay, 'mousedown', initializeDrag); + } + + function stopDrag () { + Flotr.EventAdapter.stopObserving(document, 'mousemove', move); + } + + Flotr.EventAdapter.observe(graph.overlay, 'mousedown', initializeDrag); + +}; + +})(); + --- /dev/null +++ b/js/flotr2/examples/js/examples/mouse-tracking.js @@ -1,1 +1,52 @@ +(function () { +Flotr.ExampleList.add({ + key : 'mouse-tracking', + name : 'Mouse Tracking', + callback : mouse_tracking +}); + +function mouse_tracking (container) { + + var + d1 = [], + d2 = [], + d3 = [], + graph, i; + + for (i = 0; i < 20; i += 0.5) { + d1.push([i, 2*i]); + d2.push([i, i*1.5+1.5*Math.sin(i)]); + d3.push([i, 3*Math.cos(i)+10]); + } + + graph = Flotr.draw( + container, + [ + { + data : d1, + mouse : { track : false } // Disable mouse tracking for d1 + }, + d2, + d3 + ], + { + mouse : { + track : true, // Enable mouse tracking + lineColor : 'purple', + relative : true, + position : 'ne', + sensibility : 1, + trackDecimals : 2, + trackFormatter : function (o) { return 'x = ' + o.x +', y = ' + o.y; } + }, + crosshair : { + mode : 'xy' + } + } + ); + +}; + +})(); + --- /dev/null +++ b/js/flotr2/examples/js/examples/mouse-zoom.js @@ -1,1 +1,64 @@ +(function () { +Flotr.ExampleList.add({ + key : 'mouse-zoom', + name : 'Mouse Zoom', + callback : mouse_zoom, + description : "

    Select an area of the graph to zoom. Click to reset the chart.

    " +}); + +function mouse_zoom (container) { + + var + d1 = [], + d2 = [], + d3 = [], + options, + graph, + i; + + for (i = 0; i < 40; i += 0.5) { + d1.push([i, Math.sin(i)+3*Math.cos(i)]); + d2.push([i, Math.pow(1.1, i)]); + d3.push([i, 40 - i+Math.random()*10]); + } + + options = { + selection : { mode : 'x', fps : 30 }, + title : 'Mouse Zoom' + }; + + // Draw graph with default options, overwriting with passed options + function drawGraph (opts) { + + // Clone the options, so the 'options' variable always keeps intact. + var o = Flotr._.extend(Flotr._.clone(options), opts || {}); + + // Return a new graph. + return Flotr.draw( + container, + [ d1, d2, d3 ], + o + ); + } + + // Actually draw the graph. + graph = drawGraph(); + + // Hook into the 'flotr:select' event. + Flotr.EventAdapter.observe(container, 'flotr:select', function (area) { + + // Draw graph with new area + graph = drawGraph({ + xaxis: {min:area.x1, max:area.x2}, + yaxis: {min:area.y1, max:area.y2} + }); + }); + + // When graph is clicked, draw the graph with default area. + Flotr.EventAdapter.observe(container, 'flotr:click', function () { drawGraph(); }); +}; + +})(); + + --- /dev/null +++ b/js/flotr2/examples/js/examples/negative-values.js @@ -1,1 +1,65 @@ +(function () { +Flotr.ExampleList.add({ + key : 'negative-values', + name : 'Negative Values', + callback : negative_values +}); + +function negative_values (container) { + + var + d0 = [], // Line through y = 0 + d1 = [], // Random data presented as a scatter plot. + d2 = [], // A regression line for the scatter. + sx = 0, + sy = 0, + sxy = 0, + sxsq = 0, + xmean, + ymean, + alpha, + beta, + n, x, y; + + for (n = 0; n < 20; n++){ + + x = n; + y = x + Math.random()*8 - 15; + + d0.push([x, 0]); + d1.push([x, y]); + + // Computations used for regression line + sx += x; + sy += y; + sxy += x*y; + sxsq += Math.pow(x,2); + } + + xmean = sx/n; + ymean = sy/n; + beta = ((n*sxy) - (sx*sy))/((n*sxsq)-(Math.pow(sx,2))); + alpha = ymean - (beta * xmean); + + // Compute the regression line. + for (n = 0; n < 20; n++){ + d2.push([n, alpha + beta*n]) + } + + // Draw the graph + graph = Flotr.draw( + container, [ + { data : d0, shadowSize : 0, color : '#545454' }, // Horizontal + { data : d1, label : 'y = x + (Math.random() * 8) - 15', points : { show : true } }, // Scatter + { data : d2, label : 'y = ' + alpha.toFixed(2) + ' + ' + beta.toFixed(2) + '*x' } // Regression + ], + { + legend : { position : 'se', backgroundColor : '#D2E8FF' }, + title : 'Negative Values' + } + ); +}; + +})(); + --- /dev/null +++ b/js/flotr2/examples/js/examples/profile-bars.js @@ -1,1 +1,70 @@ +(function () { +Flotr.ExampleList.add({ + key : 'profile-bars', + name : 'Profile Bars', + type : 'profile', + callback : profile_bars +}); + +/* +Flotr.ExampleList.add({ + key : 'basic-bars-horizontal', + name : 'Horizontal Bars', + args : [true], + callback : basic_bars +}); +*/ + +function profile_bars (container, horizontal) { + + var + horizontal = (horizontal ? true : false), // Show horizontal bars + d1 = [], // First data series + d2 = [], // Second data series + point, // Data point variable declaration + i; + + for (i = 0; i < 5000; i++) { + + if (horizontal) { + point = [Math.ceil(Math.random()*10), i]; + } else { + point = [i, Math.ceil(Math.random()*10)]; + } + + d1.push(point); + + if (horizontal) { + point = [Math.ceil(Math.random()*10), i+0.5]; + } else { + point = [i+0.5, Math.ceil(Math.random()*10)]; + } + + d2.push(point); + }; + + // Draw the graph + Flotr.draw( + container, + [d1, d2], + { + bars : { + show : true, + horizontal : horizontal, + barWidth : 0.5 + }, + mouse : { + track : true, + relative : true + }, + yaxis : { + min : 0, + autoscaleMargin : 1 + } + } + ); +} + +})(); + --- /dev/null +++ b/js/flotr2/examples/js/includes.dev.js @@ -1,1 +1,92 @@ +yepnope([ + // Libs + '../lib/bean-min.js', + '../lib/underscore-min.js', + { + test : (navigator.appVersion.indexOf("MSIE") != -1 && parseFloat(navigator.appVersion.split("MSIE")[1]) < 9), + // Load for IE < 9 + yep : [ + '../lib/excanvas.js', + '../lib/base64.js', + '../lib/canvastext.js' + ] + }, + 'lib/codemirror/lib/codemirror.js', + 'lib/codemirror/mode/javascript/javascript.js', + 'lib/beautify.js', + 'lib/randomseed.js', + 'lib/jquery-1.7.1.min.js', + 'lib/jquery.ba-hashchange.min.js', + // Flotr + '../js/Flotr.js', + '../js/DefaultOptions.js', + '../js/Color.js', + '../js/Date.js', + '../js/DOM.js', + '../js/EventAdapter.js', + '../js/Text.js', + '../js/Graph.js', + '../js/Axis.js', + '../js/Series.js', + '../js/types/lines.js', + '../js/types/bars.js', + '../js/types/points.js', + '../js/types/pie.js', + '../js/types/candles.js', + '../js/types/markers.js', + '../js/types/radar.js', + '../js/types/bubbles.js', + '../js/types/gantt.js', + '../js/types/timeline.js', + '../js/plugins/download.js', + '../js/plugins/selection.js', + '../js/plugins/spreadsheet.js', + '../js/plugins/grid.js', + '../js/plugins/hit.js', + '../js/plugins/crosshair.js', + '../js/plugins/labels.js', + '../js/plugins/legend.js', + '../js/plugins/titles.js', + + // Examples + 'js/Examples.js', + 'js/ExampleList.js', + 'js/Example.js', + 'js/Editor.js', + 'js/Profile.js', + 'js/examples/basic.js', + 'js/examples/basic-axis.js', + 'js/examples/basic-bars.js', + 'js/examples/basic-bars-stacked.js', + 'js/examples/basic-pie.js', + 'js/examples/basic-radar.js', + 'js/examples/basic-bubble.js', + 'js/examples/basic-candle.js', + 'js/examples/basic-legend.js', + 'js/examples/mouse-tracking.js', + 'js/examples/mouse-zoom.js', + 'js/examples/mouse-drag.js', + 'js/examples/basic-time.js', + 'js/examples/negative-values.js', + 'js/examples/click-example.js', + 'js/examples/download-image.js', + 'js/examples/download-data.js', + 'js/examples/advanced-titles.js', + 'js/examples/color-gradients.js', + 'js/examples/profile-bars.js', + 'js/examples/basic-timeline.js', + 'js/examples/advanced-markers.js', + + { complete : function () { + if (Flotr.ExamplesCallback) { + Flotr.ExamplesCallback(); + } else { + Examples = new Flotr.Examples({ + node : document.getElementById('examples') + }); + } + } + } +]); + --- /dev/null +++ b/js/flotr2/examples/js/includes.min.js @@ -1,1 +1,34 @@ +yepnope([ + { + test : (navigator.appVersion.indexOf("MSIE") != -1 && parseFloat(navigator.appVersion.split("MSIE")[1]) < 9), + // Load for IE < 9 + yep : [ + '../flotr2.ie.min.js' + ] + }, + '../flotr2.min.js', + 'lib/codemirror/lib/codemirror.js', + 'lib/codemirror/mode/javascript/javascript.js', + 'lib/beautify.js', + 'lib/randomseed.js', + 'lib/jquery-1.7.1.min.js', + 'lib/jquery.ba-hashchange.min.js', + + // Examples + '../flotr2.examples.min.js', + '../flotr2.examples.types.js', + + { complete : function () { + if (Flotr.ExamplesCallback) { + Flotr.ExamplesCallback(); + } else { + Examples = new Flotr.Examples({ + node : document.getElementById('examples') + }); + } + } + } +]); + + --- /dev/null +++ b/js/flotr2/examples/lib/beautify.js @@ -1,1 +1,1171 @@ - +/*jslint onevar: false, plusplus: false */ +/* + + JS Beautifier +--------------- + + + Written by Einar Lielmanis, + http://jsbeautifier.org/ + + Originally converted to javascript by Vital, + "End braces on own line" added by Chris J. Shull, + + You are free to use this in any way you want, in case you find this useful or working for you. + + Usage: + js_beautify(js_source_text); + js_beautify(js_source_text, options); + + The options are: + indent_size (default 4) — indentation size, + indent_char (default space) — character to indent with, + preserve_newlines (default true) — whether existing line breaks should be preserved, + preserve_max_newlines (default unlimited) - maximum number of line breaks to be preserved in one chunk, + + jslint_happy (default false) — if true, then jslint-stricter mode is enforced. + + jslint_happy !jslint_happy + --------------------------------- + function () function() + + brace_style (default "collapse") - "collapse" | "expand" | "end-expand" + put braces on the same line as control statements (default), or put braces on own line (Allman / ANSI style), or just put end braces on own line. + + e.g + + js_beautify(js_source_text, { + 'indent_size': 1, + 'indent_char': '\t' + }); + + +*/ + + + +function js_beautify(js_source_text, options) { + + var input, output, token_text, last_type, last_text, last_last_text, last_word, flags, flag_store, indent_string; + var whitespace, wordchar, punct, parser_pos, line_starters, digits; + var prefix, token_type, do_block_just_closed; + var wanted_newline, just_added_newline, n_newlines; + var preindent_string = ''; + + + // Some interpreters have unexpected results with foo = baz || bar; + options = options ? options : {}; + + var opt_brace_style; + + // compatibility + if (options.space_after_anon_function !== undefined && options.jslint_happy === undefined) { + options.jslint_happy = options.space_after_anon_function; + } + if (options.braces_on_own_line !== undefined) { //graceful handling of depricated option + opt_brace_style = options.braces_on_own_line ? "expand" : "collapse"; + } + opt_brace_style = options.brace_style ? options.brace_style : (opt_brace_style ? opt_brace_style : "collapse"); + + + var opt_indent_size = options.indent_size ? options.indent_size : 4; + var opt_indent_char = options.indent_char ? options.indent_char : ' '; + var opt_preserve_newlines = typeof options.preserve_newlines === 'undefined' ? true : options.preserve_newlines; + var opt_max_preserve_newlines = typeof options.max_preserve_newlines === 'undefined' ? false : options.max_preserve_newlines; + var opt_jslint_happy = options.jslint_happy === 'undefined' ? false : options.jslint_happy; + var opt_keep_array_indentation = typeof options.keep_array_indentation === 'undefined' ? false : options.keep_array_indentation; + + just_added_newline = false; + + // cache the source's length. + var input_length = js_source_text.length; + + function trim_output(eat_newlines) { + eat_newlines = typeof eat_newlines === 'undefined' ? false : eat_newlines; + while (output.length && (output[output.length - 1] === ' ' + || output[output.length - 1] === indent_string + || output[output.length - 1] === preindent_string + || (eat_newlines && (output[output.length - 1] === '\n' || output[output.length - 1] === '\r')))) { + output.pop(); + } + } + + function trim(s) { + return s.replace(/^\s\s*|\s\s*$/, ''); + } + + function force_newline() + { + var old_keep_array_indentation = opt_keep_array_indentation; + opt_keep_array_indentation = false; + print_newline() + opt_keep_array_indentation = old_keep_array_indentation; + } + + function print_newline(ignore_repeated) { + + flags.eat_next_space = false; + if (opt_keep_array_indentation && is_array(flags.mode)) { + return; + } + + ignore_repeated = typeof ignore_repeated === 'undefined' ? true : ignore_repeated; + + flags.if_line = false; + trim_output(); + + if (!output.length) { + return; // no newline on start of file + } + + if (output[output.length - 1] !== "\n" || !ignore_repeated) { + just_added_newline = true; + output.push("\n"); + } + if (preindent_string) { + output.push(preindent_string); + } + for (var i = 0; i < flags.indentation_level; i += 1) { + output.push(indent_string); + } + if (flags.var_line && flags.var_line_reindented) { + output.push(indent_string); // skip space-stuffing, if indenting with a tab + } + } + + + + function print_single_space() { + if (flags.eat_next_space) { + flags.eat_next_space = false; + return; + } + var last_output = ' '; + if (output.length) { + last_output = output[output.length - 1]; + } + if (last_output !== ' ' && last_output !== '\n' && last_output !== indent_string) { // prevent occassional duplicate space + output.push(' '); + } + } + + + function print_token() { + just_added_newline = false; + flags.eat_next_space = false; + output.push(token_text); + } + + function indent() { + flags.indentation_level += 1; + } + + + function remove_indent() { + if (output.length && output[output.length - 1] === indent_string) { + output.pop(); + } + } + + function set_mode(mode) { + if (flags) { + flag_store.push(flags); + } + flags = { + previous_mode: flags ? flags.mode : 'BLOCK', + mode: mode, + var_line: false, + var_line_tainted: false, + var_line_reindented: false, + in_html_comment: false, + if_line: false, + in_case: false, + eat_next_space: false, + indentation_baseline: -1, + indentation_level: (flags ? flags.indentation_level + ((flags.var_line && flags.var_line_reindented) ? 1 : 0) : 0), + ternary_depth: 0 + }; + } + + function is_array(mode) { + return mode === '[EXPRESSION]' || mode === '[INDENTED-EXPRESSION]'; + } + + function is_expression(mode) { + return mode === '[EXPRESSION]' || mode === '[INDENTED-EXPRESSION]' || mode === '(EXPRESSION)'; + } + + function restore_mode() { + do_block_just_closed = flags.mode === 'DO_BLOCK'; + if (flag_store.length > 0) { + flags = flag_store.pop(); + } + } + + function all_lines_start_with(lines, c) { + for (var i = 0; i < lines.length; i++) { + if (trim(lines[i])[0] != c) { + return false; + } + } + return true; + } + + function in_array(what, arr) { + for (var i = 0; i < arr.length; i += 1) { + if (arr[i] === what) { + return true; + } + } + return false; + } + + function get_next_token() { + n_newlines = 0; + + if (parser_pos >= input_length) { + return ['', 'TK_EOF']; + } + + wanted_newline = false; + + var c = input.charAt(parser_pos); + parser_pos += 1; + + + var keep_whitespace = opt_keep_array_indentation && is_array(flags.mode); + + if (keep_whitespace) { + + // + // slight mess to allow nice preservation of array indentation and reindent that correctly + // first time when we get to the arrays: + // var a = [ + // ....'something' + // we make note of whitespace_count = 4 into flags.indentation_baseline + // so we know that 4 whitespaces in original source match indent_level of reindented source + // + // and afterwards, when we get to + // 'something, + // .......'something else' + // we know that this should be indented to indent_level + (7 - indentation_baseline) spaces + // + var whitespace_count = 0; + + while (in_array(c, whitespace)) { + + if (c === "\n") { + trim_output(); + output.push("\n"); + just_added_newline = true; + whitespace_count = 0; + } else { + if (c === '\t') { + whitespace_count += 4; + } else if (c === '\r') { + // nothing + } else { + whitespace_count += 1; + } + } + + if (parser_pos >= input_length) { + return ['', 'TK_EOF']; + } + + c = input.charAt(parser_pos); + parser_pos += 1; + + } + if (flags.indentation_baseline === -1) { + flags.indentation_baseline = whitespace_count; + } + + if (just_added_newline) { + var i; + for (i = 0; i < flags.indentation_level + 1; i += 1) { + output.push(indent_string); + } + if (flags.indentation_baseline !== -1) { + for (i = 0; i < whitespace_count - flags.indentation_baseline; i++) { + output.push(' '); + } + } + } + + } else { + while (in_array(c, whitespace)) { + + if (c === "\n") { + n_newlines += ( (opt_max_preserve_newlines) ? (n_newlines <= opt_max_preserve_newlines) ? 1: 0: 1 ); + } + + + if (parser_pos >= input_length) { + return ['', 'TK_EOF']; + } + + c = input.charAt(parser_pos); + parser_pos += 1; + + } + + if (opt_preserve_newlines) { + if (n_newlines > 1) { + for (i = 0; i < n_newlines; i += 1) { + print_newline(i === 0); + just_added_newline = true; + } + } + } + wanted_newline = n_newlines > 0; + } + + + if (in_array(c, wordchar)) { + if (parser_pos < input_length) { + while (in_array(input.charAt(parser_pos), wordchar)) { + c += input.charAt(parser_pos); + parser_pos += 1; + if (parser_pos === input_length) { + break; + } + } + } + + // small and surprisingly unugly hack for 1E-10 representation + if (parser_pos !== input_length && c.match(/^[0-9]+[Ee]$/) && (input.charAt(parser_pos) === '-' || input.charAt(parser_pos) === '+')) { + + var sign = input.charAt(parser_pos); + parser_pos += 1; + + var t = get_next_token(parser_pos); + c += sign + t[0]; + return [c, 'TK_WORD']; + } + + if (c === 'in') { // hack for 'in' operator + return [c, 'TK_OPERATOR']; + } + if (wanted_newline && last_type !== 'TK_OPERATOR' + && last_type !== 'TK_EQUALS' + && !flags.if_line && (opt_preserve_newlines || last_text !== 'var')) { + print_newline(); + } + return [c, 'TK_WORD']; + } + + if (c === '(' || c === '[') { + return [c, 'TK_START_EXPR']; + } + + if (c === ')' || c === ']') { + return [c, 'TK_END_EXPR']; + } + + if (c === '{') { + return [c, 'TK_START_BLOCK']; + } + + if (c === '}') { + return [c, 'TK_END_BLOCK']; + } + + if (c === ';') { + return [c, 'TK_SEMICOLON']; + } + + if (c === '/') { + var comment = ''; + // peek for comment /* ... */ + var inline_comment = true; + if (input.charAt(parser_pos) === '*') { + parser_pos += 1; + if (parser_pos < input_length) { + while (! (input.charAt(parser_pos) === '*' && input.charAt(parser_pos + 1) && input.charAt(parser_pos + 1) === '/') && parser_pos < input_length) { + c = input.charAt(parser_pos); + comment += c; + if (c === '\x0d' || c === '\x0a') { + inline_comment = false; + } + parser_pos += 1; + if (parser_pos >= input_length) { + break; + } + } + } + parser_pos += 2; + if (inline_comment) { + return ['/*' + comment + '*/', 'TK_INLINE_COMMENT']; + } else { + return ['/*' + comment + '*/', 'TK_BLOCK_COMMENT']; + } + } + // peek for comment // ... + if (input.charAt(parser_pos) === '/') { + comment = c; + while (input.charAt(parser_pos) !== '\r' && input.charAt(parser_pos) !== '\n') { + comment += input.charAt(parser_pos); + parser_pos += 1; + if (parser_pos >= input_length) { + break; + } + } + parser_pos += 1; + if (wanted_newline) { + print_newline(); + } + return [comment, 'TK_COMMENT']; + } + + } + + if (c === "'" || // string + c === '"' || // string + (c === '/' && + ((last_type === 'TK_WORD' && in_array(last_text, ['return', 'do'])) || + (last_type === 'TK_COMMENT' || last_type === 'TK_START_EXPR' || last_type === 'TK_START_BLOCK' || last_type === 'TK_END_BLOCK' || last_type === 'TK_OPERATOR' || last_type === 'TK_EQUALS' || last_type === 'TK_EOF' || last_type === 'TK_SEMICOLON')))) { // regexp + var sep = c; + var esc = false; + var resulting_string = c; + + if (parser_pos < input_length) { + if (sep === '/') { + // + // handle regexp separately... + // + var in_char_class = false; + while (esc || in_char_class || input.charAt(parser_pos) !== sep) { + resulting_string += input.charAt(parser_pos); + if (!esc) { + esc = input.charAt(parser_pos) === '\\'; + if (input.charAt(parser_pos) === '[') { + in_char_class = true; + } else if (input.charAt(parser_pos) === ']') { + in_char_class = false; + } + } else { + esc = false; + } + parser_pos += 1; + if (parser_pos >= input_length) { + // incomplete string/rexp when end-of-file reached. + // bail out with what had been received so far. + return [resulting_string, 'TK_STRING']; + } + } + + } else { + // + // and handle string also separately + // + while (esc || input.charAt(parser_pos) !== sep) { + resulting_string += input.charAt(parser_pos); + if (!esc) { + esc = input.charAt(parser_pos) === '\\'; + } else { + esc = false; + } + parser_pos += 1; + if (parser_pos >= input_length) { + // incomplete string/rexp when end-of-file reached. + // bail out with what had been received so far. + return [resulting_string, 'TK_STRING']; + } + } + } + + + + } + + parser_pos += 1; + + resulting_string += sep; + + if (sep === '/') { + // regexps may have modifiers /regexp/MOD , so fetch those, too + while (parser_pos < input_length && in_array(input.charAt(parser_pos), wordchar)) { + resulting_string += input.charAt(parser_pos); + parser_pos += 1; + } + } + return [resulting_string, 'TK_STRING']; + } + + if (c === '#') { + + + if (output.length === 0 && input.charAt(parser_pos) === '!') { + // shebang + resulting_string = c; + while (parser_pos < input_length && c != '\n') { + c = input.charAt(parser_pos); + resulting_string += c; + parser_pos += 1; + } + output.push(trim(resulting_string) + '\n'); + print_newline(); + return get_next_token(); + } + + + + // Spidermonkey-specific sharp variables for circular references + // https://developer.mozilla.org/En/Sharp_variables_in_JavaScript + // http://mxr.mozilla.org/mozilla-central/source/js/src/jsscan.cpp around line 1935 + var sharp = '#'; + if (parser_pos < input_length && in_array(input.charAt(parser_pos), digits)) { + do { + c = input.charAt(parser_pos); + sharp += c; + parser_pos += 1; + } while (parser_pos < input_length && c !== '#' && c !== '='); + if (c === '#') { + // + } else if (input.charAt(parser_pos) === '[' && input.charAt(parser_pos + 1) === ']') { + sharp += '[]'; + parser_pos += 2; + } else if (input.charAt(parser_pos) === '{' && input.charAt(parser_pos + 1) === '}') { + sharp += '{}'; + parser_pos += 2; + } + return [sharp, 'TK_WORD']; + } + } + + if (c === '<' && input.substring(parser_pos - 1, parser_pos + 3) === '') { + flags.in_html_comment = false; + parser_pos += 2; + if (wanted_newline) { + print_newline(); + } + return ['-->', 'TK_COMMENT']; + } + + if (in_array(c, punct)) { + while (parser_pos < input_length && in_array(c + input.charAt(parser_pos), punct)) { + c += input.charAt(parser_pos); + parser_pos += 1; + if (parser_pos >= input_length) { + break; + } + } + + if (c === '=') { + return [c, 'TK_EQUALS']; + } else { + return [c, 'TK_OPERATOR']; + } + } + + return [c, 'TK_UNKNOWN']; + } + + //---------------------------------- + indent_string = ''; + while (opt_indent_size > 0) { + indent_string += opt_indent_char; + opt_indent_size -= 1; + } + + while (js_source_text && (js_source_text[0] === ' ' || js_source_text[0] === '\t')) { + preindent_string += js_source_text[0]; + js_source_text = js_source_text.substring(1); + } + input = js_source_text; + + last_word = ''; // last 'TK_WORD' passed + last_type = 'TK_START_EXPR'; // last token type + last_text = ''; // last token text + last_last_text = ''; // pre-last token text + output = []; + + do_block_just_closed = false; + + whitespace = "\n\r\t ".split(''); + wordchar = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$'.split(''); + digits = '0123456789'.split(''); + + punct = '+ - * / % & ++ -- = += -= *= /= %= == === != !== > < >= <= >> << >>> >>>= >>= <<= && &= | || ! !! , : ? ^ ^= |= ::'.split(' '); + + // words which should always start on new line. + line_starters = 'continue,try,throw,return,var,if,switch,case,default,for,while,break,function'.split(','); + + // states showing if we are currently in expression (i.e. "if" case) - 'EXPRESSION', or in usual block (like, procedure), 'BLOCK'. + // some formatting depends on that. + flag_store = []; + set_mode('BLOCK'); + + parser_pos = 0; + while (true) { + var t = get_next_token(parser_pos); + token_text = t[0]; + token_type = t[1]; + if (token_type === 'TK_EOF') { + break; + } + + switch (token_type) { + + case 'TK_START_EXPR': + + if (token_text === '[') { + + if (last_type === 'TK_WORD' || last_text === ')') { + // this is array index specifier, break immediately + // a[x], fn()[x] + if (in_array(last_text, line_starters)) { + print_single_space(); + } + set_mode('(EXPRESSION)'); + print_token(); + break; + } + + if (flags.mode === '[EXPRESSION]' || flags.mode === '[INDENTED-EXPRESSION]') { + if (last_last_text === ']' && last_text === ',') { + // ], [ goes to new line + if (flags.mode === '[EXPRESSION]') { + flags.mode = '[INDENTED-EXPRESSION]'; + if (!opt_keep_array_indentation) { + indent(); + } + } + set_mode('[EXPRESSION]'); + if (!opt_keep_array_indentation) { + print_newline(); + } + } else if (last_text === '[') { + if (flags.mode === '[EXPRESSION]') { + flags.mode = '[INDENTED-EXPRESSION]'; + if (!opt_keep_array_indentation) { + indent(); + } + } + set_mode('[EXPRESSION]'); + + if (!opt_keep_array_indentation) { + print_newline(); + } + } else { + set_mode('[EXPRESSION]'); + } + } else { + set_mode('[EXPRESSION]'); + } + + + + } else { + set_mode('(EXPRESSION)'); + } + + if (last_text === ';' || last_type === 'TK_START_BLOCK') { + print_newline(); + } else if (last_type === 'TK_END_EXPR' || last_type === 'TK_START_EXPR' || last_type === 'TK_END_BLOCK' || last_text === '.') { + // do nothing on (( and )( and ][ and ]( and .( + } else if (last_type !== 'TK_WORD' && last_type !== 'TK_OPERATOR') { + print_single_space(); + } else if (last_word === 'function' || last_word === 'typeof') { + // function() vs function () + if (opt_jslint_happy) { + print_single_space(); + } + } else if (in_array(last_text, line_starters) || last_text === 'catch') { + print_single_space(); + } + print_token(); + + break; + + case 'TK_END_EXPR': + if (token_text === ']') { + if (opt_keep_array_indentation) { + if (last_text === '}') { + // trim_output(); + // print_newline(true); + remove_indent(); + print_token(); + restore_mode(); + break; + } + } else { + if (flags.mode === '[INDENTED-EXPRESSION]') { + if (last_text === ']') { + restore_mode(); + print_newline(); + print_token(); + break; + } + } + } + } + restore_mode(); + print_token(); + break; + + case 'TK_START_BLOCK': + + if (last_word === 'do') { + set_mode('DO_BLOCK'); + } else { + set_mode('BLOCK'); + } + if (opt_brace_style=="expand") { + if (last_type !== 'TK_OPERATOR') { + if (last_text === 'return' || last_text === '=') { + print_single_space(); + } else { + print_newline(true); + } + } + print_token(); + indent(); + } else { + if (last_type !== 'TK_OPERATOR' && last_type !== 'TK_START_EXPR') { + if (last_type === 'TK_START_BLOCK') { + print_newline(); + } else { + print_single_space(); + } + } else { + // if TK_OPERATOR or TK_START_EXPR + if (is_array(flags.previous_mode) && last_text === ',') { + if (last_last_text === '}') { + // }, { in array context + print_single_space(); + } else { + print_newline(); // [a, b, c, { + } + } + } + indent(); + print_token(); + } + + break; + + case 'TK_END_BLOCK': + restore_mode(); + if (opt_brace_style=="expand") { + if (last_text !== '{') { + print_newline(); + } + print_token(); + } else { + if (last_type === 'TK_START_BLOCK') { + // nothing + if (just_added_newline) { + remove_indent(); + } else { + // {} + trim_output(); + } + } else { + if (is_array(flags.mode) && opt_keep_array_indentation) { + // we REALLY need a newline here, but newliner would skip that + opt_keep_array_indentation = false; + print_newline(); + opt_keep_array_indentation = true; + + } else { + print_newline(); + } + } + print_token(); + } + break; + + case 'TK_WORD': + + // no, it's not you. even I have problems understanding how this works + // and what does what. + if (do_block_just_closed) { + // do {} ## while () + print_single_space(); + print_token(); + print_single_space(); + do_block_just_closed = false; + break; + } + + if (token_text === 'function') { + if (flags.var_line) { + flags.var_line_reindented = true; + } + if ((just_added_newline || last_text === ';') && last_text !== '{') { + // make sure there is a nice clean space of at least one blank line + // before a new function definition + n_newlines = just_added_newline ? n_newlines : 0; + if ( ! opt_preserve_newlines) { + n_newlines = 1; + } + + for (var i = 0; i < 2 - n_newlines; i++) { + print_newline(false); + } + } + } + + if (token_text === 'case' || token_text === 'default') { + if (last_text === ':') { + // switch cases following one another + remove_indent(); + } else { + // case statement starts in the same line where switch + flags.indentation_level--; + print_newline(); + flags.indentation_level++; + } + print_token(); + flags.in_case = true; + break; + } + + prefix = 'NONE'; + + if (last_type === 'TK_END_BLOCK') { + + if (!in_array(token_text.toLowerCase(), ['else', 'catch', 'finally'])) { + prefix = 'NEWLINE'; + } else { + if (opt_brace_style=="expand" || opt_brace_style=="end-expand") { + prefix = 'NEWLINE'; + } else { + prefix = 'SPACE'; + print_single_space(); + } + } + } else if (last_type === 'TK_SEMICOLON' && (flags.mode === 'BLOCK' || flags.mode === 'DO_BLOCK')) { + prefix = 'NEWLINE'; + } else if (last_type === 'TK_SEMICOLON' && is_expression(flags.mode)) { + prefix = 'SPACE'; + } else if (last_type === 'TK_STRING') { + prefix = 'NEWLINE'; + } else if (last_type === 'TK_WORD') { + if (last_text === 'else') { + // eat newlines between ...else *** some_op... + // won't preserve extra newlines in this place (if any), but don't care that much + trim_output(true); + } + prefix = 'SPACE'; + } else if (last_type === 'TK_START_BLOCK') { + prefix = 'NEWLINE'; + } else if (last_type === 'TK_END_EXPR') { + print_single_space(); + prefix = 'NEWLINE'; + } + + if (in_array(token_text, line_starters) && last_text !== ')') { + if (last_text == 'else') { + prefix = 'SPACE'; + } else { + prefix = 'NEWLINE'; + } + } + + if (flags.if_line && last_type === 'TK_END_EXPR') { + flags.if_line = false; + } + if (in_array(token_text.toLowerCase(), ['else', 'catch', 'finally'])) { + if (last_type !== 'TK_END_BLOCK' || opt_brace_style=="expand" || opt_brace_style=="end-expand") { + print_newline(); + } else { + trim_output(true); + print_single_space(); + } + } else if (prefix === 'NEWLINE') { + if ((last_type === 'TK_START_EXPR' || last_text === '=' || last_text === ',') && token_text === 'function') { + // no need to force newline on 'function': (function + // DONOTHING + } else if (token_text === 'function' && last_text == 'new') { + print_single_space(); + } else if (last_text === 'return' || last_text === 'throw') { + // no newline between 'return nnn' + print_single_space(); + } else if (last_type !== 'TK_END_EXPR') { + if ((last_type !== 'TK_START_EXPR' || token_text !== 'var') && last_text !== ':') { + // no need to force newline on 'var': for (var x = 0...) + if (token_text === 'if' && last_word === 'else' && last_text !== '{') { + // no newline for } else if { + print_single_space(); + } else { + flags.var_line = false; + flags.var_line_reindented = false; + print_newline(); + } + } + } else if (in_array(token_text, line_starters) && last_text != ')') { + flags.var_line = false; + flags.var_line_reindented = false; + print_newline(); + } + } else if (is_array(flags.mode) && last_text === ',' && last_last_text === '}') { + print_newline(); // }, in lists get a newline treatment + } else if (prefix === 'SPACE') { + print_single_space(); + } + print_token(); + last_word = token_text; + + if (token_text === 'var') { + flags.var_line = true; + flags.var_line_reindented = false; + flags.var_line_tainted = false; + } + + if (token_text === 'if') { + flags.if_line = true; + } + if (token_text === 'else') { + flags.if_line = false; + } + + break; + + case 'TK_SEMICOLON': + + print_token(); + flags.var_line = false; + flags.var_line_reindented = false; + if (flags.mode == 'OBJECT') { + // OBJECT mode is weird and doesn't get reset too well. + flags.mode = 'BLOCK'; + } + break; + + case 'TK_STRING': + + if (last_type === 'TK_START_BLOCK' || last_type === 'TK_END_BLOCK' || last_type === 'TK_SEMICOLON') { + print_newline(); + } else if (last_type === 'TK_WORD') { + print_single_space(); + } + print_token(); + break; + + case 'TK_EQUALS': + if (flags.var_line) { + // just got an '=' in a var-line, different formatting/line-breaking, etc will now be done + flags.var_line_tainted = true; + } + print_single_space(); + print_token(); + print_single_space(); + break; + + case 'TK_OPERATOR': + + var space_before = true; + var space_after = true; + + if (flags.var_line && token_text === ',' && (is_expression(flags.mode))) { + // do not break on comma, for(var a = 1, b = 2) + flags.var_line_tainted = false; + } + + if (flags.var_line) { + if (token_text === ',') { + if (flags.var_line_tainted) { + print_token(); + flags.var_line_reindented = true; + flags.var_line_tainted = false; + print_newline(); + break; + } else { + flags.var_line_tainted = false; + } + // } else if (token_text === ':') { + // hmm, when does this happen? tests don't catch this + // flags.var_line = false; + } + } + + if (last_text === 'return' || last_text === 'throw') { + // "return" had a special handling in TK_WORD. Now we need to return the favor + print_single_space(); + print_token(); + break; + } + + if (token_text === ':' && flags.in_case) { + print_token(); // colon really asks for separate treatment + print_newline(); + flags.in_case = false; + break; + } + + if (token_text === '::') { + // no spaces around exotic namespacing syntax operator + print_token(); + break; + } + + if (token_text === ',') { + if (flags.var_line) { + if (flags.var_line_tainted) { + print_token(); + print_newline(); + flags.var_line_tainted = false; + } else { + print_token(); + print_single_space(); + } + } else if (last_type === 'TK_END_BLOCK' && flags.mode !== "(EXPRESSION)") { + print_token(); + if (flags.mode === 'OBJECT' && last_text === '}') { + print_newline(); + } else { + print_single_space(); + } + } else { + if (flags.mode === 'OBJECT') { + print_token(); + print_newline(); + } else { + // EXPR or DO_BLOCK + print_token(); + print_single_space(); + } + } + break; + // } else if (in_array(token_text, ['--', '++', '!']) || (in_array(token_text, ['-', '+']) && (in_array(last_type, ['TK_START_BLOCK', 'TK_START_EXPR', 'TK_EQUALS']) || in_array(last_text, line_starters) || in_array(last_text, ['==', '!=', '+=', '-=', '*=', '/=', '+', '-'])))) { + } else if (in_array(token_text, ['--', '++', '!']) || (in_array(token_text, ['-', '+']) && (in_array(last_type, ['TK_START_BLOCK', 'TK_START_EXPR', 'TK_EQUALS', 'TK_OPERATOR']) || in_array(last_text, line_starters)))) { + // unary operators (and binary +/- pretending to be unary) special cases + + space_before = false; + space_after = false; + + if (last_text === ';' && is_expression(flags.mode)) { + // for (;; ++i) + // ^^^ + space_before = true; + } + if (last_type === 'TK_WORD' && in_array(last_text, line_starters)) { + space_before = true; + } + + if (flags.mode === 'BLOCK' && (last_text === '{' || last_text === ';')) { + // { foo; --i } + // foo(); --bar; + print_newline(); + } + } else if (token_text === '.') { + // decimal digits or object.property + space_before = false; + + } else if (token_text === ':') { + if (flags.ternary_depth == 0) { + flags.mode = 'OBJECT'; + space_before = false; + } else { + flags.ternary_depth -= 1; + } + } else if (token_text === '?') { + flags.ternary_depth += 1; + } + if (space_before) { + print_single_space(); + } + + print_token(); + + if (space_after) { + print_single_space(); + } + + if (token_text === '!') { + // flags.eat_next_space = true; + } + + break; + + case 'TK_BLOCK_COMMENT': + + var lines = token_text.split(/\x0a|\x0d\x0a/); + + if (all_lines_start_with(lines.slice(1), '*')) { + // javadoc: reformat and reindent + print_newline(); + output.push(lines[0]); + for (i = 1; i < lines.length; i++) { + print_newline(); + output.push(' '); + output.push(trim(lines[i])); + } + + } else { + + // simple block comment: leave intact + if (lines.length > 1) { + // multiline comment block starts with a new line + print_newline(); + trim_output(); + } else { + // single-line /* comment */ stays where it is + print_single_space(); + + } + + for (i = 0; i < lines.length; i++) { + output.push(lines[i]); + output.push('\n'); + } + + } + print_newline(); + break; + + case 'TK_INLINE_COMMENT': + + print_single_space(); + print_token(); + if (is_expression(flags.mode)) { + print_single_space(); + } else { + force_newline(); + } + break; + + case 'TK_COMMENT': + + // print_newline(); + if (wanted_newline) { + print_newline(); + } else { + print_single_space(); + } + print_token(); + force_newline(); + break; + + case 'TK_UNKNOWN': + if (last_text === 'return' || last_text === 'throw') { + print_single_space(); + } + print_token(); + break; + } + + last_last_text = last_text; + last_type = token_type; + last_text = token_text; + } + + var sweet_code = preindent_string + output.join('').replace(/[\n ]+$/, ''); + return sweet_code; + +} + +// Add support for CommonJS. Just put this file somewhere on your require.paths +// and you will be able to `var js_beautify = require("beautify").js_beautify`. +if (typeof exports !== "undefined") + exports.js_beautify = js_beautify; + --- /dev/null +++ b/js/flotr2/examples/lib/codemirror/LICENSE @@ -1,1 +1,20 @@ +Copyright (C) 2011 by Marijn Haverbeke +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + --- /dev/null +++ b/js/flotr2/examples/lib/codemirror/README.md @@ -1,1 +1,7 @@ +# CodeMirror 2 +CodeMirror 2 is a rewrite of [CodeMirror +1](http://github.com/marijnh/CodeMirror). The docs live +[here](http://codemirror.net/doc/manual.html), and the project page is +[http://codemirror.net/](http://codemirror.net/). + --- /dev/null +++ b/js/flotr2/examples/lib/codemirror/demo/activeline.html @@ -1,1 +1,72 @@ + + + + CodeMirror: Active Line Demo + + + + + + + +

    CodeMirror: Active Line Demo

    + +
    + + + +

    Styling the current cursor line.

    + + + + --- /dev/null +++ b/js/flotr2/examples/lib/codemirror/demo/changemode.html @@ -1,1 +1,51 @@ + + + + CodeMirror: Mode-Changing Demo + + + + + + + + +

    CodeMirror: Mode-Changing demo

    + +
    + +

    On changes to the content of the above editor, a (crude) script +tries to auto-detect the language used, and switches the editor to +either JavaScript or Scheme mode based on that.

    + + + + + --- /dev/null +++ b/js/flotr2/examples/lib/codemirror/demo/complete.html @@ -1,1 +1,68 @@ + + + + CodeMirror: Autocomplete Demo + + + + + + + + + + +

    CodeMirror: Autocomplete demo

    +
    + +

    Press ctrl-space to activate autocompletion. See +the code (here +and here) to figure out +how it works.

    + + + + + --- /dev/null +++ b/js/flotr2/examples/lib/codemirror/demo/emacs.html @@ -1,1 +1,60 @@ + + + + CodeMirror: Emacs bindings demo + + + + + + + + +

    CodeMirror: Emacs bindings demo

    + +
    + +

    The emacs keybindings are enabled by +including keymap/emacs.js and setting +the keyMap option to "emacs". Because +CodeMirror's internal API is quite different from Emacs, they are only +a loose approximation of actual emacs bindings, though.

    + +

    Also note that a lot of browsers disallow certain keys from being +captured. For example, Chrome blocks both Ctrl-W and Ctrl-N, with the +result that idiomatic use of Emacs keys will constantly close your tab +or open a new window.

    + + + + + + --- /dev/null +++ b/js/flotr2/examples/lib/codemirror/demo/folding.html @@ -1,1 +1,57 @@ + + + + CodeMirror: Code Folding Demo + + + + + + + + +

    CodeMirror: Code Folding Demo

    + +
    + + + +

    Demonstration of code folding using the code + in foldcode.js. + Press ctrl-q or click on the gutter to fold a block, again + to unfold.

    + + + --- /dev/null +++ b/js/flotr2/examples/lib/codemirror/demo/formatting.html @@ -1,1 +1,81 @@ + + + + CodeMirror: Formatting Demo + + + + + + + + + + + +

    CodeMirror: Formatting demo

    + +
    + +

    Select a piece of code and click one of the links below to apply automatic formatting to the selected text or comment/uncomment the selected text. Note that the formatting behavior depends on the current block's mode. + + + + + + +
    + + Autoformat Selected + + + + Comment Selected + + + + Uncomment Selected + +
    +

    + + + + + --- /dev/null +++ b/js/flotr2/examples/lib/codemirror/demo/fullscreen.html @@ -1,1 +1,152 @@ + + + + CodeMirror: Full Screen Editing + + + + + + + + + +

    CodeMirror: Full Screen Editing

    + +
    + + +

    Press F11 (or ESC in Safari on Mac OS X) when cursor is in the editor to toggle full screen editing.

    + +

    Note: Does not currently work correctly in IE + 6 and 7, where setting the height of something + to 100% doesn't make it full-screen.

    + + + + --- /dev/null +++ b/js/flotr2/examples/lib/codemirror/demo/marker.html @@ -1,1 +1,53 @@ + + + + CodeMirror: Breakpoint Demo + + + + + + + +

    CodeMirror: Breakpoint demo

    + +
    + +

    Click the line-number gutter to add or remove 'breakpoints'.

    + + + + + + --- /dev/null +++ b/js/flotr2/examples/lib/codemirror/demo/mustache.html @@ -1,1 +1,57 @@ + + + + CodeMirror: Overlay Parser Demo + + + + + + + + +

    CodeMirror: Overlay Parser Demo

    + +
    + + + +

    Demonstration of a mode that parses HTML, highlighting + the Mustache templating + directives inside of it by using the code + in overlay.js. View + source to see the 15 lines of code needed to accomplish this.

    + + + + --- /dev/null +++ b/js/flotr2/examples/lib/codemirror/demo/preview.html @@ -1,1 +1,77 @@ + + + + CodeMirror: HTML5 preview + + + + + + + + + + + +

    CodeMirror: HTML5 preview

    + + + + + + --- /dev/null +++ b/js/flotr2/examples/lib/codemirror/demo/resize.html @@ -1,1 +1,44 @@ + + + + CodeMirror: Autoresize Demo + + + + + + + +

    CodeMirror: Autoresize demo

    + +
    + +

    By setting a few CSS properties, CodeMirror can be made to +automatically resize to fit its content.

    + + + + + + --- /dev/null +++ b/js/flotr2/examples/lib/codemirror/demo/runmode.html @@ -1,1 +1,50 @@ + + + + CodeMirror: Mode Runner Demo + + + + + + + +

    CodeMirror: Mode Runner Demo

    +
    + +
    
    +
    +    
    +
    +    

    Running a CodeMirror mode outside of the editor. + The CodeMirror.runMode function, defined + in lib/runmode.js takes the following arguments:

    + +
    +
    text (string)
    +
    The document to run through the highlighter.
    +
    mode (mode spec)
    +
    The mode to use (must be loaded as normal).
    +
    output (function or DOM node)
    +
    If this is a function, it will be called for each token with + two arguments, the token's text and the token's style class (may + be null for unstyled tokens). If it is a DOM node, + the tokens will be converted to span elements as in + an editor, and inserted into the node + (through innerHTML).
    +
    + + + + --- /dev/null +++ b/js/flotr2/examples/lib/codemirror/demo/search.html @@ -1,1 +1,84 @@ + + + + CodeMirror: Search/Replace Demo + + + + + + + + + + + +

    CodeMirror: Search/Replace Demo

    + +
    + + + +

    Demonstration of primitive search/replace functionality. The + keybindings (which can be overridden by custom keymaps) are:

    +
    +
    Ctrl-F / Cmd-F
    Start searching
    +
    Ctrl-G / Cmd-G
    Find next
    +
    Shift-Ctrl-G / Shift-Cmd-G
    Find previous
    +
    Shift-Ctrl-F / Cmd-Option-F
    Replace
    +
    Shift-Ctrl-R / Shift-Cmd-Option-F
    Replace all
    +
    +

    Searching is enabled by + including lib/util/search.js. + For good-looking input dialogs, you also want to include + lib/util/dialog.js + and lib/util/dialog.css.

    + + + --- /dev/null +++ b/js/flotr2/examples/lib/codemirror/demo/theme.html @@ -1,1 +1,61 @@ + + + + CodeMirror: Theme Demo + + + + + + + + + + + + + + +

    CodeMirror: Theme demo

    + +
    + +

    Select a theme: +

    + + + + + --- /dev/null +++ b/js/flotr2/examples/lib/codemirror/demo/vim.html @@ -1,1 +1,51 @@ + + + + CodeMirror: Vim bindings demo + + + + + + + + +

    CodeMirror: Vim bindings demo

    + +
    + +

    The vim keybindings are enabled by +including keymap/vim.js and setting +the keyMap option to "vim". Because +CodeMirror's internal API is quite different from Vim, they are only +a loose approximation of actual vim bindings, though.

    + + + + + + --- /dev/null +++ b/js/flotr2/examples/lib/codemirror/demo/visibletabs.html @@ -1,1 +1,62 @@ + + + + CodeMirror: Visible tabs demo + + + + + + + +

    CodeMirror: Visible tabs demo

    + +
    + +

    Tabs inside the editor are spans with the +class cm-tab, and can be styled. This demo uses +an :after pseudo-class CSS hack that will not work on old +browsers. You can use a more conservative technique like a background +image as an alternative.

    + + + + + + --- /dev/null +++ b/js/flotr2/examples/lib/codemirror/doc/baboon_vector.svg @@ -1,1 +1,153 @@ + + +image/svg+xml --- /dev/null +++ b/js/flotr2/examples/lib/codemirror/doc/compress.html @@ -1,1 +1,125 @@ + + + + CodeMirror: Compression Helper + + + + + +

    { } CodeMirror

    + +
    +/* Script compression
    +   helper */
    +
    + +

    To optimize loading CodeMirror, especially when including a + bunch of different modes, it is recommended that you combine and + minify (and preferably also gzip) the scripts. This page makes + those first two steps very easy. Simply select the version and + scripts you need in the form below, and + click Compress to download the minified script + file.

    + +
    + +

    Version:

    + +

    + +

    + with UglifyJS +

    + +

    Custom code to add to the compressed file:

    +
    + + + + + + + --- /dev/null +++ b/js/flotr2/examples/lib/codemirror/doc/docs.css @@ -1,1 +1,155 @@ +body { + font-family: Droid Sans, Arial, sans-serif; + line-height: 1.5; + max-width: 64.3em; + margin: 3em auto; + padding: 0 1em; +} +h1 { + letter-spacing: -3px; + font-size: 3.23em; + font-weight: bold; + margin: 0; +} + +h2 { + font-size: 1.23em; + font-weight: bold; + margin: .5em 0; + letter-spacing: -1px; +} + +h3 { + font-size: 1em; + font-weight: bold; + margin: .4em 0; +} + +pre { + background-color: #eee; + -moz-border-radius: 6px; + -webkit-border-radius: 6px; + border-radius: 6px; + padding: 1em; +} + +pre.code { + margin: 0 1em; +} + +.grey { + font-size: 2.2em; + padding: .5em 1em; + line-height: 1.2em; + margin-top: .5em; + position: relative; +} + +img.logo { + position: absolute; + right: -25px; + bottom: 4px; +} + +a:link, a:visited, .quasilink { + color: #df0019; + cursor: pointer; + text-decoration: none; +} + +a:hover, .quasilink:hover { + color: #800004; +} + +h1 a:link, h1 a:visited, h1 a:hover { + color: black; +} + +ul { + margin: 0; + padding-left: 1.2em; +} + +a.download { + color: white; + background-color: #df0019; + width: 100%; + display: block; + text-align: center; + font-size: 1.23em; + font-weight: bold; + text-decoration: none; + -moz-border-radius: 6px; + -webkit-border-radius: 6px; + border-radius: 6px; + padding: .5em 0; + margin-bottom: 1em; +} + +a.download:hover { + background-color: #bb0010; +} + +.rel { + margin-bottom: 0; +} + +.rel-note { + color: #777; + font-size: .9em; + margin-top: .1em; +} + +.logo-braces { + color: #df0019; + position: relative; + top: -4px; +} + +.blk { + float: left; +} + +.left { + width: 37em; + padding-right: 6.53em; + padding-bottom: 1em; +} + +.left1 { + width: 15.24em; + padding-right: 6.45em; +} + +.left2 { + width: 15.24em; +} + +.right { + width: 20.68em; +} + +.leftbig { + width: 42.44em; + padding-right: 6.53em; +} + +.rightsmall { + width: 15.24em; +} + +.clear:after { + visibility: hidden; + display: block; + font-size: 0; + content: " "; + clear: both; + height: 0; +} +.clear { display: inline-block; } +/* start commented backslash hack \*/ +* html .clear { height: 1%; } +.clear { display: block; } +/* close commented backslash hack */ + --- /dev/null +++ b/js/flotr2/examples/lib/codemirror/doc/internals.html @@ -1,1 +1,495 @@ - + + + + CodeMirror: Internals + + + + + + + +

    { } CodeMirror

    + +
    +/* (Re-) Implementing A Syntax-
    +   Highlighting Editor in JavaScript */
    +
    + +
    + +

    + Topic: JavaScript, code editor implementation
    + Author: Marijn Haverbeke
    + Date: March 2nd 2011 (updated November 13th 2011) +

    + +

    This is a followup to +my Brutal Odyssey to the +Dark Side of the DOM Tree story. That one describes the +mind-bending process of implementing (what would become) CodeMirror 1. +This one describes the internals of CodeMirror 2, a complete rewrite +and rethink of the old code base. I wanted to give this piece another +Hunter Thompson copycat subtitle, but somehow that would be out of +place—the process this time around was one of straightforward +engineering, requiring no serious mind-bending whatsoever.

    + +

    So, what is wrong with CodeMirror 1? I'd estimate, by mailing list +activity and general search-engine presence, that it has been +integrated into about a thousand systems by now. The most prominent +one, since a few weeks, +being Google +code's project hosting. It works, and it's being used widely. + +

    Still, I did not start replacing it because I was bored. CodeMirror +1 was heavily reliant on designMode +or contentEditable (depending on the browser). Neither of +these are well specified (HTML5 tries +to specify +their basics), and, more importantly, they tend to be one of the more +obscure and buggy areas of browser functionality—CodeMirror, by using +this functionality in a non-typical way, was constantly running up +against browser bugs. WebKit wouldn't show an empty line at the end of +the document, and in some releases would suddenly get unbearably slow. +Firefox would show the cursor in the wrong place. Internet Explorer +would insist on linkifying everything that looked like a URL or email +address, a behaviour that can't be turned off. Some bugs I managed to +work around (which was often a frustrating, painful process), others, +such as the Firefox cursor placement, I gave up on, and had to tell +user after user that they were known problems, but not something I +could help.

    + +

    Also, there is the fact that designMode (which seemed +to be less buggy than contentEditable in Webkit and +Firefox, and was thus used by CodeMirror 1 in those browsers) requires +a frame. Frames are another tricky area. It takes some effort to +prevent getting tripped up by domain restrictions, they don't +initialize synchronously, behave strangely in response to the back +button, and, on several browsers, can't be moved around the DOM +without having them re-initialize. They did provide a very nice way to +namespace the library, though—CodeMirror 1 could freely pollute the +namespace inside the frame.

    + +

    Finally, working with an editable document means working with +selection in arbitrary DOM structures. Internet Explorer (8 and +before) has an utterly different (and awkward) selection API than all +of the other browsers, and even among the different implementations of +document.selection, details about how exactly a selection +is represented vary quite a bit. Add to that the fact that Opera's +selection support tended to be very buggy until recently, and you can +imagine why CodeMirror 1 contains 700 lines of selection-handling +code.

    + +

    And that brings us to the main issue with the CodeMirror 1 +code base: The proportion of browser-bug-workarounds to real +application code was getting dangerously high. By building on top of a +few dodgy features, I put the system in a vulnerable position—any +incompatibility and bugginess in these features, I had to paper over +with my own code. Not only did I have to do some serious stunt-work to +get it to work on older browsers (as detailed in the +previous story), things +also kept breaking in newly released versions, requiring me to come up +with new scary hacks in order to keep up. This was starting +to lose its appeal.

    + +

    General Approach

    + +

    What CodeMirror 2 does is try to sidestep most of the hairy hacks +that came up in version 1. I owe a lot to the +ACE editor for inspiration on how to +approach this.

    + +

    I absolutely did not want to be completely reliant on key events to +generate my input. Every JavaScript programmer knows that key event +information is horrible and incomplete. Some people (most awesomely +Mihai Bazon with Ymacs) have been able +to build more or less functioning editors by directly reading key +events, but it takes a lot of work (the kind of never-ending, fragile +work I described earlier), and will never be able to properly support +things like multi-keystoke international character +input. [see below for caveat]

    + +

    So what I do is focus a hidden textarea, and let the browser +believe that the user is typing into that. What we show to the user is +a DOM structure we built to represent his document. If this is updated +quickly enough, and shows some kind of believable cursor, it feels +like a real text-input control.

    + +

    Another big win is that this DOM representation does not have to +span the whole document. Some CodeMirror 1 users insisted that they +needed to put a 30 thousand line XML document into CodeMirror. Putting +all that into the DOM takes a while, especially since, for some +reason, an editable DOM tree is slower than a normal one on most +browsers. If we have full control over what we show, we must only +ensure that the visible part of the document has been added, and can +do the rest only when needed. (Fortunately, the onscroll +event works almost the same on all browsers, and lends itself well to +displaying things only as they are scrolled into view.)

    + +

    Input

    + +

    ACE uses its hidden textarea only as a text input shim, and does +all cursor movement and things like text deletion itself by directly +handling key events. CodeMirror's way is to let the browser do its +thing as much as possible, and not, for example, define its own set of +key bindings. One way to do this would have been to have the whole +document inside the hidden textarea, and after each key event update +the display DOM to reflect what's in that textarea.

    + +

    That'd be simple, but it is not realistic. For even medium-sized +document the editor would be constantly munging huge strings, and get +terribly slow. What CodeMirror 2 does is put the current selection, +along with an extra line on the top and on the bottom, into the +textarea.

    + +

    This means that the arrow keys (and their ctrl-variations), home, +end, etcetera, do not have to be handled specially. We just read the +cursor position in the textarea, and update our cursor to match it. +Also, copy and paste work pretty much for free, and people get their +native key bindings, without any special work on my part. For example, +I have emacs key bindings configured for Chrome and Firefox. There is +no way for a script to detect this. [no longer the case]

    + +

    Of course, since only a small part of the document sits in the +textarea, keys like page up and ctrl-end won't do the right thing. +CodeMirror is catching those events and handling them itself.

    + +

    Selection

    + +

    Getting and setting the selection range of a textarea in modern +browsers is trivial—you just use the selectionStart +and selectionEnd properties. On IE you have to do some +insane stuff with temporary ranges and compensating for the fact that +moving the selection by a 'character' will treat \r\n as a single +character, but even there it is possible to build functions that +reliably set and get the selection range.

    + +

    But consider this typical case: When I'm somewhere in my document, +press shift, and press the up arrow, something gets selected. Then, if +I, still holding shift, press the up arrow again, the top of my +selection is adjusted. The selection remembers where its head +and its anchor are, and moves the head when we shift-move. +This is a generally accepted property of selections, and done right by +every editing component built in the past twenty years.

    + +

    But not something that the browser selection APIs expose.

    + +

    Great. So when someone creates an 'upside-down' selection, the next +time CodeMirror has to update the textarea, it'll re-create the +selection as an 'upside-up' selection, with the anchor at the top, and +the next cursor motion will behave in an unexpected way—our second +up-arrow press in the example above will not do anything, since it is +interpreted in exactly the same way as the first.

    + +

    No problem. We'll just, ehm, detect that the selection is +upside-down (you can tell by the way it was created), and then, when +an upside-down selection is present, and a cursor-moving key is +pressed in combination with shift, we quickly collapse the selection +in the textarea to its start, allow the key to take effect, and then +combine its new head with its old anchor to get the real +selection.

    + +

    In short, scary hacks could not be avoided entirely in CodeMirror +2.

    + +

    And, the observant reader might ask, how do you even know that a +key combo is a cursor-moving combo, if you claim you support any +native key bindings? Well, we don't, but we can learn. The editor +keeps a set known cursor-movement combos (initialized to the +predictable defaults), and updates this set when it observes that +pressing a certain key had (only) the effect of moving the cursor. +This, of course, doesn't work if the first time the key is used was +for extending an inverted selection, but it works most of the +time.

    + +

    Intelligent Updating

    + +

    One thing that always comes up when you have a complicated internal +state that's reflected in some user-visible external representation +(in this case, the displayed code and the textarea's content) is +keeping the two in sync. The naive way is to just update the display +every time you change your state, but this is not only error prone +(you'll forget), it also easily leads to duplicate work on big, +composite operations. Then you start passing around flags indicating +whether the display should be updated in an attempt to be efficient +again and, well, at that point you might as well give up completely.

    + +

    I did go down that road, but then switched to a much simpler model: +simply keep track of all the things that have been changed during an +action, and then, only at the end, use this information to update the +user-visible display.

    + +

    CodeMirror uses a concept of operations, which start by +calling a specific set-up function that clears the state and end by +calling another function that reads this state and does the required +updating. Most event handlers, and all the user-visible methods that +change state are wrapped like this. There's a method +called operation that accepts a function, and returns +another function that wraps the given function as an operation.

    + +

    It's trivial to extend this (as CodeMirror does) to detect nesting, +and, when an operation is started inside an operation, simply +increment the nesting count, and only do the updating when this count +reaches zero again.

    + +

    If we have a set of changed ranges and know the currently shown +range, we can (with some awkward code to deal with the fact that +changes can add and remove lines, so we're dealing with a changing +coordinate system) construct a map of the ranges that were left +intact. We can then compare this map with the part of the document +that's currently visible (based on scroll offset and editor height) to +determine whether something needs to be updated.

    + +

    CodeMirror uses two update algorithms—a full refresh, where it just +discards the whole part of the DOM that contains the edited text and +rebuilds it, and a patch algorithm, where it uses the information +about changed and intact ranges to update only the out-of-date parts +of the DOM. When more than 30 percent (which is the current heuristic, +might change) of the lines need to be updated, the full refresh is +chosen (since it's faster to do than painstakingly finding and +updating all the changed lines), in the other case it does the +patching (so that, if you scroll a line or select another character, +the whole screen doesn't have to be +re-rendered). [the full-refresh +algorithm was dropped, it wasn't really faster than the patching +one]

    + +

    All updating uses innerHTML rather than direct DOM +manipulation, since that still seems to be by far the fastest way to +build documents. There's a per-line function that combines the +highlighting, marking, and +selection info for that line into a snippet of HTML. The patch updater +uses this to reset individual lines, the refresh updater builds an +HTML chunk for the whole visible document at once, and then uses a +single innerHTML update to do the refresh.

    + +

    Parsers can be Simple

    + +

    When I wrote CodeMirror 1, I +thought interruptable +parsers were a hugely scary and complicated thing, and I used a +bunch of heavyweight abstractions to keep this supposed complexity +under control: parsers +were iterators +that consumed input from another iterator, and used funny +closure-resetting tricks to copy and resume themselves.

    + +

    This made for a rather nice system, in that parsers formed strictly +separate modules, and could be composed in predictable ways. +Unfortunately, it was quite slow (stacking three or four iterators on +top of each other), and extremely intimidating to people not used to a +functional programming style.

    + +

    With a few small changes, however, we can keep all those +advantages, but simplify the API and make the whole thing less +indirect and inefficient. CodeMirror +2's mode API uses explicit state +objects, and makes the parser/tokenizer a function that simply takes a +state and a character stream abstraction, advances the stream one +token, and returns the way the token should be styled. This state may +be copied, optionally in a mode-defined way, in order to be able to +continue a parse at a given point. Even someone who's never touched a +lambda in his life can understand this approach. Additionally, far +fewer objects are allocated in the course of parsing now.

    + +

    The biggest speedup comes from the fact that the parsing no longer +has to touch the DOM though. In CodeMirror 1, on an older browser, you +could see the parser work its way through the document, +managing some twenty lines in each 50-millisecond time slice it got. It +was reading its input from the DOM, and updating the DOM as it went +along, which any experienced JavaScript programmer will immediately +spot as a recipe for slowness. In CodeMirror 2, the parser usually +finishes the whole document in a single 100-millisecond time slice—it +manages some 1500 lines during that time on Chrome. All it has to do +is munge strings, so there is no real reason for it to be slow +anymore.

    + +

    What Gives?

    + +

    Given all this, what can you expect from CodeMirror 2?

    + +
      + +
    • Small. the base library is +some 45k when minified +now, 17k when gzipped. It's smaller than +its own logo.
    • + +
    • Lightweight. CodeMirror 2 initializes very +quickly, and does almost no work when it is not focused. This means +you can treat it almost like a textarea, have multiple instances on a +page without trouble.
    • + +
    • Huge document support. Since highlighting is +really fast, and no DOM structure is being built for non-visible +content, you don't have to worry about locking up your browser when a +user enters a megabyte-sized document.
    • + +
    • Extended API. Some things kept coming up in the +mailing list, such as marking pieces of text or lines, which were +extremely hard to do with CodeMirror 1. The new version has proper +support for these built in.
    • + +
    • Tab support. Tabs inside editable documents were, +for some reason, a no-go. At least six different people announced they +were going to add tab support to CodeMirror 1, none survived (I mean, +none delivered a working version). CodeMirror 2 no longer removes tabs +from your document.
    • + +
    • Sane styling. iframe nodes aren't +really known for respecting document flow. Now that an editor instance +is a plain div element, it is much easier to size it to +fit the surrounding elements. You don't even have to make it scroll if +you do not want to.
    • + +
    + +

    On the downside, a CodeMirror 2 instance is not a native +editable component. Though it does its best to emulate such a +component as much as possible, there is functionality that browsers +just do not allow us to hook into. Doing select-all from the context +menu, for example, is not currently detected by CodeMirror.

    + +

    [Updates from November 13th 2011] Recently, I've made +some changes to the codebase that cause some of the text above to no +longer be current. I've left the text intact, but added markers at the +passages that are now inaccurate. The new situation is described +below.

    + +

    Content Representation

    + +

    The original implementation of CodeMirror 2 represented the +document as a flat array of line objects. This worked well—splicing +arrays will require the part of the array after the splice to be +moved, but this is basically just a simple memmove of a +bunch of pointers, so it is cheap even for huge documents.

    + +

    However, I recently added line wrapping and code folding (line +collapsing, basically). Once lines start taking up a non-constant +amount of vertical space, looking up a line by vertical position +(which is needed when someone clicks the document, and to determine +the visible part of the document during scrolling) can only be done +with a linear scan through the whole array, summing up line heights as +you go. Seeing how I've been going out of my way to make big documents +fast, this is not acceptable.

    + +

    The new representation is based on a B-tree. The leaves of the tree +contain arrays of line objects, with a fixed minimum and maximum size, +and the non-leaf nodes simply hold arrays of child nodes. Each node +stores both the amount of lines that live below them and the vertical +space taken up by these lines. This allows the tree to be indexed both +by line number and by vertical position, and all access has +logarithmic complexity in relation to the document size.

    + +

    I gave line objects and tree nodes parent pointers, to the node +above them. When a line has to update its height, it can simply walk +these pointers to the top of the tree, adding or subtracting the +difference in height from each node it encounters. The parent pointers +also make it cheaper (in complexity terms, the difference is probably +tiny in normal-sized documents) to find the current line number when +given a line object. In the old approach, the whole document array had +to be searched. Now, we can just walk up the tree and count the sizes +of the nodes coming before us at each level.

    + +

    I chose B-trees, not regular binary trees, mostly because they +allow for very fast bulk insertions and deletions. When there is a big +change to a document, it typically involves adding, deleting, or +replacing a chunk of subsequent lines. In a regular balanced tree, all +these inserts or deletes would have to be done separately, which could +be really expensive. In a B-tree, to insert a chunk, you just walk +down the tree once to find where it should go, insert them all in one +shot, and then break up the node if needed. This breaking up might +involve breaking up nodes further up, but only requires a single pass +back up the tree. For deletion, I'm somewhat lax in keeping things +balanced—I just collapse nodes into a leaf when their child count goes +below a given number. This means that there are some weird editing +patterns that may result in a seriously unbalanced tree, but even such +an unbalanced tree will perform well, unless you spend a day making +strangely repeating edits to a really big document.

    + +

    Keymaps

    + +

    Above, I claimed that directly catching key +events for things like cursor movement is impractical because it +requires some browser-specific kludges. I then proceeded to explain +some awful hacks that were needed to make it +possible for the selection changes to be detected through the +textarea. In fact, the second hack is about as bad as the first.

    + +

    On top of that, in the presence of user-configurable tab sizes and +collapsed and wrapped lines, lining up cursor movement in the textarea +with what's visible on the screen becomes a nightmare. Thus, I've +decided to move to a model where the textarea's selection is no longer +depended on.

    + +

    So I moved to a model where all cursor movement is handled by my +own code. This adds support for a goal column, proper interaction of +cursor movement with collapsed lines, and makes it possible for +vertical movement to move through wrapped lines properly, instead of +just treating them like non-wrapped lines.

    + +

    The key event handlers now translate the key event into a string, +something like Ctrl-Home or Shift-Cmd-R, and +use that string to look up an action to perform. To make keybinding +customizable, this lookup goes through +a table, using a scheme that +allows such tables to be chained together (for example, the default +Mac bindings fall through to a table named 'emacsy', which defines +basic Emacs-style bindings like Ctrl-F, and which is also +used by the custom Emacs bindings).

    + +

    A new +option extraKeys +allows ad-hoc keybindings to be defined in a much nicer way than what +was possible with the +old onKeyEvent +callback. You simply provide an object mapping key identifiers to +functions, instead of painstakingly looking at raw key events.

    + +

    Built-in commands map to strings, rather than functions, for +example "goLineUp" is the default action bound to the up +arrow key. This allows new keymaps to refer to them without +duplicating any code. New commands can be defined by assigning to +the CodeMirror.commands object, which maps such commands +to functions.

    + +

    The hidden textarea now only holds the current selection, with no +extra characters around it. This has a nice advantage: polling for +input becomes much, much faster. If there's a big selection, this text +does not have to be read from the textarea every time—when we poll, +just noticing that something is still selected is enough to tell us +that no new text was typed.

    + +

    The reason that cheap polling is important is that many browsers do +not fire useful events on IME (input method engine) input, which is +the thing where people inputting a language like Japanese or Chinese +use multiple keystrokes to create a character or sequence of +characters. Most modern browsers fire input when the +composing is finished, but many don't fire anything when the character +is updated during composition. So we poll, whenever the +editor is focused, to provide immediate updates of the display.

    + +
    + +
     
    + + + --- /dev/null +++ b/js/flotr2/examples/lib/codemirror/doc/manual.html @@ -1,1 +1,968 @@ - + + + + CodeMirror: User Manual + + + + + + + +

    { } CodeMirror

    + +
    +/* User manual and
    +   reference guide */
    +
    + +
    + +

    Overview

    + +

    CodeMirror is a code-editor component that can be embedded in + Web pages. The code library provides only the editor + component, no accompanying buttons, auto-completion, or other IDE + functionality. It does provide a rich API on top of which such + functionality can be straightforwardly implemented. See + the add-ons included in the distribution, + and + the CodeMirror + UI project, for reusable implementations of extra features.

    + +

    CodeMirror works with language-specific modes. Modes are + JavaScript programs that help color (and optionally indent) text + written in a given language. The distribution comes with a few + modes (see the mode/ directory), and it isn't hard + to write new ones for other languages.

    + +

    Basic Usage

    + +

    The easiest way to use CodeMirror is to simply load the script + and style sheet found under lib/ in the distribution, + plus a mode script from one of the mode/ directories + and a theme stylesheet from theme/. (See + also the compression helper.) For + example:

    + +
    <script src="lib/codemirror.js"></script>
    +<link rel="stylesheet" href="../lib/codemirror.css">
    +<script src="mode/javascript/javascript.js"></script>
    + +

    Having done this, an editor instance can be created like + this:

    + +
    var myCodeMirror = CodeMirror(document.body);
    + +

    The editor will be appended to the document body, will start + empty, and will use the mode that we loaded. To have more control + over the new editor, a configuration object can be passed + to CodeMirror as a second argument:

    + +
    var myCodeMirror = CodeMirror(document.body, {
    +  value: "function myScript(){return 100;}\n",
    +  mode:  "javascript"
    +});
    + +

    This will initialize the editor with a piece of code already in + it, and explicitly tell it to use the JavaScript mode (which is + useful when multiple modes are loaded). + See below for a full discussion of the + configuration options that CodeMirror accepts.

    + +

    In cases where you don't want to append the editor to an + element, and need more control over the way it is inserted, the + first argument to the CodeMirror function can also + be a function that, when given a DOM element, inserts it into the + document somewhere. This could be used to, for example, replace a + textarea with a real editor:

    + +
    var myCodeMirror = CodeMirror(function(elt) {
    +  myTextArea.parentNode.replaceChild(elt, myTextArea);
    +}, {value: myTextArea.value});
    + +

    However, for this use case, which is a common way to use + CodeMirror, the library provides a much more powerful + shortcut:

    + +
    var myCodeMirror = CodeMirror.fromTextArea(myTextArea);
    + +

    This will, among other things, ensure that the textarea's value + is updated when the form (if it is part of a form) is submitted. + See the API reference for a full + description of this method.

    + +

    Configuration

    + +

    Both the CodeMirror function and + its fromTextArea method take as second (optional) + argument an object containing configuration options. Any option + not supplied like this will be taken + from CodeMirror.defaults, an object containing the + default options. You can update this object to change the defaults + on your page.

    + +

    Options are not checked in any way, so setting bogus option + values is bound to lead to odd errors.

    + +

    These are the supported options:

    + +
    +
    value (string)
    +
    The starting value of the editor.
    + +
    mode (string or object)
    +
    The mode to use. When not given, this will default to the + first mode that was loaded. It may be a string, which either + simply names the mode or is + a MIME type + associated with the mode. Alternatively, it may be an object + containing configuration options for the mode, with + a name property that names the mode (for + example {name: "javascript", json: true}). The demo + pages for each mode contain information about what configuration + parameters the mode supports. You can ask CodeMirror which modes + and MIME types are loaded with + the CodeMirror.listModes + and CodeMirror.listMIMEs functions.
    + +
    theme (string)
    +
    The theme to style the editor with. You must make sure the + CSS file defining the corresponding .cm-s-[name] + styles is loaded (see + the theme directory in the + distribution). The default is "default", for which + colors are included in codemirror.css. It is + possible to use multiple theming classes at once—for + example "foo bar" will assign both + the cm-s-foo and the cm-s-bar classes + to the editor.
    + +
    indentUnit (integer)
    +
    How many spaces a block (whatever that means in the edited + language) should be indented. The default is 2.
    + +
    tabSize (integer)
    +
    The width of a tab character. Defaults to 4.
    + +
    indentWithTabs (boolean)
    +
    Whether, when indenting, the first N*tabSize + spaces should be replaced by N tabs. Default is false.
    + +
    electricChars (boolean)
    +
    Configures whether the editor should re-indent the current + line when a character is typed that might change its proper + indentation (only works if the mode supports indentation). + Default is true.
    + +
    keyMap (string)
    +
    Configures the keymap to use. The default + is "default", which is the only keymap defined + in codemirror.js itself. Extra keymaps are found in + the keymap directory.
    + +
    extraKeys (object)
    +
    Can be used to specify extra keybindings for the editor. + When given, should be an object with property names + like Ctrl-A, Home, + and Ctrl-Alt-Left. See + the CodeMirror.keyNames object for the names of all + the keys. The values in this object can either be functions, + which will be called with the CodeMirror instance when the key + is pressed, or strings, which should name commands defined + in CodeMirror.commands (not documented properly, + but looking at the source and the definition of the built-in + keymaps, they should be rather obvious).
    + +
    lineWrapping (boolean)
    +
    Whether CodeMirror should scroll or wrap for long lines. + Defaults to false (scroll).
    + +
    lineNumbers (boolean)
    +
    Whether to show line numbers to the left of the editor.
    + +
    firstLineNumber (integer)
    +
    At which number to start counting lines. Default is 1.
    + +
    gutter (boolean)
    +
    Can be used to force a 'gutter' (empty space on the left of + the editor) to be shown even when no line numbers are active. + This is useful for setting markers.
    + +
    fixedGutter (boolean)
    +
    When enabled (off by default), this will make the gutter + stay visible when the document is scrolled horizontally.
    + +
    readOnly (boolean)
    +
    This disables editing of the editor content by the user.
    + +
    onChange (function)
    +
    When given, this function will be called every time the + content of the editor is changed. It will be given the editor + instance as first argument, and an {from, to, newText, + next} object containing information about the changes + that occurred as second argument. from + and to are the positions (in the pre-change + coordinate system) where the change started and + ended. newText is an array of strings representing + the text that replaced the changed range (split by line). If + multiple changes happened during a single operation, the object + will have a next property pointing to another + change object (which may point to another, etc).
    + +
    onCursorActivity (function)
    +
    Will be called when the cursor or selection moves, or any + change is made to the editor content.
    + +
    onGutterClick (function)
    +
    When given, will be called whenever the editor gutter (the + line-number area) is clicked. Will be given the editor instance + as first argument, the (zero-based) number of the line that was + clicked as second argument, and the raw mousedown + event object as third argument.
    + +
    onFocus, onBlur (function)
    +
    The given functions will be called whenever the editor is + focused or unfocused.
    + +
    onScroll (function)
    +
    When given, will be called whenever the editor is + scrolled.
    + +
    onHighlightComplete (function)
    +
    Whenever the editor's content has been fully highlighted, + this function (if given) will be called. It'll be given a single + argument, the editor instance.
    + +
    onUpdate (function)
    +
    Will be called whenever CodeMirror updates its DOM display.
    + +
    matchBrackets (boolean)
    +
    Determines whether brackets are matched whenever the cursor + is moved next to a bracket.
    + +
    workTime, workDelay (number)
    +
    Highlighting is done by a pseudo background-thread that will + work for workTime milliseconds, and then use + timeout to sleep for workDelay milliseconds. The + defaults are 200 and 300, you can change these options to make + the highlighting more or less aggressive.
    + +
    pollInterval (number)
    +
    Indicates how quickly CodeMirror should poll its input + textarea for changes. Most input is captured by events, but some + things, like IME input on some browsers, doesn't generate events + that allow CodeMirror to properly detect it. Thus, it polls. + Default is 100 milliseconds.
    + +
    undoDepth (integer)
    +
    The maximum number of undo levels that the editor stores. + Defaults to 40.
    + +
    tabindex (integer)
    +
    The tab + index to assign to the editor. If not given, no tab index + will be assigned.
    + +
    document (DOM document)
    +
    Use this if you want to display the editor in another DOM. + By default it will use the global document + object.
    + +
    onKeyEvent (function)
    +
    This provides a rather low-level hook into CodeMirror's key + handling. If provided, this function will be called on + every keydown, keyup, + and keypress event that CodeMirror captures. It + will be passed two arguments, the editor instance and the key + event. This key event is pretty much the raw key event, except + that a stop() method is always added to it. You + could feed it to, for example, jQuery.Event to + further normalize it.
    This function can inspect the key + event, and handle it if it wants to. It may return true to tell + CodeMirror to ignore the event. Be wary that, on some browsers, + stopping a keydown does not stop + the keypress from firing, whereas on others it + does. If you respond to an event, you should probably inspect + its type property and only do something when it + is keydown (or keypress for actions + that need character data).
    +
    + +

    Customized Styling

    + +

    Up to a certain extent, CodeMirror's look can be changed by + modifying style sheet files. The style sheets supplied by modes + simply provide the colors for that mode, and can be adapted in a + very straightforward way. To style the editor itself, it is + possible to alter or override the styles defined + in codemirror.css.

    + +

    Some care must be taken there, since a lot of the rules in this + file are necessary to have CodeMirror function properly. Adjusting + colors should be safe, of course, and with some care a lot of + other things can be changed as well. The CSS classes defined in + this file serve the following roles:

    + +
    +
    CodeMirror
    +
    The outer element of the editor. This should be used for + borders and positioning. Can also be used to set styles that + should hold for everything inside the editor (such as font + and font size), or to set a background.
    + +
    CodeMirror-scroll
    +
    This determines whether the editor scrolls (overflow: + auto + fixed height). By default, it does. Giving + this height: auto; overflow: visible; will cause + the editor to resize to fit its content.
    + +
    CodeMirror-focused
    +
    Whenever the editor is focused, the top element gets this + class. This is used to hide the cursor and give the selection a + different color when the editor is not focused.
    + +
    CodeMirror-gutter
    +
    Use this for giving a background or a border to the editor + gutter. Don't set any padding here, + use CodeMirror-gutter-text for that. By default, + the gutter is 'fluid', meaning it will adjust its width to the + maximum line number or line marker width. You can also set a + fixed width if you want.
    + +
    CodeMirror-gutter-text
    +
    Used to style the actual line numbers. For the numbers to + line up, you must make sure that the font in the gutter is the + same as the one in the rest of the editor, so you should + probably only set font style and size in + the CodeMirror class.
    + +
    CodeMirror-lines
    +
    The visible lines. If this has vertical + padding, CodeMirror-gutter should have the same + padding.
    + +
    CodeMirror-cursor
    +
    The cursor is a block element that is absolutely positioned. + You can make it look whichever way you want.
    + +
    CodeMirror-selected
    +
    The selection is represented by span elements + with this class.
    + +
    CodeMirror-matchingbracket, + CodeMirror-nonmatchingbracket
    +
    These are used to style matched (or unmatched) brackets.
    +
    + +

    The actual lines, as well as the cursor, are represented + by pre elements. By default no text styling (such as + bold) that might change line height is applied. If you do want + such effects, you'll have to give CodeMirror pre a + fixed height. Also, you must still take care that character width + is constant.

    + +

    If your page's style sheets do funky things to + all div or pre elements (you probably + shouldn't do that), you'll have to define rules to cancel these + effects out again for elements under the CodeMirror + class.

    + +

    Themes are also simply CSS files, which define colors for + various syntactic elements. See the files in + the theme directory.

    + +

    Programming API

    + +

    A lot of CodeMirror features are only available through its API. + This has the disadvantage that you need to do work to enable them, + and the advantage that CodeMirror will fit seamlessly into your + application.

    + +

    Whenever points in the document are represented, the API uses + objects with line and ch properties. + Both are zero-based. CodeMirror makes sure to 'clip' any positions + passed by client code so that they fit inside the document, so you + shouldn't worry too much about sanitizing your coordinates. If you + give ch a value of null, or don't + specify it, it will be replaced with the length of the specified + line.

    + +
    +
    getValue() → string
    +
    Get the current editor content.
    +
    setValue(string)
    +
    Set the editor content.
    + +
    getSelection() → string
    +
    Get the currently selected code.
    +
    replaceSelection(string)
    +
    Replace the selection with the given string.
    + +
    focus()
    +
    Give the editor focus.
    + +
    setOption(option, value)
    +
    Change the configuration of the editor. option + should the name of an option, + and value should be a valid value for that + option.
    +
    getOption(option) → value
    +
    Retrieves the current value of the given option for this + editor instance.
    + +
    cursorCoords(start) → object
    +
    Returns an {x, y, yBot} object containing the + coordinates of the cursor relative to the top-left corner of the + page. yBot is the coordinate of the bottom of the + cursor. start is a boolean indicating whether you + want the start or the end of the selection.
    +
    charCoords(pos) → object
    +
    Like cursorCoords, but returns the position of + an arbitrary characters. pos should be + a {line, ch} object.
    +
    coordsChar(object) → pos
    +
    Given an {x, y} object (in page coordinates), + returns the {line, ch} position that corresponds to + it.
    + +
    undo()
    +
    Undo one edit (if any undo events are stored).
    +
    redo()
    +
    Redo one undone edit.
    +
    historySize() → object
    +
    Returns an object with {undo, redo} properties, + both of which hold integers, indicating the amount of stored + undo and redo operations.
    +
    clearHistory()
    +
    Clears the editor's undo history.
    + +
    indentLine(line, dir)
    +
    Reset the given line's indentation to the indentation + prescribed by the mode. If the second argument is given, + indentation will be increased (if dir is true) or + decreased (if false) by an indent + unit instead.
    + +
    getTokenAt(pos) → object
    +
    Retrieves information about the token the current mode found + at the given position (a {line, ch} object). The + returned object has the following properties: +
    +
    start
    The character (on the given line) at which the token starts.
    +
    end
    The character at which the token ends.
    +
    string
    The token's string.
    +
    className
    The class the mode assigned + to the token. (Can be null when no class was assigned.)
    +
    state
    The mode's state at the end of this token.
    +
    + +
    markText(from, to, className) → object
    +
    Can be used to mark a range of text with a specific CSS + class name. from and to should + be {line, ch} objects. The method will return an + object with two methods, clear(), which removes the + mark, and find(), which returns a {from, + to} (both document positions), indicating the current + position of the marked range.
    + +
    setBookmark(pos) → object
    +
    Inserts a bookmark, a handle that follows the text around it + as it is being edited, at the given position. A bookmark has two + methods find() and clear(). The first + returns the current position of the bookmark, if it is still in + the document, and the second explicitly removes the + bookmark.
    + +
    setMarker(line, text, className) → lineHandle
    +
    Add a gutter marker for the given line. Gutter markers are + shown in the line-number area (instead of the number for this + line). Both text and className are + optional. Setting text to a Unicode character like + ● tends to give a nice effect. To put a picture in the gutter, + set text to a space and className to + something that sets a background image. If you + specify text, the given text (which may contain + HTML) will, by default, replace the line number for that line. + If this is not what you want, you can include the + string %N% in the text, which will be replaced by + the line number.
    +
    clearMarker(line)
    +
    Clears a marker created + with setMarker. line can be either a + number or a handle returned by setMarker (since a + number may now refer to a different line if something was added + or deleted).
    +
    setLineClass(line, className) → lineHandle
    +
    Set a CSS class name for the given line. line + can be a number or a line handle (as returned + by setMarker or this function). + Pass null to clear the class for a line.
    +
    hideLine(line) → lineHandle
    +
    Hide the given line (either by number or by handle). Hidden + lines don't show up in the editor, and their numbers are skipped + when line numbers are enabled. + Deleting a region around them does delete them, and coping a + region around will include them in the copied text.
    +
    showLine(line) → lineHandle
    +
    The inverse of hideLine—re-shows a previously + hidden line, by number or by handle.
    + +
    onDeleteLine(line, func)
    +
    Register a function that should be called when the line is + deleted from the document.
    + +
    lineInfo(line) → object
    +
    Returns the line number, text content, and marker status of + the given line, which can be either a number or a handle + returned by setMarker. The returned object has the + structure {line, handle, text, markerText, markerClass}.
    + +
    getLineHandle(num) → lineHandle
    +
    Fetches the line handle for the given line number.
    + +
    addWidget(pos, node, scrollIntoView)
    +
    Puts node, which should be an absolutely + positioned DOM node, into the editor, positioned right below the + given {line, ch} position. + When scrollIntoView is true, the editor will ensure + that the entire node is visible (if possible). To remove the + widget again, simply use DOM methods (move it somewhere else, or + call removeChild on its parent).
    + +
    matchBrackets()
    +
    Force matching-bracket-highlighting to happen.
    + +
    lineCount() → number
    +
    Get the number of lines in the editor.
    + +
    getCursor(start) → object
    +
    start is a boolean indicating whether the start + or the end of the selection must be retrieved. If it is not + given, the current cursor pos, i.e. the side of the selection + that would move if you pressed an arrow key, is chosen. + A {line, ch} object will be returned.
    +
    somethingSelected() → boolean
    +
    Return true if any text is selected.
    +
    setCursor(pos)
    +
    Set the cursor position. You can either pass a + single {line, ch} object, or the line and the + character as two separate parameters.
    +
    setSelection(start, end)
    +
    Set the selection range. start + and end should be {line, ch} objects.
    + +
    getLine(n) → string
    +
    Get the content of line n.
    +
    setLine(n, text)
    +
    Set the content of line n.
    +
    removeLine(n)
    +
    Remove the given line from the document.
    + +
    getRange(from, to) → string +
    Get the text between the given points in the editor, which + should be {line, ch} objects.
    +
    replaceRange(string, from, to)
    +
    Replace the part of the document between from + and to with the given string. from + and to must be {line, ch} + objects. to can be left off to simply insert the + string at position from.
    + +
    posFromIndex(index) → object
    +
    Calculates and returns a {line, ch} object for a + zero-based index who's value is relative to the start of the + editor's text. If the index is out of range of the text then + the returned object is clipped to start or end of the text + respectively.
    +
    indexFromPos(object) → number
    +
    The reverse of posFromIndex.
    +
    + +

    The following are more low-level methods:

    + +
    +
    operation(func) → result
    +
    CodeMirror internally buffers changes and only updates its + DOM structure after it has finished performing some operation. + If you need to perform a lot of operations on a CodeMirror + instance, you can call this method with a function argument. It + will call the function, buffering up all changes, and only doing + the expensive update after the function returns. This can be a + lot faster. The return value from this method will be the return + value of your function.
    + +
    refresh()
    +
    If your code does something to change the size of the editor + element (window resizes are already listened for), or unhides + it, you should probably follow up by calling this method to + ensure CodeMirror is still looking as intended.
    + +
    getInputField() → textarea
    +
    Returns the hiden textarea used to read input.
    +
    getWrapperElement() → node
    +
    Returns the DOM node that represents the editor. Remove this + from your tree to delete an editor instance.
    +
    getScrollerElement() → node
    +
    Returns the DOM node that is responsible for the sizing and + the scrolling of the editor. You can change + the height and width styles of this + element to resize an editor. (You might have to call + the refresh method + afterwards.)
    +
    getGutterElement() → node
    +
    Fetches the DOM node that represents the editor gutter.
    + +
    getStateAfter(line) → state
    +
    Returns the mode's parser state, if any, at the end of the + given line number. If no line number is given, the state at the + end of the document is returned. This can be useful for storing + parsing errors in the state, or getting other kinds of + contextual information for a line.
    +
    + +

    Finally, the CodeMirror object + itself has a method fromTextArea. This takes a + textarea DOM node as first argument and an optional configuration + object as second. It will replace the textarea with a CodeMirror + instance, and wire up the form of that textarea (if any) to make + sure the editor contents are put into the textarea when the form + is submitted. A CodeMirror instance created this way has two + additional methods:

    + +
    +
    save()
    +
    Copy the content of the editor into the textarea.
    + +
    toTextArea()
    +
    Remove the editor, and restore the original textarea (with + the editor's current content).
    + +
    getTextArea() → textarea
    +
    Returns the textarea that the instance was based on.
    +
    + +

    If you want to define extra methods in terms + of the CodeMirror API, it is possible to + use CodeMirror.defineExtension(name, value). This + will cause the given value (usually a method) to be added to all + CodeMirror instances created from then on.

    + +

    Add-ons

    + +

    The lib/util directory in the distribution + contains a number of reusable components that implement extra + editor functionality. In brief, they are:

    + +
    +
    dialog.js
    +
    Provides a very simple way to query users for text input. + Adds an openDialog method to CodeMirror instances, + which can be called with an HTML fragment that provides the + prompt (should include an input tag), and a + callback function that is called when text has been entered. + Depends on lib/util/dialog.css.
    +
    searchcursor.js
    +
    Adds the getSearchCursor(query, start, caseFold) → + cursor method to CodeMirror instances, which can be used + to implement search/replace functionality. query + can be a regular expression or a string (only strings will match + across lines—if they contain newlines). start + provides the starting position of the search. It can be + a {line, ch} object, or can be left off to default + to the start of the document. caseFold is only + relevant when matching a string. It will cause the search to be + case-insensitive. A search cursor has the following methods: +
    +
    findNext(), findPrevious() → boolean
    +
    Search forward or backward from the current position. + The return value indicates whether a match was found. If + matching a regular expression, the return value will be the + array returned by the match method, in case you + want to extract matched groups.
    +
    from(), to() → object
    +
    These are only valid when the last call + to findNext or findPrevious did + not return false. They will return {line, ch} + objects pointing at the start and end of the match.
    +
    replace(text)
    +
    Replaces the currently found match with the given text + and adjusts the cursor position to reflect the + replacement.
    +
    + + +
    Implements the search commands. CodeMirror has keys bound to + these by default, but will not do anything with them unless an + implementation is provided. Depends + on searchcursor.js, and will make use + of openDialog when + available to make prompting for search queries less ugly.
    +
    foldcode.js
    +
    Helps with code folding. See the + demo for an example. + Call CodeMirror.newFoldFunction with a range-finder + helper function to create a function that will, when applied to + a CodeMirror instance and a line number, attempt to fold or + unfold the block starting at the given line. A range-finder is a + language-specific functoin that also takes an instance and a + line number, and returns an end line for the block, or null if + no block is started on that line. This file + provides CodeMirror.braceRangeFinder, which finds + blocks in brace languages (JavaScript, C, Java, etc).
    +
    runmode.js
    +
    Can be used to run a CodeMirror mode over text without + actually opening an editor instance. + See the demo for an + example.
    +
    simple-hint.js
    +
    Provides a framework for showing autocompletion hints. + Defines CodeMirror.simpleHint, which takes a + CodeMirror instance and a hinting function, and pops up a widget + that allows the user to select a completion. Hinting functions + are function that take an editor instance, and return + a {list, from, to} object, where list + is an array of strings (the completions), and from + and to give the start and end of the token that is + being completed. Depends + on lib/util/simple-hint.css.
    +
    javascript-hint.js
    +
    Defines CodeMirror.javaScriptHint, which is a + simple hinting function for the JavaScript mode.
    +
    + +

    Writing CodeMirror Modes

    + +

    Modes typically consist of a single JavaScript file. This file + defines, in the simplest case, a lexer (tokenizer) for your + language—a function that takes a character stream as input, + advances it past a token, and returns a style for that token. More + advanced modes can also handle indentation for the language.

    + +

    The mode script should + call CodeMirror.defineMode to register itself with + CodeMirror. This function takes two arguments. The first should be + the name of the mode, for which you should use a lowercase string, + preferably one that is also the name of the files that define the + mode (i.e. "xml" is defined xml.js). The + second argument should be a function that, given a CodeMirror + configuration object (the thing passed to + the CodeMirror function) and an optional mode + configuration object (as in + the mode option), returns + a mode object.

    + +

    Typically, you should use this second argument + to defineMode as your module scope function (modes + should not leak anything into the global scope!), i.e. write your + whole mode inside this function.

    + +

    The main responsibility of a mode script is parsing + the content of the editor. Depending on the language and the + amount of functionality desired, this can be done in really easy + or extremely complicated ways. Some parsers can be stateless, + meaning that they look at one element (token) of the code + at a time, with no memory of what came before. Most, however, will + need to remember something. This is done by using a state + object, which is an object that is always passed when + reading a token, and which can be mutated by the tokenizer.

    + +

    Modes that use a state must define + a startState method on their mode object. This is a + function of no arguments that produces a state object to be used + at the start of a document.

    + +

    The most important part of a mode object is + its token(stream, state) method. All modes must + define this method. It should read one token from the stream it is + given as an argument, optionally update its state, and return a + style string, or null for tokens that do not have to + be styled. For your styles, you can either use the 'standard' ones + defined in the themes (without the cm- prefix), or + define your own (as the diff + mode does) and have people include a custom CSS file for your + mode.

    + +

    The stream object encapsulates a line of code + (tokens may never span lines) and our current position in that + line. It has the following API:

    + +
    +
    eol() → boolean
    +
    Returns true only if the stream is at the end of the + line.
    +
    sol() → boolean
    +
    Returns true only if the stream is at the start of the + line.
    + +
    peek() → character
    +
    Returns the next character in the stream without advancing + it. Will return undefined at the end of the + line.
    +
    next() → character
    +
    Returns the next character in the stream and advances it. + Also returns undefined when no more characters are + available.
    + +
    eat(match) → character
    +
    match can be a character, a regular expression, + or a function that takes a character and returns a boolean. If + the next character in the stream 'matches' the given argument, + it is consumed and returned. Otherwise, undefined + is returned.
    +
    eatWhile(match) → boolean
    +
    Repeatedly calls eat with the given argument, + until it fails. Returns true if any characters were eaten.
    +
    eatSpace() → boolean
    +
    Shortcut for eatWhile when matching + white-space.
    +
    skipToEnd()
    +
    Moves the position to the end of the line.
    +
    skipTo(ch) → boolean
    +
    Skips to the next occurrence of the given character, if + found on the current line (doesn't advance the stream if the + character does not occur on the line). Returns true if the + character was found.
    +
    match(pattern, consume, caseFold) → boolean
    +
    Act like a + multi-character eat—if consume is true + or not given—or a look-ahead that doesn't update the stream + position—if it is false. pattern can be either a + string or a regular expression starting with ^. + When it is a string, caseFold can be set to true to + make the match case-insensitive. When successfully matching a + regular expression, the returned value will be the array + returned by match, in case you need to extract + matched groups.
    + +
    backUp(n)
    +
    Backs up the stream n characters. Backing it up + further than the start of the current token will cause things to + break, so be careful.
    +
    column() → integer
    +
    Returns the column (taking into account tabs) at which the + current token starts. Can be used to find out whether a token + starts a new line.
    +
    indentation() → integer
    +
    Tells you how far the current line has been indented, in + spaces. Corrects for tab characters.
    + +
    current() → string
    +
    Get the string between the start of the current token and + the current stream position.
    +
    + +

    By default, blank lines are simply skipped when + tokenizing a document. For languages that have significant blank + lines, you can define a blankLine(state) method on + your mode that will get called whenever a blank line is passed + over, so that it can update the parser state.

    + +

    Because state object are mutated, and CodeMirror + needs to keep valid versions of a state around so that it can + restart a parse at any line, copies must be made of state objects. + The default algorithm used is that a new state object is created, + which gets all the properties of the old object. Any properties + which hold arrays get a copy of these arrays (since arrays tend to + be used as mutable stacks). When this is not correct, for example + because a mode mutates non-array properties of its state object, a + mode object should define a copyState method, + which is given a state and should return a safe copy of that + state.

    + +

    By default, CodeMirror will stop re-parsing + a document as soon as it encounters a few lines that were + highlighted the same in the old parse as in the new one. It is + possible to provide an explicit way to test whether a state is + equivalent to another one, which CodeMirror will use (instead of + the unchanged-lines heuristic) to decide when to stop + highlighting. You do this by providing + a compareStates method on your mode object, which + takes two state arguments and returns a boolean indicating whether + they are equivalent. See the XML mode, which uses this to provide + reliable highlighting of bad closing tags, as an example.

    + +

    If you want your mode to provide smart indentation + (though the indentLine + method and the indentAuto + and newlineAndIndent commands, which keys can be + bound to), you must define + an indent(state, textAfter) method on your mode + object.

    + +

    The indentation method should inspect the given state object, + and optionally the textAfter string, which contains + the text on the line that is being indented, and return an + integer, the amount of spaces to indent. It should usually take + the indentUnit + option into account.

    + +

    Finally, a mode may define + an electricChars property, which should hold a string + containing all the characters that should trigger the behaviour + described for + the electricChars + option.

    + +

    So, to summarize, a mode must provide + a token method, and it may + provide startState, copyState, + compareStates, and indent methods. For + an example of a trivial mode, see + the diff mode, for a more involved + example, see the C-like + mode.

    + +

    Sometimes, it is useful for modes to nest—to have one + mode delegate work to another mode. An example of this kind of + mode is the mixed-mode HTML + mode. To implement such nesting, it is usually necessary to + create mode objects and copy states yourself. To create a mode + object, there are CodeMirror.getMode(options, + parserConfig), where the first argument is a configuration + object as passed to the mode constructor function, and the second + argument is a mode specification as in + the mode option. To copy a + state object, call CodeMirror.copyState(mode, state), + where mode is the mode that created the given + state.

    + +

    To make indentation work properly in a nested parser, it is + advisable to give the startState method of modes that + are intended to be nested an optional argument that provides the + base indentation for the block of code. The JavaScript and CSS + parser do this, for example, to allow JavaScript and CSS code + inside the mixed-mode HTML mode to be properly indented.

    + +

    Finally, it is possible to associate your mode, or a certain + configuration of your mode, with + a MIME type. For + example, the JavaScript mode associates itself + with text/javascript, and its JSON variant + with application/json. To do this, + call CodeMirror.defineMIME(mime, modeSpec), + where modeSpec can be a string or object specifying a + mode, as in the mode + option.

    + +
    + +
     
    + + + + --- /dev/null +++ b/js/flotr2/examples/lib/codemirror/doc/oldrelease.html @@ -1,1 +1,215 @@ - + + + + CodeMirror + + + + + + + +

    { } CodeMirror

    + +
    +/* Old release history */
    +
    +
    +

    07-06-2011: Version 2.1:

    +

    Add + a theme system + (demo). Note that this is not + backwards-compatible—you'll have to update your styles and + modes!

    + +

    07-06-2011: Version 2.02:

    +
      +
    • Add a Lua mode.
    • +
    • Fix reverse-searching for a regexp.
    • +
    • Empty lines can no longer break highlighting.
    • +
    • Rework scrolling model (the outer wrapper no longer does the scrolling).
    • +
    • Solve horizontal jittering on long lines.
    • +
    • Add runmode.js.
    • +
    • Immediately re-highlight text when typing.
    • +
    • Fix problem with 'sticking' horizontal scrollbar.
    • +
    + +

    26-05-2011: Version 2.01:

    +
      +
    • Add a Smalltalk mode.
    • +
    • Add a reStructuredText mode.
    • +
    • Add a Python mode.
    • +
    • Add a PL/SQL mode.
    • +
    • coordsChar now works
    • +
    • Fix a problem where onCursorActivity interfered with onChange.
    • +
    • Fix a number of scrolling and mouse-click-position glitches.
    • +
    • Pass information about the changed lines to onChange.
    • +
    • Support cmd-up/down on OS X.
    • +
    • Add triple-click line selection.
    • +
    • Don't handle shift when changing the selection through the API.
    • +
    • Support "nocursor" mode for readOnly option.
    • +
    • Add an onHighlightComplete option.
    • +
    • Fix the context menu for Firefox.
    • +
    + +

    28-03-2011: Version 2.0:

    +

    CodeMirror 2 is a complete rewrite that's + faster, smaller, simpler to use, and less dependent on browser + quirks. See this + and this + for more information. + +

    28-03-2011: Version 1.0:

    +
      +
    • Fix error when debug history overflows.
    • +
    • Refine handling of C# verbatim strings.
    • +
    • Fix some issues with JavaScript indentation.
    • +
    + +

    22-02-2011: Version 2.0 beta 2:

    +

    Somewhate more mature API, lots of bugs shaken out. + +

    17-02-2011: Version 0.94:

    +
      +
    • tabMode: "spaces" was modified slightly (now indents when something is selected).
    • +
    • Fixes a bug that would cause the selection code to break on some IE versions.
    • +
    • Disabling spell-check on WebKit browsers now works.
    • +
    + +

    08-02-2011: Version 2.0 beta 1:

    +

    CodeMirror 2 is a complete rewrite of + CodeMirror, no longer depending on an editable frame.

    + +

    19-01-2011: Version 0.93:

    +
      +
    • Added a Regular Expression parser.
    • +
    • Fixes to the PHP parser.
    • +
    • Support for regular expression in search/replace.
    • +
    • Add save method to instances created with fromTextArea.
    • +
    • Add support for MS T-SQL in the SQL parser.
    • +
    • Support use of CSS classes for highlighting brackets.
    • +
    • Fix yet another hang with line-numbering in hidden editors.
    • +
    + +

    17-12-2010: Version 0.92:

    +
      +
    • Make CodeMirror work in XHTML documents.
    • +
    • Fix bug in handling of backslashes in Python strings.
    • +
    • The styleNumbers option is now officially + supported and documented.
    • +
    • onLineNumberClick option added.
    • +
    • More consistent names onLoad and + onCursorActivity callbacks. Old names still work, but + are deprecated.
    • +
    • Add a Freemarker mode.
    • +
    + +

    11-11-2010: Version 0.91:

    +
      +
    • Adds support for Java.
    • +
    • Small additions to the PHP and SQL parsers.
    • +
    • Work around various Webkit issues.
    • +
    • Fix toTextArea to update the code in the textarea.
    • +
    • Add a noScriptCaching option (hack to ease development).
    • +
    • Make sub-modes of HTML mixed mode configurable.
    • +
    + +

    02-10-2010: Version 0.9:

    +
      +
    • Add support for searching backwards.
    • +
    • There are now parsers for Scheme, XQuery, and OmetaJS.
    • +
    • Makes height: "dynamic" more robust.
    • +
    • Fixes bug where paste did not work on OS X.
    • +
    • Add a enterMode and electricChars options to make indentation even more customizable.
    • +
    • Add firstLineNumber option.
    • +
    • Fix bad handling of @media rules by the CSS parser.
    • +
    • Take a new, more robust approach to working around the invisible-last-line bug in WebKit.
    • +
    + +

    22-07-2010: Version 0.8:

    +
      +
    • Add a cursorCoords method to find the screen + coordinates of the cursor.
    • +
    • A number of fixes and support for more syntax in the PHP parser.
    • +
    • Fix indentation problem with JSON-mode JS parser in Webkit.
    • +
    • Add a minification UI.
    • +
    • Support a height: dynamic mode, where the editor's + height will adjust to the size of its content.
    • +
    • Better support for IME input mode.
    • +
    • Fix JavaScript parser getting confused when seeing a no-argument + function call.
    • +
    • Have CSS parser see the difference between selectors and other + identifiers.
    • +
    • Fix scrolling bug when pasting in a horizontally-scrolled + editor.
    • +
    • Support toTextArea method in instances created with + fromTextArea.
    • +
    • Work around new Opera cursor bug that causes the cursor to jump + when pressing backspace at the end of a line.
    • +
    + +

    27-04-2010: Version + 0.67:

    +

    More consistent page-up/page-down behaviour + across browsers. Fix some issues with hidden editors looping forever + when line-numbers were enabled. Make PHP parser parse + "\\" correctly. Have jumpToLine work on + line handles, and add cursorLine function to fetch the + line handle where the cursor currently is. Add new + setStylesheet function to switch style-sheets in a + running editor.

    + +

    01-03-2010: Version + 0.66:

    +

    Adds removeLine method to API. + Introduces the PLSQL parser. + Marks XML errors by adding (rather than replacing) a CSS class, so + that they can be disabled by modifying their style. Fixes several + selection bugs, and a number of small glitches.

    + +

    12-11-2009: Version + 0.65:

    +

    Add support for having both line-wrapping and + line-numbers turned on, make paren-highlighting style customisable + (markParen and unmarkParen config + options), work around a selection bug that Opera + reintroduced in version 10.

    + +

    23-10-2009: Version + 0.64:

    +

    Solves some issues introduced by the + paste-handling changes from the previous release. Adds + setSpellcheck, setTextWrapping, + setIndentUnit, setUndoDepth, + setTabMode, and setLineNumbers to + customise a running editor. Introduces an SQL parser. Fixes a few small + problems in the Python + parser. And, as usual, add workarounds for various newly discovered + browser incompatibilities.

    + +

    31-08-2009: Version +0.63:

    +

    Overhaul of paste-handling (less fragile), fixes for several +serious IE8 issues (cursor jumping, end-of-document bugs) and a number +of small problems.

    + +

    30-05-2009: Version +0.62:

    +

    Introduces Python +and Lua parsers. Add +setParser (on-the-fly mode changing) and +clearHistory methods. Make parsing passes time-based +instead of lines-based (see the passTime option).

    + + + --- /dev/null +++ b/js/flotr2/examples/lib/codemirror/doc/reporting.html @@ -1,1 +1,58 @@ + + + + CodeMirror: Reporting Bugs + + + + + + +

    { } CodeMirror

    + +
    +/* Reporting bugs
    +   effectively */
    +
    + +
    + +

    So you found a problem in CodeMirror. By all means, report it! Bug +reports from users are the main drive behind improvements to +CodeMirror. But first, please read over these points:

    + +
      +
    1. CodeMirror is maintained by volunteers. They don't owe you + anything, so be polite. Reports with an indignant or belligerent + tone tend to be moved to the bottom of the pile.
    2. + +
    3. Include information about the browser in which the + problem occurred. Even if you tested several browsers, and + the problem occurred in all of them, mention this fact in the bug + report. Also include browser version numbers and the operating + system that you're on.
    4. + +
    5. Mention which release of CodeMirror you're using. Preferably, + try also with the current development snapshot, to ensure the + problem has not already been fixed.
    6. + +
    7. Mention very precisely what went wrong. "X is broken" is not a + good bug report. What did you expect to happen? What happened + instead? Describe the exact steps a maintainer has to take to make + the problem occur. We can not fix something that we can not + observe.
    8. + +
    9. If the problem can not be reproduced in any of the demos + included in the CodeMirror distribution, please provide an HTML + document that demonstrates the problem. The best way to do this is + to go to jsbin.com, enter + it there, press save, and include the resulting link in your bug + report.
    10. +
    + +
    + + + + --- /dev/null +++ b/js/flotr2/examples/lib/codemirror/doc/upgrade_v2.2.html @@ -1,1 +1,96 @@ + + + + CodeMirror: Upgrading to v2.2 + + + + + +

    { } CodeMirror

    + +
    +/* Upgrading to v2.2
    + */
    +
    + +
    + +

    There are a few things in the 2.2 release that require some care +when upgrading.

    + +

    No more default.css

    + +

    The default theme is now included +in codemirror.css, so +you do not have to included it separately anymore. (It was tiny, so +even if you're not using it, the extra data overhead is negligible.) + +

    Different key customization

    + +

    CodeMirror has moved to a system +where keymaps are used to +bind behavior to keys. This means custom +bindings are now possible.

    + +

    Three options that influenced key +behavior, tabMode, enterMode, +and smartHome, are no longer supported. Instead, you can +provide custom bindings to influence the way these keys act. This is +done through the +new extraKeys +option, which can hold an object mapping key names to functionality. A +simple example would be:

    + +
      extraKeys: {
    +    "Ctrl-S": function(instance) { saveText(instance.getValue()); },
    +    "Ctrl-/": "undo"
    +  }
    + +

    Keys can be mapped either to functions, which will be given the +editor instance as argument, or to strings, which are mapped through +functions through the CodeMirror.commands table, which +contains all the built-in editing commands, and can be inspected and +extended by external code.

    + +

    By default, the Home key is bound to +the "goLineStartSmart" command, which moves the cursor to +the first non-whitespace character on the line. You can set do this to +make it always go to the very start instead:

    + +
      extraKeys: {"Home": "goLineStart"}
    + +

    Similarly, Enter is bound +to "newLineAndIndent" by default. You can bind it to +something else to get different behavior. To disable special handling +completely and only get a newline character inserted, you can bind it +to false:

    + +
      extraKeys: {"Enter": false}
    + +

    The same works for Tab. If you don't want CodeMirror +to handle it, bind it to false. The default behaviour is +to indent the current line more ("indentMore" command), +and indent it less when shift is held ("indentLess"). +There are also "indentAuto" (smart indent) +and "insertTab" commands provided for alternate +behaviors. Or you can write your own handler function to do something +different altogether.

    + +

    Tabs

    + +

    Handling of tabs changed completely. The display width of tabs can +now be set with the tabSize option, and tabs can +be styled by setting CSS rules +for the cm-tab class.

    + +

    The default width for tabs is now 4, as opposed to the 8 that is +hard-wired into browsers. If you are relying on 8-space tabs, make +sure you explicitly set tabSize: 8 in your options.

    + +
    + + + + --- /dev/null +++ b/js/flotr2/examples/lib/codemirror/index.html @@ -1,1 +1,344 @@ - + + + + CodeMirror + + + + + + + +

    { } CodeMirror

    + +
    +/* In-browser code editing
    +   made bearable */
    +
    + +
    + +

    CodeMirror is a JavaScript library that can + be used to create a relatively pleasant editor interface for + code-like content ― computer programs, HTML markup, and + similar. If a mode has been written for the language you are + editing, the code will be coloured, and the editor will optionally + help you with indentation.

    + +

    This is the project page for CodeMirror 2, the currently more + actively developed, and recommended + version. CodeMirror 1 is still available + from here.

    + + + +

    Getting the code

    + +

    All of CodeMirror is released under a MIT-style license. To get it, you can download + the latest + release or the current development + snapshot as zip files. To create a custom minified script file, + you can use the compression API.

    + +

    We use git for version control. + The main repository can be fetched in this way:

    + +
    git clone http://marijnhaverbeke.nl/git/codemirror2
    + +

    CodeMirror can also be found on GitHub at marijnh/CodeMirror2. + If you plan to hack on the code and contribute patches, the best way + to do it is to create a GitHub fork, and send pull requests.

    + +

    Documentation

    + +

    The manual is your first stop for + learning how to use this library. It starts with a quick explanation + of how to use the editor, and then describes the API in detail.

    + +

    For those who want to learn more about the code, there is + an overview of the internals available. + The source code + itself is, for the most part, also well commented.

    + +

    Support and bug reports

    + +

    There is + a Google + group (a sort of mailing list/newsgroup thing) for discussion + and news related to CodeMirror. When reporting a bug, + read this first. If you have + a github account, + simply open + an issue there. Otherwise, post something to + the group, + or e-mail me directly: Marijn + Haverbeke.

    + +

    Supported browsers

    + +

    The following browsers are able to run CodeMirror:

    + +
      +
    • Firefox 2 or higher
    • +
    • Chrome, any version
    • +
    • Safari 3 or higher
    • +
    • Internet Explorer 6 or higher
    • +
    • Opera 9 or higher (with some key-handling problems on OS X)
    • +
    + +

    I am not actively testing against every new browser release, and + vendors have a habit of introducing bugs all the time, so I am + relying on the community to tell me when something breaks. + See here for information on how to contact + me.

    + +

    Commercial support

    + +

    CodeMirror is developed and maintained by me, Marijn Haverbeke, + in my own time. If your company is getting value out of CodeMirror, + please consider purchasing a support contract.

    + +
      +
    • You'll be funding further work on CodeMirror.
    • +
    • You ensure that you get a quick response when you have a + problem, even when I am otherwise busy.
    • +
    + +

    CodeMirror support contracts exist in two + forms—basic at €100 per month, + and premium at €500 per + month. Contact me for further + information.

    + +
    + +
    + + Download the latest release + +

    Support CodeMirror

    + + + + + +

    Releases:

    + +

    20-12-2011: Version 2.2:

    + + + +

    21-11-2011: Version 2.18:

    +

    Fixes TextMarker.clear, which is broken in 2.17.

    + +

    21-11-2011: Version 2.17:

    +
      +
    • Add support for line + wrapping and code + folding.
    • +
    • Add Github-style Markdown mode.
    • +
    • Add Monokai + and Rubyblue themes.
    • +
    • Add setBookmark method.
    • +
    • Move some of the demo code into reusable components + under lib/util.
    • +
    • Make screen-coord-finding code faster and more reliable.
    • +
    • Fix drag-and-drop in Firefox.
    • +
    • Improve support for IME.
    • +
    • Speed up content rendering.
    • +
    • Fix browser's built-in search in Webkit.
    • +
    • Make double- and triple-click work in IE.
    • +
    • Various fixes to modes.
    • +
    + +

    27-10-2011: Version 2.16:

    +
      +
    • Add Perl, Rust, TiddlyWiki, and Groovy modes.
    • +
    • Dragging text inside the editor now moves, rather than copies.
    • +
    • Add a coordsFromIndex method.
    • +
    • API change: setValue now no longer clears history. Use clearHistory for that.
    • +
    • API change: markText now + returns an object with clear and find + methods. Marked text is now more robust when edited.
    • +
    • Fix editing code with tabs in Internet Explorer.
    • +
    + +

    26-09-2011: Version 2.15:

    +

    Fix bug that snuck into 2.14: Clicking the + character that currently has the cursor didn't re-focus the + editor.

    + +

    26-09-2011: Version 2.14:

    + + +

    23-08-2011: Version 2.13:

    + + +

    25-07-2011: Version 2.12:

    +
      +
    • Add a SPARQL mode.
    • +
    • Fix bug with cursor jumping around in an unfocused editor in IE.
    • +
    • Allow key and mouse events to bubble out of the editor. Ignore widget clicks.
    • +
    • Solve cursor flakiness after undo/redo.
    • +
    • Fix block-reindent ignoring the last few lines.
    • +
    • Fix parsing of multi-line attrs in XML mode.
    • +
    • Use innerHTML for HTML-escaping.
    • +
    • Some fixes to indentation in C-like mode.
    • +
    • Shrink horiz scrollbars when long lines removed.
    • +
    • Fix width feedback loop bug that caused the width of an inner DIV to shrink.
    • +
    + +

    04-07-2011: Version 2.11:

    +
      +
    • Add a Scheme mode.
    • +
    • Add a replace method to search cursors, for cursor-preserving replacements.
    • +
    • Make the C-like mode mode more customizeable.
    • +
    • Update XML mode to spot mismatched tags.
    • +
    • Add getStateAfter API and compareState mode API methods for finer-grained mode magic.
    • +
    • Add a getScrollerElement API method to manipulate the scrolling DIV.
    • +
    • Fix drag-and-drop for Firefox.
    • +
    • Add a C# configuration for the C-like mode.
    • +
    • Add full-screen editing and mode-changing demos.
    • +
    + +

    Older releases...

    + +
    + +
     
    + +
    + + +
    + + + + + --- /dev/null +++ b/js/flotr2/examples/lib/codemirror/keymap/emacs.js @@ -1,1 +1,30 @@ +// TODO number prefixes +(function() { + // Really primitive kill-ring implementation. + var killRing = []; + function addToRing(str) { + killRing.push(str); + if (killRing.length > 50) killRing.shift(); + } + function getFromRing() { return killRing[killRing.length - 1] || ""; } + function popFromRing() { if (killRing.length > 1) killRing.pop(); return getFromRing(); } + CodeMirror.keyMap.emacs = { + "Ctrl-X": function(cm) {cm.setOption("keyMap", "emacs-Ctrl-X");}, + "Ctrl-W": function(cm) {addToRing(cm.getSelection()); cm.replaceSelection("");}, + "Ctrl-Alt-W": function(cm) {addToRing(cm.getSelection()); cm.replaceSelection("");}, + "Alt-W": function(cm) {addToRing(cm.getSelection());}, + "Ctrl-Y": function(cm) {cm.replaceSelection(getFromRing());}, + "Alt-Y": function(cm) {cm.replaceSelection(popFromRing());}, + "Ctrl-/": "undo", "Shift-Ctrl--": "undo", "Shift-Alt-,": "goDocStart", "Shift-Alt-.": "goDocEnd", + "Ctrl-S": "findNext", "Ctrl-R": "findPrev", "Ctrl-G": "clearSearch", "Shift-Alt-5": "replace", + "Ctrl-Z": "undo", "Cmd-Z": "undo", + fallthrough: ["basic", "emacsy"] + }; + + CodeMirror.keyMap["emacs-Ctrl-X"] = { + "Ctrl-S": "save", "Ctrl-W": "save", "S": "saveAll", "F": "open", "U": "undo", "K": "close", + auto: "emacs", catchall: function(cm) {/*ignore*/} + }; +})(); + --- /dev/null +++ b/js/flotr2/examples/lib/codemirror/keymap/vim.js @@ -1,1 +1,77 @@ +(function() { + var count = ""; + function pushCountDigit(digit) { return function(cm) {count += digit;} } + function popCount() { var i = parseInt(count); count = ""; return i || 1; } + function countTimes(func) { + if (typeof func == "string") func = CodeMirror.commands[func]; + return function(cm) { for (var i = 0, c = popCount(); i < c; ++i) func(cm); } + } + function iterObj(o, f) { + for (var prop in o) if (o.hasOwnProperty(prop)) f(prop, o[prop]); + } + + var word = [/\w/, /[^\w\s]/], bigWord = [/\S/]; + function findWord(line, pos, dir, regexps) { + var stop = 0, next = -1; + if (dir > 0) { stop = line.length; next = 0; } + var start = stop, end = stop; + // Find bounds of next one. + outer: for (; pos != stop; pos += dir) { + for (var i = 0; i < regexps.length; ++i) { + if (regexps[i].test(line.charAt(pos + next))) { + start = pos; + for (; pos != stop; pos += dir) { + if (!regexps[i].test(line.charAt(pos + next))) break; + } + end = pos; + break outer; + } + } + } + return {from: Math.min(start, end), to: Math.max(start, end)}; + } + function moveToWord(cm, regexps, dir, where) { + var cur = cm.getCursor(), ch = cur.ch, line = cm.getLine(cur.line), word; + while (true) { + word = findWord(line, ch, dir, regexps); + ch = word[where == "end" ? "to" : "from"]; + if (ch == cur.ch && word.from != word.to) ch = word[dir < 0 ? "from" : "to"]; + else break; + } + cm.setCursor(cur.line, word[where == "end" ? "to" : "from"], true); + } + + var map = CodeMirror.keyMap.vim = { + "0": function(cm) {count.length > 0 ? pushCountDigit("0")(cm) : CodeMirror.commands.goLineStart(cm);}, + "I": function(cm) {popCount(); cm.setOption("keyMap", "vim-insert");}, + "G": function(cm) {cm.setOption("keyMap", "vim-prefix-g");}, + catchall: function(cm) {/*ignore*/} + }; + // Add bindings for number keys + for (var i = 1; i < 10; ++i) map[i] = pushCountDigit(i); + // Add bindings that are influenced by number keys + iterObj({"H": "goColumnLeft", "L": "goColumnRight", "J": "goLineDown", "K": "goLineUp", + "Left": "goColumnLeft", "Right": "goColumnRight", "Down": "goLineDown", "Up": "goLineUp", + "Backspace": "goCharLeft", "Space": "goCharRight", + "B": function(cm) {moveToWord(cm, word, -1, "end");}, + "E": function(cm) {moveToWord(cm, word, 1, "end");}, + "W": function(cm) {moveToWord(cm, word, 1, "start");}, + "Shift-B": function(cm) {moveToWord(cm, bigWord, -1, "end");}, + "Shift-E": function(cm) {moveToWord(cm, bigWord, 1, "end");}, + "Shift-W": function(cm) {moveToWord(cm, bigWord, 1, "start");}, + "U": "undo", "Ctrl-R": "redo", "Shift-4": "goLineEnd"}, + function(key, cmd) { map[key] = countTimes(cmd); }); + + CodeMirror.keyMap["vim-prefix-g"] = { + "E": countTimes(function(cm) { moveToWord(cm, word, -1, "start");}), + "Shift-E": countTimes(function(cm) { moveToWord(cm, bigWord, -1, "start");}), + auto: "vim", catchall: function(cm) {/*ignore*/} + }; + + CodeMirror.keyMap["vim-insert"] = { + "Esc": function(cm) {cm.setOption("keyMap", "vim");}, + fallthrough: ["default"] + }; +})(); + --- /dev/null +++ b/js/flotr2/examples/lib/codemirror/lib/codemirror.css @@ -1,1 +1,105 @@ +.CodeMirror { + line-height: 1em; + font-family: monospace; +} +.CodeMirror-scroll { + overflow: auto; + height: 300px; + /* This is needed to prevent an IE[67] bug where the scrolled content + is visible outside of the scrolling box. */ + position: relative; +} + +.CodeMirror-gutter { + position: absolute; left: 0; top: 0; + z-index: 10; + background-color: #f7f7f7; + border-right: 1px solid #eee; + min-width: 2em; + height: 100%; +} +.CodeMirror-gutter-text { + color: #aaa; + text-align: right; + padding: .4em .2em .4em .4em; + white-space: pre !important; +} +.CodeMirror-lines { + padding: .4em; +} + +.CodeMirror pre { + -moz-border-radius: 0; + -webkit-border-radius: 0; + -o-border-radius: 0; + border-radius: 0; + border-width: 0; margin: 0; padding: 0; background: transparent; + font-family: inherit; + font-size: inherit; + padding: 0; margin: 0; + white-space: pre; + word-wrap: normal; +} + +.CodeMirror-wrap pre { + word-wrap: break-word; + white-space: pre-wrap; +} +.CodeMirror-wrap .CodeMirror-scroll { + overflow-x: hidden; +} + +.CodeMirror textarea { + outline: none !important; +} + +.CodeMirror pre.CodeMirror-cursor { + z-index: 10; + position: absolute; + visibility: hidden; + border-left: 1px solid black; +} +.CodeMirror-focused pre.CodeMirror-cursor { + visibility: visible; +} + +span.CodeMirror-selected { background: #d9d9d9; } +.CodeMirror-focused span.CodeMirror-selected { background: #d2dcf8; } + +.CodeMirror-searching {background: #ffa;} + +/* Default theme */ + +.cm-s-default span.cm-keyword {color: #708;} +.cm-s-default span.cm-atom {color: #219;} +.cm-s-default span.cm-number {color: #164;} +.cm-s-default span.cm-def {color: #00f;} +.cm-s-default span.cm-variable {color: black;} +.cm-s-default span.cm-variable-2 {color: #05a;} +.cm-s-default span.cm-variable-3 {color: #085;} +.cm-s-default span.cm-property {color: black;} +.cm-s-default span.cm-operator {color: black;} +.cm-s-default span.cm-comment {color: #a50;} +.cm-s-default span.cm-string {color: #a11;} +.cm-s-default span.cm-string-2 {color: #f50;} +.cm-s-default span.cm-meta {color: #555;} +.cm-s-default span.cm-error {color: #f00;} +.cm-s-default span.cm-qualifier {color: #555;} +.cm-s-default span.cm-builtin {color: #30a;} +.cm-s-default span.cm-bracket {color: #cc7;} +.cm-s-default span.cm-tag {color: #170;} +.cm-s-default span.cm-attribute {color: #00c;} +.cm-s-default span.cm-header {color: #a0a;} +.cm-s-default span.cm-quote {color: #090;} +.cm-s-default span.cm-hr {color: #999;} +.cm-s-default span.cm-link {color: #00c;} + +span.cm-header, span.cm-strong {font-weight: bold;} +span.cm-em {font-style: italic;} +span.cm-emstrong {font-style: italic; font-weight: bold;} +span.cm-link {text-decoration: underline;} + +div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;} +div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} + --- /dev/null +++ b/js/flotr2/examples/lib/codemirror/lib/codemirror.js @@ -1,1 +1,2762 @@ - +// CodeMirror version 2.2 +// +// All functions that need access to the editor's state live inside +// the CodeMirror function. Below that, at the bottom of the file, +// some utilities are defined. + +// CodeMirror is the only global var we claim +var CodeMirror = (function() { + // This is the function that produces an editor instance. It's + // closure is used to store the editor state. + function CodeMirror(place, givenOptions) { + // Determine effective options based on given values and defaults. + var options = {}, defaults = CodeMirror.defaults; + for (var opt in defaults) + if (defaults.hasOwnProperty(opt)) + options[opt] = (givenOptions && givenOptions.hasOwnProperty(opt) ? givenOptions : defaults)[opt]; + + var targetDocument = options["document"]; + // The element in which the editor lives. + var wrapper = targetDocument.createElement("div"); + wrapper.className = "CodeMirror" + (options.lineWrapping ? " CodeMirror-wrap" : ""); + // This mess creates the base DOM structure for the editor. + wrapper.innerHTML = + '
    ' + // Wraps and hides input textarea + '
    ' + + '
    ' + + '
    ' + // Set to the height of the text, causes scrolling + '
    ' + // Moved around its parent to cover visible view + '
    ' + + // Provides positioning relative to (visible) text origin + '
    ' + + '
    ' + + '
     
    ' + // Absolutely positioned blinky cursor + '
    ' + // This DIV contains the actual code + '
    '; + if (place.appendChild) place.appendChild(wrapper); else place(wrapper); + // I've never seen more elegant code in my life. + var inputDiv = wrapper.firstChild, input = inputDiv.firstChild, + scroller = wrapper.lastChild, code = scroller.firstChild, + mover = code.firstChild, gutter = mover.firstChild, gutterText = gutter.firstChild, + lineSpace = gutter.nextSibling.firstChild, measure = lineSpace.firstChild, + cursor = measure.nextSibling, lineDiv = cursor.nextSibling; + themeChanged(); + // Needed to hide big blue blinking cursor on Mobile Safari + if (/AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent)) input.style.width = "0px"; + if (!webkit) lineSpace.draggable = true; + if (options.tabindex != null) input.tabIndex = options.tabindex; + if (!options.gutter && !options.lineNumbers) gutter.style.display = "none"; + + // Check for problem with IE innerHTML not working when we have a + // P (or similar) parent node. + try { stringWidth("x"); } + catch (e) { + if (e.message.match(/runtime/i)) + e = new Error("A CodeMirror inside a P-style element does not work in Internet Explorer. (innerHTML bug)"); + throw e; + } + + // Delayed object wrap timeouts, making sure only one is active. blinker holds an interval. + var poll = new Delayed(), highlight = new Delayed(), blinker; + + // mode holds a mode API object. doc is the tree of Line objects, + // work an array of lines that should be parsed, and history the + // undo history (instance of History constructor). + var mode, doc = new BranchChunk([new LeafChunk([new Line("")])]), work, focused; + loadMode(); + // The selection. These are always maintained to point at valid + // positions. Inverted is used to remember that the user is + // selecting bottom-to-top. + var sel = {from: {line: 0, ch: 0}, to: {line: 0, ch: 0}, inverted: false}; + // Selection-related flags. shiftSelecting obviously tracks + // whether the user is holding shift. + var shiftSelecting, lastClick, lastDoubleClick, draggingText, overwrite = false; + // Variables used by startOperation/endOperation to track what + // happened during the operation. + var updateInput, userSelChange, changes, textChanged, selectionChanged, leaveInputAlone, + gutterDirty, callbacks; + // Current visible range (may be bigger than the view window). + var displayOffset = 0, showingFrom = 0, showingTo = 0, lastSizeC = 0; + // bracketHighlighted is used to remember that a backet has been + // marked. + var bracketHighlighted; + // Tracks the maximum line length so that the horizontal scrollbar + // can be kept static when scrolling. + var maxLine = "", maxWidth, tabText = computeTabText(); + + // Initialize the content. + operation(function(){setValue(options.value || ""); updateInput = false;})(); + var history = new History(); + + // Register our event handlers. + connect(scroller, "mousedown", operation(onMouseDown)); + connect(scroller, "dblclick", operation(onDoubleClick)); + connect(lineSpace, "dragstart", onDragStart); + connect(lineSpace, "selectstart", e_preventDefault); + // Gecko browsers fire contextmenu *after* opening the menu, at + // which point we can't mess with it anymore. Context menu is + // handled in onMouseDown for Gecko. + if (!gecko) connect(scroller, "contextmenu", onContextMenu); + connect(scroller, "scroll", function() { + updateDisplay([]); + if (options.fixedGutter) gutter.style.left = scroller.scrollLeft + "px"; + if (options.onScroll) options.onScroll(instance); + }); + connect(window, "resize", function() {updateDisplay(true);}); + connect(input, "keyup", operation(onKeyUp)); + connect(input, "input", fastPoll); + connect(input, "keydown", operation(onKeyDown)); + connect(input, "keypress", operation(onKeyPress)); + connect(input, "focus", onFocus); + connect(input, "blur", onBlur); + + connect(scroller, "dragenter", e_stop); + connect(scroller, "dragover", e_stop); + connect(scroller, "drop", operation(onDrop)); + connect(scroller, "paste", function(){focusInput(); fastPoll();}); + connect(input, "paste", fastPoll); + connect(input, "cut", operation(function(){replaceSelection("");})); + + // IE throws unspecified error in certain cases, when + // trying to access activeElement before onload + var hasFocus; try { hasFocus = (targetDocument.activeElement == input); } catch(e) { } + if (hasFocus) setTimeout(onFocus, 20); + else onBlur(); + + function isLine(l) {return l >= 0 && l < doc.size;} + // The instance object that we'll return. Mostly calls out to + // local functions in the CodeMirror function. Some do some extra + // range checking and/or clipping. operation is used to wrap the + // call so that changes it makes are tracked, and the display is + // updated afterwards. + var instance = wrapper.CodeMirror = { + getValue: getValue, + setValue: operation(setValue), + getSelection: getSelection, + replaceSelection: operation(replaceSelection), + focus: function(){focusInput(); onFocus(); fastPoll();}, + setOption: function(option, value) { + var oldVal = options[option]; + options[option] = value; + if (option == "mode" || option == "indentUnit") loadMode(); + else if (option == "readOnly" && value) {onBlur(); input.blur();} + else if (option == "theme") themeChanged(); + else if (option == "lineWrapping" && oldVal != value) operation(wrappingChanged)(); + else if (option == "tabSize") operation(tabsChanged)(); + if (option == "lineNumbers" || option == "gutter" || option == "firstLineNumber" || option == "theme") + operation(gutterChanged)(); + }, + getOption: function(option) {return options[option];}, + undo: operation(undo), + redo: operation(redo), + indentLine: operation(function(n, dir) { + if (isLine(n)) indentLine(n, dir == null ? "smart" : dir ? "add" : "subtract"); + }), + indentSelection: operation(indentSelected), + historySize: function() {return {undo: history.done.length, redo: history.undone.length};}, + clearHistory: function() {history = new History();}, + matchBrackets: operation(function(){matchBrackets(true);}), + getTokenAt: operation(function(pos) { + pos = clipPos(pos); + return getLine(pos.line).getTokenAt(mode, getStateBefore(pos.line), pos.ch); + }), + getStateAfter: function(line) { + line = clipLine(line == null ? doc.size - 1: line); + return getStateBefore(line + 1); + }, + cursorCoords: function(start){ + if (start == null) start = sel.inverted; + return pageCoords(start ? sel.from : sel.to); + }, + charCoords: function(pos){return pageCoords(clipPos(pos));}, + coordsChar: function(coords) { + var off = eltOffset(lineSpace); + return coordsChar(coords.x - off.left, coords.y - off.top); + }, + markText: operation(markText), + setBookmark: setBookmark, + setMarker: operation(addGutterMarker), + clearMarker: operation(removeGutterMarker), + setLineClass: operation(setLineClass), + hideLine: operation(function(h) {return setLineHidden(h, true);}), + showLine: operation(function(h) {return setLineHidden(h, false);}), + onDeleteLine: function(line, f) { + if (typeof line == "number") { + if (!isLine(line)) return null; + line = getLine(line); + } + (line.handlers || (line.handlers = [])).push(f); + return line; + }, + lineInfo: lineInfo, + addWidget: function(pos, node, scroll, vert, horiz) { + pos = localCoords(clipPos(pos)); + var top = pos.yBot, left = pos.x; + node.style.position = "absolute"; + code.appendChild(node); + if (vert == "over") top = pos.y; + else if (vert == "near") { + var vspace = Math.max(scroller.offsetHeight, doc.height * textHeight()), + hspace = Math.max(code.clientWidth, lineSpace.clientWidth) - paddingLeft(); + if (pos.yBot + node.offsetHeight > vspace && pos.y > node.offsetHeight) + top = pos.y - node.offsetHeight; + if (left + node.offsetWidth > hspace) + left = hspace - node.offsetWidth; + } + node.style.top = (top + paddingTop()) + "px"; + node.style.left = node.style.right = ""; + if (horiz == "right") { + left = code.clientWidth - node.offsetWidth; + node.style.right = "0px"; + } else { + if (horiz == "left") left = 0; + else if (horiz == "middle") left = (code.clientWidth - node.offsetWidth) / 2; + node.style.left = (left + paddingLeft()) + "px"; + } + if (scroll) + scrollIntoView(left, top, left + node.offsetWidth, top + node.offsetHeight); + }, + + lineCount: function() {return doc.size;}, + clipPos: clipPos, + getCursor: function(start) { + if (start == null) start = sel.inverted; + return copyPos(start ? sel.from : sel.to); + }, + somethingSelected: function() {return !posEq(sel.from, sel.to);}, + setCursor: operation(function(line, ch, user) { + if (ch == null && typeof line.line == "number") setCursor(line.line, line.ch, user); + else setCursor(line, ch, user); + }), + setSelection: operation(function(from, to, user) { + (user ? setSelectionUser : setSelection)(clipPos(from), clipPos(to || from)); + }), + getLine: function(line) {if (isLine(line)) return getLine(line).text;}, + getLineHandle: function(line) {if (isLine(line)) return getLine(line);}, + setLine: operation(function(line, text) { + if (isLine(line)) replaceRange(text, {line: line, ch: 0}, {line: line, ch: getLine(line).text.length}); + }), + removeLine: operation(function(line) { + if (isLine(line)) replaceRange("", {line: line, ch: 0}, clipPos({line: line+1, ch: 0})); + }), + replaceRange: operation(replaceRange), + getRange: function(from, to) {return getRange(clipPos(from), clipPos(to));}, + + execCommand: function(cmd) {return commands[cmd](instance);}, + // Stuff used by commands, probably not much use to outside code. + moveH: operation(moveH), + deleteH: operation(deleteH), + moveV: operation(moveV), + toggleOverwrite: function() {overwrite = !overwrite;}, + + posFromIndex: function(off) { + var lineNo = 0, ch; + doc.iter(0, doc.size, function(line) { + var sz = line.text.length + 1; + if (sz > off) { ch = off; return true; } + off -= sz; + ++lineNo; + }); + return clipPos({line: lineNo, ch: ch}); + }, + indexFromPos: function (coords) { + if (coords.line < 0 || coords.ch < 0) return 0; + var index = coords.ch; + doc.iter(0, coords.line, function (line) { + index += line.text.length + 1; + }); + return index; + }, + + operation: function(f){return operation(f)();}, + refresh: function(){updateDisplay(true);}, + getInputField: function(){return input;}, + getWrapperElement: function(){return wrapper;}, + getScrollerElement: function(){return scroller;}, + getGutterElement: function(){return gutter;} + }; + + function getLine(n) { return getLineAt(doc, n); } + function updateLineHeight(line, height) { + gutterDirty = true; + var diff = height - line.height; + for (var n = line; n; n = n.parent) n.height += diff; + } + + function setValue(code) { + var top = {line: 0, ch: 0}; + updateLines(top, {line: doc.size - 1, ch: getLine(doc.size-1).text.length}, + splitLines(code), top, top); + updateInput = true; + } + function getValue(code) { + var text = []; + doc.iter(0, doc.size, function(line) { text.push(line.text); }); + return text.join("\n"); + } + + function onMouseDown(e) { + setShift(e.shiftKey); + // Check whether this is a click in a widget + for (var n = e_target(e); n != wrapper; n = n.parentNode) + if (n.parentNode == code && n != mover) return; + + // See if this is a click in the gutter + for (var n = e_target(e); n != wrapper; n = n.parentNode) + if (n.parentNode == gutterText) { + if (options.onGutterClick) + options.onGutterClick(instance, indexOf(gutterText.childNodes, n) + showingFrom, e); + return e_preventDefault(e); + } + + var start = posFromMouse(e); + + switch (e_button(e)) { + case 3: + if (gecko && !mac) onContextMenu(e); + return; + case 2: + if (start) setCursor(start.line, start.ch, true); + return; + } + // For button 1, if it was clicked inside the editor + // (posFromMouse returning non-null), we have to adjust the + // selection. + if (!start) {if (e_target(e) == scroller) e_preventDefault(e); return;} + + if (!focused) onFocus(); + + var now = +new Date; + if (lastDoubleClick && lastDoubleClick.time > now - 400 && posEq(lastDoubleClick.pos, start)) { + e_preventDefault(e); + setTimeout(focusInput, 20); + return selectLine(start.line); + } else if (lastClick && lastClick.time > now - 400 && posEq(lastClick.pos, start)) { + lastDoubleClick = {time: now, pos: start}; + e_preventDefault(e); + return selectWordAt(start); + } else { lastClick = {time: now, pos: start}; } + + var last = start, going; + if (dragAndDrop && !posEq(sel.from, sel.to) && + !posLess(start, sel.from) && !posLess(sel.to, start)) { + // Let the drag handler handle this. + if (webkit) lineSpace.draggable = true; + var up = connect(targetDocument, "mouseup", operation(function(e2) { + if (webkit) lineSpace.draggable = false; + draggingText = false; + up(); + if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) { + e_preventDefault(e2); + setCursor(start.line, start.ch, true); + focusInput(); + } + }), true); + draggingText = true; + return; + } + e_preventDefault(e); + setCursor(start.line, start.ch, true); + + function extend(e) { + var cur = posFromMouse(e, true); + if (cur && !posEq(cur, last)) { + if (!focused) onFocus(); + last = cur; + setSelectionUser(start, cur); + updateInput = false; + var visible = visibleLines(); + if (cur.line >= visible.to || cur.line < visible.from) + going = setTimeout(operation(function(){extend(e);}), 150); + } + } + + var move = connect(targetDocument, "mousemove", operation(function(e) { + clearTimeout(going); + e_preventDefault(e); + extend(e); + }), true); + var up = connect(targetDocument, "mouseup", operation(function(e) { + clearTimeout(going); + var cur = posFromMouse(e); + if (cur) setSelectionUser(start, cur); + e_preventDefault(e); + focusInput(); + updateInput = true; + move(); up(); + }), true); + } + function onDoubleClick(e) { + for (var n = e_target(e); n != wrapper; n = n.parentNode) + if (n.parentNode == gutterText) return e_preventDefault(e); + var start = posFromMouse(e); + if (!start) return; + lastDoubleClick = {time: +new Date, pos: start}; + e_preventDefault(e); + selectWordAt(start); + } + function onDrop(e) { + e.preventDefault(); + var pos = posFromMouse(e, true), files = e.dataTransfer.files; + if (!pos || options.readOnly) return; + if (files && files.length && window.FileReader && window.File) { + function loadFile(file, i) { + var reader = new FileReader; + reader.onload = function() { + text[i] = reader.result; + if (++read == n) { + pos = clipPos(pos); + operation(function() { + var end = replaceRange(text.join(""), pos, pos); + setSelectionUser(pos, end); + })(); + } + }; + reader.readAsText(file); + } + var n = files.length, text = Array(n), read = 0; + for (var i = 0; i < n; ++i) loadFile(files[i], i); + } + else { + try { + var text = e.dataTransfer.getData("Text"); + if (text) { + var end = replaceRange(text, pos, pos); + var curFrom = sel.from, curTo = sel.to; + setSelectionUser(pos, end); + if (draggingText) replaceRange("", curFrom, curTo); + focusInput(); + } + } + catch(e){} + } + } + function onDragStart(e) { + var txt = getSelection(); + // This will reset escapeElement + htmlEscape(txt); + e.dataTransfer.setDragImage(escapeElement, 0, 0); + e.dataTransfer.setData("Text", txt); + } + function handleKeyBinding(e) { + var name = keyNames[e.keyCode], next = keyMap[options.keyMap].auto, bound, dropShift; + if (name == null || e.altGraphKey) { + if (next) options.keyMap = next; + return null; + } + if (e.altKey) name = "Alt-" + name; + if (e.ctrlKey) name = "Ctrl-" + name; + if (e.metaKey) name = "Cmd-" + name; + if (e.shiftKey && (bound = lookupKey("Shift-" + name, options.extraKeys, options.keyMap))) { + dropShift = true; + } else { + bound = lookupKey(name, options.extraKeys, options.keyMap); + } + if (typeof bound == "string") { + if (commands.propertyIsEnumerable(bound)) bound = commands[bound]; + else bound = null; + } + if (next && (bound || !isModifierKey(e))) options.keyMap = next; + if (!bound) return false; + if (dropShift) { + var prevShift = shiftSelecting; + shiftSelecting = null; + bound(instance); + shiftSelecting = prevShift; + } else bound(instance); + e_preventDefault(e); + return true; + } + var lastStoppedKey = null; + function onKeyDown(e) { + if (!focused) onFocus(); + var code = e.keyCode; + // IE does strange things with escape. + if (ie && code == 27) { e.returnValue = false; } + setShift(code == 16 || e.shiftKey); + // First give onKeyEvent option a chance to handle this. + if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return; + var handled = handleKeyBinding(e); + if (window.opera) { + lastStoppedKey = handled ? e.keyCode : null; + // Opera has no cut event... we try to at least catch the key combo + if (!handled && (mac ? e.metaKey : e.ctrlKey) && e.keyCode == 88) + replaceSelection(""); + } + } + function onKeyPress(e) { + if (window.opera && e.keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;} + if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return; + if (window.opera && !e.which && handleKeyBinding(e)) return; + if (options.electricChars && mode.electricChars) { + var ch = String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode); + if (mode.electricChars.indexOf(ch) > -1) + setTimeout(operation(function() {indentLine(sel.to.line, "smart");}), 75); + } + fastPoll(); + } + function onKeyUp(e) { + if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return; + if (e.keyCode == 16) shiftSelecting = null; + } + + function onFocus() { + if (options.readOnly) return; + if (!focused) { + if (options.onFocus) options.onFocus(instance); + focused = true; + if (wrapper.className.search(/\bCodeMirror-focused\b/) == -1) + wrapper.className += " CodeMirror-focused"; + if (!leaveInputAlone) resetInput(true); + } + slowPoll(); + restartBlink(); + } + function onBlur() { + if (focused) { + if (options.onBlur) options.onBlur(instance); + focused = false; + wrapper.className = wrapper.className.replace(" CodeMirror-focused", ""); + } + clearInterval(blinker); + setTimeout(function() {if (!focused) shiftSelecting = null;}, 150); + } + + // Replace the range from from to to by the strings in newText. + // Afterwards, set the selection to selFrom, selTo. + function updateLines(from, to, newText, selFrom, selTo) { + if (history) { + var old = []; + doc.iter(from.line, to.line + 1, function(line) { old.push(line.text); }); + history.addChange(from.line, newText.length, old); + while (history.done.length > options.undoDepth) history.done.shift(); + } + updateLinesNoUndo(from, to, newText, selFrom, selTo); + } + function unredoHelper(from, to) { + var change = from.pop(); + if (change) { + var replaced = [], end = change.start + change.added; + doc.iter(change.start, end, function(line) { replaced.push(line.text); }); + to.push({start: change.start, added: change.old.length, old: replaced}); + var pos = clipPos({line: change.start + change.old.length - 1, + ch: editEnd(replaced[replaced.length-1], change.old[change.old.length-1])}); + updateLinesNoUndo({line: change.start, ch: 0}, {line: end - 1, ch: getLine(end-1).text.length}, change.old, pos, pos); + updateInput = true; + } + } + function undo() {unredoHelper(history.done, history.undone);} + function redo() {unredoHelper(history.undone, history.done);} + + function updateLinesNoUndo(from, to, newText, selFrom, selTo) { + var recomputeMaxLength = false, maxLineLength = maxLine.length; + if (!options.lineWrapping) + doc.iter(from.line, to.line, function(line) { + if (line.text.length == maxLineLength) {recomputeMaxLength = true; return true;} + }); + if (from.line != to.line || newText.length > 1) gutterDirty = true; + + var nlines = to.line - from.line, firstLine = getLine(from.line), lastLine = getLine(to.line); + // First adjust the line structure, taking some care to leave highlighting intact. + if (from.ch == 0 && to.ch == 0 && newText[newText.length - 1] == "") { + // This is a whole-line replace. Treated specially to make + // sure line objects move the way they are supposed to. + var added = [], prevLine = null; + if (from.line) { + prevLine = getLine(from.line - 1); + prevLine.fixMarkEnds(lastLine); + } else lastLine.fixMarkStarts(); + for (var i = 0, e = newText.length - 1; i < e; ++i) + added.push(Line.inheritMarks(newText[i], prevLine)); + if (nlines) doc.remove(from.line, nlines, callbacks); + if (added.length) doc.insert(from.line, added); + } else if (firstLine == lastLine) { + if (newText.length == 1) + firstLine.replace(from.ch, to.ch, newText[0]); + else { + lastLine = firstLine.split(to.ch, newText[newText.length-1]); + firstLine.replace(from.ch, null, newText[0]); + firstLine.fixMarkEnds(lastLine); + var added = []; + for (var i = 1, e = newText.length - 1; i < e; ++i) + added.push(Line.inheritMarks(newText[i], firstLine)); + added.push(lastLine); + doc.insert(from.line + 1, added); + } + } else if (newText.length == 1) { + firstLine.replace(from.ch, null, newText[0]); + lastLine.replace(null, to.ch, ""); + firstLine.append(lastLine); + doc.remove(from.line + 1, nlines, callbacks); + } else { + var added = []; + firstLine.replace(from.ch, null, newText[0]); + lastLine.replace(null, to.ch, newText[newText.length-1]); + firstLine.fixMarkEnds(lastLine); + for (var i = 1, e = newText.length - 1; i < e; ++i) + added.push(Line.inheritMarks(newText[i], firstLine)); + if (nlines > 1) doc.remove(from.line + 1, nlines - 1, callbacks); + doc.insert(from.line + 1, added); + } + if (options.lineWrapping) { + var perLine = scroller.clientWidth / charWidth() - 3; + doc.iter(from.line, from.line + newText.length, function(line) { + if (line.hidden) return; + var guess = Math.ceil(line.text.length / perLine) || 1; + if (guess != line.height) updateLineHeight(line, guess); + }); + } else { + doc.iter(from.line, i + newText.length, function(line) { + var l = line.text; + if (l.length > maxLineLength) { + maxLine = l; maxLineLength = l.length; maxWidth = null; + recomputeMaxLength = false; + } + }); + if (recomputeMaxLength) { + maxLineLength = 0; maxLine = ""; maxWidth = null; + doc.iter(0, doc.size, function(line) { + var l = line.text; + if (l.length > maxLineLength) { + maxLineLength = l.length; maxLine = l; + } + }); + } + } + + // Add these lines to the work array, so that they will be + // highlighted. Adjust work lines if lines were added/removed. + var newWork = [], lendiff = newText.length - nlines - 1; + for (var i = 0, l = work.length; i < l; ++i) { + var task = work[i]; + if (task < from.line) newWork.push(task); + else if (task > to.line) newWork.push(task + lendiff); + } + var hlEnd = from.line + Math.min(newText.length, 500); + highlightLines(from.line, hlEnd); + newWork.push(hlEnd); + work = newWork; + startWorker(100); + // Remember that these lines changed, for updating the display + changes.push({from: from.line, to: to.line + 1, diff: lendiff}); + var changeObj = {from: from, to: to, text: newText}; + if (textChanged) { + for (var cur = textChanged; cur.next; cur = cur.next) {} + cur.next = changeObj; + } else textChanged = changeObj; + + // Update the selection + function updateLine(n) {return n <= Math.min(to.line, to.line + lendiff) ? n : n + lendiff;} + setSelection(selFrom, selTo, updateLine(sel.from.line), updateLine(sel.to.line)); + + // Make sure the scroll-size div has the correct height. + code.style.height = (doc.height * textHeight() + 2 * paddingTop()) + "px"; + } + + function replaceRange(code, from, to) { + from = clipPos(from); + if (!to) to = from; else to = clipPos(to); + code = splitLines(code); + function adjustPos(pos) { + if (posLess(pos, from)) return pos; + if (!posLess(to, pos)) return end; + var line = pos.line + code.length - (to.line - from.line) - 1; + var ch = pos.ch; + if (pos.line == to.line) + ch += code[code.length-1].length - (to.ch - (to.line == from.line ? from.ch : 0)); + return {line: line, ch: ch}; + } + var end; + replaceRange1(code, from, to, function(end1) { + end = end1; + return {from: adjustPos(sel.from), to: adjustPos(sel.to)}; + }); + return end; + } + function replaceSelection(code, collapse) { + replaceRange1(splitLines(code), sel.from, sel.to, function(end) { + if (collapse == "end") return {from: end, to: end}; + else if (collapse == "start") return {from: sel.from, to: sel.from}; + else return {from: sel.from, to: end}; + }); + } + function replaceRange1(code, from, to, computeSel) { + var endch = code.length == 1 ? code[0].length + from.ch : code[code.length-1].length; + var newSel = computeSel({line: from.line + code.length - 1, ch: endch}); + updateLines(from, to, code, newSel.from, newSel.to); + } + + function getRange(from, to) { + var l1 = from.line, l2 = to.line; + if (l1 == l2) return getLine(l1).text.slice(from.ch, to.ch); + var code = [getLine(l1).text.slice(from.ch)]; + doc.iter(l1 + 1, l2, function(line) { code.push(line.text); }); + code.push(getLine(l2).text.slice(0, to.ch)); + return code.join("\n"); + } + function getSelection() { + return getRange(sel.from, sel.to); + } + + var pollingFast = false; // Ensures slowPoll doesn't cancel fastPoll + function slowPoll() { + if (pollingFast) return; + poll.set(options.pollInterval, function() { + startOperation(); + readInput(); + if (focused) slowPoll(); + endOperation(); + }); + } + function fastPoll() { + var missed = false; + pollingFast = true; + function p() { + startOperation(); + var changed = readInput(); + if (!changed && !missed) {missed = true; poll.set(60, p);} + else {pollingFast = false; slowPoll();} + endOperation(); + } + poll.set(20, p); + } + + // Previnput is a hack to work with IME. If we reset the textarea + // on every change, that breaks IME. So we look for changes + // compared to the previous content instead. (Modern browsers have + // events that indicate IME taking place, but these are not widely + // supported or compatible enough yet to rely on.) + var prevInput = ""; + function readInput() { + if (leaveInputAlone || !focused || hasSelection(input)) return false; + var text = input.value; + if (text == prevInput) return false; + shiftSelecting = null; + var same = 0, l = Math.min(prevInput.length, text.length); + while (same < l && prevInput[same] == text[same]) ++same; + if (same < prevInput.length) + sel.from = {line: sel.from.line, ch: sel.from.ch - (prevInput.length - same)}; + else if (overwrite && posEq(sel.from, sel.to)) + sel.to = {line: sel.to.line, ch: Math.min(getLine(sel.to.line).text.length, sel.to.ch + (text.length - same))}; + replaceSelection(text.slice(same), "end"); + prevInput = text; + return true; + } + function resetInput(user) { + if (!posEq(sel.from, sel.to)) { + prevInput = ""; + input.value = getSelection(); + input.select(); + } else if (user) prevInput = input.value = ""; + } + + function focusInput() { + if (!options.readOnly) input.focus(); + } + + function scrollEditorIntoView() { + if (!cursor.getBoundingClientRect) return; + var rect = cursor.getBoundingClientRect(); + // IE returns bogus coordinates when the instance sits inside of an iframe and the cursor is hidden + if (ie && rect.top == rect.bottom) return; + var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight); + if (rect.top < 0 || rect.bottom > winH) cursor.scrollIntoView(); + } + function scrollCursorIntoView() { + var cursor = localCoords(sel.inverted ? sel.from : sel.to); + var x = options.lineWrapping ? Math.min(cursor.x, lineSpace.offsetWidth) : cursor.x; + return scrollIntoView(x, cursor.y, x, cursor.yBot); + } + function scrollIntoView(x1, y1, x2, y2) { + var pl = paddingLeft(), pt = paddingTop(), lh = textHeight(); + y1 += pt; y2 += pt; x1 += pl; x2 += pl; + var screen = scroller.clientHeight, screentop = scroller.scrollTop, scrolled = false, result = true; + if (y1 < screentop) {scroller.scrollTop = Math.max(0, y1 - 2*lh); scrolled = true;} + else if (y2 > screentop + screen) {scroller.scrollTop = y2 + lh - screen; scrolled = true;} + + var screenw = scroller.clientWidth, screenleft = scroller.scrollLeft; + var gutterw = options.fixedGutter ? gutter.clientWidth : 0; + if (x1 < screenleft + gutterw) { + if (x1 < 50) x1 = 0; + scroller.scrollLeft = Math.max(0, x1 - 10 - gutterw); + scrolled = true; + } + else if (x2 > screenw + screenleft - 3) { + scroller.scrollLeft = x2 + 10 - screenw; + scrolled = true; + if (x2 > code.clientWidth) result = false; + } + if (scrolled && options.onScroll) options.onScroll(instance); + return result; + } + + function visibleLines() { + var lh = textHeight(), top = scroller.scrollTop - paddingTop(); + var from_height = Math.max(0, Math.floor(top / lh)); + var to_height = Math.ceil((top + scroller.clientHeight) / lh); + return {from: lineAtHeight(doc, from_height), + to: lineAtHeight(doc, to_height)}; + } + // Uses a set of changes plus the current scroll position to + // determine which DOM updates have to be made, and makes the + // updates. + function updateDisplay(changes, suppressCallback) { + if (!scroller.clientWidth) { + showingFrom = showingTo = displayOffset = 0; + return; + } + // Compute the new visible window + var visible = visibleLines(); + // Bail out if the visible area is already rendered and nothing changed. + if (changes !== true && changes.length == 0 && visible.from >= showingFrom && visible.to <= showingTo) return; + var from = Math.max(visible.from - 100, 0), to = Math.min(doc.size, visible.to + 100); + if (showingFrom < from && from - showingFrom < 20) from = showingFrom; + if (showingTo > to && showingTo - to < 20) to = Math.min(doc.size, showingTo); + + // Create a range of theoretically intact lines, and punch holes + // in that using the change info. + var intact = changes === true ? [] : + computeIntact([{from: showingFrom, to: showingTo, domStart: 0}], changes); + // Clip off the parts that won't be visible + var intactLines = 0; + for (var i = 0; i < intact.length; ++i) { + var range = intact[i]; + if (range.from < from) {range.domStart += (from - range.from); range.from = from;} + if (range.to > to) range.to = to; + if (range.from >= range.to) intact.splice(i--, 1); +