Compare commits

...

242 Commits

Author SHA1 Message Date
Vitaliy Filippov 2c0316f07d always use fontconfig 2015-02-15 12:57:28 +03:00
Vitaliy Filippov cef6c84e00 Make qphantom platform plugin static and adjust build scripts 2015-02-15 12:39:07 +03:00
Vitaliy Filippov f37c7e29e0 Remove QT source and make phantomjs compile with unmodified QT, fix binary encoding of web response 2015-02-07 01:48:33 +03:00
Ariya Hidayat d3cd0599c8 Issue #12897: README is updated with 2.0 info. 2015-01-31 21:13:44 -08:00
Ariya Hidayat a2912c216d Set version from `2.0.0-development` to `2.0.0`.
https://github.com/ariya/phantomjs/issues/12897
2015-01-23 18:19:52 -08:00
Ariya Hidayat 0352ddb502 Version 2.0.0: initial cut at the ChangeLog.
https://github.com/ariya/phantomjs/issues/12897
2015-01-23 17:00:59 -08:00
Paul Millar 05d7e3e77d remove hardcoded "PhantomJS is launching GhostDriver..." message
Apart from being undesirable that debugging messages are always
written to stdout, the information is redundant as a similar message
is logged at debug level.

https://github.com/ariya/phantomjs/issues/12681
2015-01-09 07:41:48 -08:00
Andrey Plotnikov cf246eb853 Cast maxDiskCacheSize to qint64 to allow disk cache be more than 2Gb.
https://github.com/ariya/phantomjs/issues/12303
2014-12-18 09:16:38 -08:00
Jacek Migdal 806da21e2b Fix passing date as argument to page.evaluate().
https://github.com/ariya/phantomjs/issues/12615
2014-12-11 20:43:46 -08:00
Jacek Migdal 32d20b4aa7 Port more tests from webpage-spec.
https://github.com/ariya/phantomjs/issues/12439
2014-12-11 20:38:35 -08:00
Jacek Migdal 0bf14a3d0c Don't rely on JSON.parse() for page.evaluate().
https://github.com/ariya/phantomjs/issues/12615
2014-12-10 22:53:53 -08:00
Jacek Migdal 3b8282cb2e Port the tests from webpage-spec.js
Callback, clip-rect, confirm, object, prompt, scroll-position,
viewport-size and window.

https://github.com/ariya/phantomjs/issues/12439
2014-12-07 16:59:11 -08:00
Zack Weinberg 50ae50e871 Add a command-line option --local-urls={true,false}
The default is 'true'.  When set 'false', file: and qrc: URLs are
treated as invalid (unknown scheme) rather than opening local files,
as requested in issue #12752.

In order to test this, I added a mechanism to test/run-tests.py
allowing individual tests to be annotated with command-line
options to pass to phantomjs or the script.
2014-11-21 15:51:35 +00:00
Vitaly Slobodin a65a487d99 Fix invalid directory path for Windows.
https://github.com/ariya/phantomjs/issues/12715
2014-11-16 17:02:26 -08:00
Vitaly Slobodin 12870d90ad Fix JPG image rendering.
To pass QString as a const char* we should call <QString>.toLocal8Bit().constData().

https://github.com/ariya/phantomjs/issues/12684
2014-11-14 08:22:52 -08:00
Ariya Hidayat eddb0db1d2 Port the tests for mousedown, mouseup, and mousemove events.
https://github.com/ariya/phantomjs/issues/12439
2014-10-10 06:40:42 -07:00
Ariya Hidayat 619225b1da Port the tests of keyup, keydown, and keypress events.
https://github.com/ariya/phantomjs/issues/12439
2014-10-09 07:16:59 -07:00
Ariya Hidayat ce66f290c3 Port the test of web page's zoom factor.
https://github.com/ariya/phantomjs/issues/12439
2014-10-08 06:51:16 -07:00
Ariya Hidayat 2cbb695490 Port the tests of the web page's setContent().
https://github.com/ariya/phantomjs/issues/12439
2014-10-02 22:31:49 -07:00
Ariya Hidayat bad1fee468 README: Note on PhantomJS 2.
https://github.com/ariya/phantomjs/issues/10448
2014-10-01 20:17:07 -07:00
Ariya Hidayat b68d9467a7 Port the tests of the cookiejar module.
https://github.com/ariya/phantomjs/issues/12439
2014-09-30 22:00:53 -07:00
Ariya Hidayat a5f0ff7433 Port the test for console.log multiple arguments.
https://github.com/ariya/phantomjs/issues/12439
2014-09-29 21:29:44 -07:00
Ariya Hidayat 7e8986cd3e Port test tests of CJK codecs.
https://github.com/ariya/phantomjs/issues/12439
2014-09-28 22:39:20 -07:00
Ariya Hidayat 7bcb9a8725 Add a test to demonstrate the problem with JSON-ification.
https://github.com/ariya/phantomjs/issues/12615
2014-09-27 13:22:12 -07:00
Ariya Hidayat 5768b705a0 Implement clearMemoryCache() on a web page to clear the cache.
Unfortunately, due to Qt and WebKit limitation, this is technically
clearing all the cache used by every web page instance. It is the
best we can have right now.

https://github.com/ariya/phantomjs/issues/10357
2014-09-25 07:09:33 -07:00
Ariya Hidayat 105bcb32a9 Fix the mismatch of test files and their contents.
https://github.com/ariya/phantomjs/issues/12439
2014-09-24 21:49:26 -07:00
Ariya Hidayat 51d5835942 System#os.version workaround for new(er) OS X versions.
In case Qt doesn't provide the information yet, deduce it from the OS
kernel version (e.g. 14.x.y for OS 10.10 Yosemite).

https://github.com/ariya/phantomjs/issues/12579
2014-09-23 07:51:36 -07:00
Ariya Hidayat 72c53b5476 System#os.version should know OS 10.9 Mavericks.
https://github.com/ariya/phantomjs/issues/12579
2014-09-22 20:46:51 -07:00
Ariya Hidayat 639e09bd3a Provide OS kernel version in system.os.
This is available via the new property called `release`. A very simple
example to demonstrate it:

  var system = require('system');
  console.log('Kernel release', system.os.release);

which will print (on OS X 10.7.5 Lion):

  Kernel release 11.4.2

https://github.com/ariya/phantomjs/issues/12587
2014-09-21 23:47:57 -07:00
Ariya Hidayat 7c61f8857d Port the tests of web page properties and functions.
https://github.com/ariya/phantomjs/issues/12439
2014-09-18 23:17:21 -07:00
Ariya Hidayat b36da277e9 Port the user agent test.
https://github.com/ariya/phantomjs/issues/12439
2014-09-17 21:57:42 -07:00
Ariya Hidayat 9c7753189f Speed-up the tests by reducing some time-outs.
Running all tests should finish in 22 seconds instead of 41 seconds.

https://github.com/ariya/phantomjs/issues/12439
2014-09-16 20:43:10 -07:00
Zack Weinberg 4d4aa42c94 Set SO_REUSEADDR on the test server's listening port.
This means you don't have to wait 30 seconds in between invocations of
run-tests.py.

Also, if the test server fails to bind its port, print the actual
OS-level error message rather than guessing what the problem is.

issue #12439
2014-09-16 21:00:52 +00:00
Zack Weinberg 3d4f89b41e Bug fixes to test-server Python response hook support.
* correctly fake a package to hold all the response-hook modules
* use StringIO correctly in the response hooks
* prevent .py(c) files in test/www/ from being accessed directly
* prevent test/www/__init__ from being treated as a response hook
* add a test case that makes sure the existing hooks _can_ return 200 OK

(issue #12439; buggy commit 4d60e94)
2014-09-16 20:56:27 +00:00
Ariya Hidayat 2e8f0e8f68 Minor test runner clean-up.
Unused imports are removed.
Ensure that the correct reference is used.

https://github.com/ariya/phantomjs/issues/12439
2014-09-15 21:38:36 -07:00
Zack Weinberg 767494dc35 Add support for selective test execution.
If there are any positional arguments to test/run-tests.py, they are matched
(verbatim, not as regular expressions) against each test's name.  Only those
tests whose names contain at least one of the positional arguments will be
run.  Thus, for instance, you can run just the webpage tests with

    ./test/run-tests.py module/webpage

or one specific test with

    ./test/run-tests.py exact/name/of/test.js

or the basics and standards tests with

    ./test/run-tests.py basics standards

If no tests at all match, run-tests.py will print "ALL TESTS SKIPPED" and
exit unsuccessfully.

Ongoing work on issue #12439.
2014-09-15 16:21:25 +00:00
Zack Weinberg 4d60e9450d Support Python scripts in test/www/.
Rather than add all the special URLs we'll ever want to run-tests.py,
the embedded HTTP server now supports scripts in test/www/.  If you
try to load http://localhost:9180/path and test/www/path doesn't exist
but test/www/path.py does, then test/www/path.py is loaded as a module.
That module must export one function, handle_request(), which is called
to produce the response.

handle_request() has the same semantics as
SimpleHTTPRequestHandler.send_head().  That is, it takes one argument,
the SimpleHTTPRequestHandler object, conventionally named 'req'.
It should call the send_response(), send_header(), and end_headers()
methods of that object as appropriate.  And it should return a readable
filelike whose contents are taken as the body of the response.

If either module import or handle_request() throws any exception, the
HTTP response will be a 500 Internal Server Error with body provided
by cgitb.

Ongoing work on issue #12439.
2014-09-15 16:21:17 +00:00
Zack Weinberg 2b2d52e343 Improvements to logic in FileHandler.translate_path.
We already have 'base_path' as a global variable, so use that (or rather,
a new derivative of that) instead of inspect.getfile(inspect.currentframe()).

Rather than splitting the path and then iterating over every component
trying to figure out if it's "special", take advantage of the fact that
posixpath.normpath() will reliably produce a path with all ../ and bare-/
components at the very beginning.  Preserve the distinction between paths
with and without a trailing /, as SimpleHTTPRequestHandler expects.

So that paths containing unusual (e.g. non-ASCII, non-UTF-8) segments can
safely be tested, unquote and then requote the entire path.  This means
that the *bytes* corresponding to the ASCII characters

  0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz -_./

are guaranteed to be unquoted, and all other *bytes* are guaranteed to be
%-quoted.  (Note especially that *whether or not* the tests are being run
on Windows, \ in the original URL will be represented as %5C, and will
*not* be treated as a pathname separator.)

So that the tests behave consistently whether or not the OS has a case-
sensitive filesystem, after the above transformation, lowercase the entire
path.

Ongoing work on issue #12439.
2014-09-15 16:21:04 +00:00
Zack Weinberg 1adbbe4830 Support globs in run-tests.py#TESTS.
This means that there is no longer a need to add every individual test
to the list; only new *directories* have to be mentioned.  New tests
can be added just by dropping .js files into appropriate directories.

Tests which are not meant to be run by default now live in tests/manual/.
Currently there is one such test, tests/manual/standards/ecma-test262.js,
which downloads and runs the ECMAScript conformance suite.

Ongoing work on issue #12439.
2014-09-15 16:17:27 +00:00
Ariya Hidayat 83f4baf8c6 Port the test to check for plugin non-existence.
https://github.com/ariya/phantomjs/issues/12439
2014-09-14 09:35:41 -05:00
Ariya Hidayat f85238322e Port the test to change the encoded URL of network request.
https://github.com/ariya/phantomjs/issues/12439
2014-09-13 20:00:21 -05:00
Ariya Hidayat 3b972fbfbb Port the test to change the URL of network request.
https://github.com/ariya/phantomjs/issues/12439
2014-09-12 23:29:40 -05:00
Ariya Hidayat dca6f77a36 Port the test for onRepaintRequested handler.
https://github.com/ariya/phantomjs/issues/12439
2014-09-11 09:57:07 -07:00
Ariya Hidayat d52df7a1cf Port the test to abort network request.
https://github.com/ariya/phantomjs/issues/12439
2014-09-11 09:57:03 -07:00
Ariya Hidayat f95ef19fcb Port the test to check for resource received upon error.
https://github.com/ariya/phantomjs/issues/12439
2014-09-10 21:29:07 -07:00
Ariya Hidayat f29b76bb7f Port the test for resource request error handling.
https://github.com/ariya/phantomjs/issues/12439
2014-09-09 23:08:16 -07:00
Ariya Hidayat 804f61bcf5 Speed-up the tests: default auto-exit timeout is set to 1 second.
This reduces the total test duration from 72 seconds to 54 seconds.

https://github.com/ariya/phantomjs/issues/12439
2014-09-08 08:04:06 -07:00
Ariya Hidayat f20835735c Port custom headers testing of web page.
The HTTP server launched by the test runner has a new endpoint called
/echo. This simply echoes back some information (current on the made
request, in the future it will be expanded to further information)
formatted as JSON. This echo system facilitates easy testing for request
header manipulation feature.

https://github.com/ariya/phantomjs/issues/12439
2014-09-07 21:13:59 -07:00
Ariya Hidayat 2c10f6095b Port loading tests of web page.
https://github.com/ariya/phantomjs/issues/12439
2014-09-06 22:58:02 -07:00
Ariya Hidayat 784a06c3a7 The test runner also launches an HTTP server.
The server runs on port 9180 and serves the content from test/www
directory. Any tests can use this base URL to load test content and
to exercise certain PhantomJS API.

https://github.com/ariya/phantomjs/issues/12439
2014-09-05 21:31:38 -07:00
Vitaly Slobodin 235d072db5 Cast malloc to wchar_t. This is required in C++.
https://github.com/ariya/phantomjs/issues/12543
https://github.com/ariya/phantomjs/issues/12236
2014-09-05 06:32:45 -07:00
Zack Weinberg ab2e4788c6 Set the terminate handler to std::abort. (#12541) 2014-09-04 15:45:19 -04:00
Ariya Hidayat e8598a849e Port the tests of JavaScript's date parsing.
https://github.com/ariya/phantomjs/issues/12439
2014-09-04 08:28:45 -07:00
Ariya Hidayat 729f12c7d8 Port the tests for error handling.
https://github.com/ariya/phantomjs/issues/12439
2014-09-03 23:15:11 -07:00
Ariya Hidayat c883a80caf Port a few basic tests of global objects.
https://github.com/ariya/phantomjs/issues/12439
2014-09-02 22:28:53 -07:00
Ariya Hidayat 3274001e07 Remove the deprecated phantom.scriptName.
The use of phantom.scriptName has been deprecated since System#args was
introduce (version 1.5, March 2012). Any old scripts need to migrate to
System#args.

https://github.com/ariya/phantomjs/issues/12529
2014-09-01 08:11:28 -07:00
Ariya Hidayat 6c6059fd91 Remove the deprecated phantom.args.
The use of phantom.args has been deprecated (see commit 545a3f7)
since a long time ago (version 1.5, March 2012). Any old scripts
need to switch to use System#args instead.

https://github.com/ariya/phantomjs/issues/12527
2014-08-31 10:05:19 -07:00
Zack Weinberg f4eb3645f2 Make ciphersuite selection configurable; match Chromium by default. (#12524)
New option --ssl-ciphers takes a colon-separated list of OpenSSL
cipher names and sets the client cipher list to exactly that list.

The default for this option is arranged to match Chromium 35, which
has had its cipher selection optimized for the modern Web
(see https://briansmith.org/browser-ciphersuites-01.html for
rationales).  (Newer versions are the same except that they also add
ChaCha20-based ciphersuites, which OpenSSL 1.0.1 hasn't yet picked up.)
2014-08-30 20:49:58 -04:00
Zack Weinberg e8cddbfe7b Enable support for modern SSL (#12524).
* --ssl-protocol= option now accepts 'tlsv1.2', 'tlsv1.1', 'tlsv1.0'
   and 'default' as well as the existing 'tlsv1', 'sslv3', and 'any'.

 * The default is now none of the above, but rather QSsl::SecureProtocols,
   which means "whatever subset of ANY is still considered secure and also
   supported by the OpenSSL library in use".  (As of this writing, Qt's idea
   of "still considered secure" includes everything from SSLv3 on up, which
   is technically wrong -- SSLv3 has known breaks -- but we can live with.
   Qt currently doesn't have a way to select "TLSv1.0 and up".)
2014-08-30 20:49:38 -04:00
Ariya Hidayat 488a130799 A true OS X build fix for CrashHandler.
As suggested by ZackW.

https://github.com/ariya/phantomjs/issues/12236
2014-08-30 09:14:07 -07:00
Zack Weinberg 9afcf3c23d Explicitly suppress video and audio when building QtWebkit. (#12518)
This mostly matters when system sqlite is selected; that has the side
effect of enabling pkg-config which in turn causes QtWebkit to detect
the presence of system GStreamer and/or QtMultimedia and turn video on.
This way, the build is consistent across the board.
2014-08-30 07:02:21 -07:00
Zack Weinberg c64b1c078c More adjustments to system library usage on Unix (incl. Darwin) (#12518).
The affected libraries are fontconfig, freetype, harfbuzz, libpng, libjpeg,
sqlite, pcre, and zlib.

* On Darwin, by default, fontconfig is disabled and all of the other
  libraries are bundled.
* On non-Darwin, by default, fontconfig is enabled and system-provided
  freetype, libpng, libjpeg, and zlib are used.  Harfbuzz, pcre, and sqlite
  continue to be bundled.

* Individual libraries from the above list may now be enabled or disabled
  on the build.sh command line with e.g. --freetype=system or
  --freetype=bundled.

* The existing --system-qtdeps, --system-qt, --system-qtwebkit options
  have been renamed --qtdeps=system, --qt=system, --qtwebkit=system
  respectively.  New option --qtdeps=bundled forces all available
  bundled libraries to be used.

Also:

* Slight adjustments to organization of preconfig.sh.
* Can now disable PulseAudio and ALSA.
* Directly link OpenSSL instead of loading it at runtime.
* Clarify the pkg-config situation (it must be enabled if and only if
  sqlite comes from the system).
2014-08-30 07:02:21 -07:00
Zack Weinberg 0693711b0a Make it possible to disable ALSA and PulseAudio in qtbase. (#12518)
Cherry-picked configure script changes from upstream Qt5.3.
2014-08-30 07:02:21 -07:00
Ariya Hidayat a680ed41b2 Temporary OS X build fix for CrashHandler.
https://github.com/ariya/phantomjs/issues/12236
2014-08-29 21:40:02 -07:00
Zack Weinberg 858972e7ef Convert Utils into a namespace and remove dead code.
Post-cleanup for #12236.
2014-08-28 11:42:09 -04:00
Zack Weinberg 2ab57b875e Improve handling of crash dumps (issue #12236).
* If the environment variable PHANTOMJS_DISABLE_CRASH_DUMPS
   is set to any value, do not initialize Breakpad.

 * On Mac and Linux, if the environment variable TMPDIR is set,
   put the crash dumps there instead of in /tmp.

 * On Windows, %TEMP% was already being honored, but streamline
   the code for that.

 * Move the code that initializes Breakpad, and the code to print
   the crash messages, to their own module (src/crashdump.{h,cpp})
   and RAII class (CrashHandler).

 * Better wording of the crash message, particularly in the case where
   Breakpad failed to write a minidump file; update URL of crash-reporting
   guide.

 * Generally less repetitive code.  (Still way too many #ifdefs.)
2014-08-28 11:41:50 -04:00
Ariya Hidayat 2c0364b082 Port the tests of 'system' module.
https://github.com/ariya/phantomjs/issues/12439
2014-08-27 22:57:13 -07:00
Ariya Hidayat 7317724723 Fix consistent crash on OS X when rendering to PDF format.
By implementing a dummy platform native interface (for now, it may be
extended in the near future), QPlatformPrinterSupportPlugin will avoid
the path of loading the printer support plugin
(QCocoaPrinterSupportPlugin on OS X).

Related upstream bug (QCocoaPrinterSupportPlugin problem with static build):
https://bugreports.qt-project.org/browse/QTBUG-33109

https://github.com/ariya/phantomjs/issues/12500
2014-08-26 23:25:01 -07:00
Ariya Hidayat 4bc91b1bf0 A revamped test runner.
This Python script serves as a master test runner. It will run each test
script with a fresh instance of PhantomJS. The exit code of each script
determines its success or failure.

The existing tests (run-tests.js) are wrapped as one of the test
scripts. This permits a gradual migration to the new test system.

https://github.com/ariya/phantomjs/issues/12439
2014-08-25 21:13:32 -07:00
Ariya Hidayat 3a9fc49679 Enable even more tests (to 322 specs).
https://github.com/ariya/phantomjs/issues/10448
2014-08-24 20:24:39 -07:00
Ariya Hidayat 0cd703085d Reenable some more tests.
Now that the failing tests are isolated (among other, PDF crashing of
https://github.com/ariya/phantomjs/issues/12500), more tests should be
enabled. Going from 270 specs to 316 specs.

https://github.com/ariya/phantomjs/issues/10448
2014-08-24 20:00:04 -07:00
Ariya Hidayat 5ec80ff09c Enable more system module tests.
https://github.com/ariya/phantomjs/issues/12496
2014-08-24 19:33:53 -07:00
Ariya Hidayat 8cabfed4b3 Remove GIF format for screen capture export (render).
This is to reduce maintenance burden.  A GIF representation of a web
page can be produced by converting its PNG capture. There are numerous
third-party tools which can do the job better (optimized palette,
minimized loss, etc).

https://github.com/ariya/phantomjs/issues/12480
2014-08-23 09:20:20 -07:00
Ariya Hidayat 51c8c9cc62 Fix OS X stdout, stdin, and stderr.
To prevent unintended macro expansion, don't use the name
stdout/stdin/stderr in the native System object. Those properties are
achieved by shadowing it in the module interface (JavaScript side).

https://github.com/ariya/phantomjs/issues/12496
2014-08-22 07:56:40 -07:00
Milian Wolff 9e832a1569 Disable the phantom QPA on Windows.
It cannot, nor should it, be selected on windows machines. There, we
stick to the Windows QPA which is required to get a lot of things up
and running, like an eventloop, socket integration etc. pp.

There was code in the phantom QPA to make it compile, but it never
actually worked since a lot of things where missing (such as
instantiating QWindowsContext among others).

https://github.com/ariya/phantomjs/issues/12494
2014-08-22 16:35:26 +02:00
Vitaliy Slobodin 22e74549a3 Disable colorized output in tests on Windows.
https://github.com/ariya/phantomjs/issues/12484
2014-08-20 20:57:09 -07:00
Marcel Duran 3be7005a17 run-jasmine example: Ensure exit code is always returned.
https://github.com/ariya/phantomjs/pull/12486
2014-08-20 20:56:15 -07:00
Zack Weinberg 1e7829db97 Fix crash on exit if pages have been closed (#12482)
Regression from #12431: the loop to clear all surviving pages
neglects to check for entries in `m_pages` which have already
been closed, fully destructed, and therefore replaced by NULL
pointers.
2014-08-20 14:38:45 -04:00
Ariya Hidayat b5626bff97 Add a simple test for exit behavior.
https://github.com/ariya/phantomjs/issues/12431
https://github.com/ariya/phantomjs/issues/12439
2014-08-20 05:51:19 -07:00
Milian Wolff a9809996b1 Stop processing of JavaScript after phantom.exit().
This code:

    console.log("Hello World!");
    phantom.exit();
    console.log("Meh, noone should see me!");

currently produces this unexpected output:

    Hello World!
    Meh, noone should see me!

This patch fixes it to only output the first line, by loading a blank
page on phantom.exit(). Direct deletion of the web page can trigger
crashes, so this is a safe workaround.

https://github.com/ariya/phantomjs/issues/12431
2014-08-20 05:50:30 -07:00
Ariya Hidayat 77c47044cf Remove misc references to CoffeeScript.
https://github.com/ariya/phantomjs/issues/12410
2014-08-19 20:37:06 -07:00
Artem 5e018bd650 Update sleepsort.js
https://github.com/ariya/phantomjs/pull/12344
2014-08-19 20:35:06 -07:00
Ariya Hidayat a6f6130767 Travis CI can't build PhantomJS anymore.
https://github.com/ariya/phantomjs/issues/11880
2014-08-19 20:30:22 -07:00
Zack Weinberg 26934f32a9 Add a -v/--verbose option to run-tests.{sh,js}.
The newer ConsoleReporter is very quiet by default, which is nice, but
this provides a way to get something more like the older one-line-per-test
output.

 #12230 (Test suite improvements).
2014-08-19 20:24:28 -07:00
Zack Weinberg b524d53d36 Add ability to run tests selectively.
* Anything on the command line after "run-tests.sh" will be understood
   as a regular expression (if there is more than one argument, they are
   concatenated, with spaces in between) and only the tests whose "full
   names" match that regexp will be run.  The full name of a test is the
   "describe" string plus a space plus the "it" string.  Note well that,
   unlike the test-runner output, there is no colon in there.

 * run-tests.sh and run-tests.js now correctly handle being invoked from
   an arbitrary directory; the cwd does not have to be the project root.

 * Shell portability fixes for run-tests.sh.

 #12230 (Test suite improvements).
2014-08-19 20:24:28 -07:00
Zack Weinberg 6fb347d296 Fix jasmine.ConsoleReporter.specFailureDetails.
The new Jasmine includes a version of this formerly external add-on, but it
is buggy and doesn't print details of failing tests.

 #12230 (Test suite improvements).
2014-08-19 20:24:27 -07:00
Zack Weinberg e6b67bddc5 Import Jasmine 1.3.1.
The newer jasmine-console behavior requires minor adjustments to the
 ConsoleReporter we create in run-tests.js.  Also, en passant fix for
 a bug in the final callback: exiting with status equal to the number
 of failed tests does not work, because the _exit() system call takes
 only the low eight bits of the value passed.  If a test run happened
 to have 256 failing tests, the old code would have spuriously exited
 successfully.  Instead, just exit(1) if any tests fail.

 #12230 (Test suite improvements).
2014-08-19 20:24:27 -07:00
Zack Weinberg 7102e87bf4 Eliminate console spam during normal test execution.
Three tests were (potentially) dumping text to console.log during the
run, which they should never do.

Fixing that revealed that one of them, the test for interrupting a
long-running JS script, was not actually testing what it was supposed
to test. Fixing *that* revealed that the long-running-script hook is
broken and does not actually interrupt JS infinite loops; that test
has been temporarily disabled.

 #12230 (Test suite improvements).
2014-08-19 20:24:27 -07:00
Zack Weinberg 406f736e14 Do not use github.com in tests.
Two tests were spuriously failing because they tried to load pages on
`github.com` that were no longer structured as expected.  Use a local
webserver instead.

 #12230 (Test suite improvements).
2014-08-19 20:24:27 -07:00
Craig Teegarden f245d3ed22 update modernizr to 2.8.2 - specifically shows phantomjs supports "legacyflexbox" instead of the current "flexbox"
https://github.com/ariya/phantomjs/issues/12273
2014-08-19 20:18:46 -07:00
Zack Weinberg 9bbff95a57 Correction to fontconfig usage on Unix-not-OSX.
The PhantomJS QPA hardcoded usage of QFontconfigDatabase on
Unix-not-OSX, causing build failures in "bundle all the libraries" mode.
Use QGenericUnixFontDatabase instead, which is QFontconfigDatabase if
fontconfig is enabled, and QBasicFontDatabase if it isn't.  This means
that the bundled-qtdeps build will use only the fonts bundled with Qt,
and won't be able to find them on a machine that doesn't have the source
tree, which is suboptimal, but at least this makes the bundled-qtdeps
build complete successfully again.

Part of issue #12467.
2014-08-19 16:44:12 -04:00
Ariya Hidayat 2681756efd Obsolete links to any wiki page.
The documentation has been using GitHub pages for a while already.

https://github.com/ariya/phantomjs/issues/10627
2014-08-19 07:27:39 -07:00
Zack Weinberg 30a4a01bca 80-column compliance for build.sh messages.
Cosmetic fix as part of issue #12467.
2014-08-19 07:20:50 -07:00
Zack Weinberg 8d23afb782 Add --system-qtdeps build mode.
In this mode, system-provided libraries will be used for all of
Qt's dependencies, but Qt and QtWebkit themselves are still the
bundled copies.  This mode actually works.

Now that this mode exists, disable fontconfig in the "everything
bundled" mode, because it drags in the system freetype and several
other system libraries.  (There is no bundled fontconfig.)

Part of issue #12467.
2014-08-19 07:20:49 -07:00
Zack Weinberg 4246ed0533 Correct SQLITE3SRCDIR setting.
This is how we arrange for QtWebkit to use QtBase's bundled copy of
sqlite; without it, QtWebkit will attempt to use a system-provided
library instead, and if headers are unavailable, the build will fail.

Part of issue #12467.
2014-08-19 07:20:49 -07:00
Zack Weinberg e9e6f30e69 Add option to build against system qtbase but bundled qtwebkit.
As with the system-qtwebkit option, this does not actually work at this
point, but it enables experimentation toward getting it to work.

Part of issue #12467.
2014-08-19 07:20:49 -07:00
Zack Weinberg 9254f6855e Rationalize handshake between build.sh and preconfig.sh.
* build.sh now handles building qt and qtwebkit.
 * preconfig.sh is now only responsible for accumulating arguments
   to pass to qt's configure script.
 * preconfig.sh doesn't have command line arguments of its own;
   anything on its command line will be passed directly to qt's
   configure script.
 * first pass of adjustments to the qt configure parameters
   to try to get a more static build - unfortunately, system
   sqlite, libz, libpng, and libexpat are still getting pulled
   in somehow (mostly via fontconfig, I think).

Part of issue #12467.
2014-08-19 07:20:49 -07:00
Zack Weinberg 615f33c9c4 Add capability to build PhantomJS against system Qt/Webkit.
Invoking build.sh with --system-qtwebkit will skip the build of Qt and
QtWebkit and use the qmake in $PATH to build PhantomJS proper.

This doesn't actually *work* at the moment because the bundled
copy of Webkit has patches not yet merged upstream, but it's still
useful to have for testing purposes.

Part of issue #12467.
2014-08-19 07:20:48 -07:00
Zack Weinberg 5b5e63af23 Better Qt version check.
* Allow any patchlevel of Qt 5.3.x.
 * Do it in the master .pro file instead of main.cpp; this makes the build
   fail immediately rather than after compiling a bunch of stuff.

Part of issue #12467.
2014-08-19 07:20:48 -07:00
Zack Weinberg b81d7aec0a Update .gitignore for Qt 5.3.
* Ignore src/phantomjs_plugin_import.cpp, which is now created during
   the build.
 * Add leading slashes to a bunch of files that should not be ignored if
   they crop up in subdirectories.

Part of issue #12467.
2014-08-19 07:20:48 -07:00
Vitaliy Slobodin 0c8eb88c15 Add build script for Windows 2014-08-18 23:35:27 +04:00
John Gozde de2a19da9c Use Array.prototype.slice in window.callPhantom.
window.callPhantom formerly used Array.prototype.splice for cloning
its arguments to the internal _phantom.call. This relied on
non-standard behaviour of the splice method when only a single
argument was passed to it (it requires 2 arguments).

The correct method for cloning the arguments array is to use
Array.prototype.slice, which accepts a single argument (index) and
returns a new array from the specified index.

https://github.com/ariya/phantomjs/issues/12306
2014-08-18 00:15:08 -07:00
Petteri Räty a86ae1948c Fix rasterize example exit status on failure.
https://github.com/ariya/phantomjs/issues/11911
2014-08-17 23:23:05 -07:00
Ariya Hidayat fbe8eefc29 Launcher for ECMA-262 test suite (test262.ecmascript.org).
https://github.com/ariya/phantomjs/issues/12439
2014-08-16 20:46:28 -07:00
Ariya Hidayat 25ddf566e7 Fix path handling when running the build process.
https://github.com/ariya/phantomjs/issues/12433
2014-08-16 13:22:10 -07:00
Mike McQuaid 0a8b13403f preconfig.sh: don't require ICU on OSX
This isn't needed for the full build, only QtWebKit which has it's own ways of finding the system ICU.

https://github.com/ariya/phantomjs/issues/10448
2014-08-16 11:18:27 -07:00
Ariya Hidayat f532b73cb2 More tests for the arguments object.
https://github.com/ariya/phantomjs/issues/11845
https://github.com/ariya/phantomjs/issues/11558
https://github.com/ariya/phantomjs/issues/11746
https://github.com/ariya/phantomjs/issues/10315

https://github.com/ariya/phantomjs/issues/12439
2014-08-15 22:42:23 -07:00
Ariya Hidayat 3c9cf90d12 Remove website/ directory.
The web site has been based on GitHub pages for 2.5 years already.
2014-08-15 22:42:22 -07:00
Ariya Hidayat eca1081b6e Remove patches/ since they are for 1.x only.
https://github.com/ariya/phantomjs/issues/10448
2014-08-15 22:42:21 -07:00
Milian Wolff aa0300607c Stop early when QtBase or QtWebKit failed to compile.
Currently, the build script will continue to try to build PhantomJS
even when either QtBase or QtWebKit failed to compile. In such a
case, the script should return early and emit an error message.

https://github.com/ariya/phantomjs/issues/12433
2014-08-15 21:54:56 -07:00
Milian Wolff 4bf75c50b0 Simplify Env code by reusing QProcessEnvironment.
This gets rid of the custom parse code and slims down the API.

https://github.com/ariya/phantomjs/issues/12424
2014-08-15 21:49:46 -07:00
Ariya Hidayat 3136898976 Some tests for JavaScript's Function.
https://github.com/ariya/phantomjs/issues/12439
https://github.com/ariya/phantomjs/issues/10522
2014-08-09 11:53:19 -07:00
Ariya Hidayat bbdaa9e884 A simple assertion for the fortcoming revamped test system.
https://github.com/ariya/phantomjs/issues/12439
2014-08-09 10:59:22 -07:00
Vitaly Slobodin 28045aaf6b Merge pull request #12430 from KDAB/remove_coffeescript_test
Remove CoffeeScript references from unit tests
2014-08-08 18:24:26 +04:00
Vitaly Slobodin 2ebe5fd8a8 Merge pull request #12428 from KDAB/cleanup_qt5merge
Fixup wrong merge: remove src/qt/src
2014-08-08 18:24:02 +04:00
Milian Wolff 0c55c0a9e0 Remove CoffeeScript references from unit tests
https://github.com/ariya/phantomjs/issues/12429
2014-08-06 15:08:24 +02:00
Milian Wolff 514972db80 Fixup wrong merge: remove src/qt/src
This reapplies the patch of issue #11590 and drops the patch
from issue #11264. The former is still valid, while the latter
is hopefully resolved properly in Qt5 (see e.g. this:
https://bugs.webkit.org/show_bug.cgi?id=69419).

https://github.com/ariya/phantomjs/issues/12427
2014-08-06 15:00:34 +02:00
Ariya Hidayat 48fabe0646 Remove CoffeeScript support.
https://github.com/ariya/phantomjs/issues/12410
2014-07-30 01:29:21 -07:00
Ariya Hidayat 64b6fd2f4b ChangeLog for 1.9.7.
https://github.com/ariya/phantomjs/issues/11919
2014-07-30 01:29:20 -07:00
Ariya Hidayat 20a73a6d40 Update ChangeLog for 1.9.6.
https://github.com/ariya/phantomjs/issues/11905
2014-07-30 01:29:20 -07:00
Ariya Hidayat dc8d3c7052 Update ChangeLog for 1.9.3.
https://github.com/ariya/phantomjs/issues/11904
2014-07-30 01:29:19 -07:00
Ariya Hidayat 13e788f2c1 Travis CI: Get more dependencies for building Qt 5.
https://github.com/ariya/phantomjs/issues/11880
https://github.com/ariya/phantomjs/issues/10448
2014-07-28 06:51:35 -07:00
Ariya Hidayat 53edf23e8f Reintroduce silent mode for building PhantomJS 2.
https://github.com/ariya/phantomjs/issues/11880
https://github.com/ariya/phantomjs/issues/10448
2014-07-28 06:18:10 -07:00
Ariya Hidayat e2682edf48 Disable some failing and/or crashing unit tests.
Also, reorder the tests since webpage-spec.js seems to be sensitive to
any previously executed tests.

https://github.com/ariya/phantomjs/issues/10448
2014-07-28 03:33:13 -07:00
Ariya Hidayat 1bf54d8776 Correct the unit tests of PhantomJS version.
https://github.com/ariya/phantomjs/issues/10448
2014-07-27 17:10:30 -07:00
Ariya Hidayat 125c8d3d49 Qt 5 base: Fix permissions of some files.
https://github.com/ariya/phantomjs/issues/10448
2014-07-27 07:47:55 -07:00
Vitaliy Slobodin cf12fc4a23 Long live PhantomJS 2!
https://github.com/ariya/phantomjs/issues/10448
2014-07-27 07:47:34 -07:00
Vitaly Slobodin d10b8dc583 Merge pull request #12287 from zackw/expose-http-status-to-onresourceerror
Expose HTTP status and reason to onResourceError (#12252).
2014-07-15 10:12:55 +04:00
Vitaly Slobodin 4393627a80 Merge pull request #12313 from Vitallium/remove-nullptr-warning
Variables QT_GCC_* are undefined for QPA.
2014-07-15 10:10:18 +04:00
Vitaliy Slobodin c166662c0d Variables QT_GCC_* are undefined for QPA. 2014-06-15 18:19:02 +04:00
Vitaly Slobodin 05277b2d84 Merge pull request #12300 from artkoshelev/proxysetuprefactoring
Replace proxy initialization with existing method
2014-06-15 12:19:22 +04:00
Artem Koshelev 00afabc993 Replace proxy initialization with existing method
Since we have setProxy() method, we can replace the existing code
block in Phantom::init() with simple method call getting rid of
duplicated code.
2014-06-10 16:56:29 +04:00
Zack Weinberg d65601fe90 Expose HTTP status and reason to onResourceError (#12252). 2014-06-03 20:52:44 -04:00
Sven Eckelmann 13ad8a134e Use correctly rendered pdf for webpage-spec-renders tests
The last reference test.pdf in the tests was using a complete different region
of the input "image.jpg" because the used phantomjs version used to generate it
had a bug. This bug was fixed in 833eb824f5bae07f1b157d6757e7e3c98343f812
("Don't scale the unit px to 1/2.54 points for PDFs") and
1daa2eb4dd49efb848ff96e37f298a774520cc9b ("Disable page shrinking for pdf
printing to create accurate output").

The new version should now use the same region of the input image as the other
generated files for the gif, jpg and png tests. The only difference is the
extra height is still displayed on a second page but this is currently expected
by phantomjs.

https://github.com/ariya/phantomjs/issues/11590 ("page.paperSize is not
accurate for .pdf")
2014-05-31 08:23:32 -07:00
Sven Eckelmann b4e295cc97 Disable page shrinking for pdf printing to create accurate output
PDFs are not rendered like PNG or other image formats by phantomjs because it
uses the printer functionality of Qt+Webkit. But Webkit uses some printer
"optimization" to save paper by shrinking the output. Such shrinking results in
too small content on a page.

https://github.com/ariya/phantomjs/issues/11590 ("page.paperSize is not
accurate for .pdf")
2014-05-31 08:23:24 -07:00
Sven Eckelmann 800fbe8452 Don't scale the unit px to 1/2.54 points for PDFs
The unit px is one point inside the HTML source page but phantomjs handles it
without reason as 1/2.54 points. This makes the page smaller than expected when
trying to render a page as PDF.

https://github.com/ariya/phantomjs/issues/11590 ("page.paperSize is not
accurate for .pdf")
2014-05-31 08:23:13 -07:00
Ivan De Marino 62fbad4814 Adding IRC #phantomjs notif. to TravisCI build 2014-05-10 01:28:11 +01:00
Eric Heydenberk ccdd86f47f Add missing RPM spec file names; update changelog.
Issue #11262 https://github.com/ariya/phantomjs/issues/11262
2014-04-22 21:38:38 -07:00
Artem Koshelev 3c5302d567 Example of runtime proxy setup
https://github.com/ariya/phantomjs/issues/10803
2014-04-17 23:02:43 -07:00
Thomas Schlage 9da842df2b Added setProxy function
https://github.com/ariya/phantomjs/issues/10803
2014-04-17 23:02:15 -07:00
Dmitry Mazuro 4d2fedf243 Use SVG version of travis build status badges
https://github.com/ariya/phantomjs/issues/11880
2014-04-07 22:01:46 -07:00
Richard Harris 7d3f3f0819 Fix harfbuzz assertions using patch from Chromium.
Exotic text (e.g. attempting to render a binary file such as .zip
or .exe as a webpage) can trigger an assertion failure in the
Harfbuzz code. Chromium developers also noticed this issue and
committed a patch to fix it:

http://lists.freedesktop.org/archives/harfbuzz/2009-August/000354.html

This patch has not been accepted by upstream, but this (old) version
of Harfbuzz has been abandoned and superceded by Harfbuzz-NG.

Issue #11264
2014-04-07 21:58:36 -07:00
Ivan De Marino e9c77252ee Merge branch 'master' of https://github.com/pauloalem/phantomjs into pauloalem-master 2014-03-29 11:28:50 +00:00
petercoles d831dea8c8 Update example
Since this example was written the phantomjs home page has been redesigned and the targeted ID no longer exists. This tweaks the example so that it can again find content to report.
2014-03-29 11:09:51 +00:00
Ivan De Marino e9a47eddee Changing Travis CI build list into a table 2014-03-09 19:25:54 +00:00
Ivan De Marino 8f685818aa Fixed tests that dealt with manipulating request URLs.
Related to #11952.

Those tests use "http://phantomjs.org" as fixture.
The website "/images" directory has been renamed "/img",
breaking the tests.

Maybe not the greatest way to go about it, but
for now it will do. We probably need to have fixtures
served by a local server.
2014-03-09 01:02:49 +00:00
Ivan De Marino 77b5de1362 Run PhantomJS's tests as part of TravisCI
Related to #11952.
2014-03-09 01:02:49 +00:00
Ivan De Marino ba5998f74e Making GhostDriver test "quiet-er" (and parallel)
Also, trying to get the exit status of those tests reported, in case they fail.

Related to #11952.
2014-03-09 01:02:21 +00:00
Ivan De Marino 1797c146f1 Adding "test/ghostdriver-test" to run in Travis CI
Related to issue #11880
2014-03-08 23:37:47 +00:00
Adrian Chung 300f28cc5d Add example for how to post a json request to HTTP server
https://github.com/ariya/phantomjs/issues/11969
2014-02-19 21:40:02 -08:00
Rikke Simonsen bda8838698 Fix for crash bug caused by Iframe NULL reference
https://github.com/ariya/phantomjs/issues/10947
https://github.com/ariya/phantomjs/issues/11103
https://github.com/ariya/phantomjs/pull/11984
2014-02-19 21:30:11 -08:00
paulo alem 15d0636b70 Runner for jasmine 2
The old script needed some updates in order to support the new jasmine lib
2014-02-14 19:27:14 -02:00
Ivan De Marino 9940e8b25e Travis CI: Adding comments to ".travis.yml".
Related to issue #11880
2014-02-02 21:25:05 +00:00
Ivan De Marino 0765f9bdd2 Travis CI: trying to make the build more "resilient".
Related to issue #11880.
2014-02-02 21:00:53 +00:00
Ivan De Marino 06672a03aa Add links to "travis ci" to README file.
Linking branches "master" and "1.9" for now.
2014-02-02 19:58:36 +00:00
Ivan De Marino 056aa50c19 Importing GhostDriver 1.1.1.
Yes, 1.1.0 has just been imported.
But the key feature in 1.1.1 is Session Isolation in WebDriver: something that has been requested many times,
particularly when using GhostDriver with Selenium Grid.
2014-01-12 21:08:21 +00:00
Trevor North 18b8a4d444 Update table page break improvements patch
Includes the following fixes taken from trvrnrths-qt:
- Ensure we have a first cell to measure when checking required table
  height
- Handle page break edge case with exactly fitting last table row
  In the case where the last table row on a page fitted exactly no
  extra offset was afforded to the next row. This resulted in no
  space being left for the painting of the table header on the next
  page.
- Fix segfault when checking heights for pagination if table body does
  not have a cell at 0,0

See https://github.com/ariya/phantomjs/pull/11291 and
https://github.com/ariya/phantomjs/pull/11490.
2014-01-10 20:56:52 -08:00
Ariya Hidayat 42b3a86bcd OS X: Unsafe patch to fix selectable text on PDF output.
https://github.com/ariya/phantomjs/pull/11723
https://github.com/ariya/phantomjs/pull/11509
2014-01-10 16:18:08 -08:00
Joseph Rollinson 244cf251cd Adds support for multiple Cookie Jars.
Previously, there was a single global cookie jar shared between all web pages.
Now, one can have separate cookie jars for different web pages.

Makes CookieJar a normal class, not a singleton.
Moves many public CookieJar methods to public slots.
Adds default cookie jar to Phantom.
Adds the CookieJar module that provides access to cookie jars in javascript.
Adds cookie jar module tests.

Usage:
var jar = require('cookiejar').create();
var webpage = require('webpage').create();
webpage.cookieJar = jar;
...
webpage.close();
jar.close();

JS API changes:
Webpage:
    var jar = page.cookieJar; -- assigns 'jar' the given webpage's cookie jar.
    page.cookiejar = jar; -- sets 'jar' as the given webpage's cookie jar.
CookieJar:
    var jar = require('cookiejar').create(path)
        creates a cookie jar with persistent storage at the given file path
        (path not mandatory).
    var cookies = jar.cookies; -- assign's 'jar' the list of cookies in the
        cookie jar.
    jar.cookies = [c1, c2]; -- sets the cookie jar's cookies as the ones in the
        list.
    jar.addCookie(cookie) -- adds cookie 'cookie' to the cookie jar.

https://github.com/ariya/phantomjs/issues/11417
2014-01-10 16:12:39 -08:00
Vasyl Vavrychuk 3ae9d38d40 fixed test suite 'WebPage render image'
Previously the test suite 'WebPage render image' made a series of
webpage.open without waiting them to complete. This effected next
runned tests because on load handlers for pages were fired after
'WebPage render image' test finish.

https://github.com/ariya/phantomjs/issues/11780
2014-01-09 17:47:11 -08:00
Ashish Kulkarni 3ed2f68909 Implement "page-break-inside: avoid" for non-floating block elements.
This patch is taken from https://bugs.webkit.org/show_bug.cgi?id=5097#c17

It was originally part of PR #211 but was possibly overlooked in PR #344
(when the other two patches got reapplied after the QT source import).
2014-01-07 08:46:18 -08:00
Ariya Hidayat 6b45113cfe QWidget: Fix unused parameter warning when there's no Graphics View.
This reduces the amount of repetitive compiler warnings.

https://github.com/ariya/phantomjs/issues/11880
2014-01-06 23:27:34 -08:00
Ariya Hidayat 266ef0da59 Travis CI: Silent build.
https://github.com/ariya/phantomjs/issues/11880
2014-01-06 22:35:02 -08:00
Ariya Hidayat 46eb122ba3 Travis CI: Ensure that the build script executable.
https://github.com/ariya/phantomjs/issues/11880
2014-01-06 17:08:48 -08:00
Ariya Hidayat e533587107 Travis CI: Packages installation needs a priviliged access.
https://github.com/ariya/phantomjs/issues/11880
2014-01-06 16:59:50 -08:00
Ariya Hidayat 23f31391af Travis CI: Fix the build directives.
https://github.com/ariya/phantomjs/issues/11880
2014-01-06 16:45:33 -08:00
Ariya Hidayat e897ab8bb2 Travis CI: Ensure packages are cached for faster setup.
https://github.com/ariya/phantomjs/issues/11880
2014-01-06 16:42:56 -08:00
Ariya Hidayat aa388a05ef First attempt on using Travis CI.
https://github.com/ariya/phantomjs/issues/11880
2014-01-06 16:34:23 -08:00
James McParlane dca15d7ff6 Added onRepaint callback to webpage API.
Enables subscription to RepaintRequested events.
When the callback is invoked the time that the repaint was requested as well as the x,y and width,height of the repainted rectangle are provided as parameters.
Usage: page.onRepaint = function(time, x, y, width, height) { }

https://github.com/ariya/phantomjs/issues/11793
2014-01-06 23:05:30 +00:00
Ivan De Marino 9bfe22b428 Merge pull request #11784 from vvavrychuk/parse-error
fix lack of parse time errors location info
2014-01-06 11:30:29 -08:00
Ivan De Marino a9a219e74b Importing GhostDriver 1.1.0 in PhantomJS.
CHANGELOG for v1.1.0 (https://github.com/detro/ghostdriver/issues?labels=1.1.0&state=closed)

JavaScript Driver (Core)
* ENHANCEMENT: `/maximize` window will set the window size to 1336x768,
currently most common resolution online (see http://gs.statcounter.com/#resolution-ww-monthly-201307-201312)
* ENHANCEMENT #275: Implemented Browser and Network (HAR) Logging types
* FIXED #284: Attempt to wait for Page to Load if input causes form submit
* FIXED #291: Throw exception when attempting to set invalid timeout value
* FIXED #259: Fix issue regarding mouse clicks
* ENHANCEMENT #290: Enabled support for "Keep Alive" HTTP connections
* ENHANCEMENT #262: Allow access to PhantomJS API from WebDriver (Driver part)
* ENHANCEMENT #293: Import Selenium 2.39.0 WebDriver Atoms

Java Binding
* MINOR #251: Minor compilation issues for Binding
* ENHANCEMENT #262: Allow access to PhantomJS API from WebDriver (Java Binding part)

Tested using GhostDriver validation tests (https://github.com/detro/ghostdriver/tree/master/test).

https://github.com/ariya/phantomjs/pull/11877
2014-01-04 14:44:04 -08:00
Ariya Hidayat b70ff8929c Fix warning of obsolete userSpaceScaleFactor on OS X 10.9 (Mavericks).
Related upstream bug: https://bugreports.qt-project.org/browse/QTBUG-28574

Issue #1162 https://github.com/ariya/phantomjs/issues/11612
2014-01-03 20:41:00 -08:00
Ariya Hidayat b67866b612 Fix CoreText performance note on OS X 10.9 (Mavericks).
Upstream Qt bug: https://bugreports.qt-project.org/browse/QTBUG-32789
Upstream patch: https://codereview.qt-project.org/#patch,all,70097,4.
Upstream commit: https://qt.gitorious.org/qt/qt/commit/98352b964f

https://github.com/ariya/phantomjs/issues/11418
2014-01-03 20:40:53 -08:00
Ivan De Marino 9b0132712b Merge pull request #11868 from bradleyboy/click-modifier-fix
Pass modifier to mouse events for click/dblclick
2014-01-01 11:04:44 -08:00
Brad Daily 7659f2551c Adding tests for #11867
This tests mousedown, mouseup, click, and doubleclick for clicks with
modifier events. The mousedown/mouseup tests pass in 1.9.2, the
click/doubleclick do not. All pass with a build from this branch.
2014-01-01 13:47:33 -05:00
Ben Cox 18b342d3e7 Update some grammar on the README.md
Replaces the "a, b, c, d" with the more grammatically correct "a, b, c, and d"
2014-01-01 09:44:33 -08:00
Ivan De Marino e1ae72a866 Merge pull request #11866 from bmarkovic/patch-1
Added bitmap size and clipping to rasterize.js
2014-01-01 08:18:42 -08:00
Brad Daily e40ebb93d7 Pass modifier to mouse events for click/dblclick
A fix for the issue described here:

https://github.com/ariya/phantomjs/issues/11867
2014-01-01 11:06:11 -05:00
Bojan Markovic 54c1611801 Added bitmap size and clipping to rasterize.js
Added support for defining window/viewport size and eventual clipping to bitmap rasterization similar to how it is used with paper output.
2014-01-01 13:14:19 +01:00
Aaron Stone 3d80670e22 Handle script language in debug mode too.
f919121a35
2013-12-15 22:27:26 -08:00
Aaron Stone 176d435901 REPL is only valid for javascript updates.
https://github.com/ariya/phantomjs/issues/11744
2013-12-15 22:27:10 -08:00
Oleg Plakhotniuk f4128d7ede Select monospace font family properly.
CSS style "font-family: monospace" should select monospace font.

https://github.com/ariya/phantomjs/issues/11764
2013-12-13 07:34:49 -08:00
Aaron Stone 4ca640c5e7 Reject script-language values other than javascript and coffeescript
https://github.com/ariya/phantomjs/issues/11744
2013-12-13 06:58:20 -08:00
Aaron Stone 394e2f8699 Add option --script-language to explicitly set javascript or coffeescript
https://github.com/ariya/phantomjs/issues/11744
2013-12-13 06:58:04 -08:00
Francisco de Borja Lopez Río d5eaf41063 Set proper jobs number and library paths before building in OpenBSD
https://github.com/ariya/phantomjs/issues/10996
2013-12-05 07:30:02 -08:00
Martin Popelak 8f8de58752 Update of reference for mongoose license
As it seems that project Mongoose has been relicensed from MIT to GPL2. The link provided is leading to the new licensing agreement but as today version 3.1 of Mongoose is used which is licensed under MIT therefore correct reference to a license should be provided.

https://github.com/ariya/phantomjs/issues/10718
2013-12-05 07:27:53 -08:00
Vitaliy Slobodin efcc6c7861 Define the new page callback for interrupting a long-running JavaScript
Issues:
https://github.com/ariya/phantomjs/issues/11198
https://github.com/ariya/phantomjs/issues/11183
https://github.com/ariya/phantomjs/issues/11189
2013-11-23 22:09:39 -08:00
Vasyl Vavrychuk c8e4215097 fix lack of parse time errors location info
Location information of parse time error is given to javaScriptError not
with stack by with separate lineNumber and sourceID arguments. Put this info
to stack if it is empty so that it will be visible to user.

https://github.com/ariya/phantomjs/issues/11640
2013-11-24 01:43:10 +02:00
Vitaliy Slobodin 6a01a8dece Upgrade to Qt 4.8.5
https://github.com/ariya/phantomjs/issues/11452
2013-10-19 07:52:31 -07:00
Max Edmands 94e63bfa04 Fix typo in the cookie jar debug message. 2013-10-19 07:52:01 -07:00
Vitaliy Slobodin 23df8811a1 REPL returns empty object on enumerating properties on a simple JavaScript type (Number, String, Logical).
We should not to do that.

Issue:
https://github.com/ariya/phantomjs/issues/11622
2013-10-07 20:33:52 -07:00
Mike McQuaid fe6a967bad Fix Clang compilation
Already merged in Qt: b82b8bfa81

Issue #11611 https://github.com/ariya/phantomjs/pull/11611
2013-10-01 07:38:40 -07:00
Ariya Hidayat 2691540711 Getting ready for 1.9.2.
Issue #11452: https://github.com/ariya/phantomjs/issues/11452
2013-09-08 07:25:43 -07:00
hexid b1e181176e Add require.paths support
Issues: https://github.com/n1k0/casperjs/issues/462 https://github.com/ariya/phantomjs/issues/11339
2013-09-01 07:53:08 -07:00
Morgan Roderick 7431cbf229 CONTRIBUTING.md: convenient => confident
Minor correction to language use in CONTRIBUTING.md
2013-08-15 12:05:41 +02:00
Ivan De Marino 73bb560840 Import GhostDriver v1.0.4
Issues in this release: https://github.com/detro/ghostdriver/issues?labels=1.0.4&state=closed
See GhostDriver Changelog for more details.
2013-07-25 23:24:53 +01:00
Dmitry Parshin 8114d44a28 fixed compile errors for no-JIT configuration
Issue #11475 https://github.com/ariya/phantomjs/issues/11475
2013-07-24 23:38:44 -07:00
Richard Harris 4989445e71 Fix harfbuzz assertions using patch from Chromium.
Exotic text (e.g. attempting to render a binary file such as .zip
or .exe as a webpage) can trigger an assertion failure in the
Harfbuzz code. Chromium developers also noticed this issue and
committed a patch to fix it:

http://lists.freedesktop.org/archives/harfbuzz/2009-August/000354.html

This patch has not been accepted by upstream, but this (old) version
of Harfbuzz has been abandoned and superceded by Harfbuzz-NG.

Issue #11264
2013-07-24 23:34:45 -07:00
Vitaliy Slobodin 1a25383307 Use Qt::transparent to resolve graphical artifacts with images with transparent background.
We need to use QImage::Format_ARGB32_Premultiplied on Windows to preserve a text hinting and antialiasing. Using the function `qRgba()` leads to wrong pixel values on a target image. Since, `QImage::fill(uint pixel)` doesn't handle the QImage::Format_ARGB32_Premultiplied format, so we need to use the another overload `QImage::fill(const QColor &color)`

Issues:
https://github.com/ariya/phantomjs/issues/11276
https://github.com/ariya/phantomjs/issues/11007
https://github.com/ariya/phantomjs/issues/11366
2013-06-24 01:07:24 +04:00
Vitaliy Slobodin b1cb3a00bd Merge pull request #11425 from Vitallium/master
Fix typo in the `loadurlwithoutcss` example
2013-06-23 00:45:30 -07:00
Vitaliy Slobodin fdec25ac4c Fix typo in `loadurlwithoutcss` example
Issue: https://github.com/ariya/phantomjs/issues/11321
2013-06-23 11:28:51 +04:00
Ivan De Marino 6ba33cbcab Merge pull request #11422 from detro/ghostdriver-dev
WebServer Headers for Request are treated case-insensitive
2013-06-21 15:55:25 -07:00
Ivan De Marino c466d8aeef WebServer Headers for Request are treated case-insensitive
To achieve this, Request Headers are stored in both "original" and "lowercase".
In this way we don't mangle with the request object we have received, while
still be able to handle headers when NOT in the classic "Camel-Case" format.

Fixes #11421.
2013-06-21 23:51:05 +01:00
Ariya Hidayat edf2d90a11 Patch for table page break improvement.
From d78182d3a6451522f239ee1ecbb71863eb053792 Mon Sep 17 00:00:00 2001
From: Artem Baranovskiy <likejavascript@gmail.com>
Date: Mon, 6 May 2013 08:01:01 +0400
Subject: [PATCH] Table page-break improvements

See issue #11291 https://github.com/ariya/phantomjs/pull/11291
2013-06-08 21:40:55 -07:00
Ariya Hidayat 644f379588 Include all the changes from 1.9.1. 2013-06-08 02:20:42 -07:00
Ariya Hidayat b4c4429e86 Unit tests: reduce the flakiness of loading progress tests.
For whatever reason, swapping the order with the render() tests solve the
intermittent random failures. Also, split the tests between loading
start and finish checks (to better recognize which one is failing, if
there is a failure), also make the tests more asynchoronous.

https://github.com/ariya/phantomjs/issues/11091
2013-06-08 02:18:31 -07:00
Ariya Hidayat 01587211cb Unit test: secure connection check becomes async.
Issue #10882: https://github.com/ariya/phantomjs/issues/10882
2013-06-08 02:05:07 -07:00
Ariya Hidayat 44c3d6080d Unit tests: robustify the tests of PDF, GIF, PNG, JPEG rendering.
Issue #10973 https://github.com/ariya/phantomjs/issues/10973
2013-06-08 02:04:59 -07:00
Ariya Hidayat 9f1f56bc3b Unit tests: terminate any web servers after finishing the tests.
Issue #11163: https://github.com/ariya/phantomjs/issues/11163
Issue #11243: https://github.com/ariya/phantomjs/issues/11243
2013-06-08 02:04:48 -07:00
Ariya Hidayat f57fa468ab Unit test: tweak secure connection check.
The main wikipedia page can be slow to load and thus triggers the timeout.
Let's use the fast Google site so that we don't get flaky outcome.

Issue #10882: https://github.com/ariya/phantomjs/issues/10882
2013-06-08 02:04:39 -07:00
Bryan Bishop fb8edb7c72 Fix minor typos in preconfig.sh.
One is a typo, while the other is grammar-related.

fixes #11388

https://github.com/ariya/phantomjs/issues/11388
2013-06-05 18:07:42 -05:00
Vitaliy Slobodin 4d916971b3 Fix including http:// in the proxy URL:
The proxy host parsed incorrectly, when it was typed with a scheme (http or https).
Now proxy can be specified with the scheme.

Fix invalid type conversion:
m_proxyPort converts to its ASCII representation.
Use `QString::number` to include a proxy port properly.

Issues:
https://github.com/ariya/phantomjs/issues/11117
https://github.com/ariya/phantomjs/issues/10811
2013-05-29 00:38:15 +04:00
Vitaliy Slobodin 639e8c85b2 Make QNetworkReplyHandler deliver content asynchronously
when its load type is set to SynchronousLoad.

Issue #11338: https://github.com/ariya/phantomjs/issues/11338
Upstream bug: https://bugs.webkit.org/show_bug.cgi?id=62808
2013-05-20 19:49:23 -07:00
Ariya Hidayat fa238856f9 third-party.txt: Include OpenSSL.
Issue #11269 https://github.com/ariya/phantomjs/issues/11269
2013-05-20 19:49:22 -07:00
Ariya Hidayat 9aa0705d3c Update ChangeLog. 2013-05-20 00:20:14 -07:00
Alex Alvarez 3bd7a3dfa6 Netsniff.js example should exit with an error when fails to load the adress
Issue #11333 https://github.com/ariya/phantomjs/issues/11333
2013-05-19 22:29:31 -07:00
Alex Alvarez 2f851086e4 Netsniff.coffee example should exit with an error when fails to load the adress
Issue #11333 https://github.com/ariya/phantomjs/issues/11333
2013-05-19 22:28:09 -07:00
Jan Minar 320608662d Reword for better English 2013-05-19 18:16:09 -07:00
Vitaliy Slobodin 0726a8e2bb Fix crash when calling QObject::disconnect for QNetworkReplyWrapper
Fix it by watching the QNetworkReply's destroyed() signal and avoid the dangling pointer
instead. The QNetworkReply doesn't need to be aborted in this case anyway.

Issue #11252: https://github.com/ariya/phantomjs/issues/11252
Upstream bug: https://bugs.webkit.org/show_bug.cgi?id=116035
2013-05-19 12:01:33 -07:00
Ariya Hidayat 706e928e78 Update ChangeLog. 2013-05-15 00:03:39 -07:00
Eric Heydenberk f1472b54d1 Update RPM spec changelog
- Describe %files change
- Fix year in timestamp in previous changelog entry

Issue #11262 https://github.com/ariya/phantomjs/issues/11262
2013-05-13 23:34:35 -07:00
Eric Heydenberk dff8ce2526 Update rpm spec file names
- Add missing example files
- Alphabetize names

Issue #11262 https://github.com/ariya/phantomjs/issues/11262
2013-05-13 23:33:51 -07:00
Vitaliy Slobodin 5528d75c9d Network request header manipulation
Issue: https://github.com/ariya/phantomjs/issues/11299 (#11299)

User should be able  to manipulate HTTP headers per each network request, not only using global setting page.customHeaders.
2013-05-13 22:48:58 -07:00
Vitaliy Slobodin f8e79fb8c6 Limit the maximum request post size to 10 MB (megabytes).
std::numeric_limits<qint64>::max is too big for QByteArray (throws Out of Memory exception).
Set up the limit like it was done in Google Chrome
Ref: https://code.google.com/p/chromium/codesearch#chromium/src/third_party/WebKit/Source/core/inspector/NetworkResourcesData.cpp

Related to issue #10158 https://github.com/ariya/phantomjs/issues/10158
2013-05-13 22:41:15 -07:00
Ivan De Marino 23515550d5 MINOR: Reorder initialisation order in NAM constr.
`m_resourceTimeout` is declared before of other
private variables, and the compiler was complaining
the initialisation order could not be respected.
This caused annoying (but innocuous) warnings at compile time.
2013-04-30 22:57:58 +01:00
Andrew Galloni 3ae632e704 ChangeUrl to accept an encoded string
Issue #11243: https://github.com/ariya/phantomjs/issues/11243.
2013-04-29 07:07:53 -07:00
Robin Helgelin f72f2962d1 Updated rpm spec file to work with 1.9.
Issue #10939: https://github.com/ariya/phantomjs/issues/10939
2013-04-29 07:05:48 -07:00
execjosh 39bec1ce17 Synchronize std{in,out,err} encoding with `Terminal`
See #11234 https://github.com/ariya/phantomjs/pull/11234
Spin off from #11168 https://github.com/ariya/phantomjs/pull/11168
2013-04-29 07:00:47 -07:00
execjosh b159144a48 Teach `File` how to change its encoding
If a `File` is in "text" mode, then it has an encoding.  This
encoding defaults to UTF-8; however, it can be set only at time of
construction (by using `fs.open`).

This modification allows the user to change the encoding on-the-fly
for "text" mode `File` instances.

See #11234 https://github.com/ariya/phantomjs/pull/11234
Spin off from #11168 https://github.com/ariya/phantomjs/pull/11168
2013-04-29 07:00:19 -07:00
execjosh 3d874d9e0d Make `Terminal` emit a signal upon encoding change
See #11234 https://github.com/ariya/phantomjs/pull/11234
Spin off from #11168 https://github.com/ariya/phantomjs/pull/11168
2013-04-29 06:58:44 -07:00
Ariya Hidayat c07a2efa33 Update ChangeLog. 2013-04-22 22:39:02 -07:00
execjosh f8a905c8b0 Link with text codec plugins on mac and linux
Fixes [#10249](https://github.com/ariya/phantomjs/issues/10249)
2013-04-22 22:35:56 -07:00
execjosh d925a510d9 Improve WebPage CJK support tests.
This is for issue #10249: https://github.com/ariya/phantomjs/issues/10249.
2013-04-22 22:35:08 -07:00
Vitaliy Slobodin 3edcabef9f Fix compilation with MSVC 2010
Issue #10158: https://github.com/ariya/phantomjs/issues/10158
This bug introduced by the marco max( ) defined in <windef.h>.
It replaces max( ) with another statement but still preceeded by numberic_limits<Type>::
The workaround is to use the parenthesis
2013-04-13 20:17:12 -07:00
Vitaliy Slobodin 78242e5d6c Fix command line option typo
Issue #11219: https://github.com/ariya/phantomjs/issues/11219
2013-04-12 23:12:20 -07:00
execjosh 36ab7194e4 Use UTF-8 encoding for std{in,out,err}
This fixes issue #11162.

`File` constructor takes a `QTextCodec *`, codec; but, if codec is
`NULL`, then it assumes "binary" mode, which causes non-ASCII
characters to be converted to NUL (`\0`) in `File::write`.

This change passes the codec for UTF-8 to the `File` constructor for
the `std{in,out,err}` instances, thus opening them in *text mode*.
2013-04-12 23:10:25 -07:00
execjosh 8042f3b92c Flush in `File::write` when in unbuffered "text" mode
If the wrapped `QFile` was opened with `QIODevice::Unbuffered`, any
writes should be unbuffered.  However, as currently implemented,
using `QTextStream` when the `File` is in "text" mode causes all
reads/writes to be buffered.

This modification forces a flush in `File::write` if the wrapped
`QFile` was opened with `QIODevice::Unbuffered`.

Necessary to fix issue #11162 https://github.com/ariya/phantomjs/issues/11162.
2013-04-12 23:10:08 -07:00
Ariya Hidayat 24078b56c7 Update ChangeLog. 2013-03-31 03:08:26 -07:00
Ariya Hidayat 0bc2eb418e Temporarily call this branch as version 1.10.
Issue #10448 https://github.com/ariya/phantomjs/issues/10448#issuecomment-15689386
2013-03-31 03:06:50 -07:00
Pavel fcdd274f2e Show postData in onResourceRequested callback.
Issue #10158 https://github.com/ariya/phantomjs/issues/10158
2013-03-31 02:54:37 -07:00
Vitaliy Slobodin 47dc82681d Fire `onResourceReceived` callback when the resource error occured.
Issue #11163: https://github.com/ariya/phantomjs/issues/11163
2013-03-31 02:39:53 -07:00
Vitaliy Slobodin 9ca45ed62e Fix loading modules from an absolute path on Windows.
Don't check the module path using Linux-style path checking.

Issue #11165: https://github.com/ariya/phantomjs/issues/11165
2013-03-25 19:01:32 -07:00
13507 changed files with 69773 additions and 2968437 deletions

18
.gitignore vendored
View File

@ -10,19 +10,20 @@ qrc_*
*.swp *.swp
*.pyc *.pyc
*.a *.a
debian/*.debhelper /debian/*.debhelper
debian/files /debian/files
debian/*.log /debian/*.log
debian/*.substvars /debian/*.substvars
debian/*/ /debian/*/
/deploy/qt-*.tar.gz /deploy/qt-*.tar.gz
/deploy/Qt-* /deploy/Qt-*
/symbols /symbols
src/qt/qtc-debugging-helper /src/qt/qtc-debugging-helper
/src/phantomjs_plugin_import.cpp
# ignore ctags # ignore ctags
/tags /tags
tools/dump_syms.app/ /tools/dump_syms.app/
# Ignore Visual Studio temporary files, build results, etc # Ignore Visual Studio temporary files, build results, etc
*.suo *.suo
@ -55,3 +56,6 @@ tools/dump_syms.app/
[Dd]ebug*/ [Dd]ebug*/
[Rr]elease/ [Rr]elease/
bin/ bin/
*.class
build/
.gradle/

29
.travis.yml Normal file
View File

@ -0,0 +1,29 @@
language: cpp
compiler:
- gcc
cache: apt
before_install:
- sudo apt-get -yqq update #< Suggested by the Travis CI doc
- sudo apt-get -fyq install #< Fixes inconsistency of packages installed previously
install:
- sudo apt-get -yq install build-essential chrpath libssl-dev libfontconfig1-dev sqlite3 libsqlite3-dev ruby gperf bison flex libicu48 libicu-dev #< Build Dependencies
before_script:
- chmod +x ./build.sh
- chmod +x ./test/run-tests.sh
- chmod +x ./test/run-tests-ghostdriver.sh
script:
- ./build.sh --confirm --silent #< Build
- ./test/run-tests.sh #< Test (PhantomJS)
- ./test/run-tests-ghostdriver.sh #< Test (GhostDriver / PhantomJSDriver)
notifications:
irc:
channels:
- "irc.freenode.org#phantomjs"
on_success: always
on_failure: always
use_notice: true

View File

@ -22,9 +22,9 @@ In the commit message:
*Second opinion is always important.* *Second opinion is always important.*
**Bug fixing**. If you have a fix for a bug, please attach your patch in the corresponding issue in the [issue tracker](https://github.com/ariya/phantomjs/issues). If there is no entry for the bug yet, then please create a new one. If you are convenient working with Git, see the Get Ready section below on how to submit your change. **Bug fixing**. If you have a fix for a bug, please attach your patch in the corresponding issue in the [issue tracker](https://github.com/ariya/phantomjs/issues). If there is no entry for the bug yet, then please create a new one. If you are confident working with Git, see the Get Ready section below on how to submit your change.
**Improvement and feature request**. If you have an improvement idea, please send an email to the [mailing list](http://groups.google.com/group/phantomjs) (preferable than contacting the developers directly) so that other people can give their insights and opinions. This is also important to avoid duplicate work. **Improvement and feature request**. If you have an improvement idea, please send an email to the [mailing list](http://groups.google.com/group/phantomjs) (rather than contacting the developers directly) so that other people can give their insights and opinions. This is also important to avoid duplicate work.
**Task management**. Once the feature idea is agreed upon and translated into concrete actions and tasks, please use the [issue tracker](https://github.com/ariya/phantomjs/issues) to create an issue for each individual task. Further technical discussion about the task and the implementation details should be carried out in the issue tracker. **Task management**. Once the feature idea is agreed upon and translated into concrete actions and tasks, please use the [issue tracker](https://github.com/ariya/phantomjs/issues) to create an issue for each individual task. Further technical discussion about the task and the implementation details should be carried out in the issue tracker.

View File

@ -1,5 +1,55 @@
Please see also http://phantomjs.org/releases.html. Please see also http://phantomjs.org/releases.html.
2015-01-23: Version 2.0.0
New features
* Switched to Qt 5 and updated WebKit (issue 10448)
* Implemented clearing of memory cache (issue 10357)
* Added support for HTTP header change for every request (issue 11299)
Improvements
* Fixed rendering of CJK text by always linking the codecs (issue 10249)
* Ensured onResourceReceived is still fired on an error (issue 11163)
* Fixed possible crash in handling network requests (issue 11252)
* Removed hardcoded GhostDriver launching message (issue 12681)
* Allowed disk cache more than 2 GB (issue 12303)
Examples
* Netsniff example should exit when fails to load (issue 11333)
2014-01-25: Version 1.9.7
* Reverted to GhostDriver 1.1.0 instead of 1.1.1 (issue 11915)
* Fixed another warning of obsolete userSpaceScaleFactor on OS X 10.9 (issue 11612)
2014-01-20: Version 1.9.6
* Updated GhostDriver to version 1.1.1 (issue 11877, 11893)
2014-01-19: Version 1.9.3
* Fixed CoreText performance note on OS X 10.9 (issue 11418)
* Fixed warning of obsolete userSpaceScaleFactor on OS X 10.9 (issue 11612)
2013-09-06: Version 1.9.2
* Fixed graphical artifacts with transparent background on Windows (issue 11276, 11007, 11366)
* Updated GhostDriver to version 1.0.4 (issue 11452)
2013-06-04: Version 1.9.1
Critical bug fixes:
* Fixed problems with specifying proxy server (issue 10811, 11117)
* Fixed UTF-8 encoding with system.stdout and system.stderr (issue 11162)
* Ensured that onResourceReceived will be always invoked (issue 11163)
* Fixed module loading from an absolute path on Windows (issue 11165)
* Fixed typo in the command-line option for setting the cache size (11219)
* Fixed possible crash when handling network requests (issue 11252, 11338)
2013-03-20: Version 1.9.0 "Sakura" 2013-03-20: Version 1.9.0 "Sakura"
New features New features

View File

@ -1,23 +1,23 @@
# [PhantomJS](http://phantomjs.org) - Scriptable Headless WebKit # [PhantomJS](http://phantomjs.org) - Scriptable Headless WebKit
PhantomJS ([www.phantomjs.org](http://phantomjs.org)) is a headless WebKit scriptable with JavaScript or CoffeeScript. It is used by hundreds of [developers](https://github.com/ariya/phantomjs/wiki/Buzz) and dozens of [organizations](https://github.com/ariya/phantomjs/wiki/Users) for web-related development workflow. PhantomJS ([www.phantomjs.org](http://phantomjs.org)) is a headless WebKit scriptable with JavaScript. It is used by hundreds of [developers](http://phantomjs.org/buzz.html) and dozens of [organizations](http://phantomjs.org/users.html) for web-related development workflow.
The latest [stable release](http://phantomjs.org/release-1.9.html) is version 1.9 (codenamed <a href="http://phantomjs.org/release-names.html">"Sakura"</a>). Follow the official Twitter stream [@PhantomJS](http://twitter.com/PhantomJS) to get the frequent development updates. The latest [stable release](http://phantomjs.org/release-2.0.html) is version 2.0.
**Note**: Please **do not** create a GitHub pull request **without** reading the [Contribution Guide](https://github.com/ariya/phantomjs/blob/master/CONTRIBUTING.md) first. Failure to do so may result in the rejection of the pull request. **Note**: Please **do not** create a GitHub pull request **without** reading the [Contribution Guide](https://github.com/ariya/phantomjs/blob/master/CONTRIBUTING.md) first. Failure to do so may result in the rejection of the pull request.
## Use Cases ## Use Cases
- **Headless web testing**. Lightning-fast testing without the browser is now possible! Various [test frameworks](https://github.com/ariya/phantomjs/wiki/Headless-Testing) such as Jasmine, Capybara, QUnit, Mocha, WebDriver, YUI Test, BusterJS, FuncUnit, Robot Framework, and many others are supported. - **Headless web testing**. Lightning-fast testing without the browser is now possible! Various [test frameworks](http://phantomjs.org/headless-testing.html) such as Jasmine, Capybara, QUnit, Mocha, WebDriver, YUI Test, BusterJS, FuncUnit, Robot Framework, and many others are supported.
- **Page automation**. [Access and manipulate](https://github.com/ariya/phantomjs/wiki/Page-Automation) web pages with the standard DOM API, or with usual libraries like jQuery. - **Page automation**. [Access and manipulate](http://phantomjs.org/page-automation.html) web pages with the standard DOM API, or with usual libraries like jQuery.
- **Screen capture**. Programmatically [capture web contents](https://github.com/ariya/phantomjs/wiki/Screen-Capture), including CSs, SVG and Canvas. Build server-side web graphics apps, from a screenshot service to a vector chart rasterizer. - **Screen capture**. Programmatically [capture web contents](http://phantomjs.org/screen-capture.html), including CSS, SVG and Canvas. Build server-side web graphics apps, from a screenshot service to a vector chart rasterizer.
- **Network monitoring**. Automate performance analysis, track [page loading](https://github.com/ariya/phantomjs/wiki/Network-Monitoring) and export as standard HAR format. - **Network monitoring**. Automate performance analysis, track [page loading](http://phantomjs.org/network-monitoring.html) and export as standard HAR format.
## Features ## Features
- **Multiplatform**, available on major operating systems: Windows, Mac OS X, Linux, other Unices. - **Multiplatform**, available on major operating systems: Windows, Mac OS X, Linux, and other Unices.
- **Fast and native implementation** of web standards: DOM, CSS, JavaScript, Canvas, SVG. No emulation! - **Fast and native implementation** of web standards: DOM, CSS, JavaScript, Canvas, and SVG. No emulation!
- **Pure headless (no X11) on Linux**, ideal for continuous integration systems. Also runs on Amazon EC2, Heroku, Iron.io. - **Pure headless (no X11) on Linux**, ideal for continuous integration systems. Also runs on Amazon EC2, Heroku, and Iron.io.
- **Easy to install**: [Download](http://phantomjs.org/download.html), unpack, and start having fun in just 5 minutes. - **Easy to install**: [Download](http://phantomjs.org/download.html), unpack, and start having fun in just 5 minutes.
## Ecosystem ## Ecosystem
@ -31,15 +31,16 @@ PhantomJS needs not be used only as a stand-alone tool. Check also some excellen
- [PhantomRobot](https://github.com/datakurre/phantomrobot) runs Robot Framework acceptance tests in the background via PhantomJS. - [PhantomRobot](https://github.com/datakurre/phantomrobot) runs Robot Framework acceptance tests in the background via PhantomJS.
- [Mocha-PhantomJS](https://github.com/metaskills/mocha-phantomjs) run Mocha tests using PhantomJS. - [Mocha-PhantomJS](https://github.com/metaskills/mocha-phantomjs) run Mocha tests using PhantomJS.
and many others [related projects](https://github.com/ariya/phantomjs/wiki/Related-Projects). and many others [related projects](http://phantomjs.org/related-projects.html).
## Questions? ## Questions?
- Explore the complete [documentation](https://github.com/ariya/phantomjs/wiki) - Explore the complete [documentation](http://phantomjs.org/documentation/).
- Read tons of [user articles](https://github.com/ariya/phantomjs/wiki/Buzz) on using PhantomJS. - Read tons of [user articles](http://phantomjs.org/buzz.html) on using PhantomJS.
- Join the [mailing-list](http://groups.google.com/group/phantomjs) and discuss with other PhantomJS fans. - Join the [mailing-list](http://groups.google.com/group/phantomjs) and discuss with other PhantomJS fans.
PhantomJS is free software/open source, and is distributed under the [BSD license](http://opensource.org/licenses/BSD-3-Clause). It contains third-party code, see the included `third-party.txt` file for the license information on third-party code. PhantomJS is free software/open source, and is distributed under the [BSD license](http://opensource.org/licenses/BSD-3-Clause). It contains third-party code, see the included `third-party.txt` file for the license information on third-party code.
PhantomJS is created and maintained by [Ariya Hidayat](http://ariya.ofilabs.com/about) (Twitter: [@ariyahidayat](http://twitter.com/ariyahidayat)), with the help of [many contributors](https://github.com/ariya/phantomjs/contributors). PhantomJS is created and maintained by [Ariya Hidayat](http://ariya.ofilabs.com/about) (Twitter: [@ariyahidayat](http://twitter.com/ariyahidayat)), with the help of [many contributors](https://github.com/ariya/phantomjs/contributors). Follow the official Twitter stream [@PhantomJS](http://twitter.com/PhantomJS) to get the frequent development updates.

128
build.cmd Normal file
View File

@ -0,0 +1,128 @@
@echo off
SETLOCAL EnableExtensions EnableDelayedExpansion
set BUILD_TYPE=release
if /i "%1" == "debug" (
SET BUILD_TYPE=debug
)
set ROOT_DIR=%CD%
set 3RD_PARTY_LIBRARIES_REPO_URL=https://github.com/Vitallium/phantomjs-3rdparty-win
set 3RD_PARTY_LIBRARIES_REPO_BRANCH=msvc2013
if /i BUILD_TYPE == "debug" (
set 3RD_PARTY_LIBRARIES_REPO_BRANCH=msvc2013_debug
)
set BUILD_DATESTAMP=%date:~-4,4%%date:~-7,2%%date:~-10,2%
set BUILD_TIMESTAMP=%time:~-11,2%%time:~-8,2%
:: replace leading space with 0
set BUILD_TIMESTAMP=%BUILD_TIMESTAMP: =0%
set QT_LOG_FILE=!ROOT_DIR!\build_qt_!BUILD_DATESTAMP!-!BUILD_TIMESTAMP!.log
set WEBKIT_LOG_FILE=!ROOT_DIR!\build_webkit_!BUILD_DATESTAMP!_!BUILD_TIMESTAMP!.log
set PHANTOMJS_LOG_FILE=!ROOT_DIR!\build_phantomjs_!BUILD_DATESTAMP!_!BUILD_TIMESTAMP!.log
set MAKE_TOOL=nmake
echo:
echo Build type: !BUILD_TYPE!
call :build
ENDLOCAL
@exit /B 0
rem ========================================================================================================
:build
SETLOCAL EnableExtensions EnableDelayedExpansion
set _3RDPARTY=!ROOT_DIR!\src\qt\3rdparty
for %%X in (git.exe) do (set GIT_FOUND=%%~$PATH:X)
if defined GIT_FOUND (
echo.
echo GIT found. Getting 3rd party libraries.
if not exist !_3RDPARTY! call git clone -b !3RD_PARTY_LIBRARIES_REPO_BRANCH! !3RD_PARTY_LIBRARIES_REPO_URL! !_3RDPARTY!
) else (
ECHO.
CALL :exitB "Git is missing! Can't proceed. Please install Git."
GOTO :eof
)
:: prepare 3rdparty libraries
:: setup INCLUDE and LIB environment variables
:: OpenSSL
set OPENSSL_DIR=!_3RDPARTY!\openssl
set OPENSSL_LIB=!OPENSSL_DIR!\lib
set OPENSSL_INCLUDE=!OPENSSL_DIR!\include
:: ICU
set ICU_DIR=!_3RDPARTY!\libicu
set ICU_LIB=!ICU_DIR!\lib
set ICU_INCLUDE=!ICU_DIR!\include
:: libxml
set LIBXML_DIR=!_3RDPARTY!\libxml
set LIBXML_LIB=!LIBXML_DIR!\lib
set LIBXML_INCLUDE=!LIBXML_DIR!\include\libxml2
:: sqlite
set SQLITE3SRCDIR=!ROOT_DIR!\src\qt\qtbase\src\3rdparty\sqlite
set LIB=!OPENSSL_LIB!;!ICU_LIB!;!LIBXML_LIB!;%LIB%
set INCLUDE=!OPENSSL_INCLUDE!;!ICU_INCLUDE!;!LIBXML_INCLUDE!;%INCLUDE%
set PATH=!_3RDPARTY!\gnuwin32\bin;%PATH%
echo LIB: %LIB%
echo INCLUDE: %INCLUDE%
for %%X in (jom.exe) do (set JOMFOUND=%%~$PATH:X)
if defined JOMFOUND (
set MAKE_TOOL=jom
) else (
set MAKE_TOOL=nmake
)
pushd !ROOT_DIR!\src\qt
call preconfig.cmd !BUILD_TYPE! 2>&1 >> !QT_LOG_FILE!
popd
set PATH=!ROOT_DIR!\src\qt\qtbase\bin;%PATH%
for %%X in (qmake.exe) do (set QMAKE_FOUND=%%~$PATH:X)
if defined QMAKE_FOUND (
echo.
echo qmake found. Building QtWebkit
) else (
ECHO.
CALL :exitB "qmake.exe is missing! Can't proceed."
GOTO :eof
)
pushd !ROOT_DIR!\src\qt\qtwebkit
call qmake.exe
%MAKE_TOOL% %BUILD_TYPE% 2>&1 >> !WEBKIT_LOG_FILE!
popd
pushd !ROOT_DIR!\src
call qmake.exe
%MAKE_TOOL% %BUILD_TYPE% 2>&1 >> !PHANTOMJS_LOG_FILE!
popd
if EXIST !ROOT_DIR!\bin\phantomjs.exe (
echo.
echo Build has finished
echo.
) else (
echo:
echo Unable to find phantomjs.exe. Please, check log files:
echo Qt: !QT_LOG_FILE!
echo Webkit: !WEBKIT_LOG_FILE!
echo PhantomJS: !PHANTOMJS_LOG_FILE!
echo:
)
EXIT /b
rem ========================================================================================================
:: %1 an error message
:exitB
echo:
echo Error: %1
echo:
echo Contact vitaliy.slobodin@gmail.com
@exit /B 0

View File

@ -2,9 +2,6 @@
set -e set -e
QT_CFG=''
BUILD_CONFIRM=0
COMPILE_JOBS=1 COMPILE_JOBS=1
MAKEFLAGS_JOBS='' MAKEFLAGS_JOBS=''
@ -33,62 +30,53 @@ if [[ "$COMPILE_JOBS" -gt 8 ]]; then
COMPILE_JOBS=8 COMPILE_JOBS=8
fi fi
until [ -z "$1" ]; do SILENT=
until [[ -z "$1" ]]; do
case $1 in case $1 in
"--qt-config") (--qmake-args)
shift
QT_CFG=" $1"
shift;;
"--qmake-args")
shift shift
QMAKE_ARGS=$1 QMAKE_ARGS=$1
shift;; shift;;
"--jobs") (--jobs)
shift shift
COMPILE_JOBS=$1 COMPILE_JOBS=$1
shift;; shift;;
"--confirm") (--silent)
BUILD_CONFIRM=1 SILENT=silent
shift;; shift;;
"--help") "--help")
echo "Usage: $0 [--qt-config CONFIG] [--jobs NUM]" cat <<EOF
echo Usage: $0 [--jobs NUM]
echo " --confirm Silently confirm the build."
echo " --qt-config CONFIG Specify extra config options to be used when configuring Qt" --silent Produce less verbose output.
echo " --jobs NUM How many parallel compile jobs to use. Defaults to 4." --jobs NUM How many parallel compile jobs to use.
echo Defaults to the number of CPU cores you have,
with a maximum of 8.
EOF
exit 0 exit 0
;; ;;
*) *)
echo "Unrecognised option: $1" echo "Unrecognised option: $1" >&2
exit 1;; exit 1;;
esac esac
done done
UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
if [[ "$BUILD_CONFIRM" -eq 0 ]]; then echo "System architecture... ($UNAME_SYSTEM $UNAME_RELEASE $UNAME_MACHINE)"
cat << EOF
----------------------------------------
WARNING
----------------------------------------
Building PhantomJS from source takes a very long time, anywhere from 30 minutes export QMAKE=qmake
to several hours (depending on the machine configuration). It is recommended to # some Linux distros (e.g. Debian) allow you to parallel-install
use the premade binary packages on supported operating systems. # Qt4 and Qt5, using this environment variable to declare which
# one you want
export QT_SELECT=qt5
For details, please go the the web site: http://phantomjs.org/download.html. echo
echo "Building main PhantomJS application..."
EOF echo
$QMAKE $QMAKE_ARGS
echo "Do you want to continue (y/n)?"
read continue
if [[ "$continue" != "y" ]]; then
exit 1
fi
echo
echo
fi
cd src/qt && ./preconfig.sh --jobs $COMPILE_JOBS --qt-config "$QT_CFG" && cd ../..
src/qt/bin/qmake $QMAKE_ARGS
make -j$COMPILE_JOBS make -j$COMPILE_JOBS

View File

@ -1,7 +0,0 @@
system = require 'system'
if system.args.length is 1
console.log 'Try to pass some args when invoking this script!'
else
for arg, i in system.args
console.log i + ': ' + arg
phantom.exit()

View File

@ -1,20 +0,0 @@
{spawn, execFile} = require "child_process"
child = spawn "ls", ["-lF", "/rooot"]
child.stdout.on "data", (data) ->
console.log "spawnSTDOUT:", JSON.stringify data
child.stderr.on "data", (data) ->
console.log "spawnSTDERR:", JSON.stringify data
child.on "exit", (code) ->
console.log "spawnEXIT:", code
#child.kill "SIGKILL"
execFile "ls", ["-lF", "/usr"], null, (err, stdout, stderr) ->
console.log "execFileSTDOUT:", JSON.stringify stdout
console.log "execFileSTDERR:", JSON.stringify stderr
setTimeout (-> phantom.exit 0), 2000

View File

@ -1,46 +0,0 @@
page = require('webpage').create()
page.viewportSize = { width: 400, height : 400 }
page.content = '<html><body><canvas id="surface"></canvas></body></html>'
page.evaluate ->
el = document.getElementById 'surface'
context = el.getContext '2d'
width = window.innerWidth
height = window.innerHeight
cx = width / 2
cy = height / 2
radius = width / 2.3
i = 0
el.width = width
el.height = height
imageData = context.createImageData(width, height)
pixels = imageData.data
for y in [0...height]
for x in [0...width]
i = i + 4
rx = x - cx
ry = y - cy
d = rx * rx + ry * ry
if d < radius * radius
hue = 6 * (Math.atan2(ry, rx) + Math.PI) / (2 * Math.PI)
sat = Math.sqrt(d) / radius
g = Math.floor(hue)
f = hue - g
u = 255 * (1 - sat)
v = 255 * (1 - sat * f)
w = 255 * (1 - sat * (1 - f))
pixels[i] = [255, v, u, u, w, 255, 255][g]
pixels[i + 1] = [w, 255, 255, v, u, u, w][g]
pixels[i + 2] = [u, u, w, 255, 255, v, u][g]
pixels[i + 3] = 255
context.putImageData imageData, 0, 0
document.body.style.backgroundColor = 'white'
document.body.style.margin = '0px'
page.render('colorwheel.png')
phantom.exit()

View File

@ -1,8 +0,0 @@
t = 10
interval = setInterval ->
if t > 0
console.log t--
else
console.log 'BLAST OFF!'
phantom.exit()
, 1000

View File

@ -1,42 +0,0 @@
page = require('webpage').create()
system = require 'system'
page.onInitialized = ->
page.evaluate ->
userAgent = window.navigator.userAgent
platform = window.navigator.platform
window.navigator =
appCodeName: 'Mozilla'
appName: 'Netscape'
cookieEnabled: false
sniffed: false
window.navigator.__defineGetter__ 'userAgent', ->
window.navigator.sniffed = true
userAgent
window.navigator.__defineGetter__ 'platform', ->
window.navigator.sniffed = true
platform
if system.args.length is 1
console.log 'Usage: detectsniff.coffee <some URL>'
phantom.exit 1
else
address = system.args[1]
console.log 'Checking ' + address + '...'
page.open address, (status) ->
if status isnt 'success'
console.log 'FAIL to load the address'
phantom.exit()
else
window.setTimeout ->
sniffed = page.evaluate(->
navigator.sniffed
)
if sniffed
console.log 'The page tried to sniff the user agent.'
else
console.log 'The page did not try to sniff the user agent.'
phantom.exit()
, 1500

View File

@ -1,30 +0,0 @@
# Get driving direction using Google Directions API.
page = require('webpage').create()
system = require 'system'
if system.args.length < 3
console.log 'Usage: direction.coffee origin destination'
console.log 'Example: direction.coffee "San Diego" "Palo Alto"'
phantom.exit 1
else
origin = system.args[1]
dest = system.args[2]
page.open encodeURI('http://maps.googleapis.com/maps/api/directions/xml?origin=' + origin +
'&destination=' + dest + '&units=imperial&mode=driving&sensor=false'),
(status) ->
if status isnt 'success'
console.log 'Unable to access network'
else
steps = page.content.match(/<html_instructions>(.*)<\/html_instructions>/ig)
if not steps
console.log 'No data available for ' + origin + ' to ' + dest
else
for ins in steps
ins = ins.replace(/\&lt;/ig, '<').replace(/\&gt;/ig, '>')
ins = ins.replace(/\<div/ig, '\n<div')
ins = ins.replace(/<.*?>/g, '')
console.log(ins)
console.log ''
console.log page.content.match(/<copyrights>.*<\/copyrights>/ig).join('').replace(/<.*?>/g, '')
phantom.exit()

View File

@ -1,19 +0,0 @@
# echoToFile.coffee - Write in a given file all the parameters passed on the CLI
fs = require 'fs'
system = require 'system'
if system.args.length < 3
console.log "Usage: echoToFile.coffee DESTINATION_FILE <arguments to echo...>"
phantom.exit 1
else
content = ""
f = null
i = 2
while i < system.args.length
content += system.args[i] + (if i == system.args.length - 1 then "" else " ")
++i
try
fs.write system.args[1], content, "w"
catch e
console.log e
phantom.exit()

View File

@ -1,23 +0,0 @@
feature = undefined
supported = []
unsupported = []
phantom.injectJs "modernizr.js"
console.log "Detected features (using Modernizr " + Modernizr._version + "):"
for feature of Modernizr
if Modernizr.hasOwnProperty(feature)
if feature[0] isnt "_" and typeof Modernizr[feature] isnt "function" and feature isnt "input" and feature isnt "inputtypes"
if Modernizr[feature]
supported.push feature
else
unsupported.push feature
console.log ""
console.log "Supported:"
supported.forEach (e) ->
console.log " " + e
console.log ""
console.log "Not supported:"
unsupported.forEach (e) ->
console.log " " + e
phantom.exit()

View File

@ -1,8 +0,0 @@
fibs = [0, 1]
f = ->
console.log fibs[fibs.length - 1]
fibs.push fibs[fibs.length - 1] + fibs[fibs.length - 2]
if fibs.length > 10
window.clearInterval ticker
phantom.exit()
ticker = window.setInterval(f, 300)

View File

@ -1,33 +0,0 @@
# List following and followers from several accounts
users = [
'PhantomJS'
'ariyahidayat'
'detronizator'
'KDABQt'
'lfranchi'
'jonleighton'
'_jamesmgreene'
'Vitalliumm'
]
follow = (user, callback) ->
page = require('webpage').create()
page.open 'http://mobile.twitter.com/' + user, (status) ->
if status is 'fail'
console.log user + ': ?'
else
data = page.evaluate -> document.querySelector('div.profile td.stat.stat-last div.statnum').innerText;
console.log user + ': ' + data
page.close()
callback.apply()
process = () ->
if (users.length > 0)
user = users[0]
users.splice(0, 1)
follow(user, process)
else
phantom.exit()
process()

View File

@ -1,2 +0,0 @@
console.log 'Hello, world!'
phantom.exit()

View File

@ -1,20 +0,0 @@
# Upload an image to imagebin.org
page = require('webpage').create()
system = require 'system'
if system.args.length isnt 2
console.log 'Usage: imagebin.coffee filename'
phantom.exit 1
else
fname = system.args[1]
page.open 'http://imagebin.org/index.php?page=add', ->
page.uploadFile 'input[name=image]', fname
page.evaluate ->
document.querySelector('input[name=nickname]').value = 'phantom'
document.querySelector('input[name=disclaimer_agree]').click()
document.querySelector('form').submit()
window.setTimeout ->
phantom.exit()
, 3000

View File

@ -1,23 +0,0 @@
# Use 'page.injectJs()' to load the script itself in the Page context
if phantom?
page = require('webpage').create()
# Route "console.log()" calls from within the Page context to the main
# Phantom context (i.e. current "this")
page.onConsoleMessage = (msg) -> console.log(msg)
page.onAlert = (msg) -> console.log(msg)
console.log "* Script running in the Phantom context."
console.log "* Script will 'inject' itself in a page..."
page.open "about:blank", (status) ->
if status is "success"
if page.injectJs("injectme.coffee")
console.log "... done injecting itself!"
else
console.log "... fail! Check the $PWD?!"
phantom.exit()
else
alert "* Script running in the Page context."

View File

@ -1,13 +0,0 @@
# Give the estimated location based on the IP address.
window.cb = (data) ->
loc = data.city
if data.region_name.length > 0
loc = loc + ', ' + data.region_name
console.log 'IP address: ' + data.ip
console.log 'Estimated location: ' + loc
phantom.exit()
el = document.createElement 'script'
el.src = 'http://freegeoip.net/json/?callback=window.cb'
document.body.appendChild el

View File

@ -1,18 +0,0 @@
page = require('webpage').create()
system = require 'system'
if system.args.length is 1
console.log 'Usage: loadspeed.coffee <some URL>'
phantom.exit 1
else
t = Date.now()
address = system.args[1]
page.open address, (status) ->
if status isnt 'success'
console.log('FAIL to load the address')
else
t = Date.now() - t
console.log('Page title is ' + page.evaluate( (-> document.title) ))
console.log('Loading time ' + t + ' msec')
phantom.exit()

View File

@ -1,20 +0,0 @@
page = require("webpage").create()
system = require("system")
if system.args.length < 2
console.log "Usage: loadurlwithoutcss.js URL"
phantom.exit()
address = system.args[1]
page.onResourceRequested = (requestData, request) ->
if (/http:\/\/.+?\.css/g).test(requestData["url"]) or requestData["Content-Type"] is "text/css"
console.log "The url of the request is matching. Aborting: " + requestData["url"]
request.abort()
page.open address, (status) ->
if status is "success"
phantom.exit()
else
console.log "Unable to load the address!"
phantom.exit()

View File

@ -9,7 +9,7 @@ if (system.args.length < 2) {
var address = system.args[1]; var address = system.args[1];
page.onResourceRequested = function(requestData, request) { page.onResourceRequested = function(requestData, request) {
if ((/http:\/\/.+?\.css/gi).test(requestData['url']) || requestData['Content-Type'] == 'text/css') { if ((/http:\/\/.+?\.css/gi).test(requestData['url']) || requestData.headers['Content-Type'] == 'text/css') {
console.log('The url of the request is matching. Aborting: ' + requestData['url']); console.log('The url of the request is matching. Aborting: ' + requestData['url']);
request.abort(); request.abort();
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +0,0 @@
universe = require './universe'
universe.start()
console.log 'The answer is' + universe.answer
phantom.exit()

View File

@ -1,13 +0,0 @@
# List movies from kids-in-mind.com
window.cbfunc = (data) ->
globaldata = data
list = data.query.results.movie
for item in list
console.log item.title + ' [' + item.rating.MPAA.content + ']'
phantom.exit()
el = document.createElement 'script'
el.src =
"http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20movies.kids-in-mind&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys&callback=window.cbfunc"
document.body.appendChild el

View File

@ -1,18 +0,0 @@
page = require('webpage').create()
system = require 'system'
if system.args.length is 1
console.log 'Usage: netlog.coffee <some URL>'
phantom.exit 1
else
address = system.args[1]
page.onResourceRequested = (req) ->
console.log 'requested ' + JSON.stringify(req, undefined, 4)
page.onResourceReceived = (res) ->
console.log 'received ' + JSON.stringify(res, undefined, 4)
page.open address, (status) ->
if status isnt 'success'
console.log 'FAIL to load the address'
phantom.exit()

View File

@ -1,113 +0,0 @@
if not Date::toISOString
Date::toISOString = ->
pad = (n) ->
if n < 10 then '0' + n else n
ms = (n) ->
if n < 10 then '00' + n else (if n < 100 then '0' + n else n)
@getFullYear() + '-' +
pad(@getMonth() + 1) + '-' +
pad(@getDate()) + 'T' +
pad(@getHours()) + ':' +
pad(@getMinutes()) + ':' +
pad(@getSeconds()) + '.' +
ms(@getMilliseconds()) + 'Z'
createHAR = (address, title, startTime, resources) ->
entries = []
resources.forEach (resource) ->
request = resource.request
startReply = resource.startReply
endReply = resource.endReply
if not request or not startReply or not endReply
return
entries.push
startedDateTime: request.time.toISOString()
time: endReply.time - request.time
request:
method: request.method
url: request.url
httpVersion: 'HTTP/1.1'
cookies: []
headers: request.headers
queryString: []
headersSize: -1
bodySize: -1
response:
status: endReply.status
statusText: endReply.statusText
httpVersion: 'HTTP/1.1'
cookies: []
headers: endReply.headers
redirectURL: ''
headersSize: -1
bodySize: startReply.bodySize
content:
size: startReply.bodySize
mimeType: endReply.contentType
cache: {}
timings:
blocked: 0
dns: -1
connect: -1
send: 0
wait: startReply.time - request.time
receive: endReply.time - startReply.time
ssl: -1
pageref: address
log:
version: '1.2'
creator:
name: 'PhantomJS'
version: phantom.version.major + '.' + phantom.version.minor + '.' + phantom.version.patch
pages: [
startedDateTime: startTime.toISOString()
id: address
title: title
pageTimings:
onLoad: page.endTime - page.startTime
]
entries: entries
page = require('webpage').create()
system = require 'system'
if system.args.length is 1
console.log 'Usage: netsniff.coffee <some URL>'
phantom.exit 1
else
page.address = system.args[1]
page.resources = []
page.onLoadStarted = ->
page.startTime = new Date()
page.onResourceRequested = (req) ->
page.resources[req.id] =
request: req
startReply: null
endReply: null
page.onResourceReceived = (res) ->
if res.stage is 'start'
page.resources[res.id].startReply = res
if res.stage is 'end'
page.resources[res.id].endReply = res
page.open page.address, (status) ->
if status isnt 'success'
console.log 'FAIL to load the address'
else
page.endTime = new Date()
page.title = page.evaluate ->
document.title
har = createHAR page.address, page.title, page.startTime, page.resources
console.log JSON.stringify har, undefined, 4
phantom.exit()

View File

@ -129,6 +129,7 @@ if (system.args.length === 1) {
var har; var har;
if (status !== 'success') { if (status !== 'success') {
console.log('FAIL to load the address'); console.log('FAIL to load the address');
phantom.exit(1);
} else { } else {
page.endTime = new Date(); page.endTime = new Date();
page.title = page.evaluate(function () { page.title = page.evaluate(function () {
@ -136,7 +137,7 @@ if (system.args.length === 1) {
}); });
har = createHAR(page.address, page.title, page.startTime, page.resources); har = createHAR(page.address, page.title, page.startTime, page.resources);
console.log(JSON.stringify(har, undefined, 4)); console.log(JSON.stringify(har, undefined, 4));
}
phantom.exit(); phantom.exit();
}
}); });
} }

View File

@ -0,0 +1,24 @@
var page = require('webpage').create(),
system = require('system'),
host, port, address;
if (system.args.length < 4) {
console.log('Usage: openurlwithproxy.js <proxyHost> <proxyPort> <URL>');
phantom.exit(1);
} else {
host = system.args[1];
port = system.args[2];
address = system.args[3];
phantom.setProxy(host, port, 'manual', '', '');
page.open(address, function (status) {
if (status !== 'success') {
console.log('FAIL to load the address "' +
address + '" using proxy "' + host + ':' + port + '"');
} else {
console.log('Page title is ' + page.evaluate(function () {
return document.title;
}));
}
phantom.exit();
});
}

View File

@ -1,12 +0,0 @@
helloWorld = () -> console.log phantom.outputEncoding + ": こんにちは、世界!"
console.log "Using default encoding..."
helloWorld()
console.log "\nUsing other encodings..."
for enc in ["euc-jp", "sjis", "utf8", "System"]
do (enc) ->
phantom.outputEncoding = enc
helloWorld()
phantom.exit()

View File

@ -1,132 +0,0 @@
# The purpose of this is to show how and when events fire, considering 5 steps
# happening as follows:
#
# 1. Load URL
# 2. Load same URL, but adding an internal FRAGMENT to it
# 3. Click on an internal Link, that points to another internal FRAGMENT
# 4. Click on an external Link, that will send the page somewhere else
# 5. Close page
#
# Take particular care when going through the output, to understand when
# things happen (and in which order). Particularly, notice what DOESN'T
# happen during step 3.
#
# If invoked with "-v" it will print out the Page Resources as they are
# Requested and Received.
#
# NOTE.1: The "onConsoleMessage/onAlert/onPrompt/onConfirm" events are
# registered but not used here. This is left for you to have fun with.
# NOTE.2: This script is not here to teach you ANY JavaScript. It's aweful!
# NOTE.3: Main audience for this are people new to PhantomJS.
printArgs = ->
i = undefined
ilen = undefined
i = 0
ilen = arguments_.length
while i < ilen
console.log " arguments[" + i + "] = " + JSON.stringify(arguments_[i])
++i
console.log ""
sys = require("system")
page = require("webpage").create()
logResources = false
step1url = "http://en.wikipedia.org/wiki/DOM_events"
step2url = "http://en.wikipedia.org/wiki/DOM_events#Event_flow"
logResources = true if sys.args.length > 1 and sys.args[1] is "-v"
#//////////////////////////////////////////////////////////////////////////////
page.onInitialized = ->
console.log "page.onInitialized"
printArgs.apply this, arguments_
page.onLoadStarted = ->
console.log "page.onLoadStarted"
printArgs.apply this, arguments_
page.onLoadFinished = ->
console.log "page.onLoadFinished"
printArgs.apply this, arguments_
page.onUrlChanged = ->
console.log "page.onUrlChanged"
printArgs.apply this, arguments_
page.onNavigationRequested = ->
console.log "page.onNavigationRequested"
printArgs.apply this, arguments_
if logResources is true
page.onResourceRequested = ->
console.log "page.onResourceRequested"
printArgs.apply this, arguments_
page.onResourceReceived = ->
console.log "page.onResourceReceived"
printArgs.apply this, arguments_
page.onClosing = ->
console.log "page.onClosing"
printArgs.apply this, arguments_
# window.console.log(msg);
page.onConsoleMessage = ->
console.log "page.onConsoleMessage"
printArgs.apply this, arguments_
# window.alert(msg);
page.onAlert = ->
console.log "page.onAlert"
printArgs.apply this, arguments_
# var confirmed = window.confirm(msg);
page.onConfirm = ->
console.log "page.onConfirm"
printArgs.apply this, arguments_
# var user_value = window.prompt(msg, default_value);
page.onPrompt = ->
console.log "page.onPrompt"
printArgs.apply this, arguments_
#//////////////////////////////////////////////////////////////////////////////
setTimeout (->
console.log ""
console.log "### STEP 1: Load '" + step1url + "'"
page.open step1url
), 0
setTimeout (->
console.log ""
console.log "### STEP 2: Load '" + step2url + "' (load same URL plus FRAGMENT)"
page.open step2url
), 5000
setTimeout (->
console.log ""
console.log "### STEP 3: Click on page internal link (aka FRAGMENT)"
page.evaluate ->
ev = document.createEvent("MouseEvents")
ev.initEvent "click", true, true
document.querySelector("a[href='#Event_object']").dispatchEvent ev
), 10000
setTimeout (->
console.log ""
console.log "### STEP 4: Click on page external link"
page.evaluate ->
ev = document.createEvent("MouseEvents")
ev.initEvent "click", true, true
document.querySelector("a[title='JavaScript']").dispatchEvent ev
), 15000
setTimeout (->
console.log ""
console.log "### STEP 5: Close page and shutdown (with a delay)"
page.close()
setTimeout (->
phantom.exit()
), 100
), 20000

View File

@ -59,6 +59,10 @@ page.onNavigationRequested = function() {
console.log("page.onNavigationRequested"); console.log("page.onNavigationRequested");
printArgs.apply(this, arguments); printArgs.apply(this, arguments);
}; };
page.onRepaintRequested = function() {
console.log("page.onRepaintRequested");
printArgs.apply(this, arguments);
};
if (logResources === true) { if (logResources === true) {
page.onResourceRequested = function() { page.onResourceRequested = function() {

View File

@ -1,16 +0,0 @@
p = require("webpage").create()
p.onConsoleMessage = (msg) ->
console.log msg
# Calls to "callPhantom" within the page 'p' arrive here
p.onCallback = (msg) ->
console.log "Received by the 'phantom' main context: " + msg
"Hello there, I'm coming to you from the 'phantom' context instead"
p.evaluate ->
# Return-value of the "onCallback" handler arrive here
callbackResponse = window.callPhantom "Hello, I'm coming to you from the 'page' context"
console.log "Received by the 'page' context: " + callbackResponse
phantom.exit()

View File

@ -1,13 +0,0 @@
# Read the Phantom webpage '#intro' element text using jQuery and "includeJs"
page = require('webpage').create()
page.onConsoleMessage = (msg) -> console.log msg
page.open "http://www.phantomjs.org", (status) ->
if status is "success"
page.includeJs "http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js", ->
page.evaluate ->
console.log "$(\"#intro\").text() -> " + $("#intro").text()
phantom.exit()

View File

@ -10,7 +10,7 @@ page.open("http://www.phantomjs.org", function(status) {
if ( status === "success" ) { if ( status === "success" ) {
page.includeJs("http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js", function() { page.includeJs("http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js", function() {
page.evaluate(function() { page.evaluate(function() {
console.log("$(\"#intro\").text() -> " + $("#intro").text()); console.log("$(\".explanation\").text() -> " + $(".explanation").text());
}); });
phantom.exit(); phantom.exit();
}); });

View File

@ -1,18 +0,0 @@
# Find pizza in Mountain View using Yelp
page = require('webpage').create()
url = 'http://lite.yelp.com/search?find_desc=pizza&find_loc=94040&find_submit=Search'
page.open url,
(status) ->
if status isnt 'success'
console.log 'Unable to access network'
else
results = page.evaluate ->
pizza = []
list = document.querySelectorAll 'address'
for item in list
pizza.push(item.innerText)
return pizza
console.log results.join('\n')
phantom.exit()

View File

@ -1,12 +0,0 @@
# Example using HTTP POST operation
page = require('webpage').create()
server = 'http://posttestserver.com/post.php?dump'
data = 'universe=expanding&answer=42'
page.open server, 'post', data, (status) ->
if status isnt 'success'
console.log 'Unable to post!'
else
console.log page.content
phantom.exit()

18
examples/postjson.js Normal file
View File

@ -0,0 +1,18 @@
// Example using HTTP POST operation
var page = require('webpage').create(),
server = 'http://posttestserver.com/post.php?dump',
data = '{"universe": "expanding", "answer": 42}';
var headers = {
"Content-Type": "application/json"
}
page.open(server, 'post', data, headers, function (status) {
if (status !== 'success') {
console.log('Unable to post!');
} else {
console.log(page.content);
}
phantom.exit();
});

View File

@ -1,25 +0,0 @@
# Example using HTTP POST operation
page = require("webpage").create()
server = require("webserver").create()
system = require("system")
data = "universe=expanding&answer=42"
if system.args.length isnt 2
console.log "Usage: postserver.js <portnumber>"
phantom.exit 1
port = system.args[1]
service = server.listen(port, (request, response) ->
console.log "Request received at " + new Date()
response.statusCode = 200
response.headers =
Cache: "no-cache"
"Content-Type": "text/plain;charset=utf-8"
response.write JSON.stringify(request, null, 4)
response.close()
)
page.open "http://localhost:" + port + "/", "post", data, (status) ->
if status isnt "success"
console.log "Unable to post!"
else
console.log page.plainText
phantom.exit()

View File

@ -1,6 +0,0 @@
system = require("system")
env = system.env
key = undefined
for key of env
console.log key + "=" + env[key] if env.hasOwnProperty(key)
phantom.exit()

View File

@ -1,88 +0,0 @@
someCallback = (pageNum, numPages) ->
"<h1> someCallback: " + pageNum + " / " + numPages + "</h1>"
page = require("webpage").create()
system = require("system")
if system.args.length < 3
console.log "Usage: printheaderfooter.js URL filename"
phantom.exit 1
else
address = system.args[1]
output = system.args[2]
page.viewportSize =
width: 600
height: 600
page.paperSize =
format: "A4"
margin: "1cm"
# default header/footer for pages that don't have custom overwrites (see below)
header:
height: "1cm"
contents: phantom.callback((pageNum, numPages) ->
return "" if pageNum is 1
"<h1>Header <span style='float:right'>" + pageNum + " / " + numPages + "</span></h1>"
)
footer:
height: "1cm"
contents: phantom.callback((pageNum, numPages) ->
return "" if pageNum is numPages
"<h1>Footer <span style='float:right'>" + pageNum + " / " + numPages + "</span></h1>"
)
page.open address, (status) ->
if status isnt "success"
console.log "Unable to load the address!"
else
# check whether the loaded page overwrites the header/footer setting,
# i.e. whether a PhantomJSPriting object exists. Use that then instead
# of our defaults above.
#
# example:
# <html>
# <head>
# <script type="text/javascript">
# var PhantomJSPrinting = {
# header: {
# height: "1cm",
# contents: function(pageNum, numPages) { return pageNum + "/" + numPages; }
# },
# footer: {
# height: "1cm",
# contents: function(pageNum, numPages) { return pageNum + "/" + numPages; }
# }
# };
# </script>
# </head>
# <body><h1>asdfadsf</h1><p>asdfadsfycvx</p></body>
# </html>
#
if page.evaluate(->
typeof PhantomJSPrinting is "object"
)
paperSize = page.paperSize
paperSize.header.height = page.evaluate(->
PhantomJSPrinting.header.height
)
paperSize.header.contents = phantom.callback((pageNum, numPages) ->
page.evaluate ((pageNum, numPages) ->
PhantomJSPrinting.header.contents pageNum, numPages
), pageNum, numPages
)
paperSize.footer.height = page.evaluate(->
PhantomJSPrinting.footer.height
)
paperSize.footer.contents = phantom.callback((pageNum, numPages) ->
page.evaluate ((pageNum, numPages) ->
PhantomJSPrinting.footer.contents pageNum, numPages
), pageNum, numPages
)
page.paperSize = paperSize
console.log page.paperSize.header.height
console.log page.paperSize.footer.height
window.setTimeout (->
page.render output
phantom.exit()
), 200

View File

@ -1,33 +0,0 @@
page = require("webpage").create()
system = require("system")
if system.args.length < 7
console.log "Usage: printmargins.js URL filename LEFT TOP RIGHT BOTTOM"
console.log " margin examples: \"1cm\", \"10px\", \"7mm\", \"5in\""
phantom.exit 1
else
address = system.args[1]
output = system.args[2]
marginLeft = system.args[3]
marginTop = system.args[4]
marginRight = system.args[5]
marginBottom = system.args[6]
page.viewportSize =
width: 600
height: 600
page.paperSize =
format: "A4"
margin:
left: marginLeft
top: marginTop
right: marginRight
bottom: marginBottom
page.open address, (status) ->
if status isnt "success"
console.log "Unable to load the address!"
else
window.setTimeout (->
page.render output
phantom.exit()
), 200

View File

@ -1,23 +0,0 @@
page = require('webpage').create()
system = require 'system'
if system.args.length < 3 or system.args.length > 4
console.log 'Usage: rasterize.coffee URL filename [paperwidth*paperheight|paperformat]'
console.log ' paper (pdf output) examples: "5in*7.5in", "10cm*20cm", "A4", "Letter"'
phantom.exit 1
else
address = system.args[1]
output = system.args[2]
page.viewportSize = { width: 600, height: 600 }
if system.args.length is 4 and system.args[2].substr(-4) is ".pdf"
size = system.args[3].split '*'
if size.length is 2
page.paperSize = { width: size[0], height: size[1], border: '0px' }
else
page.paperSize = { format: system.args[3], orientation: 'portrait', border: '1cm' }
page.open address, (status) ->
if status isnt 'success'
console.log 'Unable to load the address!'
phantom.exit()
else
window.setTimeout (-> page.render output; phantom.exit()), 200

View File

@ -5,6 +5,8 @@ var page = require('webpage').create(),
if (system.args.length < 3 || system.args.length > 5) { if (system.args.length < 3 || system.args.length > 5) {
console.log('Usage: rasterize.js URL filename [paperwidth*paperheight|paperformat] [zoom]'); console.log('Usage: rasterize.js URL filename [paperwidth*paperheight|paperformat] [zoom]');
console.log(' paper (pdf output) examples: "5in*7.5in", "10cm*20cm", "A4", "Letter"'); console.log(' paper (pdf output) examples: "5in*7.5in", "10cm*20cm", "A4", "Letter"');
console.log(' image (png/jpg output) examples: "1920px" entire page, window width 1920px');
console.log(' "800px*600px" window, clipped to 800x600');
phantom.exit(1); phantom.exit(1);
} else { } else {
address = system.args[1]; address = system.args[1];
@ -14,6 +16,20 @@ if (system.args.length < 3 || system.args.length > 5) {
size = system.args[3].split('*'); size = system.args[3].split('*');
page.paperSize = size.length === 2 ? { width: size[0], height: size[1], margin: '0px' } page.paperSize = size.length === 2 ? { width: size[0], height: size[1], margin: '0px' }
: { format: system.args[3], orientation: 'portrait', margin: '1cm' }; : { format: system.args[3], orientation: 'portrait', margin: '1cm' };
} else if (system.args.length > 3 && system.args[3].substr(-2) === "px") {
size = system.args[3].split('*');
if (size.length === 2) {
pageWidth = parseInt(size[0], 10);
pageHeight = parseInt(size[1], 10);
page.viewportSize = { width: pageWidth, height: pageHeight };
page.clipRect = { top: 0, left: 0, width: pageWidth, height: pageHeight };
} else {
console.log("size:", system.args[3]);
pageWidth = parseInt(system.args[3], 10);
pageHeight = parseInt(pageWidth * 3/4, 10); // it's as good an assumption as any
console.log ("pageHeight:",pageHeight);
page.viewportSize = { width: pageWidth, height: pageHeight };
}
} }
if (system.args.length > 4) { if (system.args.length > 4) {
page.zoomFactor = system.args[4]; page.zoomFactor = system.args[4];
@ -21,7 +37,7 @@ if (system.args.length < 3 || system.args.length > 5) {
page.open(address, function (status) { page.open(address, function (status) {
if (status !== 'success') { if (status !== 'success') {
console.log('Unable to load the address!'); console.log('Unable to load the address!');
phantom.exit(); phantom.exit(1);
} else { } else {
window.setTimeout(function () { window.setTimeout(function () {
page.render(output); page.render(output);

View File

@ -1,60 +0,0 @@
# Render Multiple URLs to file
system = require("system")
# Render given urls
# @param array of URLs to render
# @param callbackPerUrl Function called after finishing each URL, including the last URL
# @param callbackFinal Function called after finishing everything
RenderUrlsToFile = (urls, callbackPerUrl, callbackFinal) ->
urlIndex = 0 # only for easy file naming
webpage = require("webpage")
page = null
getFilename = ->
"rendermulti-" + urlIndex + ".png"
next = (status, url, file) ->
page.close()
callbackPerUrl status, url, file
retrieve()
retrieve = ->
if urls.length > 0
url = urls.shift()
urlIndex++
page = webpage.create()
page.viewportSize =
width: 800
height: 600
page.settings.userAgent = "Phantom.js bot"
page.open "http://" + url, (status) ->
file = getFilename()
if status is "success"
window.setTimeout (->
page.render file
next status, url, file
), 200
else
next status, url, file
else
callbackFinal()
retrieve()
arrayOfUrls = null
if system.args.length > 1
arrayOfUrls = Array::slice.call(system.args, 1)
else
# Default (no args passed)
console.log "Usage: phantomjs render_multi_url.js [domain.name1, domain.name2, ...]"
arrayOfUrls = ["www.google.com", "www.bbc.co.uk", "www.phantomjs.org"]
RenderUrlsToFile arrayOfUrls, ((status, url, file) ->
if status isnt "success"
console.log "Unable to render '" + url + "'"
else
console.log "Rendered '" + url + "' at '" + file + "'"
), ->
phantom.exit()

View File

@ -1,61 +0,0 @@
system = require 'system'
##
# Wait until the test condition is true or a timeout occurs. Useful for waiting
# on a server response or for a ui change (fadeIn, etc.) to occur.
#
# @param testFx javascript condition that evaluates to a boolean,
# it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
# as a callback function.
# @param onReady what to do when testFx condition is fulfilled,
# it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
# as a callback function.
# @param timeOutMillis the max amount of time to wait. If not specified, 3 sec is used.
##
waitFor = (testFx, onReady, timeOutMillis=3000) ->
start = new Date().getTime()
condition = false
f = ->
if (new Date().getTime() - start < timeOutMillis) and not condition
# If not time-out yet and condition not yet fulfilled
condition = (if typeof testFx is 'string' then eval testFx else testFx()) #< defensive code
else
if not condition
# If condition still not fulfilled (timeout but condition is 'false')
console.log "'waitFor()' timeout"
phantom.exit 1
else
# Condition fulfilled (timeout and/or condition is 'true')
console.log "'waitFor()' finished in #{new Date().getTime() - start}ms."
if typeof onReady is 'string' then eval onReady else onReady() #< Do what it's supposed to do once the condition is fulfilled
clearInterval interval #< Stop this interval
interval = setInterval f, 100 #< repeat check every 100ms
if system.args.length isnt 2
console.log 'Usage: run-jasmine.coffee URL'
phantom.exit 1
page = require('webpage').create()
# Route "console.log()" calls from within the Page context to the main Phantom context (i.e. current "this")
page.onConsoleMessage = (msg) ->
console.log msg
page.open system.args[1], (status) ->
if status isnt 'success'
console.log 'Unable to access network'
phantom.exit()
else
waitFor ->
page.evaluate ->
if document.body.querySelector '.finished-at'
return true
return false
, ->
page.evaluate ->
console.log document.body.querySelector('.description').innerText
list = document.body.querySelectorAll('.failed > .description, .failed > .messages > .resultMessage')
for el in list
console.log el.innerText
phantom.exit()

View File

@ -50,8 +50,8 @@ page.onConsoleMessage = function(msg) {
page.open(system.args[1], function(status){ page.open(system.args[1], function(status){
if (status !== "success") { if (status !== "success") {
console.log("Unable to access network"); console.log("Unable to open " + system.args[1]);
phantom.exit(); phantom.exit(1);
} else { } else {
waitFor(function(){ waitFor(function(){
return page.evaluate(function(){ return page.evaluate(function(){
@ -59,6 +59,7 @@ page.open(system.args[1], function(status){
}); });
}, function(){ }, function(){
var exitCode = page.evaluate(function(){ var exitCode = page.evaluate(function(){
try {
console.log(''); console.log('');
console.log(document.body.querySelector('.description').innerText); console.log(document.body.querySelector('.description').innerText);
var list = document.body.querySelectorAll('.results > #details > .specDetail.failed'); var list = document.body.querySelectorAll('.results > #details > .specDetail.failed');
@ -79,6 +80,10 @@ page.open(system.args[1], function(status){
console.log(document.body.querySelector('.alert > .passingAlert.bar').innerText); console.log(document.body.querySelector('.alert > .passingAlert.bar').innerText);
return 0; return 0;
} }
} catch (ex) {
console.log(ex);
return 1;
}
}); });
phantom.exit(exitCode); phantom.exit(exitCode);
}); });

92
examples/run-jasmine2.js Normal file
View File

@ -0,0 +1,92 @@
var system = require('system');
/**
* Wait until the test condition is true or a timeout occurs. Useful for waiting
* on a server response or for a ui change (fadeIn, etc.) to occur.
*
* @param testFx javascript condition that evaluates to a boolean,
* it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
* as a callback function.
* @param onReady what to do when testFx condition is fulfilled,
* it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
* as a callback function.
* @param timeOutMillis the max amount of time to wait. If not specified, 3 sec is used.
*/
function waitFor(testFx, onReady, timeOutMillis) {
var maxtimeOutMillis = timeOutMillis ? timeOutMillis : 3001, //< Default Max Timeout is 3s
start = new Date().getTime(),
condition = false,
interval = setInterval(function() {
if ( (new Date().getTime() - start < maxtimeOutMillis) && !condition ) {
// If not time-out yet and condition not yet fulfilled
condition = (typeof(testFx) === "string" ? eval(testFx) : testFx()); //< defensive code
} else {
if(!condition) {
// If condition still not fulfilled (timeout but condition is 'false')
console.log("'waitFor()' timeout");
phantom.exit(1);
} else {
// Condition fulfilled (timeout and/or condition is 'true')
console.log("'waitFor()' finished in " + (new Date().getTime() - start) + "ms.");
typeof(onReady) === "string" ? eval(onReady) : onReady(); //< Do what it's supposed to do once the condition is fulfilled
clearInterval(interval); //< Stop this interval
}
}
}, 100); //< repeat check every 100ms
};
if (system.args.length !== 2) {
console.log('Usage: run-jasmine.js URL');
phantom.exit(1);
}
var page = require('webpage').create();
// Route "console.log()" calls from within the Page context to the main Phantom context (i.e. current "this")
page.onConsoleMessage = function(msg) {
console.log(msg);
};
page.open(system.args[1], function(status){
if (status !== "success") {
console.log("Unable to access network");
phantom.exit();
} else {
waitFor(function(){
return page.evaluate(function(){
return document.body.querySelector('.symbolSummary .pending') === null
});
}, function(){
var exitCode = page.evaluate(function(){
console.log('');
var el = document.body.querySelector('.banner');
var banner = el.querySelector('.title').innerText + " " +
el.querySelector('.version').innerText + " " +
el.querySelector('.duration').innerText;
console.log(banner);
var list = document.body.querySelectorAll('.results > .failures > .spec-detail.failed');
if (list && list.length > 0) {
console.log('');
console.log(list.length + ' test(s) FAILED:');
for (i = 0; i < list.length; ++i) {
var el = list[i],
desc = el.querySelector('.description'),
msg = el.querySelector('.messages > .result-message');
console.log('');
console.log(desc.innerText);
console.log(msg.innerText);
console.log('');
}
return 1;
} else {
console.log(document.body.querySelector('.alert > .bar.passed').innerText);
return 0;
}
});
phantom.exit(exitCode);
});
}
});

View File

@ -1,64 +0,0 @@
system = require 'system'
##
# Wait until the test condition is true or a timeout occurs. Useful for waiting
# on a server response or for a ui change (fadeIn, etc.) to occur.
#
# @param testFx javascript condition that evaluates to a boolean,
# it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
# as a callback function.
# @param onReady what to do when testFx condition is fulfilled,
# it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
# as a callback function.
# @param timeOutMillis the max amount of time to wait. If not specified, 3 sec is used.
##
waitFor = (testFx, onReady, timeOutMillis=3000) ->
start = new Date().getTime()
condition = false
f = ->
if (new Date().getTime() - start < timeOutMillis) and not condition
# If not time-out yet and condition not yet fulfilled
condition = (if typeof testFx is 'string' then eval testFx else testFx()) #< defensive code
else
if not condition
# If condition still not fulfilled (timeout but condition is 'false')
console.log "'waitFor()' timeout"
phantom.exit 1
else
# Condition fulfilled (timeout and/or condition is 'true')
console.log "'waitFor()' finished in #{new Date().getTime() - start}ms."
if typeof onReady is 'string' then eval onReady else onReady() #< Do what it's supposed to do once the condition is fulfilled
clearInterval interval #< Stop this interval
interval = setInterval f, 100 #< repeat check every 100ms
if system.args.length isnt 2
console.log 'Usage: run-qunit.coffee URL'
phantom.exit 1
page = require('webpage').create()
# Route "console.log()" calls from within the Page context to the main Phantom context (i.e. current "this")
page.onConsoleMessage = (msg) ->
console.log msg
page.open system.args[1], (status) ->
if status isnt 'success'
console.log 'Unable to access network'
phantom.exit 1
else
waitFor ->
page.evaluate ->
el = document.getElementById 'qunit-testresult'
if el and el.innerText.match 'completed'
return true
return false
, ->
failedNum = page.evaluate ->
el = document.getElementById 'qunit-testresult'
console.log el.innerText
try
return el.getElementsByClassName('failed')[0].innerHTML
catch e
return 10000
phantom.exit if parseInt(failedNum, 10) > 0 then 1 else 0

View File

@ -1,16 +0,0 @@
# List all the files in a Tree of Directories
system = require 'system'
if system.args.length != 2
console.log "Usage: phantomjs scandir.coffee DIRECTORY_TO_SCAN"
phantom.exit 1
scanDirectory = (path) ->
fs = require 'fs'
if fs.exists(path) and fs.isFile(path)
console.log path
else if fs.isDirectory(path)
fs.list(path).forEach (e) ->
scanDirectory path + "/" + e if e != "." and e != ".."
scanDirectory system.args[1]
phantom.exit()

View File

@ -1,17 +0,0 @@
# Show BBC seasonal food list.
window.cbfunc = (data) ->
list = data.query.results.results.result
names = ['January', 'February', 'March',
'April', 'May', 'June',
'July', 'August', 'September',
'October', 'November', 'December']
for item in list
console.log [item.name.replace(/\s/ig, ' '), ':',
names[item.atItsBestUntil], 'to',
names[item.atItsBestFrom]].join(' ')
phantom.exit()
el = document.createElement 'script'
el.src = 'http://query.yahooapis.com/v1/public/yql?q=SELECT%20*%20FROM%20bbc.goodfood.seasonal%3B&format=json&diagnostics=true&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys&callback=window.cbfunc'
document.body.appendChild el

View File

@ -1,45 +0,0 @@
page = require("webpage").create()
server = require("webserver").create()
system = require("system")
host = undefined
port = undefined
if system.args.length isnt 2
console.log "Usage: server.js <some port>"
phantom.exit 1
else
port = system.args[1]
listening = server.listen(port, (request, response) ->
console.log "GOT HTTP REQUEST"
console.log JSON.stringify(request, null, 4)
# we set the headers here
response.statusCode = 200
response.headers =
Cache: "no-cache"
"Content-Type": "text/html"
# this is also possible:
response.setHeader "foo", "bar"
# now we write the body
# note: the headers above will now be sent implictly
response.write "<html><head><title>YES!</title></head>"
# note: writeBody can be called multiple times
response.write "<body><p>pretty cool :)</body></html>"
response.close()
)
unless listening
console.log "could not create web server listening on port " + port
phantom.exit()
url = "http://localhost:" + port + "/foo/bar.php?asdf=true"
console.log "SENDING REQUEST TO:"
console.log url
page.open url, (status) ->
if status isnt "success"
console.log "FAIL to load the address"
else
console.log "GOT REPLY FROM SERVER:"
console.log page.content
phantom.exit()

View File

@ -1,32 +0,0 @@
port = undefined
server = undefined
service = undefined
system = require("system")
if system.args.length isnt 2
console.log "Usage: serverkeepalive.js <portnumber>"
phantom.exit 1
else
port = system.args[1]
server = require("webserver").create()
service = server.listen(port,
keepAlive: true
, (request, response) ->
console.log "Request at " + new Date()
console.log JSON.stringify(request, null, 4)
body = JSON.stringify(request, null, 4)
response.statusCode = 200
response.headers =
Cache: "no-cache"
"Content-Type": "text/plain"
Connection: "Keep-Alive"
"Keep-Alive": "timeout=5, max=100"
"Content-Length": body.length
response.write body
response.close()
)
if service
console.log "Web server running on port " + port
else
console.log "Error: Could not create web server listening on port " + port
phantom.exit()

View File

@ -1,38 +0,0 @@
system = require 'system'
if system.args.length is 1
console.log "Usage: simpleserver.coffee <portnumber>"
phantom.exit 1
else
port = system.args[1]
server = require("webserver").create()
service = server.listen(port, (request, response) ->
console.log "Request at " + new Date()
console.log JSON.stringify(request, null, 4)
response.statusCode = 200
response.headers =
Cache: "no-cache"
"Content-Type": "text/html"
response.write "<html>"
response.write "<head>"
response.write "<title>Hello, world!</title>"
response.write "</head>"
response.write "<body>"
response.write "<p>This is from PhantomJS web server.</p>"
response.write "<p>Request data:</p>"
response.write "<pre>"
response.write JSON.stringify(request, null, 4)
response.write "</pre>"
response.write "</body>"
response.write "</html>"
response.close()
)
if service
console.log "Web server running on port " + port
else
console.log "Error: Could not create web server listening on port " + port
phantom.exit()

View File

@ -1,20 +0,0 @@
###
Sort integers from the command line in a very ridiculous way: leveraging timeouts :P
###
system = require 'system'
if system.args.length < 2
console.log "Usage: phantomjs sleepsort.coffee PUT YOUR INTEGERS HERE SEPARATED BY SPACES"
phantom.exit 1
else
sortedCount = 0
args = Array.prototype.slice.call(system.args, 1)
for int in args
setTimeout (do (int) ->
->
console.log int
++sortedCount
phantom.exit() if sortedCount is args.length),
int

View File

@ -15,11 +15,11 @@ function sleepSort(array, callback) {
} }
} }
if ( system.args < 2 ) { if ( system.args.length < 2 ) {
console.log("Usage: phantomjs sleepsort.js PUT YOUR INTEGERS HERE SEPARATED BY SPACES"); console.log("Usage: phantomjs sleepsort.js PUT YOUR INTEGERS HERE SEPARATED BY SPACES");
phantom.exit(1); phantom.exit(1);
} else { } else {
sleepSort(Array.prototype.slice.call(system.args, 1), function() { sleepSort(system.args.slice(1), function() {
phantom.exit(); phantom.exit();
}); });
} }

View File

@ -1,18 +0,0 @@
system = require 'system'
system.stdout.write 'Hello, system.stdout.write!'
system.stdout.writeLine '\nHello, system.stdout.writeLine!'
system.stderr.write 'Hello, system.stderr.write!'
system.stderr.writeLine '\nHello, system.stderr.writeLine!'
system.stdout.writeLine 'system.stdin.readLine(): '
line = system.stdin.readLine()
system.stdout.writeLine JSON.stringify line
# This is essentially a `readAll`
system.stdout.writeLine 'system.stdin.read(5): (ctrl+D to end)'
input = system.stdin.read 5
system.stdout.writeLine JSON.stringify input
phantom.exit 0

View File

@ -1,17 +0,0 @@
page = require('webpage').create()
page.viewportSize = { width: 320, height: 480 }
page.open 'http://news.google.com/news/i/section?&topic=t',
(status) ->
if status isnt 'success'
console.log 'Unable to access the network!'
else
page.evaluate ->
body = document.body
body.style.backgroundColor = '#fff'
body.querySelector('div#title-block').style.display = 'none'
body.querySelector('form#edition-picker-form')
.parentElement.parentElement.style.display = 'none'
page.render 'technews.png'
phantom.exit()

View File

@ -1,31 +0,0 @@
# Get twitter status for given account (or for the default one, "PhantomJS")
page = require('webpage').create()
system = require 'system'
twitterId = 'PhantomJS' #< default value
# Route "console.log()" calls from within the Page context to the main Phantom context (i.e. current "this")
page.onConsoleMessage = (msg) ->
console.log msg
# Print usage message, if no twitter ID is passed
if system.args.length < 2
console.log 'Usage: tweets.coffee [twitter ID]'
else
twitterId = system.args[1]
# Heading
console.log "*** Latest tweets from @#{twitterId} ***\n"
# Open Twitter Mobile and, onPageLoad, do...
page.open encodeURI("http://mobile.twitter.com/#{twitterId}"), (status) ->
# Check for page load success
if status isnt 'success'
console.log 'Unable to access network'
else
# Execute some DOM inspection within the page context
page.evaluate ->
list = document.querySelectorAll 'div.tweet-text'
for i, j in list
console.log "#{j + 1}: #{i.innerText}"
phantom.exit()

View File

@ -1,18 +0,0 @@
# Modify global object at the page initialization.
# In this example, effectively Math.random() always returns 0.42.
page = require('webpage').create()
page.onInitialized = ->
page.evaluate ->
Math.random = ->
42 / 100
page.open "http://ariya.github.com/js/random/", (status) ->
if status != "success"
console.log "Network error."
else
console.log page.evaluate(->
document.getElementById("numbers").textContent
)
phantom.exit()

View File

@ -1,11 +0,0 @@
page = require('webpage').create()
console.log 'The default user agent is ' + page.settings.userAgent
page.settings.userAgent = 'SpecialAgent'
page.open 'http://www.httpuseragent.org', (status) ->
if status isnt 'success'
console.log 'Unable to access network'
else
console.log page.evaluate -> document.getElementById('myagent').innerText
phantom.exit()

View File

@ -1,5 +0,0 @@
console.log 'using PhantomJS version ' +
phantom.version.major + '.' +
phantom.version.minor + '.' +
phantom.version.patch
phantom.exit()

View File

@ -1,48 +0,0 @@
##
# Wait until the test condition is true or a timeout occurs. Useful for waiting
# on a server response or for a ui change (fadeIn, etc.) to occur.
#
# @param testFx javascript condition that evaluates to a boolean,
# it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
# as a callback function.
# @param onReady what to do when testFx condition is fulfilled,
# it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
# as a callback function.
# @param timeOutMillis the max amount of time to wait. If not specified, 3 sec is used.
##
waitFor = (testFx, onReady, timeOutMillis=3000) ->
start = new Date().getTime()
condition = false
f = ->
if (new Date().getTime() - start < timeOutMillis) and not condition
# If not time-out yet and condition not yet fulfilled
condition = (if typeof testFx is 'string' then eval testFx else testFx()) #< defensive code
else
if not condition
# If condition still not fulfilled (timeout but condition is 'false')
console.log "'waitFor()' timeout"
phantom.exit 1
else
# Condition fulfilled (timeout and/or condition is 'true')
console.log "'waitFor()' finished in #{new Date().getTime() - start}ms."
if typeof onReady is 'string' then eval onReady else onReady() #< Do what it's supposed to do once the condition is fulfilled
clearInterval interval #< Stop this interval
interval = setInterval f, 250 #< repeat check every 250ms
page = require('webpage').create()
# Open Twitter on 'sencha' profile and, onPageLoad, do...
page.open 'http://twitter.com/#!/sencha', (status) ->
# Check for page load success
if status isnt 'success'
console.log 'Unable to access network'
else
# Wait for 'signin-dropdown' to be visible
waitFor ->
# Check in the page if a specific element is now visible
page.evaluate ->
$('#signin-dropdown').is ':visible'
, ->
console.log 'The sign-in dialog should be visible now.'
phantom.exit()

View File

@ -1,66 +0,0 @@
pageTitle = (page) ->
page.evaluate ->
window.document.title
setPageTitle = (page, newTitle) ->
page.evaluate ((newTitle) ->
window.document.title = newTitle
), newTitle
p = require("webpage").create()
p.open "../test/webpage-spec-frames/index.html", (status) ->
console.log "pageTitle(): " + pageTitle(p)
console.log "currentFrameName(): " + p.currentFrameName()
console.log "childFramesCount(): " + p.childFramesCount()
console.log "childFramesName(): " + p.childFramesName()
console.log "setPageTitle(CURRENT TITLE+'-visited')"
setPageTitle p, pageTitle(p) + "-visited"
console.log ""
console.log "p.switchToChildFrame(\"frame1\"): " + p.switchToChildFrame("frame1")
console.log "pageTitle(): " + pageTitle(p)
console.log "currentFrameName(): " + p.currentFrameName()
console.log "childFramesCount(): " + p.childFramesCount()
console.log "childFramesName(): " + p.childFramesName()
console.log "setPageTitle(CURRENT TITLE+'-visited')"
setPageTitle p, pageTitle(p) + "-visited"
console.log ""
console.log "p.switchToChildFrame(\"frame1-2\"): " + p.switchToChildFrame("frame1-2")
console.log "pageTitle(): " + pageTitle(p)
console.log "currentFrameName(): " + p.currentFrameName()
console.log "childFramesCount(): " + p.childFramesCount()
console.log "childFramesName(): " + p.childFramesName()
console.log "setPageTitle(CURRENT TITLE+'-visited')"
setPageTitle p, pageTitle(p) + "-visited"
console.log ""
console.log "p.switchToParentFrame(): " + p.switchToParentFrame()
console.log "pageTitle(): " + pageTitle(p)
console.log "currentFrameName(): " + p.currentFrameName()
console.log "childFramesCount(): " + p.childFramesCount()
console.log "childFramesName(): " + p.childFramesName()
console.log "setPageTitle(CURRENT TITLE+'-visited')"
setPageTitle p, pageTitle(p) + "-visited"
console.log ""
console.log "p.switchToChildFrame(0): " + p.switchToChildFrame(0)
console.log "pageTitle(): " + pageTitle(p)
console.log "currentFrameName(): " + p.currentFrameName()
console.log "childFramesCount(): " + p.childFramesCount()
console.log "childFramesName(): " + p.childFramesName()
console.log "setPageTitle(CURRENT TITLE+'-visited')"
setPageTitle p, pageTitle(p) + "-visited"
console.log ""
console.log "p.switchToMainFrame()"
p.switchToMainFrame()
console.log "pageTitle(): " + pageTitle(p)
console.log "currentFrameName(): " + p.currentFrameName()
console.log "childFramesCount(): " + p.childFramesCount()
console.log "childFramesName(): " + p.childFramesName()
console.log "setPageTitle(CURRENT TITLE+'-visited')"
setPageTitle p, pageTitle(p) + "-visited"
console.log ""
console.log "p.switchToChildFrame(\"frame2\"): " + p.switchToChildFrame("frame2")
console.log "pageTitle(): " + pageTitle(p)
console.log "currentFrameName(): " + p.currentFrameName()
console.log "childFramesCount(): " + p.childFramesCount()
console.log "childFramesName(): " + p.childFramesName()
console.log "setPageTitle(CURRENT TITLE+'-visited')"
setPageTitle p, pageTitle(p) + "-visited"
console.log ""
phantom.exit()

View File

@ -1,29 +0,0 @@
page = require('webpage').create()
system = require 'system'
city = 'Mountain View, California'; # default
if system.args.length > 1
city = Array.prototype.slice.call(system.args, 1).join(' ')
url = encodeURI 'http://api.openweathermap.org/data/2.1/find/name?q=' + city
console.log 'Checking weather condition for', city, '...'
page.open url, (status) ->
if status isnt 'success'
console.log 'Error: Unable to access network!'
else
result = page.evaluate ->
return document.body.innerText
try
data = JSON.parse result
data = data.list[0]
console.log ''
console.log 'City:', data.name
console.log 'Condition:', data.weather.map (entry) ->
return entry.main
console.log 'Temperature:', Math.round(data.main.temp - 273.15), 'C'
console.log 'Humidity:', Math.round(data.main.humidity), '%'
catch e
console.log 'Error:', e.toString()
phantom.exit()

View File

@ -1,141 +0,0 @@
From 837407c2b8279d9b30e75470218b3ada9b12208c Mon Sep 17 00:00:00 2001
From: Julian Szulc <julian.szulc@allegro.pl>
Date: Tue, 19 Feb 2013 18:09:15 +0100
Subject: [PATCH] Fixed issue with phantomjs reporting touch support
Fix compilation of webkit without the TOUCH_EVENTS
Added missing #if ENABLE(TOUCH_EVENTS)
for generated/JSDocument.* files
Disabled webkit touch events compilation by default
issue: http://code.google.com/p/phantomjs/issues/detail?id=375
---
src/qt/src/3rdparty/webkit/Source/WebCore/features.pri | 3 ++-
.../3rdparty/webkit/Source/WebCore/generated/JSDocument.cpp | 13 ++++++++++---
.../3rdparty/webkit/Source/WebCore/generated/JSDocument.h | 6 ++++++
3 files changed, 18 insertions(+), 4 deletions(-)
diff --git a/src/qt/src/3rdparty/webkit/Source/WebCore/features.pri b/src/qt/src/3rdparty/webkit/Source/WebCore/features.pri
index 2b8b281..14e9479 100644
--- a/src/qt/src/3rdparty/webkit/Source/WebCore/features.pri
+++ b/src/qt/src/3rdparty/webkit/Source/WebCore/features.pri
@@ -159,7 +159,8 @@ symbian|maemo5|maemo6 {
}
}
-!contains(DEFINES, ENABLE_TOUCH_EVENTS=.): DEFINES += ENABLE_TOUCH_EVENTS=1
+# If not requested, do not enable touch events
+!contains(DEFINES, ENABLE_TOUCH_EVENTS=.): DEFINES += ENABLE_TOUCH_EVENTS=0
# HTML5 Media Support
# We require QtMultimedia
diff --git a/src/qt/src/3rdparty/webkit/Source/WebCore/generated/JSDocument.cpp b/src/qt/src/3rdparty/webkit/Source/WebCore/generated/JSDocument.cpp
index 7bc127c..972c592 100644
--- a/src/qt/src/3rdparty/webkit/Source/WebCore/generated/JSDocument.cpp
+++ b/src/qt/src/3rdparty/webkit/Source/WebCore/generated/JSDocument.cpp
@@ -68,7 +68,9 @@
#include "JSRange.h"
#include "JSStyleSheetList.h"
#include "JSText.h"
+#if ENABLE(TOUCH_EVENTS)
#include "JSTouch.h"
+#endif
#include "JSTreeWalker.h"
#include "JSXPathExpression.h"
#include "JSXPathNSResolver.h"
@@ -84,8 +86,10 @@
#include "Range.h"
#include "StyleSheetList.h"
#include "Text.h"
+#if ENABLE(TOUCH_EVENTS)
#include "Touch.h"
#include "TouchList.h"
+#endif
#include "TreeWalker.h"
#include "XPathExpression.h"
#include "XPathNSResolver.h"
@@ -296,8 +300,10 @@ bool JSDocumentConstructor::getOwnPropertyDescriptor(ExecState* exec, const Iden
{ "getElementsByClassName", DontDelete | Function, (intptr_t)static_cast<NativeFunction>(jsDocumentPrototypeFunctionGetElementsByClassName), (intptr_t)1 THUNK_GENERATOR(0) },
{ "querySelector", DontDelete | Function, (intptr_t)static_cast<NativeFunction>(jsDocumentPrototypeFunctionQuerySelector), (intptr_t)1 THUNK_GENERATOR(0) },
{ "querySelectorAll", DontDelete | Function, (intptr_t)static_cast<NativeFunction>(jsDocumentPrototypeFunctionQuerySelectorAll), (intptr_t)1 THUNK_GENERATOR(0) },
+#if ENABLE(TOUCH_EVENTS)
{ "createTouch", DontDelete | Function, (intptr_t)static_cast<NativeFunction>(jsDocumentPrototypeFunctionCreateTouch), (intptr_t)7 THUNK_GENERATOR(0) },
{ "createTouchList", DontDelete | Function, (intptr_t)static_cast<NativeFunction>(jsDocumentPrototypeFunctionCreateTouchList), (intptr_t)0 THUNK_GENERATOR(0) },
+#endif
{ 0, 0, 0, 0 THUNK_GENERATOR(0) }
};
@@ -2569,7 +2575,7 @@ EncodedJSValue JSC_HOST_CALL jsDocumentPrototypeFunctionQuerySelectorAll(ExecSta
setDOMException(exec, ec);
return JSValue::encode(result);
}
-
+#if ENABLE(TOUCH_EVENTS)
EncodedJSValue JSC_HOST_CALL jsDocumentPrototypeFunctionCreateTouch(ExecState* exec)
{
JSValue thisValue = exec->hostThisValue();
@@ -2605,7 +2611,8 @@ EncodedJSValue JSC_HOST_CALL jsDocumentPrototypeFunctionCreateTouch(ExecState* e
setDOMException(exec, ec);
return JSValue::encode(result);
}
-
+#endif
+#if ENABLE(TOUCH_EVENTS)
EncodedJSValue JSC_HOST_CALL jsDocumentPrototypeFunctionCreateTouchList(ExecState* exec)
{
JSValue thisValue = exec->hostThisValue();
@@ -2614,7 +2621,7 @@ EncodedJSValue JSC_HOST_CALL jsDocumentPrototypeFunctionCreateTouchList(ExecStat
JSDocument* castedThis = static_cast<JSDocument*>(asObject(thisValue));
return JSValue::encode(castedThis->createTouchList(exec));
}
-
+#endif
Document* toDocument(JSC::JSValue value)
{
return value.inherits(&JSDocument::s_info) ? static_cast<JSDocument*>(asObject(value))->impl() : 0;
diff --git a/src/qt/src/3rdparty/webkit/Source/WebCore/generated/JSDocument.h b/src/qt/src/3rdparty/webkit/Source/WebCore/generated/JSDocument.h
index 69d7fb5..ba5c736 100644
--- a/src/qt/src/3rdparty/webkit/Source/WebCore/generated/JSDocument.h
+++ b/src/qt/src/3rdparty/webkit/Source/WebCore/generated/JSDocument.h
@@ -53,7 +53,9 @@ class JSDocument : public JSNode {
void setLocation(JSC::ExecState*, JSC::JSValue);
// Custom functions
+#if ENABLE(TOUCH_EVENTS)
JSC::JSValue createTouchList(JSC::ExecState*);
+#endif
Document* impl() const
{
return static_cast<Document*>(Base::impl());
@@ -130,8 +132,10 @@ class JSDocumentPrototype : public JSC::JSObjectWithGlobalObject {
JSC::EncodedJSValue JSC_HOST_CALL jsDocumentPrototypeFunctionGetElementsByClassName(JSC::ExecState*);
JSC::EncodedJSValue JSC_HOST_CALL jsDocumentPrototypeFunctionQuerySelector(JSC::ExecState*);
JSC::EncodedJSValue JSC_HOST_CALL jsDocumentPrototypeFunctionQuerySelectorAll(JSC::ExecState*);
+#if ENABLE(TOUCH_EVENTS)
JSC::EncodedJSValue JSC_HOST_CALL jsDocumentPrototypeFunctionCreateTouch(JSC::ExecState*);
JSC::EncodedJSValue JSC_HOST_CALL jsDocumentPrototypeFunctionCreateTouchList(JSC::ExecState*);
+#endif
// Attributes
JSC::JSValue jsDocumentDoctype(JSC::ExecState*, JSC::JSValue, const JSC::Identifier&);
@@ -257,6 +261,7 @@ class JSDocumentPrototype : public JSC::JSObjectWithGlobalObject {
void setJSDocumentOnselectstart(JSC::ExecState*, JSC::JSObject*, JSC::JSValue);
JSC::JSValue jsDocumentOnselectionchange(JSC::ExecState*, JSC::JSValue, const JSC::Identifier&);
void setJSDocumentOnselectionchange(JSC::ExecState*, JSC::JSObject*, JSC::JSValue);
+#if ENABLE(TOUCH_EVENTS)
JSC::JSValue jsDocumentOntouchstart(JSC::ExecState*, JSC::JSValue, const JSC::Identifier&);
void setJSDocumentOntouchstart(JSC::ExecState*, JSC::JSObject*, JSC::JSValue);
JSC::JSValue jsDocumentOntouchmove(JSC::ExecState*, JSC::JSValue, const JSC::Identifier&);
@@ -265,6 +270,7 @@ class JSDocumentPrototype : public JSC::JSObjectWithGlobalObject {
void setJSDocumentOntouchend(JSC::ExecState*, JSC::JSObject*, JSC::JSValue);
JSC::JSValue jsDocumentOntouchcancel(JSC::ExecState*, JSC::JSValue, const JSC::Identifier&);
void setJSDocumentOntouchcancel(JSC::ExecState*, JSC::JSObject*, JSC::JSValue);
+#endif
JSC::JSValue jsDocumentOnwebkitfullscreenchange(JSC::ExecState*, JSC::JSValue, const JSC::Identifier&);
void setJSDocumentOnwebkitfullscreenchange(JSC::ExecState*, JSC::JSObject*, JSC::JSValue);
JSC::JSValue jsDocumentConstructor(JSC::ExecState*, JSC::JSValue, const JSC::Identifier&);
--
1.8.1.5

View File

@ -1,3 +1,3 @@
TEMPLATE = subdirs TEMPLATE = subdirs
CONFIG += ordered CONFIG += ordered
SUBDIRS += src/phantomjs.pro SUBDIRS += src/qphantom/phantom.pro src/phantomjs.pro

View File

@ -1,5 +1,5 @@
%define name phantomjs %define name phantomjs
%define version 1.8 %define version 1.9
%define release 1 %define release 1
%define prefix /usr %define prefix /usr
@ -23,11 +23,9 @@ Canvas, and SVG. PhantomJS is created by Ariya Hidayat.
%prep %prep
%setup -q %setup -q
%setup %install
mkdir -p %{mybuilddir}%{prefix}/bin mkdir -p %{mybuilddir}%{prefix}/bin
mkdir -p %{mybuilddir}%{prefix}/share/%{name}/examples mkdir -p %{mybuilddir}%{prefix}/share/%{name}/examples
%install
cp bin/%{name} %{mybuilddir}%{prefix}/bin/%{name} cp bin/%{name} %{mybuilddir}%{prefix}/bin/%{name}
cp examples/* %{mybuilddir}%{prefix}/share/%{name}/examples/ cp examples/* %{mybuilddir}%{prefix}/share/%{name}/examples/
cp CONTRIBUTING.md %{mybuilddir}%{prefix}/share/%{name}/ cp CONTRIBUTING.md %{mybuilddir}%{prefix}/share/%{name}/
@ -38,12 +36,12 @@ cp README.md %{mybuilddir}%{prefix}/share/%{name}/
%files %files
%defattr(0444,root,root) %defattr(0444,root,root)
%attr(0555,root,root)%{prefix}/bin/%{name} %attr(0555,root,root)%{prefix}/bin/%{name}
%{prefix}/share/%{name}/CONTRIBUTING.md
%{prefix}/share/%{name}/ChangeLog %{prefix}/share/%{name}/ChangeLog
%{prefix}/share/%{name}/LICENSE.BSD %{prefix}/share/%{name}/CONTRIBUTING.md
%{prefix}/share/%{name}/README.md
%{prefix}/share/%{name}/examples/arguments.coffee %{prefix}/share/%{name}/examples/arguments.coffee
%{prefix}/share/%{name}/examples/arguments.js %{prefix}/share/%{name}/examples/arguments.js
%{prefix}/share/%{name}/examples/child_process-examples.coffee
%{prefix}/share/%{name}/examples/child_process-examples.js
%{prefix}/share/%{name}/examples/colorwheel.coffee %{prefix}/share/%{name}/examples/colorwheel.coffee
%{prefix}/share/%{name}/examples/colorwheel.js %{prefix}/share/%{name}/examples/colorwheel.js
%{prefix}/share/%{name}/examples/countdown.coffee %{prefix}/share/%{name}/examples/countdown.coffee
@ -54,6 +52,7 @@ cp README.md %{mybuilddir}%{prefix}/share/%{name}/
%{prefix}/share/%{name}/examples/direction.js %{prefix}/share/%{name}/examples/direction.js
%{prefix}/share/%{name}/examples/echoToFile.coffee %{prefix}/share/%{name}/examples/echoToFile.coffee
%{prefix}/share/%{name}/examples/echoToFile.js %{prefix}/share/%{name}/examples/echoToFile.js
%{prefix}/share/%{name}/examples/features.coffee
%{prefix}/share/%{name}/examples/features.js %{prefix}/share/%{name}/examples/features.js
%{prefix}/share/%{name}/examples/fibo.coffee %{prefix}/share/%{name}/examples/fibo.coffee
%{prefix}/share/%{name}/examples/fibo.js %{prefix}/share/%{name}/examples/fibo.js
@ -69,7 +68,10 @@ cp README.md %{mybuilddir}%{prefix}/share/%{name}/
%{prefix}/share/%{name}/examples/ipgeocode.js %{prefix}/share/%{name}/examples/ipgeocode.js
%{prefix}/share/%{name}/examples/loadspeed.coffee %{prefix}/share/%{name}/examples/loadspeed.coffee
%{prefix}/share/%{name}/examples/loadspeed.js %{prefix}/share/%{name}/examples/loadspeed.js
%{prefix}/share/%{name}/examples/loadurlwithoutcss.coffee
%{prefix}/share/%{name}/examples/loadurlwithoutcss.js
%{prefix}/share/%{name}/examples/modernizr.js %{prefix}/share/%{name}/examples/modernizr.js
%{prefix}/share/%{name}/examples/module.coffee
%{prefix}/share/%{name}/examples/module.js %{prefix}/share/%{name}/examples/module.js
%{prefix}/share/%{name}/examples/movies.coffee %{prefix}/share/%{name}/examples/movies.coffee
%{prefix}/share/%{name}/examples/movies.js %{prefix}/share/%{name}/examples/movies.js
@ -77,17 +79,29 @@ cp README.md %{mybuilddir}%{prefix}/share/%{name}/
%{prefix}/share/%{name}/examples/netlog.js %{prefix}/share/%{name}/examples/netlog.js
%{prefix}/share/%{name}/examples/netsniff.coffee %{prefix}/share/%{name}/examples/netsniff.coffee
%{prefix}/share/%{name}/examples/netsniff.js %{prefix}/share/%{name}/examples/netsniff.js
%{prefix}/share/%{name}/examples/openurlwithproxy.coffee
%{prefix}/share/%{name}/examples/openurlwithproxy.js
%{prefix}/share/%{name}/examples/outputEncoding.coffee %{prefix}/share/%{name}/examples/outputEncoding.coffee
%{prefix}/share/%{name}/examples/outputEncoding.js %{prefix}/share/%{name}/examples/outputEncoding.js
%{prefix}/share/%{name}/examples/page_events.coffee
%{prefix}/share/%{name}/examples/page_events.js
%{prefix}/share/%{name}/examples/pagecallback.coffee
%{prefix}/share/%{name}/examples/pagecallback.js
%{prefix}/share/%{name}/examples/phantomwebintro.coffee %{prefix}/share/%{name}/examples/phantomwebintro.coffee
%{prefix}/share/%{name}/examples/phantomwebintro.js %{prefix}/share/%{name}/examples/phantomwebintro.js
%{prefix}/share/%{name}/examples/pizza.coffee %{prefix}/share/%{name}/examples/pizza.coffee
%{prefix}/share/%{name}/examples/pizza.js %{prefix}/share/%{name}/examples/pizza.js
%{prefix}/share/%{name}/examples/post.coffee %{prefix}/share/%{name}/examples/post.coffee
%{prefix}/share/%{name}/examples/post.js %{prefix}/share/%{name}/examples/post.js
%{prefix}/share/%{name}/examples/postjson.coffee
%{prefix}/share/%{name}/examples/postjson.js
%{prefix}/share/%{name}/examples/postserver.coffee
%{prefix}/share/%{name}/examples/postserver.js %{prefix}/share/%{name}/examples/postserver.js
%{prefix}/share/%{name}/examples/printenv.coffee
%{prefix}/share/%{name}/examples/printenv.js %{prefix}/share/%{name}/examples/printenv.js
%{prefix}/share/%{name}/examples/printheaderfooter.coffee
%{prefix}/share/%{name}/examples/printheaderfooter.js %{prefix}/share/%{name}/examples/printheaderfooter.js
%{prefix}/share/%{name}/examples/printmargins.coffee
%{prefix}/share/%{name}/examples/printmargins.js %{prefix}/share/%{name}/examples/printmargins.js
%{prefix}/share/%{name}/examples/rasterize.coffee %{prefix}/share/%{name}/examples/rasterize.coffee
%{prefix}/share/%{name}/examples/rasterize.js %{prefix}/share/%{name}/examples/rasterize.js
@ -95,18 +109,23 @@ cp README.md %{mybuilddir}%{prefix}/share/%{name}/
%{prefix}/share/%{name}/examples/render_multi_url.js %{prefix}/share/%{name}/examples/render_multi_url.js
%{prefix}/share/%{name}/examples/run-jasmine.coffee %{prefix}/share/%{name}/examples/run-jasmine.coffee
%{prefix}/share/%{name}/examples/run-jasmine.js %{prefix}/share/%{name}/examples/run-jasmine.js
%{prefix}/share/%{name}/examples/run-jasmine2.js
%{prefix}/share/%{name}/examples/run-qunit.coffee %{prefix}/share/%{name}/examples/run-qunit.coffee
%{prefix}/share/%{name}/examples/run-qunit.js %{prefix}/share/%{name}/examples/run-qunit.js
%{prefix}/share/%{name}/examples/scandir.coffee %{prefix}/share/%{name}/examples/scandir.coffee
%{prefix}/share/%{name}/examples/scandir.js %{prefix}/share/%{name}/examples/scandir.js
%{prefix}/share/%{name}/examples/seasonfood.coffee %{prefix}/share/%{name}/examples/seasonfood.coffee
%{prefix}/share/%{name}/examples/seasonfood.js %{prefix}/share/%{name}/examples/seasonfood.js
%{prefix}/share/%{name}/examples/server.coffee
%{prefix}/share/%{name}/examples/server.js %{prefix}/share/%{name}/examples/server.js
%{prefix}/share/%{name}/examples/serverkeepalive.coffee
%{prefix}/share/%{name}/examples/serverkeepalive.js %{prefix}/share/%{name}/examples/serverkeepalive.js
%{prefix}/share/%{name}/examples/simpleserver.coffee %{prefix}/share/%{name}/examples/simpleserver.coffee
%{prefix}/share/%{name}/examples/simpleserver.js %{prefix}/share/%{name}/examples/simpleserver.js
%{prefix}/share/%{name}/examples/sleepsort.coffee %{prefix}/share/%{name}/examples/sleepsort.coffee
%{prefix}/share/%{name}/examples/sleepsort.js %{prefix}/share/%{name}/examples/sleepsort.js
%{prefix}/share/%{name}/examples/stdin-stdout-stderr.coffee
%{prefix}/share/%{name}/examples/stdin-stdout-stderr.js
%{prefix}/share/%{name}/examples/technews.coffee %{prefix}/share/%{name}/examples/technews.coffee
%{prefix}/share/%{name}/examples/technews.js %{prefix}/share/%{name}/examples/technews.js
%{prefix}/share/%{name}/examples/tweets.coffee %{prefix}/share/%{name}/examples/tweets.coffee
@ -122,20 +141,21 @@ cp README.md %{mybuilddir}%{prefix}/share/%{name}/
%{prefix}/share/%{name}/examples/waitfor.js %{prefix}/share/%{name}/examples/waitfor.js
%{prefix}/share/%{name}/examples/walk_through_frames.coffee %{prefix}/share/%{name}/examples/walk_through_frames.coffee
%{prefix}/share/%{name}/examples/walk_through_frames.js %{prefix}/share/%{name}/examples/walk_through_frames.js
%{prefix}/share/%{name}/examples/features.coffee %{prefix}/share/%{name}/examples/weather.coffee
%{prefix}/share/%{name}/examples/module.coffee %{prefix}/share/%{name}/examples/weather.js
%{prefix}/share/%{name}/examples/page_events.coffee %{prefix}/share/%{name}/LICENSE.BSD
%{prefix}/share/%{name}/examples/page_events.js %{prefix}/share/%{name}/README.md
%{prefix}/share/%{name}/examples/pagecallback.coffee
%{prefix}/share/%{name}/examples/pagecallback.js
%{prefix}/share/%{name}/examples/postserver.coffee
%{prefix}/share/%{name}/examples/printenv.coffee
%{prefix}/share/%{name}/examples/printheaderfooter.coffee
%{prefix}/share/%{name}/examples/printmargins.coffee
%{prefix}/share/%{name}/examples/server.coffee
%{prefix}/share/%{name}/examples/serverkeepalive.coffee
%changelog %changelog
* Fri Apr 18 2014 Eric Heydenberk <heydenberk@gmail.com>
- add missing filenames for examples to files section
* Tue Apr 30 2013 Eric Heydenberk <heydenberk@gmail.com>
- add missing filenames for examples to files section
* Wed Apr 24 2013 Robin Helgelin <lobbin@gmail.com>
- updated to version 1.9
* Thu Jan 24 2013 Matthew Barr <mbarr@snap-interactive.com> * Thu Jan 24 2013 Matthew Barr <mbarr@snap-interactive.com>
- updated to version 1.8 - updated to version 1.8

View File

@ -35,44 +35,45 @@
*/ */
phantom.__defineErrorSignalHandler__ = function(obj, page, handlers) { phantom.__defineErrorSignalHandler__ = function(obj, page, handlers) {
var signal = page.javaScriptErrorSent;
var handlerName = 'onError'; var handlerName = 'onError';
obj.__defineSetter__(handlerName, function(f) { Object.defineProperty(obj, handlerName, {
set: function (f) {
// Disconnect previous handler (if any) // Disconnect previous handler (if any)
var handlerObj = handlers[handlerName]; var handlerObj = handlers[handlerName];
if (!!handlerObj && typeof handlerObj.callback === "function" && typeof handlerObj.connector === "function") { if (!!handlerObj && typeof handlerObj.callback === "function" && typeof handlerObj.connector === "function") {
try { signal.disconnect(handlerObj.connector); } try { page.javaScriptErrorSent.disconnect(handlerObj.connector); }
catch (e) {} catch (e) { }
} }
// Delete the previous handler // Delete the previous handler
delete handlers[handlerName]; delete handlers[handlerName];
if (typeof f === 'function') { if (typeof f === 'function') {
var connector = function(message, stack) { var connector = function (message, lineNumber, source, stack) {
var revisedStack = JSON.parse(stack).map(function(item) { var revisedStack = JSON.parse(stack).map(function (item) {
return { file: item.url, line: item.lineNumber, function: item.functionName } return { file: item.url, line: item.lineNumber, function: item.functionName };
}); });
if (revisedStack.length == 0)
revisedStack = [{ file: source, line: lineNumber }];
f(message, revisedStack); f(message, revisedStack);
}; };
// Store the new handler for reference // Store the new handler for reference
handlers[handlerName] = { handlers[handlerName] = {
callback: f, callback: f,
connector: connector connector: connector
}; };
signal.connect(connector); page.javaScriptErrorSent.connect(connector);
} }
}); },
get: function () {
obj.__defineGetter__(handlerName, function() {
var handlerObj = handlers[handlerName]; var handlerObj = handlers[handlerName];
return (!!handlerObj && typeof handlerObj.callback === "function" && typeof handlerObj.connector === "function") ? return (!!handlerObj && typeof handlerObj.callback === "function" && typeof handlerObj.connector === "function") ?
handlers[handlerName].callback : handlers[handlerName].callback :
undefined; undefined;
}
}); });
}; };
@ -111,6 +112,7 @@ phantom.callback = function(callback) {
// fs is loaded at the end, when everything is ready // fs is loaded at the end, when everything is ready
var fs; var fs;
var cache = {}; var cache = {};
var paths = [];
// use getters to initialize lazily // use getters to initialize lazily
// (for future, now both fs and system are loaded anyway) // (for future, now both fs and system are loaded anyway)
var nativeExports = { var nativeExports = {
@ -209,36 +211,44 @@ phantom.callback = function(callback) {
Module.prototype._isNative = function() { Module.prototype._isNative = function() {
return this.filename && this.filename[0] === ':'; return this.filename && this.filename[0] === ':';
} };
Module.prototype._getPaths = function(request) { Module.prototype._getPaths = function(request) {
var paths = [], dir; var _paths = [], dir;
if (request[0] === '.') { if (request[0] === '.') {
paths.push(fs.absolute(joinPath(phantom.webdriverMode ? ":/ghostdriver" : this.dirname, request))); _paths.push(fs.absolute(joinPath(phantom.webdriverMode ? ":/ghostdriver" : this.dirname, request)));
} else if (request[0] === '/') { } else if (fs.isAbsolute(request)) {
paths.push(fs.absolute(request)); _paths.push(fs.absolute(request));
} else { } else {
// first look in PhantomJS modules // first look in PhantomJS modules
paths.push(joinPath(':/modules', request)); _paths.push(joinPath(':/modules', request));
// then look in node_modules directories // then look in node_modules directories
if (!this._isNative()) { if (!this._isNative()) {
dir = this.dirname; dir = this.dirname;
while (dir) { while (dir) {
paths.push(joinPath(dir, 'node_modules', request)); _paths.push(joinPath(dir, 'node_modules', request));
dir = dirname(dir); dir = dirname(dir);
} }
} }
} }
return paths; for (var i=0; i<paths.length; ++i) {
if(fs.isAbsolute(paths[i])) {
_paths.push(fs.absolute(joinPath(paths[i], request)));
} else {
_paths.push(fs.absolute(joinPath(this.dirname, paths[i], request)));
}
}
return _paths;
}; };
Module.prototype._getFilename = function(request) { Module.prototype._getFilename = function(request) {
var path, filename = null, paths = this._getPaths(request); var path, filename = null, _paths = this._getPaths(request);
for (var i=0; i<paths.length && !filename; ++i) { for (var i=0; i<_paths.length && !filename; ++i) {
path = paths[i]; path = _paths[i];
filename = tryFile(path) || tryExtensions(path) || tryPackage(path) || filename = tryFile(path) || tryExtensions(path) || tryPackage(path) ||
tryExtensions(joinPath(path, 'index')); tryExtensions(joinPath(path, 'index'));
} }
@ -254,6 +264,7 @@ phantom.callback = function(callback) {
} }
require.cache = cache; require.cache = cache;
require.extensions = extensions; require.extensions = extensions;
require.paths = paths;
require.stub = function(request, exports) { require.stub = function(request, exports) {
self.stubs[request] = { exports: exports }; self.stubs[request] = { exports: exports };
}; };
@ -309,11 +320,6 @@ phantom.callback = function(callback) {
cwd = fs.absolute(phantom.libraryPath); cwd = fs.absolute(phantom.libraryPath);
mainFilename = joinPath(cwd, basename(require('system').args[0]) || 'repl'); mainFilename = joinPath(cwd, basename(require('system').args[0]) || 'repl');
mainModule._setFilename(mainFilename); mainModule._setFilename(mainFilename);
// include CoffeeScript which takes care of adding .coffee extension (only if not in Webdriver mode)
if (!phantom.webdriverMode) {
require('_coffee-script');
}
}()); }());
}()); }());

View File

@ -1 +0,0 @@
../.gitignore-breakpad

18
src/breakpad/.gitignore vendored Normal file
View File

@ -0,0 +1,18 @@
/src/client/linux/linux_dumper_unittest_helper
/src/processor/minidump_dump
/src/processor/minidump_stackwalk
/src/tools/linux/core2md/core2md
/src/tools/linux/dump_syms/dump_syms
/src/tools/linux/md2core/minidump-2-core
/src/tools/linux/symupload/minidump_upload
/src/tools/linux/symupload/sym_upload
/src/config.h
/src/stamp-h1
/config.log
/config.status
/autom4te.cache
!Makefile.am
!Makefile.in
.dirstamp
.deps

View File

@ -1 +0,0 @@
/usr/share/automake-1.11/compile

View File

@ -1,9 +0,0 @@
raw
presentation
test.coffee
parser.output
test/fixtures/underscore
test/*.js
examples/beautiful_code/parse.coffee
*.gem
/node_modules

View File

@ -1,11 +0,0 @@
*.coffee
*.html
.DS_Store
.git*
Cakefile
documentation/
examples/
extras/coffee-script.js
raw/
src/
test/

View File

@ -1,22 +0,0 @@
Copyright (c) 2009-2012 Jeremy Ashkenas
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.

View File

@ -1,51 +0,0 @@
{
} } {
{ { } }
} }{ {
{ }{ } } _____ __ __
( }{ }{ { ) / ____| / _|/ _|
.- { { } { }} -. | | ___ | |_| |_ ___ ___
( ( } { } { } } ) | | / _ \| _| _/ _ \/ _ \
|`-..________ ..-'| | |___| (_) | | | || __/ __/
| | \_____\___/|_| |_| \___|\___|
| ;--.
| (__ \ _____ _ _
| | ) ) / ____| (_) | |
| |/ / | (___ ___ _ __ _ _ __ | |_
| ( / \___ \ / __| '__| | '_ \| __|
| |/ ____) | (__| | | | |_) | |_
| | |_____/ \___|_| |_| .__/ \__|
`-.._________..-' | |
|_|
CoffeeScript is a little language that compiles into JavaScript.
Install Node.js, and then the CoffeeScript compiler:
sudo bin/cake install
Or, if you have the Node Package Manager installed:
npm install -g coffee-script
(Leave off the -g if you don't wish to install globally.)
Execute a script:
coffee /path/to/script.coffee
Compile a script:
coffee -c /path/to/script.coffee
For documentation, usage, and examples, see:
http://coffeescript.org/
To suggest a feature, report a bug, or general discussion:
http://github.com/jashkenas/coffee-script/issues/
If you'd like to chat, drop by #coffeescript on Freenode IRC,
or on webchat.freenode.net.
The source repository:
git://github.com/jashkenas/coffee-script.git
All contributors are listed here:
http://github.com/jashkenas/coffee-script/contributors

File diff suppressed because one or more lines are too long

View File

@ -1,92 +0,0 @@
// Generated by CoffeeScript 1.3.3
(function() {
var CoffeeScript, runScripts;
CoffeeScript = require('./coffee-script');
CoffeeScript.require = require;
CoffeeScript["eval"] = function(code, options) {
var _ref;
if (options == null) {
options = {};
}
if ((_ref = options.bare) == null) {
options.bare = true;
}
return eval(CoffeeScript.compile(code, options));
};
CoffeeScript.run = function(code, options) {
if (options == null) {
options = {};
}
options.bare = true;
return Function(CoffeeScript.compile(code, options))();
};
if (typeof window === "undefined" || window === null) {
return;
}
CoffeeScript.load = function(url, callback) {
var xhr;
xhr = new (window.ActiveXObject || XMLHttpRequest)('Microsoft.XMLHTTP');
xhr.open('GET', url, true);
if ('overrideMimeType' in xhr) {
xhr.overrideMimeType('text/plain');
}
xhr.onreadystatechange = function() {
var _ref;
if (xhr.readyState === 4) {
if ((_ref = xhr.status) === 0 || _ref === 200) {
CoffeeScript.run(xhr.responseText);
} else {
throw new Error("Could not load " + url);
}
if (callback) {
return callback();
}
}
};
return xhr.send(null);
};
runScripts = function() {
var coffees, execute, index, length, s, scripts;
scripts = document.getElementsByTagName('script');
coffees = (function() {
var _i, _len, _results;
_results = [];
for (_i = 0, _len = scripts.length; _i < _len; _i++) {
s = scripts[_i];
if (s.type === 'text/coffeescript') {
_results.push(s);
}
}
return _results;
})();
index = 0;
length = coffees.length;
(execute = function() {
var script;
script = coffees[index++];
if ((script != null ? script.type : void 0) === 'text/coffeescript') {
if (script.src) {
return CoffeeScript.load(script.src, execute);
} else {
CoffeeScript.run(script.innerHTML);
return execute();
}
}
})();
return null;
};
if (window.addEventListener) {
addEventListener('DOMContentLoaded', runScripts, false);
} else {
attachEvent('onload', runScripts);
}
}).call(this);

View File

@ -1,111 +0,0 @@
// Generated by CoffeeScript 1.3.3
(function() {
var CoffeeScript, cakefileDirectory, fatalError, fs, helpers, missingTask, oparse, options, optparse, path, printTasks, switches, tasks;
fs = require('fs');
path = require('path');
helpers = require('./helpers');
optparse = require('./optparse');
CoffeeScript = require('./coffee-script');
tasks = {};
options = {};
switches = [];
oparse = null;
helpers.extend(global, {
task: function(name, description, action) {
var _ref;
if (!action) {
_ref = [description, action], action = _ref[0], description = _ref[1];
}
return tasks[name] = {
name: name,
description: description,
action: action
};
},
option: function(letter, flag, description) {
return switches.push([letter, flag, description]);
},
invoke: function(name) {
if (!tasks[name]) {
missingTask(name);
}
return tasks[name].action(options);
}
});
exports.run = function() {
var arg, args, _i, _len, _ref, _results;
global.__originalDirname = fs.realpathSync('.');
process.chdir(cakefileDirectory(__originalDirname));
args = process.argv.slice(2);
CoffeeScript.run(fs.readFileSync('Cakefile').toString(), {
filename: 'Cakefile'
});
oparse = new optparse.OptionParser(switches);
if (!args.length) {
return printTasks();
}
try {
options = oparse.parse(args);
} catch (e) {
return fatalError("" + e);
}
_ref = options["arguments"];
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
arg = _ref[_i];
_results.push(invoke(arg));
}
return _results;
};
printTasks = function() {
var cakefilePath, desc, name, relative, spaces, task;
relative = path.relative || path.resolve;
cakefilePath = path.join(relative(__originalDirname, process.cwd()), 'Cakefile');
console.log("" + cakefilePath + " defines the following tasks:\n");
for (name in tasks) {
task = tasks[name];
spaces = 20 - name.length;
spaces = spaces > 0 ? Array(spaces + 1).join(' ') : '';
desc = task.description ? "# " + task.description : '';
console.log("cake " + name + spaces + " " + desc);
}
if (switches.length) {
return console.log(oparse.help());
}
};
fatalError = function(message) {
console.error(message + '\n');
console.log('To see a list of all tasks/options, run "cake"');
return process.exit(1);
};
missingTask = function(task) {
return fatalError("No such task: " + task);
};
cakefileDirectory = function(dir) {
var parent;
if (path.existsSync(path.join(dir, 'Cakefile'))) {
return dir;
}
parent = path.normalize(path.join(dir, '..'));
if (parent !== dir) {
return cakefileDirectory(parent);
}
throw new Error("Cakefile not found in " + (process.cwd()));
};
}).call(this);

View File

@ -1,167 +0,0 @@
// Generated by CoffeeScript 1.3.3
(function() {
var Lexer, RESERVED, compile, fs, lexer, parser, path, vm, _ref,
__hasProp = {}.hasOwnProperty;
fs = require('fs');
path = require('path');
_ref = require('./lexer'), Lexer = _ref.Lexer, RESERVED = _ref.RESERVED;
parser = require('./parser').parser;
vm = require('vm');
if (require.extensions) {
require.extensions['.coffee'] = function(module, filename) {
var content;
content = compile(fs.readFileSync(filename, 'utf8'), {
filename: filename
});
return module._compile(content, filename);
};
} else if (require.registerExtension) {
require.registerExtension('.coffee', function(content) {
return compile(content);
});
}
exports.VERSION = '1.3.3';
exports.RESERVED = RESERVED;
exports.helpers = require('./helpers');
exports.compile = compile = function(code, options) {
var header, js, merge;
if (options == null) {
options = {};
}
merge = exports.helpers.merge;
try {
js = (parser.parse(lexer.tokenize(code))).compile(options);
if (!options.header) {
return js;
}
} catch (err) {
if (options.filename) {
err.message = "In " + options.filename + ", " + err.message;
}
throw err;
}
header = "Generated by CoffeeScript " + this.VERSION;
return "// " + header + "\n" + js;
};
exports.tokens = function(code, options) {
return lexer.tokenize(code, options);
};
exports.nodes = function(source, options) {
if (typeof source === 'string') {
return parser.parse(lexer.tokenize(source, options));
} else {
return parser.parse(source);
}
};
exports.run = function(code, options) {
var mainModule;
if (options == null) {
options = {};
}
mainModule = require.main;
mainModule.filename = process.argv[1] = options.filename ? fs.realpathSync(options.filename) : '.';
mainModule.moduleCache && (mainModule.moduleCache = {});
mainModule.paths = require('module')._nodeModulePaths(path.dirname(fs.realpathSync(options.filename)));
if (path.extname(mainModule.filename) !== '.coffee' || require.extensions) {
return mainModule._compile(compile(code, options), mainModule.filename);
} else {
return mainModule._compile(code, mainModule.filename);
}
};
exports["eval"] = function(code, options) {
var Module, Script, js, k, o, r, sandbox, v, _i, _len, _module, _ref1, _ref2, _require;
if (options == null) {
options = {};
}
if (!(code = code.trim())) {
return;
}
Script = vm.Script;
if (Script) {
if (options.sandbox != null) {
if (options.sandbox instanceof Script.createContext().constructor) {
sandbox = options.sandbox;
} else {
sandbox = Script.createContext();
_ref1 = options.sandbox;
for (k in _ref1) {
if (!__hasProp.call(_ref1, k)) continue;
v = _ref1[k];
sandbox[k] = v;
}
}
sandbox.global = sandbox.root = sandbox.GLOBAL = sandbox;
} else {
sandbox = global;
}
sandbox.__filename = options.filename || 'eval';
sandbox.__dirname = path.dirname(sandbox.__filename);
if (!(sandbox !== global || sandbox.module || sandbox.require)) {
Module = require('module');
sandbox.module = _module = new Module(options.modulename || 'eval');
sandbox.require = _require = function(path) {
return Module._load(path, _module, true);
};
_module.filename = sandbox.__filename;
_ref2 = Object.getOwnPropertyNames(require);
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
r = _ref2[_i];
if (r !== 'paths') {
_require[r] = require[r];
}
}
_require.paths = _module.paths = Module._nodeModulePaths(process.cwd());
_require.resolve = function(request) {
return Module._resolveFilename(request, _module);
};
}
}
o = {};
for (k in options) {
if (!__hasProp.call(options, k)) continue;
v = options[k];
o[k] = v;
}
o.bare = true;
js = compile(code, o);
if (sandbox === global) {
return vm.runInThisContext(js);
} else {
return vm.runInContext(js, sandbox);
}
};
lexer = new Lexer;
parser.lexer = {
lex: function() {
var tag, _ref1;
_ref1 = this.tokens[this.pos++] || [''], tag = _ref1[0], this.yytext = _ref1[1], this.yylineno = _ref1[2];
return tag;
},
setInput: function(tokens) {
this.tokens = tokens;
return this.pos = 0;
},
upcomingInput: function() {
return "";
}
};
parser.yy = require('./nodes');
}).call(this);

View File

@ -1,500 +0,0 @@
// Generated by CoffeeScript 1.3.3
(function() {
var BANNER, CoffeeScript, EventEmitter, SWITCHES, compileJoin, compileOptions, compilePath, compileScript, compileStdio, exec, forkNode, fs, helpers, hidden, joinTimeout, lint, loadRequires, notSources, optionParser, optparse, opts, outputPath, parseOptions, path, printLine, printTokens, printWarn, removeSource, sourceCode, sources, spawn, timeLog, unwatchDir, usage, version, wait, watch, watchDir, watchers, writeJs, _ref;
fs = require('fs');
path = require('path');
helpers = require('./helpers');
optparse = require('./optparse');
CoffeeScript = require('./coffee-script');
_ref = require('child_process'), spawn = _ref.spawn, exec = _ref.exec;
EventEmitter = require('events').EventEmitter;
helpers.extend(CoffeeScript, new EventEmitter);
printLine = function(line) {
return process.stdout.write(line + '\n');
};
printWarn = function(line) {
return process.stderr.write(line + '\n');
};
hidden = function(file) {
return /^\.|~$/.test(file);
};
BANNER = 'Usage: coffee [options] path/to/script.coffee -- [args]\n\nIf called without options, `coffee` will run your script.';
SWITCHES = [['-b', '--bare', 'compile without a top-level function wrapper'], ['-c', '--compile', 'compile to JavaScript and save as .js files'], ['-e', '--eval', 'pass a string from the command line as input'], ['-h', '--help', 'display this help message'], ['-i', '--interactive', 'run an interactive CoffeeScript REPL'], ['-j', '--join [FILE]', 'concatenate the source CoffeeScript before compiling'], ['-l', '--lint', 'pipe the compiled JavaScript through JavaScript Lint'], ['-n', '--nodes', 'print out the parse tree that the parser produces'], ['--nodejs [ARGS]', 'pass options directly to the "node" binary'], ['-o', '--output [DIR]', 'set the output directory for compiled JavaScript'], ['-p', '--print', 'print out the compiled JavaScript'], ['-r', '--require [FILE*]', 'require a library before executing your script'], ['-s', '--stdio', 'listen for and compile scripts over stdio'], ['-t', '--tokens', 'print out the tokens that the lexer/rewriter produce'], ['-v', '--version', 'display the version number'], ['-w', '--watch', 'watch scripts for changes and rerun commands']];
opts = {};
sources = [];
sourceCode = [];
notSources = {};
watchers = {};
optionParser = null;
exports.run = function() {
var literals, source, _i, _len, _results;
parseOptions();
if (opts.nodejs) {
return forkNode();
}
if (opts.help) {
return usage();
}
if (opts.version) {
return version();
}
if (opts.require) {
loadRequires();
}
if (opts.interactive) {
return require('./repl');
}
if (opts.watch && !fs.watch) {
return printWarn("The --watch feature depends on Node v0.6.0+. You are running " + process.version + ".");
}
if (opts.stdio) {
return compileStdio();
}
if (opts["eval"]) {
return compileScript(null, sources[0]);
}
if (!sources.length) {
return require('./repl');
}
literals = opts.run ? sources.splice(1) : [];
process.argv = process.argv.slice(0, 2).concat(literals);
process.argv[0] = 'coffee';
process.execPath = require.main.filename;
_results = [];
for (_i = 0, _len = sources.length; _i < _len; _i++) {
source = sources[_i];
_results.push(compilePath(source, true, path.normalize(source)));
}
return _results;
};
compilePath = function(source, topLevel, base) {
return fs.stat(source, function(err, stats) {
if (err && err.code !== 'ENOENT') {
throw err;
}
if ((err != null ? err.code : void 0) === 'ENOENT') {
if (topLevel && source.slice(-7) !== '.coffee') {
source = sources[sources.indexOf(source)] = "" + source + ".coffee";
return compilePath(source, topLevel, base);
}
if (topLevel) {
console.error("File not found: " + source);
process.exit(1);
}
return;
}
if (stats.isDirectory()) {
if (opts.watch) {
watchDir(source, base);
}
return fs.readdir(source, function(err, files) {
var file, index, _ref1, _ref2;
if (err && err.code !== 'ENOENT') {
throw err;
}
if ((err != null ? err.code : void 0) === 'ENOENT') {
return;
}
index = sources.indexOf(source);
files = files.filter(function(file) {
return !hidden(file);
});
[].splice.apply(sources, [index, index - index + 1].concat(_ref1 = (function() {
var _i, _len, _results;
_results = [];
for (_i = 0, _len = files.length; _i < _len; _i++) {
file = files[_i];
_results.push(path.join(source, file));
}
return _results;
})())), _ref1;
[].splice.apply(sourceCode, [index, index - index + 1].concat(_ref2 = files.map(function() {
return null;
}))), _ref2;
return files.forEach(function(file) {
return compilePath(path.join(source, file), false, base);
});
});
} else if (topLevel || path.extname(source) === '.coffee') {
if (opts.watch) {
watch(source, base);
}
return fs.readFile(source, function(err, code) {
if (err && err.code !== 'ENOENT') {
throw err;
}
if ((err != null ? err.code : void 0) === 'ENOENT') {
return;
}
return compileScript(source, code.toString(), base);
});
} else {
notSources[source] = true;
return removeSource(source, base);
}
});
};
compileScript = function(file, input, base) {
var o, options, t, task;
o = opts;
options = compileOptions(file);
try {
t = task = {
file: file,
input: input,
options: options
};
CoffeeScript.emit('compile', task);
if (o.tokens) {
return printTokens(CoffeeScript.tokens(t.input));
} else if (o.nodes) {
return printLine(CoffeeScript.nodes(t.input).toString().trim());
} else if (o.run) {
return CoffeeScript.run(t.input, t.options);
} else if (o.join && t.file !== o.join) {
sourceCode[sources.indexOf(t.file)] = t.input;
return compileJoin();
} else {
t.output = CoffeeScript.compile(t.input, t.options);
CoffeeScript.emit('success', task);
if (o.print) {
return printLine(t.output.trim());
} else if (o.compile) {
return writeJs(t.file, t.output, base);
} else if (o.lint) {
return lint(t.file, t.output);
}
}
} catch (err) {
CoffeeScript.emit('failure', err, task);
if (CoffeeScript.listeners('failure').length) {
return;
}
if (o.watch) {
return printLine(err.message + '\x07');
}
printWarn(err instanceof Error && err.stack || ("ERROR: " + err));
return process.exit(1);
}
};
compileStdio = function() {
var code, stdin;
code = '';
stdin = process.openStdin();
stdin.on('data', function(buffer) {
if (buffer) {
return code += buffer.toString();
}
});
return stdin.on('end', function() {
return compileScript(null, code);
});
};
joinTimeout = null;
compileJoin = function() {
if (!opts.join) {
return;
}
if (!sourceCode.some(function(code) {
return code === null;
})) {
clearTimeout(joinTimeout);
return joinTimeout = wait(100, function() {
return compileScript(opts.join, sourceCode.join('\n'), opts.join);
});
}
};
loadRequires = function() {
var realFilename, req, _i, _len, _ref1;
realFilename = module.filename;
module.filename = '.';
_ref1 = opts.require;
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
req = _ref1[_i];
require(req);
}
return module.filename = realFilename;
};
watch = function(source, base) {
var compile, compileTimeout, prevStats, rewatch, watchErr, watcher;
prevStats = null;
compileTimeout = null;
watchErr = function(e) {
if (e.code === 'ENOENT') {
if (sources.indexOf(source) === -1) {
return;
}
try {
rewatch();
return compile();
} catch (e) {
removeSource(source, base, true);
return compileJoin();
}
} else {
throw e;
}
};
compile = function() {
clearTimeout(compileTimeout);
return compileTimeout = wait(25, function() {
return fs.stat(source, function(err, stats) {
if (err) {
return watchErr(err);
}
if (prevStats && stats.size === prevStats.size && stats.mtime.getTime() === prevStats.mtime.getTime()) {
return rewatch();
}
prevStats = stats;
return fs.readFile(source, function(err, code) {
if (err) {
return watchErr(err);
}
compileScript(source, code.toString(), base);
return rewatch();
});
});
});
};
try {
watcher = fs.watch(source, compile);
} catch (e) {
watchErr(e);
}
return rewatch = function() {
if (watcher != null) {
watcher.close();
}
return watcher = fs.watch(source, compile);
};
};
watchDir = function(source, base) {
var readdirTimeout, watcher;
readdirTimeout = null;
try {
return watcher = fs.watch(source, function() {
clearTimeout(readdirTimeout);
return readdirTimeout = wait(25, function() {
return fs.readdir(source, function(err, files) {
var file, _i, _len, _results;
if (err) {
if (err.code !== 'ENOENT') {
throw err;
}
watcher.close();
return unwatchDir(source, base);
}
_results = [];
for (_i = 0, _len = files.length; _i < _len; _i++) {
file = files[_i];
if (!(!hidden(file) && !notSources[file])) {
continue;
}
file = path.join(source, file);
if (sources.some(function(s) {
return s.indexOf(file) >= 0;
})) {
continue;
}
sources.push(file);
sourceCode.push(null);
_results.push(compilePath(file, false, base));
}
return _results;
});
});
});
} catch (e) {
if (e.code !== 'ENOENT') {
throw e;
}
}
};
unwatchDir = function(source, base) {
var file, prevSources, toRemove, _i, _len;
prevSources = sources.slice(0);
toRemove = (function() {
var _i, _len, _results;
_results = [];
for (_i = 0, _len = sources.length; _i < _len; _i++) {
file = sources[_i];
if (file.indexOf(source) >= 0) {
_results.push(file);
}
}
return _results;
})();
for (_i = 0, _len = toRemove.length; _i < _len; _i++) {
file = toRemove[_i];
removeSource(file, base, true);
}
if (!sources.some(function(s, i) {
return prevSources[i] !== s;
})) {
return;
}
return compileJoin();
};
removeSource = function(source, base, removeJs) {
var index, jsPath;
index = sources.indexOf(source);
sources.splice(index, 1);
sourceCode.splice(index, 1);
if (removeJs && !opts.join) {
jsPath = outputPath(source, base);
return path.exists(jsPath, function(exists) {
if (exists) {
return fs.unlink(jsPath, function(err) {
if (err && err.code !== 'ENOENT') {
throw err;
}
return timeLog("removed " + source);
});
}
});
}
};
outputPath = function(source, base) {
var baseDir, dir, filename, srcDir;
filename = path.basename(source, path.extname(source)) + '.js';
srcDir = path.dirname(source);
baseDir = base === '.' ? srcDir : srcDir.substring(base.length);
dir = opts.output ? path.join(opts.output, baseDir) : srcDir;
return path.join(dir, filename);
};
writeJs = function(source, js, base) {
var compile, jsDir, jsPath;
jsPath = outputPath(source, base);
jsDir = path.dirname(jsPath);
compile = function() {
if (js.length <= 0) {
js = ' ';
}
return fs.writeFile(jsPath, js, function(err) {
if (err) {
return printLine(err.message);
} else if (opts.compile && opts.watch) {
return timeLog("compiled " + source);
}
});
};
return path.exists(jsDir, function(exists) {
if (exists) {
return compile();
} else {
return exec("mkdir -p " + jsDir, compile);
}
});
};
wait = function(milliseconds, func) {
return setTimeout(func, milliseconds);
};
timeLog = function(message) {
return console.log("" + ((new Date).toLocaleTimeString()) + " - " + message);
};
lint = function(file, js) {
var conf, jsl, printIt;
printIt = function(buffer) {
return printLine(file + ':\t' + buffer.toString().trim());
};
conf = __dirname + '/../../extras/jsl.conf';
jsl = spawn('jsl', ['-nologo', '-stdin', '-conf', conf]);
jsl.stdout.on('data', printIt);
jsl.stderr.on('data', printIt);
jsl.stdin.write(js);
return jsl.stdin.end();
};
printTokens = function(tokens) {
var strings, tag, token, value;
strings = (function() {
var _i, _len, _ref1, _results;
_results = [];
for (_i = 0, _len = tokens.length; _i < _len; _i++) {
token = tokens[_i];
_ref1 = [token[0], token[1].toString().replace(/\n/, '\\n')], tag = _ref1[0], value = _ref1[1];
_results.push("[" + tag + " " + value + "]");
}
return _results;
})();
return printLine(strings.join(' '));
};
parseOptions = function() {
var i, o, source, _i, _len;
optionParser = new optparse.OptionParser(SWITCHES, BANNER);
o = opts = optionParser.parse(process.argv.slice(2));
o.compile || (o.compile = !!o.output);
o.run = !(o.compile || o.print || o.lint);
o.print = !!(o.print || (o["eval"] || o.stdio && o.compile));
sources = o["arguments"];
for (i = _i = 0, _len = sources.length; _i < _len; i = ++_i) {
source = sources[i];
sourceCode[i] = null;
}
};
compileOptions = function(filename) {
return {
filename: filename,
bare: opts.bare,
header: opts.compile
};
};
forkNode = function() {
var args, nodeArgs;
nodeArgs = opts.nodejs.split(/\s+/);
args = process.argv.slice(1);
args.splice(args.indexOf('--nodejs'), 2);
return spawn(process.execPath, nodeArgs.concat(args), {
cwd: process.cwd(),
env: process.env,
customFds: [0, 1, 2]
});
};
usage = function() {
return printLine((new optparse.OptionParser(SWITCHES, BANNER)).help());
};
version = function() {
return printLine("CoffeeScript version " + CoffeeScript.VERSION);
};
}).call(this);

View File

@ -1,606 +0,0 @@
// Generated by CoffeeScript 1.3.3
(function() {
var Parser, alt, alternatives, grammar, name, o, operators, token, tokens, unwrap;
Parser = require('jison').Parser;
unwrap = /^function\s*\(\)\s*\{\s*return\s*([\s\S]*);\s*\}/;
o = function(patternString, action, options) {
var match;
patternString = patternString.replace(/\s{2,}/g, ' ');
if (!action) {
return [patternString, '$$ = $1;', options];
}
action = (match = unwrap.exec(action)) ? match[1] : "(" + action + "())";
action = action.replace(/\bnew /g, '$&yy.');
action = action.replace(/\b(?:Block\.wrap|extend)\b/g, 'yy.$&');
return [patternString, "$$ = " + action + ";", options];
};
grammar = {
Root: [
o('', function() {
return new Block;
}), o('Body'), o('Block TERMINATOR')
],
Body: [
o('Line', function() {
return Block.wrap([$1]);
}), o('Body TERMINATOR Line', function() {
return $1.push($3);
}), o('Body TERMINATOR')
],
Line: [o('Expression'), o('Statement')],
Statement: [
o('Return'), o('Comment'), o('STATEMENT', function() {
return new Literal($1);
})
],
Expression: [o('Value'), o('Invocation'), o('Code'), o('Operation'), o('Assign'), o('If'), o('Try'), o('While'), o('For'), o('Switch'), o('Class'), o('Throw')],
Block: [
o('INDENT OUTDENT', function() {
return new Block;
}), o('INDENT Body OUTDENT', function() {
return $2;
})
],
Identifier: [
o('IDENTIFIER', function() {
return new Literal($1);
})
],
AlphaNumeric: [
o('NUMBER', function() {
return new Literal($1);
}), o('STRING', function() {
return new Literal($1);
})
],
Literal: [
o('AlphaNumeric'), o('JS', function() {
return new Literal($1);
}), o('REGEX', function() {
return new Literal($1);
}), o('DEBUGGER', function() {
return new Literal($1);
}), o('UNDEFINED', function() {
return new Undefined;
}), o('NULL', function() {
return new Null;
}), o('BOOL', function() {
return new Bool($1);
})
],
Assign: [
o('Assignable = Expression', function() {
return new Assign($1, $3);
}), o('Assignable = TERMINATOR Expression', function() {
return new Assign($1, $4);
}), o('Assignable = INDENT Expression OUTDENT', function() {
return new Assign($1, $4);
})
],
AssignObj: [
o('ObjAssignable', function() {
return new Value($1);
}), o('ObjAssignable : Expression', function() {
return new Assign(new Value($1), $3, 'object');
}), o('ObjAssignable :\
INDENT Expression OUTDENT', function() {
return new Assign(new Value($1), $4, 'object');
}), o('Comment')
],
ObjAssignable: [o('Identifier'), o('AlphaNumeric'), o('ThisProperty')],
Return: [
o('RETURN Expression', function() {
return new Return($2);
}), o('RETURN', function() {
return new Return;
})
],
Comment: [
o('HERECOMMENT', function() {
return new Comment($1);
})
],
Code: [
o('PARAM_START ParamList PARAM_END FuncGlyph Block', function() {
return new Code($2, $5, $4);
}), o('FuncGlyph Block', function() {
return new Code([], $2, $1);
})
],
FuncGlyph: [
o('->', function() {
return 'func';
}), o('=>', function() {
return 'boundfunc';
})
],
OptComma: [o(''), o(',')],
ParamList: [
o('', function() {
return [];
}), o('Param', function() {
return [$1];
}), o('ParamList , Param', function() {
return $1.concat($3);
}), o('ParamList OptComma TERMINATOR Param', function() {
return $1.concat($4);
}), o('ParamList OptComma INDENT ParamList OptComma OUTDENT', function() {
return $1.concat($4);
})
],
Param: [
o('ParamVar', function() {
return new Param($1);
}), o('ParamVar ...', function() {
return new Param($1, null, true);
}), o('ParamVar = Expression', function() {
return new Param($1, $3);
})
],
ParamVar: [o('Identifier'), o('ThisProperty'), o('Array'), o('Object')],
Splat: [
o('Expression ...', function() {
return new Splat($1);
})
],
SimpleAssignable: [
o('Identifier', function() {
return new Value($1);
}), o('Value Accessor', function() {
return $1.add($2);
}), o('Invocation Accessor', function() {
return new Value($1, [].concat($2));
}), o('ThisProperty')
],
Assignable: [
o('SimpleAssignable'), o('Array', function() {
return new Value($1);
}), o('Object', function() {
return new Value($1);
})
],
Value: [
o('Assignable'), o('Literal', function() {
return new Value($1);
}), o('Parenthetical', function() {
return new Value($1);
}), o('Range', function() {
return new Value($1);
}), o('This')
],
Accessor: [
o('. Identifier', function() {
return new Access($2);
}), o('?. Identifier', function() {
return new Access($2, 'soak');
}), o(':: Identifier', function() {
return [new Access(new Literal('prototype')), new Access($2)];
}), o('::', function() {
return new Access(new Literal('prototype'));
}), o('Index')
],
Index: [
o('INDEX_START IndexValue INDEX_END', function() {
return $2;
}), o('INDEX_SOAK Index', function() {
return extend($2, {
soak: true
});
})
],
IndexValue: [
o('Expression', function() {
return new Index($1);
}), o('Slice', function() {
return new Slice($1);
})
],
Object: [
o('{ AssignList OptComma }', function() {
return new Obj($2, $1.generated);
})
],
AssignList: [
o('', function() {
return [];
}), o('AssignObj', function() {
return [$1];
}), o('AssignList , AssignObj', function() {
return $1.concat($3);
}), o('AssignList OptComma TERMINATOR AssignObj', function() {
return $1.concat($4);
}), o('AssignList OptComma INDENT AssignList OptComma OUTDENT', function() {
return $1.concat($4);
})
],
Class: [
o('CLASS', function() {
return new Class;
}), o('CLASS Block', function() {
return new Class(null, null, $2);
}), o('CLASS EXTENDS Expression', function() {
return new Class(null, $3);
}), o('CLASS EXTENDS Expression Block', function() {
return new Class(null, $3, $4);
}), o('CLASS SimpleAssignable', function() {
return new Class($2);
}), o('CLASS SimpleAssignable Block', function() {
return new Class($2, null, $3);
}), o('CLASS SimpleAssignable EXTENDS Expression', function() {
return new Class($2, $4);
}), o('CLASS SimpleAssignable EXTENDS Expression Block', function() {
return new Class($2, $4, $5);
})
],
Invocation: [
o('Value OptFuncExist Arguments', function() {
return new Call($1, $3, $2);
}), o('Invocation OptFuncExist Arguments', function() {
return new Call($1, $3, $2);
}), o('SUPER', function() {
return new Call('super', [new Splat(new Literal('arguments'))]);
}), o('SUPER Arguments', function() {
return new Call('super', $2);
})
],
OptFuncExist: [
o('', function() {
return false;
}), o('FUNC_EXIST', function() {
return true;
})
],
Arguments: [
o('CALL_START CALL_END', function() {
return [];
}), o('CALL_START ArgList OptComma CALL_END', function() {
return $2;
})
],
This: [
o('THIS', function() {
return new Value(new Literal('this'));
}), o('@', function() {
return new Value(new Literal('this'));
})
],
ThisProperty: [
o('@ Identifier', function() {
return new Value(new Literal('this'), [new Access($2)], 'this');
})
],
Array: [
o('[ ]', function() {
return new Arr([]);
}), o('[ ArgList OptComma ]', function() {
return new Arr($2);
})
],
RangeDots: [
o('..', function() {
return 'inclusive';
}), o('...', function() {
return 'exclusive';
})
],
Range: [
o('[ Expression RangeDots Expression ]', function() {
return new Range($2, $4, $3);
})
],
Slice: [
o('Expression RangeDots Expression', function() {
return new Range($1, $3, $2);
}), o('Expression RangeDots', function() {
return new Range($1, null, $2);
}), o('RangeDots Expression', function() {
return new Range(null, $2, $1);
}), o('RangeDots', function() {
return new Range(null, null, $1);
})
],
ArgList: [
o('Arg', function() {
return [$1];
}), o('ArgList , Arg', function() {
return $1.concat($3);
}), o('ArgList OptComma TERMINATOR Arg', function() {
return $1.concat($4);
}), o('INDENT ArgList OptComma OUTDENT', function() {
return $2;
}), o('ArgList OptComma INDENT ArgList OptComma OUTDENT', function() {
return $1.concat($4);
})
],
Arg: [o('Expression'), o('Splat')],
SimpleArgs: [
o('Expression'), o('SimpleArgs , Expression', function() {
return [].concat($1, $3);
})
],
Try: [
o('TRY Block', function() {
return new Try($2);
}), o('TRY Block Catch', function() {
return new Try($2, $3[0], $3[1]);
}), o('TRY Block FINALLY Block', function() {
return new Try($2, null, null, $4);
}), o('TRY Block Catch FINALLY Block', function() {
return new Try($2, $3[0], $3[1], $5);
})
],
Catch: [
o('CATCH Identifier Block', function() {
return [$2, $3];
})
],
Throw: [
o('THROW Expression', function() {
return new Throw($2);
})
],
Parenthetical: [
o('( Body )', function() {
return new Parens($2);
}), o('( INDENT Body OUTDENT )', function() {
return new Parens($3);
})
],
WhileSource: [
o('WHILE Expression', function() {
return new While($2);
}), o('WHILE Expression WHEN Expression', function() {
return new While($2, {
guard: $4
});
}), o('UNTIL Expression', function() {
return new While($2, {
invert: true
});
}), o('UNTIL Expression WHEN Expression', function() {
return new While($2, {
invert: true,
guard: $4
});
})
],
While: [
o('WhileSource Block', function() {
return $1.addBody($2);
}), o('Statement WhileSource', function() {
return $2.addBody(Block.wrap([$1]));
}), o('Expression WhileSource', function() {
return $2.addBody(Block.wrap([$1]));
}), o('Loop', function() {
return $1;
})
],
Loop: [
o('LOOP Block', function() {
return new While(new Literal('true')).addBody($2);
}), o('LOOP Expression', function() {
return new While(new Literal('true')).addBody(Block.wrap([$2]));
})
],
For: [
o('Statement ForBody', function() {
return new For($1, $2);
}), o('Expression ForBody', function() {
return new For($1, $2);
}), o('ForBody Block', function() {
return new For($2, $1);
})
],
ForBody: [
o('FOR Range', function() {
return {
source: new Value($2)
};
}), o('ForStart ForSource', function() {
$2.own = $1.own;
$2.name = $1[0];
$2.index = $1[1];
return $2;
})
],
ForStart: [
o('FOR ForVariables', function() {
return $2;
}), o('FOR OWN ForVariables', function() {
$3.own = true;
return $3;
})
],
ForValue: [
o('Identifier'), o('ThisProperty'), o('Array', function() {
return new Value($1);
}), o('Object', function() {
return new Value($1);
})
],
ForVariables: [
o('ForValue', function() {
return [$1];
}), o('ForValue , ForValue', function() {
return [$1, $3];
})
],
ForSource: [
o('FORIN Expression', function() {
return {
source: $2
};
}), o('FOROF Expression', function() {
return {
source: $2,
object: true
};
}), o('FORIN Expression WHEN Expression', function() {
return {
source: $2,
guard: $4
};
}), o('FOROF Expression WHEN Expression', function() {
return {
source: $2,
guard: $4,
object: true
};
}), o('FORIN Expression BY Expression', function() {
return {
source: $2,
step: $4
};
}), o('FORIN Expression WHEN Expression BY Expression', function() {
return {
source: $2,
guard: $4,
step: $6
};
}), o('FORIN Expression BY Expression WHEN Expression', function() {
return {
source: $2,
step: $4,
guard: $6
};
})
],
Switch: [
o('SWITCH Expression INDENT Whens OUTDENT', function() {
return new Switch($2, $4);
}), o('SWITCH Expression INDENT Whens ELSE Block OUTDENT', function() {
return new Switch($2, $4, $6);
}), o('SWITCH INDENT Whens OUTDENT', function() {
return new Switch(null, $3);
}), o('SWITCH INDENT Whens ELSE Block OUTDENT', function() {
return new Switch(null, $3, $5);
})
],
Whens: [
o('When'), o('Whens When', function() {
return $1.concat($2);
})
],
When: [
o('LEADING_WHEN SimpleArgs Block', function() {
return [[$2, $3]];
}), o('LEADING_WHEN SimpleArgs Block TERMINATOR', function() {
return [[$2, $3]];
})
],
IfBlock: [
o('IF Expression Block', function() {
return new If($2, $3, {
type: $1
});
}), o('IfBlock ELSE IF Expression Block', function() {
return $1.addElse(new If($4, $5, {
type: $3
}));
})
],
If: [
o('IfBlock'), o('IfBlock ELSE Block', function() {
return $1.addElse($3);
}), o('Statement POST_IF Expression', function() {
return new If($3, Block.wrap([$1]), {
type: $2,
statement: true
});
}), o('Expression POST_IF Expression', function() {
return new If($3, Block.wrap([$1]), {
type: $2,
statement: true
});
})
],
Operation: [
o('UNARY Expression', function() {
return new Op($1, $2);
}), o('- Expression', (function() {
return new Op('-', $2);
}), {
prec: 'UNARY'
}), o('+ Expression', (function() {
return new Op('+', $2);
}), {
prec: 'UNARY'
}), o('-- SimpleAssignable', function() {
return new Op('--', $2);
}), o('++ SimpleAssignable', function() {
return new Op('++', $2);
}), o('SimpleAssignable --', function() {
return new Op('--', $1, null, true);
}), o('SimpleAssignable ++', function() {
return new Op('++', $1, null, true);
}), o('Expression ?', function() {
return new Existence($1);
}), o('Expression + Expression', function() {
return new Op('+', $1, $3);
}), o('Expression - Expression', function() {
return new Op('-', $1, $3);
}), o('Expression MATH Expression', function() {
return new Op($2, $1, $3);
}), o('Expression SHIFT Expression', function() {
return new Op($2, $1, $3);
}), o('Expression COMPARE Expression', function() {
return new Op($2, $1, $3);
}), o('Expression LOGIC Expression', function() {
return new Op($2, $1, $3);
}), o('Expression RELATION Expression', function() {
if ($2.charAt(0) === '!') {
return new Op($2.slice(1), $1, $3).invert();
} else {
return new Op($2, $1, $3);
}
}), o('SimpleAssignable COMPOUND_ASSIGN\
Expression', function() {
return new Assign($1, $3, $2);
}), o('SimpleAssignable COMPOUND_ASSIGN\
INDENT Expression OUTDENT', function() {
return new Assign($1, $4, $2);
}), o('SimpleAssignable EXTENDS Expression', function() {
return new Extends($1, $3);
})
]
};
operators = [['left', '.', '?.', '::'], ['left', 'CALL_START', 'CALL_END'], ['nonassoc', '++', '--'], ['left', '?'], ['right', 'UNARY'], ['left', 'MATH'], ['left', '+', '-'], ['left', 'SHIFT'], ['left', 'RELATION'], ['left', 'COMPARE'], ['left', 'LOGIC'], ['nonassoc', 'INDENT', 'OUTDENT'], ['right', '=', ':', 'COMPOUND_ASSIGN', 'RETURN', 'THROW', 'EXTENDS'], ['right', 'FORIN', 'FOROF', 'BY', 'WHEN'], ['right', 'IF', 'ELSE', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS'], ['right', 'POST_IF']];
tokens = [];
for (name in grammar) {
alternatives = grammar[name];
grammar[name] = (function() {
var _i, _j, _len, _len1, _ref, _results;
_results = [];
for (_i = 0, _len = alternatives.length; _i < _len; _i++) {
alt = alternatives[_i];
_ref = alt[0].split(' ');
for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
token = _ref[_j];
if (!grammar[token]) {
tokens.push(token);
}
}
if (name === 'Root') {
alt[1] = "return " + alt[1];
}
_results.push(alt);
}
return _results;
})();
}
exports.parser = new Parser({
tokens: tokens.join(' '),
bnf: grammar,
operators: operators.reverse(),
startSymbol: 'Root'
});
}).call(this);

View File

@ -1,77 +0,0 @@
// Generated by CoffeeScript 1.3.3
(function() {
var extend, flatten;
exports.starts = function(string, literal, start) {
return literal === string.substr(start, literal.length);
};
exports.ends = function(string, literal, back) {
var len;
len = literal.length;
return literal === string.substr(string.length - len - (back || 0), len);
};
exports.compact = function(array) {
var item, _i, _len, _results;
_results = [];
for (_i = 0, _len = array.length; _i < _len; _i++) {
item = array[_i];
if (item) {
_results.push(item);
}
}
return _results;
};
exports.count = function(string, substr) {
var num, pos;
num = pos = 0;
if (!substr.length) {
return 1 / 0;
}
while (pos = 1 + string.indexOf(substr, pos)) {
num++;
}
return num;
};
exports.merge = function(options, overrides) {
return extend(extend({}, options), overrides);
};
extend = exports.extend = function(object, properties) {
var key, val;
for (key in properties) {
val = properties[key];
object[key] = val;
}
return object;
};
exports.flatten = flatten = function(array) {
var element, flattened, _i, _len;
flattened = [];
for (_i = 0, _len = array.length; _i < _len; _i++) {
element = array[_i];
if (element instanceof Array) {
flattened = flattened.concat(flatten(element));
} else {
flattened.push(element);
}
}
return flattened;
};
exports.del = function(obj, key) {
var val;
val = obj[key];
delete obj[key];
return val;
};
exports.last = function(array, back) {
return array[array.length - (back || 0) - 1];
};
}).call(this);

View File

@ -1,11 +0,0 @@
// Generated by CoffeeScript 1.3.3
(function() {
var key, val, _ref;
_ref = require('./coffee-script');
for (key in _ref) {
val = _ref[key];
exports[key] = val;
}
}).call(this);

View File

@ -1,788 +0,0 @@
// Generated by CoffeeScript 1.3.3
(function() {
var BOOL, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_ALIAS_MAP, COFFEE_KEYWORDS, COMMENT, COMPARE, COMPOUND_ASSIGN, HEREDOC, HEREDOC_ILLEGAL, HEREDOC_INDENT, HEREGEX, HEREGEX_OMIT, IDENTIFIER, INDEXABLE, INVERSES, JSTOKEN, JS_FORBIDDEN, JS_KEYWORDS, LINE_BREAK, LINE_CONTINUER, LOGIC, Lexer, MATH, MULTILINER, MULTI_DENT, NOT_REGEX, NOT_SPACED_REGEX, NUMBER, OPERATOR, REGEX, RELATION, RESERVED, Rewriter, SHIFT, SIMPLESTR, STRICT_PROSCRIBED, TRAILING_SPACES, UNARY, WHITESPACE, compact, count, key, last, starts, _ref, _ref1,
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
_ref = require('./rewriter'), Rewriter = _ref.Rewriter, INVERSES = _ref.INVERSES;
_ref1 = require('./helpers'), count = _ref1.count, starts = _ref1.starts, compact = _ref1.compact, last = _ref1.last;
exports.Lexer = Lexer = (function() {
function Lexer() {}
Lexer.prototype.tokenize = function(code, opts) {
var i, tag;
if (opts == null) {
opts = {};
}
if (WHITESPACE.test(code)) {
code = "\n" + code;
}
code = code.replace(/\r/g, '').replace(TRAILING_SPACES, '');
this.code = code;
this.line = opts.line || 0;
this.indent = 0;
this.indebt = 0;
this.outdebt = 0;
this.indents = [];
this.ends = [];
this.tokens = [];
i = 0;
while (this.chunk = code.slice(i)) {
i += this.identifierToken() || this.commentToken() || this.whitespaceToken() || this.lineToken() || this.heredocToken() || this.stringToken() || this.numberToken() || this.regexToken() || this.jsToken() || this.literalToken();
}
this.closeIndentation();
if (tag = this.ends.pop()) {
this.error("missing " + tag);
}
if (opts.rewrite === false) {
return this.tokens;
}
return (new Rewriter).rewrite(this.tokens);
};
Lexer.prototype.identifierToken = function() {
var colon, forcedIdentifier, id, input, match, prev, tag, _ref2, _ref3;
if (!(match = IDENTIFIER.exec(this.chunk))) {
return 0;
}
input = match[0], id = match[1], colon = match[2];
if (id === 'own' && this.tag() === 'FOR') {
this.token('OWN', id);
return id.length;
}
forcedIdentifier = colon || (prev = last(this.tokens)) && (((_ref2 = prev[0]) === '.' || _ref2 === '?.' || _ref2 === '::') || !prev.spaced && prev[0] === '@');
tag = 'IDENTIFIER';
if (!forcedIdentifier && (__indexOf.call(JS_KEYWORDS, id) >= 0 || __indexOf.call(COFFEE_KEYWORDS, id) >= 0)) {
tag = id.toUpperCase();
if (tag === 'WHEN' && (_ref3 = this.tag(), __indexOf.call(LINE_BREAK, _ref3) >= 0)) {
tag = 'LEADING_WHEN';
} else if (tag === 'FOR') {
this.seenFor = true;
} else if (tag === 'UNLESS') {
tag = 'IF';
} else if (__indexOf.call(UNARY, tag) >= 0) {
tag = 'UNARY';
} else if (__indexOf.call(RELATION, tag) >= 0) {
if (tag !== 'INSTANCEOF' && this.seenFor) {
tag = 'FOR' + tag;
this.seenFor = false;
} else {
tag = 'RELATION';
if (this.value() === '!') {
this.tokens.pop();
id = '!' + id;
}
}
}
}
if (__indexOf.call(JS_FORBIDDEN, id) >= 0) {
if (forcedIdentifier) {
tag = 'IDENTIFIER';
id = new String(id);
id.reserved = true;
} else if (__indexOf.call(RESERVED, id) >= 0) {
this.error("reserved word \"" + id + "\"");
}
}
if (!forcedIdentifier) {
if (__indexOf.call(COFFEE_ALIASES, id) >= 0) {
id = COFFEE_ALIAS_MAP[id];
}
tag = (function() {
switch (id) {
case '!':
return 'UNARY';
case '==':
case '!=':
return 'COMPARE';
case '&&':
case '||':
return 'LOGIC';
case 'true':
case 'false':
return 'BOOL';
case 'break':
case 'continue':
return 'STATEMENT';
default:
return tag;
}
})();
}
this.token(tag, id);
if (colon) {
this.token(':', ':');
}
return input.length;
};
Lexer.prototype.numberToken = function() {
var binaryLiteral, lexedLength, match, number, octalLiteral;
if (!(match = NUMBER.exec(this.chunk))) {
return 0;
}
number = match[0];
if (/^0[BOX]/.test(number)) {
this.error("radix prefix '" + number + "' must be lowercase");
} else if (/E/.test(number) && !/^0x/.test(number)) {
this.error("exponential notation '" + number + "' must be indicated with a lowercase 'e'");
} else if (/^0\d*[89]/.test(number)) {
this.error("decimal literal '" + number + "' must not be prefixed with '0'");
} else if (/^0\d+/.test(number)) {
this.error("octal literal '" + number + "' must be prefixed with '0o'");
}
lexedLength = number.length;
if (octalLiteral = /^0o([0-7]+)/.exec(number)) {
number = '0x' + (parseInt(octalLiteral[1], 8)).toString(16);
}
if (binaryLiteral = /^0b([01]+)/.exec(number)) {
number = '0x' + (parseInt(binaryLiteral[1], 2)).toString(16);
}
this.token('NUMBER', number);
return lexedLength;
};
Lexer.prototype.stringToken = function() {
var match, octalEsc, string;
switch (this.chunk.charAt(0)) {
case "'":
if (!(match = SIMPLESTR.exec(this.chunk))) {
return 0;
}
this.token('STRING', (string = match[0]).replace(MULTILINER, '\\\n'));
break;
case '"':
if (!(string = this.balancedString(this.chunk, '"'))) {
return 0;
}
if (0 < string.indexOf('#{', 1)) {
this.interpolateString(string.slice(1, -1));
} else {
this.token('STRING', this.escapeLines(string));
}
break;
default:
return 0;
}
if (octalEsc = /^(?:\\.|[^\\])*\\(?:0[0-7]|[1-7])/.test(string)) {
this.error("octal escape sequences " + string + " are not allowed");
}
this.line += count(string, '\n');
return string.length;
};
Lexer.prototype.heredocToken = function() {
var doc, heredoc, match, quote;
if (!(match = HEREDOC.exec(this.chunk))) {
return 0;
}
heredoc = match[0];
quote = heredoc.charAt(0);
doc = this.sanitizeHeredoc(match[2], {
quote: quote,
indent: null
});
if (quote === '"' && 0 <= doc.indexOf('#{')) {
this.interpolateString(doc, {
heredoc: true
});
} else {
this.token('STRING', this.makeString(doc, quote, true));
}
this.line += count(heredoc, '\n');
return heredoc.length;
};
Lexer.prototype.commentToken = function() {
var comment, here, match;
if (!(match = this.chunk.match(COMMENT))) {
return 0;
}
comment = match[0], here = match[1];
if (here) {
this.token('HERECOMMENT', this.sanitizeHeredoc(here, {
herecomment: true,
indent: Array(this.indent + 1).join(' ')
}));
}
this.line += count(comment, '\n');
return comment.length;
};
Lexer.prototype.jsToken = function() {
var match, script;
if (!(this.chunk.charAt(0) === '`' && (match = JSTOKEN.exec(this.chunk)))) {
return 0;
}
this.token('JS', (script = match[0]).slice(1, -1));
return script.length;
};
Lexer.prototype.regexToken = function() {
var flags, length, match, prev, regex, _ref2, _ref3;
if (this.chunk.charAt(0) !== '/') {
return 0;
}
if (match = HEREGEX.exec(this.chunk)) {
length = this.heregexToken(match);
this.line += count(match[0], '\n');
return length;
}
prev = last(this.tokens);
if (prev && (_ref2 = prev[0], __indexOf.call((prev.spaced ? NOT_REGEX : NOT_SPACED_REGEX), _ref2) >= 0)) {
return 0;
}
if (!(match = REGEX.exec(this.chunk))) {
return 0;
}
_ref3 = match, match = _ref3[0], regex = _ref3[1], flags = _ref3[2];
if (regex.slice(0, 2) === '/*') {
this.error('regular expressions cannot begin with `*`');
}
if (regex === '//') {
regex = '/(?:)/';
}
this.token('REGEX', "" + regex + flags);
return match.length;
};
Lexer.prototype.heregexToken = function(match) {
var body, flags, heregex, re, tag, tokens, value, _i, _len, _ref2, _ref3, _ref4, _ref5;
heregex = match[0], body = match[1], flags = match[2];
if (0 > body.indexOf('#{')) {
re = body.replace(HEREGEX_OMIT, '').replace(/\//g, '\\/');
if (re.match(/^\*/)) {
this.error('regular expressions cannot begin with `*`');
}
this.token('REGEX', "/" + (re || '(?:)') + "/" + flags);
return heregex.length;
}
this.token('IDENTIFIER', 'RegExp');
this.tokens.push(['CALL_START', '(']);
tokens = [];
_ref2 = this.interpolateString(body, {
regex: true
});
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
_ref3 = _ref2[_i], tag = _ref3[0], value = _ref3[1];
if (tag === 'TOKENS') {
tokens.push.apply(tokens, value);
} else {
if (!(value = value.replace(HEREGEX_OMIT, ''))) {
continue;
}
value = value.replace(/\\/g, '\\\\');
tokens.push(['STRING', this.makeString(value, '"', true)]);
}
tokens.push(['+', '+']);
}
tokens.pop();
if (((_ref4 = tokens[0]) != null ? _ref4[0] : void 0) !== 'STRING') {
this.tokens.push(['STRING', '""'], ['+', '+']);
}
(_ref5 = this.tokens).push.apply(_ref5, tokens);
if (flags) {
this.tokens.push([',', ','], ['STRING', '"' + flags + '"']);
}
this.token(')', ')');
return heregex.length;
};
Lexer.prototype.lineToken = function() {
var diff, indent, match, noNewlines, prev, size;
if (!(match = MULTI_DENT.exec(this.chunk))) {
return 0;
}
indent = match[0];
this.line += count(indent, '\n');
this.seenFor = false;
prev = last(this.tokens, 1);
size = indent.length - 1 - indent.lastIndexOf('\n');
noNewlines = this.unfinished();
if (size - this.indebt === this.indent) {
if (noNewlines) {
this.suppressNewlines();
} else {
this.newlineToken();
}
return indent.length;
}
if (size > this.indent) {
if (noNewlines) {
this.indebt = size - this.indent;
this.suppressNewlines();
return indent.length;
}
diff = size - this.indent + this.outdebt;
this.token('INDENT', diff);
this.indents.push(diff);
this.ends.push('OUTDENT');
this.outdebt = this.indebt = 0;
} else {
this.indebt = 0;
this.outdentToken(this.indent - size, noNewlines);
}
this.indent = size;
return indent.length;
};
Lexer.prototype.outdentToken = function(moveOut, noNewlines) {
var dent, len;
while (moveOut > 0) {
len = this.indents.length - 1;
if (this.indents[len] === void 0) {
moveOut = 0;
} else if (this.indents[len] === this.outdebt) {
moveOut -= this.outdebt;
this.outdebt = 0;
} else if (this.indents[len] < this.outdebt) {
this.outdebt -= this.indents[len];
moveOut -= this.indents[len];
} else {
dent = this.indents.pop() - this.outdebt;
moveOut -= dent;
this.outdebt = 0;
this.pair('OUTDENT');
this.token('OUTDENT', dent);
}
}
if (dent) {
this.outdebt -= moveOut;
}
while (this.value() === ';') {
this.tokens.pop();
}
if (!(this.tag() === 'TERMINATOR' || noNewlines)) {
this.token('TERMINATOR', '\n');
}
return this;
};
Lexer.prototype.whitespaceToken = function() {
var match, nline, prev;
if (!((match = WHITESPACE.exec(this.chunk)) || (nline = this.chunk.charAt(0) === '\n'))) {
return 0;
}
prev = last(this.tokens);
if (prev) {
prev[match ? 'spaced' : 'newLine'] = true;
}
if (match) {
return match[0].length;
} else {
return 0;
}
};
Lexer.prototype.newlineToken = function() {
while (this.value() === ';') {
this.tokens.pop();
}
if (this.tag() !== 'TERMINATOR') {
this.token('TERMINATOR', '\n');
}
return this;
};
Lexer.prototype.suppressNewlines = function() {
if (this.value() === '\\') {
this.tokens.pop();
}
return this;
};
Lexer.prototype.literalToken = function() {
var match, prev, tag, value, _ref2, _ref3, _ref4, _ref5;
if (match = OPERATOR.exec(this.chunk)) {
value = match[0];
if (CODE.test(value)) {
this.tagParameters();
}
} else {
value = this.chunk.charAt(0);
}
tag = value;
prev = last(this.tokens);
if (value === '=' && prev) {
if (!prev[1].reserved && (_ref2 = prev[1], __indexOf.call(JS_FORBIDDEN, _ref2) >= 0)) {
this.error("reserved word \"" + (this.value()) + "\" can't be assigned");
}
if ((_ref3 = prev[1]) === '||' || _ref3 === '&&') {
prev[0] = 'COMPOUND_ASSIGN';
prev[1] += '=';
return value.length;
}
}
if (value === ';') {
this.seenFor = false;
tag = 'TERMINATOR';
} else if (__indexOf.call(MATH, value) >= 0) {
tag = 'MATH';
} else if (__indexOf.call(COMPARE, value) >= 0) {
tag = 'COMPARE';
} else if (__indexOf.call(COMPOUND_ASSIGN, value) >= 0) {
tag = 'COMPOUND_ASSIGN';
} else if (__indexOf.call(UNARY, value) >= 0) {
tag = 'UNARY';
} else if (__indexOf.call(SHIFT, value) >= 0) {
tag = 'SHIFT';
} else if (__indexOf.call(LOGIC, value) >= 0 || value === '?' && (prev != null ? prev.spaced : void 0)) {
tag = 'LOGIC';
} else if (prev && !prev.spaced) {
if (value === '(' && (_ref4 = prev[0], __indexOf.call(CALLABLE, _ref4) >= 0)) {
if (prev[0] === '?') {
prev[0] = 'FUNC_EXIST';
}
tag = 'CALL_START';
} else if (value === '[' && (_ref5 = prev[0], __indexOf.call(INDEXABLE, _ref5) >= 0)) {
tag = 'INDEX_START';
switch (prev[0]) {
case '?':
prev[0] = 'INDEX_SOAK';
}
}
}
switch (value) {
case '(':
case '{':
case '[':
this.ends.push(INVERSES[value]);
break;
case ')':
case '}':
case ']':
this.pair(value);
}
this.token(tag, value);
return value.length;
};
Lexer.prototype.sanitizeHeredoc = function(doc, options) {
var attempt, herecomment, indent, match, _ref2;
indent = options.indent, herecomment = options.herecomment;
if (herecomment) {
if (HEREDOC_ILLEGAL.test(doc)) {
this.error("block comment cannot contain \"*/\", starting");
}
if (doc.indexOf('\n') <= 0) {
return doc;
}
} else {
while (match = HEREDOC_INDENT.exec(doc)) {
attempt = match[1];
if (indent === null || (0 < (_ref2 = attempt.length) && _ref2 < indent.length)) {
indent = attempt;
}
}
}
if (indent) {
doc = doc.replace(RegExp("\\n" + indent, "g"), '\n');
}
if (!herecomment) {
doc = doc.replace(/^\n/, '');
}
return doc;
};
Lexer.prototype.tagParameters = function() {
var i, stack, tok, tokens;
if (this.tag() !== ')') {
return this;
}
stack = [];
tokens = this.tokens;
i = tokens.length;
tokens[--i][0] = 'PARAM_END';
while (tok = tokens[--i]) {
switch (tok[0]) {
case ')':
stack.push(tok);
break;
case '(':
case 'CALL_START':
if (stack.length) {
stack.pop();
} else if (tok[0] === '(') {
tok[0] = 'PARAM_START';
return this;
} else {
return this;
}
}
}
return this;
};
Lexer.prototype.closeIndentation = function() {
return this.outdentToken(this.indent);
};
Lexer.prototype.balancedString = function(str, end) {
var continueCount, i, letter, match, prev, stack, _i, _ref2;
continueCount = 0;
stack = [end];
for (i = _i = 1, _ref2 = str.length; 1 <= _ref2 ? _i < _ref2 : _i > _ref2; i = 1 <= _ref2 ? ++_i : --_i) {
if (continueCount) {
--continueCount;
continue;
}
switch (letter = str.charAt(i)) {
case '\\':
++continueCount;
continue;
case end:
stack.pop();
if (!stack.length) {
return str.slice(0, i + 1 || 9e9);
}
end = stack[stack.length - 1];
continue;
}
if (end === '}' && (letter === '"' || letter === "'")) {
stack.push(end = letter);
} else if (end === '}' && letter === '/' && (match = HEREGEX.exec(str.slice(i)) || REGEX.exec(str.slice(i)))) {
continueCount += match[0].length - 1;
} else if (end === '}' && letter === '{') {
stack.push(end = '}');
} else if (end === '"' && prev === '#' && letter === '{') {
stack.push(end = '}');
}
prev = letter;
}
return this.error("missing " + (stack.pop()) + ", starting");
};
Lexer.prototype.interpolateString = function(str, options) {
var expr, heredoc, i, inner, interpolated, len, letter, nested, pi, regex, tag, tokens, value, _i, _len, _ref2, _ref3, _ref4;
if (options == null) {
options = {};
}
heredoc = options.heredoc, regex = options.regex;
tokens = [];
pi = 0;
i = -1;
while (letter = str.charAt(i += 1)) {
if (letter === '\\') {
i += 1;
continue;
}
if (!(letter === '#' && str.charAt(i + 1) === '{' && (expr = this.balancedString(str.slice(i + 1), '}')))) {
continue;
}
if (pi < i) {
tokens.push(['NEOSTRING', str.slice(pi, i)]);
}
inner = expr.slice(1, -1);
if (inner.length) {
nested = new Lexer().tokenize(inner, {
line: this.line,
rewrite: false
});
nested.pop();
if (((_ref2 = nested[0]) != null ? _ref2[0] : void 0) === 'TERMINATOR') {
nested.shift();
}
if (len = nested.length) {
if (len > 1) {
nested.unshift(['(', '(', this.line]);
nested.push([')', ')', this.line]);
}
tokens.push(['TOKENS', nested]);
}
}
i += expr.length;
pi = i + 1;
}
if ((i > pi && pi < str.length)) {
tokens.push(['NEOSTRING', str.slice(pi)]);
}
if (regex) {
return tokens;
}
if (!tokens.length) {
return this.token('STRING', '""');
}
if (tokens[0][0] !== 'NEOSTRING') {
tokens.unshift(['', '']);
}
if (interpolated = tokens.length > 1) {
this.token('(', '(');
}
for (i = _i = 0, _len = tokens.length; _i < _len; i = ++_i) {
_ref3 = tokens[i], tag = _ref3[0], value = _ref3[1];
if (i) {
this.token('+', '+');
}
if (tag === 'TOKENS') {
(_ref4 = this.tokens).push.apply(_ref4, value);
} else {
this.token('STRING', this.makeString(value, '"', heredoc));
}
}
if (interpolated) {
this.token(')', ')');
}
return tokens;
};
Lexer.prototype.pair = function(tag) {
var size, wanted;
if (tag !== (wanted = last(this.ends))) {
if ('OUTDENT' !== wanted) {
this.error("unmatched " + tag);
}
this.indent -= size = last(this.indents);
this.outdentToken(size, true);
return this.pair(tag);
}
return this.ends.pop();
};
Lexer.prototype.token = function(tag, value) {
return this.tokens.push([tag, value, this.line]);
};
Lexer.prototype.tag = function(index, tag) {
var tok;
return (tok = last(this.tokens, index)) && (tag ? tok[0] = tag : tok[0]);
};
Lexer.prototype.value = function(index, val) {
var tok;
return (tok = last(this.tokens, index)) && (val ? tok[1] = val : tok[1]);
};
Lexer.prototype.unfinished = function() {
var _ref2;
return LINE_CONTINUER.test(this.chunk) || ((_ref2 = this.tag()) === '\\' || _ref2 === '.' || _ref2 === '?.' || _ref2 === 'UNARY' || _ref2 === 'MATH' || _ref2 === '+' || _ref2 === '-' || _ref2 === 'SHIFT' || _ref2 === 'RELATION' || _ref2 === 'COMPARE' || _ref2 === 'LOGIC' || _ref2 === 'THROW' || _ref2 === 'EXTENDS');
};
Lexer.prototype.escapeLines = function(str, heredoc) {
return str.replace(MULTILINER, heredoc ? '\\n' : '');
};
Lexer.prototype.makeString = function(body, quote, heredoc) {
if (!body) {
return quote + quote;
}
body = body.replace(/\\([\s\S])/g, function(match, contents) {
if (contents === '\n' || contents === quote) {
return contents;
} else {
return match;
}
});
body = body.replace(RegExp("" + quote, "g"), '\\$&');
return quote + this.escapeLines(body, heredoc) + quote;
};
Lexer.prototype.error = function(message) {
throw SyntaxError("" + message + " on line " + (this.line + 1));
};
return Lexer;
})();
JS_KEYWORDS = ['true', 'false', 'null', 'this', 'new', 'delete', 'typeof', 'in', 'instanceof', 'return', 'throw', 'break', 'continue', 'debugger', 'if', 'else', 'switch', 'for', 'while', 'do', 'try', 'catch', 'finally', 'class', 'extends', 'super'];
COFFEE_KEYWORDS = ['undefined', 'then', 'unless', 'until', 'loop', 'of', 'by', 'when'];
COFFEE_ALIAS_MAP = {
and: '&&',
or: '||',
is: '==',
isnt: '!=',
not: '!',
yes: 'true',
no: 'false',
on: 'true',
off: 'false'
};
COFFEE_ALIASES = (function() {
var _results;
_results = [];
for (key in COFFEE_ALIAS_MAP) {
_results.push(key);
}
return _results;
})();
COFFEE_KEYWORDS = COFFEE_KEYWORDS.concat(COFFEE_ALIASES);
RESERVED = ['case', 'default', 'function', 'var', 'void', 'with', 'const', 'let', 'enum', 'export', 'import', 'native', '__hasProp', '__extends', '__slice', '__bind', '__indexOf', 'implements', 'interface', 'let', 'package', 'private', 'protected', 'public', 'static', 'yield'];
STRICT_PROSCRIBED = ['arguments', 'eval'];
JS_FORBIDDEN = JS_KEYWORDS.concat(RESERVED).concat(STRICT_PROSCRIBED);
exports.RESERVED = RESERVED.concat(JS_KEYWORDS).concat(COFFEE_KEYWORDS).concat(STRICT_PROSCRIBED);
exports.STRICT_PROSCRIBED = STRICT_PROSCRIBED;
IDENTIFIER = /^([$A-Za-z_\x7f-\uffff][$\w\x7f-\uffff]*)([^\n\S]*:(?!:))?/;
NUMBER = /^0b[01]+|^0o[0-7]+|^0x[\da-f]+|^\d*\.?\d+(?:e[+-]?\d+)?/i;
HEREDOC = /^("""|''')([\s\S]*?)(?:\n[^\n\S]*)?\1/;
OPERATOR = /^(?:[-=]>|[-+*\/%<>&|^!?=]=|>>>=?|([-+:])\1|([&|<>])\2=?|\?\.|\.{2,3})/;
WHITESPACE = /^[^\n\S]+/;
COMMENT = /^###([^#][\s\S]*?)(?:###[^\n\S]*|(?:###)?$)|^(?:\s*#(?!##[^#]).*)+/;
CODE = /^[-=]>/;
MULTI_DENT = /^(?:\n[^\n\S]*)+/;
SIMPLESTR = /^'[^\\']*(?:\\.[^\\']*)*'/;
JSTOKEN = /^`[^\\`]*(?:\\.[^\\`]*)*`/;
REGEX = /^(\/(?![\s=])[^[\/\n\\]*(?:(?:\\[\s\S]|\[[^\]\n\\]*(?:\\[\s\S][^\]\n\\]*)*])[^[\/\n\\]*)*\/)([imgy]{0,4})(?!\w)/;
HEREGEX = /^\/{3}([\s\S]+?)\/{3}([imgy]{0,4})(?!\w)/;
HEREGEX_OMIT = /\s+(?:#.*)?/g;
MULTILINER = /\n/g;
HEREDOC_INDENT = /\n+([^\n\S]*)/g;
HEREDOC_ILLEGAL = /\*\//;
LINE_CONTINUER = /^\s*(?:,|\??\.(?![.\d])|::)/;
TRAILING_SPACES = /\s+$/;
COMPOUND_ASSIGN = ['-=', '+=', '/=', '*=', '%=', '||=', '&&=', '?=', '<<=', '>>=', '>>>=', '&=', '^=', '|='];
UNARY = ['!', '~', 'NEW', 'TYPEOF', 'DELETE', 'DO'];
LOGIC = ['&&', '||', '&', '|', '^'];
SHIFT = ['<<', '>>', '>>>'];
COMPARE = ['==', '!=', '<', '>', '<=', '>='];
MATH = ['*', '/', '%'];
RELATION = ['IN', 'OF', 'INSTANCEOF'];
BOOL = ['TRUE', 'FALSE'];
NOT_REGEX = ['NUMBER', 'REGEX', 'BOOL', 'NULL', 'UNDEFINED', '++', '--', ']'];
NOT_SPACED_REGEX = NOT_REGEX.concat(')', '}', 'THIS', 'IDENTIFIER', 'STRING');
CALLABLE = ['IDENTIFIER', 'STRING', 'REGEX', ')', ']', '}', '?', '::', '@', 'THIS', 'SUPER'];
INDEXABLE = CALLABLE.concat('NUMBER', 'BOOL', 'NULL', 'UNDEFINED');
LINE_BREAK = ['INDENT', 'OUTDENT', 'TERMINATOR'];
}).call(this);

File diff suppressed because it is too large Load Diff

View File

@ -1,138 +0,0 @@
// Generated by CoffeeScript 1.3.3
(function() {
var LONG_FLAG, MULTI_FLAG, OPTIONAL, OptionParser, SHORT_FLAG, buildRule, buildRules, normalizeArguments;
exports.OptionParser = OptionParser = (function() {
function OptionParser(rules, banner) {
this.banner = banner;
this.rules = buildRules(rules);
}
OptionParser.prototype.parse = function(args) {
var arg, i, isOption, matchedRule, options, originalArgs, pos, rule, seenNonOptionArg, skippingArgument, value, _i, _j, _len, _len1, _ref;
options = {
"arguments": []
};
skippingArgument = false;
originalArgs = args;
args = normalizeArguments(args);
for (i = _i = 0, _len = args.length; _i < _len; i = ++_i) {
arg = args[i];
if (skippingArgument) {
skippingArgument = false;
continue;
}
if (arg === '--') {
pos = originalArgs.indexOf('--');
options["arguments"] = options["arguments"].concat(originalArgs.slice(pos + 1));
break;
}
isOption = !!(arg.match(LONG_FLAG) || arg.match(SHORT_FLAG));
seenNonOptionArg = options["arguments"].length > 0;
if (!seenNonOptionArg) {
matchedRule = false;
_ref = this.rules;
for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
rule = _ref[_j];
if (rule.shortFlag === arg || rule.longFlag === arg) {
value = true;
if (rule.hasArgument) {
skippingArgument = true;
value = args[i + 1];
}
options[rule.name] = rule.isList ? (options[rule.name] || []).concat(value) : value;
matchedRule = true;
break;
}
}
if (isOption && !matchedRule) {
throw new Error("unrecognized option: " + arg);
}
}
if (seenNonOptionArg || !isOption) {
options["arguments"].push(arg);
}
}
return options;
};
OptionParser.prototype.help = function() {
var letPart, lines, rule, spaces, _i, _len, _ref;
lines = [];
if (this.banner) {
lines.unshift("" + this.banner + "\n");
}
_ref = this.rules;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
rule = _ref[_i];
spaces = 15 - rule.longFlag.length;
spaces = spaces > 0 ? Array(spaces + 1).join(' ') : '';
letPart = rule.shortFlag ? rule.shortFlag + ', ' : ' ';
lines.push(' ' + letPart + rule.longFlag + spaces + rule.description);
}
return "\n" + (lines.join('\n')) + "\n";
};
return OptionParser;
})();
LONG_FLAG = /^(--\w[\w\-]*)/;
SHORT_FLAG = /^(-\w)$/;
MULTI_FLAG = /^-(\w{2,})/;
OPTIONAL = /\[(\w+(\*?))\]/;
buildRules = function(rules) {
var tuple, _i, _len, _results;
_results = [];
for (_i = 0, _len = rules.length; _i < _len; _i++) {
tuple = rules[_i];
if (tuple.length < 3) {
tuple.unshift(null);
}
_results.push(buildRule.apply(null, tuple));
}
return _results;
};
buildRule = function(shortFlag, longFlag, description, options) {
var match;
if (options == null) {
options = {};
}
match = longFlag.match(OPTIONAL);
longFlag = longFlag.match(LONG_FLAG)[1];
return {
name: longFlag.substr(2),
shortFlag: shortFlag,
longFlag: longFlag,
description: description,
hasArgument: !!(match && match[1]),
isList: !!(match && match[2])
};
};
normalizeArguments = function(args) {
var arg, l, match, result, _i, _j, _len, _len1, _ref;
args = args.slice(0);
result = [];
for (_i = 0, _len = args.length; _i < _len; _i++) {
arg = args[_i];
if (match = arg.match(MULTI_FLAG)) {
_ref = match[1].split('');
for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
l = _ref[_j];
result.push('-' + l);
}
} else {
result.push(arg);
}
}
return result;
};
}).call(this);

File diff suppressed because one or more lines are too long

View File

@ -1,261 +0,0 @@
// Generated by CoffeeScript 1.3.3
(function() {
var ACCESSOR, CoffeeScript, Module, REPL_PROMPT, REPL_PROMPT_CONTINUATION, REPL_PROMPT_MULTILINE, SIMPLEVAR, Script, autocomplete, backlog, completeAttribute, completeVariable, enableColours, error, getCompletions, inspect, multilineMode, pipedInput, readline, repl, run, stdin, stdout;
stdin = process.openStdin();
stdout = process.stdout;
CoffeeScript = require('./coffee-script');
readline = require('readline');
inspect = require('util').inspect;
Script = require('vm').Script;
Module = require('module');
REPL_PROMPT = 'coffee> ';
REPL_PROMPT_MULTILINE = '------> ';
REPL_PROMPT_CONTINUATION = '......> ';
enableColours = false;
if (process.platform !== 'win32') {
enableColours = !process.env.NODE_DISABLE_COLORS;
}
error = function(err) {
return stdout.write((err.stack || err.toString()) + '\n');
};
ACCESSOR = /\s*([\w\.]+)(?:\.(\w*))$/;
SIMPLEVAR = /(\w+)$/i;
autocomplete = function(text) {
return completeAttribute(text) || completeVariable(text) || [[], text];
};
completeAttribute = function(text) {
var all, completions, key, match, obj, possibilities, prefix, val;
if (match = text.match(ACCESSOR)) {
all = match[0], obj = match[1], prefix = match[2];
try {
val = Script.runInThisContext(obj);
} catch (error) {
return;
}
val = Object(val);
possibilities = Object.getOwnPropertyNames(val);
for (key in val) {
if (~possibilities.indexOf(val)) {
possibilities.push(key);
}
}
completions = getCompletions(prefix, possibilities);
return [completions, prefix];
}
};
completeVariable = function(text) {
var completions, free, keywords, possibilities, r, vars, _ref;
free = (_ref = text.match(SIMPLEVAR)) != null ? _ref[1] : void 0;
if (text === "") {
free = "";
}
if (free != null) {
vars = Script.runInThisContext('Object.getOwnPropertyNames(Object(this))');
keywords = (function() {
var _i, _len, _ref1, _results;
_ref1 = CoffeeScript.RESERVED;
_results = [];
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
r = _ref1[_i];
if (r.slice(0, 2) !== '__') {
_results.push(r);
}
}
return _results;
})();
possibilities = vars.concat(keywords);
completions = getCompletions(free, possibilities);
return [completions, free];
}
};
getCompletions = function(prefix, candidates) {
var el, _i, _len, _results;
_results = [];
for (_i = 0, _len = candidates.length; _i < _len; _i++) {
el = candidates[_i];
if (el.indexOf(prefix) === 0) {
_results.push(el);
}
}
return _results;
};
process.on('uncaughtException', error);
backlog = '';
run = function(buffer) {
var code, returnValue, _;
buffer = buffer.replace(/(^|[\r\n]+)(\s*)##?(?:[^#\r\n][^\r\n]*|)($|[\r\n])/, "$1$2$3");
buffer = buffer.replace(/[\r\n]+$/, "");
if (multilineMode) {
backlog += "" + buffer + "\n";
repl.setPrompt(REPL_PROMPT_CONTINUATION);
repl.prompt();
return;
}
if (!buffer.toString().trim() && !backlog) {
repl.prompt();
return;
}
code = backlog += buffer;
if (code[code.length - 1] === '\\') {
backlog = "" + backlog.slice(0, -1) + "\n";
repl.setPrompt(REPL_PROMPT_CONTINUATION);
repl.prompt();
return;
}
repl.setPrompt(REPL_PROMPT);
backlog = '';
try {
_ = global._;
returnValue = CoffeeScript["eval"]("_=(" + code + "\n)", {
filename: 'repl',
modulename: 'repl'
});
if (returnValue === void 0) {
global._ = _;
}
repl.output.write("" + (inspect(returnValue, false, 2, enableColours)) + "\n");
} catch (err) {
error(err);
}
return repl.prompt();
};
if (stdin.readable) {
pipedInput = '';
repl = {
prompt: function() {
return stdout.write(this._prompt);
},
setPrompt: function(p) {
return this._prompt = p;
},
input: stdin,
output: stdout,
on: function() {}
};
stdin.on('data', function(chunk) {
var line, lines, _i, _len, _ref;
pipedInput += chunk;
if (!/\n/.test(pipedInput)) {
return;
}
lines = pipedInput.split("\n");
pipedInput = lines[lines.length - 1];
_ref = lines.slice(0, -1);
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
line = _ref[_i];
if (!(line)) {
continue;
}
stdout.write("" + line + "\n");
run(line);
}
});
stdin.on('end', function() {
var line, _i, _len, _ref;
_ref = pipedInput.trim().split("\n");
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
line = _ref[_i];
if (!(line)) {
continue;
}
stdout.write("" + line + "\n");
run(line);
}
stdout.write('\n');
return process.exit(0);
});
} else {
if (readline.createInterface.length < 3) {
repl = readline.createInterface(stdin, autocomplete);
stdin.on('data', function(buffer) {
return repl.write(buffer);
});
} else {
repl = readline.createInterface(stdin, stdout, autocomplete);
}
}
multilineMode = false;
repl.input.on('keypress', function(char, key) {
var cursorPos, newPrompt;
if (!(key && key.ctrl && !key.meta && !key.shift && key.name === 'v')) {
return;
}
cursorPos = repl.cursor;
repl.output.cursorTo(0);
repl.output.clearLine(1);
multilineMode = !multilineMode;
if (!multilineMode && backlog) {
repl._line();
}
backlog = '';
repl.setPrompt((newPrompt = multilineMode ? REPL_PROMPT_MULTILINE : REPL_PROMPT));
repl.prompt();
return repl.output.cursorTo(newPrompt.length + (repl.cursor = cursorPos));
});
repl.input.on('keypress', function(char, key) {
if (!(multilineMode && repl.line)) {
return;
}
if (!(key && key.ctrl && !key.meta && !key.shift && key.name === 'd')) {
return;
}
multilineMode = false;
return repl._line();
});
repl.on('attemptClose', function() {
if (multilineMode) {
multilineMode = false;
repl.output.cursorTo(0);
repl.output.clearLine(1);
repl._onLine(repl.line);
return;
}
if (backlog) {
backlog = '';
repl.output.write('\n');
repl.setPrompt(REPL_PROMPT);
return repl.prompt();
} else {
return repl.close();
}
});
repl.on('close', function() {
repl.output.write('\n');
return repl.input.destroy();
});
repl.on('line', run);
repl.setPrompt(REPL_PROMPT);
repl.prompt();
}).call(this);

View File

@ -1,349 +0,0 @@
// Generated by CoffeeScript 1.3.3
(function() {
var BALANCED_PAIRS, EXPRESSION_CLOSE, EXPRESSION_END, EXPRESSION_START, IMPLICIT_BLOCK, IMPLICIT_CALL, IMPLICIT_END, IMPLICIT_FUNC, IMPLICIT_UNSPACED_CALL, INVERSES, LINEBREAKS, SINGLE_CLOSERS, SINGLE_LINERS, left, rite, _i, _len, _ref,
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
__slice = [].slice;
exports.Rewriter = (function() {
function Rewriter() {}
Rewriter.prototype.rewrite = function(tokens) {
this.tokens = tokens;
this.removeLeadingNewlines();
this.removeMidExpressionNewlines();
this.closeOpenCalls();
this.closeOpenIndexes();
this.addImplicitIndentation();
this.tagPostfixConditionals();
this.addImplicitBraces();
this.addImplicitParentheses();
return this.tokens;
};
Rewriter.prototype.scanTokens = function(block) {
var i, token, tokens;
tokens = this.tokens;
i = 0;
while (token = tokens[i]) {
i += block.call(this, token, i, tokens);
}
return true;
};
Rewriter.prototype.detectEnd = function(i, condition, action) {
var levels, token, tokens, _ref, _ref1;
tokens = this.tokens;
levels = 0;
while (token = tokens[i]) {
if (levels === 0 && condition.call(this, token, i)) {
return action.call(this, token, i);
}
if (!token || levels < 0) {
return action.call(this, token, i - 1);
}
if (_ref = token[0], __indexOf.call(EXPRESSION_START, _ref) >= 0) {
levels += 1;
} else if (_ref1 = token[0], __indexOf.call(EXPRESSION_END, _ref1) >= 0) {
levels -= 1;
}
i += 1;
}
return i - 1;
};
Rewriter.prototype.removeLeadingNewlines = function() {
var i, tag, _i, _len, _ref;
_ref = this.tokens;
for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
tag = _ref[i][0];
if (tag !== 'TERMINATOR') {
break;
}
}
if (i) {
return this.tokens.splice(0, i);
}
};
Rewriter.prototype.removeMidExpressionNewlines = function() {
return this.scanTokens(function(token, i, tokens) {
var _ref;
if (!(token[0] === 'TERMINATOR' && (_ref = this.tag(i + 1), __indexOf.call(EXPRESSION_CLOSE, _ref) >= 0))) {
return 1;
}
tokens.splice(i, 1);
return 0;
});
};
Rewriter.prototype.closeOpenCalls = function() {
var action, condition;
condition = function(token, i) {
var _ref;
return ((_ref = token[0]) === ')' || _ref === 'CALL_END') || token[0] === 'OUTDENT' && this.tag(i - 1) === ')';
};
action = function(token, i) {
return this.tokens[token[0] === 'OUTDENT' ? i - 1 : i][0] = 'CALL_END';
};
return this.scanTokens(function(token, i) {
if (token[0] === 'CALL_START') {
this.detectEnd(i + 1, condition, action);
}
return 1;
});
};
Rewriter.prototype.closeOpenIndexes = function() {
var action, condition;
condition = function(token, i) {
var _ref;
return (_ref = token[0]) === ']' || _ref === 'INDEX_END';
};
action = function(token, i) {
return token[0] = 'INDEX_END';
};
return this.scanTokens(function(token, i) {
if (token[0] === 'INDEX_START') {
this.detectEnd(i + 1, condition, action);
}
return 1;
});
};
Rewriter.prototype.addImplicitBraces = function() {
var action, condition, sameLine, stack, start, startIndent, startIndex, startsLine;
stack = [];
start = null;
startsLine = null;
sameLine = true;
startIndent = 0;
startIndex = 0;
condition = function(token, i) {
var one, tag, three, two, _ref, _ref1;
_ref = this.tokens.slice(i + 1, (i + 3) + 1 || 9e9), one = _ref[0], two = _ref[1], three = _ref[2];
if ('HERECOMMENT' === (one != null ? one[0] : void 0)) {
return false;
}
tag = token[0];
if (__indexOf.call(LINEBREAKS, tag) >= 0) {
sameLine = false;
}
return (((tag === 'TERMINATOR' || tag === 'OUTDENT') || (__indexOf.call(IMPLICIT_END, tag) >= 0 && sameLine && !(i - startIndex === 1))) && ((!startsLine && this.tag(i - 1) !== ',') || !((two != null ? two[0] : void 0) === ':' || (one != null ? one[0] : void 0) === '@' && (three != null ? three[0] : void 0) === ':'))) || (tag === ',' && one && ((_ref1 = one[0]) !== 'IDENTIFIER' && _ref1 !== 'NUMBER' && _ref1 !== 'STRING' && _ref1 !== '@' && _ref1 !== 'TERMINATOR' && _ref1 !== 'OUTDENT'));
};
action = function(token, i) {
var tok;
tok = this.generate('}', '}', token[2]);
return this.tokens.splice(i, 0, tok);
};
return this.scanTokens(function(token, i, tokens) {
var ago, idx, prevTag, tag, tok, value, _ref, _ref1;
if (_ref = (tag = token[0]), __indexOf.call(EXPRESSION_START, _ref) >= 0) {
stack.push([(tag === 'INDENT' && this.tag(i - 1) === '{' ? '{' : tag), i]);
return 1;
}
if (__indexOf.call(EXPRESSION_END, tag) >= 0) {
start = stack.pop();
return 1;
}
if (!(tag === ':' && ((ago = this.tag(i - 2)) === ':' || ((_ref1 = stack[stack.length - 1]) != null ? _ref1[0] : void 0) !== '{'))) {
return 1;
}
sameLine = true;
startIndex = i + 1;
stack.push(['{']);
idx = ago === '@' ? i - 2 : i - 1;
while (this.tag(idx - 2) === 'HERECOMMENT') {
idx -= 2;
}
prevTag = this.tag(idx - 1);
startsLine = !prevTag || (__indexOf.call(LINEBREAKS, prevTag) >= 0);
value = new String('{');
value.generated = true;
tok = this.generate('{', value, token[2]);
tokens.splice(idx, 0, tok);
this.detectEnd(i + 2, condition, action);
return 2;
});
};
Rewriter.prototype.addImplicitParentheses = function() {
var action, condition, noCall, seenControl, seenSingle;
noCall = seenSingle = seenControl = false;
condition = function(token, i) {
var post, tag, _ref, _ref1;
tag = token[0];
if (!seenSingle && token.fromThen) {
return true;
}
if (tag === 'IF' || tag === 'ELSE' || tag === 'CATCH' || tag === '->' || tag === '=>' || tag === 'CLASS') {
seenSingle = true;
}
if (tag === 'IF' || tag === 'ELSE' || tag === 'SWITCH' || tag === 'TRY' || tag === '=') {
seenControl = true;
}
if ((tag === '.' || tag === '?.' || tag === '::') && this.tag(i - 1) === 'OUTDENT') {
return true;
}
return !token.generated && this.tag(i - 1) !== ',' && (__indexOf.call(IMPLICIT_END, tag) >= 0 || (tag === 'INDENT' && !seenControl)) && (tag !== 'INDENT' || (((_ref = this.tag(i - 2)) !== 'CLASS' && _ref !== 'EXTENDS') && (_ref1 = this.tag(i - 1), __indexOf.call(IMPLICIT_BLOCK, _ref1) < 0) && !((post = this.tokens[i + 1]) && post.generated && post[0] === '{')));
};
action = function(token, i) {
return this.tokens.splice(i, 0, this.generate('CALL_END', ')', token[2]));
};
return this.scanTokens(function(token, i, tokens) {
var callObject, current, next, prev, tag, _ref, _ref1, _ref2;
tag = token[0];
if (tag === 'CLASS' || tag === 'IF' || tag === 'FOR' || tag === 'WHILE') {
noCall = true;
}
_ref = tokens.slice(i - 1, (i + 1) + 1 || 9e9), prev = _ref[0], current = _ref[1], next = _ref[2];
callObject = !noCall && tag === 'INDENT' && next && next.generated && next[0] === '{' && prev && (_ref1 = prev[0], __indexOf.call(IMPLICIT_FUNC, _ref1) >= 0);
seenSingle = false;
seenControl = false;
if (__indexOf.call(LINEBREAKS, tag) >= 0) {
noCall = false;
}
if (prev && !prev.spaced && tag === '?') {
token.call = true;
}
if (token.fromThen) {
return 1;
}
if (!(callObject || (prev != null ? prev.spaced : void 0) && (prev.call || (_ref2 = prev[0], __indexOf.call(IMPLICIT_FUNC, _ref2) >= 0)) && (__indexOf.call(IMPLICIT_CALL, tag) >= 0 || !(token.spaced || token.newLine) && __indexOf.call(IMPLICIT_UNSPACED_CALL, tag) >= 0))) {
return 1;
}
tokens.splice(i, 0, this.generate('CALL_START', '(', token[2]));
this.detectEnd(i + 1, condition, action);
if (prev[0] === '?') {
prev[0] = 'FUNC_EXIST';
}
return 2;
});
};
Rewriter.prototype.addImplicitIndentation = function() {
var action, condition, indent, outdent, starter;
starter = indent = outdent = null;
condition = function(token, i) {
var _ref;
return token[1] !== ';' && (_ref = token[0], __indexOf.call(SINGLE_CLOSERS, _ref) >= 0) && !(token[0] === 'ELSE' && (starter !== 'IF' && starter !== 'THEN'));
};
action = function(token, i) {
return this.tokens.splice((this.tag(i - 1) === ',' ? i - 1 : i), 0, outdent);
};
return this.scanTokens(function(token, i, tokens) {
var tag, _ref, _ref1;
tag = token[0];
if (tag === 'TERMINATOR' && this.tag(i + 1) === 'THEN') {
tokens.splice(i, 1);
return 0;
}
if (tag === 'ELSE' && this.tag(i - 1) !== 'OUTDENT') {
tokens.splice.apply(tokens, [i, 0].concat(__slice.call(this.indentation(token))));
return 2;
}
if (tag === 'CATCH' && ((_ref = this.tag(i + 2)) === 'OUTDENT' || _ref === 'TERMINATOR' || _ref === 'FINALLY')) {
tokens.splice.apply(tokens, [i + 2, 0].concat(__slice.call(this.indentation(token))));
return 4;
}
if (__indexOf.call(SINGLE_LINERS, tag) >= 0 && this.tag(i + 1) !== 'INDENT' && !(tag === 'ELSE' && this.tag(i + 1) === 'IF')) {
starter = tag;
_ref1 = this.indentation(token, true), indent = _ref1[0], outdent = _ref1[1];
if (starter === 'THEN') {
indent.fromThen = true;
}
tokens.splice(i + 1, 0, indent);
this.detectEnd(i + 2, condition, action);
if (tag === 'THEN') {
tokens.splice(i, 1);
}
return 1;
}
return 1;
});
};
Rewriter.prototype.tagPostfixConditionals = function() {
var action, condition, original;
original = null;
condition = function(token, i) {
var _ref;
return (_ref = token[0]) === 'TERMINATOR' || _ref === 'INDENT';
};
action = function(token, i) {
if (token[0] !== 'INDENT' || (token.generated && !token.fromThen)) {
return original[0] = 'POST_' + original[0];
}
};
return this.scanTokens(function(token, i) {
if (token[0] !== 'IF') {
return 1;
}
original = token;
this.detectEnd(i + 1, condition, action);
return 1;
});
};
Rewriter.prototype.indentation = function(token, implicit) {
var indent, outdent;
if (implicit == null) {
implicit = false;
}
indent = ['INDENT', 2, token[2]];
outdent = ['OUTDENT', 2, token[2]];
if (implicit) {
indent.generated = outdent.generated = true;
}
return [indent, outdent];
};
Rewriter.prototype.generate = function(tag, value, line) {
var tok;
tok = [tag, value, line];
tok.generated = true;
return tok;
};
Rewriter.prototype.tag = function(i) {
var _ref;
return (_ref = this.tokens[i]) != null ? _ref[0] : void 0;
};
return Rewriter;
})();
BALANCED_PAIRS = [['(', ')'], ['[', ']'], ['{', '}'], ['INDENT', 'OUTDENT'], ['CALL_START', 'CALL_END'], ['PARAM_START', 'PARAM_END'], ['INDEX_START', 'INDEX_END']];
exports.INVERSES = INVERSES = {};
EXPRESSION_START = [];
EXPRESSION_END = [];
for (_i = 0, _len = BALANCED_PAIRS.length; _i < _len; _i++) {
_ref = BALANCED_PAIRS[_i], left = _ref[0], rite = _ref[1];
EXPRESSION_START.push(INVERSES[rite] = left);
EXPRESSION_END.push(INVERSES[left] = rite);
}
EXPRESSION_CLOSE = ['CATCH', 'WHEN', 'ELSE', 'FINALLY'].concat(EXPRESSION_END);
IMPLICIT_FUNC = ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '@', 'THIS'];
IMPLICIT_CALL = ['IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START', 'CLASS', 'IF', 'TRY', 'SWITCH', 'THIS', 'BOOL', 'NULL', 'UNDEFINED', 'UNARY', 'SUPER', '@', '->', '=>', '[', '(', '{', '--', '++'];
IMPLICIT_UNSPACED_CALL = ['+', '-'];
IMPLICIT_BLOCK = ['->', '=>', '{', '[', ','];
IMPLICIT_END = ['POST_IF', 'FOR', 'WHILE', 'UNTIL', 'WHEN', 'BY', 'LOOP', 'TERMINATOR'];
SINGLE_LINERS = ['ELSE', '->', '=>', 'TRY', 'FINALLY', 'THEN'];
SINGLE_CLOSERS = ['TERMINATOR', 'CATCH', 'FINALLY', 'ELSE', 'OUTDENT', 'LEADING_WHEN'];
LINEBREAKS = ['TERMINATOR', 'INDENT', 'OUTDENT'];
}).call(this);

View File

@ -1,146 +0,0 @@
// Generated by CoffeeScript 1.3.3
(function() {
var Scope, extend, last, _ref;
_ref = require('./helpers'), extend = _ref.extend, last = _ref.last;
exports.Scope = Scope = (function() {
Scope.root = null;
function Scope(parent, expressions, method) {
this.parent = parent;
this.expressions = expressions;
this.method = method;
this.variables = [
{
name: 'arguments',
type: 'arguments'
}
];
this.positions = {};
if (!this.parent) {
Scope.root = this;
}
}
Scope.prototype.add = function(name, type, immediate) {
if (this.shared && !immediate) {
return this.parent.add(name, type, immediate);
}
if (Object.prototype.hasOwnProperty.call(this.positions, name)) {
return this.variables[this.positions[name]].type = type;
} else {
return this.positions[name] = this.variables.push({
name: name,
type: type
}) - 1;
}
};
Scope.prototype.namedMethod = function() {
if (this.method.name || !this.parent) {
return this.method;
}
return this.parent.namedMethod();
};
Scope.prototype.find = function(name) {
if (this.check(name)) {
return true;
}
this.add(name, 'var');
return false;
};
Scope.prototype.parameter = function(name) {
if (this.shared && this.parent.check(name, true)) {
return;
}
return this.add(name, 'param');
};
Scope.prototype.check = function(name) {
var _ref1;
return !!(this.type(name) || ((_ref1 = this.parent) != null ? _ref1.check(name) : void 0));
};
Scope.prototype.temporary = function(name, index) {
if (name.length > 1) {
return '_' + name + (index > 1 ? index - 1 : '');
} else {
return '_' + (index + parseInt(name, 36)).toString(36).replace(/\d/g, 'a');
}
};
Scope.prototype.type = function(name) {
var v, _i, _len, _ref1;
_ref1 = this.variables;
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
v = _ref1[_i];
if (v.name === name) {
return v.type;
}
}
return null;
};
Scope.prototype.freeVariable = function(name, reserve) {
var index, temp;
if (reserve == null) {
reserve = true;
}
index = 0;
while (this.check((temp = this.temporary(name, index)))) {
index++;
}
if (reserve) {
this.add(temp, 'var', true);
}
return temp;
};
Scope.prototype.assign = function(name, value) {
this.add(name, {
value: value,
assigned: true
}, true);
return this.hasAssignments = true;
};
Scope.prototype.hasDeclarations = function() {
return !!this.declaredVariables().length;
};
Scope.prototype.declaredVariables = function() {
var realVars, tempVars, v, _i, _len, _ref1;
realVars = [];
tempVars = [];
_ref1 = this.variables;
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
v = _ref1[_i];
if (v.type === 'var') {
(v.name.charAt(0) === '_' ? tempVars : realVars).push(v.name);
}
}
return realVars.sort().concat(tempVars.sort());
};
Scope.prototype.assignedVariables = function() {
var v, _i, _len, _ref1, _results;
_ref1 = this.variables;
_results = [];
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
v = _ref1[_i];
if (v.type.assigned) {
_results.push("" + v.name + " = " + v.type.value);
}
}
return _results;
};
return Scope;
})();
}).call(this);

View File

@ -1,32 +0,0 @@
{
"name": "coffee-script",
"description": "Unfancy JavaScript",
"keywords": ["javascript", "language", "coffeescript", "compiler"],
"author": "Jeremy Ashkenas",
"version": "1.3.3",
"licenses": [{
"type": "MIT",
"url": "https://raw.github.com/jashkenas/coffee-script/master/LICENSE"
}],
"engines": {
"node": ">=0.4.0"
},
"directories" : {
"lib" : "./lib/coffee-script"
},
"main" : "./lib/coffee-script/coffee-script",
"bin": {
"coffee": "./bin/coffee",
"cake": "./bin/cake"
},
"homepage": "http://coffeescript.org",
"bugs": "https://github.com/jashkenas/coffee-script/issues",
"repository": {
"type": "git",
"url": "git://github.com/jashkenas/coffee-script.git"
},
"devDependencies": {
"uglify-js": ">=1.0.0",
"jison": ">=0.2.0"
}
}

View File

@ -34,8 +34,8 @@
#include <QDir> #include <QDir>
#include <QFileInfo> #include <QFileInfo>
#include <QWebPage> #include <QtWebKitWidgets/QWebPage>
#include <QWebFrame> #include <QtWebKitWidgets/QWebFrame>
#include <QNetworkProxy> #include <QNetworkProxy>
#include "terminal.h" #include "terminal.h"
@ -56,6 +56,7 @@ static const struct QCommandLineConfigEntry flags[] =
{ QCommandLine::Option, '\0', "load-images", "Loads all inlined images: 'true' (default) or 'false'", QCommandLine::Optional }, { QCommandLine::Option, '\0', "load-images", "Loads all inlined images: 'true' (default) or 'false'", QCommandLine::Optional },
{ QCommandLine::Option, '\0', "local-storage-path", "Specifies the location for offline local storage", QCommandLine::Optional }, { QCommandLine::Option, '\0', "local-storage-path", "Specifies the location for offline local storage", QCommandLine::Optional },
{ QCommandLine::Option, '\0', "local-storage-quota", "Sets the maximum size of the offline local storage (in KB)", QCommandLine::Optional }, { QCommandLine::Option, '\0', "local-storage-quota", "Sets the maximum size of the offline local storage (in KB)", QCommandLine::Optional },
{ QCommandLine::Option, '\0', "local-url-access", "Allows use of 'file:///' URLs: 'true' (default) or 'false'", QCommandLine::Optional },
{ QCommandLine::Option, '\0', "local-to-remote-url-access", "Allows local content to access remote URL: 'true' or 'false' (default)", QCommandLine::Optional }, { QCommandLine::Option, '\0', "local-to-remote-url-access", "Allows local content to access remote URL: 'true' or 'false' (default)", QCommandLine::Optional },
{ QCommandLine::Option, '\0', "max-disk-cache-size", "Limits the size of the disk cache (in KB)", QCommandLine::Optional }, { QCommandLine::Option, '\0', "max-disk-cache-size", "Limits the size of the disk cache (in KB)", QCommandLine::Optional },
{ QCommandLine::Option, '\0', "output-encoding", "Sets the encoding for the terminal output, default is 'utf8'", QCommandLine::Optional }, { QCommandLine::Option, '\0', "output-encoding", "Sets the encoding for the terminal output, default is 'utf8'", QCommandLine::Optional },
@ -65,8 +66,10 @@ static const struct QCommandLineConfigEntry flags[] =
{ QCommandLine::Option, '\0', "proxy-auth", "Provides authentication information for the proxy, e.g. ''-proxy-auth=username:password'", QCommandLine::Optional }, { QCommandLine::Option, '\0', "proxy-auth", "Provides authentication information for the proxy, e.g. ''-proxy-auth=username:password'", QCommandLine::Optional },
{ QCommandLine::Option, '\0', "proxy-type", "Specifies the proxy type, 'http' (default), 'none' (disable completely), or 'socks5'", QCommandLine::Optional }, { QCommandLine::Option, '\0', "proxy-type", "Specifies the proxy type, 'http' (default), 'none' (disable completely), or 'socks5'", QCommandLine::Optional },
{ QCommandLine::Option, '\0', "script-encoding", "Sets the encoding used for the starting script, default is 'utf8'", QCommandLine::Optional }, { QCommandLine::Option, '\0', "script-encoding", "Sets the encoding used for the starting script, default is 'utf8'", QCommandLine::Optional },
{ QCommandLine::Option, '\0', "script-language", "Sets the script language instead of detecting it: 'javascript'", QCommandLine::Optional },
{ QCommandLine::Option, '\0', "web-security", "Enables web security, 'true' (default) or 'false'", QCommandLine::Optional }, { QCommandLine::Option, '\0', "web-security", "Enables web security, 'true' (default) or 'false'", QCommandLine::Optional },
{ QCommandLine::Option, '\0', "ssl-protocol", "Sets the SSL protocol (supported protocols: 'SSLv3' (default), 'SSLv2', 'TLSv1', 'any')", QCommandLine::Optional }, { QCommandLine::Option, '\0', "ssl-protocol", "Selects a specific SSL protocol version to offer. Values (case insensitive): TLSv1.2, TLSv1.1, TLSv1.0, TLSv1 (same as v1.0), SSLv3, or ANY. Default is to offer all that Qt thinks are secure (SSLv3 and up). Not all values may be supported, depending on the system OpenSSL library.", QCommandLine::Optional },
{ QCommandLine::Option, '\0', "ssl-ciphers", "Sets supported TLS/SSL ciphers. Argument is a colon-separated list of OpenSSL cipher names (macros like ALL, kRSA, etc. may not be used). Default matches modern browsers.", QCommandLine::Optional },
{ QCommandLine::Option, '\0', "ssl-certificates-path", "Sets the location for custom CA certificates (if none set, uses system default)", QCommandLine::Optional }, { QCommandLine::Option, '\0', "ssl-certificates-path", "Sets the location for custom CA certificates (if none set, uses system default)", QCommandLine::Optional },
{ QCommandLine::Option, '\0', "webdriver", "Starts in 'Remote WebDriver mode' (embedded GhostDriver): '[[<IP>:]<PORT>]' (default '127.0.0.1:8910') ", QCommandLine::Optional }, { QCommandLine::Option, '\0', "webdriver", "Starts in 'Remote WebDriver mode' (embedded GhostDriver): '[[<IP>:]<PORT>]' (default '127.0.0.1:8910') ", QCommandLine::Optional },
{ QCommandLine::Option, '\0', "webdriver-logfile", "File where to write the WebDriver's Log (default 'none') (NOTE: needs '--webdriver') ", QCommandLine::Optional }, { QCommandLine::Option, '\0', "webdriver-logfile", "File where to write the WebDriver's Log (default 'none') (NOTE: needs '--webdriver') ", QCommandLine::Optional },
@ -83,7 +86,7 @@ static const struct QCommandLineConfigEntry flags[] =
Config::Config(QObject *parent) Config::Config(QObject *parent)
: QObject(parent) : QObject(parent)
{ {
m_cmdLine = new QCommandLine; m_cmdLine = new QCommandLine(this);
// We will handle --help and --version ourselves in phantom.cpp // We will handle --help and --version ourselves in phantom.cpp
m_cmdLine->enableHelp(false); m_cmdLine->enableHelp(false);
@ -168,7 +171,7 @@ void Config::loadJsonFile(const QString &filePath)
// Add this object to the global scope // Add this object to the global scope
webPage.mainFrame()->addToJavaScriptWindowObject("config", this); webPage.mainFrame()->addToJavaScriptWindowObject("config", this);
// Apply the JSON config settings to this very object // Apply the JSON config settings to this very object
webPage.mainFrame()->evaluateJavaScript(configurator.arg(jsonConfig), QString()); webPage.mainFrame()->evaluateJavaScript(configurator.arg(jsonConfig));
} }
QString Config::helpText() const QString Config::helpText() const
@ -247,6 +250,16 @@ void Config::setIgnoreSslErrors(const bool value)
m_ignoreSslErrors = value; m_ignoreSslErrors = value;
} }
bool Config::localUrlAccessEnabled() const
{
return m_localUrlAccessEnabled;
}
void Config::setLocalUrlAccessEnabled(const bool value)
{
m_localUrlAccessEnabled = value;
}
bool Config::localToRemoteUrlAccessEnabled() const bool Config::localToRemoteUrlAccessEnabled() const
{ {
return m_localToRemoteUrlAccessEnabled; return m_localToRemoteUrlAccessEnabled;
@ -283,25 +296,17 @@ void Config::setProxyType(const QString value)
QString Config::proxy() const QString Config::proxy() const
{ {
return proxyHost() + ":" + proxyPort(); return m_proxyHost + ":" + QString::number(m_proxyPort);
} }
void Config::setProxy(const QString &value) void Config::setProxy(const QString &value)
{ {
QString proxyHost = value; QUrl proxyUrl = QUrl::fromUserInput(value);
int proxyPort = 1080;
if (proxyHost.lastIndexOf(':') > 0) { if (proxyUrl.isValid()) {
bool ok = true; setProxyHost(proxyUrl.host());
int port = proxyHost.mid(proxyHost.lastIndexOf(':') + 1).toInt(&ok); setProxyPort(proxyUrl.port(1080));
if (ok) {
proxyHost = proxyHost.left(proxyHost.lastIndexOf(':')).trimmed();
proxyPort = port;
} }
}
setProxyHost(proxyHost);
setProxyPort(proxyPort);
} }
void Config::setProxyAuth(const QString &value) void Config::setProxyAuth(const QString &value)
@ -372,6 +377,20 @@ void Config::setScriptEncoding(const QString &value)
m_scriptEncoding = value; m_scriptEncoding = value;
} }
QString Config::scriptLanguage() const
{
return m_scriptLanguage;
}
void Config::setScriptLanguage(const QString &value)
{
if (value.isEmpty()) {
return;
}
m_scriptLanguage = value;
}
QString Config::scriptFile() const QString Config::scriptFile() const
{ {
return m_scriptFile; return m_scriptFile;
@ -527,6 +546,7 @@ void Config::resetToDefaults()
m_diskCacheEnabled = false; m_diskCacheEnabled = false;
m_maxDiskCacheSize = -1; m_maxDiskCacheSize = -1;
m_ignoreSslErrors = false; m_ignoreSslErrors = false;
m_localUrlAccessEnabled = true;
m_localToRemoteUrlAccessEnabled = false; m_localToRemoteUrlAccessEnabled = false;
m_outputEncoding = "UTF-8"; m_outputEncoding = "UTF-8";
m_proxyType = "http"; m_proxyType = "http";
@ -536,6 +556,7 @@ void Config::resetToDefaults()
m_proxyAuthPass.clear(); m_proxyAuthPass.clear();
m_scriptArgs.clear(); m_scriptArgs.clear();
m_scriptEncoding = "UTF-8"; m_scriptEncoding = "UTF-8";
m_scriptLanguage.clear();
m_scriptFile.clear(); m_scriptFile.clear();
m_unknownOption.clear(); m_unknownOption.clear();
m_versionFlag = false; m_versionFlag = false;
@ -547,7 +568,26 @@ void Config::resetToDefaults()
m_javascriptCanCloseWindows = true; m_javascriptCanCloseWindows = true;
m_helpFlag = false; m_helpFlag = false;
m_printDebugMessages = false; m_printDebugMessages = false;
m_sslProtocol = "sslv3"; m_sslProtocol = "default";
// Default taken from Chromium 35.0.1916.153
m_sslCiphers = ("ECDHE-ECDSA-AES128-GCM-SHA256"
":ECDHE-RSA-AES128-GCM-SHA256"
":DHE-RSA-AES128-GCM-SHA256"
":ECDHE-ECDSA-AES256-SHA"
":ECDHE-ECDSA-AES128-SHA"
":ECDHE-RSA-AES128-SHA"
":ECDHE-RSA-AES256-SHA"
":ECDHE-ECDSA-RC4-SHA"
":ECDHE-RSA-RC4-SHA"
":DHE-RSA-AES128-SHA"
":DHE-DSS-AES128-SHA"
":DHE-RSA-AES256-SHA"
":AES128-GCM-SHA256"
":AES128-SHA"
":AES256-SHA"
":DES-CBC3-SHA"
":RC4-SHA"
":RC4-MD5");
m_sslCertificatesPath.clear(); m_sslCertificatesPath.clear();
m_webdriverIp = QString(); m_webdriverIp = QString();
m_webdriverPort = QString(); m_webdriverPort = QString();
@ -615,6 +655,7 @@ void Config::handleOption(const QString &option, const QVariant &value)
booleanFlags << "disk-cache"; booleanFlags << "disk-cache";
booleanFlags << "ignore-ssl-errors"; booleanFlags << "ignore-ssl-errors";
booleanFlags << "load-images"; booleanFlags << "load-images";
booleanFlags << "local-url-access";
booleanFlags << "local-to-remote-url-access"; booleanFlags << "local-to-remote-url-access";
booleanFlags << "remote-debugger-autorun"; booleanFlags << "remote-debugger-autorun";
booleanFlags << "web-security"; booleanFlags << "web-security";
@ -658,11 +699,15 @@ void Config::handleOption(const QString &option, const QVariant &value)
setOfflineStorageDefaultQuota(value.toInt()); setOfflineStorageDefaultQuota(value.toInt());
} }
if (option == "local-url-access") {
setLocalUrlAccessEnabled(boolValue);
}
if (option == "local-to-remote-url-access") { if (option == "local-to-remote-url-access") {
setLocalToRemoteUrlAccessEnabled(boolValue); setLocalToRemoteUrlAccessEnabled(boolValue);
} }
if (option == "max-disk-cache") { if (option == "max-disk-cache-size") {
setMaxDiskCacheSize(value.toInt()); setMaxDiskCacheSize(value.toInt());
} }
@ -695,12 +740,19 @@ void Config::handleOption(const QString &option, const QVariant &value)
setScriptEncoding(value.toString()); setScriptEncoding(value.toString());
} }
if (option == "script-language") {
setScriptLanguage(value.toString());
}
if (option == "web-security") { if (option == "web-security") {
setWebSecurityEnabled(boolValue); setWebSecurityEnabled(boolValue);
} }
if (option == "ssl-protocol") { if (option == "ssl-protocol") {
setSslProtocol(value.toString()); setSslProtocol(value.toString());
} }
if (option == "ssl-ciphers") {
setSslCiphers(value.toString());
}
if (option == "ssl-certificates-path") { if (option == "ssl-certificates-path") {
setSslCertificatesPath(value.toString()); setSslCertificatesPath(value.toString());
} }
@ -743,6 +795,17 @@ void Config::setSslProtocol(const QString& sslProtocolName)
m_sslProtocol = sslProtocolName.toLower(); m_sslProtocol = sslProtocolName.toLower();
} }
QString Config::sslCiphers() const
{
return m_sslCiphers;
}
void Config::setSslCiphers(const QString& sslCiphersName)
{
// OpenSSL cipher strings are case sensitive.
m_sslCiphers = sslCiphersName;
}
QString Config::sslCertificatesPath() const QString Config::sslCertificatesPath() const
{ {
return m_sslCertificatesPath; return m_sslCertificatesPath;

View File

@ -45,6 +45,7 @@ class Config: public QObject
Q_PROPERTY(bool diskCacheEnabled READ diskCacheEnabled WRITE setDiskCacheEnabled) Q_PROPERTY(bool diskCacheEnabled READ diskCacheEnabled WRITE setDiskCacheEnabled)
Q_PROPERTY(int maxDiskCacheSize READ maxDiskCacheSize WRITE setMaxDiskCacheSize) Q_PROPERTY(int maxDiskCacheSize READ maxDiskCacheSize WRITE setMaxDiskCacheSize)
Q_PROPERTY(bool ignoreSslErrors READ ignoreSslErrors WRITE setIgnoreSslErrors) Q_PROPERTY(bool ignoreSslErrors READ ignoreSslErrors WRITE setIgnoreSslErrors)
Q_PROPERTY(bool localUrlAccessEnabled READ localUrlAccessEnabled WRITE setLocalUrlAccessEnabled)
Q_PROPERTY(bool localToRemoteUrlAccessEnabled READ localToRemoteUrlAccessEnabled WRITE setLocalToRemoteUrlAccessEnabled) Q_PROPERTY(bool localToRemoteUrlAccessEnabled READ localToRemoteUrlAccessEnabled WRITE setLocalToRemoteUrlAccessEnabled)
Q_PROPERTY(QString outputEncoding READ outputEncoding WRITE setOutputEncoding) Q_PROPERTY(QString outputEncoding READ outputEncoding WRITE setOutputEncoding)
Q_PROPERTY(QString proxyType READ proxyType WRITE setProxyType) Q_PROPERTY(QString proxyType READ proxyType WRITE setProxyType)
@ -58,6 +59,7 @@ class Config: public QObject
Q_PROPERTY(bool javascriptCanOpenWindows READ javascriptCanOpenWindows WRITE setJavascriptCanOpenWindows) Q_PROPERTY(bool javascriptCanOpenWindows READ javascriptCanOpenWindows WRITE setJavascriptCanOpenWindows)
Q_PROPERTY(bool javascriptCanCloseWindows READ javascriptCanCloseWindows WRITE setJavascriptCanCloseWindows) Q_PROPERTY(bool javascriptCanCloseWindows READ javascriptCanCloseWindows WRITE setJavascriptCanCloseWindows)
Q_PROPERTY(QString sslProtocol READ sslProtocol WRITE setSslProtocol) Q_PROPERTY(QString sslProtocol READ sslProtocol WRITE setSslProtocol)
Q_PROPERTY(QString sslCiphers READ sslCiphers WRITE setSslCiphers)
Q_PROPERTY(QString sslCertificatesPath READ sslCertificatesPath WRITE setSslCertificatesPath) Q_PROPERTY(QString sslCertificatesPath READ sslCertificatesPath WRITE setSslCertificatesPath)
Q_PROPERTY(QString webdriver READ webdriver WRITE setWebdriver) Q_PROPERTY(QString webdriver READ webdriver WRITE setWebdriver)
Q_PROPERTY(QString webdriverLogFile READ webdriverLogFile WRITE setWebdriverLogFile) Q_PROPERTY(QString webdriverLogFile READ webdriverLogFile WRITE setWebdriverLogFile)
@ -94,6 +96,9 @@ public:
bool ignoreSslErrors() const; bool ignoreSslErrors() const;
void setIgnoreSslErrors(const bool value); void setIgnoreSslErrors(const bool value);
bool localUrlAccessEnabled() const;
void setLocalUrlAccessEnabled(const bool value);
bool localToRemoteUrlAccessEnabled() const; bool localToRemoteUrlAccessEnabled() const;
void setLocalToRemoteUrlAccessEnabled(const bool value); void setLocalToRemoteUrlAccessEnabled(const bool value);
@ -121,6 +126,9 @@ public:
QString scriptEncoding() const; QString scriptEncoding() const;
void setScriptEncoding(const QString &value); void setScriptEncoding(const QString &value);
QString scriptLanguage() const;
void setScriptLanguage(const QString &value);
QString scriptFile() const; QString scriptFile() const;
void setScriptFile(const QString &value); void setScriptFile(const QString &value);
@ -157,6 +165,9 @@ public:
void setSslProtocol(const QString& sslProtocolName); void setSslProtocol(const QString& sslProtocolName);
QString sslProtocol() const; QString sslProtocol() const;
void setSslCiphers(const QString& sslCiphersName);
QString sslCiphers() const;
void setSslCertificatesPath(const QString& sslCertificatesPath); void setSslCertificatesPath(const QString& sslCertificatesPath);
QString sslCertificatesPath() const; QString sslCertificatesPath() const;
@ -194,6 +205,7 @@ private:
bool m_diskCacheEnabled; bool m_diskCacheEnabled;
int m_maxDiskCacheSize; int m_maxDiskCacheSize;
bool m_ignoreSslErrors; bool m_ignoreSslErrors;
bool m_localUrlAccessEnabled;
bool m_localToRemoteUrlAccessEnabled; bool m_localToRemoteUrlAccessEnabled;
QString m_outputEncoding; QString m_outputEncoding;
QString m_proxyType; QString m_proxyType;
@ -203,6 +215,7 @@ private:
QString m_proxyAuthPass; QString m_proxyAuthPass;
QStringList m_scriptArgs; QStringList m_scriptArgs;
QString m_scriptEncoding; QString m_scriptEncoding;
QString m_scriptLanguage;
QString m_scriptFile; QString m_scriptFile;
QString m_unknownOption; QString m_unknownOption;
bool m_versionFlag; bool m_versionFlag;
@ -217,6 +230,7 @@ private:
bool m_javascriptCanOpenWindows; bool m_javascriptCanOpenWindows;
bool m_javascriptCanCloseWindows; bool m_javascriptCanCloseWindows;
QString m_sslProtocol; QString m_sslProtocol;
QString m_sslCiphers;
QString m_sslCertificatesPath; QString m_sslCertificatesPath;
QString m_webdriverIp; QString m_webdriverIp;
QString m_webdriverPort; QString m_webdriverPort;

View File

@ -32,12 +32,13 @@
#ifndef CONSTS_H #ifndef CONSTS_H
#define CONSTS_H #define CONSTS_H
#define PHANTOMJS_VERSION_MAJOR 1 #define PHANTOMJS_VERSION_MAJOR 2
#define PHANTOMJS_VERSION_MINOR 9 #define PHANTOMJS_VERSION_MINOR 0
#define PHANTOMJS_VERSION_PATCH 0 #define PHANTOMJS_VERSION_PATCH 0
#define PHANTOMJS_VERSION_STRING "1.9.0" #define PHANTOMJS_VERSION_STRING "2.0.0"
#define COFFEE_SCRIPT_EXTENSION ".coffee" #define HTTP_HEADER_CONTENT_LENGTH "content-length"
#define HTTP_HEADER_CONTENT_TYPE "content-type"
#define JS_ELEMENT_CLICK "(function (el) { " \ #define JS_ELEMENT_CLICK "(function (el) { " \
"var ev = document.createEvent('MouseEvents');" \ "var ev = document.createEvent('MouseEvents');" \

View File

@ -78,32 +78,22 @@ QDataStream &operator>>(QDataStream &stream, QList<QNetworkCookie> &list)
} }
QT_END_NAMESPACE QT_END_NAMESPACE
// private: // public:
CookieJar::CookieJar(QString cookiesFile, QObject *parent) CookieJar::CookieJar(QString cookiesFile, QObject *parent)
: QNetworkCookieJar(parent) : QNetworkCookieJar(parent)
, m_cookieStorage(new QSettings(cookiesFile, QSettings::IniFormat, this))
, m_enabled(true) , m_enabled(true)
{ {
load(); if (cookiesFile == "") {
} m_cookieStorage = 0;
qDebug() << "CookieJar - Created but will not store cookies (use option '--cookies-file=<filename>' to enable persistent cookie storage)";
// public:
CookieJar *CookieJar::instance(QString cookiesFile)
{
static CookieJar *singleton = NULL;
if (!singleton) {
if (cookiesFile.isEmpty()) {
qDebug() << "CookieJar - Created but will not store cookies (use option '--cookies-file=<filename>' to enable persisten cookie storage)";
} else { } else {
m_cookieStorage = new QSettings(cookiesFile, QSettings::IniFormat, this);
load();
qDebug() << "CookieJar - Created and will store cookies in:" << cookiesFile; qDebug() << "CookieJar - Created and will store cookies in:" << cookiesFile;
} }
// Create singleton and assign ownershipt to the Phantom singleton object
// NOTE: First time this is done is when we set "once and for all" the Cookies' File
singleton = new CookieJar(cookiesFile, Phantom::instance());
}
return singleton;
} }
// private:
CookieJar::~CookieJar() CookieJar::~CookieJar()
{ {
// On destruction, before saving, clear all the session cookies // On destruction, before saving, clear all the session cookies
@ -154,6 +144,11 @@ bool CookieJar::addCookie(const QNetworkCookie &cookie, const QString &url)
return false; return false;
} }
void CookieJar::addCookie(const QVariantMap &cookie)
{
addCookieFromMap(cookie);
}
bool CookieJar::addCookieFromMap(const QVariantMap &cookie, const QString &url) bool CookieJar::addCookieFromMap(const QVariantMap &cookie, const QString &url)
{ {
QNetworkCookie newCookie; QNetworkCookie newCookie;
@ -390,6 +385,11 @@ bool CookieJar::isEnabled() const
return m_enabled; return m_enabled;
} }
void CookieJar::close()
{
deleteLater();
}
// private: // private:
bool CookieJar::purgeExpiredCookies() bool CookieJar::purgeExpiredCookies()
{ {
@ -457,8 +457,10 @@ void CookieJar::save()
#endif #endif
// Store cookies // Store cookies
if (m_cookieStorage) {
m_cookieStorage->setValue(QLatin1String("cookies"), QVariant::fromValue<QList<QNetworkCookie> >(allCookies())); m_cookieStorage->setValue(QLatin1String("cookies"), QVariant::fromValue<QList<QNetworkCookie> >(allCookies()));
} }
}
} }
void CookieJar::load() void CookieJar::load()
@ -468,7 +470,9 @@ void CookieJar::load()
qRegisterMetaTypeStreamOperators<QList<QNetworkCookie> >("QList<QNetworkCookie>"); qRegisterMetaTypeStreamOperators<QList<QNetworkCookie> >("QList<QNetworkCookie>");
// Load all the cookies // Load all the cookies
if (m_cookieStorage) {
setAllCookies(qvariant_cast<QList<QNetworkCookie> >(m_cookieStorage->value(QLatin1String("cookies")))); setAllCookies(qvariant_cast<QList<QNetworkCookie> >(m_cookieStorage->value(QLatin1String("cookies"))));
}
// If any cookie has expired since last execution, purge and save before going any further // If any cookie has expired since last execution, purge and save before going any further
if (purgeExpiredCookies()) { if (purgeExpiredCookies()) {

View File

@ -32,6 +32,7 @@
#define COOKIEJAR_H #define COOKIEJAR_H
#include <QSettings> #include <QSettings>
#include <QNetworkCookie>
#include <QNetworkCookieJar> #include <QNetworkCookieJar>
#include <QVariantList> #include <QVariantList>
#include <QVariantMap> #include <QVariantMap>
@ -40,35 +41,39 @@ class CookieJar: public QNetworkCookieJar
{ {
Q_OBJECT Q_OBJECT
private: Q_PROPERTY(QVariantList cookies READ cookiesToMap WRITE addCookiesFromMap)
CookieJar(QString cookiesFile, QObject *parent = NULL);
public: public:
static CookieJar *instance(QString cookiesFile = QString()); CookieJar(QString cookiesFile, QObject *parent = NULL);
virtual ~CookieJar(); virtual ~CookieJar();
bool setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl & url); bool setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl & url);
QList<QNetworkCookie> cookiesForUrl (const QUrl & url) const; QList<QNetworkCookie> cookiesForUrl (const QUrl & url) const;
bool addCookie(const QNetworkCookie &cookie, const QString &url = QString()); bool addCookie(const QNetworkCookie &cookie, const QString &url = QString());
bool addCookieFromMap(const QVariantMap &cookie, const QString &url = QString());
bool addCookies(const QList<QNetworkCookie> &cookiesList, const QString &url = QString()); bool addCookies(const QList<QNetworkCookie> &cookiesList, const QString &url = QString());
bool addCookiesFromMap(const QVariantList &cookiesList, const QString &url = QString());
QList<QNetworkCookie> cookies(const QString &url = QString()) const; QList<QNetworkCookie> cookies(const QString &url = QString()) const;
QVariantList cookiesToMap(const QString &url = QString()) const;
QNetworkCookie cookie(const QString &name, const QString &url = QString()) const; QNetworkCookie cookie(const QString &name, const QString &url = QString()) const;
QVariantMap cookieToMap(const QString &name, const QString &url = QString()) const;
bool deleteCookie(const QString &name, const QString &url = QString()); using QNetworkCookieJar::deleteCookie;
bool deleteCookies(const QString &url = QString()); bool deleteCookies(const QString &url = QString());
void clearCookies();
void enable(); void enable();
void disable(); void disable();
bool isEnabled() const; bool isEnabled() const;
public slots:
void addCookie(const QVariantMap &cookie);
bool addCookieFromMap(const QVariantMap &cookie, const QString &url = QString());
bool addCookiesFromMap(const QVariantList &cookiesList, const QString &url = QString());
QVariantList cookiesToMap(const QString &url = QString()) const;
QVariantMap cookieToMap(const QString &name, const QString &url = QString()) const;
bool deleteCookie(const QString &name, const QString &url = QString());
void clearCookies();
void close();
private slots: private slots:
bool purgeExpiredCookies(); bool purgeExpiredCookies();
bool purgeSessionCookies(); bool purgeSessionCookies();

199
src/crashdump.cpp Normal file
View File

@ -0,0 +1,199 @@
/*
This file is part of the PhantomJS project from Ofi Labs.
Copyright (C) 2011 Ariya Hidayat <ariya.hidayat@gmail.com>
Copyright (C) 2011 Ivan De Marino <ivan.de.marino@gmail.com>
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the <organization> nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "crashdump.h"
#include <QtGlobal>
#include <QString>
#include <QByteArray>
#include <exception>
#include <cstdlib>
#ifdef Q_OS_LINUX
#include "client/linux/handler/exception_handler.h"
#define HAVE_BREAKPAD
#define EHC_EXTRA_ARGS true
#define MDC_PATH_ARG const char*
#define MDC_EXTRA_ARGS void*
#endif
#ifdef Q_OS_MAC
#include "client/mac/handler/exception_handler.h"
#define HAVE_BREAKPAD
#define EHC_EXTRA_ARGS true, NULL
#define MDC_PATH_ARG const char*
#define MDC_EXTRA_ARGS void*
#endif
#ifdef Q_OS_WIN32
#include "client/windows/handler/exception_handler.h"
#define HAVE_BREAKPAD
#define EHC_EXTRA_ARGS BreakpadEH::HANDLER_ALL
#define MDC_PATH_ARG const wchar_t*
#define MDC_EXTRA_ARGS void*, EXCEPTION_POINTERS*, MDRawAssertionInfo*
#endif
#ifdef HAVE_BREAKPAD
// This is not just 'using google_breakpad::ExceptionHandler' because
// one of the headers included by exception_handler.h on MacOS defines
// a typedef name 'ExceptionHandler' in the global namespace, and
// (apparently) a using-directive doesn't completely mask that.
typedef google_breakpad::ExceptionHandler BreakpadEH;
#ifdef Q_OS_WIN32
// qgetenv doesn't handle environment variables containing Unicode
// characters very well. Breakpad-for-Windows works exclusively with
// Unicode paths anyway, so we use the native API to retrieve %TEMP%
// as Unicode. This code based upon qglobal.cpp::qgetenv.
static QString
q_wgetenv(const wchar_t *varName)
{
size_t requiredSize;
_wgetenv_s(&requiredSize, 0, 0, varName);
if (requiredSize == 0 || requiredSize > size_t(INT_MAX / sizeof(wchar_t)))
return QString();
// Unfortunately it does not appear to be safe to pass QString::data()
// to a Windows API that expects wchar_t*. QChar is too different.
// We have to employ a scratch buffer. Limiting the length to
// INT_MAX / sizeof(wchar_t), above, ensures that the multiplication
// here cannot overflow.
wchar_t *buffer = (wchar_t *)malloc(requiredSize * sizeof(wchar_t));
if (!buffer)
return QString();
// requiredSize includes the terminating null, which we don't want.
// The range-check above also ensures that the conversion to int here
// does not overflow.
_wgetenv_s(&requiredSize, buffer, requiredSize, varName);
Q_ASSERT(buffer[requiredSize-1] == L'\0');
QString ret = QString::fromWCharArray(buffer, int(requiredSize - 1));
free(buffer);
return ret;
}
#endif
//
// Crash messages.
//
#ifdef Q_OS_WIN32
#define CRASH_DUMP_FMT "%ls\\%ls.dmp"
#define CRASH_DIR_FMT "%%TEMP%% (%ls)"
#else
#define CRASH_DUMP_FMT "%s/%s.dmp"
#define CRASH_DIR_FMT "$TMPDIR (%s)"
#endif
#define CRASH_MESSAGE_BASE \
"PhantomJS has crashed. Please read the crash reporting guide at\n" \
"<http://phantomjs.org/crash-reporting.html> and file a bug report at\n" \
"<https://github.com/ariya/phantomjs/issues/new>.\n"
#define CRASH_MESSAGE_HAVE_DUMP \
CRASH_MESSAGE_BASE \
"Please attach the crash dump file:\n " CRASH_DUMP_FMT "\n"
#define CRASH_MESSAGE_NO_DUMP \
CRASH_MESSAGE_BASE \
"Unfortunately, no crash dump is available.\n" \
"(Is " CRASH_DIR_FMT " a directory you cannot write?)\n"
static bool minidumpCallback(MDC_PATH_ARG dump_path,
MDC_PATH_ARG minidump_id,
MDC_EXTRA_ARGS,
bool succeeded)
{
if (succeeded)
fprintf(stderr, CRASH_MESSAGE_HAVE_DUMP, dump_path, minidump_id);
else
fprintf(stderr, CRASH_MESSAGE_NO_DUMP, dump_path);
return succeeded;
}
static BreakpadEH *initBreakpad()
{
// On all platforms, Breakpad can be disabled by setting the
// environment variable PHANTOMJS_DISABLE_CRASH_DUMPS to any
// non-empty value. This is not a command line argument because
// we want to initialize Breakpad before parsing the command line.
if (!qEnvironmentVariableIsEmpty("PHANTOMJS_DISABLE_CRASH_DUMPS"))
return 0;
// Windows and Unix have different conventions for the environment
// variable naming the directory that should hold scratch files.
#ifdef Q_OS_WIN32
std::wstring dumpPath(L".");
QString varbuf = q_wgetenv(L"TEMP");
if (!varbuf.isEmpty())
dumpPath = varbuf.toStdWString();
#else
std::string dumpPath("/tmp");
QByteArray varbuf = qgetenv("TMPDIR");
if (!varbuf.isEmpty())
dumpPath = varbuf.constData();
#endif
return new BreakpadEH(dumpPath, NULL, minidumpCallback, NULL,
EHC_EXTRA_ARGS);
}
#else // no HAVE_BREAKPAD
#define initBreakpad() NULL
#endif
// Qt, QtWebkit, and PhantomJS mostly don't make use of C++ exceptions,
// so in the rare cases where an exception does get thrown, it tends
// to pass all the way up the stack and cause the C++ runtime to call
// std::terminate(). The default std::terminate() handler in some
// C++ runtimes tries to print details of the exception or maybe even
// a stack trace. Breakpad does a better job of this.
//
// Worse, if the exception is bad_alloc, thrown because we've run into
// a system-imposed hard upper limit on memory allocation, a clever
// terminate handler like that may itself perform more memory allocation,
// which will throw another bad_alloc, and cause a recursive call to
// terminate. In some cases this may happen several times before the
// process finally dies.
//
// Short-circuit all this mess by forcing the terminate handler to
// be plain old std::abort, which will invoke Breakpad if it's active
// and crash promptly if not.
CrashHandler::CrashHandler()
: old_terminate_handler(std::set_terminate(std::abort)),
eh(initBreakpad())
{}
CrashHandler::~CrashHandler()
{
delete eh;
std::set_terminate(old_terminate_handler);
}

Some files were not shown because too many files have changed in this diff Show More