From b0108959bca352aad20cccd9ebfa257c26d990e1 Mon Sep 17 00:00:00 2001 From: c9bot Date: Tue, 10 Feb 2015 23:41:24 +0400 Subject: [PATCH] initial commit --- .eslintrc | 46 + .gitignore | 75 + .nakignore | 7 + LICENSE | 239 + README.md | 80 + bin/c9 | 29 + bin/launch.bat | 133 + build/browser_extensions/chrome/icon128.png | Bin 0 -> 9864 bytes build/browser_extensions/chrome/manifest.json | 25 + build/build-local.sh | 201 + build/build-standalone.sh | 145 + build/osx/c9.icns | Bin 0 -> 126811 bytes build/win32/Cloud9.ico | Bin 0 -> 32038 bytes build/win32/icon.png | Bin 0 -> 4314 bytes configs/cdn-cli.js | 64 + configs/cdn.js | 28 + configs/cli.js | 157 + configs/client-default.js | 689 + configs/local.js | 14 + configs/standalone.js | 214 + docs/CODING_STANDARDS.md | 702 + local/Info.plist | 210 + local/favicon.ico | 1 + local/index.html | 499 + local/install.sh | 242 + local/logger.js | 39 + local/menus.js | 333 + local/package.json | 19 + local/projectManager.html | 27 + local/server.js | 1264 + node_modules/ace/.gitignore | 23 + node_modules/ace/.gitmodules | 6 + node_modules/ace/.travis.yml | 1 + node_modules/ace/CNAME | 1 + node_modules/ace/CONTRIBUTING.md | 22 + node_modules/ace/ChangeLog.txt | 325 + node_modules/ace/LICENSE | 24 + node_modules/ace/Makefile | 44 + node_modules/ace/Makefile.dryice.js | 566 + node_modules/ace/Readme.md | 168 + node_modules/ace/api/ace.html | 149 + node_modules/ace/api/anchor.html | 272 + .../ace/api/background_tokenizer.html | 320 + node_modules/ace/api/command_manager.html | 55 + node_modules/ace/api/document.html | 927 + node_modules/ace/api/edit_session.html | 3235 + node_modules/ace/api/editor.html | 4689 + node_modules/ace/api/index.html | 12 + node_modules/ace/api/placeholder.html | 293 + node_modules/ace/api/range.html | 968 + node_modules/ace/api/renderloop.html | 55 + .../ace/api/resources/csses/ace_api.css | 912 + .../resources/font/fontawesome-webfont.eot | Bin 0 -> 38708 bytes .../resources/font/fontawesome-webfont.svg | 255 + .../resources/font/fontawesome-webfont.ttf | Bin 0 -> 68476 bytes .../resources/font/fontawesome-webfont.woff | Bin 0 -> 41752 bytes .../ace/api/resources/images/Ace_ERD.png | Bin 0 -> 59424 bytes .../ace/api/resources/images/ace_logo.png | Bin 0 -> 42538 bytes .../api/resources/images/ace_logo_menu.png | Bin 0 -> 3252 bytes .../api/resources/images/c9-log-footer.png | Bin 0 -> 6859 bytes .../ace/api/resources/images/c9-sponsor.png | Bin 0 -> 12244 bytes .../ace/api/resources/images/cloud9-logo.png | Bin 0 -> 14564 bytes .../ace/api/resources/images/content-top.png | Bin 0 -> 3172 bytes .../ace/api/resources/images/content_bg.png | Bin 0 -> 4177 bytes .../api/resources/images/content_top_bg.png | Bin 0 -> 629 bytes .../ace/api/resources/images/dashed_back.png | Bin 0 -> 3445 bytes .../ace/api/resources/images/footer-bg.png | Bin 0 -> 1090 bytes .../ace/api/resources/images/main_bg.png | Bin 0 -> 9630 bytes .../api/resources/images/member-sprites.png | Bin 0 -> 3505 bytes .../ace/api/resources/images/menu_disc.png | Bin 0 -> 556 bytes .../ace/api/resources/images/method_bg.png | Bin 0 -> 8001 bytes .../images/scrolled-heading-shadow.png | Bin 0 -> 3903 bytes .../api/resources/images/sidebar-top-bg.png | Bin 0 -> 2693 bytes .../api/resources/images/sidebar_border.png | Bin 0 -> 2967 bytes .../api/resources/images/swirl_divider.png | Bin 0 -> 1043 bytes .../ace/api/resources/javascripts/bbq.js | 18 + .../api/resources/javascripts/bootstrap.js | 389 + .../ace/api/resources/javascripts/clicker.js | 69 + .../api/resources/javascripts/disqus-ext.js | 17 + .../resources/javascripts/jquery-scrollspy.js | 98 + .../resources/javascripts/jquery.collapse.js | 151 + .../resources/javascripts/jquery.cookie.js | 96 + .../ace/api/resources/javascripts/plugins.js | 13 + .../javascripts/prettify-extension.js | 24 + .../ace/api/resources/javascripts/prettify.js | 28 + .../ace/api/resources/javascripts/ux.js | 135 + node_modules/ace/api/scrollbar.html | 261 + node_modules/ace/api/search.html | 295 + node_modules/ace/api/selection.html | 1781 + node_modules/ace/api/split.html | 640 + node_modules/ace/api/token_iterator.html | 248 + node_modules/ace/api/tokenizer.html | 122 + node_modules/ace/api/undomanager.html | 271 + node_modules/ace/api/virtual_renderer.html | 2190 + .../ace/build_support/bookmarklet.html | 112 + node_modules/ace/build_support/editor.html | 39 + .../ace/build_support/mini_require.js | 187 + node_modules/ace/build_support/style.css | 226 + node_modules/ace/demo/autocompletion.html | 45 + node_modules/ace/demo/autoresize.html | 60 + node_modules/ace/demo/chromevox.html | 39 + node_modules/ace/demo/emmet.html | 43 + node_modules/ace/demo/ie7.html | 44 + node_modules/ace/demo/keyboard_shortcuts.html | 51 + node_modules/ace/demo/kitchen-sink/demo.js | 585 + .../ace/demo/kitchen-sink/dev_util.js | 217 + node_modules/ace/demo/kitchen-sink/doclist.js | 218 + .../ace/demo/kitchen-sink/docs/.gitignore | 11 + .../ace/demo/kitchen-sink/docs/Dockerfile | 53 + .../ace/demo/kitchen-sink/docs/Haxe.hx | 17 + .../ace/demo/kitchen-sink/docs/Jack.jack | 247 + .../ace/demo/kitchen-sink/docs/Makefile | 122 + .../ace/demo/kitchen-sink/docs/Nix.nix | 57 + .../ace/demo/kitchen-sink/docs/abap.abap | 36 + .../ace/demo/kitchen-sink/docs/abc.abc | 171 + .../demo/kitchen-sink/docs/actionscript.as | 51 + .../ace/demo/kitchen-sink/docs/ada.ada | 5 + .../demo/kitchen-sink/docs/asciidoc.asciidoc | 6040 ++ .../demo/kitchen-sink/docs/assembly_x86.asm | 18 + .../ace/demo/kitchen-sink/docs/autohotkey.ahk | 35 + .../ace/demo/kitchen-sink/docs/batchfile.bat | 15 + .../docs/c9search.c9search_results | 25 + .../ace/demo/kitchen-sink/docs/c_cpp.cpp | 44 + .../ace/demo/kitchen-sink/docs/cirru.cirru | 42 + .../ace/demo/kitchen-sink/docs/clojure.clj | 19 + .../ace/demo/kitchen-sink/docs/cobol.CBL | 1 + .../ace/demo/kitchen-sink/docs/coffee.coffee | 22 + .../ace/demo/kitchen-sink/docs/coldfusion.cfm | 5 + .../ace/demo/kitchen-sink/docs/csharp.cs | 4 + .../ace/demo/kitchen-sink/docs/css.css | 18 + .../ace/demo/kitchen-sink/docs/curly.curly | 16 + node_modules/ace/demo/kitchen-sink/docs/d.d | 14 + .../ace/demo/kitchen-sink/docs/dart.dart | 19 + .../ace/demo/kitchen-sink/docs/diff.diff | 69 + .../ace/demo/kitchen-sink/docs/dot.dot | 110 + .../ace/demo/kitchen-sink/docs/eiffel.e | 30 + .../ace/demo/kitchen-sink/docs/ejs.ejs | 31 + .../ace/demo/kitchen-sink/docs/elixir.ex | 42 + .../ace/demo/kitchen-sink/docs/elm.elm | 12 + .../ace/demo/kitchen-sink/docs/erlang.erl | 20 + .../ace/demo/kitchen-sink/docs/forth.frt | 41 + .../ace/demo/kitchen-sink/docs/ftl.ftl | 46 + .../ace/demo/kitchen-sink/docs/gcode.gcode | 31 + .../demo/kitchen-sink/docs/gherkin.feature | 28 + .../ace/demo/kitchen-sink/docs/glsl.glsl | 20 + .../ace/demo/kitchen-sink/docs/golang.go | 34 + .../ace/demo/kitchen-sink/docs/groovy.groovy | 41 + .../ace/demo/kitchen-sink/docs/haml.haml | 36 + .../ace/demo/kitchen-sink/docs/handlebars.hbs | 8 + .../ace/demo/kitchen-sink/docs/haskell.hs | 20 + .../ace/demo/kitchen-sink/docs/htaccess | 10 + .../ace/demo/kitchen-sink/docs/html.html | 17 + .../ace/demo/kitchen-sink/docs/html_ruby.erb | 26 + .../ace/demo/kitchen-sink/docs/ini.ini | 4 + node_modules/ace/demo/kitchen-sink/docs/io.io | 6 + .../ace/demo/kitchen-sink/docs/jade.jade | 45 + .../ace/demo/kitchen-sink/docs/java.java | 15 + .../ace/demo/kitchen-sink/docs/javascript.js | 5 + .../ace/demo/kitchen-sink/docs/json.json | 66 + .../ace/demo/kitchen-sink/docs/jsoniq.jq | 1 + .../ace/demo/kitchen-sink/docs/jsp.jsp | 46 + .../ace/demo/kitchen-sink/docs/jsx.jsx | 9 + .../ace/demo/kitchen-sink/docs/julia.jl | 15 + .../ace/demo/kitchen-sink/docs/latex.tex | 22 + .../ace/demo/kitchen-sink/docs/less.less | 28 + .../ace/demo/kitchen-sink/docs/liquid.liquid | 76 + .../ace/demo/kitchen-sink/docs/lisp.lisp | 22 + .../ace/demo/kitchen-sink/docs/livescript.ls | 245 + .../ace/demo/kitchen-sink/docs/logiql.logic | 16 + .../ace/demo/kitchen-sink/docs/lsl.lsl | 75 + .../ace/demo/kitchen-sink/docs/lua.lua | 38 + .../ace/demo/kitchen-sink/docs/luapage.lp | 71 + .../ace/demo/kitchen-sink/docs/lucene.lucene | 1 + .../ace/demo/kitchen-sink/docs/markdown.md | 186 + .../ace/demo/kitchen-sink/docs/mask.mask | 52 + .../ace/demo/kitchen-sink/docs/matlab.matlab | 17 + .../ace/demo/kitchen-sink/docs/mel.mel | 33 + .../ace/demo/kitchen-sink/docs/mushcode.mc | 8 + .../ace/demo/kitchen-sink/docs/mysql.mysql | 1 + .../ace/demo/kitchen-sink/docs/objectivec.m | 104 + .../ace/demo/kitchen-sink/docs/ocaml.ml | 18 + .../ace/demo/kitchen-sink/docs/pascal.pas | 48 + .../ace/demo/kitchen-sink/docs/perl.pl | 37 + .../ace/demo/kitchen-sink/docs/pgsql.pgsql | 118 + .../ace/demo/kitchen-sink/docs/php.php | 19 + .../ace/demo/kitchen-sink/docs/plaintext.txt | 11 + .../ace/demo/kitchen-sink/docs/powershell.ps1 | 24 + .../ace/demo/kitchen-sink/docs/praat.praat | 148 + .../ace/demo/kitchen-sink/docs/prolog.plg | 18 + .../kitchen-sink/docs/properties.properties | 15 + .../ace/demo/kitchen-sink/docs/protobuf.proto | 16 + .../ace/demo/kitchen-sink/docs/python.py | 19 + node_modules/ace/demo/kitchen-sink/docs/r.r | 20 + .../ace/demo/kitchen-sink/docs/rdoc.Rd | 64 + .../ace/demo/kitchen-sink/docs/rhtml.Rhtml | 22 + .../ace/demo/kitchen-sink/docs/ruby.rb | 35 + .../ace/demo/kitchen-sink/docs/rust.rs | 20 + .../ace/demo/kitchen-sink/docs/sass.sass | 39 + .../ace/demo/kitchen-sink/docs/scad.scad | 21 + .../ace/demo/kitchen-sink/docs/scala.scala | 69 + .../ace/demo/kitchen-sink/docs/scheme.scm | 21 + .../ace/demo/kitchen-sink/docs/scss.scss | 20 + node_modules/ace/demo/kitchen-sink/docs/sh.sh | 40 + .../ace/demo/kitchen-sink/docs/sjs.sjs | 28 + .../ace/demo/kitchen-sink/docs/smarty.smarty | 7 + .../demo/kitchen-sink/docs/snippets.snippets | 26 + .../demo/kitchen-sink/docs/soy_template.soy | 46 + .../ace/demo/kitchen-sink/docs/space.space | 56 + .../ace/demo/kitchen-sink/docs/sql.sql | 6 + .../ace/demo/kitchen-sink/docs/stylus.styl | 55 + .../ace/demo/kitchen-sink/docs/svg.svg | 83 + .../ace/demo/kitchen-sink/docs/tcl.tcl | 40 + .../ace/demo/kitchen-sink/docs/tex.tex | 20 + .../demo/kitchen-sink/docs/textile.textile | 29 + .../ace/demo/kitchen-sink/docs/toml.toml | 29 + .../ace/demo/kitchen-sink/docs/twig.twig | 30 + .../ace/demo/kitchen-sink/docs/typescript.ts | 72 + .../ace/demo/kitchen-sink/docs/vala.vala | 21 + .../ace/demo/kitchen-sink/docs/vbscript.vbs | 23 + .../ace/demo/kitchen-sink/docs/velocity.vm | 44 + .../ace/demo/kitchen-sink/docs/verilog.v | 12 + .../ace/demo/kitchen-sink/docs/vhdl.vhd | 34 + .../ace/demo/kitchen-sink/docs/xml.xml | 55 + .../ace/demo/kitchen-sink/docs/xquery.xq | 6 + .../ace/demo/kitchen-sink/docs/yaml.yaml | 35 + .../ace/demo/kitchen-sink/file_drop.js | 73 + .../ace/demo/kitchen-sink/icons/Readme.txt | 1 + .../ace/demo/kitchen-sink/icons/epl.html | 260 + .../ace/demo/kitchen-sink/icons/error_obj.gif | Bin 0 -> 339 bytes .../demo/kitchen-sink/icons/warning_obj.gif | Bin 0 -> 324 bytes .../ace/demo/kitchen-sink/inline_editor.js | 102 + node_modules/ace/demo/kitchen-sink/layout.js | 132 + node_modules/ace/demo/kitchen-sink/logo.png | Bin 0 -> 49263 bytes node_modules/ace/demo/kitchen-sink/require.js | 2074 + node_modules/ace/demo/kitchen-sink/styles.css | 55 + .../ace/demo/kitchen-sink/token_tooltip.js | 156 + node_modules/ace/demo/kitchen-sink/util.js | 235 + node_modules/ace/demo/modelist.html | 51 + node_modules/ace/demo/r.js/build.js | 20 + node_modules/ace/demo/r.js/editor.html | 36 + node_modules/ace/demo/requirejs+build.html | 49 + node_modules/ace/demo/scrollable-page.html | 155 + node_modules/ace/demo/settings_menu.html | 49 + node_modules/ace/demo/show_own_source.js | 16 + node_modules/ace/demo/static-highlighter.html | 64 + .../ace/demo/static-highlighter/client.html | 47 + .../ace/demo/static-highlighter/server.js | 37 + node_modules/ace/demo/statusbar.html | 61 + .../doc/Contributor_License_Agreement-v2.pdf | Bin 0 -> 89761 bytes ...orate_Contributor_License_Agreement-v2.pdf | Bin 0 -> 376398 bytes node_modules/ace/doc/README.md | 17 + node_modules/ace/doc/additionalObjs.json | 27 + node_modules/ace/doc/build.js | 67 + node_modules/ace/doc/index.md | 5 + node_modules/ace/doc/package.json | 8 + node_modules/ace/doc/site/images/ac-logo.png | Bin 0 -> 2662 bytes node_modules/ace/doc/site/images/ace-logo.png | Bin 0 -> 60546 bytes node_modules/ace/doc/site/images/ace-tab.png | Bin 0 -> 2655 bytes node_modules/ace/doc/site/images/ace.png | Bin 0 -> 24364 bytes .../ace/doc/site/images/background.png | Bin 0 -> 3445 bytes .../ace/doc/site/images/body_background.png | Bin 0 -> 3013 bytes .../ace/doc/site/images/bottombar.png | Bin 0 -> 1186 bytes .../ace/doc/site/images/cloud9-logo.png | Bin 0 -> 10601 bytes .../ace/doc/site/images/codecademy-logo.png | Bin 0 -> 4643 bytes node_modules/ace/doc/site/images/codiad.png | Bin 0 -> 10708 bytes .../ace/doc/site/images/crunchapp-logo.png | Bin 0 -> 15917 bytes .../ace/doc/site/images/empty-logo.png | Bin 0 -> 2481 bytes node_modules/ace/doc/site/images/favicon.ico | Bin 0 -> 1150 bytes .../ace/doc/site/images/firefox-logo.png | Bin 0 -> 18993 bytes .../ace/doc/site/images/fork_on_github.png | Bin 0 -> 18528 bytes .../ace/doc/site/images/github-logo.png | Bin 0 -> 6318 bytes .../ace/doc/site/images/habitat-logo.svg | 1 + .../ace/doc/site/images/header-bg.png | Bin 0 -> 154 bytes .../ace/doc/site/images/ideone-logo.png | Bin 0 -> 2938 bytes .../ace/doc/site/images/khan-logo.png | Bin 0 -> 8882 bytes node_modules/ace/doc/site/images/logo.png | Bin 0 -> 52537 bytes .../ace/doc/site/images/logo_half.png | Bin 0 -> 19990 bytes .../ace/doc/site/images/modx-logo-4.png | Bin 0 -> 4550 bytes .../ace/doc/site/images/pixie-logo.png | Bin 0 -> 5632 bytes node_modules/ace/doc/site/images/plunker.png | Bin 0 -> 2190 bytes .../ace/doc/site/images/processwire-logo.svg | 44 + .../ace/doc/site/images/repl.it-logo.png | Bin 0 -> 4291 bytes .../ace/doc/site/images/rstudio_logo_64.png | Bin 0 -> 5631 bytes .../ace/doc/site/images/sassmeister-logo.png | Bin 0 -> 6293 bytes .../ace/doc/site/images/shiftedit-logo.png | Bin 0 -> 12956 bytes .../ace/doc/site/images/spandexio-logo.png | Bin 0 -> 10621 bytes .../ace/doc/site/images/stypi-logo.png | Bin 0 -> 3092 bytes node_modules/ace/doc/site/images/sx-logo.png | Bin 0 -> 9584 bytes .../ace/doc/site/images/textimage.png | Bin 0 -> 11444 bytes .../ace/doc/site/images/weecod-logo.png | Bin 0 -> 2935 bytes .../doc/site/images/wolf_3d_logo_trans.png | Bin 0 -> 46064 bytes .../ace/doc/site/images/zorba-logo.png | Bin 0 -> 8197 bytes node_modules/ace/doc/site/iphone.css | 25 + node_modules/ace/doc/site/js/ga.js | 9 + node_modules/ace/doc/site/js/main.js | 187 + node_modules/ace/doc/site/style.css | 509 + .../ace/doc/template/jade/common_layout.jade | 55 + .../ace/doc/template/jade/layout.jade | 12 + node_modules/ace/doc/template/jade/lib.jade | 217 + .../doc/template/resources/csses/ace_api.css | 912 + .../resources/font/fontawesome-webfont.eot | Bin 0 -> 38708 bytes .../resources/font/fontawesome-webfont.svg | 255 + .../resources/font/fontawesome-webfont.ttf | Bin 0 -> 68476 bytes .../resources/font/fontawesome-webfont.woff | Bin 0 -> 41752 bytes .../doc/template/resources/images/Ace_ERD.png | Bin 0 -> 59424 bytes .../template/resources/images/ace_logo.png | Bin 0 -> 42538 bytes .../resources/images/ace_logo_menu.png | Bin 0 -> 3252 bytes .../resources/images/c9-log-footer.png | Bin 0 -> 6859 bytes .../template/resources/images/c9-sponsor.png | Bin 0 -> 12244 bytes .../template/resources/images/cloud9-logo.png | Bin 0 -> 14564 bytes .../template/resources/images/content-top.png | Bin 0 -> 3172 bytes .../template/resources/images/content_bg.png | Bin 0 -> 4177 bytes .../resources/images/content_top_bg.png | Bin 0 -> 629 bytes .../template/resources/images/dashed_back.png | Bin 0 -> 3445 bytes .../template/resources/images/footer-bg.png | Bin 0 -> 1090 bytes .../doc/template/resources/images/main_bg.png | Bin 0 -> 9630 bytes .../resources/images/member-sprites.png | Bin 0 -> 3505 bytes .../template/resources/images/menu_disc.png | Bin 0 -> 556 bytes .../template/resources/images/method_bg.png | Bin 0 -> 8001 bytes .../images/scrolled-heading-shadow.png | Bin 0 -> 3903 bytes .../resources/images/sidebar-top-bg.png | Bin 0 -> 2693 bytes .../resources/images/sidebar_border.png | Bin 0 -> 2967 bytes .../resources/images/swirl_divider.png | Bin 0 -> 1043 bytes .../doc/template/resources/javascripts/bbq.js | 18 + .../resources/javascripts/bootstrap.js | 389 + .../template/resources/javascripts/clicker.js | 69 + .../resources/javascripts/disqus-ext.js | 17 + .../resources/javascripts/jquery-scrollspy.js | 98 + .../resources/javascripts/jquery.collapse.js | 151 + .../resources/javascripts/jquery.cookie.js | 96 + .../template/resources/javascripts/plugins.js | 13 + .../javascripts/prettify-extension.js | 24 + .../resources/javascripts/prettify.js | 28 + .../doc/template/resources/javascripts/ux.js | 135 + .../ace/experiments/animate_folding.html | 249 + .../ace/experiments/basic_animation.html | 191 + node_modules/ace/experiments/capture.html | 45 + node_modules/ace/experiments/cut_copy.html | 105 + .../ace/experiments/triple_click.html | 34 + node_modules/ace/experiments/worker.html | 33 + node_modules/ace/experiments/worker.js | 3 + node_modules/ace/experiments/zenbg.png | Bin 0 -> 50753 bytes node_modules/ace/index.html | 1352 + node_modules/ace/kitchen-sink.html | 294 + node_modules/ace/lib/ace/ace.js | 129 + node_modules/ace/lib/ace/anchor.js | 227 + node_modules/ace/lib/ace/anchor_test.js | 223 + node_modules/ace/lib/ace/apply_delta.js | 108 + node_modules/ace/lib/ace/autocomplete.js | 497 + .../ace/lib/ace/autocomplete/popup.js | 339 + .../lib/ace/autocomplete/text_completer.js | 78 + node_modules/ace/lib/ace/autocomplete/util.js | 74 + .../ace/lib/ace/background_tokenizer.js | 249 + .../ace/lib/ace/background_tokenizer_test.js | 85 + .../ace/lib/ace/commands/command_manager.js | 118 + .../lib/ace/commands/command_manager_test.js | 199 + .../ace/lib/ace/commands/default_commands.js | 725 + .../commands/incremental_search_commands.js | 232 + .../lib/ace/commands/multi_select_commands.js | 113 + .../ace/lib/ace/commands/occur_commands.js | 110 + node_modules/ace/lib/ace/config.js | 202 + node_modules/ace/lib/ace/config_test.js | 135 + .../css/codefolding-fold-button-states.png | Bin 0 -> 759 bytes node_modules/ace/lib/ace/css/editor.css | 429 + .../ace/lib/ace/css/expand-marker.png | Bin 0 -> 290 bytes node_modules/ace/lib/ace/document.js | 692 + node_modules/ace/lib/ace/document_test.js | 335 + node_modules/ace/lib/ace/edit_session.js | 2565 + .../ace/lib/ace/edit_session/bracket_match.js | 221 + node_modules/ace/lib/ace/edit_session/fold.js | 140 + .../ace/lib/ace/edit_session/fold_line.js | 269 + .../ace/lib/ace/edit_session/folding.js | 857 + node_modules/ace/lib/ace/edit_session_test.js | 1075 + node_modules/ace/lib/ace/editor.js | 2660 + .../lib/ace/editor_change_document_test.js | 188 + .../editor_highlight_selected_word_test.js | 223 + .../ace/lib/ace/editor_navigation_test.js | 164 + .../ace/lib/ace/editor_text_edit_test.js | 557 + node_modules/ace/lib/ace/ext/beautify.js | 57 + .../ace/lib/ace/ext/beautify/php_rules.js | 366 + node_modules/ace/lib/ace/ext/chromevox.js | 979 + .../ace/lib/ace/ext/elastic_tabstops_lite.js | 318 + node_modules/ace/lib/ace/ext/emmet.js | 434 + node_modules/ace/lib/ace/ext/error_marker.js | 214 + .../ace/lib/ace/ext/keybinding_menu.js | 86 + .../ace/lib/ace/ext/language_tools.js | 226 + node_modules/ace/lib/ace/ext/linking.js | 78 + .../ext/menu_tools/add_editor_menu_options.js | 109 + .../ace/ext/menu_tools/element_generator.js | 148 + .../ext/menu_tools/generate_settings_menu.js | 264 + .../get_editor_keyboard_shortcuts.js | 91 + .../ace/ext/menu_tools/get_set_functions.js | 141 + .../lib/ace/ext/menu_tools/overlay_page.js | 116 + .../lib/ace/ext/menu_tools/settings_menu.css | 48 + node_modules/ace/lib/ace/ext/modelist.js | 193 + node_modules/ace/lib/ace/ext/old_ie.js | 114 + node_modules/ace/lib/ace/ext/old_ie_test.js | 77 + node_modules/ace/lib/ace/ext/searchbox.css | 153 + node_modules/ace/lib/ace/ext/searchbox.js | 308 + node_modules/ace/lib/ace/ext/settings_menu.js | 76 + node_modules/ace/lib/ace/ext/spellcheck.js | 69 + node_modules/ace/lib/ace/ext/split.js | 40 + node_modules/ace/lib/ace/ext/static.css | 31 + .../ace/lib/ace/ext/static_highlight.js | 190 + .../ace/lib/ace/ext/static_highlight_test.js | 96 + node_modules/ace/lib/ace/ext/statusbar.js | 48 + node_modules/ace/lib/ace/ext/textarea.js | 521 + node_modules/ace/lib/ace/ext/themelist.js | 100 + node_modules/ace/lib/ace/ext/whitespace.js | 213 + .../ace/lib/ace/ext/whitespace_test.js | 116 + .../ace/lib/ace/incremental_search.js | 317 + .../ace/lib/ace/incremental_search_test.js | 213 + node_modules/ace/lib/ace/keyboard/emacs.js | 652 + .../ace/lib/ace/keyboard/emacs_test.js | 151 + .../ace/lib/ace/keyboard/hash_handler.js | 248 + .../ace/lib/ace/keyboard/keybinding.js | 145 + .../ace/lib/ace/keyboard/keybinding_test.js | 69 + .../ace/lib/ace/keyboard/state_handler.js | 249 + node_modules/ace/lib/ace/keyboard/sublime.js | 465 + node_modules/ace/lib/ace/keyboard/textarea.js | 82 + .../ace/lib/ace/keyboard/textinput.js | 511 + node_modules/ace/lib/ace/keyboard/vim.js | 6065 ++ node_modules/ace/lib/ace/keyboard/vim_test.js | 3866 + node_modules/ace/lib/ace/layer/cursor.js | 240 + .../ace/lib/ace/layer/font_metrics.js | 188 + node_modules/ace/lib/ace/layer/gutter.js | 285 + node_modules/ace/lib/ace/layer/marker.js | 218 + node_modules/ace/lib/ace/layer/text.js | 575 + node_modules/ace/lib/ace/layer/text_test.js | 126 + node_modules/ace/lib/ace/lib/app_config.js | 157 + node_modules/ace/lib/ace/lib/dom.js | 284 + node_modules/ace/lib/ace/lib/es5-shim.js | 1062 + node_modules/ace/lib/ace/lib/event.js | 367 + node_modules/ace/lib/ace/lib/event_emitter.js | 155 + .../ace/lib/ace/lib/event_emitter_test.js | 65 + .../ace/lib/ace/lib/fixoldbrowsers.js | 19 + node_modules/ace/lib/ace/lib/keys.js | 163 + node_modules/ace/lib/ace/lib/lang.js | 221 + node_modules/ace/lib/ace/lib/net.js | 51 + node_modules/ace/lib/ace/lib/oop.js | 57 + node_modules/ace/lib/ace/lib/regexp.js | 113 + node_modules/ace/lib/ace/lib/useragent.js | 106 + node_modules/ace/lib/ace/line_widgets.js | 295 + node_modules/ace/lib/ace/mode/_test/Readme.md | 9 + .../ace/mode/_test/highlight_rules_test.js | 210 + .../ace/lib/ace/mode/_test/package.json | 8 + .../ace/lib/ace/mode/_test/text_asciidoc.txt | 111 + .../ace/lib/ace/mode/_test/text_coffee.txt | 57 + .../ace/lib/ace/mode/_test/text_curly.txt | 9 + .../ace/lib/ace/mode/_test/text_html.txt | 10 + .../lib/ace/mode/_test/text_javascript.txt | 86 + .../lib/ace/mode/_test/text_livescript.txt | 1 + .../ace/lib/ace/mode/_test/text_lucene.txt | 16 + .../ace/lib/ace/mode/_test/text_markdown.txt | 22 + .../ace/lib/ace/mode/_test/text_php.txt | 24 + .../ace/lib/ace/mode/_test/text_ruby.txt | 34 + .../ace/lib/ace/mode/_test/text_xml.txt | 7 + .../ace/lib/ace/mode/_test/tokens_abap.json | 189 + .../ace/lib/ace/mode/_test/tokens_abc.json | 2207 + .../ace/mode/_test/tokens_actionscript.json | 263 + .../ace/lib/ace/mode/_test/tokens_ada.json | 39 + .../lib/ace/mode/_test/tokens_asciidoc.json | 422 + .../ace/mode/_test/tokens_assembly_x86.json | 114 + .../lib/ace/mode/_test/tokens_autohotkey.json | 261 + .../lib/ace/mode/_test/tokens_batchfile.json | 70 + .../lib/ace/mode/_test/tokens_c9search.json | 131 + .../ace/lib/ace/mode/_test/tokens_c_cpp.json | 190 + .../ace/lib/ace/mode/_test/tokens_cirru.json | 267 + .../lib/ace/mode/_test/tokens_clojure.json | 162 + .../ace/lib/ace/mode/_test/tokens_cobol.json | 4 + .../ace/lib/ace/mode/_test/tokens_coffee.json | 545 + .../lib/ace/mode/_test/tokens_coldfusion.json | 26 + .../ace/lib/ace/mode/_test/tokens_csharp.json | 31 + .../ace/lib/ace/mode/_test/tokens_css.json | 148 + .../ace/lib/ace/mode/_test/tokens_curly.json | 56 + .../ace/lib/ace/mode/_test/tokens_d.json | 111 + .../ace/lib/ace/mode/_test/tokens_dart.json | 368 + .../ace/lib/ace/mode/_test/tokens_diff.json | 262 + .../ace/lib/ace/mode/_test/tokens_dot.json | 2254 + .../ace/lib/ace/mode/_test/tokens_eiffel.json | 141 + .../ace/lib/ace/mode/_test/tokens_ejs.json | 296 + .../ace/lib/ace/mode/_test/tokens_elixir.json | 196 + .../ace/lib/ace/mode/_test/tokens_elm.json | 198 + .../ace/lib/ace/mode/_test/tokens_erlang.json | 166 + .../ace/lib/ace/mode/_test/tokens_forth.json | 219 + .../ace/lib/ace/mode/_test/tokens_ftl.json | 341 + .../ace/lib/ace/mode/_test/tokens_gcode.json | 296 + .../lib/ace/mode/_test/tokens_gherkin.json | 142 + .../lib/ace/mode/_test/tokens_gitignore.json | 33 + .../ace/lib/ace/mode/_test/tokens_glsl.json | 127 + .../ace/lib/ace/mode/_test/tokens_golang.json | 256 + .../ace/lib/ace/mode/_test/tokens_groovy.json | 410 + .../ace/lib/ace/mode/_test/tokens_haml.json | 174 + .../lib/ace/mode/_test/tokens_handlebars.json | 81 + .../lib/ace/mode/_test/tokens_haskell.json | 156 + .../ace/lib/ace/mode/_test/tokens_haxe.json | 143 + .../ace/lib/ace/mode/_test/tokens_html.json | 63 + .../lib/ace/mode/_test/tokens_html_ruby.json | 257 + .../ace/lib/ace/mode/_test/tokens_ini.json | 23 + .../ace/lib/ace/mode/_test/tokens_io.json | 49 + .../ace/lib/ace/mode/_test/tokens_jack.json | 1786 + .../ace/lib/ace/mode/_test/tokens_jade.json | 188 + .../ace/lib/ace/mode/_test/tokens_java.json | 95 + .../lib/ace/mode/_test/tokens_javascript.json | 593 + .../ace/lib/ace/mode/_test/tokens_json.json | 412 + .../ace/lib/ace/mode/_test/tokens_jsoniq.json | 4 + .../ace/lib/ace/mode/_test/tokens_jsp.json | 435 + .../ace/lib/ace/mode/_test/tokens_jsx.json | 51 + .../ace/lib/ace/mode/_test/tokens_julia.json | 111 + .../ace/lib/ace/mode/_test/tokens_latex.json | 127 + .../ace/lib/ace/mode/_test/tokens_less.json | 204 + .../ace/lib/ace/mode/_test/tokens_liquid.json | 551 + .../ace/lib/ace/mode/_test/tokens_lisp.json | 248 + .../lib/ace/mode/_test/tokens_livescript.json | 6 + .../ace/lib/ace/mode/_test/tokens_logiql.json | 190 + .../ace/lib/ace/mode/_test/tokens_lsl.json | 503 + .../ace/lib/ace/mode/_test/tokens_lua.json | 348 + .../lib/ace/mode/_test/tokens_luapage.json | 633 + .../ace/lib/ace/mode/_test/tokens_lucene.json | 92 + .../lib/ace/mode/_test/tokens_markdown.json | 114 + .../ace/lib/ace/mode/_test/tokens_mask.json | 302 + .../ace/lib/ace/mode/_test/tokens_matlab.json | 90 + .../ace/lib/ace/mode/_test/tokens_mel.json | 257 + .../lib/ace/mode/_test/tokens_mushcode.json | 790 + .../ace/lib/ace/mode/_test/tokens_mysql.json | 4 + .../ace/lib/ace/mode/_test/tokens_nix.json | 360 + .../lib/ace/mode/_test/tokens_objectivec.json | 793 + .../ace/lib/ace/mode/_test/tokens_ocaml.json | 200 + .../ace/lib/ace/mode/_test/tokens_pascal.json | 297 + .../ace/lib/ace/mode/_test/tokens_perl.json | 227 + .../ace/lib/ace/mode/_test/tokens_pgsql.json | 889 + .../ace/lib/ace/mode/_test/tokens_php.json | 171 + .../lib/ace/mode/_test/tokens_powershell.json | 184 + .../ace/lib/ace/mode/_test/tokens_prolog.json | 245 + .../lib/ace/mode/_test/tokens_properties.json | 68 + .../lib/ace/mode/_test/tokens_protobuf.json | 136 + .../ace/lib/ace/mode/_test/tokens_python.json | 152 + .../ace/lib/ace/mode/_test/tokens_r.json | 235 + .../ace/lib/ace/mode/_test/tokens_rdoc.json | 441 + .../ace/lib/ace/mode/_test/tokens_rhtml.json | 106 + .../ace/lib/ace/mode/_test/tokens_ruby.json | 242 + .../ace/lib/ace/mode/_test/tokens_rust.json | 136 + .../ace/lib/ace/mode/_test/tokens_sass.json | 229 + .../ace/lib/ace/mode/_test/tokens_scad.json | 194 + .../ace/lib/ace/mode/_test/tokens_scala.json | 542 + .../ace/lib/ace/mode/_test/tokens_scheme.json | 216 + .../ace/lib/ace/mode/_test/tokens_scss.json | 123 + .../ace/lib/ace/mode/_test/tokens_sh.json | 334 + .../ace/lib/ace/mode/_test/tokens_sjs.json | 276 + .../ace/lib/ace/mode/_test/tokens_smarty.json | 98 + .../lib/ace/mode/_test/tokens_snippets.json | 159 + .../ace/mode/_test/tokens_soy_template.json | 286 + .../ace/lib/ace/mode/_test/tokens_space.json | 322 + .../ace/lib/ace/mode/_test/tokens_sql.json | 54 + .../ace/lib/ace/mode/_test/tokens_stylus.json | 271 + .../ace/lib/ace/mode/_test/tokens_svg.json | 684 + .../ace/lib/ace/mode/_test/tokens_tcl.json | 385 + .../ace/lib/ace/mode/_test/tokens_tex.json | 130 + .../ace/lib/ace/mode/_test/tokens_text.json | 29 + .../lib/ace/mode/_test/tokens_textile.json | 113 + .../ace/lib/ace/mode/_test/tokens_toml.json | 131 + .../ace/lib/ace/mode/_test/tokens_twig.json | 288 + .../lib/ace/mode/_test/tokens_typescript.json | 559 + .../ace/lib/ace/mode/_test/tokens_vala.json | 158 + .../lib/ace/mode/_test/tokens_vbscript.json | 205 + .../lib/ace/mode/_test/tokens_velocity.json | 285 + .../lib/ace/mode/_test/tokens_verilog.json | 113 + .../ace/lib/ace/mode/_test/tokens_vhdl.json | 271 + .../ace/lib/ace/mode/_test/tokens_xml.json | 43 + .../ace/lib/ace/mode/_test/tokens_xquery.json | 44 + .../ace/lib/ace/mode/_test/tokens_yaml.json | 150 + node_modules/ace/lib/ace/mode/abap.js | 77 + .../ace/lib/ace/mode/abap_highlight_rules.js | 134 + node_modules/ace/lib/ace/mode/abc.js | 58 + .../ace/lib/ace/mode/abc_highlight_rules.js | 114 + node_modules/ace/lib/ace/mode/actionscript.js | 58 + .../ace/mode/actionscript_highlight_rules.js | 141 + node_modules/ace/lib/ace/mode/ada.js | 54 + .../ace/lib/ace/mode/ada_highlight_rules.js | 93 + node_modules/ace/lib/ace/mode/apache_conf.js | 62 + .../ace/mode/apache_conf_highlight_rules.js | 231 + node_modules/ace/lib/ace/mode/applescript.js | 55 + .../ace/mode/applescript_highlight_rules.js | 139 + node_modules/ace/lib/ace/mode/asciidoc.js | 64 + .../lib/ace/mode/asciidoc_highlight_rules.js | 234 + node_modules/ace/lib/ace/mode/assembly_x86.js | 56 + .../ace/mode/assembly_x86_highlight_rules.js | 114 + node_modules/ace/lib/ace/mode/autohotkey.js | 57 + .../ace/mode/autohotkey_highlight_rules.js | 107 + node_modules/ace/lib/ace/mode/batchfile.js | 61 + .../lib/ace/mode/batchfile_highlight_rules.js | 97 + node_modules/ace/lib/ace/mode/behaviour.js | 90 + .../lib/ace/mode/behaviour/behaviour_test.js | 139 + .../ace/lib/ace/mode/behaviour/css.js | 108 + .../ace/lib/ace/mode/behaviour/cstyle.js | 392 + .../ace/lib/ace/mode/behaviour/html.js | 46 + .../ace/lib/ace/mode/behaviour/xml.js | 202 + .../ace/lib/ace/mode/behaviour/xquery.js | 92 + node_modules/ace/lib/ace/mode/c9search.js | 67 + .../lib/ace/mode/c9search_highlight_rules.js | 182 + node_modules/ace/lib/ace/mode/c_cpp.js | 101 + .../ace/lib/ace/mode/c_cpp_highlight_rules.js | 196 + node_modules/ace/lib/ace/mode/cirru.js | 51 + .../ace/lib/ace/mode/cirru_highlight_rules.js | 125 + node_modules/ace/lib/ace/mode/clojure.js | 128 + .../lib/ace/mode/clojure_highlight_rules.js | 200 + node_modules/ace/lib/ace/mode/cobol.js | 53 + .../ace/lib/ace/mode/cobol_highlight_rules.js | 100 + node_modules/ace/lib/ace/mode/coffee.js | 135 + .../ace/lib/ace/mode/coffee/coffee-script.js | 62 + .../ace/lib/ace/mode/coffee/helpers.js | 271 + node_modules/ace/lib/ace/mode/coffee/lexer.js | 935 + node_modules/ace/lib/ace/mode/coffee/nodes.js | 3106 + .../ace/lib/ace/mode/coffee/parser.js | 724 + .../ace/lib/ace/mode/coffee/parser_test.js | 88 + .../ace/lib/ace/mode/coffee/rewriter.js | 516 + node_modules/ace/lib/ace/mode/coffee/scope.js | 174 + .../lib/ace/mode/coffee_highlight_rules.js | 233 + .../ace/lib/ace/mode/coffee_worker.js | 73 + node_modules/ace/lib/ace/mode/coldfusion.js | 61 + .../ace/mode/coldfusion_highlight_rules.js | 49 + .../ace/lib/ace/mode/coldfusion_test.js | 67 + node_modules/ace/lib/ace/mode/csharp.js | 61 + .../lib/ace/mode/csharp_highlight_rules.js | 93 + node_modules/ace/lib/ace/mode/css.js | 100 + node_modules/ace/lib/ace/mode/css/csslint.js | 9628 ++ .../ace/lib/ace/mode/css_highlight_rules.js | 179 + node_modules/ace/lib/ace/mode/css_test.js | 78 + node_modules/ace/lib/ace/mode/css_worker.js | 100 + .../ace/lib/ace/mode/css_worker_test.js | 68 + node_modules/ace/lib/ace/mode/curly.js | 63 + .../ace/lib/ace/mode/curly_highlight_rules.js | 66 + node_modules/ace/lib/ace/mode/d.js | 56 + .../ace/lib/ace/mode/d_highlight_rules.js | 334 + node_modules/ace/lib/ace/mode/dart.js | 62 + .../ace/lib/ace/mode/dart_highlight_rules.js | 186 + node_modules/ace/lib/ace/mode/diff.js | 52 + .../ace/lib/ace/mode/diff_highlight_rules.js | 108 + node_modules/ace/lib/ace/mode/django.js | 119 + .../ace/mode/doc_comment_highlight_rules.js | 79 + node_modules/ace/lib/ace/mode/dockerfile.js | 52 + .../ace/mode/dockerfile_highlight_rules.js | 57 + node_modules/ace/lib/ace/mode/dot.js | 55 + .../ace/lib/ace/mode/dot_highlight_rules.js | 126 + node_modules/ace/lib/ace/mode/eiffel.js | 52 + .../lib/ace/mode/eiffel_highlight_rules.js | 136 + node_modules/ace/lib/ace/mode/ejs.js | 109 + node_modules/ace/lib/ace/mode/elixir.js | 58 + .../lib/ace/mode/elixir_highlight_rules.js | 433 + node_modules/ace/lib/ace/mode/elm.js | 58 + .../ace/lib/ace/mode/elm_highlight_rules.js | 162 + node_modules/ace/lib/ace/mode/erlang.js | 57 + .../lib/ace/mode/erlang_highlight_rules.js | 876 + .../ace/lib/ace/mode/folding/asciidoc.js | 142 + .../ace/lib/ace/mode/folding/c9search.js | 83 + .../ace/lib/ace/mode/folding/coffee.js | 120 + .../ace/lib/ace/mode/folding/coffee_test.js | 101 + .../ace/lib/ace/mode/folding/csharp.js | 137 + .../ace/lib/ace/mode/folding/cstyle.js | 186 + .../ace/lib/ace/mode/folding/cstyle_test.js | 109 + node_modules/ace/lib/ace/mode/folding/diff.js | 69 + .../ace/lib/ace/mode/folding/fold_mode.js | 120 + node_modules/ace/lib/ace/mode/folding/html.js | 48 + .../ace/lib/ace/mode/folding/html_test.js | 186 + node_modules/ace/lib/ace/mode/folding/ini.js | 80 + .../ace/lib/ace/mode/folding/latex.js | 162 + node_modules/ace/lib/ace/mode/folding/lua.js | 163 + .../ace/lib/ace/mode/folding/markdown.js | 125 + .../ace/lib/ace/mode/folding/mixed.js | 83 + .../ace/lib/ace/mode/folding/pythonic.js | 58 + .../ace/lib/ace/mode/folding/pythonic_test.js | 98 + .../ace/lib/ace/mode/folding/velocity.js | 120 + node_modules/ace/lib/ace/mode/folding/xml.js | 278 + .../ace/lib/ace/mode/folding/xml_test.js | 110 + node_modules/ace/lib/ace/mode/forth.js | 58 + .../ace/lib/ace/mode/forth_highlight_rules.js | 164 + node_modules/ace/lib/ace/mode/ftl.js | 49 + .../ace/lib/ace/mode/ftl_highlight_rules.js | 195 + node_modules/ace/lib/ace/mode/gcode.js | 51 + .../ace/lib/ace/mode/gcode_highlight_rules.js | 94 + node_modules/ace/lib/ace/mode/gherkin.js | 80 + .../lib/ace/mode/gherkin_highlight_rules.js | 113 + node_modules/ace/lib/ace/mode/gitignore.js | 20 + .../lib/ace/mode/gitignore_highlight_rules.js | 31 + node_modules/ace/lib/ace/mode/glsl.js | 56 + .../ace/lib/ace/mode/glsl_highlight_rules.js | 81 + node_modules/ace/lib/ace/mode/golang.js | 55 + .../lib/ace/mode/golang_highlight_rules.js | 108 + node_modules/ace/lib/ace/mode/groovy.js | 24 + .../lib/ace/mode/groovy_highlight_rules.js | 173 + node_modules/ace/lib/ace/mode/haml.js | 61 + .../ace/lib/ace/mode/haml_highlight_rules.js | 132 + node_modules/ace/lib/ace/mode/handlebars.js | 29 + .../ace/mode/handlebars_highlight_rules.js | 72 + node_modules/ace/lib/ace/mode/haskell.js | 62 + .../lib/ace/mode/haskell_highlight_rules.js | 246 + node_modules/ace/lib/ace/mode/haxe.js | 56 + .../ace/lib/ace/mode/haxe_highlight_rules.js | 98 + node_modules/ace/lib/ace/mode/html.js | 106 + .../ace/lib/ace/mode/html/saxparser.js | 10430 ++ .../ace/lib/ace/mode/html_completions.js | 305 + .../ace/lib/ace/mode/html_highlight_rules.js | 111 + node_modules/ace/lib/ace/mode/html_ruby.js | 59 + .../lib/ace/mode/html_ruby_highlight_rules.js | 84 + node_modules/ace/lib/ace/mode/html_test.js | 67 + node_modules/ace/lib/ace/mode/html_worker.js | 92 + node_modules/ace/lib/ace/mode/ini.js | 53 + .../ace/lib/ace/mode/ini_highlight_rules.js | 112 + node_modules/ace/lib/ace/mode/io.js | 58 + .../ace/lib/ace/mode/io_highlight_rules.js | 120 + node_modules/ace/lib/ace/mode/jack.js | 79 + .../ace/lib/ace/mode/jack_highlight_rules.js | 142 + node_modules/ace/lib/ace/mode/jade.js | 57 + .../ace/lib/ace/mode/jade_highlight_rules.js | 341 + node_modules/ace/lib/ace/mode/java.js | 24 + .../ace/lib/ace/mode/java_highlight_rules.js | 128 + node_modules/ace/lib/ace/mode/javascript.js | 116 + .../ace/lib/ace/mode/javascript/jshint.js | 10843 +++ .../ace/mode/javascript_highlight_rules.js | 405 + .../ace/lib/ace/mode/javascript_test.js | 213 + .../ace/lib/ace/mode/javascript_worker.js | 185 + .../lib/ace/mode/javascript_worker_test.js | 106 + .../lib/ace/mode/js_regex_highlight_rules.js | 94 + node_modules/ace/lib/ace/mode/json.js | 93 + .../ace/lib/ace/mode/json/json_parse.js | 346 + .../ace/lib/ace/mode/json_highlight_rules.js | 100 + node_modules/ace/lib/ace/mode/json_worker.js | 67 + .../ace/lib/ace/mode/json_worker_test.js | 102 + node_modules/ace/lib/ace/mode/jsoniq.js | 203 + node_modules/ace/lib/ace/mode/jsp.js | 55 + .../ace/lib/ace/mode/jsp_highlight_rules.js | 91 + node_modules/ace/lib/ace/mode/jsx.js | 56 + .../ace/lib/ace/mode/jsx_highlight_rules.js | 120 + node_modules/ace/lib/ace/mode/julia.js | 62 + .../ace/lib/ace/mode/julia_highlight_rules.js | 170 + node_modules/ace/lib/ace/mode/latex.js | 26 + .../ace/lib/ace/mode/latex_highlight_rules.js | 73 + node_modules/ace/lib/ace/mode/less.js | 84 + .../ace/lib/ace/mode/less_highlight_rules.js | 271 + node_modules/ace/lib/ace/mode/liquid.js | 82 + .../lib/ace/mode/liquid_highlight_rules.js | 131 + node_modules/ace/lib/ace/mode/lisp.js | 56 + .../ace/lib/ace/mode/lisp_highlight_rules.js | 124 + node_modules/ace/lib/ace/mode/livescript.js | 246 + node_modules/ace/lib/ace/mode/logiql.js | 139 + .../lib/ace/mode/logiql_highlight_rules.js | 119 + node_modules/ace/lib/ace/mode/logiql_test.js | 98 + node_modules/ace/lib/ace/mode/lsl.js | 92 + .../ace/lib/ace/mode/lsl_highlight_rules.js | 123 + node_modules/ace/lib/ace/mode/lua.js | 168 + node_modules/ace/lib/ace/mode/lua/luaparse.js | 1989 + .../ace/lib/ace/mode/lua_highlight_rules.js | 193 + node_modules/ace/lib/ace/mode/lua_worker.js | 70 + node_modules/ace/lib/ace/mode/luapage.js | 24 + .../lib/ace/mode/luapage_highlight_rules.js | 49 + node_modules/ace/lib/ace/mode/lucene.js | 19 + .../lib/ace/mode/lucene_highlight_rules.js | 49 + node_modules/ace/lib/ace/mode/makefile.js | 58 + .../lib/ace/mode/makefile_highlight_rules.js | 75 + node_modules/ace/lib/ace/mode/markdown.js | 76 + .../lib/ace/mode/markdown_highlight_rules.js | 228 + node_modules/ace/lib/ace/mode/mask.js | 84 + .../ace/lib/ace/mode/mask_highlight_rules.js | 309 + .../lib/ace/mode/matching_brace_outdent.js | 69 + .../lib/ace/mode/matching_parens_outdent.js | 74 + node_modules/ace/lib/ace/mode/matlab.js | 55 + .../lib/ace/mode/matlab_highlight_rules.js | 262 + node_modules/ace/lib/ace/mode/mel.js | 56 + .../ace/lib/ace/mode/mel_highlight_rules.js | 133 + node_modules/ace/lib/ace/mode/mushcode.js | 116 + .../lib/ace/mode/mushcode_highlight_rules.js | 569 + node_modules/ace/lib/ace/mode/mysql.js | 51 + .../ace/lib/ace/mode/mysql_highlight_rules.js | 122 + node_modules/ace/lib/ace/mode/nix.js | 62 + .../ace/lib/ace/mode/nix_highlight_rules.js | 119 + node_modules/ace/lib/ace/mode/objectivec.js | 61 + .../ace/mode/objectivec_highlight_rules.js | 331 + node_modules/ace/lib/ace/mode/ocaml.js | 97 + .../ace/lib/ace/mode/ocaml_highlight_rules.js | 337 + node_modules/ace/lib/ace/mode/pascal.js | 67 + .../lib/ace/mode/pascal_highlight_rules.js | 127 + node_modules/ace/lib/ace/mode/perl.js | 90 + .../ace/lib/ace/mode/perl_highlight_rules.js | 165 + node_modules/ace/lib/ace/mode/pgsql.js | 59 + .../ace/lib/ace/mode/pgsql_highlight_rules.js | 619 + node_modules/ace/lib/ace/mode/php.js | 161 + node_modules/ace/lib/ace/mode/php/php.js | 5031 + .../ace/lib/ace/mode/php_highlight_rules.js | 1085 + node_modules/ace/lib/ace/mode/php_test.js | 65 + node_modules/ace/lib/ace/mode/php_worker.js | 77 + node_modules/ace/lib/ace/mode/plain_text.js | 55 + .../ace/lib/ace/mode/plain_text_test.js | 56 + node_modules/ace/lib/ace/mode/powershell.js | 61 + .../ace/mode/powershell_highlight_rules.js | 145 + node_modules/ace/lib/ace/mode/praat.js | 84 + .../ace/lib/ace/mode/praat_highlight_rules.js | 262 + node_modules/ace/lib/ace/mode/prolog.js | 62 + .../lib/ace/mode/prolog_highlight_rules.js | 238 + node_modules/ace/lib/ace/mode/properties.js | 48 + .../ace/mode/properties_highlight_rules.js | 86 + node_modules/ace/lib/ace/mode/protobuf.js | 63 + .../lib/ace/mode/protobuf_highlight_rules.js | 66 + node_modules/ace/lib/ace/mode/python.js | 113 + .../lib/ace/mode/python_highlight_rules.js | 191 + node_modules/ace/lib/ace/mode/python_test.js | 79 + node_modules/ace/lib/ace/mode/r.js | 154 + .../ace/lib/ace/mode/r_highlight_rules.js | 208 + node_modules/ace/lib/ace/mode/rdoc.js | 61 + .../ace/lib/ace/mode/rdoc_highlight_rules.js | 119 + node_modules/ace/lib/ace/mode/rhtml.js | 87 + .../ace/lib/ace/mode/rhtml_highlight_rules.js | 66 + node_modules/ace/lib/ace/mode/ruby.js | 100 + .../ace/lib/ace/mode/ruby_highlight_rules.js | 326 + node_modules/ace/lib/ace/mode/ruby_test.js | 77 + node_modules/ace/lib/ace/mode/rust.js | 58 + .../ace/lib/ace/mode/rust_highlight_rules.js | 158 + node_modules/ace/lib/ace/mode/sass.js | 52 + .../ace/lib/ace/mode/sass_highlight_rules.js | 79 + node_modules/ace/lib/ace/mode/scad.js | 99 + .../ace/lib/ace/mode/scad_highlight_rules.js | 142 + node_modules/ace/lib/ace/mode/scala.js | 25 + .../ace/lib/ace/mode/scala_highlight_rules.js | 160 + node_modules/ace/lib/ace/mode/scheme.js | 56 + .../lib/ace/mode/scheme_highlight_rules.js | 123 + node_modules/ace/lib/ace/mode/scss.js | 84 + .../ace/lib/ace/mode/scss_highlight_rules.js | 296 + node_modules/ace/lib/ace/mode/sh.js | 116 + .../ace/lib/ace/mode/sh_highlight_rules.js | 203 + node_modules/ace/lib/ace/mode/sjs.js | 56 + .../ace/lib/ace/mode/sjs_highlight_rules.js | 233 + node_modules/ace/lib/ace/mode/smarty.js | 51 + .../lib/ace/mode/smarty_highlight_rules.js | 139 + node_modules/ace/lib/ace/mode/snippets.js | 113 + node_modules/ace/lib/ace/mode/soy_template.js | 60 + .../ace/mode/soy_template_highlight_rules.js | 356 + node_modules/ace/lib/ace/mode/space.js | 21 + .../ace/lib/ace/mode/space_highlight_rules.js | 56 + node_modules/ace/lib/ace/mode/sql.js | 53 + .../ace/lib/ace/mode/sql_highlight_rules.js | 99 + node_modules/ace/lib/ace/mode/stylus.js | 62 + .../lib/ace/mode/stylus_highlight_rules.js | 165 + node_modules/ace/lib/ace/mode/svg.js | 69 + .../ace/lib/ace/mode/svg_highlight_rules.js | 49 + node_modules/ace/lib/ace/mode/tcl.js | 84 + .../ace/lib/ace/mode/tcl_highlight_rules.js | 172 + node_modules/ace/lib/ace/mode/tex.js | 68 + .../ace/lib/ace/mode/tex_highlight_rules.js | 127 + node_modules/ace/lib/ace/mode/text.js | 386 + .../ace/lib/ace/mode/text_highlight_rules.js | 234 + node_modules/ace/lib/ace/mode/text_test.js | 64 + node_modules/ace/lib/ace/mode/textile.js | 67 + .../lib/ace/mode/textile_highlight_rules.js | 93 + node_modules/ace/lib/ace/mode/toml.js | 56 + .../ace/lib/ace/mode/toml_highlight_rules.js | 103 + node_modules/ace/lib/ace/mode/twig.js | 81 + .../ace/lib/ace/mode/twig_highlight_rules.js | 166 + node_modules/ace/lib/ace/mode/typescript.js | 62 + .../ace/mode/typescript_highlight_rules.js | 98 + node_modules/ace/lib/ace/mode/vala.js | 105 + .../ace/lib/ace/mode/vala_highlight_rules.js | 457 + node_modules/ace/lib/ace/mode/vbscript.js | 60 + .../lib/ace/mode/vbscript_highlight_rules.js | 246 + node_modules/ace/lib/ace/mode/velocity.js | 58 + .../lib/ace/mode/velocity_highlight_rules.js | 177 + node_modules/ace/lib/ace/mode/verilog.js | 54 + .../lib/ace/mode/verilog_highlight_rules.js | 101 + node_modules/ace/lib/ace/mode/vhdl.js | 52 + .../ace/lib/ace/mode/vhdl_highlight_rules.js | 115 + node_modules/ace/lib/ace/mode/xml.js | 75 + .../ace/lib/ace/mode/xml/dom-parser.js | 260 + node_modules/ace/lib/ace/mode/xml/dom.js | 1138 + node_modules/ace/lib/ace/mode/xml/sax.js | 592 + .../ace/lib/ace/mode/xml_highlight_rules.js | 242 + node_modules/ace/lib/ace/mode/xml_test.js | 75 + node_modules/ace/lib/ace/mode/xml_worker.js | 92 + node_modules/ace/lib/ace/mode/xquery.js | 216 + .../ace/lib/ace/mode/xquery/Readme.md | 1 + .../ace/lib/ace/mode/xquery/jsoniq_lexer.js | 4453 + .../ace/lib/ace/mode/xquery/xqlint.js | 78911 ++++++++++++++++ .../ace/lib/ace/mode/xquery/xquery_lexer.js | 4422 + .../ace/lib/ace/mode/xquery_worker.js | 114 + node_modules/ace/lib/ace/mode/yaml.js | 78 + .../ace/lib/ace/mode/yaml_highlight_rules.js | 113 + node_modules/ace/lib/ace/model/editor.js | 62 + .../lib/ace/mouse/default_gutter_handler.js | 183 + .../ace/lib/ace/mouse/default_handlers.js | 278 + .../ace/lib/ace/mouse/dragdrop_handler.js | 424 + .../ace/lib/ace/mouse/fold_handler.js | 93 + node_modules/ace/lib/ace/mouse/mouse_event.js | 129 + .../ace/lib/ace/mouse/mouse_handler.js | 205 + .../ace/lib/ace/mouse/mouse_handler_test.js | 77 + .../ace/lib/ace/mouse/multi_select_handler.js | 204 + node_modules/ace/lib/ace/multi_select.js | 965 + node_modules/ace/lib/ace/multi_select_test.js | 285 + node_modules/ace/lib/ace/occur.js | 193 + node_modules/ace/lib/ace/occur_test.js | 154 + node_modules/ace/lib/ace/placeholder.js | 273 + node_modules/ace/lib/ace/placeholder_test.js | 157 + node_modules/ace/lib/ace/range.js | 549 + node_modules/ace/lib/ace/range_list.js | 239 + node_modules/ace/lib/ace/range_list_test.js | 182 + node_modules/ace/lib/ace/range_test.js | 191 + node_modules/ace/lib/ace/renderloop.js | 75 + node_modules/ace/lib/ace/requirejs/text.js | 52 + .../ace/lib/ace/requirejs/text_build.js | 60 + node_modules/ace/lib/ace/scrollbar.js | 270 + node_modules/ace/lib/ace/search.js | 403 + node_modules/ace/lib/ace/search_highlight.js | 82 + node_modules/ace/lib/ace/search_test.js | 494 + node_modules/ace/lib/ace/selection.js | 955 + node_modules/ace/lib/ace/selection_test.js | 480 + node_modules/ace/lib/ace/snippets.js | 949 + node_modules/ace/lib/ace/snippets/_.snippets | 240 + .../ace/lib/ace/snippets/_all_modes.js | 7 + .../ace/lib/ace/snippets/_all_modes.snippets | 0 node_modules/ace/lib/ace/snippets/abap.js | 7 + .../ace/lib/ace/snippets/abap.snippets | 0 node_modules/ace/lib/ace/snippets/abc.js | 7 + .../ace/lib/ace/snippets/abc.snippets | 31 + .../ace/lib/ace/snippets/actionscript.js | 7 + .../lib/ace/snippets/actionscript.snippets | 157 + node_modules/ace/lib/ace/snippets/ada.js | 7 + .../ace/lib/ace/snippets/ada.snippets | 0 .../ace/lib/ace/snippets/all_modes.js | 7 + .../ace/lib/ace/snippets/all_modes.snippets | 0 .../ace/lib/ace/snippets/apache.snippets | 35 + .../ace/lib/ace/snippets/apache_conf.js | 7 + .../ace/lib/ace/snippets/apache_conf.snippets | 0 .../ace/lib/ace/snippets/applescript.js | 7 + .../ace/lib/ace/snippets/applescript.snippets | 0 node_modules/ace/lib/ace/snippets/asciidoc.js | 7 + .../ace/lib/ace/snippets/asciidoc.snippets | 0 .../ace/lib/ace/snippets/assembly_x86.js | 7 + .../lib/ace/snippets/assembly_x86.snippets | 0 .../ace/lib/ace/snippets/autohotkey.js | 7 + .../ace/lib/ace/snippets/autohotkey.snippets | 0 .../ace/lib/ace/snippets/autoit.snippets | 66 + .../ace/lib/ace/snippets/batchfile.js | 7 + .../ace/lib/ace/snippets/batchfile.snippets | 0 node_modules/ace/lib/ace/snippets/c.snippets | 235 + node_modules/ace/lib/ace/snippets/c9search.js | 7 + .../ace/lib/ace/snippets/c9search.snippets | 0 node_modules/ace/lib/ace/snippets/c_cpp.js | 7 + .../ace/lib/ace/snippets/c_cpp.snippets | 131 + .../ace/lib/ace/snippets/chef.snippets | 204 + node_modules/ace/lib/ace/snippets/cirru.js | 7 + .../ace/lib/ace/snippets/cirru.snippets | 0 node_modules/ace/lib/ace/snippets/clojure.js | 7 + .../ace/lib/ace/snippets/clojure.snippets | 90 + .../ace/lib/ace/snippets/cmake.snippets | 58 + node_modules/ace/lib/ace/snippets/cobol.js | 7 + .../ace/lib/ace/snippets/cobol.snippets | 0 node_modules/ace/lib/ace/snippets/coffee.js | 7 + .../ace/lib/ace/snippets/coffee.snippets | 95 + .../ace/lib/ace/snippets/coldfusion.js | 7 + .../ace/lib/ace/snippets/coldfusion.snippets | 0 node_modules/ace/lib/ace/snippets/cs.snippets | 374 + node_modules/ace/lib/ace/snippets/csharp.js | 7 + .../ace/lib/ace/snippets/csharp.snippets | 0 node_modules/ace/lib/ace/snippets/css.js | 7 + .../ace/lib/ace/snippets/css.snippets | 6 + node_modules/ace/lib/ace/snippets/curly.js | 7 + .../ace/lib/ace/snippets/curly.snippets | 0 node_modules/ace/lib/ace/snippets/d.js | 7 + node_modules/ace/lib/ace/snippets/d.snippets | 0 node_modules/ace/lib/ace/snippets/dart.js | 7 + .../ace/lib/ace/snippets/dart.snippets | 83 + node_modules/ace/lib/ace/snippets/diff.js | 7 + .../ace/lib/ace/snippets/diff.snippets | 11 + node_modules/ace/lib/ace/snippets/django.js | 7 + .../ace/lib/ace/snippets/django.snippets | 108 + .../ace/lib/ace/snippets/dockerfile.js | 7 + .../ace/lib/ace/snippets/dockerfile.snippets | 0 node_modules/ace/lib/ace/snippets/dot.js | 7 + .../ace/lib/ace/snippets/dot.snippets | 0 node_modules/ace/lib/ace/snippets/dummy.js | 7 + .../ace/lib/ace/snippets/dummy_syntax.js | 7 + node_modules/ace/lib/ace/snippets/eiffel.js | 7 + .../ace/lib/ace/snippets/eiffel.snippets | 0 node_modules/ace/lib/ace/snippets/ejs.js | 7 + .../ace/lib/ace/snippets/ejs.snippets | 0 node_modules/ace/lib/ace/snippets/elixir.js | 7 + .../ace/lib/ace/snippets/elixir.snippets | 0 node_modules/ace/lib/ace/snippets/elm.js | 7 + .../ace/lib/ace/snippets/elm.snippets | 0 node_modules/ace/lib/ace/snippets/erlang.js | 7 + .../ace/lib/ace/snippets/erlang.snippets | 160 + .../ace/lib/ace/snippets/eruby.snippets | 113 + .../ace/lib/ace/snippets/falcon.snippets | 71 + node_modules/ace/lib/ace/snippets/forth.js | 7 + .../ace/lib/ace/snippets/forth.snippets | 0 node_modules/ace/lib/ace/snippets/ftl.js | 7 + .../ace/lib/ace/snippets/ftl.snippets | 0 node_modules/ace/lib/ace/snippets/gcode.js | 7 + .../ace/lib/ace/snippets/gcode.snippets | 0 node_modules/ace/lib/ace/snippets/gherkin.js | 7 + .../ace/lib/ace/snippets/gherkin.snippets | 0 .../ace/lib/ace/snippets/gitignore.js | 7 + .../ace/lib/ace/snippets/gitignore.snippets | 0 node_modules/ace/lib/ace/snippets/glsl.js | 7 + .../ace/lib/ace/snippets/glsl.snippets | 0 node_modules/ace/lib/ace/snippets/go.snippets | 201 + node_modules/ace/lib/ace/snippets/golang.js | 7 + .../ace/lib/ace/snippets/golang.snippets | 0 node_modules/ace/lib/ace/snippets/groovy.js | 7 + .../ace/lib/ace/snippets/groovy.snippets | 0 node_modules/ace/lib/ace/snippets/haml.js | 7 + .../ace/lib/ace/snippets/haml.snippets | 20 + .../ace/lib/ace/snippets/handlebars.js | 7 + .../ace/lib/ace/snippets/handlebars.snippets | 0 node_modules/ace/lib/ace/snippets/haskell.js | 7 + .../ace/lib/ace/snippets/haskell.snippets | 82 + node_modules/ace/lib/ace/snippets/haxe.js | 7 + .../ace/lib/ace/snippets/haxe.snippets | 0 node_modules/ace/lib/ace/snippets/html.js | 7 + .../ace/lib/ace/snippets/html.snippets | 49 + .../ace/lib/ace/snippets/html_ruby.js | 7 + .../ace/lib/ace/snippets/html_ruby.snippets | 0 .../ace/lib/ace/snippets/htmldjango.snippets | 136 + .../ace/lib/ace/snippets/htmltornado.snippets | 55 + node_modules/ace/lib/ace/snippets/ini.js | 7 + .../ace/lib/ace/snippets/ini.snippets | 0 node_modules/ace/lib/ace/snippets/io.js | 69 + node_modules/ace/lib/ace/snippets/io.snippets | 0 node_modules/ace/lib/ace/snippets/jack.js | 7 + .../ace/lib/ace/snippets/jack.snippets | 0 node_modules/ace/lib/ace/snippets/jade.js | 7 + .../ace/lib/ace/snippets/jade.snippets | 0 node_modules/ace/lib/ace/snippets/java.js | 7 + .../ace/lib/ace/snippets/java.snippets | 240 + .../ace/snippets/javascript-jquery.snippets | 589 + .../ace/lib/ace/snippets/javascript.js | 7 + .../ace/lib/ace/snippets/javascript.snippets | 195 + node_modules/ace/lib/ace/snippets/json.js | 7 + .../ace/lib/ace/snippets/json.snippets | 0 node_modules/ace/lib/ace/snippets/jsoniq.js | 7 + .../ace/lib/ace/snippets/jsoniq.snippets | 61 + node_modules/ace/lib/ace/snippets/jsp.js | 7 + .../ace/lib/ace/snippets/jsp.snippets | 99 + node_modules/ace/lib/ace/snippets/jsx.js | 7 + .../ace/lib/ace/snippets/jsx.snippets | 0 node_modules/ace/lib/ace/snippets/julia.js | 7 + .../ace/lib/ace/snippets/julia.snippets | 0 node_modules/ace/lib/ace/snippets/latex.js | 7 + .../ace/lib/ace/snippets/latex.snippets | 0 .../ace/lib/ace/snippets/ledger.snippets | 5 + node_modules/ace/lib/ace/snippets/less.js | 7 + .../ace/lib/ace/snippets/less.snippets | 0 node_modules/ace/lib/ace/snippets/liquid.js | 7 + .../ace/lib/ace/snippets/liquid.snippets | 0 node_modules/ace/lib/ace/snippets/lisp.js | 7 + .../ace/lib/ace/snippets/lisp.snippets | 0 .../ace/lib/ace/snippets/livescript.js | 7 + .../ace/lib/ace/snippets/livescript.snippets | 0 node_modules/ace/lib/ace/snippets/logiql.js | 7 + .../ace/lib/ace/snippets/logiql.snippets | 0 node_modules/ace/lib/ace/snippets/lsl.js | 7 + .../ace/lib/ace/snippets/lsl.snippets | 1066 + node_modules/ace/lib/ace/snippets/lua.js | 7 + .../ace/lib/ace/snippets/lua.snippets | 21 + node_modules/ace/lib/ace/snippets/luapage.js | 7 + .../ace/lib/ace/snippets/luapage.snippets | 0 node_modules/ace/lib/ace/snippets/lucene.js | 7 + .../ace/lib/ace/snippets/lucene.snippets | 0 node_modules/ace/lib/ace/snippets/makefile.js | 7 + .../ace/lib/ace/snippets/makefile.snippets | 4 + .../ace/lib/ace/snippets/mako.snippets | 54 + node_modules/ace/lib/ace/snippets/markdown.js | 7 + .../ace/lib/ace/snippets/markdown.snippets | 88 + node_modules/ace/lib/ace/snippets/matlab.js | 7 + .../ace/lib/ace/snippets/matlab.snippets | 0 node_modules/ace/lib/ace/snippets/mel.js | 7 + .../ace/lib/ace/snippets/mel.snippets | 0 node_modules/ace/lib/ace/snippets/mushcode.js | 7 + .../ace/lib/ace/snippets/mushcode.snippets | 0 .../lib/ace/snippets/mushcode_high_rules.js | 7 + .../ace/snippets/mushcode_high_rules.snippets | 0 node_modules/ace/lib/ace/snippets/mysql.js | 7 + .../ace/lib/ace/snippets/mysql.snippets | 0 node_modules/ace/lib/ace/snippets/nix.js | 7 + .../ace/lib/ace/snippets/nix.snippets | 0 .../ace/lib/ace/snippets/objc.snippets | 247 + .../ace/lib/ace/snippets/objectivec.js | 7 + .../ace/lib/ace/snippets/objectivec.snippets | 0 node_modules/ace/lib/ace/snippets/ocaml.js | 7 + .../ace/lib/ace/snippets/ocaml.snippets | 0 node_modules/ace/lib/ace/snippets/pascal.js | 7 + .../ace/lib/ace/snippets/pascal.snippets | 0 node_modules/ace/lib/ace/snippets/perl.js | 7 + .../ace/lib/ace/snippets/perl.snippets | 347 + node_modules/ace/lib/ace/snippets/pgsql.js | 7 + .../ace/lib/ace/snippets/pgsql.snippets | 0 node_modules/ace/lib/ace/snippets/php.js | 7 + .../ace/lib/ace/snippets/php.snippets | 377 + .../ace/lib/ace/snippets/plain_text.js | 7 + .../ace/lib/ace/snippets/plain_text.snippets | 0 .../ace/lib/ace/snippets/powershell.js | 7 + .../ace/lib/ace/snippets/powershell.snippets | 0 node_modules/ace/lib/ace/snippets/praat.js | 7 + .../ace/lib/ace/snippets/praat.snippets | 0 node_modules/ace/lib/ace/snippets/prolog.js | 7 + .../ace/lib/ace/snippets/prolog.snippets | 0 .../ace/lib/ace/snippets/properties.js | 7 + .../ace/lib/ace/snippets/properties.snippets | 0 node_modules/ace/lib/ace/snippets/protobuf.js | 7 + .../ace/lib/ace/snippets/protobuf.snippets | 0 node_modules/ace/lib/ace/snippets/python.js | 7 + .../ace/lib/ace/snippets/python.snippets | 158 + node_modules/ace/lib/ace/snippets/r.js | 7 + node_modules/ace/lib/ace/snippets/r.snippets | 121 + node_modules/ace/lib/ace/snippets/rdoc.js | 7 + .../ace/lib/ace/snippets/rdoc.snippets | 0 node_modules/ace/lib/ace/snippets/rhtml.js | 7 + .../ace/lib/ace/snippets/rhtml.snippets | 0 .../ace/lib/ace/snippets/rst.snippets | 22 + node_modules/ace/lib/ace/snippets/ruby.js | 7 + .../ace/lib/ace/snippets/ruby.snippets | 928 + node_modules/ace/lib/ace/snippets/rust.js | 7 + .../ace/lib/ace/snippets/rust.snippets | 0 node_modules/ace/lib/ace/snippets/sass.js | 7 + .../ace/lib/ace/snippets/sass.snippets | 0 node_modules/ace/lib/ace/snippets/scad.js | 7 + .../ace/lib/ace/snippets/scad.snippets | 0 node_modules/ace/lib/ace/snippets/scala.js | 7 + .../ace/lib/ace/snippets/scala.snippets | 0 node_modules/ace/lib/ace/snippets/scheme.js | 7 + .../ace/lib/ace/snippets/scheme.snippets | 0 node_modules/ace/lib/ace/snippets/scss.js | 7 + .../ace/lib/ace/snippets/scss.snippets | 0 node_modules/ace/lib/ace/snippets/sh.js | 7 + node_modules/ace/lib/ace/snippets/sh.snippets | 83 + node_modules/ace/lib/ace/snippets/sjs.js | 7 + .../ace/lib/ace/snippets/sjs.snippets | 0 node_modules/ace/lib/ace/snippets/smarty.js | 7 + .../ace/lib/ace/snippets/smarty.snippets | 0 node_modules/ace/lib/ace/snippets/snippets.js | 7 + .../ace/lib/ace/snippets/snippets.snippets | 9 + .../ace/lib/ace/snippets/soy_template.js | 7 + .../lib/ace/snippets/soy_template.snippets | 0 node_modules/ace/lib/ace/snippets/space.js | 7 + .../ace/lib/ace/snippets/space.snippets | 0 node_modules/ace/lib/ace/snippets/sql.js | 7 + .../ace/lib/ace/snippets/sql.snippets | 26 + node_modules/ace/lib/ace/snippets/stylus.js | 7 + .../ace/lib/ace/snippets/stylus.snippets | 0 node_modules/ace/lib/ace/snippets/svg.js | 7 + .../ace/lib/ace/snippets/svg.snippets | 0 node_modules/ace/lib/ace/snippets/tcl.js | 7 + .../ace/lib/ace/snippets/tcl.snippets | 92 + node_modules/ace/lib/ace/snippets/tex.js | 7 + .../ace/lib/ace/snippets/tex.snippets | 191 + node_modules/ace/lib/ace/snippets/text.js | 7 + .../ace/lib/ace/snippets/text.snippets | 0 node_modules/ace/lib/ace/snippets/textile.js | 7 + .../ace/lib/ace/snippets/textile.snippets | 30 + .../ace/lib/ace/snippets/tmsnippet.snippets | 0 node_modules/ace/lib/ace/snippets/toml.js | 7 + .../ace/lib/ace/snippets/toml.snippets | 0 node_modules/ace/lib/ace/snippets/twig.js | 7 + .../ace/lib/ace/snippets/twig.snippets | 0 .../ace/lib/ace/snippets/typescript.js | 7 + .../ace/lib/ace/snippets/typescript.snippets | 0 node_modules/ace/lib/ace/snippets/vala.js | 195 + .../ace/lib/ace/snippets/vala.snippets | 0 node_modules/ace/lib/ace/snippets/vbscript.js | 7 + .../ace/lib/ace/snippets/vbscript.snippets | 0 node_modules/ace/lib/ace/snippets/velocity.js | 8 + .../ace/lib/ace/snippets/velocity.snippets | 28 + node_modules/ace/lib/ace/snippets/verilog.js | 7 + .../ace/lib/ace/snippets/verilog.snippets | 0 node_modules/ace/lib/ace/snippets/vhdl.js | 7 + .../ace/lib/ace/snippets/vhdl.snippets | 0 node_modules/ace/lib/ace/snippets/xml.js | 7 + .../ace/lib/ace/snippets/xml.snippets | 0 node_modules/ace/lib/ace/snippets/xquery.js | 7 + .../ace/lib/ace/snippets/xquery.snippets | 61 + .../ace/lib/ace/snippets/xslt.snippets | 97 + node_modules/ace/lib/ace/snippets/yaml.js | 7 + .../ace/lib/ace/snippets/yaml.snippets | 0 node_modules/ace/lib/ace/snippets_test.js | 131 + node_modules/ace/lib/ace/split.js | 373 + node_modules/ace/lib/ace/test/all.js | 35 + node_modules/ace/lib/ace/test/all_browser.js | 151 + node_modules/ace/lib/ace/test/assertions.js | 56 + .../ace/lib/ace/test/asyncjs/assert.js | 313 + .../ace/lib/ace/test/asyncjs/async.js | 529 + .../ace/lib/ace/test/asyncjs/index.js | 13 + node_modules/ace/lib/ace/test/asyncjs/test.js | 195 + .../ace/lib/ace/test/asyncjs/utils.js | 65 + node_modules/ace/lib/ace/test/benchmark.js | 78 + node_modules/ace/lib/ace/test/mockdom.js | 10 + node_modules/ace/lib/ace/test/mockrenderer.js | 208 + node_modules/ace/lib/ace/test/tests.html | 46 + node_modules/ace/lib/ace/theme/ambiance.css | 221 + node_modules/ace/lib/ace/theme/ambiance.js | 33 + node_modules/ace/lib/ace/theme/chaos.css | 154 + node_modules/ace/lib/ace/theme/chaos.js | 33 + node_modules/ace/lib/ace/theme/chrome.css | 154 + node_modules/ace/lib/ace/theme/chrome.js | 39 + node_modules/ace/lib/ace/theme/cloud9_day.css | 155 + node_modules/ace/lib/ace/theme/cloud9_day.js | 40 + .../ace/lib/ace/theme/cloud9_night.css | 140 + .../ace/lib/ace/theme/cloud9_night.js | 39 + .../lib/ace/theme/cloud9_night_low_color.css | 129 + .../lib/ace/theme/cloud9_night_low_color.js | 39 + node_modules/ace/lib/ace/theme/clouds.css | 112 + node_modules/ace/lib/ace/theme/clouds.js | 39 + .../ace/lib/ace/theme/clouds_midnight.css | 113 + .../ace/lib/ace/theme/clouds_midnight.js | 39 + node_modules/ace/lib/ace/theme/cobalt.css | 134 + node_modules/ace/lib/ace/theme/cobalt.js | 39 + .../ace/lib/ace/theme/crimson_editor.css | 143 + .../ace/lib/ace/theme/crimson_editor.js | 39 + node_modules/ace/lib/ace/theme/dawn.css | 127 + node_modules/ace/lib/ace/theme/dawn.js | 39 + .../ace/lib/ace/theme/dreamweaver.css | 176 + node_modules/ace/lib/ace/theme/dreamweaver.js | 38 + node_modules/ace/lib/ace/theme/eclipse.css | 113 + node_modules/ace/lib/ace/theme/eclipse.js | 41 + node_modules/ace/lib/ace/theme/github.css | 119 + node_modules/ace/lib/ace/theme/github.js | 39 + .../ace/lib/ace/theme/idle_fingers.css | 113 + .../ace/lib/ace/theme/idle_fingers.js | 39 + .../ace/lib/ace/theme/katzenmilch.css | 140 + node_modules/ace/lib/ace/theme/katzenmilch.js | 39 + node_modules/ace/lib/ace/theme/kr_theme.css | 124 + node_modules/ace/lib/ace/theme/kr_theme.js | 39 + node_modules/ace/lib/ace/theme/kuroir.css | 67 + node_modules/ace/lib/ace/theme/kuroir.js | 39 + node_modules/ace/lib/ace/theme/merbivore.css | 110 + node_modules/ace/lib/ace/theme/merbivore.js | 39 + .../ace/lib/ace/theme/merbivore_soft.css | 111 + .../ace/lib/ace/theme/merbivore_soft.js | 39 + .../ace/lib/ace/theme/mono_industrial.css | 126 + .../ace/lib/ace/theme/mono_industrial.js | 39 + node_modules/ace/lib/ace/theme/monokai.css | 122 + node_modules/ace/lib/ace/theme/monokai.js | 39 + .../ace/lib/ace/theme/pastel_on_dark.css | 129 + .../ace/lib/ace/theme/pastel_on_dark.js | 39 + .../ace/lib/ace/theme/solarized_dark.css | 101 + .../ace/lib/ace/theme/solarized_dark.js | 39 + .../ace/lib/ace/theme/solarized_light.css | 106 + .../ace/lib/ace/theme/solarized_light.js | 39 + node_modules/ace/lib/ace/theme/terminal.css | 132 + node_modules/ace/lib/ace/theme/terminal.js | 39 + node_modules/ace/lib/ace/theme/textmate.css | 155 + node_modules/ace/lib/ace/theme/textmate.js | 40 + node_modules/ace/lib/ace/theme/tomorrow.css | 125 + node_modules/ace/lib/ace/theme/tomorrow.js | 39 + .../ace/lib/ace/theme/tomorrow_night.css | 125 + .../ace/lib/ace/theme/tomorrow_night.js | 39 + .../ace/lib/ace/theme/tomorrow_night_blue.css | 122 + .../ace/lib/ace/theme/tomorrow_night_blue.js | 39 + .../lib/ace/theme/tomorrow_night_bright.css | 141 + .../lib/ace/theme/tomorrow_night_bright.js | 39 + .../lib/ace/theme/tomorrow_night_eighties.css | 125 + .../lib/ace/theme/tomorrow_night_eighties.js | 39 + node_modules/ace/lib/ace/theme/twilight.css | 128 + node_modules/ace/lib/ace/theme/twilight.js | 39 + .../ace/lib/ace/theme/vibrant_ink.css | 110 + node_modules/ace/lib/ace/theme/vibrant_ink.js | 39 + node_modules/ace/lib/ace/theme/xcode.css | 103 + node_modules/ace/lib/ace/theme/xcode.js | 39 + node_modules/ace/lib/ace/token_iterator.js | 150 + .../ace/lib/ace/token_iterator_test.js | 212 + node_modules/ace/lib/ace/tokenizer.js | 362 + node_modules/ace/lib/ace/tokenizer_dev.js | 183 + node_modules/ace/lib/ace/tokenizer_test.js | 97 + node_modules/ace/lib/ace/tooltip.js | 138 + node_modules/ace/lib/ace/undomanager.js | 215 + node_modules/ace/lib/ace/unicode.js | 107 + node_modules/ace/lib/ace/virtual_renderer.js | 1761 + .../ace/lib/ace/virtual_renderer_test.js | 86 + node_modules/ace/lib/ace/worker/mirror.js | 75 + node_modules/ace/lib/ace/worker/worker.js | 194 + .../ace/lib/ace/worker/worker_client.js | 258 + .../ace/lib/ace/worker/worker_test.js | 125 + node_modules/ace/package.json | 37 + node_modules/ace/static.js | 109 + node_modules/ace/static.py | 298 + node_modules/ace/tool/Readme.md | 26 + node_modules/ace/tool/add_mode.js | 106 + node_modules/ace/tool/lib.js | 78 + node_modules/ace/tool/mode_creator.html | 101 + node_modules/ace/tool/mode_creator.js | 259 + node_modules/ace/tool/package.json | 9 + node_modules/ace/tool/perf-test.html | 410 + node_modules/ace/tool/regexp_tokenizer.js | 114 + .../ace/tool/regexp_tokenizer_test.js | 30 + node_modules/ace/tool/release.sh | 74 + .../ace/tool/templates/dummy.JSON-tmLanguage | 45 + .../ace/tool/templates/highlight_rules.js | 58 + node_modules/ace/tool/templates/mode.js | 58 + node_modules/ace/tool/templates/snippets.js | 7 + node_modules/ace/tool/templates/theme.css | 60 + node_modules/ace/tool/templates/theme.js | 39 + node_modules/ace/tool/tmlanguage.js | 697 + node_modules/ace/tool/tmsnippets.js | 82 + node_modules/ace/tool/tmtheme.js | 412 + .../ace/tool/tmthemes/Active4D.tmTheme | 407 + .../ace/tool/tmthemes/All Hallows Eve.tmTheme | 277 + node_modules/ace/tool/tmthemes/Amy.tmTheme | 557 + .../ace/tool/tmthemes/Blackboard.tmTheme | 350 + .../tool/tmthemes/Brilliance Black.tmTheme | 2619 + .../ace/tool/tmthemes/Brilliance Dull.tmTheme | 2243 + .../ace/tool/tmthemes/Chrome DevTools.tmTheme | 294 + .../ace/tool/tmthemes/Clouds Midnight.tmTheme | 361 + node_modules/ace/tool/tmthemes/Clouds.tmTheme | 348 + node_modules/ace/tool/tmthemes/Cobalt.tmTheme | 559 + node_modules/ace/tool/tmthemes/Dawn.tmTheme | 437 + .../ace/tool/tmthemes/Dreamweaver.tmTheme | 521 + node_modules/ace/tool/tmthemes/Eiffel.tmTheme | 439 + .../ace/tool/tmthemes/Espresso Libre.tmTheme | 402 + node_modules/ace/tool/tmthemes/GitHub.tmTheme | 573 + node_modules/ace/tool/tmthemes/IDLE.tmTheme | 235 + .../ace/tool/tmthemes/Katzenmilch.tmTheme | 399 + .../ace/tool/tmthemes/Kuroir Theme.tmTheme | 916 + node_modules/ace/tool/tmthemes/LAZY.tmTheme | 291 + node_modules/ace/tool/tmthemes/LICENSE | 8 + .../ace/tool/tmthemes/MagicWB (Amiga).tmTheme | 376 + .../ace/tool/tmthemes/Merbivore Soft.tmTheme | 322 + .../ace/tool/tmthemes/Merbivore.tmTheme | 296 + .../ace/tool/tmthemes/Monokai.tmTheme | 387 + .../ace/tool/tmthemes/Pastels on Dark.tmTheme | 727 + .../tool/tmthemes/Slush and Poppies.tmTheme | 336 + .../ace/tool/tmthemes/Solarized-dark.tmTheme | 312 + .../ace/tool/tmthemes/Solarized-light.tmTheme | 305 + .../ace/tool/tmthemes/SpaceCadet.tmTheme | 212 + .../ace/tool/tmthemes/Sunburst.tmTheme | 665 + .../tmthemes/Textmate (Mac Classic).tmTheme | 450 + .../tool/tmthemes/Tomorrow-Night-Blue.tmTheme | 186 + .../tmthemes/Tomorrow-Night-Bright.tmTheme | 186 + .../tmthemes/Tomorrow-Night-Eighties.tmTheme | 186 + .../ace/tool/tmthemes/Tomorrow-Night.tmTheme | 186 + .../ace/tool/tmthemes/Tomorrow.tmTheme | 186 + .../ace/tool/tmthemes/Twilight.tmTheme | 527 + .../ace/tool/tmthemes/Vibrant Ink.tmTheme | 460 + .../ace/tool/tmthemes/Xcode_default.tmTheme | 240 + .../ace/tool/tmthemes/Zenburnesque.tmTheme | 343 + .../ace/tool/tmthemes/iPlastic.tmTheme | 286 + .../ace/tool/tmthemes/idleFingers.tmTheme | 393 + .../ace/tool/tmthemes/krTheme.tmTheme | 551 + .../ace/tool/tmthemes/monoindustrial.tmTheme | 451 + node_modules/ace/tool/update_deps.js | 324 + node_modules/ace/tool/wrap_keyword_regexp.js | 21 + node_modules/ace/version.js | 4 + node_modules/ace_tree/.gitignore | 20 + node_modules/ace_tree/LICENSE | 15 + node_modules/ace_tree/demo.html | 25 + node_modules/ace_tree/demo/demo.js | 117 + node_modules/ace_tree/demo/layout.js | 134 + node_modules/ace_tree/demo/styles.css | 52 + node_modules/ace_tree/demo/util.js | 238 + node_modules/ace_tree/lib/ace_tree/anchor.js | 242 + .../lib/ace_tree/commands/default_commands.js | 159 + node_modules/ace_tree/lib/ace_tree/config.js | 273 + .../ace_tree/lib/ace_tree/config_test.js | 118 + .../ace_tree/lib/ace_tree/css/light_theme.css | 90 + .../ace_tree/lib/ace_tree/css/light_theme.js | 33 + .../ace_tree/lib/ace_tree/css/tree.css | 191 + .../lib/ace_tree/css/tree_background.png | Bin 0 -> 3676 bytes .../ace_tree/css/tree_close_arrow_small.png | Bin 0 -> 3077 bytes .../ace_tree/lib/ace_tree/data_provider.js | 480 + .../lib/ace_tree/data_provider_mirror.js | 71 + .../lib/ace_tree/data_provider_test.js | 96 + node_modules/ace_tree/lib/ace_tree/edit.js | 396 + node_modules/ace_tree/lib/ace_tree/filter.js | 140 + .../ace_tree/lib/ace_tree/layer/cells.js | 199 + .../ace_tree/lib/ace_tree/layer/heading.js | 193 + .../ace_tree/lib/ace_tree/layer/markers.js | 153 + .../ace_tree/lib/ace_tree/lib/btree.js | 501 + .../ace_tree/lib/ace_tree/lib/btree_test.js | 266 + .../ace_tree/lib/ace_tree/list_data.js | 85 + .../lib/ace_tree/mouse/default_handlers.js | 253 + .../lib/ace_tree/mouse/drag_handler.js | 293 + .../lib/ace_tree/mouse/heading_handler.js | 74 + .../lib/ace_tree/mouse/mouse_event.js | 129 + .../lib/ace_tree/mouse/mouse_handler.js | 144 + .../ace_tree/lib/ace_tree/quicksearch.js | 40 + .../ace_tree/lib/ace_tree/scrollable.js | 45 + .../ace_tree/lib/ace_tree/selection.js | 269 + .../ace_tree/lib/ace_tree/selection_test.js | 465 + .../ace_tree/lib/ace_tree/test/setup_paths.js | 19 + node_modules/ace_tree/lib/ace_tree/tooltip.js | 93 + node_modules/ace_tree/lib/ace_tree/tree.js | 726 + .../ace_tree/lib/ace_tree/undomanager.js | 135 + .../ace_tree/lib/ace_tree/virtual_renderer.js | 1166 + .../lib/ace_tree/virtual_renderer_test.js | 86 + node_modules/ace_tree/list.txt | 1318 + node_modules/ace_tree/list_demo.html | 71 + node_modules/ace_tree/package.json | 6 + node_modules/architect-build/.gitignore | 1 + node_modules/architect-build/LICENSE | 21 + node_modules/architect-build/README.md | 1 + node_modules/architect-build/build.js | 380 + .../build_support/mini_require.js | 218 + node_modules/architect-build/compress.js | 126 + .../architect-build/compress_folder.js | 47 + node_modules/architect-build/copy.js | 133 + node_modules/architect-build/module-deps.js | 401 + node_modules/architect-build/npm_build.js | 208 + node_modules/architect-build/package.json | 32 + node_modules/architect/.gitignore | 3 + node_modules/architect/.jamignore | 1 + node_modules/architect/.npmignore | 1 + node_modules/architect/LICENSE | 21 + node_modules/architect/README.markdown | 108 + node_modules/architect/architect.js | 597 + node_modules/architect/component.json | 10 + node_modules/architect/package.json | 34 + .../plugins/architect.log/log-service.js | 36 + .../plugins/architect.log/package.json | 13 + node_modules/c9/assert.js | 44 + node_modules/c9/async_tools.js | 77 + node_modules/c9/async_tools_test.js | 152 + node_modules/c9/atomic.js | 27 + node_modules/c9/crypt.js | 28 + node_modules/c9/crypt_test.js | 25 + node_modules/c9/git.js | 96 + node_modules/c9/git_test.js | 75 + node_modules/c9/hashing.js | 14 + node_modules/c9/hostname.js | 23 + node_modules/c9/inline-mocha.js | 17 + node_modules/c9/instance_cache.js | 134 + node_modules/c9/instance_cache_test.js | 71 + node_modules/c9/manifest.js | 14 + node_modules/c9/package.json | 16 + node_modules/c9/passcrypt.js | 28 + node_modules/c9/passcrypt_test.js | 83 + node_modules/c9/proxies.js | 38 + node_modules/c9/ratelimit.js | 32 + node_modules/c9/request_timeout.js | 6 + node_modules/c9/rest_client.js | 137 + node_modules/c9/ssh.js | 148 + node_modules/c9/string.js | 47 + node_modules/c9/uid.js | 12 + node_modules/connect-architect/.gitignore | 1 + node_modules/connect-architect/.npmignore | 3 + node_modules/connect-architect/.travis.yml | 4 + node_modules/connect-architect/LICENSE | 21 + node_modules/connect-architect/README.md | 19 + .../connect.basicauth/basicauth-plugin.js | 14 + .../connect.basicauth/package.json | 14 + .../connect.bodyparser/bodyparser.js | 9 + .../connect.bodyparser/package.json | 16 + .../connect.cookieparser/cookieparser.js | 8 + .../connect.cookieparser/package.json | 16 + .../connect-architect/connect.cors/cors.js | 44 + .../connect.cors/package.json | 16 + .../connect-architect/connect.csp/csp.js | 150 + .../connect.csp/package.json | 17 + .../connect-architect/connect.csrf/csrf.js | 51 + .../connect.csrf/package.json | 17 + .../connect.ensure-login/ensure-login.js | 13 + .../connect.ensure-login/package.json | 16 + .../connect-architect/connect.flash/flash.js | 10 + .../connect.flash/package.json | 16 + .../connect.logger/logger.js | 8 + .../connect.logger/package.json | 16 + .../connect.query/package.json | 16 + .../connect-architect/connect.query/query.js | 8 + .../connect.redirect/package.json | 14 + .../connect.redirect/redirect.js | 28 + .../connect.remote-address/package.json | 16 + .../connect.remote-address/remote-address.js | 22 + .../connect.render.ejs/package.json | 16 + .../connect.render.ejs/render-ejs.js | 58 + .../connect.render/package.json | 16 + .../connect.render/render.js | 124 + .../connect.session.file/package.json | 11 + .../connect.session.file/session-ext.js | 169 + .../connect.session.memory/package.json | 10 + .../connect.session.memory/session-ext.js | 17 + .../connect.session.mongodb/package.json | 10 + .../connect.session.mongodb/session-ext.js | 21 + .../multi-region-store.js | 63 + .../connect.session.redis/package.json | 10 + .../connect.session.redis/session-ext.js | 53 + .../connect.session/package.json | 15 + .../connect.session/session-ext.js | 43 + .../connect.static/package.json | 15 + .../connect.static/static-plugin.js | 78 + .../connect/connect-plugin.js | 224 + .../connect/middleware/static.js | 235 + .../connect-architect/connect/package.json | 14 + .../connect-architect/demo/configs/default.js | 17 + .../demo/plugin/package.json | 13 + .../connect-architect/demo/plugin/plugin.js | 11 + .../demo/plugin/www/index.html | 1 + node_modules/connect-architect/demo/server.js | 31 + node_modules/connect-architect/package.json | 39 + node_modules/connect-architect/test/all.js | 39 + node_modules/frontdoor/.gitignore | 3 + node_modules/frontdoor/.travis.yml | 4 + node_modules/frontdoor/LICENSE | 21 + node_modules/frontdoor/README.md | 10 + node_modules/frontdoor/example/api.js | 84 + node_modules/frontdoor/example/express.js | 36 + .../example/public/javascripts/todo.js | 53 + .../example/public/stylesheets/style.css | 16 + .../frontdoor/example/views/index.ejs | 18 + node_modules/frontdoor/frontdoor.js | 20 + node_modules/frontdoor/lib/api-client.js | 128 + node_modules/frontdoor/lib/api-client_test.js | 92 + node_modules/frontdoor/lib/api.js | 11 + node_modules/frontdoor/lib/api_test.js | 464 + node_modules/frontdoor/lib/http_node.js | 169 + node_modules/frontdoor/lib/middleware.js | 35 + node_modules/frontdoor/lib/route.js | 280 + node_modules/frontdoor/lib/route_test.js | 137 + node_modules/frontdoor/lib/section.js | 209 + node_modules/frontdoor/lib/types.js | 132 + node_modules/frontdoor/lib/types_test.js | 28 + node_modules/frontdoor/lib/utils.js | 18 + node_modules/frontdoor/package.json | 37 + node_modules/kaefer/Makefile | 26 + node_modules/kaefer/index.js | 16 + node_modules/kaefer/lib/client.js | 122 + node_modules/kaefer/lib/reconnect_socket.js | 107 + node_modules/kaefer/lib/reliable_socket.js | 317 + node_modules/kaefer/lib/server.js | 95 + node_modules/kaefer/lib/util.js | 11 + node_modules/kaefer/lib/version.js | 7 + node_modules/kaefer/package.json | 26 + .../kaefer/test/integration/chaos_monkey.js | 94 + .../integration/congestion_control_test.js | 65 + .../kaefer/test/integration/smith_test.js | 51 + .../kaefer/test/reliable_socket_test.js | 106 + node_modules/smith/.gitignore | 3 + node_modules/smith/.npmignore | 3 + node_modules/smith/.travis.yml | 7 + node_modules/smith/LICENSE | 21 + node_modules/smith/README.markdown | 238 + node_modules/smith/component.json | 11 + node_modules/smith/package.json | 32 + node_modules/smith/protocol.markdown | 114 + node_modules/smith/samples/process-child.js | 23 + node_modules/smith/samples/process-parent.js | 25 + .../smith/samples/process-shared-api.js | 4 + .../smith/samples/tcp-client-autoreconnect.js | 56 + node_modules/smith/samples/tcp-client.js | 14 + node_modules/smith/samples/tcp-server.js | 27 + node_modules/smith/smith.js | 825 + node_modules/smith/test-all.sh | 14 + node_modules/smith/tests/README | 1 + node_modules/smith/tests/helpers.js | 45 + node_modules/smith/tests/package.json | 21 + node_modules/smith/tests/phantom.js | 28 + node_modules/smith/tests/public/.gitignore | 1 + node_modules/smith/tests/public/index.html | 34 + node_modules/smith/tests/public/smith.js | 1 + node_modules/smith/tests/public/test.js | 85 + node_modules/smith/tests/test-agent.js | 84 + node_modules/smith/tests/test-browser.js | 43 + node_modules/smith/tests/test-framer.js | 90 + node_modules/smith/tests/test-memory-leaks.js | 71 + node_modules/smith/tests/test-scrubber.js | 87 + node_modules/treehugger/README.md | 166 + node_modules/treehugger/lib/demo.js | 38 + node_modules/treehugger/lib/jquery.js | 9046 ++ node_modules/treehugger/lib/require.js | 33 + node_modules/treehugger/lib/setup_paths.js | 15 + .../treehugger/lib/treehugger/js/acorn.js | 2638 + .../lib/treehugger/js/acorn_loose.js | 1111 + .../treehugger/lib/treehugger/js/builtin.json | 161 + .../treehugger/lib/treehugger/js/infer.js | 405 + .../treehugger/lib/treehugger/js/inferUp.js | 87 + .../treehugger/lib/treehugger/js/parse.js | 284 + .../lib/treehugger/js/parse_test.js | 114 + .../treehugger/lib/treehugger/js/types.js | 152 + .../lib/treehugger/js/uglifyparser.js | 1507 + .../treehugger/lib/treehugger/js/util/walk.js | 366 + .../treehugger/lib/treehugger/js/values.js | 119 + .../lib/treehugger/rewrite.disabled.js | 250 + .../treehugger/lib/treehugger/traverse.js | 207 + .../treehugger/lib/treehugger/tree.js | 613 + node_modules/treehugger/package.json | 18 + node_modules/treehugger/test.html | 55 + node_modules/vfs-child/.gitignore | 1 + node_modules/vfs-child/LICENSE | 21 + node_modules/vfs-child/README.md | 4 + node_modules/vfs-child/child.js | 16 + .../vfs-child/example/node_modules/vfs-child | 1 + node_modules/vfs-child/example/npm-debug.log | 22 + .../vfs-child/example/test-child-extend.js | 40 + .../vfs-child/example/test-child-streams.js | 23 + .../vfs-child/example/vfs-child-example.js | 23 + node_modules/vfs-child/package.json | 34 + node_modules/vfs-child/parent.js | 51 + node_modules/vfs-http-adapter/.gitignore | 1 + node_modules/vfs-http-adapter/LICENSE | 21 + node_modules/vfs-http-adapter/README.md | 68 + node_modules/vfs-http-adapter/multipart.js | 317 + node_modules/vfs-http-adapter/package.json | 24 + node_modules/vfs-http-adapter/restful.js | 340 + .../vfs-http-adapter/test-multipart.js | 83 + node_modules/vfs-lint/README.md | 0 node_modules/vfs-lint/lint.js | 73 + node_modules/vfs-lint/package.json | 15 + node_modules/vfs-local/.gitignore | 1 + node_modules/vfs-local/.travis.yml | 6 + node_modules/vfs-local/LICENSE | 21 + node_modules/vfs-local/README.md | 196 + node_modules/vfs-local/localfs.js | 2438 + node_modules/vfs-local/package.json | 35 + node_modules/vfs-local/test/math.js | 10 + .../vfs-local/test/mock/dir/smile.png | 0 .../vfs-local/test/mock/dir/stuff.json | 0 node_modules/vfs-local/test/mock/dirLink | 1 + node_modules/vfs-local/test/mock/file.txt | 1 + node_modules/vfs-local/test/mock/fileLink.txt | 1 + node_modules/vfs-local/test/mock/listing.json | 7 + .../vfs-local/test/node_modules/vfs-local | 1 + node_modules/vfs-local/test/test-local.js | 1025 + node_modules/vfs-nodefs-adapter/LICENSE | 21 + node_modules/vfs-nodefs-adapter/nodefs.js | 233 + node_modules/vfs-nodefs-adapter/package.json | 21 + node_modules/vfs-socket/.gitignore | 2 + node_modules/vfs-socket/.travis.yml | 6 + node_modules/vfs-socket/LICENSE | 21 + node_modules/vfs-socket/README.md | 12 + node_modules/vfs-socket/component.json | 12 + node_modules/vfs-socket/consumer.js | 448 + node_modules/vfs-socket/package.json | 33 + node_modules/vfs-socket/test/math.js | 10 + .../vfs-socket/test/mock/dir/smile.png | 0 .../vfs-socket/test/mock/dir/stuff.json | 0 node_modules/vfs-socket/test/mock/dirLink | 1 + node_modules/vfs-socket/test/mock/file.txt | 1 + .../vfs-socket/test/mock/fileLink.txt | 1 + .../vfs-socket/test/mock/listing.json | 7 + node_modules/vfs-socket/test/test-socket.js | 883 + node_modules/vfs-socket/worker.js | 422 + package.json | 105 + plugins/c9.cli.bridge/bridge-client.js | 62 + plugins/c9.cli.bridge/bridge-service.js | 37 + plugins/c9.cli.bridge/bridge.js | 108 + plugins/c9.cli.bridge/bridge_commands.js | 113 + plugins/c9.cli.bridge/bridge_test.js | 64 + plugins/c9.cli.mount/mount.js | 159 + plugins/c9.cli.open/open.js | 186 + plugins/c9.cli.open/restart.js | 114 + plugins/c9.cli.publish/README.md | 24 + plugins/c9.cli.publish/publish.git.sh | 23 + plugins/c9.cli.publish/publish.js | 888 + plugins/c9.cli.publish/publish_test.git.sh | 15 + plugins/c9.cli.publish/publish_test.js | 345 + plugins/c9.cli.sync/sync-server.js | 13 + plugins/c9.cli.sync/sync.js | 269 + plugins/c9.cli/auth.bootstrap.js | 97 + plugins/c9.cli/cli.js | 103 + plugins/c9.connect.favicon/favicon.ico | Bin 0 -> 1150 bytes plugins/c9.connect.favicon/favicon.js | 21 + plugins/c9.core/api.js | 101 + plugins/c9.core/assert_root.js | 15 + plugins/c9.core/c9.js | 410 + plugins/c9.core/c9_test.js | 92 + plugins/c9.core/client.js | 30 + plugins/c9.core/ext.js | 930 + plugins/c9.core/ext_test.js | 218 + plugins/c9.core/http-node.js | 55 + plugins/c9.core/http-xhr.js | 270 + plugins/c9.core/http-xhr_test.js | 36 + plugins/c9.core/node_defaults.js | 31 + plugins/c9.core/settings.js | 693 + plugins/c9.core/settings_test.js | 119 + plugins/c9.core/util.js | 377 + plugins/c9.core/util_test.js | 40 + plugins/c9.error/error_handler.js | 129 + plugins/c9.error/logger.raygun.js | 28 + plugins/c9.error/logger.raygun_mock.js | 18 + plugins/c9.error/raygun.connect.js | 95 + plugins/c9.error/raygun.js | 52 + plugins/c9.error/views/error-401.html.ejs | 21 + plugins/c9.error/views/error-404.html.ejs | 21 + plugins/c9.error/views/error-500.html.ejs | 38 + plugins/c9.error/views/error-503.html.ejs | 35 + plugins/c9.error/views/error.html.ejs | 35 + plugins/c9.error/www/images/apple.jpg | Bin 0 -> 192911 bytes plugins/c9.error/www/images/bench.jpg | Bin 0 -> 677828 bytes plugins/c9.error/www/images/bookmark.jpg | Bin 0 -> 846705 bytes plugins/c9.error/www/images/bulb.jpg | Bin 0 -> 568885 bytes plugins/c9.error/www/images/c9logo.png | Bin 0 -> 9801 bytes plugins/c9.error/www/images/chamomile.jpg | Bin 0 -> 142904 bytes plugins/c9.error/www/images/dandelions.jpg | Bin 0 -> 431063 bytes plugins/c9.error/www/images/flowersfence.jpg | Bin 0 -> 355871 bytes plugins/c9.error/www/style.css | 219 + plugins/c9.example.formatjson/formatjson.js | 115 + plugins/c9.fs/fs.cache.xml.js | 866 + plugins/c9.fs/fs.cache.xml_test.js | 865 + plugins/c9.fs/fs.errors.js | 145 + plugins/c9.fs/fs.js | 745 + plugins/c9.fs/fs.streams.js | 257 + plugins/c9.fs/fs.xhr.js | 206 + plugins/c9.fs/fs_test.js | 554 + plugins/c9.fs/mock/README.md | 123 + plugins/c9.fs/mock/dir/smile.png | 0 plugins/c9.fs/mock/dir/stuff.json | 1 + plugins/c9.fs/mock/dir/subfolder/bright.txt | 1 + plugins/c9.fs/mock/dir/subfolder/exciting.js | 1 + plugins/c9.fs/mock/dirLink | 1 + plugins/c9.fs/mock/example.png | Bin 0 -> 5080 bytes plugins/c9.fs/mock/file.js | 489 + plugins/c9.fs/mock/file.txt | 1 + plugins/c9.fs/mock/fileLink.txt | 1 + plugins/c9.fs/mock/language.js | 7 + plugins/c9.fs/mock/less.less | 6 + plugins/c9.fs/mock/listing.json | 7 + plugins/c9.fs/mock/live.js | 5 + plugins/c9.fs/mock/plugins/c9.core/ext.js | 65 + .../mock/plugins/c9.dummy/architect_test.js | 64 + .../c9.fs/mock/plugins/c9.dummy/dep-define.js | 7 + plugins/c9.fs/mock/plugins/c9.dummy/dep.js | 3 + plugins/c9.fs/mock/test blah$.js | 1 + plugins/c9.fs/mock/test.css | 18 + plugins/c9.fs/mock/test.js | 31 + plugins/c9.fs/mock/test.js.map | 1 + plugins/c9.fs/mock/test.sh | 9 + plugins/c9.fs/mock/test.ts | 20 + plugins/c9.fs/mock/test.unicode.txt | 22 + plugins/c9.fs/mock/test2.js | 12 + plugins/c9.fs/mock/test_broken.go | 1 + plugins/c9.fs/mock/test_broken.php | 5 + plugins/c9.fs/mock/test_broken.rb | 3 + plugins/c9.fs/mock/test_broken.sh | 12 + plugins/c9.fs/mock/test_es6.js | 59 + plugins/c9.fs/mock/very_large_file.js | 72166 ++++++++++++++ plugins/c9.fs/net.js | 103 + plugins/c9.fs/net_test.js | 82 + plugins/c9.fs/proc.apigen.js | 218 + plugins/c9.fs/proc.js | 499 + plugins/c9.fs/proc_test.js | 152 + plugins/c9.ide.ace/ace.js | 2629 + plugins/c9.ide.ace/ace_test.js | 545 + plugins/c9.ide.ace/modes.js | 47 + plugins/c9.ide.ace/scrollbar.js | 39 + plugins/c9.ide.ace/style.less | 249 + plugins/c9.ide.ace/themes.js | 211 + plugins/c9.ide.ace/themes.json | 43 + plugins/c9.ide.auth/auth.js | 203 + .../c9.ide.browsersupport/browsersupport.js | 117 + plugins/c9.ide.clipboard/clipboard.js | 491 + plugins/c9.ide.clipboard/clipboard_test.js | 84 + plugins/c9.ide.clipboard/html5.js | 226 + plugins/c9.ide.console/console.js | 599 + plugins/c9.ide.console/console.xml | 11 + plugins/c9.ide.console/console_test.js | 395 + plugins/c9.ide.console/style.css | 19 + plugins/c9.ide.dialog.common/alert.js | 109 + .../c9.ide.dialog.common/alert_internal.js | 81 + plugins/c9.ide.dialog.common/confirm.js | 47 + plugins/c9.ide.dialog.common/error.css | 77 + plugins/c9.ide.dialog.common/error.js | 276 + plugins/c9.ide.dialog.common/error_test.js | 74 + plugins/c9.ide.dialog.common/filechange.js | 66 + plugins/c9.ide.dialog.common/fileoverwrite.js | 81 + plugins/c9.ide.dialog.common/fileremove.js | 58 + plugins/c9.ide.dialog.common/notification.css | 21 + plugins/c9.ide.dialog.common/notification.js | 158 + plugins/c9.ide.dialog.common/question.js | 132 + plugins/c9.ide.dialog.file/filesave.css | 43 + plugins/c9.ide.dialog.file/filesave.js | 374 + plugins/c9.ide.dialog.file/filesave.xml | 87 + plugins/c9.ide.dialog.login/login.css | 10 + plugins/c9.ide.dialog.login/login.js | 143 + plugins/c9.ide.dialog.login/login.xml | 64 + plugins/c9.ide.dialog/dialog.js | 528 + plugins/c9.ide.editors/document.js | 590 + plugins/c9.ide.editors/document_test.js | 100 + plugins/c9.ide.editors/editor.js | 582 + plugins/c9.ide.editors/editor_test.js | 153 + plugins/c9.ide.editors/editors.js | 260 + plugins/c9.ide.editors/editors_test.js | 82 + plugins/c9.ide.editors/htmlview.js | 61 + plugins/c9.ide.editors/imgview.js | 138 + plugins/c9.ide.editors/metadata.js | 593 + plugins/c9.ide.editors/metadata_test.js | 463 + plugins/c9.ide.editors/pane.js | 869 + plugins/c9.ide.editors/tab.js | 607 + plugins/c9.ide.editors/tab_test.js | 136 + plugins/c9.ide.editors/tabmanager.js | 1947 + plugins/c9.ide.editors/tabmanager_test.js | 592 + plugins/c9.ide.editors/texteditor.js | 206 + plugins/c9.ide.editors/timeview.js | 104 + plugins/c9.ide.editors/undomanager.js | 400 + plugins/c9.ide.editors/undomanager_test.js | 146 + plugins/c9.ide.editors/urlview.js | 196 + plugins/c9.ide.errorhandler/raygun.js | 1611 + .../raygun_error_handler.js | 83 + .../simple_error_handler.js | 109 + plugins/c9.ide.help/help.js | 183 + plugins/c9.ide.help/help.xml | 34 + plugins/c9.ide.help/images/about_cloud.png | Bin 0 -> 67893 bytes plugins/c9.ide.help/images/close.png | Bin 0 -> 1701 bytes plugins/c9.ide.help/skin.xml | 66 + plugins/c9.ide.help/style.css | 45 + plugins/c9.ide.info/info.js | 102 + plugins/c9.ide.keys/commands.js | 669 + plugins/c9.ide.keys/commands_test.js | 107 + plugins/c9.ide.keys/dataprovider.js | 142 + plugins/c9.ide.keys/editor.js | 537 + plugins/c9.ide.keys/editordp.js | 75 + plugins/c9.ide.keys/panel.js | 270 + plugins/c9.ide.keys/panel.xml | 7 + plugins/c9.ide.keys/style.css | 84 + plugins/c9.ide.layout.classic/icons/bug.png | Bin 0 -> 4730 bytes .../c9.ide.layout.classic/icons/bug@2x.png | Bin 0 -> 4730 bytes .../icons/bug_flat_light.png | Bin 0 -> 1496 bytes .../icons/bug_flat_light@2x.png | Bin 0 -> 3312 bytes plugins/c9.ide.layout.classic/icons/cog.png | Bin 0 -> 512 bytes .../icons/conflict_sel.png | Bin 0 -> 322 bytes .../icons/conflict_unsel.png | Bin 0 -> 261 bytes .../icons/console_clear.png | Bin 0 -> 1344 bytes .../icons/console_close_btn.png | Bin 0 -> 1318 bytes .../icons/console_close_btn@2x.png | Bin 0 -> 1520 bytes .../icons/console_close_btn_dark.png | Bin 0 -> 1572 bytes .../icons/console_close_btn_dark@2x.png | Bin 0 -> 2012 bytes .../icons/console_max.png | Bin 0 -> 1671 bytes .../icons/console_settings.png | Bin 0 -> 1334 bytes plugins/c9.ide.layout.classic/icons/css.png | Bin 0 -> 524 bytes .../icons/debugger/brkp_obj.gif | Bin 0 -> 197 bytes .../icons/debugger/brkp_obj.png | Bin 0 -> 1551 bytes .../icons/debugger/brkp_obj@2x.gif | Bin 0 -> 197 bytes .../icons/debugger/brkp_obj@2x.png | Bin 0 -> 1551 bytes .../icons/debugger/brkp_obj_condition.png | Bin 0 -> 1514 bytes .../icons/debugger/brkp_obj_condition@2x.png | Bin 0 -> 1514 bytes .../debugger/brkp_obj_condition_disabled.png | Bin 0 -> 1443 bytes .../brkp_obj_condition_disabled@2x.png | Bin 0 -> 1443 bytes .../icons/debugger/brkp_obj_current_line.png | Bin 0 -> 1633 bytes .../debugger/brkp_obj_current_line@2x.png | Bin 0 -> 1633 bytes .../brkp_obj_current_line_condition.png | Bin 0 -> 1560 bytes .../brkp_obj_current_line_condition@2x.png | Bin 0 -> 1560 bytes .../debugger/brkp_obj_current_line_dark.png | Bin 0 -> 1625 bytes .../brkp_obj_current_line_dark@2x.png | Bin 0 -> 1948 bytes .../icons/debugger/brkp_obj_dark.png | Bin 0 -> 1571 bytes .../icons/debugger/brkp_obj_dark@2x.png | Bin 0 -> 1582 bytes .../icons/debugger/brkp_obj_disabled.png | Bin 0 -> 1465 bytes .../icons/debugger/brkp_obj_disabled@2x.png | Bin 0 -> 1465 bytes .../brkp_obj_disabled_current_line_dark.png | Bin 0 -> 1603 bytes ...brkp_obj_disabled_current_line_dark@2x.png | Bin 0 -> 1603 bytes .../icons/debugger/brkp_obj_disabled_dark.png | Bin 0 -> 3333 bytes .../debugger/brkp_obj_disabled_dark@2x.png | Bin 0 -> 3333 bytes .../icons/debugger/brkp_obj_warn.png | Bin 0 -> 1562 bytes .../icons/debugger/brkp_obj_warn@2x.png | Bin 0 -> 1562 bytes .../icons/debugger/brkp_obj_warn_dark.png | Bin 0 -> 1577 bytes .../icons/debugger/brkp_obj_warn_dark@2x.png | Bin 0 -> 1577 bytes .../icons/debugger/brkpd_obj_disabled.gif | Bin 0 -> 139 bytes .../icons/debugger/brkpd_obj_disabled@2x.gif | Bin 0 -> 139 bytes .../icons/debugger/copy_edit_co.gif | Bin 0 -> 381 bytes .../icons/debugger/copy_edit_co.png | Bin 0 -> 1387 bytes .../icons/debugger/copy_edit_co_disabled.gif | Bin 0 -> 366 bytes .../icons/debugger/copy_edit_co_disabled.png | Bin 0 -> 1295 bytes .../icons/debugger/current_line copy.png | Bin 0 -> 1205 bytes .../icons/debugger/current_line.png | Bin 0 -> 1205 bytes .../icons/debugger/current_line_dark.png | Bin 0 -> 1197 bytes .../icons/debugger/current_line_dark@2x.png | Bin 0 -> 1499 bytes .../icons/debugger/delete_config.gif | Bin 0 -> 351 bytes .../icons/debugger/delete_config.png | Bin 0 -> 1218 bytes .../icons/debugger/delete_config_disabled.gif | Bin 0 -> 159 bytes .../icons/debugger/delete_config_disabled.png | Bin 0 -> 1219 bytes .../icons/debugger/disconnect_co.png | Bin 0 -> 1507 bytes .../icons/debugger/disconnect_co_disabled.png | Bin 0 -> 1381 bytes .../icons/debugger/error_obj.gif | Bin 0 -> 339 bytes .../icons/debugger/file_obj.gif | Bin 0 -> 561 bytes .../icons/debugger/genericvariable_obj.gif | Bin 0 -> 191 bytes .../icons/debugger/genericvariable_obj@2x.gif | Bin 0 -> 191 bytes .../genericvariable_obj_flat_light.png | Bin 0 -> 377 bytes .../genericvariable_obj_flat_light@2x.png | Bin 0 -> 772 bytes .../icons/debugger/ldebug_obj.png | Bin 0 -> 1672 bytes .../icons/debugger/ldebug_obj_disabled.png | Bin 0 -> 1447 bytes .../icons/debugger/monitorexpression_tsk.gif | Bin 0 -> 318 bytes .../icons/debugger/monitorexpression_tsk.png | Bin 0 -> 1139 bytes .../monitorexpression_tsk_disabled.gif | Bin 0 -> 138 bytes .../monitorexpression_tsk_disabled.png | Bin 0 -> 1143 bytes .../icons/debugger/resume_co.gif | Bin 0 -> 337 bytes .../icons/debugger/resume_co.png | Bin 0 -> 1215 bytes .../icons/debugger/resume_co_disabled.gif | Bin 0 -> 207 bytes .../icons/debugger/resume_co_disabled.png | Bin 0 -> 1180 bytes .../icons/debugger/run_tool.png | Bin 0 -> 1488 bytes .../icons/debugger/run_tool_disabled.png | Bin 0 -> 1418 bytes .../icons/debugger/save_edit.gif | Bin 0 -> 639 bytes .../icons/debugger/save_edit_disabled.gif | Bin 0 -> 378 bytes .../icons/debugger/stack_co.png | Bin 0 -> 1358 bytes .../icons/debugger/stack_co@2x.png | Bin 0 -> 1358 bytes .../icons/debugger/stckframe_obj.gif | Bin 0 -> 104 bytes .../icons/debugger/stckframe_running_obj.gif | Bin 0 -> 213 bytes .../icons/debugger/stepbystep_co.gif | Bin 0 -> 221 bytes .../icons/debugger/stepbystep_co_disabled.gif | Bin 0 -> 201 bytes .../icons/debugger/stepinto_co.png | Bin 0 -> 1295 bytes .../icons/debugger/stepinto_co_disabled.png | Bin 0 -> 1286 bytes .../icons/debugger/stepover_co.png | Bin 0 -> 1438 bytes .../icons/debugger/stepover_co_disabled.png | Bin 0 -> 1397 bytes .../icons/debugger/stepreturn_co.png | Bin 0 -> 1296 bytes .../icons/debugger/stepreturn_co_disabled.png | Bin 0 -> 1240 bytes .../icons/debugger/suspend_co.png | Bin 0 -> 1039 bytes .../icons/debugger/suspend_co_disabled.png | Bin 0 -> 1019 bytes .../icons/debugger/terminate_co.png | Bin 0 -> 1064 bytes .../icons/debugger/terminate_co_disabled.png | Bin 0 -> 1023 bytes .../icons/debugger/warning_obj.gif | Bin 0 -> 324 bytes .../icons/delete_icon.png | Bin 0 -> 2176 bytes .../icons/exception_break.png | Bin 0 -> 4443 bytes .../icons/exception_break@2x.png | Bin 0 -> 5065 bytes .../icons/exception_break_flat_light.png | Bin 0 -> 843 bytes .../icons/exception_break_flat_light@2x.png | Bin 0 -> 1736 bytes ...e-load-spinner-dark-unfocus_flat_light.gif | Bin 0 -> 3069 bytes ...oad-spinner-dark-unfocus_flat_light@2x.gif | Bin 0 -> 606 bytes ...-tree-load-spinner-selected_flat_light.gif | Bin 0 -> 3069 bytes ...ee-load-spinner-selected_flat_light@2x.gif | Bin 0 -> 582 bytes .../file-tree-load-spinner_flat_light.gif | Bin 0 -> 3069 bytes .../file-tree-load-spinner_flat_light@2x.gif | Bin 0 -> 617 bytes .../c9.ide.layout.classic/icons/folder.png | Bin 0 -> 1291 bytes .../c9.ide.layout.classic/icons/folder@2x.png | Bin 0 -> 1291 bytes .../icons/folder_alternative.png | Bin 0 -> 1424 bytes .../icons/folder_alternative@2x.png | Bin 0 -> 1424 bytes .../icons/folder_flat_light.png | Bin 0 -> 243 bytes .../icons/folder_flat_light@2x.png | Bin 0 -> 428 bytes .../icons/folder_light.png | Bin 0 -> 1363 bytes .../icons/folder_light@2x.png | Bin 0 -> 1363 bytes .../icons/folder_new.png | Bin 0 -> 1660 bytes plugins/c9.ide.layout.classic/icons/html.png | Bin 0 -> 1389 bytes plugins/c9.ide.layout.classic/icons/image.png | Bin 0 -> 516 bytes plugins/c9.ide.layout.classic/icons/info.png | Bin 0 -> 3700 bytes .../c9.ide.layout.classic/icons/logiql.png | Bin 0 -> 3361 bytes plugins/c9.ide.layout.classic/icons/min.png | Bin 0 -> 2983 bytes plugins/c9.ide.layout.classic/icons/minus.png | Bin 0 -> 1017 bytes .../icons/page_white.png | Bin 0 -> 294 bytes .../icons/page_white_acrobat.png | Bin 0 -> 591 bytes .../icons/page_white_actionscript.png | Bin 0 -> 664 bytes .../icons/page_white_add.png | Bin 0 -> 512 bytes .../icons/page_white_c.png | Bin 0 -> 587 bytes .../icons/page_white_camera.png | Bin 0 -> 656 bytes .../icons/page_white_cd.png | Bin 0 -> 666 bytes .../icons/page_white_code.png | Bin 0 -> 603 bytes .../icons/page_white_code_red.png | Bin 0 -> 587 bytes .../icons/page_white_coldfusion.png | Bin 0 -> 592 bytes .../icons/page_white_compressed.png | Bin 0 -> 724 bytes .../icons/page_white_copy.png | Bin 0 -> 309 bytes .../icons/page_white_cplusplus.png | Bin 0 -> 621 bytes .../icons/page_white_csharp.png | Bin 0 -> 700 bytes .../icons/page_white_cup.png | Bin 0 -> 639 bytes .../icons/page_white_database.png | Bin 0 -> 579 bytes .../icons/page_white_delete.png | Bin 0 -> 536 bytes .../icons/page_white_dvd.png | Bin 0 -> 638 bytes .../icons/page_white_edit.png | Bin 0 -> 618 bytes .../icons/page_white_error.png | Bin 0 -> 623 bytes .../icons/page_white_excel.png | Bin 0 -> 663 bytes .../icons/page_white_find.png | Bin 0 -> 676 bytes .../icons/page_white_flash.png | Bin 0 -> 582 bytes .../icons/page_white_freehand.png | Bin 0 -> 639 bytes .../icons/page_white_gear.png | Bin 0 -> 402 bytes .../icons/page_white_get.png | Bin 0 -> 516 bytes .../icons/page_white_go.png | Bin 0 -> 612 bytes .../icons/page_white_h.png | Bin 0 -> 603 bytes .../icons/page_white_horizontal.png | Bin 0 -> 296 bytes .../icons/page_white_key.png | Bin 0 -> 616 bytes .../icons/page_white_lightning.png | Bin 0 -> 669 bytes .../icons/page_white_link.png | Bin 0 -> 614 bytes .../icons/page_white_magnify.png | Bin 0 -> 554 bytes .../icons/page_white_medal.png | Bin 0 -> 706 bytes .../icons/page_white_office.png | Bin 0 -> 779 bytes .../icons/page_white_paint.png | Bin 0 -> 688 bytes .../icons/page_white_paintbrush.png | Bin 0 -> 618 bytes .../icons/page_white_paste.png | Bin 0 -> 620 bytes .../icons/page_white_php.png | Bin 0 -> 538 bytes .../icons/page_white_picture.png | Bin 0 -> 650 bytes .../icons/page_white_powerpoint.png | Bin 0 -> 588 bytes .../icons/page_white_put.png | Bin 0 -> 523 bytes .../icons/page_white_ruby.png | Bin 0 -> 626 bytes .../icons/page_white_stack.png | Bin 0 -> 317 bytes .../icons/page_white_star.png | Bin 0 -> 565 bytes .../icons/page_white_swoosh.png | Bin 0 -> 634 bytes .../icons/page_white_text.png | Bin 0 -> 342 bytes .../icons/page_white_text_width.png | Bin 0 -> 315 bytes .../icons/page_white_tux.png | Bin 0 -> 668 bytes .../icons/page_white_vector.png | Bin 0 -> 644 bytes .../icons/page_white_visualstudio.png | Bin 0 -> 702 bytes .../icons/page_white_width.png | Bin 0 -> 309 bytes .../icons/page_white_word.png | Bin 0 -> 651 bytes .../icons/page_white_world.png | Bin 0 -> 734 bytes .../icons/page_white_wrench.png | Bin 0 -> 613 bytes .../icons/page_white_zip.png | Bin 0 -> 386 bytes plugins/c9.ide.layout.classic/icons/pause.png | Bin 0 -> 3154 bytes .../c9.ide.layout.classic/icons/pause@2x.png | Bin 0 -> 1900 bytes .../icons/pause_flat_light.png | Bin 0 -> 389 bytes .../icons/pause_flat_light@2x.png | Bin 0 -> 723 bytes plugins/c9.ide.layout.classic/icons/play.png | Bin 0 -> 3707 bytes .../c9.ide.layout.classic/icons/play@2x.png | Bin 0 -> 3227 bytes .../icons/play_flat_light.png | Bin 0 -> 706 bytes .../icons/play_flat_light@2x.png | Bin 0 -> 1416 bytes plugins/c9.ide.layout.classic/icons/plus.png | Bin 0 -> 3107 bytes plugins/c9.ide.layout.classic/icons/plus2.png | Bin 0 -> 1277 bytes .../c9.ide.layout.classic/icons/pref-ico.png | Bin 0 -> 6324 bytes .../icons/pref-ico@2x.png | Bin 0 -> 6324 bytes .../icons/pref-ico_flat_light.png | Bin 0 -> 1703 bytes .../icons/pref-ico_flat_light@2x.png | Bin 0 -> 3562 bytes .../icons/remove_breakpoints.png | Bin 0 -> 3272 bytes .../icons/remove_breakpoints@2x.png | Bin 0 -> 6647 bytes .../icons/remove_breakpoints_flat_light.png | Bin 0 -> 1215 bytes .../remove_breakpoints_flat_light@2x.png | Bin 0 -> 2389 bytes .../icons/restart-icon.png | Bin 0 -> 1719 bytes .../icons/restart-icon@2x.png | Bin 0 -> 2564 bytes .../icons/restart-icon_flat_light.png | Bin 0 -> 3136 bytes .../icons/restart-icon_flat_light@2x.png | Bin 0 -> 3580 bytes plugins/c9.ide.layout.classic/icons/run.png | Bin 0 -> 2254 bytes .../c9.ide.layout.classic/icons/run@2x.png | Bin 0 -> 3772 bytes .../icons/run_flat_light.png | Bin 0 -> 887 bytes .../icons/run_flat_light@2x.png | Bin 0 -> 2120 bytes plugins/c9.ide.layout.classic/icons/save.png | Bin 0 -> 1658 bytes .../icons/script_code.png | Bin 0 -> 859 bytes .../c9.ide.layout.classic/icons/scripts.png | Bin 0 -> 1477 bytes .../icons/scripts@2x.png | Bin 0 -> 1477 bytes .../icons/scripts_flat_light.png | Bin 0 -> 654 bytes .../icons/scripts_flat_light@2x.png | Bin 0 -> 1254 bytes .../icons/search-ico_flat_light.png | Bin 0 -> 325 bytes .../icons/search-ico_flat_light@2x.png | Bin 0 -> 624 bytes plugins/c9.ide.layout.classic/icons/step.png | Bin 0 -> 4332 bytes .../c9.ide.layout.classic/icons/step@2x.png | Bin 0 -> 4918 bytes .../icons/step_flat_light.png | Bin 0 -> 1111 bytes .../icons/step_flat_light@2x.png | Bin 0 -> 2293 bytes .../c9.ide.layout.classic/icons/stepback.png | Bin 0 -> 3804 bytes .../icons/stepback@2x.png | Bin 0 -> 3606 bytes .../icons/stepback_flat_light.png | Bin 0 -> 629 bytes .../icons/stepback_flat_light@2x.png | Bin 0 -> 1195 bytes .../c9.ide.layout.classic/icons/stepinto.png | Bin 0 -> 1829 bytes .../icons/stepinto@2x.png | Bin 0 -> 3184 bytes .../icons/stepinto_co.gif | Bin 0 -> 197 bytes .../icons/stepinto_flat_light.png | Bin 0 -> 550 bytes .../icons/stepinto_flat_light@2x.png | Bin 0 -> 1033 bytes plugins/c9.ide.layout.classic/icons/stop.png | Bin 0 -> 1253 bytes .../c9.ide.layout.classic/icons/stop@2x.png | Bin 0 -> 2792 bytes .../icons/stop_flat_light.png | Bin 0 -> 321 bytes .../icons/stop_flat_light@2x.png | Bin 0 -> 631 bytes .../c9.ide.layout.classic/icons/switch.png | Bin 0 -> 306 bytes .../c9.ide.layout.classic/icons/symlink.png | Bin 0 -> 1176 bytes .../icons/symlink_dark.png | Bin 0 -> 1107 bytes .../icons/synced_sel.png | Bin 0 -> 337 bytes .../icons/synced_unsel.png | Bin 0 -> 340 bytes .../icons/syncing_sel.gif | Bin 0 -> 1621 bytes .../icons/syncing_unsel.gif | Bin 0 -> 1616 bytes .../icons/terminal_tab_icon.png | Bin 0 -> 489 bytes .../icons/toggle_breakpoints1.png | Bin 0 -> 4009 bytes .../icons/toggle_breakpoints1_flat_light.png | Bin 0 -> 669 bytes .../toggle_breakpoints1_flat_light@2x.png | Bin 0 -> 1364 bytes .../icons/toggle_breakpoints2.png | Bin 0 -> 4507 bytes .../icons/toggle_breakpoints2@2x.png | Bin 0 -> 5552 bytes .../icons/toggle_breakpoints2_flat_light.png | Bin 0 -> 802 bytes .../toggle_breakpoints2_flat_light@2x.png | Bin 0 -> 1901 bytes .../icons/unsynced_added_sel.png | Bin 0 -> 319 bytes .../icons/unsynced_added_unsel.png | Bin 0 -> 321 bytes .../images/accordion_apf_icon.png | Bin 0 -> 2900 bytes .../images/accordion_apf_icon_hor.png | Bin 0 -> 2856 bytes .../images/accordion_apf_title.png | Bin 0 -> 2904 bytes .../images/accordion_apf_title_hor.png | Bin 0 -> 2885 bytes .../images/accordion_header.png | Bin 0 -> 2846 bytes .../images/accordion_icon.png | Bin 0 -> 2831 bytes .../images/accordion_menu_bg.png | Bin 0 -> 2972 bytes .../images/accordion_menu_rounded.png | Bin 0 -> 3220 bytes .../images/accordion_menu_rrounded.png | Bin 0 -> 3195 bytes .../images/accordion_menu_title.png | Bin 0 -> 3437 bytes .../images/accordion_title.png | Bin 0 -> 2985 bytes .../images/accordion_title_h.png | Bin 0 -> 2994 bytes .../images/ace_error_dark.png | Bin 0 -> 3444 bytes .../images/ace_error_dark@2x.png | Bin 0 -> 3444 bytes .../images/ace_error_flat_light.png | Bin 0 -> 385 bytes .../images/ace_error_flat_light@2x.png | Bin 0 -> 820 bytes .../images/ace_error_light.png | Bin 0 -> 385 bytes .../images/ace_error_light@2x.png | Bin 0 -> 385 bytes .../images/ace_warning_dark.png | Bin 0 -> 3184 bytes .../images/ace_warning_dark@2x.png | Bin 0 -> 3184 bytes .../images/ace_warning_flat_light.png | Bin 0 -> 3082 bytes .../images/ace_warning_flat_light@2x.png | Bin 0 -> 3382 bytes .../images/ace_warning_light.png | Bin 0 -> 368 bytes .../images/ace_warning_light@x.png | Bin 0 -> 368 bytes .../images/ace_warning_light_flat_light.png | Bin 0 -> 348 bytes .../ace_warning_light_flat_light@2x.png | Bin 0 -> 679 bytes .../c9.ide.layout.classic/images/ad_next.png | Bin 0 -> 355 bytes .../c9.ide.layout.classic/images/ad_prev.png | Bin 0 -> 364 bytes .../c9.ide.layout.classic/images/alert.png | Bin 0 -> 1304 bytes .../c9.ide.layout.classic/images/arrow-sb.png | Bin 0 -> 1527 bytes .../images/arrow_down_black.png | Bin 0 -> 126 bytes .../images/arrow_down_grey.png | Bin 0 -> 987 bytes .../images/arrow_down_grey@2x.png | Bin 0 -> 1056 bytes .../images/arrow_down_white.png | Bin 0 -> 149 bytes .../images/arrow_right.gif | Bin 0 -> 49 bytes .../images/arrow_right.png | Bin 0 -> 165 bytes .../images/ballon_left.gif | Bin 0 -> 74 bytes .../images/ballon_left.png | Bin 0 -> 179 bytes .../images/ballon_middle.gif | Bin 0 -> 153 bytes .../images/ballon_middle.png | Bin 0 -> 362 bytes .../images/bar11x_left.png | Bin 0 -> 710 bytes .../images/bar11x_right.png | Bin 0 -> 369 bytes .../images/bar16x_left.png | Bin 0 -> 944 bytes .../images/bar16x_right.png | Bin 0 -> 466 bytes .../c9.ide.layout.classic/images/bar_left.png | Bin 0 -> 519 bytes .../images/bar_right.png | Bin 0 -> 281 bytes .../images/bg-overlay.png | Bin 0 -> 1024 bytes .../images/bg_counter.png | Bin 0 -> 117 bytes .../images/big_close.png | Bin 0 -> 1852 bytes .../images/bk-close-btn.png | Bin 0 -> 2215 bytes .../images/bk-close-btn@2x.png | Bin 0 -> 2215 bytes .../images/bk-win-footer.png | Bin 0 -> 2083 bytes .../images/bk-win-header.png | Bin 0 -> 1542 bytes .../images/black-panel_arrow.png | Bin 0 -> 2866 bytes .../images/black-tab_btn_bg.png | Bin 0 -> 940 bytes plugins/c9.ide.layout.classic/images/bold.png | Bin 0 -> 332 bytes .../images/browser_button.png | Bin 0 -> 1715 bytes .../images/browsers/chrome_32x32.png | Bin 0 -> 2966 bytes .../images/browsers/ff_32x32.png | Bin 0 -> 2927 bytes .../images/browsers/ie_32x32.png | Bin 0 -> 3101 bytes .../images/browsers/safari_32x32.png | Bin 0 -> 3385 bytes .../images/btn-arrow.png | Bin 0 -> 959 bytes .../images/btn-arrow2.png | Bin 0 -> 2828 bytes .../images/btn_remove.png | Bin 0 -> 3245 bytes .../c9.ide.layout.classic/images/btnclose.gif | Bin 0 -> 416 bytes .../images/btnclose@2x.gif | Bin 0 -> 416 bytes .../images/btnclose_flat_light.png | Bin 0 -> 666 bytes .../images/btnclose_flat_light@2x.png | Bin 0 -> 1455 bytes .../images/button_left.png | Bin 0 -> 3737 bytes .../images/button_middle.png | Bin 0 -> 2893 bytes .../images/button_right.png | Bin 0 -> 3740 bytes .../images/c9-find-and-replace.png | Bin 0 -> 8726 bytes .../images/c9-menu-backg.png | Bin 0 -> 1004 bytes .../images/c9-menu-backg2.png | Bin 0 -> 1867 bytes .../images/c9-menu-round.png | Bin 0 -> 2733 bytes .../images/c9-no-repeat.png | Bin 0 -> 42320 bytes .../images/c9-no-repeat@2x.png | Bin 0 -> 256443 bytes .../images/c9-no-repeat_flat_light.png | Bin 0 -> 15017 bytes .../images/c9-no-repeat_flat_light@2x.png | Bin 0 -> 33315 bytes .../images/c9-noise-light-10.png | Bin 0 -> 16419 bytes .../images/c9-noise-with-background.png | Bin 0 -> 5690 bytes .../c9.ide.layout.classic/images/c9-noise.png | Bin 0 -> 4538 bytes .../images/c9-repeat-x.png | Bin 0 -> 17277 bytes .../images/c9-repeat-x@2x.png | Bin 0 -> 90935 bytes .../images/c9-repeat-x_flat_light.png | Bin 0 -> 17029 bytes .../images/c9-repeat-x_flat_light@2x.png | Bin 0 -> 45774 bytes .../images/c9-topbar-btns.png | Bin 0 -> 6880 bytes .../images/c9menulogo.png | Bin 0 -> 3950 bytes .../images/c9readonly.png | Bin 0 -> 1199 bytes .../images/calendar_bg.png | Bin 0 -> 2826 bytes .../images/calendar_body.png | Bin 0 -> 2865 bytes .../images/calendar_button.png | Bin 0 -> 3228 bytes .../images/calendar_left.png | Bin 0 -> 2852 bytes .../images/calendar_m_minus.png | Bin 0 -> 2895 bytes .../images/calendar_m_plus.png | Bin 0 -> 2919 bytes .../images/calendar_y_minus.png | Bin 0 -> 2950 bytes .../images/calendar_y_plus.png | Bin 0 -> 2898 bytes plugins/c9.ide.layout.classic/images/cell.gif | Bin 0 -> 754 bytes .../images/change_photo_box.png | Bin 0 -> 4868 bytes .../images/change_photo_win_backg.png | Bin 0 -> 2821 bytes .../images/chat_history.png | Bin 0 -> 635 bytes .../images/chatlist_toolbar_bg.png | Bin 0 -> 4042 bytes .../c9.ide.layout.classic/images/check.gif | Bin 0 -> 92 bytes .../c9.ide.layout.classic/images/check.png | Bin 0 -> 1283 bytes .../images/checkbox-blue.png | Bin 0 -> 1780 bytes .../images/checkbox.old.png | Bin 0 -> 3207 bytes .../c9.ide.layout.classic/images/checkbox.png | Bin 0 -> 559 bytes .../images/checkbox2.png | Bin 0 -> 384 bytes .../images/checkbox3.png | Bin 0 -> 3374 bytes .../images/checkbox_black.png | Bin 0 -> 3053 bytes .../images/checkbox_black@2x.png | Bin 0 -> 3053 bytes .../images/checkbox_black_flat_light.png | Bin 0 -> 1105 bytes .../images/checkbox_black_flat_light@2x.png | Bin 0 -> 2327 bytes .../images/checkbox_flat_light.png | Bin 0 -> 1219 bytes .../images/checkbox_flat_light@2x.png | Bin 0 -> 2759 bytes .../images/checkbox_grey.png | Bin 0 -> 2747 bytes .../c9.ide.layout.classic/images/clear.png | Bin 0 -> 1336 bytes .../images/clear_dark.png | Bin 0 -> 1438 bytes .../images/clear_dark_flat_light.png | Bin 0 -> 411 bytes .../images/clear_dark_flat_light@2x.png | Bin 0 -> 792 bytes .../images/clear_light_flat_light.png | Bin 0 -> 392 bytes .../images/clear_light_flat_light@2x.png | Bin 0 -> 780 bytes .../images/cli-block-expand.png | Bin 0 -> 944 bytes .../images/close-btn.png | Bin 0 -> 1804 bytes .../images/close-search-icon.png | Bin 0 -> 2509 bytes .../c9.ide.layout.classic/images/close.png | Bin 0 -> 1701 bytes .../images/close_tab_btn.png | Bin 0 -> 4807 bytes .../images/close_tab_btn@2x.png | Bin 0 -> 4970 bytes .../images/close_tab_btn_flat_light.png | Bin 0 -> 1231 bytes .../images/close_tab_btn_flat_light@2x.png | Bin 0 -> 2583 bytes .../images/cloud9logo.png | Bin 0 -> 8715 bytes .../images/cloud9logo_transparent.png | Bin 0 -> 5180 bytes .../c9.ide.layout.classic/images/colorbox.png | Bin 0 -> 237 bytes .../images/column_picker.gif | Bin 0 -> 81 bytes .../images/console-action-cancel.png | Bin 0 -> 1755 bytes .../images/console-expand-contract.png | Bin 0 -> 709 bytes .../images/console-tab-btn-curr.png | Bin 0 -> 2815 bytes .../images/console-tab-close-button.png | Bin 0 -> 2081 bytes .../images/console_arrow.png | Bin 0 -> 1178 bytes .../images/console_spinner_proc.gif | Bin 0 -> 2133 bytes plugins/c9.ide.layout.classic/images/copy.png | Bin 0 -> 260 bytes .../images/cover-heaeder.png | Bin 0 -> 113 bytes .../images/cover-logo.png | Bin 0 -> 17700 bytes plugins/c9.ide.layout.classic/images/cut.png | Bin 0 -> 232 bytes .../c9.ide.layout.classic/images/ddarrow.png | Bin 0 -> 1044 bytes .../images/debug-panel_bg.png | Bin 0 -> 3443 bytes .../images/debugicons.png | Bin 0 -> 8042 bytes .../images/delete_btn.png | Bin 0 -> 2274 bytes .../c9.ide.layout.classic/images/deploy.png | Bin 0 -> 3344 bytes .../c9.ide.layout.classic/images/dg_noise.png | Bin 0 -> 1914 bytes .../images/dockLeftBackground.png | Bin 0 -> 2176 bytes .../images/dockPanelButtonDown.png | Bin 0 -> 1091 bytes .../images/dockPanelSpeckledBG.png | Bin 0 -> 364 bytes .../images/dock_button_sprite.png | Bin 0 -> 1514 bytes .../images/dock_cloud9_bg.gif | Bin 0 -> 983 bytes .../images/dock_notification_bg.png | Bin 0 -> 490 bytes .../c9.ide.layout.classic/images/dot_blue.png | Bin 0 -> 1345 bytes .../images/drag-tree-item-backg.png | Bin 0 -> 2830 bytes .../images/dragarrows.gif | Bin 0 -> 89 bytes .../images/dropdown-dark-glossy/arrow.png | Bin 0 -> 1138 bytes .../dropdown-dark-glossy/background.png | Bin 0 -> 1718 bytes .../images/dropdown-dark-glossy/button.png | Bin 0 -> 1173 bytes .../images/dropdown-dark-glossy/button@2x.png | Bin 0 -> 3917 bytes .../images/dropdown-dark-glossy/divider.png | Bin 0 -> 1066 bytes .../images/dropdown.old.20081120.png | Bin 0 -> 1522 bytes .../images/dropdown.old.big.png | Bin 0 -> 1189 bytes .../images/dropdown.old.png | Bin 0 -> 785 bytes .../c9.ide.layout.classic/images/dropdown.png | Bin 0 -> 1486 bytes .../images/dropdown_background.png | Bin 0 -> 551 bytes .../images/dropdown_background2.png | Bin 0 -> 904 bytes .../images/dropdown_background_top.png | Bin 0 -> 179 bytes .../images/editor_bar_bg.png | Bin 0 -> 185 bytes .../images/editor_header.png | Bin 0 -> 974 bytes .../images/editor_tab.png | Bin 0 -> 4148 bytes .../images/editor_tab_bg.png | Bin 0 -> 15259 bytes .../images/editor_tabs_container_bg.gif | Bin 0 -> 504 bytes .../images/empty_editor_divider.png | Bin 0 -> 2150 bytes .../images/empty_editor_icon.png | Bin 0 -> 8515 bytes .../images/error_box_b.png | Bin 0 -> 2819 bytes .../images/error_box_lb.png | Bin 0 -> 269 bytes .../images/error_box_lt.png | Bin 0 -> 2910 bytes .../images/error_box_r.png | Bin 0 -> 132 bytes .../images/error_box_rb.png | Bin 0 -> 377 bytes .../images/error_box_rt.png | Bin 0 -> 2994 bytes .../images/error_logo.png | Bin 0 -> 33712 bytes .../images/errorbox_backg.png | Bin 0 -> 136 bytes .../images/errorbox_bottom.png | Bin 0 -> 622 bytes .../images/errorbox_top.old.png | Bin 0 -> 463 bytes .../images/errorbox_top.png | Bin 0 -> 443 bytes .../c9.ide.layout.classic/images/excel.cur | Bin 0 -> 766 bytes .../file-tree-load-spinner-dark-selected.gif | Bin 0 -> 3690 bytes ...ile-tree-load-spinner-dark-selected@2x.gif | Bin 0 -> 3690 bytes .../file-tree-load-spinner-dark-unfocus.gif | Bin 0 -> 3697 bytes ...file-tree-load-spinner-dark-unfocus@2x.gif | Bin 0 -> 3697 bytes ...e-load-spinner-dark-unfocus_flat_light.gif | Bin 0 -> 3069 bytes ...oad-spinner-dark-unfocus_flat_light@2x.gif | Bin 0 -> 606 bytes .../images/file-tree-load-spinner-dark.gif | Bin 0 -> 3669 bytes .../images/file-tree-load-spinner-dark@2x.gif | Bin 0 -> 3669 bytes .../file-tree-load-spinner-selected.gif | Bin 0 -> 3007 bytes .../file-tree-load-spinner-selected@2x.gif | Bin 0 -> 3007 bytes ...-tree-load-spinner-selected_flat_light.gif | Bin 0 -> 3069 bytes ...ee-load-spinner-selected_flat_light@2x.gif | Bin 0 -> 582 bytes .../images/file-tree-load-spinner.gif | Bin 0 -> 3227 bytes .../images/file-tree-load-spinner@2x.gif | Bin 0 -> 3227 bytes .../file-tree-load-spinner_flat_light.gif | Bin 0 -> 3069 bytes .../file-tree-load-spinner_flat_light@2x.gif | Bin 0 -> 617 bytes plugins/c9.ide.layout.classic/images/file.png | Bin 0 -> 657 bytes .../images/flyout_arrows.png | Bin 0 -> 1821 bytes .../images/footer-line.png | Bin 0 -> 1170 bytes .../images/gecko_mask.png | Bin 0 -> 1228 bytes .../images/gecko_mask_flat_light.png | Bin 0 -> 3280 bytes .../images/gecko_mask_flat_light@2x.png | Bin 0 -> 3777 bytes plugins/c9.ide.layout.classic/images/girl.png | Bin 0 -> 14053 bytes .../images/git_corner.png | Bin 0 -> 5366 bytes .../images/gitui_close_arrow.png | Bin 0 -> 2884 bytes .../images/gitui_menu_backg.png | Bin 0 -> 2988 bytes .../images/glossy-header.png | Bin 0 -> 955 bytes .../images/glossy_top_header.png | Bin 0 -> 963 bytes .../images/green-arrow-left.png | Bin 0 -> 1845 bytes .../images/headerBarBg.png | Bin 0 -> 945 bytes .../images/header_backg.png | Bin 0 -> 2835 bytes .../images/header_bg.png | Bin 0 -> 38860 bytes .../images/header_right.png | Bin 0 -> 3002 bytes .../images/headertbleft.png | Bin 0 -> 1369 bytes .../images/headertbrepeat.png | Bin 0 -> 949 bytes .../images/headertbright.png | Bin 0 -> 1421 bytes .../images/hp_errorbox_arrow.png | Bin 0 -> 1245 bytes .../images/hp_errorbox_backg.png | Bin 0 -> 1012 bytes .../images/hp_errorbox_bb.png | Bin 0 -> 967 bytes .../images/hp_errorbox_bl.png | Bin 0 -> 999 bytes .../images/hp_errorbox_bottom.png | Bin 0 -> 1438 bytes .../images/hp_errorbox_br.png | Bin 0 -> 999 bytes .../images/hp_errorbox_bt.png | Bin 0 -> 932 bytes .../images/hp_errorbox_cbl.png | Bin 0 -> 1138 bytes .../images/hp_errorbox_cbr.png | Bin 0 -> 1135 bytes .../images/hp_errorbox_close.png | Bin 0 -> 1598 bytes .../images/hp_errorbox_ctl.png | Bin 0 -> 1059 bytes .../images/hp_errorbox_ctr.png | Bin 0 -> 1061 bytes .../images/hp_errorbox_top.png | Bin 0 -> 1185 bytes .../images/ide_loading_bg_pattern.png | Bin 0 -> 645 bytes .../c9.ide.layout.classic/images/input.png | Bin 0 -> 3100 bytes .../images/input_background.png | Bin 0 -> 135 bytes .../images/input_border.png | Bin 0 -> 149 bytes .../images/input_border_lr.png | Bin 0 -> 118 bytes .../images/input_border_tb.png | Bin 0 -> 121 bytes .../images/input_error_background.gif | Bin 0 -> 93 bytes .../images/input_error_background2.gif | Bin 0 -> 1249 bytes .../c9.ide.layout.classic/images/italic.png | Bin 0 -> 221 bytes .../images/label_hover.png | Bin 0 -> 1301 bytes .../images/label_hover_bb.png | Bin 0 -> 126 bytes .../images/label_hover_br.png | Bin 0 -> 214 bytes .../images/label_hover_lb.png | Bin 0 -> 157 bytes .../images/load-indicator-active-tab.gif | Bin 0 -> 1455 bytes .../images/load-indicator-inactive-tab.gif | Bin 0 -> 1458 bytes .../images/loader-bg.png | Bin 0 -> 2631 bytes .../c9.ide.layout.classic/images/loader.gif | Bin 0 -> 781 bytes .../images/loader_logo.png | Bin 0 -> 827 bytes .../images/loader_progressbar_bg.png | Bin 0 -> 119 bytes .../images/loading-ind.png | Bin 0 -> 583 bytes .../images/loading-logo.png | Bin 0 -> 31022 bytes .../images/loading-logo@2x.png | Bin 0 -> 79642 bytes .../images/local_green.png | Bin 0 -> 3508 bytes .../images/logo-viewmode.png | Bin 0 -> 8188 bytes plugins/c9.ide.layout.classic/images/logo.png | Bin 0 -> 5204 bytes .../c9.ide.layout.classic/images/logo2.png | Bin 0 -> 5448 bytes .../c9.ide.layout.classic/images/main_bg.jpg | Bin 0 -> 1535 bytes .../c9.ide.layout.classic/images/maximize.png | Bin 0 -> 1035 bytes .../images/maximize@2x.png | Bin 0 -> 1051 bytes .../images/maximize_dark.png | Bin 0 -> 1056 bytes .../images/maximize_dark@2x.png | Bin 0 -> 1188 bytes .../c9.ide.layout.classic/images/mediabtn.png | Bin 0 -> 1387 bytes .../c9.ide.layout.classic/images/menu-btn.png | Bin 0 -> 3577 bytes .../images/menu_context_left.gif | Bin 0 -> 65 bytes .../images/menu_context_left_over.gif | Bin 0 -> 65 bytes .../images/menu_context_right.gif | Bin 0 -> 65 bytes .../images/menu_context_right_over.gif | Bin 0 -> 65 bytes .../images/menu_context_shadow_b.png | Bin 0 -> 213 bytes .../images/menu_context_shadow_corner.png | Bin 0 -> 160 bytes .../images/menu_context_shadow_lat.png | Bin 0 -> 672 bytes .../images/menu_context_shadow_lt.png | Bin 0 -> 3778 bytes .../images/menu_context_shadow_r.png | Bin 0 -> 205 bytes .../images/menu_context_shb.png | Bin 0 -> 281 bytes .../images/menu_context_shl.png | Bin 0 -> 731 bytes .../images/menu_context_shlr.png | Bin 0 -> 227 bytes .../images/menu_context_shr.png | Bin 0 -> 558 bytes .../images/menu_context_shtb.png | Bin 0 -> 204 bytes .../images/menu_down.gif | Bin 0 -> 68 bytes .../images/menu_over.gif | Bin 0 -> 54 bytes .../images/menu_tab_header.png | Bin 0 -> 174 bytes .../images/menu_tab_row.png | Bin 0 -> 143 bytes .../images/menu_win_background.png | Bin 0 -> 177 bytes .../images/menu_win_bottom.png | Bin 0 -> 573 bytes .../images/menu_win_l.png | Bin 0 -> 118 bytes .../images/menu_win_r.png | Bin 0 -> 116 bytes .../images/menubar_row.png | Bin 0 -> 3259 bytes plugins/c9.ide.layout.classic/images/min.png | Bin 0 -> 157 bytes .../c9.ide.layout.classic/images/min_dark.png | Bin 0 -> 1170 bytes .../images/modalbg-dark.png | Bin 0 -> 44873 bytes .../c9.ide.layout.classic/images/modalbg.png | Bin 0 -> 7459 bytes .../c9.ide.layout.classic/images/new_cal.jpg | Bin 0 -> 10804 bytes .../images/new_cal_big.jpg | Bin 0 -> 10974 bytes .../images/new_cal_hov.jpg | Bin 0 -> 10858 bytes .../images/new_cal_hov_big.jpg | Bin 0 -> 11058 bytes .../images/new_cal_sel.jpg | Bin 0 -> 10805 bytes .../images/new_cal_sel_big.jpg | Bin 0 -> 11298 bytes .../images/noconnection.png | Bin 0 -> 1366 bytes .../images/noise_pattern_transparent.png | Bin 0 -> 29538 bytes .../images/noise_pattern_transparent30.png | Bin 0 -> 28843 bytes .../c9.ide.layout.classic/images/offline.png | Bin 0 -> 3996 bytes .../images/open_files.png | Bin 0 -> 3931 bytes .../c9.ide.layout.classic/images/page_bt.png | Bin 0 -> 125 bytes .../c9.ide.layout.classic/images/panelBg.png | Bin 0 -> 16604 bytes .../c9.ide.layout.classic/images/paste.png | Bin 0 -> 290 bytes .../images/pause-icon.png | Bin 0 -> 973 bytes .../c9.ide.layout.classic/images/pause.gif | Bin 0 -> 118 bytes .../c9.ide.layout.classic/images/pause.png | Bin 0 -> 290 bytes .../images/play-button-active.png | Bin 0 -> 1350 bytes plugins/c9.ide.layout.classic/images/play.gif | Bin 0 -> 139 bytes plugins/c9.ide.layout.classic/images/play.png | Bin 0 -> 361 bytes plugins/c9.ide.layout.classic/images/plus.png | Bin 0 -> 166 bytes .../c9.ide.layout.classic/images/plus2.png | Bin 0 -> 1117 bytes .../images/plus_dark.png | Bin 0 -> 1203 bytes .../images/plusplain.gif | Bin 0 -> 60 bytes .../images/plustabbtn.png | Bin 0 -> 2085 bytes .../c9.ide.layout.classic/images/popout.png | Bin 0 -> 1179 bytes .../images/popout_dark.png | Bin 0 -> 1206 bytes .../images/preferences.png | Bin 0 -> 5850 bytes .../images/progressbar.old.png | Bin 0 -> 3094 bytes .../images/progressbar.png | Bin 0 -> 540 bytes .../images/project_files.png | Bin 0 -> 5507 bytes .../images/radio-black.png | Bin 0 -> 4288 bytes .../images/radio-grey.png | Bin 0 -> 3037 bytes .../c9.ide.layout.classic/images/radio.gif | Bin 0 -> 82 bytes .../c9.ide.layout.classic/images/radio.png | Bin 0 -> 3682 bytes .../images/radiobutton_over.png | Bin 0 -> 3355 bytes .../c9.ide.layout.classic/images/raster.gif | Bin 0 -> 44 bytes .../images/red-arrow-down.png | Bin 0 -> 1535 bytes plugins/c9.ide.layout.classic/images/redo.png | Bin 0 -> 224 bytes .../images/resizehandle.gif | Bin 0 -> 64 bytes .../images/revisions_search.png | Bin 0 -> 363 bytes .../images/rightclickmenu_background.png | Bin 0 -> 191 bytes .../images/rightclickmenu_bottom.png | Bin 0 -> 530 bytes .../images/rightclickmenu_top.png | Bin 0 -> 386 bytes .../c9.ide.layout.classic/images/rundebug.png | Bin 0 -> 3869 bytes .../c9.ide.layout.classic/images/running.png | Bin 0 -> 8190 bytes .../images/running_flat_light.png | Bin 0 -> 6214 bytes .../images/running_flat_light@2x.png | Bin 0 -> 16153 bytes .../images/save-indicator-active-tab.gif | Bin 0 -> 1454 bytes .../images/save-indicator-inactive-tab.gif | Bin 0 -> 1453 bytes .../images/scrollbar/grabber.png | Bin 0 -> 15271 bytes .../images/scrollbar/local_green.png | Bin 0 -> 50983 bytes .../images/scrollbar/sprite_ver_scrollbar.png | Bin 0 -> 1113 bytes .../images/scrolldown.gif | Bin 0 -> 49 bytes .../images/scrolldowndisabled.gif | Bin 0 -> 59 bytes .../c9.ide.layout.classic/images/scrollup.gif | Bin 0 -> 48 bytes .../images/scrollupdisabled.gif | Bin 0 -> 59 bytes .../images/search-icon.png | Bin 0 -> 1725 bytes .../images/search_arrow.png | Bin 0 -> 1928 bytes .../images/searchbox_textbox_icon.png | Bin 0 -> 4417 bytes .../c9.ide.layout.classic/images/segment.jpg | Bin 0 -> 11203 bytes .../images/segment_active.jpg | Bin 0 -> 11193 bytes .../images/segment_hover.jpg | Bin 0 -> 11202 bytes .../images/segment_weekend.jpg | Bin 0 -> 11507 bytes .../c9.ide.layout.classic/images/shop1.png | Bin 0 -> 6355 bytes .../c9.ide.layout.classic/images/shop2.png | Bin 0 -> 7210 bytes .../c9.ide.layout.classic/images/shop3.png | Bin 0 -> 6418 bytes .../c9.ide.layout.classic/images/shop4.png | Bin 0 -> 7062 bytes .../images/sidebar_preview_icon.png | Bin 0 -> 1666 bytes .../images/sidebar_right_bar_inset.gif | Bin 0 -> 454 bytes .../images/signedInLogo.png | Bin 0 -> 8621 bytes .../images/signin_bitbucket.png | Bin 0 -> 2653 bytes .../images/signin_facebook.png | Bin 0 -> 3978 bytes .../images/signin_github.png | Bin 0 -> 4307 bytes .../images/signin_google.png | Bin 0 -> 3970 bytes .../images/signin_twitter.png | Bin 0 -> 2468 bytes .../c9.ide.layout.classic/images/slider.png | Bin 0 -> 500 bytes .../images/slider11x.png | Bin 0 -> 289 bytes .../images/slider11x_high.png | Bin 0 -> 507 bytes .../images/slider16x.png | Bin 0 -> 731 bytes .../images/slider16x_high.png | Bin 0 -> 1052 bytes .../c9.ide.layout.classic/images/slider2.png | Bin 0 -> 504 bytes .../images/slider_tbutton.png | Bin 0 -> 3304 bytes .../images/small-player-left-arr.png | Bin 0 -> 346 bytes .../images/small-player-right-arr.png | Bin 0 -> 336 bytes .../images/smile-image.png | Bin 0 -> 3243 bytes plugins/c9.ide.layout.classic/images/smin.gif | Bin 0 -> 837 bytes .../c9.ide.layout.classic/images/sort_asc.gif | Bin 0 -> 54 bytes .../images/sort_desc.gif | Bin 0 -> 54 bytes .../c9.ide.layout.classic/images/spacer.gif | Bin 0 -> 49 bytes .../images/spinner_body2.png | Bin 0 -> 2837 bytes .../images/spinner_min.png | Bin 0 -> 959 bytes .../images/spinner_min_dark.png | Bin 0 -> 966 bytes .../images/spinner_plus.png | Bin 0 -> 1032 bytes .../images/spinner_plus_dark.png | Bin 0 -> 981 bytes .../images/splitter_dark_bg.png | Bin 0 -> 136 bytes .../images/splitter_dark_grab.png | Bin 0 -> 2901 bytes .../images/splitter_docs.gif | Bin 0 -> 53 bytes .../images/splitter_handle_horizontal.gif | Bin 0 -> 49 bytes .../images/splitter_handle_vertical.gif | Bin 0 -> 50 bytes .../c9.ide.layout.classic/images/splus.gif | Bin 0 -> 841 bytes .../images/sprite-rounded-vert.png | Bin 0 -> 29042 bytes .../images/sprite_boxes_hor.png | Bin 0 -> 5413 bytes .../images/sprite_boxes_ver.png | Bin 0 -> 1004 bytes .../images/statusbar.gif | Bin 0 -> 68 bytes plugins/c9.ide.layout.classic/images/stop.png | Bin 0 -> 2831 bytes .../images/submenu_arrow.gif | Bin 0 -> 70 bytes .../images/sync-state-label.png | Bin 0 -> 2859 bytes plugins/c9.ide.layout.classic/images/sync.png | Bin 0 -> 2071 bytes .../images/sync_toggle.png | Bin 0 -> 4898 bytes .../images/tab-save-spinner-active.gif | Bin 0 -> 2370 bytes .../images/tab-save-spinner-active.png | Bin 0 -> 1217 bytes .../images/tab-save-spinner-active@2x.png | Bin 0 -> 1217 bytes .../tab-save-spinner-active_flat_light.png | Bin 0 -> 2922 bytes .../tab-save-spinner-active_flat_light@2x.png | Bin 0 -> 6793 bytes .../images/tab-save-spinner-inactive.gif | Bin 0 -> 2316 bytes .../images/tab_but_bottomleft.old.png | Bin 0 -> 444 bytes .../images/tab_but_bottomleft.png | Bin 0 -> 412 bytes .../images/tab_but_bottomright.old.png | Bin 0 -> 283 bytes .../images/tab_but_bottomright.png | Bin 0 -> 258 bytes .../images/tab_but_l.png | Bin 0 -> 291 bytes .../images/tab_but_lb.png | Bin 0 -> 284 bytes .../images/tab_but_lt.png | Bin 0 -> 298 bytes .../images/tab_but_m.png | Bin 0 -> 156 bytes .../images/tab_but_mb.png | Bin 0 -> 169 bytes .../images/tab_but_mt.png | Bin 0 -> 151 bytes .../images/tab_but_r.png | Bin 0 -> 321 bytes .../images/tab_but_rb.png | Bin 0 -> 283 bytes .../images/tab_but_rt.png | Bin 0 -> 321 bytes .../images/tab_but_top.png | Bin 0 -> 632 bytes .../images/tab_but_topleft.old.png | Bin 0 -> 451 bytes .../images/tab_but_topleft.png | Bin 0 -> 406 bytes .../images/tab_but_topright.old.png | Bin 0 -> 321 bytes .../images/tab_but_topright.png | Bin 0 -> 285 bytes .../c9.ide.layout.classic/images/tab_menu.png | Bin 0 -> 1182 bytes .../images/tab_menu@2x.png | Bin 0 -> 1504 bytes .../images/tab_menu_dark.png | Bin 0 -> 1178 bytes .../images/tab_menu_dark@2x.png | Bin 0 -> 1514 bytes .../images/tab_menu_flat_light.png | Bin 0 -> 1021 bytes .../images/tab_menu_flat_light@2x.png | Bin 0 -> 1131 bytes .../c9.ide.layout.classic/images/tab_next.gif | Bin 0 -> 493 bytes .../images/tab_next_blink.gif | Bin 0 -> 1150 bytes .../images/tab_pag_lb.png | Bin 0 -> 350 bytes .../images/tab_pag_rb.png | Bin 0 -> 351 bytes .../c9.ide.layout.classic/images/tab_plus.png | Bin 0 -> 1030 bytes .../images/tab_plus@2x.png | Bin 0 -> 1153 bytes .../images/tab_plus_dark.png | Bin 0 -> 1040 bytes .../images/tab_plus_dark@2x.png | Bin 0 -> 1146 bytes .../images/tab_plus_flat_light.png | Bin 0 -> 1446 bytes .../images/tab_plus_flat_light@2x.png | Bin 0 -> 1847 bytes .../c9.ide.layout.classic/images/tab_prev.gif | Bin 0 -> 471 bytes .../images/tab_prev_blink.gif | Bin 0 -> 1143 bytes .../images/tabdropdown.png | Bin 0 -> 1651 bytes .../images/tabsave-flat.png | Bin 0 -> 1236 bytes .../images/tabsave-flat@2x.png | Bin 0 -> 1443 bytes .../c9.ide.layout.classic/images/tabsave.png | Bin 0 -> 1880 bytes .../images/tabsave@2x.png | Bin 0 -> 5069 bytes .../c9.ide.layout.classic/images/testing.png | Bin 0 -> 2064 bytes .../images/textarea_background.png | Bin 0 -> 1259 bytes .../images/textarea_background2.png | Bin 0 -> 3747 bytes .../images/textarea_background_left.png | Bin 0 -> 118 bytes .../images/textarea_background_top.png | Bin 0 -> 120 bytes .../images/the_store.png | Bin 0 -> 5388 bytes .../images/toolbar-arrows.png | Bin 0 -> 1106 bytes .../images/toolbar-divider.png | Bin 0 -> 134 bytes .../images/toolbar.icons.gif | Bin 0 -> 11505 bytes .../images/toolbar_a_down.png | Bin 0 -> 512 bytes .../images/toolbar_a_down_right.png | Bin 0 -> 279 bytes .../images/toolbar_a_hover.png | Bin 0 -> 486 bytes .../images/toolbar_a_hover_right.png | Bin 0 -> 240 bytes .../images/toolbar_a_small_hover.png | Bin 0 -> 394 bytes .../images/toolbar_a_small_sel.png | Bin 0 -> 345 bytes .../images/toolbar_btn.gif | Bin 0 -> 1010 bytes .../images/toolbar_row.png | Bin 0 -> 132 bytes .../c9.ide.layout.classic/images/tools.png | Bin 0 -> 153 bytes .../images/tooltip_arrow.png | Bin 0 -> 428 bytes .../images/tree-shadow-left.png | Bin 0 -> 2815 bytes .../images/tree-shadow-right.png | Bin 0 -> 2832 bytes .../images/tree_backg.png | Bin 0 -> 3676 bytes .../images/tree_checkbox.png | Bin 0 -> 559 bytes .../images/tree_close_arrow.png | Bin 0 -> 3190 bytes .../images/tree_close_arrow_small.png | Bin 0 -> 2971 bytes .../images/tree_close_arrow_small@2x.png | Bin 0 -> 2971 bytes .../images/tree_close_arrow_small_dark.png | Bin 0 -> 3077 bytes .../images/tree_close_arrow_small_dark@2x.png | Bin 0 -> 3077 bytes .../images/tree_selected.png | Bin 0 -> 2792 bytes .../images/tree_upload_icon.png | Bin 0 -> 1387 bytes .../images/underline.png | Bin 0 -> 172 bytes plugins/c9.ide.layout.classic/images/undo.png | Bin 0 -> 220 bytes .../c9.ide.layout.classic/images/updatec9.png | Bin 0 -> 1363 bytes .../images/versions_search_close.png | Bin 0 -> 1520 bytes .../images/visual_editor.png | Bin 0 -> 4867 bytes .../c9.ide.layout.classic/images/volume.gif | Bin 0 -> 173 bytes .../images/wide-view-icn.png | Bin 0 -> 619 bytes .../c9.ide.layout.classic/images/win16x.png | Bin 0 -> 334 bytes .../c9.ide.layout.classic/images/win19x.png | Bin 0 -> 348 bytes .../c9.ide.layout.classic/images/win28x.png | Bin 0 -> 416 bytes .../c9.ide.layout.classic/images/win32x.png | Bin 0 -> 421 bytes .../c9.ide.layout.classic/images/win64x.png | Bin 0 -> 533 bytes .../c9.ide.layout.classic/images/win_edit.gif | Bin 0 -> 117 bytes .../c9.ide.layout.classic/images/win_edit.png | Bin 0 -> 791 bytes .../c9.ide.layout.classic/images/win_max.gif | Bin 0 -> 117 bytes .../c9.ide.layout.classic/images/win_min.gif | Bin 0 -> 104 bytes .../images/win_restore.gif | Bin 0 -> 92 bytes .../c9.ide.layout.classic/images/win_x.gif | Bin 0 -> 100 bytes .../c9.ide.layout.classic/images/win_x.png | Bin 0 -> 1494 bytes .../c9.ide.layout.classic/images/winc9.png | Bin 0 -> 4355 bytes .../images/winc9_light.png | Bin 0 -> 4110 bytes .../images/window_border.png | Bin 0 -> 113 bytes .../images/window_lb.png | Bin 0 -> 296 bytes .../images/window_lb_rounded.png | Bin 0 -> 242 bytes .../images/window_lb_small.png | Bin 0 -> 135 bytes .../images/window_lt.png | Bin 0 -> 362 bytes .../images/window_mb.png | Bin 0 -> 173 bytes .../images/window_mb_small.png | Bin 0 -> 119 bytes .../images/window_mt.png | Bin 0 -> 185 bytes .../images/window_rb.png | Bin 0 -> 299 bytes .../images/window_rb_rounded.png | Bin 0 -> 252 bytes .../images/window_rb_small.png | Bin 0 -> 135 bytes .../images/window_rt.png | Bin 0 -> 366 bytes .../images/wp_searchbox_clearbtn.png | Bin 0 -> 1214 bytes .../images/wp_searchbox_icon.png | Bin 0 -> 1217 bytes plugins/c9.ide.layout.classic/images/x.png | Bin 0 -> 138 bytes .../images/zen-buttons.png | Bin 0 -> 3095 bytes .../c9.ide.layout.classic/images/zenbg.png | Bin 0 -> 50753 bytes plugins/c9.ide.layout.classic/keyframes.css | 50 + plugins/c9.ide.layout.classic/layout.js | 600 + plugins/c9.ide.layout.classic/layout.xml | 56 + plugins/c9.ide.layout.classic/less/bar.less | 64 + .../c9.ide.layout.classic/less/bk-window.less | 132 + .../less/bk-window2.less | 0 .../less/black_dropdown.less | 88 + .../less/blackbutton.less | 28 + .../c9.ide.layout.classic/less/blackdg.less | 283 + .../less/browser-btn.less | 36 + .../less/btn-default-css3.less | 189 + .../less/btn_console.less | 36 + .../less/btn_console_open.less | 44 + .../less/btn_icon_only.less | 76 + .../c9.ide.layout.classic/less/button.less | 480 + .../less/c9-divider-double.less | 35 + .../less/c9-divider-hor.less | 23 + .../less/c9-divider.less | 11 + .../less/c9-menu-bar.less | 226 + .../less/c9-menu-btn.less | 118 + .../less/c9-notification-bar.less | 22 + .../less/c9-simple-btn.less | 10 + .../less/c9-toolbarbutton-glossy.less | 127 + .../less/c9-toolbarbutton-light.less | 51 + .../less/c9-toolbarbutton.less | 132 + .../c9.ide.layout.classic/less/cboffline.less | 43 + .../c9.ide.layout.classic/less/checkbox.less | 67 + .../less/checkbox_black.less | 58 + .../less/checkbox_grey.less | 53 + .../c9.ide.layout.classic/less/codebox.less | 89 + .../c9.ide.layout.classic/less/colorbox.less | 6 + .../c9.ide.layout.classic/less/datagrid.less | 527 + .../c9.ide.layout.classic/less/divider.less | 51 + .../less/divider_console.less | 7 + .../less/dropdown-dark-glossy.less | 104 + .../c9.ide.layout.classic/less/dropdown.less | 182 + .../less/editor_tab.less | 541 + .../c9.ide.layout.classic/less/errorbox.less | 176 + plugins/c9.ide.layout.classic/less/frame.less | 88 + .../less/grouped_checkbox.less | 106 + .../less/header-btn.less | 69 + plugins/c9.ide.layout.classic/less/img.less | 20 + plugins/c9.ide.layout.classic/less/label.less | 15 + .../c9.ide.layout.classic/less/lesshat.less | 2289 + .../less/lineselect.less | 5 + plugins/c9.ide.layout.classic/less/list.less | 92 + .../c9.ide.layout.classic/less/list_dark.less | 7 + plugins/c9.ide.layout.classic/less/main.less | 97 + plugins/c9.ide.layout.classic/less/menu.less | 113 + .../less/notification-bar.less | 0 .../c9.ide.layout.classic/less/panel-bar.less | 23 + .../c9.ide.layout.classic/less/password.less | 10 + .../less/radiobutton.less | 42 + plugins/c9.ide.layout.classic/less/sbios.less | 92 + .../c9.ide.layout.classic/less/scrollbar.less | 107 + .../c9.ide.layout.classic/less/searchbox.less | 125 + .../c9.ide.layout.classic/less/simplebox.less | 19 + .../c9.ide.layout.classic/less/simpleimg.less | 0 .../c9.ide.layout.classic/less/spinner.less | 179 + .../c9.ide.layout.classic/less/splitter.less | 73 + plugins/c9.ide.layout.classic/less/style.less | 203 + .../c9.ide.layout.classic/less/tbsimple.less | 13 + .../c9.ide.layout.classic/less/textarea.less | 37 + .../c9.ide.layout.classic/less/textbox.less | 49 + .../less/toolbar-bottom.less | 21 + .../less/toolbar-top.less | 35 + .../c9.ide.layout.classic/less/toolbar.less | 74 + .../less/tooltiplabel.less | 18 + plugins/c9.ide.layout.classic/loading.css | 88 + plugins/c9.ide.layout.classic/preload.js | 81 + plugins/c9.ide.layout.classic/skins.xml | 863 + .../c9.ide.layout.classic/themes/crazy.less | 253 + .../themes/default-dark-gray.less | 1681 + .../themes/default-dark.less | 1681 + .../themes/default-flat-light.less | 1681 + .../themes/default-light-gray.less | 1681 + .../themes/default-light.less | 1681 + .../themes/flat-light.less | 448 + plugins/c9.ide.panels/area.js | 470 + plugins/c9.ide.panels/panel.js | 443 + plugins/c9.ide.panels/panels.js | 278 + plugins/c9.ide.panels/panels_test.js | 437 + plugins/c9.ide.panels/skin.xml | 117 + plugins/c9.ide.plugins/debug.js | 302 + plugins/c9.ide.plugins/installer.js | 194 + plugins/c9.ide.plugins/loader.js | 144 + plugins/c9.ide.plugins/manager.js | 669 + plugins/c9.ide.plugins/managerdp.js | 75 + plugins/c9.ide.plugins/market.js | 224 + plugins/c9.ide.plugins/mock/c9.ide.example | 1 + .../mock/c9.ide.example2/example.js | 63 + .../mock/c9.ide.example2/package.json | 23 + .../templates/plugin.default.tar.gz | Bin 0 -> 40960 bytes .../templates/plugin.default/README.md | 3 + .../templates/plugin.default/images/puppy.jpg | Bin 0 -> 26429 bytes .../templates/plugin.default/package.json | 21 + .../templates/plugin.default/plugin.html | 1 + .../templates/plugin.default/plugin.js | 155 + .../templates/plugin.default/plugin_test.js | 47 + .../templates/plugin.default/style.css | 13 + .../templates/plugin.simple.tar.gz | Bin 0 -> 10240 bytes .../templates/plugin.simple/README.md | 3 + .../templates/plugin.simple/package.json | 21 + .../templates/plugin.simple/plugin.js | 40 + .../templates/plugin.simple/plugin_test.js | 47 + plugins/c9.ide.plugins/test.js | 299 + plugins/c9.ide.preferences/general.js | 150 + .../c9.ide.preferences/images/c9-noise.png | Bin 0 -> 4538 bytes plugins/c9.ide.preferences/images/panelbg.png | Bin 0 -> 5088 bytes .../c9.ide.preferences/images/preferences.png | Bin 0 -> 3769 bytes .../images/tree_close_arrow_small.png | Bin 0 -> 2971 bytes .../images/tree_close_arrow_small@2x.png | Bin 0 -> 2971 bytes .../images/tree_close_arrow_small_dark.png | Bin 0 -> 3077 bytes plugins/c9.ide.preferences/preferencepanel.js | 398 + plugins/c9.ide.preferences/preferences.css | 386 + plugins/c9.ide.preferences/preferences.js | 493 + .../c9.ide.preferences/preferences_test.js | 196 + plugins/c9.ide.preferences/project.js | 108 + plugins/c9.ide.server/plugins.js | 135 + plugins/c9.ide.server/www/require.js | 2054 + plugins/c9.ide.server/www/text.js | 388 + plugins/c9.ide.terminal/aceterm/aceterm.js | 565 + plugins/c9.ide.terminal/aceterm/hover_link.js | 372 + plugins/c9.ide.terminal/aceterm/input.js | 217 + plugins/c9.ide.terminal/aceterm/libterm.js | 3579 + plugins/c9.ide.terminal/aceterm/mouse.js | 311 + .../c9.ide.terminal/aceterm/scroll_buffer.js | 51 + .../c9.ide.terminal/aceterm/term_colors.js | 109 + plugins/c9.ide.terminal/images/tile.png | Bin 0 -> 942 bytes plugins/c9.ide.terminal/install-tmux.sh | 24 + plugins/c9.ide.terminal/link_handler.js | 262 + plugins/c9.ide.terminal/menu.xml | 25 + plugins/c9.ide.terminal/opentermhere.js | 88 + plugins/c9.ide.terminal/predict_echo.js | 765 + plugins/c9.ide.terminal/predict_echo_test.js | 555 + plugins/c9.ide.terminal/style.css | 108 + plugins/c9.ide.terminal/terminal.js | 1303 + plugins/c9.ide.terminal/terminal.xml | 9 + plugins/c9.ide.terminal/terminal_test.js | 304 + plugins/c9.ide.terminal/tmux_connection.js | 346 + plugins/c9.ide.tree/favorites.js | 892 + plugins/c9.ide.tree/style.css | 217 + plugins/c9.ide.tree/tree.js | 1557 + plugins/c9.ide.tree/tree.xml | 12 + plugins/c9.ide.tree/tree_test.js | 667 + plugins/c9.ide.ui/_docs.js | 2258 + plugins/c9.ide.ui/anims.js | 340 + plugins/c9.ide.ui/codebox.js | 221 + plugins/c9.ide.ui/docklayout.js | 1850 + plugins/c9.ide.ui/docklayout_test.js | 105 + plugins/c9.ide.ui/focus.js | 78 + plugins/c9.ide.ui/forms.js | 849 + plugins/c9.ide.ui/lib/core.js | 134 + plugins/c9.ide.ui/lib/dropdown.js | 8392 ++ plugins/c9.ide.ui/lib/flexbox.js | 994 + plugins/c9.ide.ui/lib/menu/menu.js | 1830 + plugins/c9.ide.ui/lib/page.js | 2171 + plugins/c9.ide.ui/lib/splitbox.js | 1568 + plugins/c9.ide.ui/lib_apf.js | 37142 ++++++++ plugins/c9.ide.ui/lib_firmin.js | 4 + plugins/c9.ide.ui/lib_less1.5.js | 6914 ++ plugins/c9.ide.ui/menus.js | 1449 + plugins/c9.ide.ui/menus_test.js | 233 + plugins/c9.ide.ui/style.css | 1 + plugins/c9.ide.ui/tooltip.js | 255 + plugins/c9.ide.ui/ui.js | 770 + plugins/c9.ide.ui/ui_test.js | 133 + plugins/c9.ide.watcher/gui.js | 625 + plugins/c9.ide.watcher/watcher.js | 346 + plugins/c9.ide.watcher/watcher_test.js | 197 + plugins/c9.logtimestamp/logtimestamp.js | 29 + plugins/c9.nodeapi/assert.js | 324 + plugins/c9.nodeapi/async.js | 955 + plugins/c9.nodeapi/events.js | 311 + plugins/c9.nodeapi/events_test.js | 104 + plugins/c9.nodeapi/http-error.js | 124 + plugins/c9.nodeapi/http.js | 44 + plugins/c9.nodeapi/lodash.js | 6753 ++ plugins/c9.nodeapi/nodeapi.js | 45 + plugins/c9.nodeapi/path.js | 210 + plugins/c9.nodeapi/querystring.js | 213 + plugins/c9.nodeapi/sinon.js | 4220 + plugins/c9.nodeapi/stream.js | 121 + plugins/c9.nodeapi/url.js | 697 + plugins/c9.nodeapi/util.js | 540 + plugins/c9.nodeapi/ws.js | 26 + plugins/c9.preview/preview.handler.js | 289 + plugins/c9.preview/preview.js | 127 + plugins/c9.preview/static/livecss.js | 1027 + plugins/c9.preview/statics.js | 14 + plugins/c9.preview/views/listing.html.ejs | 36 + plugins/c9.preview/views/progress.html.ejs | 26 + plugins/c9.static/build.js | 405 + plugins/c9.static/build_test.js | 76 + plugins/c9.static/cdn.cli.js | 212 + plugins/c9.static/cdn.js | 155 + plugins/c9.static/connect-static.js | 65 + plugins/c9.static/connect.js | 38 + plugins/c9.static/makestatic.js | 100 + plugins/c9.vfs.client/endpoint.js | 356 + plugins/c9.vfs.client/ping-service.js | 7 + plugins/c9.vfs.client/vfs.cli.js | 20 + plugins/c9.vfs.client/vfs.ping.js | 83 + plugins/c9.vfs.client/vfs_client.js | 430 + plugins/c9.vfs.client/vfs_test.js | 106 + plugins/c9.vfs.server/cache.js | 255 + plugins/c9.vfs.server/download.js | 141 + plugins/c9.vfs.server/download_test.js | 120 + plugins/c9.vfs.server/filelist.js | 123 + plugins/c9.vfs.server/statics.js | 101 + plugins/c9.vfs.server/vfs.connect.local.js | 69 + .../c9.vfs.server/vfs.connect.standalone.js | 80 + plugins/c9.vfs.server/vfs.js | 232 + plugins/c9.vfs.server/vfs.server.js | 319 + plugins/c9.vfs.server/vfs_proxy.js | 70 + plugins/c9.vfs.server/vfs_wrapper.js | 99 + plugins/c9.vfs.standalone/standalone.js | 325 + .../views/standalone.html.ejs | 143 + plugins/c9.vfs.standalone/www/html2canvas.js | 2841 + plugins/c9.vfs.standalone/www/install.html | 43 + plugins/c9.vfs.standalone/www/packed.html | 37 + plugins/c9.vfs.standalone/www/places.html | 71 + plugins/c9.vfs.standalone/www/require.js | 1999 + plugins/c9.vfs.standalone/www/test.html | 380 + plugins/c9.vfs.standalone/www/test.js | 469 + plugins/c9.vfs.standalone/www/testsuite.html | 142 + plugins/c9.vfs.standalone/www/text.js | 308 + scripts/initlocal.sh | 71 + scripts/install-sdk.sh | 80 + scripts/makelocal.sh | 54 + scripts/makestandalone.sh | 42 + scripts/makestatic.js | 107 + scripts/setup-local-dev.sh | 67 + scripts/uninstall-c9.sh | 9 + scripts/update-npm.sh | 6 + server.js | 132 + settings/local.js | 62 + settings/standalone.js | 142 + test/filefinder.js | 164 + 2812 files changed, 628435 insertions(+) create mode 100644 .eslintrc create mode 100644 .gitignore create mode 100644 .nakignore create mode 100644 LICENSE create mode 100644 README.md create mode 100755 bin/c9 create mode 100644 bin/launch.bat create mode 100644 build/browser_extensions/chrome/icon128.png create mode 100644 build/browser_extensions/chrome/manifest.json create mode 100755 build/build-local.sh create mode 100755 build/build-standalone.sh create mode 100644 build/osx/c9.icns create mode 100644 build/win32/Cloud9.ico create mode 100644 build/win32/icon.png create mode 100644 configs/cdn-cli.js create mode 100644 configs/cdn.js create mode 100644 configs/cli.js create mode 100644 configs/client-default.js create mode 100644 configs/local.js create mode 100644 configs/standalone.js create mode 100644 docs/CODING_STANDARDS.md create mode 100644 local/Info.plist create mode 120000 local/favicon.ico create mode 100644 local/index.html create mode 100755 local/install.sh create mode 100644 local/logger.js create mode 100644 local/menus.js create mode 100644 local/package.json create mode 100644 local/projectManager.html create mode 100644 local/server.js create mode 100644 node_modules/ace/.gitignore create mode 100644 node_modules/ace/.gitmodules create mode 100644 node_modules/ace/.travis.yml create mode 100644 node_modules/ace/CNAME create mode 100644 node_modules/ace/CONTRIBUTING.md create mode 100644 node_modules/ace/ChangeLog.txt create mode 100644 node_modules/ace/LICENSE create mode 100644 node_modules/ace/Makefile create mode 100755 node_modules/ace/Makefile.dryice.js create mode 100644 node_modules/ace/Readme.md create mode 100644 node_modules/ace/api/ace.html create mode 100644 node_modules/ace/api/anchor.html create mode 100644 node_modules/ace/api/background_tokenizer.html create mode 100644 node_modules/ace/api/command_manager.html create mode 100644 node_modules/ace/api/document.html create mode 100644 node_modules/ace/api/edit_session.html create mode 100644 node_modules/ace/api/editor.html create mode 100644 node_modules/ace/api/index.html create mode 100644 node_modules/ace/api/placeholder.html create mode 100644 node_modules/ace/api/range.html create mode 100644 node_modules/ace/api/renderloop.html create mode 100644 node_modules/ace/api/resources/csses/ace_api.css create mode 100644 node_modules/ace/api/resources/font/fontawesome-webfont.eot create mode 100644 node_modules/ace/api/resources/font/fontawesome-webfont.svg create mode 100644 node_modules/ace/api/resources/font/fontawesome-webfont.ttf create mode 100644 node_modules/ace/api/resources/font/fontawesome-webfont.woff create mode 100644 node_modules/ace/api/resources/images/Ace_ERD.png create mode 100644 node_modules/ace/api/resources/images/ace_logo.png create mode 100644 node_modules/ace/api/resources/images/ace_logo_menu.png create mode 100644 node_modules/ace/api/resources/images/c9-log-footer.png create mode 100644 node_modules/ace/api/resources/images/c9-sponsor.png create mode 100644 node_modules/ace/api/resources/images/cloud9-logo.png create mode 100644 node_modules/ace/api/resources/images/content-top.png create mode 100644 node_modules/ace/api/resources/images/content_bg.png create mode 100644 node_modules/ace/api/resources/images/content_top_bg.png create mode 100644 node_modules/ace/api/resources/images/dashed_back.png create mode 100644 node_modules/ace/api/resources/images/footer-bg.png create mode 100644 node_modules/ace/api/resources/images/main_bg.png create mode 100644 node_modules/ace/api/resources/images/member-sprites.png create mode 100644 node_modules/ace/api/resources/images/menu_disc.png create mode 100644 node_modules/ace/api/resources/images/method_bg.png create mode 100644 node_modules/ace/api/resources/images/scrolled-heading-shadow.png create mode 100644 node_modules/ace/api/resources/images/sidebar-top-bg.png create mode 100644 node_modules/ace/api/resources/images/sidebar_border.png create mode 100644 node_modules/ace/api/resources/images/swirl_divider.png create mode 100644 node_modules/ace/api/resources/javascripts/bbq.js create mode 100644 node_modules/ace/api/resources/javascripts/bootstrap.js create mode 100644 node_modules/ace/api/resources/javascripts/clicker.js create mode 100644 node_modules/ace/api/resources/javascripts/disqus-ext.js create mode 100644 node_modules/ace/api/resources/javascripts/jquery-scrollspy.js create mode 100644 node_modules/ace/api/resources/javascripts/jquery.collapse.js create mode 100644 node_modules/ace/api/resources/javascripts/jquery.cookie.js create mode 100644 node_modules/ace/api/resources/javascripts/plugins.js create mode 100644 node_modules/ace/api/resources/javascripts/prettify-extension.js create mode 100644 node_modules/ace/api/resources/javascripts/prettify.js create mode 100644 node_modules/ace/api/resources/javascripts/ux.js create mode 100644 node_modules/ace/api/scrollbar.html create mode 100644 node_modules/ace/api/search.html create mode 100644 node_modules/ace/api/selection.html create mode 100644 node_modules/ace/api/split.html create mode 100644 node_modules/ace/api/token_iterator.html create mode 100644 node_modules/ace/api/tokenizer.html create mode 100644 node_modules/ace/api/undomanager.html create mode 100644 node_modules/ace/api/virtual_renderer.html create mode 100644 node_modules/ace/build_support/bookmarklet.html create mode 100644 node_modules/ace/build_support/editor.html create mode 100644 node_modules/ace/build_support/mini_require.js create mode 100644 node_modules/ace/build_support/style.css create mode 100644 node_modules/ace/demo/autocompletion.html create mode 100644 node_modules/ace/demo/autoresize.html create mode 100644 node_modules/ace/demo/chromevox.html create mode 100644 node_modules/ace/demo/emmet.html create mode 100644 node_modules/ace/demo/ie7.html create mode 100644 node_modules/ace/demo/keyboard_shortcuts.html create mode 100644 node_modules/ace/demo/kitchen-sink/demo.js create mode 100644 node_modules/ace/demo/kitchen-sink/dev_util.js create mode 100644 node_modules/ace/demo/kitchen-sink/doclist.js create mode 100644 node_modules/ace/demo/kitchen-sink/docs/.gitignore create mode 100644 node_modules/ace/demo/kitchen-sink/docs/Dockerfile create mode 100644 node_modules/ace/demo/kitchen-sink/docs/Haxe.hx create mode 100644 node_modules/ace/demo/kitchen-sink/docs/Jack.jack create mode 100644 node_modules/ace/demo/kitchen-sink/docs/Makefile create mode 100644 node_modules/ace/demo/kitchen-sink/docs/Nix.nix create mode 100644 node_modules/ace/demo/kitchen-sink/docs/abap.abap create mode 100644 node_modules/ace/demo/kitchen-sink/docs/abc.abc create mode 100644 node_modules/ace/demo/kitchen-sink/docs/actionscript.as create mode 100644 node_modules/ace/demo/kitchen-sink/docs/ada.ada create mode 100644 node_modules/ace/demo/kitchen-sink/docs/asciidoc.asciidoc create mode 100644 node_modules/ace/demo/kitchen-sink/docs/assembly_x86.asm create mode 100644 node_modules/ace/demo/kitchen-sink/docs/autohotkey.ahk create mode 100644 node_modules/ace/demo/kitchen-sink/docs/batchfile.bat create mode 100644 node_modules/ace/demo/kitchen-sink/docs/c9search.c9search_results create mode 100644 node_modules/ace/demo/kitchen-sink/docs/c_cpp.cpp create mode 100644 node_modules/ace/demo/kitchen-sink/docs/cirru.cirru create mode 100644 node_modules/ace/demo/kitchen-sink/docs/clojure.clj create mode 100644 node_modules/ace/demo/kitchen-sink/docs/cobol.CBL create mode 100644 node_modules/ace/demo/kitchen-sink/docs/coffee.coffee create mode 100644 node_modules/ace/demo/kitchen-sink/docs/coldfusion.cfm create mode 100644 node_modules/ace/demo/kitchen-sink/docs/csharp.cs create mode 100644 node_modules/ace/demo/kitchen-sink/docs/css.css create mode 100644 node_modules/ace/demo/kitchen-sink/docs/curly.curly create mode 100644 node_modules/ace/demo/kitchen-sink/docs/d.d create mode 100644 node_modules/ace/demo/kitchen-sink/docs/dart.dart create mode 100644 node_modules/ace/demo/kitchen-sink/docs/diff.diff create mode 100644 node_modules/ace/demo/kitchen-sink/docs/dot.dot create mode 100644 node_modules/ace/demo/kitchen-sink/docs/eiffel.e create mode 100644 node_modules/ace/demo/kitchen-sink/docs/ejs.ejs create mode 100644 node_modules/ace/demo/kitchen-sink/docs/elixir.ex create mode 100644 node_modules/ace/demo/kitchen-sink/docs/elm.elm create mode 100644 node_modules/ace/demo/kitchen-sink/docs/erlang.erl create mode 100644 node_modules/ace/demo/kitchen-sink/docs/forth.frt create mode 100644 node_modules/ace/demo/kitchen-sink/docs/ftl.ftl create mode 100644 node_modules/ace/demo/kitchen-sink/docs/gcode.gcode create mode 100644 node_modules/ace/demo/kitchen-sink/docs/gherkin.feature create mode 100644 node_modules/ace/demo/kitchen-sink/docs/glsl.glsl create mode 100644 node_modules/ace/demo/kitchen-sink/docs/golang.go create mode 100644 node_modules/ace/demo/kitchen-sink/docs/groovy.groovy create mode 100644 node_modules/ace/demo/kitchen-sink/docs/haml.haml create mode 100644 node_modules/ace/demo/kitchen-sink/docs/handlebars.hbs create mode 100644 node_modules/ace/demo/kitchen-sink/docs/haskell.hs create mode 100644 node_modules/ace/demo/kitchen-sink/docs/htaccess create mode 100644 node_modules/ace/demo/kitchen-sink/docs/html.html create mode 100644 node_modules/ace/demo/kitchen-sink/docs/html_ruby.erb create mode 100644 node_modules/ace/demo/kitchen-sink/docs/ini.ini create mode 100644 node_modules/ace/demo/kitchen-sink/docs/io.io create mode 100644 node_modules/ace/demo/kitchen-sink/docs/jade.jade create mode 100644 node_modules/ace/demo/kitchen-sink/docs/java.java create mode 100644 node_modules/ace/demo/kitchen-sink/docs/javascript.js create mode 100644 node_modules/ace/demo/kitchen-sink/docs/json.json create mode 100644 node_modules/ace/demo/kitchen-sink/docs/jsoniq.jq create mode 100644 node_modules/ace/demo/kitchen-sink/docs/jsp.jsp create mode 100644 node_modules/ace/demo/kitchen-sink/docs/jsx.jsx create mode 100644 node_modules/ace/demo/kitchen-sink/docs/julia.jl create mode 100644 node_modules/ace/demo/kitchen-sink/docs/latex.tex create mode 100644 node_modules/ace/demo/kitchen-sink/docs/less.less create mode 100644 node_modules/ace/demo/kitchen-sink/docs/liquid.liquid create mode 100644 node_modules/ace/demo/kitchen-sink/docs/lisp.lisp create mode 100644 node_modules/ace/demo/kitchen-sink/docs/livescript.ls create mode 100644 node_modules/ace/demo/kitchen-sink/docs/logiql.logic create mode 100644 node_modules/ace/demo/kitchen-sink/docs/lsl.lsl create mode 100644 node_modules/ace/demo/kitchen-sink/docs/lua.lua create mode 100644 node_modules/ace/demo/kitchen-sink/docs/luapage.lp create mode 100644 node_modules/ace/demo/kitchen-sink/docs/lucene.lucene create mode 100644 node_modules/ace/demo/kitchen-sink/docs/markdown.md create mode 100644 node_modules/ace/demo/kitchen-sink/docs/mask.mask create mode 100644 node_modules/ace/demo/kitchen-sink/docs/matlab.matlab create mode 100644 node_modules/ace/demo/kitchen-sink/docs/mel.mel create mode 100644 node_modules/ace/demo/kitchen-sink/docs/mushcode.mc create mode 100644 node_modules/ace/demo/kitchen-sink/docs/mysql.mysql create mode 100644 node_modules/ace/demo/kitchen-sink/docs/objectivec.m create mode 100644 node_modules/ace/demo/kitchen-sink/docs/ocaml.ml create mode 100644 node_modules/ace/demo/kitchen-sink/docs/pascal.pas create mode 100644 node_modules/ace/demo/kitchen-sink/docs/perl.pl create mode 100644 node_modules/ace/demo/kitchen-sink/docs/pgsql.pgsql create mode 100644 node_modules/ace/demo/kitchen-sink/docs/php.php create mode 100644 node_modules/ace/demo/kitchen-sink/docs/plaintext.txt create mode 100644 node_modules/ace/demo/kitchen-sink/docs/powershell.ps1 create mode 100644 node_modules/ace/demo/kitchen-sink/docs/praat.praat create mode 100644 node_modules/ace/demo/kitchen-sink/docs/prolog.plg create mode 100644 node_modules/ace/demo/kitchen-sink/docs/properties.properties create mode 100644 node_modules/ace/demo/kitchen-sink/docs/protobuf.proto create mode 100644 node_modules/ace/demo/kitchen-sink/docs/python.py create mode 100644 node_modules/ace/demo/kitchen-sink/docs/r.r create mode 100644 node_modules/ace/demo/kitchen-sink/docs/rdoc.Rd create mode 100644 node_modules/ace/demo/kitchen-sink/docs/rhtml.Rhtml create mode 100644 node_modules/ace/demo/kitchen-sink/docs/ruby.rb create mode 100644 node_modules/ace/demo/kitchen-sink/docs/rust.rs create mode 100644 node_modules/ace/demo/kitchen-sink/docs/sass.sass create mode 100644 node_modules/ace/demo/kitchen-sink/docs/scad.scad create mode 100644 node_modules/ace/demo/kitchen-sink/docs/scala.scala create mode 100644 node_modules/ace/demo/kitchen-sink/docs/scheme.scm create mode 100644 node_modules/ace/demo/kitchen-sink/docs/scss.scss create mode 100755 node_modules/ace/demo/kitchen-sink/docs/sh.sh create mode 100644 node_modules/ace/demo/kitchen-sink/docs/sjs.sjs create mode 100644 node_modules/ace/demo/kitchen-sink/docs/smarty.smarty create mode 100644 node_modules/ace/demo/kitchen-sink/docs/snippets.snippets create mode 100644 node_modules/ace/demo/kitchen-sink/docs/soy_template.soy create mode 100644 node_modules/ace/demo/kitchen-sink/docs/space.space create mode 100644 node_modules/ace/demo/kitchen-sink/docs/sql.sql create mode 100644 node_modules/ace/demo/kitchen-sink/docs/stylus.styl create mode 100644 node_modules/ace/demo/kitchen-sink/docs/svg.svg create mode 100644 node_modules/ace/demo/kitchen-sink/docs/tcl.tcl create mode 100644 node_modules/ace/demo/kitchen-sink/docs/tex.tex create mode 100644 node_modules/ace/demo/kitchen-sink/docs/textile.textile create mode 100644 node_modules/ace/demo/kitchen-sink/docs/toml.toml create mode 100644 node_modules/ace/demo/kitchen-sink/docs/twig.twig create mode 100644 node_modules/ace/demo/kitchen-sink/docs/typescript.ts create mode 100644 node_modules/ace/demo/kitchen-sink/docs/vala.vala create mode 100644 node_modules/ace/demo/kitchen-sink/docs/vbscript.vbs create mode 100644 node_modules/ace/demo/kitchen-sink/docs/velocity.vm create mode 100644 node_modules/ace/demo/kitchen-sink/docs/verilog.v create mode 100644 node_modules/ace/demo/kitchen-sink/docs/vhdl.vhd create mode 100644 node_modules/ace/demo/kitchen-sink/docs/xml.xml create mode 100644 node_modules/ace/demo/kitchen-sink/docs/xquery.xq create mode 100644 node_modules/ace/demo/kitchen-sink/docs/yaml.yaml create mode 100644 node_modules/ace/demo/kitchen-sink/file_drop.js create mode 100644 node_modules/ace/demo/kitchen-sink/icons/Readme.txt create mode 100644 node_modules/ace/demo/kitchen-sink/icons/epl.html create mode 100644 node_modules/ace/demo/kitchen-sink/icons/error_obj.gif create mode 100644 node_modules/ace/demo/kitchen-sink/icons/warning_obj.gif create mode 100644 node_modules/ace/demo/kitchen-sink/inline_editor.js create mode 100644 node_modules/ace/demo/kitchen-sink/layout.js create mode 100644 node_modules/ace/demo/kitchen-sink/logo.png create mode 100644 node_modules/ace/demo/kitchen-sink/require.js create mode 100644 node_modules/ace/demo/kitchen-sink/styles.css create mode 100644 node_modules/ace/demo/kitchen-sink/token_tooltip.js create mode 100644 node_modules/ace/demo/kitchen-sink/util.js create mode 100644 node_modules/ace/demo/modelist.html create mode 100644 node_modules/ace/demo/r.js/build.js create mode 100644 node_modules/ace/demo/r.js/editor.html create mode 100644 node_modules/ace/demo/requirejs+build.html create mode 100644 node_modules/ace/demo/scrollable-page.html create mode 100644 node_modules/ace/demo/settings_menu.html create mode 100644 node_modules/ace/demo/show_own_source.js create mode 100644 node_modules/ace/demo/static-highlighter.html create mode 100644 node_modules/ace/demo/static-highlighter/client.html create mode 100644 node_modules/ace/demo/static-highlighter/server.js create mode 100644 node_modules/ace/demo/statusbar.html create mode 100644 node_modules/ace/doc/Contributor_License_Agreement-v2.pdf create mode 100644 node_modules/ace/doc/Corporate_Contributor_License_Agreement-v2.pdf create mode 100644 node_modules/ace/doc/README.md create mode 100644 node_modules/ace/doc/additionalObjs.json create mode 100644 node_modules/ace/doc/build.js create mode 100644 node_modules/ace/doc/index.md create mode 100644 node_modules/ace/doc/package.json create mode 100644 node_modules/ace/doc/site/images/ac-logo.png create mode 100644 node_modules/ace/doc/site/images/ace-logo.png create mode 100644 node_modules/ace/doc/site/images/ace-tab.png create mode 100644 node_modules/ace/doc/site/images/ace.png create mode 100644 node_modules/ace/doc/site/images/background.png create mode 100644 node_modules/ace/doc/site/images/body_background.png create mode 100644 node_modules/ace/doc/site/images/bottombar.png create mode 100644 node_modules/ace/doc/site/images/cloud9-logo.png create mode 100644 node_modules/ace/doc/site/images/codecademy-logo.png create mode 100644 node_modules/ace/doc/site/images/codiad.png create mode 100644 node_modules/ace/doc/site/images/crunchapp-logo.png create mode 100644 node_modules/ace/doc/site/images/empty-logo.png create mode 100644 node_modules/ace/doc/site/images/favicon.ico create mode 100644 node_modules/ace/doc/site/images/firefox-logo.png create mode 100644 node_modules/ace/doc/site/images/fork_on_github.png create mode 100644 node_modules/ace/doc/site/images/github-logo.png create mode 100644 node_modules/ace/doc/site/images/habitat-logo.svg create mode 100644 node_modules/ace/doc/site/images/header-bg.png create mode 100644 node_modules/ace/doc/site/images/ideone-logo.png create mode 100644 node_modules/ace/doc/site/images/khan-logo.png create mode 100644 node_modules/ace/doc/site/images/logo.png create mode 100644 node_modules/ace/doc/site/images/logo_half.png create mode 100644 node_modules/ace/doc/site/images/modx-logo-4.png create mode 100644 node_modules/ace/doc/site/images/pixie-logo.png create mode 100644 node_modules/ace/doc/site/images/plunker.png create mode 100644 node_modules/ace/doc/site/images/processwire-logo.svg create mode 100644 node_modules/ace/doc/site/images/repl.it-logo.png create mode 100644 node_modules/ace/doc/site/images/rstudio_logo_64.png create mode 100644 node_modules/ace/doc/site/images/sassmeister-logo.png create mode 100644 node_modules/ace/doc/site/images/shiftedit-logo.png create mode 100644 node_modules/ace/doc/site/images/spandexio-logo.png create mode 100644 node_modules/ace/doc/site/images/stypi-logo.png create mode 100644 node_modules/ace/doc/site/images/sx-logo.png create mode 100644 node_modules/ace/doc/site/images/textimage.png create mode 100644 node_modules/ace/doc/site/images/weecod-logo.png create mode 100644 node_modules/ace/doc/site/images/wolf_3d_logo_trans.png create mode 100644 node_modules/ace/doc/site/images/zorba-logo.png create mode 100644 node_modules/ace/doc/site/iphone.css create mode 100644 node_modules/ace/doc/site/js/ga.js create mode 100644 node_modules/ace/doc/site/js/main.js create mode 100644 node_modules/ace/doc/site/style.css create mode 100644 node_modules/ace/doc/template/jade/common_layout.jade create mode 100644 node_modules/ace/doc/template/jade/layout.jade create mode 100644 node_modules/ace/doc/template/jade/lib.jade create mode 100644 node_modules/ace/doc/template/resources/csses/ace_api.css create mode 100644 node_modules/ace/doc/template/resources/font/fontawesome-webfont.eot create mode 100644 node_modules/ace/doc/template/resources/font/fontawesome-webfont.svg create mode 100644 node_modules/ace/doc/template/resources/font/fontawesome-webfont.ttf create mode 100644 node_modules/ace/doc/template/resources/font/fontawesome-webfont.woff create mode 100644 node_modules/ace/doc/template/resources/images/Ace_ERD.png create mode 100644 node_modules/ace/doc/template/resources/images/ace_logo.png create mode 100644 node_modules/ace/doc/template/resources/images/ace_logo_menu.png create mode 100644 node_modules/ace/doc/template/resources/images/c9-log-footer.png create mode 100644 node_modules/ace/doc/template/resources/images/c9-sponsor.png create mode 100644 node_modules/ace/doc/template/resources/images/cloud9-logo.png create mode 100644 node_modules/ace/doc/template/resources/images/content-top.png create mode 100644 node_modules/ace/doc/template/resources/images/content_bg.png create mode 100644 node_modules/ace/doc/template/resources/images/content_top_bg.png create mode 100644 node_modules/ace/doc/template/resources/images/dashed_back.png create mode 100644 node_modules/ace/doc/template/resources/images/footer-bg.png create mode 100644 node_modules/ace/doc/template/resources/images/main_bg.png create mode 100644 node_modules/ace/doc/template/resources/images/member-sprites.png create mode 100644 node_modules/ace/doc/template/resources/images/menu_disc.png create mode 100644 node_modules/ace/doc/template/resources/images/method_bg.png create mode 100644 node_modules/ace/doc/template/resources/images/scrolled-heading-shadow.png create mode 100644 node_modules/ace/doc/template/resources/images/sidebar-top-bg.png create mode 100644 node_modules/ace/doc/template/resources/images/sidebar_border.png create mode 100644 node_modules/ace/doc/template/resources/images/swirl_divider.png create mode 100644 node_modules/ace/doc/template/resources/javascripts/bbq.js create mode 100644 node_modules/ace/doc/template/resources/javascripts/bootstrap.js create mode 100644 node_modules/ace/doc/template/resources/javascripts/clicker.js create mode 100644 node_modules/ace/doc/template/resources/javascripts/disqus-ext.js create mode 100644 node_modules/ace/doc/template/resources/javascripts/jquery-scrollspy.js create mode 100644 node_modules/ace/doc/template/resources/javascripts/jquery.collapse.js create mode 100644 node_modules/ace/doc/template/resources/javascripts/jquery.cookie.js create mode 100644 node_modules/ace/doc/template/resources/javascripts/plugins.js create mode 100644 node_modules/ace/doc/template/resources/javascripts/prettify-extension.js create mode 100644 node_modules/ace/doc/template/resources/javascripts/prettify.js create mode 100644 node_modules/ace/doc/template/resources/javascripts/ux.js create mode 100644 node_modules/ace/experiments/animate_folding.html create mode 100644 node_modules/ace/experiments/basic_animation.html create mode 100644 node_modules/ace/experiments/capture.html create mode 100644 node_modules/ace/experiments/cut_copy.html create mode 100644 node_modules/ace/experiments/triple_click.html create mode 100644 node_modules/ace/experiments/worker.html create mode 100644 node_modules/ace/experiments/worker.js create mode 100644 node_modules/ace/experiments/zenbg.png create mode 100644 node_modules/ace/index.html create mode 100644 node_modules/ace/kitchen-sink.html create mode 100644 node_modules/ace/lib/ace/ace.js create mode 100644 node_modules/ace/lib/ace/anchor.js create mode 100644 node_modules/ace/lib/ace/anchor_test.js create mode 100644 node_modules/ace/lib/ace/apply_delta.js create mode 100644 node_modules/ace/lib/ace/autocomplete.js create mode 100644 node_modules/ace/lib/ace/autocomplete/popup.js create mode 100644 node_modules/ace/lib/ace/autocomplete/text_completer.js create mode 100644 node_modules/ace/lib/ace/autocomplete/util.js create mode 100644 node_modules/ace/lib/ace/background_tokenizer.js create mode 100644 node_modules/ace/lib/ace/background_tokenizer_test.js create mode 100644 node_modules/ace/lib/ace/commands/command_manager.js create mode 100644 node_modules/ace/lib/ace/commands/command_manager_test.js create mode 100644 node_modules/ace/lib/ace/commands/default_commands.js create mode 100644 node_modules/ace/lib/ace/commands/incremental_search_commands.js create mode 100644 node_modules/ace/lib/ace/commands/multi_select_commands.js create mode 100644 node_modules/ace/lib/ace/commands/occur_commands.js create mode 100644 node_modules/ace/lib/ace/config.js create mode 100644 node_modules/ace/lib/ace/config_test.js create mode 100644 node_modules/ace/lib/ace/css/codefolding-fold-button-states.png create mode 100644 node_modules/ace/lib/ace/css/editor.css create mode 100644 node_modules/ace/lib/ace/css/expand-marker.png create mode 100644 node_modules/ace/lib/ace/document.js create mode 100644 node_modules/ace/lib/ace/document_test.js create mode 100644 node_modules/ace/lib/ace/edit_session.js create mode 100644 node_modules/ace/lib/ace/edit_session/bracket_match.js create mode 100644 node_modules/ace/lib/ace/edit_session/fold.js create mode 100644 node_modules/ace/lib/ace/edit_session/fold_line.js create mode 100644 node_modules/ace/lib/ace/edit_session/folding.js create mode 100644 node_modules/ace/lib/ace/edit_session_test.js create mode 100644 node_modules/ace/lib/ace/editor.js create mode 100644 node_modules/ace/lib/ace/editor_change_document_test.js create mode 100644 node_modules/ace/lib/ace/editor_highlight_selected_word_test.js create mode 100644 node_modules/ace/lib/ace/editor_navigation_test.js create mode 100644 node_modules/ace/lib/ace/editor_text_edit_test.js create mode 100644 node_modules/ace/lib/ace/ext/beautify.js create mode 100644 node_modules/ace/lib/ace/ext/beautify/php_rules.js create mode 100644 node_modules/ace/lib/ace/ext/chromevox.js create mode 100644 node_modules/ace/lib/ace/ext/elastic_tabstops_lite.js create mode 100644 node_modules/ace/lib/ace/ext/emmet.js create mode 100644 node_modules/ace/lib/ace/ext/error_marker.js create mode 100644 node_modules/ace/lib/ace/ext/keybinding_menu.js create mode 100644 node_modules/ace/lib/ace/ext/language_tools.js create mode 100644 node_modules/ace/lib/ace/ext/linking.js create mode 100644 node_modules/ace/lib/ace/ext/menu_tools/add_editor_menu_options.js create mode 100644 node_modules/ace/lib/ace/ext/menu_tools/element_generator.js create mode 100644 node_modules/ace/lib/ace/ext/menu_tools/generate_settings_menu.js create mode 100644 node_modules/ace/lib/ace/ext/menu_tools/get_editor_keyboard_shortcuts.js create mode 100644 node_modules/ace/lib/ace/ext/menu_tools/get_set_functions.js create mode 100644 node_modules/ace/lib/ace/ext/menu_tools/overlay_page.js create mode 100644 node_modules/ace/lib/ace/ext/menu_tools/settings_menu.css create mode 100644 node_modules/ace/lib/ace/ext/modelist.js create mode 100644 node_modules/ace/lib/ace/ext/old_ie.js create mode 100644 node_modules/ace/lib/ace/ext/old_ie_test.js create mode 100644 node_modules/ace/lib/ace/ext/searchbox.css create mode 100644 node_modules/ace/lib/ace/ext/searchbox.js create mode 100644 node_modules/ace/lib/ace/ext/settings_menu.js create mode 100644 node_modules/ace/lib/ace/ext/spellcheck.js create mode 100644 node_modules/ace/lib/ace/ext/split.js create mode 100644 node_modules/ace/lib/ace/ext/static.css create mode 100644 node_modules/ace/lib/ace/ext/static_highlight.js create mode 100644 node_modules/ace/lib/ace/ext/static_highlight_test.js create mode 100644 node_modules/ace/lib/ace/ext/statusbar.js create mode 100644 node_modules/ace/lib/ace/ext/textarea.js create mode 100644 node_modules/ace/lib/ace/ext/themelist.js create mode 100644 node_modules/ace/lib/ace/ext/whitespace.js create mode 100644 node_modules/ace/lib/ace/ext/whitespace_test.js create mode 100644 node_modules/ace/lib/ace/incremental_search.js create mode 100644 node_modules/ace/lib/ace/incremental_search_test.js create mode 100644 node_modules/ace/lib/ace/keyboard/emacs.js create mode 100644 node_modules/ace/lib/ace/keyboard/emacs_test.js create mode 100644 node_modules/ace/lib/ace/keyboard/hash_handler.js create mode 100644 node_modules/ace/lib/ace/keyboard/keybinding.js create mode 100644 node_modules/ace/lib/ace/keyboard/keybinding_test.js create mode 100644 node_modules/ace/lib/ace/keyboard/state_handler.js create mode 100644 node_modules/ace/lib/ace/keyboard/sublime.js create mode 100644 node_modules/ace/lib/ace/keyboard/textarea.js create mode 100644 node_modules/ace/lib/ace/keyboard/textinput.js create mode 100644 node_modules/ace/lib/ace/keyboard/vim.js create mode 100644 node_modules/ace/lib/ace/keyboard/vim_test.js create mode 100644 node_modules/ace/lib/ace/layer/cursor.js create mode 100644 node_modules/ace/lib/ace/layer/font_metrics.js create mode 100644 node_modules/ace/lib/ace/layer/gutter.js create mode 100644 node_modules/ace/lib/ace/layer/marker.js create mode 100644 node_modules/ace/lib/ace/layer/text.js create mode 100644 node_modules/ace/lib/ace/layer/text_test.js create mode 100644 node_modules/ace/lib/ace/lib/app_config.js create mode 100644 node_modules/ace/lib/ace/lib/dom.js create mode 100644 node_modules/ace/lib/ace/lib/es5-shim.js create mode 100644 node_modules/ace/lib/ace/lib/event.js create mode 100644 node_modules/ace/lib/ace/lib/event_emitter.js create mode 100644 node_modules/ace/lib/ace/lib/event_emitter_test.js create mode 100644 node_modules/ace/lib/ace/lib/fixoldbrowsers.js create mode 100644 node_modules/ace/lib/ace/lib/keys.js create mode 100644 node_modules/ace/lib/ace/lib/lang.js create mode 100644 node_modules/ace/lib/ace/lib/net.js create mode 100644 node_modules/ace/lib/ace/lib/oop.js create mode 100644 node_modules/ace/lib/ace/lib/regexp.js create mode 100644 node_modules/ace/lib/ace/lib/useragent.js create mode 100644 node_modules/ace/lib/ace/line_widgets.js create mode 100644 node_modules/ace/lib/ace/mode/_test/Readme.md create mode 100644 node_modules/ace/lib/ace/mode/_test/highlight_rules_test.js create mode 100644 node_modules/ace/lib/ace/mode/_test/package.json create mode 100644 node_modules/ace/lib/ace/mode/_test/text_asciidoc.txt create mode 100644 node_modules/ace/lib/ace/mode/_test/text_coffee.txt create mode 100644 node_modules/ace/lib/ace/mode/_test/text_curly.txt create mode 100644 node_modules/ace/lib/ace/mode/_test/text_html.txt create mode 100644 node_modules/ace/lib/ace/mode/_test/text_javascript.txt create mode 100644 node_modules/ace/lib/ace/mode/_test/text_livescript.txt create mode 100644 node_modules/ace/lib/ace/mode/_test/text_lucene.txt create mode 100644 node_modules/ace/lib/ace/mode/_test/text_markdown.txt create mode 100644 node_modules/ace/lib/ace/mode/_test/text_php.txt create mode 100644 node_modules/ace/lib/ace/mode/_test/text_ruby.txt create mode 100644 node_modules/ace/lib/ace/mode/_test/text_xml.txt create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_abap.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_abc.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_actionscript.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_ada.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_asciidoc.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_assembly_x86.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_autohotkey.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_batchfile.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_c9search.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_c_cpp.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_cirru.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_clojure.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_cobol.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_coffee.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_coldfusion.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_csharp.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_css.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_curly.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_d.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_dart.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_diff.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_dot.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_eiffel.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_ejs.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_elixir.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_elm.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_erlang.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_forth.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_ftl.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_gcode.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_gherkin.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_gitignore.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_glsl.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_golang.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_groovy.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_haml.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_handlebars.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_haskell.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_haxe.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_html.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_html_ruby.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_ini.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_io.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_jack.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_jade.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_java.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_javascript.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_json.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_jsoniq.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_jsp.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_jsx.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_julia.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_latex.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_less.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_liquid.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_lisp.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_livescript.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_logiql.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_lsl.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_lua.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_luapage.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_lucene.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_markdown.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_mask.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_matlab.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_mel.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_mushcode.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_mysql.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_nix.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_objectivec.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_ocaml.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_pascal.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_perl.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_pgsql.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_php.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_powershell.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_prolog.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_properties.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_protobuf.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_python.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_r.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_rdoc.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_rhtml.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_ruby.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_rust.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_sass.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_scad.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_scala.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_scheme.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_scss.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_sh.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_sjs.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_smarty.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_snippets.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_soy_template.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_space.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_sql.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_stylus.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_svg.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_tcl.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_tex.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_text.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_textile.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_toml.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_twig.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_typescript.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_vala.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_vbscript.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_velocity.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_verilog.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_vhdl.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_xml.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_xquery.json create mode 100644 node_modules/ace/lib/ace/mode/_test/tokens_yaml.json create mode 100644 node_modules/ace/lib/ace/mode/abap.js create mode 100644 node_modules/ace/lib/ace/mode/abap_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/abc.js create mode 100644 node_modules/ace/lib/ace/mode/abc_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/actionscript.js create mode 100644 node_modules/ace/lib/ace/mode/actionscript_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/ada.js create mode 100644 node_modules/ace/lib/ace/mode/ada_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/apache_conf.js create mode 100644 node_modules/ace/lib/ace/mode/apache_conf_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/applescript.js create mode 100644 node_modules/ace/lib/ace/mode/applescript_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/asciidoc.js create mode 100644 node_modules/ace/lib/ace/mode/asciidoc_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/assembly_x86.js create mode 100644 node_modules/ace/lib/ace/mode/assembly_x86_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/autohotkey.js create mode 100644 node_modules/ace/lib/ace/mode/autohotkey_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/batchfile.js create mode 100644 node_modules/ace/lib/ace/mode/batchfile_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/behaviour.js create mode 100644 node_modules/ace/lib/ace/mode/behaviour/behaviour_test.js create mode 100644 node_modules/ace/lib/ace/mode/behaviour/css.js create mode 100644 node_modules/ace/lib/ace/mode/behaviour/cstyle.js create mode 100644 node_modules/ace/lib/ace/mode/behaviour/html.js create mode 100644 node_modules/ace/lib/ace/mode/behaviour/xml.js create mode 100644 node_modules/ace/lib/ace/mode/behaviour/xquery.js create mode 100644 node_modules/ace/lib/ace/mode/c9search.js create mode 100644 node_modules/ace/lib/ace/mode/c9search_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/c_cpp.js create mode 100644 node_modules/ace/lib/ace/mode/c_cpp_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/cirru.js create mode 100644 node_modules/ace/lib/ace/mode/cirru_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/clojure.js create mode 100644 node_modules/ace/lib/ace/mode/clojure_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/cobol.js create mode 100644 node_modules/ace/lib/ace/mode/cobol_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/coffee.js create mode 100644 node_modules/ace/lib/ace/mode/coffee/coffee-script.js create mode 100644 node_modules/ace/lib/ace/mode/coffee/helpers.js create mode 100644 node_modules/ace/lib/ace/mode/coffee/lexer.js create mode 100644 node_modules/ace/lib/ace/mode/coffee/nodes.js create mode 100644 node_modules/ace/lib/ace/mode/coffee/parser.js create mode 100644 node_modules/ace/lib/ace/mode/coffee/parser_test.js create mode 100644 node_modules/ace/lib/ace/mode/coffee/rewriter.js create mode 100644 node_modules/ace/lib/ace/mode/coffee/scope.js create mode 100644 node_modules/ace/lib/ace/mode/coffee_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/coffee_worker.js create mode 100644 node_modules/ace/lib/ace/mode/coldfusion.js create mode 100644 node_modules/ace/lib/ace/mode/coldfusion_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/coldfusion_test.js create mode 100644 node_modules/ace/lib/ace/mode/csharp.js create mode 100644 node_modules/ace/lib/ace/mode/csharp_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/css.js create mode 100644 node_modules/ace/lib/ace/mode/css/csslint.js create mode 100644 node_modules/ace/lib/ace/mode/css_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/css_test.js create mode 100644 node_modules/ace/lib/ace/mode/css_worker.js create mode 100644 node_modules/ace/lib/ace/mode/css_worker_test.js create mode 100644 node_modules/ace/lib/ace/mode/curly.js create mode 100644 node_modules/ace/lib/ace/mode/curly_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/d.js create mode 100644 node_modules/ace/lib/ace/mode/d_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/dart.js create mode 100644 node_modules/ace/lib/ace/mode/dart_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/diff.js create mode 100644 node_modules/ace/lib/ace/mode/diff_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/django.js create mode 100644 node_modules/ace/lib/ace/mode/doc_comment_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/dockerfile.js create mode 100644 node_modules/ace/lib/ace/mode/dockerfile_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/dot.js create mode 100644 node_modules/ace/lib/ace/mode/dot_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/eiffel.js create mode 100644 node_modules/ace/lib/ace/mode/eiffel_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/ejs.js create mode 100644 node_modules/ace/lib/ace/mode/elixir.js create mode 100644 node_modules/ace/lib/ace/mode/elixir_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/elm.js create mode 100644 node_modules/ace/lib/ace/mode/elm_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/erlang.js create mode 100644 node_modules/ace/lib/ace/mode/erlang_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/folding/asciidoc.js create mode 100644 node_modules/ace/lib/ace/mode/folding/c9search.js create mode 100644 node_modules/ace/lib/ace/mode/folding/coffee.js create mode 100644 node_modules/ace/lib/ace/mode/folding/coffee_test.js create mode 100644 node_modules/ace/lib/ace/mode/folding/csharp.js create mode 100644 node_modules/ace/lib/ace/mode/folding/cstyle.js create mode 100644 node_modules/ace/lib/ace/mode/folding/cstyle_test.js create mode 100644 node_modules/ace/lib/ace/mode/folding/diff.js create mode 100644 node_modules/ace/lib/ace/mode/folding/fold_mode.js create mode 100644 node_modules/ace/lib/ace/mode/folding/html.js create mode 100644 node_modules/ace/lib/ace/mode/folding/html_test.js create mode 100644 node_modules/ace/lib/ace/mode/folding/ini.js create mode 100644 node_modules/ace/lib/ace/mode/folding/latex.js create mode 100644 node_modules/ace/lib/ace/mode/folding/lua.js create mode 100644 node_modules/ace/lib/ace/mode/folding/markdown.js create mode 100644 node_modules/ace/lib/ace/mode/folding/mixed.js create mode 100644 node_modules/ace/lib/ace/mode/folding/pythonic.js create mode 100644 node_modules/ace/lib/ace/mode/folding/pythonic_test.js create mode 100644 node_modules/ace/lib/ace/mode/folding/velocity.js create mode 100644 node_modules/ace/lib/ace/mode/folding/xml.js create mode 100644 node_modules/ace/lib/ace/mode/folding/xml_test.js create mode 100644 node_modules/ace/lib/ace/mode/forth.js create mode 100644 node_modules/ace/lib/ace/mode/forth_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/ftl.js create mode 100644 node_modules/ace/lib/ace/mode/ftl_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/gcode.js create mode 100644 node_modules/ace/lib/ace/mode/gcode_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/gherkin.js create mode 100644 node_modules/ace/lib/ace/mode/gherkin_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/gitignore.js create mode 100644 node_modules/ace/lib/ace/mode/gitignore_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/glsl.js create mode 100644 node_modules/ace/lib/ace/mode/glsl_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/golang.js create mode 100644 node_modules/ace/lib/ace/mode/golang_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/groovy.js create mode 100644 node_modules/ace/lib/ace/mode/groovy_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/haml.js create mode 100644 node_modules/ace/lib/ace/mode/haml_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/handlebars.js create mode 100644 node_modules/ace/lib/ace/mode/handlebars_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/haskell.js create mode 100644 node_modules/ace/lib/ace/mode/haskell_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/haxe.js create mode 100644 node_modules/ace/lib/ace/mode/haxe_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/html.js create mode 100644 node_modules/ace/lib/ace/mode/html/saxparser.js create mode 100644 node_modules/ace/lib/ace/mode/html_completions.js create mode 100644 node_modules/ace/lib/ace/mode/html_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/html_ruby.js create mode 100644 node_modules/ace/lib/ace/mode/html_ruby_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/html_test.js create mode 100644 node_modules/ace/lib/ace/mode/html_worker.js create mode 100644 node_modules/ace/lib/ace/mode/ini.js create mode 100644 node_modules/ace/lib/ace/mode/ini_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/io.js create mode 100644 node_modules/ace/lib/ace/mode/io_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/jack.js create mode 100644 node_modules/ace/lib/ace/mode/jack_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/jade.js create mode 100644 node_modules/ace/lib/ace/mode/jade_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/java.js create mode 100644 node_modules/ace/lib/ace/mode/java_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/javascript.js create mode 100644 node_modules/ace/lib/ace/mode/javascript/jshint.js create mode 100644 node_modules/ace/lib/ace/mode/javascript_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/javascript_test.js create mode 100644 node_modules/ace/lib/ace/mode/javascript_worker.js create mode 100644 node_modules/ace/lib/ace/mode/javascript_worker_test.js create mode 100644 node_modules/ace/lib/ace/mode/js_regex_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/json.js create mode 100644 node_modules/ace/lib/ace/mode/json/json_parse.js create mode 100644 node_modules/ace/lib/ace/mode/json_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/json_worker.js create mode 100644 node_modules/ace/lib/ace/mode/json_worker_test.js create mode 100644 node_modules/ace/lib/ace/mode/jsoniq.js create mode 100644 node_modules/ace/lib/ace/mode/jsp.js create mode 100644 node_modules/ace/lib/ace/mode/jsp_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/jsx.js create mode 100644 node_modules/ace/lib/ace/mode/jsx_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/julia.js create mode 100644 node_modules/ace/lib/ace/mode/julia_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/latex.js create mode 100644 node_modules/ace/lib/ace/mode/latex_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/less.js create mode 100644 node_modules/ace/lib/ace/mode/less_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/liquid.js create mode 100644 node_modules/ace/lib/ace/mode/liquid_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/lisp.js create mode 100644 node_modules/ace/lib/ace/mode/lisp_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/livescript.js create mode 100644 node_modules/ace/lib/ace/mode/logiql.js create mode 100644 node_modules/ace/lib/ace/mode/logiql_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/logiql_test.js create mode 100644 node_modules/ace/lib/ace/mode/lsl.js create mode 100644 node_modules/ace/lib/ace/mode/lsl_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/lua.js create mode 100644 node_modules/ace/lib/ace/mode/lua/luaparse.js create mode 100644 node_modules/ace/lib/ace/mode/lua_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/lua_worker.js create mode 100644 node_modules/ace/lib/ace/mode/luapage.js create mode 100644 node_modules/ace/lib/ace/mode/luapage_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/lucene.js create mode 100644 node_modules/ace/lib/ace/mode/lucene_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/makefile.js create mode 100644 node_modules/ace/lib/ace/mode/makefile_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/markdown.js create mode 100644 node_modules/ace/lib/ace/mode/markdown_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/mask.js create mode 100644 node_modules/ace/lib/ace/mode/mask_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/matching_brace_outdent.js create mode 100644 node_modules/ace/lib/ace/mode/matching_parens_outdent.js create mode 100644 node_modules/ace/lib/ace/mode/matlab.js create mode 100644 node_modules/ace/lib/ace/mode/matlab_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/mel.js create mode 100644 node_modules/ace/lib/ace/mode/mel_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/mushcode.js create mode 100644 node_modules/ace/lib/ace/mode/mushcode_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/mysql.js create mode 100644 node_modules/ace/lib/ace/mode/mysql_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/nix.js create mode 100644 node_modules/ace/lib/ace/mode/nix_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/objectivec.js create mode 100644 node_modules/ace/lib/ace/mode/objectivec_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/ocaml.js create mode 100644 node_modules/ace/lib/ace/mode/ocaml_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/pascal.js create mode 100644 node_modules/ace/lib/ace/mode/pascal_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/perl.js create mode 100644 node_modules/ace/lib/ace/mode/perl_highlight_rules.js create mode 100755 node_modules/ace/lib/ace/mode/pgsql.js create mode 100755 node_modules/ace/lib/ace/mode/pgsql_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/php.js create mode 100644 node_modules/ace/lib/ace/mode/php/php.js create mode 100644 node_modules/ace/lib/ace/mode/php_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/php_test.js create mode 100644 node_modules/ace/lib/ace/mode/php_worker.js create mode 100644 node_modules/ace/lib/ace/mode/plain_text.js create mode 100644 node_modules/ace/lib/ace/mode/plain_text_test.js create mode 100644 node_modules/ace/lib/ace/mode/powershell.js create mode 100644 node_modules/ace/lib/ace/mode/powershell_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/praat.js create mode 100644 node_modules/ace/lib/ace/mode/praat_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/prolog.js create mode 100644 node_modules/ace/lib/ace/mode/prolog_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/properties.js create mode 100644 node_modules/ace/lib/ace/mode/properties_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/protobuf.js create mode 100644 node_modules/ace/lib/ace/mode/protobuf_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/python.js create mode 100644 node_modules/ace/lib/ace/mode/python_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/python_test.js create mode 100644 node_modules/ace/lib/ace/mode/r.js create mode 100644 node_modules/ace/lib/ace/mode/r_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/rdoc.js create mode 100644 node_modules/ace/lib/ace/mode/rdoc_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/rhtml.js create mode 100644 node_modules/ace/lib/ace/mode/rhtml_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/ruby.js create mode 100644 node_modules/ace/lib/ace/mode/ruby_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/ruby_test.js create mode 100644 node_modules/ace/lib/ace/mode/rust.js create mode 100644 node_modules/ace/lib/ace/mode/rust_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/sass.js create mode 100644 node_modules/ace/lib/ace/mode/sass_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/scad.js create mode 100644 node_modules/ace/lib/ace/mode/scad_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/scala.js create mode 100644 node_modules/ace/lib/ace/mode/scala_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/scheme.js create mode 100644 node_modules/ace/lib/ace/mode/scheme_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/scss.js create mode 100644 node_modules/ace/lib/ace/mode/scss_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/sh.js create mode 100644 node_modules/ace/lib/ace/mode/sh_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/sjs.js create mode 100644 node_modules/ace/lib/ace/mode/sjs_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/smarty.js create mode 100644 node_modules/ace/lib/ace/mode/smarty_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/snippets.js create mode 100644 node_modules/ace/lib/ace/mode/soy_template.js create mode 100644 node_modules/ace/lib/ace/mode/soy_template_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/space.js create mode 100644 node_modules/ace/lib/ace/mode/space_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/sql.js create mode 100644 node_modules/ace/lib/ace/mode/sql_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/stylus.js create mode 100644 node_modules/ace/lib/ace/mode/stylus_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/svg.js create mode 100644 node_modules/ace/lib/ace/mode/svg_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/tcl.js create mode 100644 node_modules/ace/lib/ace/mode/tcl_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/tex.js create mode 100644 node_modules/ace/lib/ace/mode/tex_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/text.js create mode 100644 node_modules/ace/lib/ace/mode/text_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/text_test.js create mode 100644 node_modules/ace/lib/ace/mode/textile.js create mode 100644 node_modules/ace/lib/ace/mode/textile_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/toml.js create mode 100644 node_modules/ace/lib/ace/mode/toml_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/twig.js create mode 100644 node_modules/ace/lib/ace/mode/twig_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/typescript.js create mode 100644 node_modules/ace/lib/ace/mode/typescript_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/vala.js create mode 100644 node_modules/ace/lib/ace/mode/vala_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/vbscript.js create mode 100644 node_modules/ace/lib/ace/mode/vbscript_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/velocity.js create mode 100644 node_modules/ace/lib/ace/mode/velocity_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/verilog.js create mode 100644 node_modules/ace/lib/ace/mode/verilog_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/vhdl.js create mode 100644 node_modules/ace/lib/ace/mode/vhdl_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/xml.js create mode 100644 node_modules/ace/lib/ace/mode/xml/dom-parser.js create mode 100644 node_modules/ace/lib/ace/mode/xml/dom.js create mode 100644 node_modules/ace/lib/ace/mode/xml/sax.js create mode 100644 node_modules/ace/lib/ace/mode/xml_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/mode/xml_test.js create mode 100644 node_modules/ace/lib/ace/mode/xml_worker.js create mode 100644 node_modules/ace/lib/ace/mode/xquery.js create mode 100644 node_modules/ace/lib/ace/mode/xquery/Readme.md create mode 100644 node_modules/ace/lib/ace/mode/xquery/jsoniq_lexer.js create mode 100644 node_modules/ace/lib/ace/mode/xquery/xqlint.js create mode 100644 node_modules/ace/lib/ace/mode/xquery/xquery_lexer.js create mode 100644 node_modules/ace/lib/ace/mode/xquery_worker.js create mode 100644 node_modules/ace/lib/ace/mode/yaml.js create mode 100644 node_modules/ace/lib/ace/mode/yaml_highlight_rules.js create mode 100644 node_modules/ace/lib/ace/model/editor.js create mode 100644 node_modules/ace/lib/ace/mouse/default_gutter_handler.js create mode 100644 node_modules/ace/lib/ace/mouse/default_handlers.js create mode 100644 node_modules/ace/lib/ace/mouse/dragdrop_handler.js create mode 100644 node_modules/ace/lib/ace/mouse/fold_handler.js create mode 100644 node_modules/ace/lib/ace/mouse/mouse_event.js create mode 100644 node_modules/ace/lib/ace/mouse/mouse_handler.js create mode 100644 node_modules/ace/lib/ace/mouse/mouse_handler_test.js create mode 100644 node_modules/ace/lib/ace/mouse/multi_select_handler.js create mode 100644 node_modules/ace/lib/ace/multi_select.js create mode 100644 node_modules/ace/lib/ace/multi_select_test.js create mode 100644 node_modules/ace/lib/ace/occur.js create mode 100644 node_modules/ace/lib/ace/occur_test.js create mode 100644 node_modules/ace/lib/ace/placeholder.js create mode 100644 node_modules/ace/lib/ace/placeholder_test.js create mode 100644 node_modules/ace/lib/ace/range.js create mode 100644 node_modules/ace/lib/ace/range_list.js create mode 100644 node_modules/ace/lib/ace/range_list_test.js create mode 100644 node_modules/ace/lib/ace/range_test.js create mode 100644 node_modules/ace/lib/ace/renderloop.js create mode 100644 node_modules/ace/lib/ace/requirejs/text.js create mode 100644 node_modules/ace/lib/ace/requirejs/text_build.js create mode 100644 node_modules/ace/lib/ace/scrollbar.js create mode 100644 node_modules/ace/lib/ace/search.js create mode 100644 node_modules/ace/lib/ace/search_highlight.js create mode 100644 node_modules/ace/lib/ace/search_test.js create mode 100644 node_modules/ace/lib/ace/selection.js create mode 100644 node_modules/ace/lib/ace/selection_test.js create mode 100644 node_modules/ace/lib/ace/snippets.js create mode 100644 node_modules/ace/lib/ace/snippets/_.snippets create mode 100644 node_modules/ace/lib/ace/snippets/_all_modes.js create mode 100644 node_modules/ace/lib/ace/snippets/_all_modes.snippets create mode 100644 node_modules/ace/lib/ace/snippets/abap.js create mode 100644 node_modules/ace/lib/ace/snippets/abap.snippets create mode 100644 node_modules/ace/lib/ace/snippets/abc.js create mode 100644 node_modules/ace/lib/ace/snippets/abc.snippets create mode 100644 node_modules/ace/lib/ace/snippets/actionscript.js create mode 100644 node_modules/ace/lib/ace/snippets/actionscript.snippets create mode 100644 node_modules/ace/lib/ace/snippets/ada.js create mode 100644 node_modules/ace/lib/ace/snippets/ada.snippets create mode 100644 node_modules/ace/lib/ace/snippets/all_modes.js create mode 100644 node_modules/ace/lib/ace/snippets/all_modes.snippets create mode 100644 node_modules/ace/lib/ace/snippets/apache.snippets create mode 100644 node_modules/ace/lib/ace/snippets/apache_conf.js create mode 100644 node_modules/ace/lib/ace/snippets/apache_conf.snippets create mode 100644 node_modules/ace/lib/ace/snippets/applescript.js create mode 100644 node_modules/ace/lib/ace/snippets/applescript.snippets create mode 100644 node_modules/ace/lib/ace/snippets/asciidoc.js create mode 100644 node_modules/ace/lib/ace/snippets/asciidoc.snippets create mode 100644 node_modules/ace/lib/ace/snippets/assembly_x86.js create mode 100644 node_modules/ace/lib/ace/snippets/assembly_x86.snippets create mode 100644 node_modules/ace/lib/ace/snippets/autohotkey.js create mode 100644 node_modules/ace/lib/ace/snippets/autohotkey.snippets create mode 100644 node_modules/ace/lib/ace/snippets/autoit.snippets create mode 100644 node_modules/ace/lib/ace/snippets/batchfile.js create mode 100644 node_modules/ace/lib/ace/snippets/batchfile.snippets create mode 100644 node_modules/ace/lib/ace/snippets/c.snippets create mode 100644 node_modules/ace/lib/ace/snippets/c9search.js create mode 100644 node_modules/ace/lib/ace/snippets/c9search.snippets create mode 100644 node_modules/ace/lib/ace/snippets/c_cpp.js create mode 100644 node_modules/ace/lib/ace/snippets/c_cpp.snippets create mode 100644 node_modules/ace/lib/ace/snippets/chef.snippets create mode 100644 node_modules/ace/lib/ace/snippets/cirru.js create mode 100644 node_modules/ace/lib/ace/snippets/cirru.snippets create mode 100644 node_modules/ace/lib/ace/snippets/clojure.js create mode 100644 node_modules/ace/lib/ace/snippets/clojure.snippets create mode 100644 node_modules/ace/lib/ace/snippets/cmake.snippets create mode 100644 node_modules/ace/lib/ace/snippets/cobol.js create mode 100644 node_modules/ace/lib/ace/snippets/cobol.snippets create mode 100644 node_modules/ace/lib/ace/snippets/coffee.js create mode 100644 node_modules/ace/lib/ace/snippets/coffee.snippets create mode 100644 node_modules/ace/lib/ace/snippets/coldfusion.js create mode 100644 node_modules/ace/lib/ace/snippets/coldfusion.snippets create mode 100644 node_modules/ace/lib/ace/snippets/cs.snippets create mode 100644 node_modules/ace/lib/ace/snippets/csharp.js create mode 100644 node_modules/ace/lib/ace/snippets/csharp.snippets create mode 100644 node_modules/ace/lib/ace/snippets/css.js create mode 100644 node_modules/ace/lib/ace/snippets/css.snippets create mode 100644 node_modules/ace/lib/ace/snippets/curly.js create mode 100644 node_modules/ace/lib/ace/snippets/curly.snippets create mode 100644 node_modules/ace/lib/ace/snippets/d.js create mode 100644 node_modules/ace/lib/ace/snippets/d.snippets create mode 100644 node_modules/ace/lib/ace/snippets/dart.js create mode 100644 node_modules/ace/lib/ace/snippets/dart.snippets create mode 100644 node_modules/ace/lib/ace/snippets/diff.js create mode 100644 node_modules/ace/lib/ace/snippets/diff.snippets create mode 100644 node_modules/ace/lib/ace/snippets/django.js create mode 100644 node_modules/ace/lib/ace/snippets/django.snippets create mode 100644 node_modules/ace/lib/ace/snippets/dockerfile.js create mode 100644 node_modules/ace/lib/ace/snippets/dockerfile.snippets create mode 100644 node_modules/ace/lib/ace/snippets/dot.js create mode 100644 node_modules/ace/lib/ace/snippets/dot.snippets create mode 100644 node_modules/ace/lib/ace/snippets/dummy.js create mode 100644 node_modules/ace/lib/ace/snippets/dummy_syntax.js create mode 100644 node_modules/ace/lib/ace/snippets/eiffel.js create mode 100644 node_modules/ace/lib/ace/snippets/eiffel.snippets create mode 100644 node_modules/ace/lib/ace/snippets/ejs.js create mode 100644 node_modules/ace/lib/ace/snippets/ejs.snippets create mode 100644 node_modules/ace/lib/ace/snippets/elixir.js create mode 100644 node_modules/ace/lib/ace/snippets/elixir.snippets create mode 100644 node_modules/ace/lib/ace/snippets/elm.js create mode 100644 node_modules/ace/lib/ace/snippets/elm.snippets create mode 100644 node_modules/ace/lib/ace/snippets/erlang.js create mode 100644 node_modules/ace/lib/ace/snippets/erlang.snippets create mode 100644 node_modules/ace/lib/ace/snippets/eruby.snippets create mode 100644 node_modules/ace/lib/ace/snippets/falcon.snippets create mode 100644 node_modules/ace/lib/ace/snippets/forth.js create mode 100644 node_modules/ace/lib/ace/snippets/forth.snippets create mode 100644 node_modules/ace/lib/ace/snippets/ftl.js create mode 100644 node_modules/ace/lib/ace/snippets/ftl.snippets create mode 100644 node_modules/ace/lib/ace/snippets/gcode.js create mode 100644 node_modules/ace/lib/ace/snippets/gcode.snippets create mode 100644 node_modules/ace/lib/ace/snippets/gherkin.js create mode 100644 node_modules/ace/lib/ace/snippets/gherkin.snippets create mode 100644 node_modules/ace/lib/ace/snippets/gitignore.js create mode 100644 node_modules/ace/lib/ace/snippets/gitignore.snippets create mode 100644 node_modules/ace/lib/ace/snippets/glsl.js create mode 100644 node_modules/ace/lib/ace/snippets/glsl.snippets create mode 100644 node_modules/ace/lib/ace/snippets/go.snippets create mode 100644 node_modules/ace/lib/ace/snippets/golang.js create mode 100644 node_modules/ace/lib/ace/snippets/golang.snippets create mode 100644 node_modules/ace/lib/ace/snippets/groovy.js create mode 100644 node_modules/ace/lib/ace/snippets/groovy.snippets create mode 100644 node_modules/ace/lib/ace/snippets/haml.js create mode 100644 node_modules/ace/lib/ace/snippets/haml.snippets create mode 100644 node_modules/ace/lib/ace/snippets/handlebars.js create mode 100644 node_modules/ace/lib/ace/snippets/handlebars.snippets create mode 100644 node_modules/ace/lib/ace/snippets/haskell.js create mode 100644 node_modules/ace/lib/ace/snippets/haskell.snippets create mode 100644 node_modules/ace/lib/ace/snippets/haxe.js create mode 100644 node_modules/ace/lib/ace/snippets/haxe.snippets create mode 100644 node_modules/ace/lib/ace/snippets/html.js create mode 100644 node_modules/ace/lib/ace/snippets/html.snippets create mode 100644 node_modules/ace/lib/ace/snippets/html_ruby.js create mode 100644 node_modules/ace/lib/ace/snippets/html_ruby.snippets create mode 100644 node_modules/ace/lib/ace/snippets/htmldjango.snippets create mode 100644 node_modules/ace/lib/ace/snippets/htmltornado.snippets create mode 100644 node_modules/ace/lib/ace/snippets/ini.js create mode 100644 node_modules/ace/lib/ace/snippets/ini.snippets create mode 100644 node_modules/ace/lib/ace/snippets/io.js create mode 100644 node_modules/ace/lib/ace/snippets/io.snippets create mode 100644 node_modules/ace/lib/ace/snippets/jack.js create mode 100644 node_modules/ace/lib/ace/snippets/jack.snippets create mode 100644 node_modules/ace/lib/ace/snippets/jade.js create mode 100644 node_modules/ace/lib/ace/snippets/jade.snippets create mode 100644 node_modules/ace/lib/ace/snippets/java.js create mode 100644 node_modules/ace/lib/ace/snippets/java.snippets create mode 100644 node_modules/ace/lib/ace/snippets/javascript-jquery.snippets create mode 100644 node_modules/ace/lib/ace/snippets/javascript.js create mode 100644 node_modules/ace/lib/ace/snippets/javascript.snippets create mode 100644 node_modules/ace/lib/ace/snippets/json.js create mode 100644 node_modules/ace/lib/ace/snippets/json.snippets create mode 100644 node_modules/ace/lib/ace/snippets/jsoniq.js create mode 100644 node_modules/ace/lib/ace/snippets/jsoniq.snippets create mode 100644 node_modules/ace/lib/ace/snippets/jsp.js create mode 100644 node_modules/ace/lib/ace/snippets/jsp.snippets create mode 100644 node_modules/ace/lib/ace/snippets/jsx.js create mode 100644 node_modules/ace/lib/ace/snippets/jsx.snippets create mode 100644 node_modules/ace/lib/ace/snippets/julia.js create mode 100644 node_modules/ace/lib/ace/snippets/julia.snippets create mode 100644 node_modules/ace/lib/ace/snippets/latex.js create mode 100644 node_modules/ace/lib/ace/snippets/latex.snippets create mode 100644 node_modules/ace/lib/ace/snippets/ledger.snippets create mode 100644 node_modules/ace/lib/ace/snippets/less.js create mode 100644 node_modules/ace/lib/ace/snippets/less.snippets create mode 100644 node_modules/ace/lib/ace/snippets/liquid.js create mode 100644 node_modules/ace/lib/ace/snippets/liquid.snippets create mode 100644 node_modules/ace/lib/ace/snippets/lisp.js create mode 100644 node_modules/ace/lib/ace/snippets/lisp.snippets create mode 100644 node_modules/ace/lib/ace/snippets/livescript.js create mode 100644 node_modules/ace/lib/ace/snippets/livescript.snippets create mode 100644 node_modules/ace/lib/ace/snippets/logiql.js create mode 100644 node_modules/ace/lib/ace/snippets/logiql.snippets create mode 100644 node_modules/ace/lib/ace/snippets/lsl.js create mode 100644 node_modules/ace/lib/ace/snippets/lsl.snippets create mode 100644 node_modules/ace/lib/ace/snippets/lua.js create mode 100644 node_modules/ace/lib/ace/snippets/lua.snippets create mode 100644 node_modules/ace/lib/ace/snippets/luapage.js create mode 100644 node_modules/ace/lib/ace/snippets/luapage.snippets create mode 100644 node_modules/ace/lib/ace/snippets/lucene.js create mode 100644 node_modules/ace/lib/ace/snippets/lucene.snippets create mode 100644 node_modules/ace/lib/ace/snippets/makefile.js create mode 100644 node_modules/ace/lib/ace/snippets/makefile.snippets create mode 100644 node_modules/ace/lib/ace/snippets/mako.snippets create mode 100644 node_modules/ace/lib/ace/snippets/markdown.js create mode 100644 node_modules/ace/lib/ace/snippets/markdown.snippets create mode 100644 node_modules/ace/lib/ace/snippets/matlab.js create mode 100644 node_modules/ace/lib/ace/snippets/matlab.snippets create mode 100644 node_modules/ace/lib/ace/snippets/mel.js create mode 100644 node_modules/ace/lib/ace/snippets/mel.snippets create mode 100644 node_modules/ace/lib/ace/snippets/mushcode.js create mode 100644 node_modules/ace/lib/ace/snippets/mushcode.snippets create mode 100644 node_modules/ace/lib/ace/snippets/mushcode_high_rules.js create mode 100644 node_modules/ace/lib/ace/snippets/mushcode_high_rules.snippets create mode 100644 node_modules/ace/lib/ace/snippets/mysql.js create mode 100644 node_modules/ace/lib/ace/snippets/mysql.snippets create mode 100644 node_modules/ace/lib/ace/snippets/nix.js create mode 100644 node_modules/ace/lib/ace/snippets/nix.snippets create mode 100644 node_modules/ace/lib/ace/snippets/objc.snippets create mode 100644 node_modules/ace/lib/ace/snippets/objectivec.js create mode 100644 node_modules/ace/lib/ace/snippets/objectivec.snippets create mode 100644 node_modules/ace/lib/ace/snippets/ocaml.js create mode 100644 node_modules/ace/lib/ace/snippets/ocaml.snippets create mode 100644 node_modules/ace/lib/ace/snippets/pascal.js create mode 100644 node_modules/ace/lib/ace/snippets/pascal.snippets create mode 100644 node_modules/ace/lib/ace/snippets/perl.js create mode 100644 node_modules/ace/lib/ace/snippets/perl.snippets create mode 100644 node_modules/ace/lib/ace/snippets/pgsql.js create mode 100644 node_modules/ace/lib/ace/snippets/pgsql.snippets create mode 100644 node_modules/ace/lib/ace/snippets/php.js create mode 100644 node_modules/ace/lib/ace/snippets/php.snippets create mode 100644 node_modules/ace/lib/ace/snippets/plain_text.js create mode 100644 node_modules/ace/lib/ace/snippets/plain_text.snippets create mode 100644 node_modules/ace/lib/ace/snippets/powershell.js create mode 100644 node_modules/ace/lib/ace/snippets/powershell.snippets create mode 100644 node_modules/ace/lib/ace/snippets/praat.js create mode 100644 node_modules/ace/lib/ace/snippets/praat.snippets create mode 100644 node_modules/ace/lib/ace/snippets/prolog.js create mode 100644 node_modules/ace/lib/ace/snippets/prolog.snippets create mode 100644 node_modules/ace/lib/ace/snippets/properties.js create mode 100644 node_modules/ace/lib/ace/snippets/properties.snippets create mode 100644 node_modules/ace/lib/ace/snippets/protobuf.js create mode 100644 node_modules/ace/lib/ace/snippets/protobuf.snippets create mode 100644 node_modules/ace/lib/ace/snippets/python.js create mode 100644 node_modules/ace/lib/ace/snippets/python.snippets create mode 100644 node_modules/ace/lib/ace/snippets/r.js create mode 100644 node_modules/ace/lib/ace/snippets/r.snippets create mode 100644 node_modules/ace/lib/ace/snippets/rdoc.js create mode 100644 node_modules/ace/lib/ace/snippets/rdoc.snippets create mode 100644 node_modules/ace/lib/ace/snippets/rhtml.js create mode 100644 node_modules/ace/lib/ace/snippets/rhtml.snippets create mode 100644 node_modules/ace/lib/ace/snippets/rst.snippets create mode 100644 node_modules/ace/lib/ace/snippets/ruby.js create mode 100644 node_modules/ace/lib/ace/snippets/ruby.snippets create mode 100644 node_modules/ace/lib/ace/snippets/rust.js create mode 100644 node_modules/ace/lib/ace/snippets/rust.snippets create mode 100644 node_modules/ace/lib/ace/snippets/sass.js create mode 100644 node_modules/ace/lib/ace/snippets/sass.snippets create mode 100644 node_modules/ace/lib/ace/snippets/scad.js create mode 100644 node_modules/ace/lib/ace/snippets/scad.snippets create mode 100644 node_modules/ace/lib/ace/snippets/scala.js create mode 100644 node_modules/ace/lib/ace/snippets/scala.snippets create mode 100644 node_modules/ace/lib/ace/snippets/scheme.js create mode 100644 node_modules/ace/lib/ace/snippets/scheme.snippets create mode 100644 node_modules/ace/lib/ace/snippets/scss.js create mode 100644 node_modules/ace/lib/ace/snippets/scss.snippets create mode 100644 node_modules/ace/lib/ace/snippets/sh.js create mode 100644 node_modules/ace/lib/ace/snippets/sh.snippets create mode 100644 node_modules/ace/lib/ace/snippets/sjs.js create mode 100644 node_modules/ace/lib/ace/snippets/sjs.snippets create mode 100644 node_modules/ace/lib/ace/snippets/smarty.js create mode 100644 node_modules/ace/lib/ace/snippets/smarty.snippets create mode 100644 node_modules/ace/lib/ace/snippets/snippets.js create mode 100644 node_modules/ace/lib/ace/snippets/snippets.snippets create mode 100644 node_modules/ace/lib/ace/snippets/soy_template.js create mode 100644 node_modules/ace/lib/ace/snippets/soy_template.snippets create mode 100644 node_modules/ace/lib/ace/snippets/space.js create mode 100644 node_modules/ace/lib/ace/snippets/space.snippets create mode 100644 node_modules/ace/lib/ace/snippets/sql.js create mode 100644 node_modules/ace/lib/ace/snippets/sql.snippets create mode 100644 node_modules/ace/lib/ace/snippets/stylus.js create mode 100644 node_modules/ace/lib/ace/snippets/stylus.snippets create mode 100644 node_modules/ace/lib/ace/snippets/svg.js create mode 100644 node_modules/ace/lib/ace/snippets/svg.snippets create mode 100644 node_modules/ace/lib/ace/snippets/tcl.js create mode 100644 node_modules/ace/lib/ace/snippets/tcl.snippets create mode 100644 node_modules/ace/lib/ace/snippets/tex.js create mode 100644 node_modules/ace/lib/ace/snippets/tex.snippets create mode 100644 node_modules/ace/lib/ace/snippets/text.js create mode 100644 node_modules/ace/lib/ace/snippets/text.snippets create mode 100644 node_modules/ace/lib/ace/snippets/textile.js create mode 100644 node_modules/ace/lib/ace/snippets/textile.snippets create mode 100644 node_modules/ace/lib/ace/snippets/tmsnippet.snippets create mode 100644 node_modules/ace/lib/ace/snippets/toml.js create mode 100644 node_modules/ace/lib/ace/snippets/toml.snippets create mode 100644 node_modules/ace/lib/ace/snippets/twig.js create mode 100644 node_modules/ace/lib/ace/snippets/twig.snippets create mode 100644 node_modules/ace/lib/ace/snippets/typescript.js create mode 100644 node_modules/ace/lib/ace/snippets/typescript.snippets create mode 100644 node_modules/ace/lib/ace/snippets/vala.js create mode 100644 node_modules/ace/lib/ace/snippets/vala.snippets create mode 100644 node_modules/ace/lib/ace/snippets/vbscript.js create mode 100644 node_modules/ace/lib/ace/snippets/vbscript.snippets create mode 100644 node_modules/ace/lib/ace/snippets/velocity.js create mode 100644 node_modules/ace/lib/ace/snippets/velocity.snippets create mode 100644 node_modules/ace/lib/ace/snippets/verilog.js create mode 100644 node_modules/ace/lib/ace/snippets/verilog.snippets create mode 100644 node_modules/ace/lib/ace/snippets/vhdl.js create mode 100644 node_modules/ace/lib/ace/snippets/vhdl.snippets create mode 100644 node_modules/ace/lib/ace/snippets/xml.js create mode 100644 node_modules/ace/lib/ace/snippets/xml.snippets create mode 100644 node_modules/ace/lib/ace/snippets/xquery.js create mode 100644 node_modules/ace/lib/ace/snippets/xquery.snippets create mode 100644 node_modules/ace/lib/ace/snippets/xslt.snippets create mode 100644 node_modules/ace/lib/ace/snippets/yaml.js create mode 100644 node_modules/ace/lib/ace/snippets/yaml.snippets create mode 100644 node_modules/ace/lib/ace/snippets_test.js create mode 100644 node_modules/ace/lib/ace/split.js create mode 100644 node_modules/ace/lib/ace/test/all.js create mode 100644 node_modules/ace/lib/ace/test/all_browser.js create mode 100644 node_modules/ace/lib/ace/test/assertions.js create mode 100644 node_modules/ace/lib/ace/test/asyncjs/assert.js create mode 100644 node_modules/ace/lib/ace/test/asyncjs/async.js create mode 100644 node_modules/ace/lib/ace/test/asyncjs/index.js create mode 100644 node_modules/ace/lib/ace/test/asyncjs/test.js create mode 100644 node_modules/ace/lib/ace/test/asyncjs/utils.js create mode 100644 node_modules/ace/lib/ace/test/benchmark.js create mode 100644 node_modules/ace/lib/ace/test/mockdom.js create mode 100644 node_modules/ace/lib/ace/test/mockrenderer.js create mode 100644 node_modules/ace/lib/ace/test/tests.html create mode 100644 node_modules/ace/lib/ace/theme/ambiance.css create mode 100644 node_modules/ace/lib/ace/theme/ambiance.js create mode 100644 node_modules/ace/lib/ace/theme/chaos.css create mode 100644 node_modules/ace/lib/ace/theme/chaos.js create mode 100644 node_modules/ace/lib/ace/theme/chrome.css create mode 100644 node_modules/ace/lib/ace/theme/chrome.js create mode 100644 node_modules/ace/lib/ace/theme/cloud9_day.css create mode 100644 node_modules/ace/lib/ace/theme/cloud9_day.js create mode 100644 node_modules/ace/lib/ace/theme/cloud9_night.css create mode 100644 node_modules/ace/lib/ace/theme/cloud9_night.js create mode 100644 node_modules/ace/lib/ace/theme/cloud9_night_low_color.css create mode 100644 node_modules/ace/lib/ace/theme/cloud9_night_low_color.js create mode 100644 node_modules/ace/lib/ace/theme/clouds.css create mode 100644 node_modules/ace/lib/ace/theme/clouds.js create mode 100644 node_modules/ace/lib/ace/theme/clouds_midnight.css create mode 100644 node_modules/ace/lib/ace/theme/clouds_midnight.js create mode 100644 node_modules/ace/lib/ace/theme/cobalt.css create mode 100644 node_modules/ace/lib/ace/theme/cobalt.js create mode 100644 node_modules/ace/lib/ace/theme/crimson_editor.css create mode 100644 node_modules/ace/lib/ace/theme/crimson_editor.js create mode 100644 node_modules/ace/lib/ace/theme/dawn.css create mode 100644 node_modules/ace/lib/ace/theme/dawn.js create mode 100644 node_modules/ace/lib/ace/theme/dreamweaver.css create mode 100644 node_modules/ace/lib/ace/theme/dreamweaver.js create mode 100644 node_modules/ace/lib/ace/theme/eclipse.css create mode 100644 node_modules/ace/lib/ace/theme/eclipse.js create mode 100644 node_modules/ace/lib/ace/theme/github.css create mode 100644 node_modules/ace/lib/ace/theme/github.js create mode 100644 node_modules/ace/lib/ace/theme/idle_fingers.css create mode 100644 node_modules/ace/lib/ace/theme/idle_fingers.js create mode 100644 node_modules/ace/lib/ace/theme/katzenmilch.css create mode 100644 node_modules/ace/lib/ace/theme/katzenmilch.js create mode 100644 node_modules/ace/lib/ace/theme/kr_theme.css create mode 100644 node_modules/ace/lib/ace/theme/kr_theme.js create mode 100644 node_modules/ace/lib/ace/theme/kuroir.css create mode 100644 node_modules/ace/lib/ace/theme/kuroir.js create mode 100644 node_modules/ace/lib/ace/theme/merbivore.css create mode 100644 node_modules/ace/lib/ace/theme/merbivore.js create mode 100644 node_modules/ace/lib/ace/theme/merbivore_soft.css create mode 100644 node_modules/ace/lib/ace/theme/merbivore_soft.js create mode 100644 node_modules/ace/lib/ace/theme/mono_industrial.css create mode 100644 node_modules/ace/lib/ace/theme/mono_industrial.js create mode 100644 node_modules/ace/lib/ace/theme/monokai.css create mode 100644 node_modules/ace/lib/ace/theme/monokai.js create mode 100644 node_modules/ace/lib/ace/theme/pastel_on_dark.css create mode 100644 node_modules/ace/lib/ace/theme/pastel_on_dark.js create mode 100644 node_modules/ace/lib/ace/theme/solarized_dark.css create mode 100644 node_modules/ace/lib/ace/theme/solarized_dark.js create mode 100644 node_modules/ace/lib/ace/theme/solarized_light.css create mode 100644 node_modules/ace/lib/ace/theme/solarized_light.js create mode 100644 node_modules/ace/lib/ace/theme/terminal.css create mode 100644 node_modules/ace/lib/ace/theme/terminal.js create mode 100644 node_modules/ace/lib/ace/theme/textmate.css create mode 100644 node_modules/ace/lib/ace/theme/textmate.js create mode 100644 node_modules/ace/lib/ace/theme/tomorrow.css create mode 100644 node_modules/ace/lib/ace/theme/tomorrow.js create mode 100644 node_modules/ace/lib/ace/theme/tomorrow_night.css create mode 100644 node_modules/ace/lib/ace/theme/tomorrow_night.js create mode 100644 node_modules/ace/lib/ace/theme/tomorrow_night_blue.css create mode 100644 node_modules/ace/lib/ace/theme/tomorrow_night_blue.js create mode 100644 node_modules/ace/lib/ace/theme/tomorrow_night_bright.css create mode 100644 node_modules/ace/lib/ace/theme/tomorrow_night_bright.js create mode 100644 node_modules/ace/lib/ace/theme/tomorrow_night_eighties.css create mode 100644 node_modules/ace/lib/ace/theme/tomorrow_night_eighties.js create mode 100644 node_modules/ace/lib/ace/theme/twilight.css create mode 100644 node_modules/ace/lib/ace/theme/twilight.js create mode 100644 node_modules/ace/lib/ace/theme/vibrant_ink.css create mode 100644 node_modules/ace/lib/ace/theme/vibrant_ink.js create mode 100644 node_modules/ace/lib/ace/theme/xcode.css create mode 100644 node_modules/ace/lib/ace/theme/xcode.js create mode 100644 node_modules/ace/lib/ace/token_iterator.js create mode 100644 node_modules/ace/lib/ace/token_iterator_test.js create mode 100644 node_modules/ace/lib/ace/tokenizer.js create mode 100644 node_modules/ace/lib/ace/tokenizer_dev.js create mode 100644 node_modules/ace/lib/ace/tokenizer_test.js create mode 100644 node_modules/ace/lib/ace/tooltip.js create mode 100644 node_modules/ace/lib/ace/undomanager.js create mode 100644 node_modules/ace/lib/ace/unicode.js create mode 100644 node_modules/ace/lib/ace/virtual_renderer.js create mode 100644 node_modules/ace/lib/ace/virtual_renderer_test.js create mode 100644 node_modules/ace/lib/ace/worker/mirror.js create mode 100644 node_modules/ace/lib/ace/worker/worker.js create mode 100644 node_modules/ace/lib/ace/worker/worker_client.js create mode 100644 node_modules/ace/lib/ace/worker/worker_test.js create mode 100644 node_modules/ace/package.json create mode 100755 node_modules/ace/static.js create mode 100755 node_modules/ace/static.py create mode 100644 node_modules/ace/tool/Readme.md create mode 100644 node_modules/ace/tool/add_mode.js create mode 100644 node_modules/ace/tool/lib.js create mode 100644 node_modules/ace/tool/mode_creator.html create mode 100644 node_modules/ace/tool/mode_creator.js create mode 100644 node_modules/ace/tool/package.json create mode 100644 node_modules/ace/tool/perf-test.html create mode 100644 node_modules/ace/tool/regexp_tokenizer.js create mode 100644 node_modules/ace/tool/regexp_tokenizer_test.js create mode 100644 node_modules/ace/tool/release.sh create mode 100644 node_modules/ace/tool/templates/dummy.JSON-tmLanguage create mode 100644 node_modules/ace/tool/templates/highlight_rules.js create mode 100644 node_modules/ace/tool/templates/mode.js create mode 100644 node_modules/ace/tool/templates/snippets.js create mode 100644 node_modules/ace/tool/templates/theme.css create mode 100644 node_modules/ace/tool/templates/theme.js create mode 100644 node_modules/ace/tool/tmlanguage.js create mode 100644 node_modules/ace/tool/tmsnippets.js create mode 100755 node_modules/ace/tool/tmtheme.js create mode 100644 node_modules/ace/tool/tmthemes/Active4D.tmTheme create mode 100644 node_modules/ace/tool/tmthemes/All Hallows Eve.tmTheme create mode 100644 node_modules/ace/tool/tmthemes/Amy.tmTheme create mode 100644 node_modules/ace/tool/tmthemes/Blackboard.tmTheme create mode 100644 node_modules/ace/tool/tmthemes/Brilliance Black.tmTheme create mode 100644 node_modules/ace/tool/tmthemes/Brilliance Dull.tmTheme create mode 100644 node_modules/ace/tool/tmthemes/Chrome DevTools.tmTheme create mode 100644 node_modules/ace/tool/tmthemes/Clouds Midnight.tmTheme create mode 100644 node_modules/ace/tool/tmthemes/Clouds.tmTheme create mode 100644 node_modules/ace/tool/tmthemes/Cobalt.tmTheme create mode 100644 node_modules/ace/tool/tmthemes/Dawn.tmTheme create mode 100644 node_modules/ace/tool/tmthemes/Dreamweaver.tmTheme create mode 100644 node_modules/ace/tool/tmthemes/Eiffel.tmTheme create mode 100644 node_modules/ace/tool/tmthemes/Espresso Libre.tmTheme create mode 100644 node_modules/ace/tool/tmthemes/GitHub.tmTheme create mode 100644 node_modules/ace/tool/tmthemes/IDLE.tmTheme create mode 100644 node_modules/ace/tool/tmthemes/Katzenmilch.tmTheme create mode 100644 node_modules/ace/tool/tmthemes/Kuroir Theme.tmTheme create mode 100644 node_modules/ace/tool/tmthemes/LAZY.tmTheme create mode 100644 node_modules/ace/tool/tmthemes/LICENSE create mode 100644 node_modules/ace/tool/tmthemes/MagicWB (Amiga).tmTheme create mode 100644 node_modules/ace/tool/tmthemes/Merbivore Soft.tmTheme create mode 100644 node_modules/ace/tool/tmthemes/Merbivore.tmTheme create mode 100644 node_modules/ace/tool/tmthemes/Monokai.tmTheme create mode 100644 node_modules/ace/tool/tmthemes/Pastels on Dark.tmTheme create mode 100644 node_modules/ace/tool/tmthemes/Slush and Poppies.tmTheme create mode 100644 node_modules/ace/tool/tmthemes/Solarized-dark.tmTheme create mode 100644 node_modules/ace/tool/tmthemes/Solarized-light.tmTheme create mode 100644 node_modules/ace/tool/tmthemes/SpaceCadet.tmTheme create mode 100644 node_modules/ace/tool/tmthemes/Sunburst.tmTheme create mode 100644 node_modules/ace/tool/tmthemes/Textmate (Mac Classic).tmTheme create mode 100644 node_modules/ace/tool/tmthemes/Tomorrow-Night-Blue.tmTheme create mode 100644 node_modules/ace/tool/tmthemes/Tomorrow-Night-Bright.tmTheme create mode 100644 node_modules/ace/tool/tmthemes/Tomorrow-Night-Eighties.tmTheme create mode 100644 node_modules/ace/tool/tmthemes/Tomorrow-Night.tmTheme create mode 100644 node_modules/ace/tool/tmthemes/Tomorrow.tmTheme create mode 100644 node_modules/ace/tool/tmthemes/Twilight.tmTheme create mode 100644 node_modules/ace/tool/tmthemes/Vibrant Ink.tmTheme create mode 100644 node_modules/ace/tool/tmthemes/Xcode_default.tmTheme create mode 100644 node_modules/ace/tool/tmthemes/Zenburnesque.tmTheme create mode 100644 node_modules/ace/tool/tmthemes/iPlastic.tmTheme create mode 100644 node_modules/ace/tool/tmthemes/idleFingers.tmTheme create mode 100644 node_modules/ace/tool/tmthemes/krTheme.tmTheme create mode 100644 node_modules/ace/tool/tmthemes/monoindustrial.tmTheme create mode 100644 node_modules/ace/tool/update_deps.js create mode 100644 node_modules/ace/tool/wrap_keyword_regexp.js create mode 100755 node_modules/ace/version.js create mode 100644 node_modules/ace_tree/.gitignore create mode 100644 node_modules/ace_tree/LICENSE create mode 100644 node_modules/ace_tree/demo.html create mode 100644 node_modules/ace_tree/demo/demo.js create mode 100644 node_modules/ace_tree/demo/layout.js create mode 100644 node_modules/ace_tree/demo/styles.css create mode 100644 node_modules/ace_tree/demo/util.js create mode 100644 node_modules/ace_tree/lib/ace_tree/anchor.js create mode 100644 node_modules/ace_tree/lib/ace_tree/commands/default_commands.js create mode 100644 node_modules/ace_tree/lib/ace_tree/config.js create mode 100644 node_modules/ace_tree/lib/ace_tree/config_test.js create mode 100644 node_modules/ace_tree/lib/ace_tree/css/light_theme.css create mode 100644 node_modules/ace_tree/lib/ace_tree/css/light_theme.js create mode 100644 node_modules/ace_tree/lib/ace_tree/css/tree.css create mode 100644 node_modules/ace_tree/lib/ace_tree/css/tree_background.png create mode 100644 node_modules/ace_tree/lib/ace_tree/css/tree_close_arrow_small.png create mode 100644 node_modules/ace_tree/lib/ace_tree/data_provider.js create mode 100644 node_modules/ace_tree/lib/ace_tree/data_provider_mirror.js create mode 100644 node_modules/ace_tree/lib/ace_tree/data_provider_test.js create mode 100644 node_modules/ace_tree/lib/ace_tree/edit.js create mode 100644 node_modules/ace_tree/lib/ace_tree/filter.js create mode 100644 node_modules/ace_tree/lib/ace_tree/layer/cells.js create mode 100644 node_modules/ace_tree/lib/ace_tree/layer/heading.js create mode 100644 node_modules/ace_tree/lib/ace_tree/layer/markers.js create mode 100644 node_modules/ace_tree/lib/ace_tree/lib/btree.js create mode 100644 node_modules/ace_tree/lib/ace_tree/lib/btree_test.js create mode 100644 node_modules/ace_tree/lib/ace_tree/list_data.js create mode 100644 node_modules/ace_tree/lib/ace_tree/mouse/default_handlers.js create mode 100644 node_modules/ace_tree/lib/ace_tree/mouse/drag_handler.js create mode 100644 node_modules/ace_tree/lib/ace_tree/mouse/heading_handler.js create mode 100644 node_modules/ace_tree/lib/ace_tree/mouse/mouse_event.js create mode 100644 node_modules/ace_tree/lib/ace_tree/mouse/mouse_handler.js create mode 100644 node_modules/ace_tree/lib/ace_tree/quicksearch.js create mode 100644 node_modules/ace_tree/lib/ace_tree/scrollable.js create mode 100644 node_modules/ace_tree/lib/ace_tree/selection.js create mode 100644 node_modules/ace_tree/lib/ace_tree/selection_test.js create mode 100644 node_modules/ace_tree/lib/ace_tree/test/setup_paths.js create mode 100644 node_modules/ace_tree/lib/ace_tree/tooltip.js create mode 100644 node_modules/ace_tree/lib/ace_tree/tree.js create mode 100644 node_modules/ace_tree/lib/ace_tree/undomanager.js create mode 100644 node_modules/ace_tree/lib/ace_tree/virtual_renderer.js create mode 100644 node_modules/ace_tree/lib/ace_tree/virtual_renderer_test.js create mode 100644 node_modules/ace_tree/list.txt create mode 100644 node_modules/ace_tree/list_demo.html create mode 100644 node_modules/ace_tree/package.json create mode 100644 node_modules/architect-build/.gitignore create mode 100644 node_modules/architect-build/LICENSE create mode 100644 node_modules/architect-build/README.md create mode 100644 node_modules/architect-build/build.js create mode 100644 node_modules/architect-build/build_support/mini_require.js create mode 100644 node_modules/architect-build/compress.js create mode 100644 node_modules/architect-build/compress_folder.js create mode 100644 node_modules/architect-build/copy.js create mode 100644 node_modules/architect-build/module-deps.js create mode 100644 node_modules/architect-build/npm_build.js create mode 100644 node_modules/architect-build/package.json create mode 100644 node_modules/architect/.gitignore create mode 120000 node_modules/architect/.jamignore create mode 100644 node_modules/architect/.npmignore create mode 100644 node_modules/architect/LICENSE create mode 100644 node_modules/architect/README.markdown create mode 100644 node_modules/architect/architect.js create mode 100644 node_modules/architect/component.json create mode 100644 node_modules/architect/package.json create mode 100644 node_modules/architect/plugins/architect.log/log-service.js create mode 100644 node_modules/architect/plugins/architect.log/package.json create mode 100644 node_modules/c9/assert.js create mode 100644 node_modules/c9/async_tools.js create mode 100755 node_modules/c9/async_tools_test.js create mode 100644 node_modules/c9/atomic.js create mode 100644 node_modules/c9/crypt.js create mode 100644 node_modules/c9/crypt_test.js create mode 100644 node_modules/c9/git.js create mode 100644 node_modules/c9/git_test.js create mode 100644 node_modules/c9/hashing.js create mode 100644 node_modules/c9/hostname.js create mode 100644 node_modules/c9/inline-mocha.js create mode 100644 node_modules/c9/instance_cache.js create mode 100644 node_modules/c9/instance_cache_test.js create mode 100644 node_modules/c9/manifest.js create mode 100644 node_modules/c9/package.json create mode 100644 node_modules/c9/passcrypt.js create mode 100644 node_modules/c9/passcrypt_test.js create mode 100644 node_modules/c9/proxies.js create mode 100644 node_modules/c9/ratelimit.js create mode 100644 node_modules/c9/request_timeout.js create mode 100644 node_modules/c9/rest_client.js create mode 100644 node_modules/c9/ssh.js create mode 100644 node_modules/c9/string.js create mode 100644 node_modules/c9/uid.js create mode 100644 node_modules/connect-architect/.gitignore create mode 100644 node_modules/connect-architect/.npmignore create mode 100644 node_modules/connect-architect/.travis.yml create mode 100644 node_modules/connect-architect/LICENSE create mode 100644 node_modules/connect-architect/README.md create mode 100644 node_modules/connect-architect/connect.basicauth/basicauth-plugin.js create mode 100644 node_modules/connect-architect/connect.basicauth/package.json create mode 100644 node_modules/connect-architect/connect.bodyparser/bodyparser.js create mode 100644 node_modules/connect-architect/connect.bodyparser/package.json create mode 100644 node_modules/connect-architect/connect.cookieparser/cookieparser.js create mode 100644 node_modules/connect-architect/connect.cookieparser/package.json create mode 100644 node_modules/connect-architect/connect.cors/cors.js create mode 100644 node_modules/connect-architect/connect.cors/package.json create mode 100644 node_modules/connect-architect/connect.csp/csp.js create mode 100644 node_modules/connect-architect/connect.csp/package.json create mode 100644 node_modules/connect-architect/connect.csrf/csrf.js create mode 100644 node_modules/connect-architect/connect.csrf/package.json create mode 100644 node_modules/connect-architect/connect.ensure-login/ensure-login.js create mode 100644 node_modules/connect-architect/connect.ensure-login/package.json create mode 100644 node_modules/connect-architect/connect.flash/flash.js create mode 100644 node_modules/connect-architect/connect.flash/package.json create mode 100644 node_modules/connect-architect/connect.logger/logger.js create mode 100644 node_modules/connect-architect/connect.logger/package.json create mode 100644 node_modules/connect-architect/connect.query/package.json create mode 100644 node_modules/connect-architect/connect.query/query.js create mode 100644 node_modules/connect-architect/connect.redirect/package.json create mode 100644 node_modules/connect-architect/connect.redirect/redirect.js create mode 100644 node_modules/connect-architect/connect.remote-address/package.json create mode 100644 node_modules/connect-architect/connect.remote-address/remote-address.js create mode 100644 node_modules/connect-architect/connect.render.ejs/package.json create mode 100644 node_modules/connect-architect/connect.render.ejs/render-ejs.js create mode 100644 node_modules/connect-architect/connect.render/package.json create mode 100644 node_modules/connect-architect/connect.render/render.js create mode 100644 node_modules/connect-architect/connect.session.file/package.json create mode 100644 node_modules/connect-architect/connect.session.file/session-ext.js create mode 100644 node_modules/connect-architect/connect.session.memory/package.json create mode 100644 node_modules/connect-architect/connect.session.memory/session-ext.js create mode 100644 node_modules/connect-architect/connect.session.mongodb/package.json create mode 100644 node_modules/connect-architect/connect.session.mongodb/session-ext.js create mode 100644 node_modules/connect-architect/connect.session.redis/multi-region-store.js create mode 100644 node_modules/connect-architect/connect.session.redis/package.json create mode 100644 node_modules/connect-architect/connect.session.redis/session-ext.js create mode 100644 node_modules/connect-architect/connect.session/package.json create mode 100644 node_modules/connect-architect/connect.session/session-ext.js create mode 100644 node_modules/connect-architect/connect.static/package.json create mode 100644 node_modules/connect-architect/connect.static/static-plugin.js create mode 100644 node_modules/connect-architect/connect/connect-plugin.js create mode 100644 node_modules/connect-architect/connect/middleware/static.js create mode 100644 node_modules/connect-architect/connect/package.json create mode 100644 node_modules/connect-architect/demo/configs/default.js create mode 100644 node_modules/connect-architect/demo/plugin/package.json create mode 100644 node_modules/connect-architect/demo/plugin/plugin.js create mode 100644 node_modules/connect-architect/demo/plugin/www/index.html create mode 100644 node_modules/connect-architect/demo/server.js create mode 100644 node_modules/connect-architect/package.json create mode 100644 node_modules/connect-architect/test/all.js create mode 100644 node_modules/frontdoor/.gitignore create mode 100644 node_modules/frontdoor/.travis.yml create mode 100644 node_modules/frontdoor/LICENSE create mode 100644 node_modules/frontdoor/README.md create mode 100644 node_modules/frontdoor/example/api.js create mode 100644 node_modules/frontdoor/example/express.js create mode 100644 node_modules/frontdoor/example/public/javascripts/todo.js create mode 100644 node_modules/frontdoor/example/public/stylesheets/style.css create mode 100644 node_modules/frontdoor/example/views/index.ejs create mode 100644 node_modules/frontdoor/frontdoor.js create mode 100644 node_modules/frontdoor/lib/api-client.js create mode 100644 node_modules/frontdoor/lib/api-client_test.js create mode 100644 node_modules/frontdoor/lib/api.js create mode 100644 node_modules/frontdoor/lib/api_test.js create mode 100644 node_modules/frontdoor/lib/http_node.js create mode 100644 node_modules/frontdoor/lib/middleware.js create mode 100644 node_modules/frontdoor/lib/route.js create mode 100644 node_modules/frontdoor/lib/route_test.js create mode 100644 node_modules/frontdoor/lib/section.js create mode 100644 node_modules/frontdoor/lib/types.js create mode 100644 node_modules/frontdoor/lib/types_test.js create mode 100644 node_modules/frontdoor/lib/utils.js create mode 100644 node_modules/frontdoor/package.json create mode 100644 node_modules/kaefer/Makefile create mode 100644 node_modules/kaefer/index.js create mode 100644 node_modules/kaefer/lib/client.js create mode 100644 node_modules/kaefer/lib/reconnect_socket.js create mode 100644 node_modules/kaefer/lib/reliable_socket.js create mode 100644 node_modules/kaefer/lib/server.js create mode 100644 node_modules/kaefer/lib/util.js create mode 100644 node_modules/kaefer/lib/version.js create mode 100644 node_modules/kaefer/package.json create mode 100755 node_modules/kaefer/test/integration/chaos_monkey.js create mode 100755 node_modules/kaefer/test/integration/congestion_control_test.js create mode 100755 node_modules/kaefer/test/integration/smith_test.js create mode 100755 node_modules/kaefer/test/reliable_socket_test.js create mode 100644 node_modules/smith/.gitignore create mode 100644 node_modules/smith/.npmignore create mode 100644 node_modules/smith/.travis.yml create mode 100644 node_modules/smith/LICENSE create mode 100644 node_modules/smith/README.markdown create mode 100644 node_modules/smith/component.json create mode 100644 node_modules/smith/package.json create mode 100644 node_modules/smith/protocol.markdown create mode 100644 node_modules/smith/samples/process-child.js create mode 100644 node_modules/smith/samples/process-parent.js create mode 100644 node_modules/smith/samples/process-shared-api.js create mode 100644 node_modules/smith/samples/tcp-client-autoreconnect.js create mode 100644 node_modules/smith/samples/tcp-client.js create mode 100644 node_modules/smith/samples/tcp-server.js create mode 100644 node_modules/smith/smith.js create mode 100755 node_modules/smith/test-all.sh create mode 100644 node_modules/smith/tests/README create mode 100644 node_modules/smith/tests/helpers.js create mode 100644 node_modules/smith/tests/package.json create mode 100755 node_modules/smith/tests/phantom.js create mode 100644 node_modules/smith/tests/public/.gitignore create mode 100644 node_modules/smith/tests/public/index.html create mode 120000 node_modules/smith/tests/public/smith.js create mode 100644 node_modules/smith/tests/public/test.js create mode 100644 node_modules/smith/tests/test-agent.js create mode 100644 node_modules/smith/tests/test-browser.js create mode 100644 node_modules/smith/tests/test-framer.js create mode 100644 node_modules/smith/tests/test-memory-leaks.js create mode 100644 node_modules/smith/tests/test-scrubber.js create mode 100644 node_modules/treehugger/README.md create mode 100644 node_modules/treehugger/lib/demo.js create mode 100644 node_modules/treehugger/lib/jquery.js create mode 100644 node_modules/treehugger/lib/require.js create mode 100644 node_modules/treehugger/lib/setup_paths.js create mode 100644 node_modules/treehugger/lib/treehugger/js/acorn.js create mode 100644 node_modules/treehugger/lib/treehugger/js/acorn_loose.js create mode 100644 node_modules/treehugger/lib/treehugger/js/builtin.json create mode 100644 node_modules/treehugger/lib/treehugger/js/infer.js create mode 100644 node_modules/treehugger/lib/treehugger/js/inferUp.js create mode 100644 node_modules/treehugger/lib/treehugger/js/parse.js create mode 100644 node_modules/treehugger/lib/treehugger/js/parse_test.js create mode 100644 node_modules/treehugger/lib/treehugger/js/types.js create mode 100644 node_modules/treehugger/lib/treehugger/js/uglifyparser.js create mode 100644 node_modules/treehugger/lib/treehugger/js/util/walk.js create mode 100644 node_modules/treehugger/lib/treehugger/js/values.js create mode 100644 node_modules/treehugger/lib/treehugger/rewrite.disabled.js create mode 100644 node_modules/treehugger/lib/treehugger/traverse.js create mode 100644 node_modules/treehugger/lib/treehugger/tree.js create mode 100644 node_modules/treehugger/package.json create mode 100644 node_modules/treehugger/test.html create mode 100644 node_modules/vfs-child/.gitignore create mode 100644 node_modules/vfs-child/LICENSE create mode 100644 node_modules/vfs-child/README.md create mode 100644 node_modules/vfs-child/child.js create mode 120000 node_modules/vfs-child/example/node_modules/vfs-child create mode 100644 node_modules/vfs-child/example/npm-debug.log create mode 100644 node_modules/vfs-child/example/test-child-extend.js create mode 100644 node_modules/vfs-child/example/test-child-streams.js create mode 100644 node_modules/vfs-child/example/vfs-child-example.js create mode 100644 node_modules/vfs-child/package.json create mode 100644 node_modules/vfs-child/parent.js create mode 100644 node_modules/vfs-http-adapter/.gitignore create mode 100644 node_modules/vfs-http-adapter/LICENSE create mode 100644 node_modules/vfs-http-adapter/README.md create mode 100644 node_modules/vfs-http-adapter/multipart.js create mode 100644 node_modules/vfs-http-adapter/package.json create mode 100644 node_modules/vfs-http-adapter/restful.js create mode 100644 node_modules/vfs-http-adapter/test-multipart.js create mode 100644 node_modules/vfs-lint/README.md create mode 100644 node_modules/vfs-lint/lint.js create mode 100644 node_modules/vfs-lint/package.json create mode 100644 node_modules/vfs-local/.gitignore create mode 100644 node_modules/vfs-local/.travis.yml create mode 100644 node_modules/vfs-local/LICENSE create mode 100644 node_modules/vfs-local/README.md create mode 100644 node_modules/vfs-local/localfs.js create mode 100644 node_modules/vfs-local/package.json create mode 100644 node_modules/vfs-local/test/math.js create mode 100644 node_modules/vfs-local/test/mock/dir/smile.png create mode 100644 node_modules/vfs-local/test/mock/dir/stuff.json create mode 120000 node_modules/vfs-local/test/mock/dirLink create mode 100644 node_modules/vfs-local/test/mock/file.txt create mode 120000 node_modules/vfs-local/test/mock/fileLink.txt create mode 100644 node_modules/vfs-local/test/mock/listing.json create mode 120000 node_modules/vfs-local/test/node_modules/vfs-local create mode 100644 node_modules/vfs-local/test/test-local.js create mode 100644 node_modules/vfs-nodefs-adapter/LICENSE create mode 100644 node_modules/vfs-nodefs-adapter/nodefs.js create mode 100644 node_modules/vfs-nodefs-adapter/package.json create mode 100644 node_modules/vfs-socket/.gitignore create mode 100644 node_modules/vfs-socket/.travis.yml create mode 100644 node_modules/vfs-socket/LICENSE create mode 100644 node_modules/vfs-socket/README.md create mode 100644 node_modules/vfs-socket/component.json create mode 100644 node_modules/vfs-socket/consumer.js create mode 100644 node_modules/vfs-socket/package.json create mode 100644 node_modules/vfs-socket/test/math.js create mode 100644 node_modules/vfs-socket/test/mock/dir/smile.png create mode 100644 node_modules/vfs-socket/test/mock/dir/stuff.json create mode 120000 node_modules/vfs-socket/test/mock/dirLink create mode 100644 node_modules/vfs-socket/test/mock/file.txt create mode 120000 node_modules/vfs-socket/test/mock/fileLink.txt create mode 100644 node_modules/vfs-socket/test/mock/listing.json create mode 100644 node_modules/vfs-socket/test/test-socket.js create mode 100644 node_modules/vfs-socket/worker.js create mode 100644 package.json create mode 100644 plugins/c9.cli.bridge/bridge-client.js create mode 100644 plugins/c9.cli.bridge/bridge-service.js create mode 100644 plugins/c9.cli.bridge/bridge.js create mode 100644 plugins/c9.cli.bridge/bridge_commands.js create mode 100644 plugins/c9.cli.bridge/bridge_test.js create mode 100755 plugins/c9.cli.mount/mount.js create mode 100755 plugins/c9.cli.open/open.js create mode 100755 plugins/c9.cli.open/restart.js create mode 100644 plugins/c9.cli.publish/README.md create mode 100644 plugins/c9.cli.publish/publish.git.sh create mode 100644 plugins/c9.cli.publish/publish.js create mode 100755 plugins/c9.cli.publish/publish_test.git.sh create mode 100644 plugins/c9.cli.publish/publish_test.js create mode 100644 plugins/c9.cli.sync/sync-server.js create mode 100755 plugins/c9.cli.sync/sync.js create mode 100644 plugins/c9.cli/auth.bootstrap.js create mode 100755 plugins/c9.cli/cli.js create mode 100644 plugins/c9.connect.favicon/favicon.ico create mode 100644 plugins/c9.connect.favicon/favicon.js create mode 100644 plugins/c9.core/api.js create mode 100644 plugins/c9.core/assert_root.js create mode 100644 plugins/c9.core/c9.js create mode 100644 plugins/c9.core/c9_test.js create mode 100644 plugins/c9.core/client.js create mode 100644 plugins/c9.core/ext.js create mode 100644 plugins/c9.core/ext_test.js create mode 100644 plugins/c9.core/http-node.js create mode 100644 plugins/c9.core/http-xhr.js create mode 100644 plugins/c9.core/http-xhr_test.js create mode 100644 plugins/c9.core/node_defaults.js create mode 100644 plugins/c9.core/settings.js create mode 100644 plugins/c9.core/settings_test.js create mode 100644 plugins/c9.core/util.js create mode 100644 plugins/c9.core/util_test.js create mode 100644 plugins/c9.error/error_handler.js create mode 100644 plugins/c9.error/logger.raygun.js create mode 100644 plugins/c9.error/logger.raygun_mock.js create mode 100644 plugins/c9.error/raygun.connect.js create mode 100644 plugins/c9.error/raygun.js create mode 100644 plugins/c9.error/views/error-401.html.ejs create mode 100644 plugins/c9.error/views/error-404.html.ejs create mode 100644 plugins/c9.error/views/error-500.html.ejs create mode 100644 plugins/c9.error/views/error-503.html.ejs create mode 100644 plugins/c9.error/views/error.html.ejs create mode 100644 plugins/c9.error/www/images/apple.jpg create mode 100644 plugins/c9.error/www/images/bench.jpg create mode 100644 plugins/c9.error/www/images/bookmark.jpg create mode 100644 plugins/c9.error/www/images/bulb.jpg create mode 100644 plugins/c9.error/www/images/c9logo.png create mode 100644 plugins/c9.error/www/images/chamomile.jpg create mode 100644 plugins/c9.error/www/images/dandelions.jpg create mode 100644 plugins/c9.error/www/images/flowersfence.jpg create mode 100644 plugins/c9.error/www/style.css create mode 100644 plugins/c9.example.formatjson/formatjson.js create mode 100644 plugins/c9.fs/fs.cache.xml.js create mode 100644 plugins/c9.fs/fs.cache.xml_test.js create mode 100644 plugins/c9.fs/fs.errors.js create mode 100644 plugins/c9.fs/fs.js create mode 100644 plugins/c9.fs/fs.streams.js create mode 100644 plugins/c9.fs/fs.xhr.js create mode 100644 plugins/c9.fs/fs_test.js create mode 100644 plugins/c9.fs/mock/README.md create mode 100644 plugins/c9.fs/mock/dir/smile.png create mode 100644 plugins/c9.fs/mock/dir/stuff.json create mode 100644 plugins/c9.fs/mock/dir/subfolder/bright.txt create mode 100644 plugins/c9.fs/mock/dir/subfolder/exciting.js create mode 120000 plugins/c9.fs/mock/dirLink create mode 100644 plugins/c9.fs/mock/example.png create mode 100644 plugins/c9.fs/mock/file.js create mode 100644 plugins/c9.fs/mock/file.txt create mode 120000 plugins/c9.fs/mock/fileLink.txt create mode 100644 plugins/c9.fs/mock/language.js create mode 100644 plugins/c9.fs/mock/less.less create mode 100644 plugins/c9.fs/mock/listing.json create mode 100755 plugins/c9.fs/mock/live.js create mode 100644 plugins/c9.fs/mock/plugins/c9.core/ext.js create mode 100644 plugins/c9.fs/mock/plugins/c9.dummy/architect_test.js create mode 100644 plugins/c9.fs/mock/plugins/c9.dummy/dep-define.js create mode 100644 plugins/c9.fs/mock/plugins/c9.dummy/dep.js create mode 120000 plugins/c9.fs/mock/test blah$.js create mode 100644 plugins/c9.fs/mock/test.css create mode 100644 plugins/c9.fs/mock/test.js create mode 100644 plugins/c9.fs/mock/test.js.map create mode 100644 plugins/c9.fs/mock/test.sh create mode 100644 plugins/c9.fs/mock/test.ts create mode 100644 plugins/c9.fs/mock/test.unicode.txt create mode 100644 plugins/c9.fs/mock/test2.js create mode 100644 plugins/c9.fs/mock/test_broken.go create mode 100644 plugins/c9.fs/mock/test_broken.php create mode 100644 plugins/c9.fs/mock/test_broken.rb create mode 100644 plugins/c9.fs/mock/test_broken.sh create mode 100644 plugins/c9.fs/mock/test_es6.js create mode 100644 plugins/c9.fs/mock/very_large_file.js create mode 100644 plugins/c9.fs/net.js create mode 100644 plugins/c9.fs/net_test.js create mode 100644 plugins/c9.fs/proc.apigen.js create mode 100644 plugins/c9.fs/proc.js create mode 100644 plugins/c9.fs/proc_test.js create mode 100644 plugins/c9.ide.ace/ace.js create mode 100644 plugins/c9.ide.ace/ace_test.js create mode 100644 plugins/c9.ide.ace/modes.js create mode 100644 plugins/c9.ide.ace/scrollbar.js create mode 100644 plugins/c9.ide.ace/style.less create mode 100644 plugins/c9.ide.ace/themes.js create mode 100644 plugins/c9.ide.ace/themes.json create mode 100644 plugins/c9.ide.auth/auth.js create mode 100644 plugins/c9.ide.browsersupport/browsersupport.js create mode 100644 plugins/c9.ide.clipboard/clipboard.js create mode 100644 plugins/c9.ide.clipboard/clipboard_test.js create mode 100644 plugins/c9.ide.clipboard/html5.js create mode 100644 plugins/c9.ide.console/console.js create mode 100644 plugins/c9.ide.console/console.xml create mode 100644 plugins/c9.ide.console/console_test.js create mode 100644 plugins/c9.ide.console/style.css create mode 100644 plugins/c9.ide.dialog.common/alert.js create mode 100644 plugins/c9.ide.dialog.common/alert_internal.js create mode 100644 plugins/c9.ide.dialog.common/confirm.js create mode 100644 plugins/c9.ide.dialog.common/error.css create mode 100644 plugins/c9.ide.dialog.common/error.js create mode 100644 plugins/c9.ide.dialog.common/error_test.js create mode 100644 plugins/c9.ide.dialog.common/filechange.js create mode 100644 plugins/c9.ide.dialog.common/fileoverwrite.js create mode 100644 plugins/c9.ide.dialog.common/fileremove.js create mode 100644 plugins/c9.ide.dialog.common/notification.css create mode 100644 plugins/c9.ide.dialog.common/notification.js create mode 100644 plugins/c9.ide.dialog.common/question.js create mode 100644 plugins/c9.ide.dialog.file/filesave.css create mode 100644 plugins/c9.ide.dialog.file/filesave.js create mode 100644 plugins/c9.ide.dialog.file/filesave.xml create mode 100644 plugins/c9.ide.dialog.login/login.css create mode 100644 plugins/c9.ide.dialog.login/login.js create mode 100644 plugins/c9.ide.dialog.login/login.xml create mode 100644 plugins/c9.ide.dialog/dialog.js create mode 100644 plugins/c9.ide.editors/document.js create mode 100644 plugins/c9.ide.editors/document_test.js create mode 100644 plugins/c9.ide.editors/editor.js create mode 100644 plugins/c9.ide.editors/editor_test.js create mode 100644 plugins/c9.ide.editors/editors.js create mode 100644 plugins/c9.ide.editors/editors_test.js create mode 100644 plugins/c9.ide.editors/htmlview.js create mode 100644 plugins/c9.ide.editors/imgview.js create mode 100644 plugins/c9.ide.editors/metadata.js create mode 100644 plugins/c9.ide.editors/metadata_test.js create mode 100644 plugins/c9.ide.editors/pane.js create mode 100644 plugins/c9.ide.editors/tab.js create mode 100644 plugins/c9.ide.editors/tab_test.js create mode 100644 plugins/c9.ide.editors/tabmanager.js create mode 100644 plugins/c9.ide.editors/tabmanager_test.js create mode 100644 plugins/c9.ide.editors/texteditor.js create mode 100644 plugins/c9.ide.editors/timeview.js create mode 100644 plugins/c9.ide.editors/undomanager.js create mode 100644 plugins/c9.ide.editors/undomanager_test.js create mode 100644 plugins/c9.ide.editors/urlview.js create mode 100644 plugins/c9.ide.errorhandler/raygun.js create mode 100644 plugins/c9.ide.errorhandler/raygun_error_handler.js create mode 100644 plugins/c9.ide.errorhandler/simple_error_handler.js create mode 100644 plugins/c9.ide.help/help.js create mode 100644 plugins/c9.ide.help/help.xml create mode 100644 plugins/c9.ide.help/images/about_cloud.png create mode 100644 plugins/c9.ide.help/images/close.png create mode 100644 plugins/c9.ide.help/skin.xml create mode 100644 plugins/c9.ide.help/style.css create mode 100644 plugins/c9.ide.info/info.js create mode 100644 plugins/c9.ide.keys/commands.js create mode 100644 plugins/c9.ide.keys/commands_test.js create mode 100644 plugins/c9.ide.keys/dataprovider.js create mode 100644 plugins/c9.ide.keys/editor.js create mode 100644 plugins/c9.ide.keys/editordp.js create mode 100644 plugins/c9.ide.keys/panel.js create mode 100644 plugins/c9.ide.keys/panel.xml create mode 100644 plugins/c9.ide.keys/style.css create mode 100644 plugins/c9.ide.layout.classic/icons/bug.png create mode 100644 plugins/c9.ide.layout.classic/icons/bug@2x.png create mode 100644 plugins/c9.ide.layout.classic/icons/bug_flat_light.png create mode 100644 plugins/c9.ide.layout.classic/icons/bug_flat_light@2x.png create mode 100755 plugins/c9.ide.layout.classic/icons/cog.png create mode 100644 plugins/c9.ide.layout.classic/icons/conflict_sel.png create mode 100644 plugins/c9.ide.layout.classic/icons/conflict_unsel.png create mode 100755 plugins/c9.ide.layout.classic/icons/console_clear.png create mode 100644 plugins/c9.ide.layout.classic/icons/console_close_btn.png create mode 100644 plugins/c9.ide.layout.classic/icons/console_close_btn@2x.png create mode 100755 plugins/c9.ide.layout.classic/icons/console_close_btn_dark.png create mode 100644 plugins/c9.ide.layout.classic/icons/console_close_btn_dark@2x.png create mode 100755 plugins/c9.ide.layout.classic/icons/console_max.png create mode 100755 plugins/c9.ide.layout.classic/icons/console_settings.png create mode 100755 plugins/c9.ide.layout.classic/icons/css.png create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/brkp_obj.gif create mode 100644 plugins/c9.ide.layout.classic/icons/debugger/brkp_obj.png create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/brkp_obj@2x.gif create mode 100644 plugins/c9.ide.layout.classic/icons/debugger/brkp_obj@2x.png create mode 100644 plugins/c9.ide.layout.classic/icons/debugger/brkp_obj_condition.png create mode 100644 plugins/c9.ide.layout.classic/icons/debugger/brkp_obj_condition@2x.png create mode 100644 plugins/c9.ide.layout.classic/icons/debugger/brkp_obj_condition_disabled.png create mode 100644 plugins/c9.ide.layout.classic/icons/debugger/brkp_obj_condition_disabled@2x.png create mode 100644 plugins/c9.ide.layout.classic/icons/debugger/brkp_obj_current_line.png create mode 100644 plugins/c9.ide.layout.classic/icons/debugger/brkp_obj_current_line@2x.png create mode 100644 plugins/c9.ide.layout.classic/icons/debugger/brkp_obj_current_line_condition.png create mode 100644 plugins/c9.ide.layout.classic/icons/debugger/brkp_obj_current_line_condition@2x.png create mode 100644 plugins/c9.ide.layout.classic/icons/debugger/brkp_obj_current_line_dark.png create mode 100644 plugins/c9.ide.layout.classic/icons/debugger/brkp_obj_current_line_dark@2x.png create mode 100644 plugins/c9.ide.layout.classic/icons/debugger/brkp_obj_dark.png create mode 100644 plugins/c9.ide.layout.classic/icons/debugger/brkp_obj_dark@2x.png create mode 100644 plugins/c9.ide.layout.classic/icons/debugger/brkp_obj_disabled.png create mode 100644 plugins/c9.ide.layout.classic/icons/debugger/brkp_obj_disabled@2x.png create mode 100644 plugins/c9.ide.layout.classic/icons/debugger/brkp_obj_disabled_current_line_dark.png create mode 100644 plugins/c9.ide.layout.classic/icons/debugger/brkp_obj_disabled_current_line_dark@2x.png create mode 100644 plugins/c9.ide.layout.classic/icons/debugger/brkp_obj_disabled_dark.png create mode 100644 plugins/c9.ide.layout.classic/icons/debugger/brkp_obj_disabled_dark@2x.png create mode 100644 plugins/c9.ide.layout.classic/icons/debugger/brkp_obj_warn.png create mode 100644 plugins/c9.ide.layout.classic/icons/debugger/brkp_obj_warn@2x.png create mode 100644 plugins/c9.ide.layout.classic/icons/debugger/brkp_obj_warn_dark.png create mode 100644 plugins/c9.ide.layout.classic/icons/debugger/brkp_obj_warn_dark@2x.png create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/brkpd_obj_disabled.gif create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/brkpd_obj_disabled@2x.gif create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/copy_edit_co.gif create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/copy_edit_co.png create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/copy_edit_co_disabled.gif create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/copy_edit_co_disabled.png create mode 100644 plugins/c9.ide.layout.classic/icons/debugger/current_line copy.png create mode 100644 plugins/c9.ide.layout.classic/icons/debugger/current_line.png create mode 100644 plugins/c9.ide.layout.classic/icons/debugger/current_line_dark.png create mode 100644 plugins/c9.ide.layout.classic/icons/debugger/current_line_dark@2x.png create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/delete_config.gif create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/delete_config.png create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/delete_config_disabled.gif create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/delete_config_disabled.png create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/disconnect_co.png create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/disconnect_co_disabled.png create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/error_obj.gif create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/file_obj.gif create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/genericvariable_obj.gif create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/genericvariable_obj@2x.gif create mode 100644 plugins/c9.ide.layout.classic/icons/debugger/genericvariable_obj_flat_light.png create mode 100644 plugins/c9.ide.layout.classic/icons/debugger/genericvariable_obj_flat_light@2x.png create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/ldebug_obj.png create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/ldebug_obj_disabled.png create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/monitorexpression_tsk.gif create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/monitorexpression_tsk.png create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/monitorexpression_tsk_disabled.gif create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/monitorexpression_tsk_disabled.png create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/resume_co.gif create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/resume_co.png create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/resume_co_disabled.gif create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/resume_co_disabled.png create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/run_tool.png create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/run_tool_disabled.png create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/save_edit.gif create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/save_edit_disabled.gif create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/stack_co.png create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/stack_co@2x.png create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/stckframe_obj.gif create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/stckframe_running_obj.gif create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/stepbystep_co.gif create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/stepbystep_co_disabled.gif create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/stepinto_co.png create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/stepinto_co_disabled.png create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/stepover_co.png create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/stepover_co_disabled.png create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/stepreturn_co.png create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/stepreturn_co_disabled.png create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/suspend_co.png create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/suspend_co_disabled.png create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/terminate_co.png create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/terminate_co_disabled.png create mode 100755 plugins/c9.ide.layout.classic/icons/debugger/warning_obj.gif create mode 100755 plugins/c9.ide.layout.classic/icons/delete_icon.png create mode 100644 plugins/c9.ide.layout.classic/icons/exception_break.png create mode 100644 plugins/c9.ide.layout.classic/icons/exception_break@2x.png create mode 100644 plugins/c9.ide.layout.classic/icons/exception_break_flat_light.png create mode 100644 plugins/c9.ide.layout.classic/icons/exception_break_flat_light@2x.png create mode 100644 plugins/c9.ide.layout.classic/icons/file-tree-load-spinner-dark-unfocus_flat_light.gif create mode 100644 plugins/c9.ide.layout.classic/icons/file-tree-load-spinner-dark-unfocus_flat_light@2x.gif create mode 100644 plugins/c9.ide.layout.classic/icons/file-tree-load-spinner-selected_flat_light.gif create mode 100644 plugins/c9.ide.layout.classic/icons/file-tree-load-spinner-selected_flat_light@2x.gif create mode 100644 plugins/c9.ide.layout.classic/icons/file-tree-load-spinner_flat_light.gif create mode 100644 plugins/c9.ide.layout.classic/icons/file-tree-load-spinner_flat_light@2x.gif create mode 100755 plugins/c9.ide.layout.classic/icons/folder.png create mode 100755 plugins/c9.ide.layout.classic/icons/folder@2x.png create mode 100755 plugins/c9.ide.layout.classic/icons/folder_alternative.png create mode 100755 plugins/c9.ide.layout.classic/icons/folder_alternative@2x.png create mode 100644 plugins/c9.ide.layout.classic/icons/folder_flat_light.png create mode 100644 plugins/c9.ide.layout.classic/icons/folder_flat_light@2x.png create mode 100644 plugins/c9.ide.layout.classic/icons/folder_light.png create mode 100644 plugins/c9.ide.layout.classic/icons/folder_light@2x.png create mode 100755 plugins/c9.ide.layout.classic/icons/folder_new.png create mode 100755 plugins/c9.ide.layout.classic/icons/html.png create mode 100755 plugins/c9.ide.layout.classic/icons/image.png create mode 100644 plugins/c9.ide.layout.classic/icons/info.png create mode 100644 plugins/c9.ide.layout.classic/icons/logiql.png create mode 100644 plugins/c9.ide.layout.classic/icons/min.png create mode 100755 plugins/c9.ide.layout.classic/icons/minus.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_acrobat.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_actionscript.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_add.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_c.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_camera.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_cd.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_code.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_code_red.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_coldfusion.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_compressed.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_copy.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_cplusplus.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_csharp.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_cup.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_database.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_delete.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_dvd.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_edit.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_error.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_excel.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_find.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_flash.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_freehand.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_gear.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_get.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_go.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_h.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_horizontal.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_key.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_lightning.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_link.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_magnify.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_medal.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_office.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_paint.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_paintbrush.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_paste.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_php.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_picture.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_powerpoint.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_put.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_ruby.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_stack.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_star.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_swoosh.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_text.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_text_width.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_tux.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_vector.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_visualstudio.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_width.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_word.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_world.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_wrench.png create mode 100755 plugins/c9.ide.layout.classic/icons/page_white_zip.png create mode 100755 plugins/c9.ide.layout.classic/icons/pause.png create mode 100644 plugins/c9.ide.layout.classic/icons/pause@2x.png create mode 100644 plugins/c9.ide.layout.classic/icons/pause_flat_light.png create mode 100644 plugins/c9.ide.layout.classic/icons/pause_flat_light@2x.png create mode 100755 plugins/c9.ide.layout.classic/icons/play.png create mode 100644 plugins/c9.ide.layout.classic/icons/play@2x.png create mode 100644 plugins/c9.ide.layout.classic/icons/play_flat_light.png create mode 100644 plugins/c9.ide.layout.classic/icons/play_flat_light@2x.png create mode 100644 plugins/c9.ide.layout.classic/icons/plus.png create mode 100644 plugins/c9.ide.layout.classic/icons/plus2.png create mode 100755 plugins/c9.ide.layout.classic/icons/pref-ico.png create mode 100755 plugins/c9.ide.layout.classic/icons/pref-ico@2x.png create mode 100644 plugins/c9.ide.layout.classic/icons/pref-ico_flat_light.png create mode 100644 plugins/c9.ide.layout.classic/icons/pref-ico_flat_light@2x.png create mode 100644 plugins/c9.ide.layout.classic/icons/remove_breakpoints.png create mode 100644 plugins/c9.ide.layout.classic/icons/remove_breakpoints@2x.png create mode 100644 plugins/c9.ide.layout.classic/icons/remove_breakpoints_flat_light.png create mode 100644 plugins/c9.ide.layout.classic/icons/remove_breakpoints_flat_light@2x.png create mode 100644 plugins/c9.ide.layout.classic/icons/restart-icon.png create mode 100644 plugins/c9.ide.layout.classic/icons/restart-icon@2x.png create mode 100644 plugins/c9.ide.layout.classic/icons/restart-icon_flat_light.png create mode 100644 plugins/c9.ide.layout.classic/icons/restart-icon_flat_light@2x.png create mode 100755 plugins/c9.ide.layout.classic/icons/run.png create mode 100644 plugins/c9.ide.layout.classic/icons/run@2x.png create mode 100644 plugins/c9.ide.layout.classic/icons/run_flat_light.png create mode 100644 plugins/c9.ide.layout.classic/icons/run_flat_light@2x.png create mode 100755 plugins/c9.ide.layout.classic/icons/save.png create mode 100755 plugins/c9.ide.layout.classic/icons/script_code.png create mode 100644 plugins/c9.ide.layout.classic/icons/scripts.png create mode 100644 plugins/c9.ide.layout.classic/icons/scripts@2x.png create mode 100644 plugins/c9.ide.layout.classic/icons/scripts_flat_light.png create mode 100644 plugins/c9.ide.layout.classic/icons/scripts_flat_light@2x.png create mode 100644 plugins/c9.ide.layout.classic/icons/search-ico_flat_light.png create mode 100644 plugins/c9.ide.layout.classic/icons/search-ico_flat_light@2x.png create mode 100644 plugins/c9.ide.layout.classic/icons/step.png create mode 100644 plugins/c9.ide.layout.classic/icons/step@2x.png create mode 100644 plugins/c9.ide.layout.classic/icons/step_flat_light.png create mode 100644 plugins/c9.ide.layout.classic/icons/step_flat_light@2x.png create mode 100755 plugins/c9.ide.layout.classic/icons/stepback.png create mode 100644 plugins/c9.ide.layout.classic/icons/stepback@2x.png create mode 100644 plugins/c9.ide.layout.classic/icons/stepback_flat_light.png create mode 100644 plugins/c9.ide.layout.classic/icons/stepback_flat_light@2x.png create mode 100644 plugins/c9.ide.layout.classic/icons/stepinto.png create mode 100644 plugins/c9.ide.layout.classic/icons/stepinto@2x.png create mode 100755 plugins/c9.ide.layout.classic/icons/stepinto_co.gif create mode 100644 plugins/c9.ide.layout.classic/icons/stepinto_flat_light.png create mode 100644 plugins/c9.ide.layout.classic/icons/stepinto_flat_light@2x.png create mode 100755 plugins/c9.ide.layout.classic/icons/stop.png create mode 100644 plugins/c9.ide.layout.classic/icons/stop@2x.png create mode 100644 plugins/c9.ide.layout.classic/icons/stop_flat_light.png create mode 100644 plugins/c9.ide.layout.classic/icons/stop_flat_light@2x.png create mode 100755 plugins/c9.ide.layout.classic/icons/switch.png create mode 100644 plugins/c9.ide.layout.classic/icons/symlink.png create mode 100644 plugins/c9.ide.layout.classic/icons/symlink_dark.png create mode 100644 plugins/c9.ide.layout.classic/icons/synced_sel.png create mode 100644 plugins/c9.ide.layout.classic/icons/synced_unsel.png create mode 100644 plugins/c9.ide.layout.classic/icons/syncing_sel.gif create mode 100644 plugins/c9.ide.layout.classic/icons/syncing_unsel.gif create mode 100644 plugins/c9.ide.layout.classic/icons/terminal_tab_icon.png create mode 100644 plugins/c9.ide.layout.classic/icons/toggle_breakpoints1.png create mode 100644 plugins/c9.ide.layout.classic/icons/toggle_breakpoints1_flat_light.png create mode 100644 plugins/c9.ide.layout.classic/icons/toggle_breakpoints1_flat_light@2x.png create mode 100644 plugins/c9.ide.layout.classic/icons/toggle_breakpoints2.png create mode 100644 plugins/c9.ide.layout.classic/icons/toggle_breakpoints2@2x.png create mode 100644 plugins/c9.ide.layout.classic/icons/toggle_breakpoints2_flat_light.png create mode 100644 plugins/c9.ide.layout.classic/icons/toggle_breakpoints2_flat_light@2x.png create mode 100644 plugins/c9.ide.layout.classic/icons/unsynced_added_sel.png create mode 100644 plugins/c9.ide.layout.classic/icons/unsynced_added_unsel.png create mode 100755 plugins/c9.ide.layout.classic/images/accordion_apf_icon.png create mode 100755 plugins/c9.ide.layout.classic/images/accordion_apf_icon_hor.png create mode 100755 plugins/c9.ide.layout.classic/images/accordion_apf_title.png create mode 100755 plugins/c9.ide.layout.classic/images/accordion_apf_title_hor.png create mode 100755 plugins/c9.ide.layout.classic/images/accordion_header.png create mode 100755 plugins/c9.ide.layout.classic/images/accordion_icon.png create mode 100755 plugins/c9.ide.layout.classic/images/accordion_menu_bg.png create mode 100755 plugins/c9.ide.layout.classic/images/accordion_menu_rounded.png create mode 100755 plugins/c9.ide.layout.classic/images/accordion_menu_rrounded.png create mode 100755 plugins/c9.ide.layout.classic/images/accordion_menu_title.png create mode 100755 plugins/c9.ide.layout.classic/images/accordion_title.png create mode 100755 plugins/c9.ide.layout.classic/images/accordion_title_h.png create mode 100644 plugins/c9.ide.layout.classic/images/ace_error_dark.png create mode 100644 plugins/c9.ide.layout.classic/images/ace_error_dark@2x.png create mode 100644 plugins/c9.ide.layout.classic/images/ace_error_flat_light.png create mode 100644 plugins/c9.ide.layout.classic/images/ace_error_flat_light@2x.png create mode 100644 plugins/c9.ide.layout.classic/images/ace_error_light.png create mode 100644 plugins/c9.ide.layout.classic/images/ace_error_light@2x.png create mode 100644 plugins/c9.ide.layout.classic/images/ace_warning_dark.png create mode 100644 plugins/c9.ide.layout.classic/images/ace_warning_dark@2x.png create mode 100644 plugins/c9.ide.layout.classic/images/ace_warning_flat_light.png create mode 100644 plugins/c9.ide.layout.classic/images/ace_warning_flat_light@2x.png create mode 100644 plugins/c9.ide.layout.classic/images/ace_warning_light.png create mode 100644 plugins/c9.ide.layout.classic/images/ace_warning_light@x.png create mode 100644 plugins/c9.ide.layout.classic/images/ace_warning_light_flat_light.png create mode 100644 plugins/c9.ide.layout.classic/images/ace_warning_light_flat_light@2x.png create mode 100755 plugins/c9.ide.layout.classic/images/ad_next.png create mode 100755 plugins/c9.ide.layout.classic/images/ad_prev.png create mode 100755 plugins/c9.ide.layout.classic/images/alert.png create mode 100755 plugins/c9.ide.layout.classic/images/arrow-sb.png create mode 100755 plugins/c9.ide.layout.classic/images/arrow_down_black.png create mode 100644 plugins/c9.ide.layout.classic/images/arrow_down_grey.png create mode 100644 plugins/c9.ide.layout.classic/images/arrow_down_grey@2x.png create mode 100755 plugins/c9.ide.layout.classic/images/arrow_down_white.png create mode 100755 plugins/c9.ide.layout.classic/images/arrow_right.gif create mode 100755 plugins/c9.ide.layout.classic/images/arrow_right.png create mode 100755 plugins/c9.ide.layout.classic/images/ballon_left.gif create mode 100755 plugins/c9.ide.layout.classic/images/ballon_left.png create mode 100755 plugins/c9.ide.layout.classic/images/ballon_middle.gif create mode 100755 plugins/c9.ide.layout.classic/images/ballon_middle.png create mode 100755 plugins/c9.ide.layout.classic/images/bar11x_left.png create mode 100755 plugins/c9.ide.layout.classic/images/bar11x_right.png create mode 100755 plugins/c9.ide.layout.classic/images/bar16x_left.png create mode 100755 plugins/c9.ide.layout.classic/images/bar16x_right.png create mode 100755 plugins/c9.ide.layout.classic/images/bar_left.png create mode 100755 plugins/c9.ide.layout.classic/images/bar_right.png create mode 100755 plugins/c9.ide.layout.classic/images/bg-overlay.png create mode 100644 plugins/c9.ide.layout.classic/images/bg_counter.png create mode 100755 plugins/c9.ide.layout.classic/images/big_close.png create mode 100755 plugins/c9.ide.layout.classic/images/bk-close-btn.png create mode 100755 plugins/c9.ide.layout.classic/images/bk-close-btn@2x.png create mode 100755 plugins/c9.ide.layout.classic/images/bk-win-footer.png create mode 100755 plugins/c9.ide.layout.classic/images/bk-win-header.png create mode 100755 plugins/c9.ide.layout.classic/images/black-panel_arrow.png create mode 100755 plugins/c9.ide.layout.classic/images/black-tab_btn_bg.png create mode 100755 plugins/c9.ide.layout.classic/images/bold.png create mode 100755 plugins/c9.ide.layout.classic/images/browser_button.png create mode 100755 plugins/c9.ide.layout.classic/images/browsers/chrome_32x32.png create mode 100755 plugins/c9.ide.layout.classic/images/browsers/ff_32x32.png create mode 100755 plugins/c9.ide.layout.classic/images/browsers/ie_32x32.png create mode 100755 plugins/c9.ide.layout.classic/images/browsers/safari_32x32.png create mode 100755 plugins/c9.ide.layout.classic/images/btn-arrow.png create mode 100755 plugins/c9.ide.layout.classic/images/btn-arrow2.png create mode 100755 plugins/c9.ide.layout.classic/images/btn_remove.png create mode 100755 plugins/c9.ide.layout.classic/images/btnclose.gif create mode 100755 plugins/c9.ide.layout.classic/images/btnclose@2x.gif create mode 100644 plugins/c9.ide.layout.classic/images/btnclose_flat_light.png create mode 100644 plugins/c9.ide.layout.classic/images/btnclose_flat_light@2x.png create mode 100755 plugins/c9.ide.layout.classic/images/button_left.png create mode 100755 plugins/c9.ide.layout.classic/images/button_middle.png create mode 100755 plugins/c9.ide.layout.classic/images/button_right.png create mode 100644 plugins/c9.ide.layout.classic/images/c9-find-and-replace.png create mode 100755 plugins/c9.ide.layout.classic/images/c9-menu-backg.png create mode 100755 plugins/c9.ide.layout.classic/images/c9-menu-backg2.png create mode 100755 plugins/c9.ide.layout.classic/images/c9-menu-round.png create mode 100644 plugins/c9.ide.layout.classic/images/c9-no-repeat.png create mode 100644 plugins/c9.ide.layout.classic/images/c9-no-repeat@2x.png create mode 100644 plugins/c9.ide.layout.classic/images/c9-no-repeat_flat_light.png create mode 100644 plugins/c9.ide.layout.classic/images/c9-no-repeat_flat_light@2x.png create mode 100644 plugins/c9.ide.layout.classic/images/c9-noise-light-10.png create mode 100644 plugins/c9.ide.layout.classic/images/c9-noise-with-background.png create mode 100644 plugins/c9.ide.layout.classic/images/c9-noise.png create mode 100644 plugins/c9.ide.layout.classic/images/c9-repeat-x.png create mode 100644 plugins/c9.ide.layout.classic/images/c9-repeat-x@2x.png create mode 100644 plugins/c9.ide.layout.classic/images/c9-repeat-x_flat_light.png create mode 100644 plugins/c9.ide.layout.classic/images/c9-repeat-x_flat_light@2x.png create mode 100755 plugins/c9.ide.layout.classic/images/c9-topbar-btns.png create mode 100755 plugins/c9.ide.layout.classic/images/c9menulogo.png create mode 100644 plugins/c9.ide.layout.classic/images/c9readonly.png create mode 100755 plugins/c9.ide.layout.classic/images/calendar_bg.png create mode 100755 plugins/c9.ide.layout.classic/images/calendar_body.png create mode 100755 plugins/c9.ide.layout.classic/images/calendar_button.png create mode 100755 plugins/c9.ide.layout.classic/images/calendar_left.png create mode 100755 plugins/c9.ide.layout.classic/images/calendar_m_minus.png create mode 100755 plugins/c9.ide.layout.classic/images/calendar_m_plus.png create mode 100755 plugins/c9.ide.layout.classic/images/calendar_y_minus.png create mode 100755 plugins/c9.ide.layout.classic/images/calendar_y_plus.png create mode 100755 plugins/c9.ide.layout.classic/images/cell.gif create mode 100755 plugins/c9.ide.layout.classic/images/change_photo_box.png create mode 100755 plugins/c9.ide.layout.classic/images/change_photo_win_backg.png create mode 100755 plugins/c9.ide.layout.classic/images/chat_history.png create mode 100755 plugins/c9.ide.layout.classic/images/chatlist_toolbar_bg.png create mode 100755 plugins/c9.ide.layout.classic/images/check.gif create mode 100644 plugins/c9.ide.layout.classic/images/check.png create mode 100755 plugins/c9.ide.layout.classic/images/checkbox-blue.png create mode 100755 plugins/c9.ide.layout.classic/images/checkbox.old.png create mode 100755 plugins/c9.ide.layout.classic/images/checkbox.png create mode 100755 plugins/c9.ide.layout.classic/images/checkbox2.png create mode 100755 plugins/c9.ide.layout.classic/images/checkbox3.png create mode 100644 plugins/c9.ide.layout.classic/images/checkbox_black.png create mode 100644 plugins/c9.ide.layout.classic/images/checkbox_black@2x.png create mode 100644 plugins/c9.ide.layout.classic/images/checkbox_black_flat_light.png create mode 100644 plugins/c9.ide.layout.classic/images/checkbox_black_flat_light@2x.png create mode 100644 plugins/c9.ide.layout.classic/images/checkbox_flat_light.png create mode 100644 plugins/c9.ide.layout.classic/images/checkbox_flat_light@2x.png create mode 100644 plugins/c9.ide.layout.classic/images/checkbox_grey.png create mode 100644 plugins/c9.ide.layout.classic/images/clear.png create mode 100644 plugins/c9.ide.layout.classic/images/clear_dark.png create mode 100644 plugins/c9.ide.layout.classic/images/clear_dark_flat_light.png create mode 100644 plugins/c9.ide.layout.classic/images/clear_dark_flat_light@2x.png create mode 100644 plugins/c9.ide.layout.classic/images/clear_light_flat_light.png create mode 100644 plugins/c9.ide.layout.classic/images/clear_light_flat_light@2x.png create mode 100644 plugins/c9.ide.layout.classic/images/cli-block-expand.png create mode 100644 plugins/c9.ide.layout.classic/images/close-btn.png create mode 100644 plugins/c9.ide.layout.classic/images/close-search-icon.png create mode 100755 plugins/c9.ide.layout.classic/images/close.png create mode 100755 plugins/c9.ide.layout.classic/images/close_tab_btn.png create mode 100644 plugins/c9.ide.layout.classic/images/close_tab_btn@2x.png create mode 100644 plugins/c9.ide.layout.classic/images/close_tab_btn_flat_light.png create mode 100644 plugins/c9.ide.layout.classic/images/close_tab_btn_flat_light@2x.png create mode 100755 plugins/c9.ide.layout.classic/images/cloud9logo.png create mode 100755 plugins/c9.ide.layout.classic/images/cloud9logo_transparent.png create mode 100755 plugins/c9.ide.layout.classic/images/colorbox.png create mode 100755 plugins/c9.ide.layout.classic/images/column_picker.gif create mode 100644 plugins/c9.ide.layout.classic/images/console-action-cancel.png create mode 100644 plugins/c9.ide.layout.classic/images/console-expand-contract.png create mode 100755 plugins/c9.ide.layout.classic/images/console-tab-btn-curr.png create mode 100755 plugins/c9.ide.layout.classic/images/console-tab-close-button.png create mode 100755 plugins/c9.ide.layout.classic/images/console_arrow.png create mode 100644 plugins/c9.ide.layout.classic/images/console_spinner_proc.gif create mode 100755 plugins/c9.ide.layout.classic/images/copy.png create mode 100755 plugins/c9.ide.layout.classic/images/cover-heaeder.png create mode 100755 plugins/c9.ide.layout.classic/images/cover-logo.png create mode 100755 plugins/c9.ide.layout.classic/images/cut.png create mode 100755 plugins/c9.ide.layout.classic/images/ddarrow.png create mode 100755 plugins/c9.ide.layout.classic/images/debug-panel_bg.png create mode 100755 plugins/c9.ide.layout.classic/images/debugicons.png create mode 100644 plugins/c9.ide.layout.classic/images/delete_btn.png create mode 100755 plugins/c9.ide.layout.classic/images/deploy.png create mode 100755 plugins/c9.ide.layout.classic/images/dg_noise.png create mode 100755 plugins/c9.ide.layout.classic/images/dockLeftBackground.png create mode 100755 plugins/c9.ide.layout.classic/images/dockPanelButtonDown.png create mode 100755 plugins/c9.ide.layout.classic/images/dockPanelSpeckledBG.png create mode 100755 plugins/c9.ide.layout.classic/images/dock_button_sprite.png create mode 100755 plugins/c9.ide.layout.classic/images/dock_cloud9_bg.gif create mode 100755 plugins/c9.ide.layout.classic/images/dock_notification_bg.png create mode 100755 plugins/c9.ide.layout.classic/images/dot_blue.png create mode 100755 plugins/c9.ide.layout.classic/images/drag-tree-item-backg.png create mode 100755 plugins/c9.ide.layout.classic/images/dragarrows.gif create mode 100644 plugins/c9.ide.layout.classic/images/dropdown-dark-glossy/arrow.png create mode 100644 plugins/c9.ide.layout.classic/images/dropdown-dark-glossy/background.png create mode 100644 plugins/c9.ide.layout.classic/images/dropdown-dark-glossy/button.png create mode 100644 plugins/c9.ide.layout.classic/images/dropdown-dark-glossy/button@2x.png create mode 100644 plugins/c9.ide.layout.classic/images/dropdown-dark-glossy/divider.png create mode 100755 plugins/c9.ide.layout.classic/images/dropdown.old.20081120.png create mode 100755 plugins/c9.ide.layout.classic/images/dropdown.old.big.png create mode 100755 plugins/c9.ide.layout.classic/images/dropdown.old.png create mode 100755 plugins/c9.ide.layout.classic/images/dropdown.png create mode 100755 plugins/c9.ide.layout.classic/images/dropdown_background.png create mode 100755 plugins/c9.ide.layout.classic/images/dropdown_background2.png create mode 100755 plugins/c9.ide.layout.classic/images/dropdown_background_top.png create mode 100755 plugins/c9.ide.layout.classic/images/editor_bar_bg.png create mode 100755 plugins/c9.ide.layout.classic/images/editor_header.png create mode 100755 plugins/c9.ide.layout.classic/images/editor_tab.png create mode 100755 plugins/c9.ide.layout.classic/images/editor_tab_bg.png create mode 100755 plugins/c9.ide.layout.classic/images/editor_tabs_container_bg.gif create mode 100755 plugins/c9.ide.layout.classic/images/empty_editor_divider.png create mode 100755 plugins/c9.ide.layout.classic/images/empty_editor_icon.png create mode 100755 plugins/c9.ide.layout.classic/images/error_box_b.png create mode 100755 plugins/c9.ide.layout.classic/images/error_box_lb.png create mode 100755 plugins/c9.ide.layout.classic/images/error_box_lt.png create mode 100755 plugins/c9.ide.layout.classic/images/error_box_r.png create mode 100755 plugins/c9.ide.layout.classic/images/error_box_rb.png create mode 100755 plugins/c9.ide.layout.classic/images/error_box_rt.png create mode 100755 plugins/c9.ide.layout.classic/images/error_logo.png create mode 100755 plugins/c9.ide.layout.classic/images/errorbox_backg.png create mode 100755 plugins/c9.ide.layout.classic/images/errorbox_bottom.png create mode 100755 plugins/c9.ide.layout.classic/images/errorbox_top.old.png create mode 100755 plugins/c9.ide.layout.classic/images/errorbox_top.png create mode 100755 plugins/c9.ide.layout.classic/images/excel.cur create mode 100644 plugins/c9.ide.layout.classic/images/file-tree-load-spinner-dark-selected.gif create mode 100644 plugins/c9.ide.layout.classic/images/file-tree-load-spinner-dark-selected@2x.gif create mode 100644 plugins/c9.ide.layout.classic/images/file-tree-load-spinner-dark-unfocus.gif create mode 100644 plugins/c9.ide.layout.classic/images/file-tree-load-spinner-dark-unfocus@2x.gif create mode 100644 plugins/c9.ide.layout.classic/images/file-tree-load-spinner-dark-unfocus_flat_light.gif create mode 100644 plugins/c9.ide.layout.classic/images/file-tree-load-spinner-dark-unfocus_flat_light@2x.gif create mode 100644 plugins/c9.ide.layout.classic/images/file-tree-load-spinner-dark.gif create mode 100644 plugins/c9.ide.layout.classic/images/file-tree-load-spinner-dark@2x.gif create mode 100755 plugins/c9.ide.layout.classic/images/file-tree-load-spinner-selected.gif create mode 100755 plugins/c9.ide.layout.classic/images/file-tree-load-spinner-selected@2x.gif create mode 100644 plugins/c9.ide.layout.classic/images/file-tree-load-spinner-selected_flat_light.gif create mode 100644 plugins/c9.ide.layout.classic/images/file-tree-load-spinner-selected_flat_light@2x.gif create mode 100755 plugins/c9.ide.layout.classic/images/file-tree-load-spinner.gif create mode 100755 plugins/c9.ide.layout.classic/images/file-tree-load-spinner@2x.gif create mode 100644 plugins/c9.ide.layout.classic/images/file-tree-load-spinner_flat_light.gif create mode 100644 plugins/c9.ide.layout.classic/images/file-tree-load-spinner_flat_light@2x.gif create mode 100755 plugins/c9.ide.layout.classic/images/file.png create mode 100755 plugins/c9.ide.layout.classic/images/flyout_arrows.png create mode 100644 plugins/c9.ide.layout.classic/images/footer-line.png create mode 100644 plugins/c9.ide.layout.classic/images/gecko_mask.png create mode 100644 plugins/c9.ide.layout.classic/images/gecko_mask_flat_light.png create mode 100644 plugins/c9.ide.layout.classic/images/gecko_mask_flat_light@2x.png create mode 100755 plugins/c9.ide.layout.classic/images/girl.png create mode 100755 plugins/c9.ide.layout.classic/images/git_corner.png create mode 100755 plugins/c9.ide.layout.classic/images/gitui_close_arrow.png create mode 100755 plugins/c9.ide.layout.classic/images/gitui_menu_backg.png create mode 100755 plugins/c9.ide.layout.classic/images/glossy-header.png create mode 100755 plugins/c9.ide.layout.classic/images/glossy_top_header.png create mode 100755 plugins/c9.ide.layout.classic/images/green-arrow-left.png create mode 100755 plugins/c9.ide.layout.classic/images/headerBarBg.png create mode 100755 plugins/c9.ide.layout.classic/images/header_backg.png create mode 100755 plugins/c9.ide.layout.classic/images/header_bg.png create mode 100755 plugins/c9.ide.layout.classic/images/header_right.png create mode 100755 plugins/c9.ide.layout.classic/images/headertbleft.png create mode 100755 plugins/c9.ide.layout.classic/images/headertbrepeat.png create mode 100755 plugins/c9.ide.layout.classic/images/headertbright.png create mode 100755 plugins/c9.ide.layout.classic/images/hp_errorbox_arrow.png create mode 100755 plugins/c9.ide.layout.classic/images/hp_errorbox_backg.png create mode 100755 plugins/c9.ide.layout.classic/images/hp_errorbox_bb.png create mode 100755 plugins/c9.ide.layout.classic/images/hp_errorbox_bl.png create mode 100755 plugins/c9.ide.layout.classic/images/hp_errorbox_bottom.png create mode 100755 plugins/c9.ide.layout.classic/images/hp_errorbox_br.png create mode 100755 plugins/c9.ide.layout.classic/images/hp_errorbox_bt.png create mode 100755 plugins/c9.ide.layout.classic/images/hp_errorbox_cbl.png create mode 100755 plugins/c9.ide.layout.classic/images/hp_errorbox_cbr.png create mode 100755 plugins/c9.ide.layout.classic/images/hp_errorbox_close.png create mode 100755 plugins/c9.ide.layout.classic/images/hp_errorbox_ctl.png create mode 100755 plugins/c9.ide.layout.classic/images/hp_errorbox_ctr.png create mode 100755 plugins/c9.ide.layout.classic/images/hp_errorbox_top.png create mode 100644 plugins/c9.ide.layout.classic/images/ide_loading_bg_pattern.png create mode 100755 plugins/c9.ide.layout.classic/images/input.png create mode 100755 plugins/c9.ide.layout.classic/images/input_background.png create mode 100755 plugins/c9.ide.layout.classic/images/input_border.png create mode 100755 plugins/c9.ide.layout.classic/images/input_border_lr.png create mode 100755 plugins/c9.ide.layout.classic/images/input_border_tb.png create mode 100755 plugins/c9.ide.layout.classic/images/input_error_background.gif create mode 100755 plugins/c9.ide.layout.classic/images/input_error_background2.gif create mode 100755 plugins/c9.ide.layout.classic/images/italic.png create mode 100755 plugins/c9.ide.layout.classic/images/label_hover.png create mode 100755 plugins/c9.ide.layout.classic/images/label_hover_bb.png create mode 100755 plugins/c9.ide.layout.classic/images/label_hover_br.png create mode 100755 plugins/c9.ide.layout.classic/images/label_hover_lb.png create mode 100755 plugins/c9.ide.layout.classic/images/load-indicator-active-tab.gif create mode 100755 plugins/c9.ide.layout.classic/images/load-indicator-inactive-tab.gif create mode 100755 plugins/c9.ide.layout.classic/images/loader-bg.png create mode 100755 plugins/c9.ide.layout.classic/images/loader.gif create mode 100644 plugins/c9.ide.layout.classic/images/loader_logo.png create mode 100644 plugins/c9.ide.layout.classic/images/loader_progressbar_bg.png create mode 100644 plugins/c9.ide.layout.classic/images/loading-ind.png create mode 100644 plugins/c9.ide.layout.classic/images/loading-logo.png create mode 100644 plugins/c9.ide.layout.classic/images/loading-logo@2x.png create mode 100644 plugins/c9.ide.layout.classic/images/local_green.png create mode 100644 plugins/c9.ide.layout.classic/images/logo-viewmode.png create mode 100755 plugins/c9.ide.layout.classic/images/logo.png create mode 100755 plugins/c9.ide.layout.classic/images/logo2.png create mode 100755 plugins/c9.ide.layout.classic/images/main_bg.jpg create mode 100644 plugins/c9.ide.layout.classic/images/maximize.png create mode 100644 plugins/c9.ide.layout.classic/images/maximize@2x.png create mode 100644 plugins/c9.ide.layout.classic/images/maximize_dark.png create mode 100644 plugins/c9.ide.layout.classic/images/maximize_dark@2x.png create mode 100755 plugins/c9.ide.layout.classic/images/mediabtn.png create mode 100755 plugins/c9.ide.layout.classic/images/menu-btn.png create mode 100755 plugins/c9.ide.layout.classic/images/menu_context_left.gif create mode 100755 plugins/c9.ide.layout.classic/images/menu_context_left_over.gif create mode 100755 plugins/c9.ide.layout.classic/images/menu_context_right.gif create mode 100755 plugins/c9.ide.layout.classic/images/menu_context_right_over.gif create mode 100755 plugins/c9.ide.layout.classic/images/menu_context_shadow_b.png create mode 100755 plugins/c9.ide.layout.classic/images/menu_context_shadow_corner.png create mode 100755 plugins/c9.ide.layout.classic/images/menu_context_shadow_lat.png create mode 100755 plugins/c9.ide.layout.classic/images/menu_context_shadow_lt.png create mode 100755 plugins/c9.ide.layout.classic/images/menu_context_shadow_r.png create mode 100755 plugins/c9.ide.layout.classic/images/menu_context_shb.png create mode 100755 plugins/c9.ide.layout.classic/images/menu_context_shl.png create mode 100755 plugins/c9.ide.layout.classic/images/menu_context_shlr.png create mode 100755 plugins/c9.ide.layout.classic/images/menu_context_shr.png create mode 100755 plugins/c9.ide.layout.classic/images/menu_context_shtb.png create mode 100755 plugins/c9.ide.layout.classic/images/menu_down.gif create mode 100755 plugins/c9.ide.layout.classic/images/menu_over.gif create mode 100755 plugins/c9.ide.layout.classic/images/menu_tab_header.png create mode 100755 plugins/c9.ide.layout.classic/images/menu_tab_row.png create mode 100755 plugins/c9.ide.layout.classic/images/menu_win_background.png create mode 100755 plugins/c9.ide.layout.classic/images/menu_win_bottom.png create mode 100755 plugins/c9.ide.layout.classic/images/menu_win_l.png create mode 100755 plugins/c9.ide.layout.classic/images/menu_win_r.png create mode 100755 plugins/c9.ide.layout.classic/images/menubar_row.png create mode 100755 plugins/c9.ide.layout.classic/images/min.png create mode 100644 plugins/c9.ide.layout.classic/images/min_dark.png create mode 100644 plugins/c9.ide.layout.classic/images/modalbg-dark.png create mode 100755 plugins/c9.ide.layout.classic/images/modalbg.png create mode 100755 plugins/c9.ide.layout.classic/images/new_cal.jpg create mode 100755 plugins/c9.ide.layout.classic/images/new_cal_big.jpg create mode 100755 plugins/c9.ide.layout.classic/images/new_cal_hov.jpg create mode 100755 plugins/c9.ide.layout.classic/images/new_cal_hov_big.jpg create mode 100755 plugins/c9.ide.layout.classic/images/new_cal_sel.jpg create mode 100755 plugins/c9.ide.layout.classic/images/new_cal_sel_big.jpg create mode 100644 plugins/c9.ide.layout.classic/images/noconnection.png create mode 100755 plugins/c9.ide.layout.classic/images/noise_pattern_transparent.png create mode 100644 plugins/c9.ide.layout.classic/images/noise_pattern_transparent30.png create mode 100755 plugins/c9.ide.layout.classic/images/offline.png create mode 100755 plugins/c9.ide.layout.classic/images/open_files.png create mode 100755 plugins/c9.ide.layout.classic/images/page_bt.png create mode 100755 plugins/c9.ide.layout.classic/images/panelBg.png create mode 100755 plugins/c9.ide.layout.classic/images/paste.png create mode 100644 plugins/c9.ide.layout.classic/images/pause-icon.png create mode 100755 plugins/c9.ide.layout.classic/images/pause.gif create mode 100644 plugins/c9.ide.layout.classic/images/pause.png create mode 100755 plugins/c9.ide.layout.classic/images/play-button-active.png create mode 100755 plugins/c9.ide.layout.classic/images/play.gif create mode 100755 plugins/c9.ide.layout.classic/images/play.png create mode 100755 plugins/c9.ide.layout.classic/images/plus.png create mode 100644 plugins/c9.ide.layout.classic/images/plus2.png create mode 100644 plugins/c9.ide.layout.classic/images/plus_dark.png create mode 100755 plugins/c9.ide.layout.classic/images/plusplain.gif create mode 100755 plugins/c9.ide.layout.classic/images/plustabbtn.png create mode 100644 plugins/c9.ide.layout.classic/images/popout.png create mode 100644 plugins/c9.ide.layout.classic/images/popout_dark.png create mode 100755 plugins/c9.ide.layout.classic/images/preferences.png create mode 100755 plugins/c9.ide.layout.classic/images/progressbar.old.png create mode 100755 plugins/c9.ide.layout.classic/images/progressbar.png create mode 100755 plugins/c9.ide.layout.classic/images/project_files.png create mode 100755 plugins/c9.ide.layout.classic/images/radio-black.png create mode 100755 plugins/c9.ide.layout.classic/images/radio-grey.png create mode 100755 plugins/c9.ide.layout.classic/images/radio.gif create mode 100755 plugins/c9.ide.layout.classic/images/radio.png create mode 100755 plugins/c9.ide.layout.classic/images/radiobutton_over.png create mode 100755 plugins/c9.ide.layout.classic/images/raster.gif create mode 100755 plugins/c9.ide.layout.classic/images/red-arrow-down.png create mode 100755 plugins/c9.ide.layout.classic/images/redo.png create mode 100755 plugins/c9.ide.layout.classic/images/resizehandle.gif create mode 100644 plugins/c9.ide.layout.classic/images/revisions_search.png create mode 100755 plugins/c9.ide.layout.classic/images/rightclickmenu_background.png create mode 100755 plugins/c9.ide.layout.classic/images/rightclickmenu_bottom.png create mode 100755 plugins/c9.ide.layout.classic/images/rightclickmenu_top.png create mode 100755 plugins/c9.ide.layout.classic/images/rundebug.png create mode 100644 plugins/c9.ide.layout.classic/images/running.png create mode 100644 plugins/c9.ide.layout.classic/images/running_flat_light.png create mode 100644 plugins/c9.ide.layout.classic/images/running_flat_light@2x.png create mode 100755 plugins/c9.ide.layout.classic/images/save-indicator-active-tab.gif create mode 100755 plugins/c9.ide.layout.classic/images/save-indicator-inactive-tab.gif create mode 100755 plugins/c9.ide.layout.classic/images/scrollbar/grabber.png create mode 100644 plugins/c9.ide.layout.classic/images/scrollbar/local_green.png create mode 100755 plugins/c9.ide.layout.classic/images/scrollbar/sprite_ver_scrollbar.png create mode 100755 plugins/c9.ide.layout.classic/images/scrolldown.gif create mode 100755 plugins/c9.ide.layout.classic/images/scrolldowndisabled.gif create mode 100755 plugins/c9.ide.layout.classic/images/scrollup.gif create mode 100755 plugins/c9.ide.layout.classic/images/scrollupdisabled.gif create mode 100644 plugins/c9.ide.layout.classic/images/search-icon.png create mode 100755 plugins/c9.ide.layout.classic/images/search_arrow.png create mode 100755 plugins/c9.ide.layout.classic/images/searchbox_textbox_icon.png create mode 100755 plugins/c9.ide.layout.classic/images/segment.jpg create mode 100755 plugins/c9.ide.layout.classic/images/segment_active.jpg create mode 100755 plugins/c9.ide.layout.classic/images/segment_hover.jpg create mode 100755 plugins/c9.ide.layout.classic/images/segment_weekend.jpg create mode 100755 plugins/c9.ide.layout.classic/images/shop1.png create mode 100755 plugins/c9.ide.layout.classic/images/shop2.png create mode 100755 plugins/c9.ide.layout.classic/images/shop3.png create mode 100755 plugins/c9.ide.layout.classic/images/shop4.png create mode 100644 plugins/c9.ide.layout.classic/images/sidebar_preview_icon.png create mode 100755 plugins/c9.ide.layout.classic/images/sidebar_right_bar_inset.gif create mode 100755 plugins/c9.ide.layout.classic/images/signedInLogo.png create mode 100755 plugins/c9.ide.layout.classic/images/signin_bitbucket.png create mode 100755 plugins/c9.ide.layout.classic/images/signin_facebook.png create mode 100755 plugins/c9.ide.layout.classic/images/signin_github.png create mode 100755 plugins/c9.ide.layout.classic/images/signin_google.png create mode 100755 plugins/c9.ide.layout.classic/images/signin_twitter.png create mode 100755 plugins/c9.ide.layout.classic/images/slider.png create mode 100755 plugins/c9.ide.layout.classic/images/slider11x.png create mode 100755 plugins/c9.ide.layout.classic/images/slider11x_high.png create mode 100755 plugins/c9.ide.layout.classic/images/slider16x.png create mode 100755 plugins/c9.ide.layout.classic/images/slider16x_high.png create mode 100755 plugins/c9.ide.layout.classic/images/slider2.png create mode 100755 plugins/c9.ide.layout.classic/images/slider_tbutton.png create mode 100755 plugins/c9.ide.layout.classic/images/small-player-left-arr.png create mode 100755 plugins/c9.ide.layout.classic/images/small-player-right-arr.png create mode 100644 plugins/c9.ide.layout.classic/images/smile-image.png create mode 100755 plugins/c9.ide.layout.classic/images/smin.gif create mode 100755 plugins/c9.ide.layout.classic/images/sort_asc.gif create mode 100755 plugins/c9.ide.layout.classic/images/sort_desc.gif create mode 100755 plugins/c9.ide.layout.classic/images/spacer.gif create mode 100755 plugins/c9.ide.layout.classic/images/spinner_body2.png create mode 100644 plugins/c9.ide.layout.classic/images/spinner_min.png create mode 100644 plugins/c9.ide.layout.classic/images/spinner_min_dark.png create mode 100644 plugins/c9.ide.layout.classic/images/spinner_plus.png create mode 100644 plugins/c9.ide.layout.classic/images/spinner_plus_dark.png create mode 100755 plugins/c9.ide.layout.classic/images/splitter_dark_bg.png create mode 100755 plugins/c9.ide.layout.classic/images/splitter_dark_grab.png create mode 100755 plugins/c9.ide.layout.classic/images/splitter_docs.gif create mode 100755 plugins/c9.ide.layout.classic/images/splitter_handle_horizontal.gif create mode 100755 plugins/c9.ide.layout.classic/images/splitter_handle_vertical.gif create mode 100755 plugins/c9.ide.layout.classic/images/splus.gif create mode 100755 plugins/c9.ide.layout.classic/images/sprite-rounded-vert.png create mode 100755 plugins/c9.ide.layout.classic/images/sprite_boxes_hor.png create mode 100755 plugins/c9.ide.layout.classic/images/sprite_boxes_ver.png create mode 100755 plugins/c9.ide.layout.classic/images/statusbar.gif create mode 100755 plugins/c9.ide.layout.classic/images/stop.png create mode 100755 plugins/c9.ide.layout.classic/images/submenu_arrow.gif create mode 100644 plugins/c9.ide.layout.classic/images/sync-state-label.png create mode 100644 plugins/c9.ide.layout.classic/images/sync.png create mode 100644 plugins/c9.ide.layout.classic/images/sync_toggle.png create mode 100755 plugins/c9.ide.layout.classic/images/tab-save-spinner-active.gif create mode 100644 plugins/c9.ide.layout.classic/images/tab-save-spinner-active.png create mode 100644 plugins/c9.ide.layout.classic/images/tab-save-spinner-active@2x.png create mode 100644 plugins/c9.ide.layout.classic/images/tab-save-spinner-active_flat_light.png create mode 100644 plugins/c9.ide.layout.classic/images/tab-save-spinner-active_flat_light@2x.png create mode 100755 plugins/c9.ide.layout.classic/images/tab-save-spinner-inactive.gif create mode 100755 plugins/c9.ide.layout.classic/images/tab_but_bottomleft.old.png create mode 100755 plugins/c9.ide.layout.classic/images/tab_but_bottomleft.png create mode 100755 plugins/c9.ide.layout.classic/images/tab_but_bottomright.old.png create mode 100755 plugins/c9.ide.layout.classic/images/tab_but_bottomright.png create mode 100755 plugins/c9.ide.layout.classic/images/tab_but_l.png create mode 100755 plugins/c9.ide.layout.classic/images/tab_but_lb.png create mode 100755 plugins/c9.ide.layout.classic/images/tab_but_lt.png create mode 100755 plugins/c9.ide.layout.classic/images/tab_but_m.png create mode 100755 plugins/c9.ide.layout.classic/images/tab_but_mb.png create mode 100755 plugins/c9.ide.layout.classic/images/tab_but_mt.png create mode 100755 plugins/c9.ide.layout.classic/images/tab_but_r.png create mode 100755 plugins/c9.ide.layout.classic/images/tab_but_rb.png create mode 100755 plugins/c9.ide.layout.classic/images/tab_but_rt.png create mode 100755 plugins/c9.ide.layout.classic/images/tab_but_top.png create mode 100755 plugins/c9.ide.layout.classic/images/tab_but_topleft.old.png create mode 100755 plugins/c9.ide.layout.classic/images/tab_but_topleft.png create mode 100755 plugins/c9.ide.layout.classic/images/tab_but_topright.old.png create mode 100755 plugins/c9.ide.layout.classic/images/tab_but_topright.png create mode 100644 plugins/c9.ide.layout.classic/images/tab_menu.png create mode 100644 plugins/c9.ide.layout.classic/images/tab_menu@2x.png create mode 100644 plugins/c9.ide.layout.classic/images/tab_menu_dark.png create mode 100644 plugins/c9.ide.layout.classic/images/tab_menu_dark@2x.png create mode 100644 plugins/c9.ide.layout.classic/images/tab_menu_flat_light.png create mode 100644 plugins/c9.ide.layout.classic/images/tab_menu_flat_light@2x.png create mode 100755 plugins/c9.ide.layout.classic/images/tab_next.gif create mode 100755 plugins/c9.ide.layout.classic/images/tab_next_blink.gif create mode 100755 plugins/c9.ide.layout.classic/images/tab_pag_lb.png create mode 100755 plugins/c9.ide.layout.classic/images/tab_pag_rb.png create mode 100644 plugins/c9.ide.layout.classic/images/tab_plus.png create mode 100644 plugins/c9.ide.layout.classic/images/tab_plus@2x.png create mode 100644 plugins/c9.ide.layout.classic/images/tab_plus_dark.png create mode 100644 plugins/c9.ide.layout.classic/images/tab_plus_dark@2x.png create mode 100644 plugins/c9.ide.layout.classic/images/tab_plus_flat_light.png create mode 100644 plugins/c9.ide.layout.classic/images/tab_plus_flat_light@2x.png create mode 100755 plugins/c9.ide.layout.classic/images/tab_prev.gif create mode 100755 plugins/c9.ide.layout.classic/images/tab_prev_blink.gif create mode 100755 plugins/c9.ide.layout.classic/images/tabdropdown.png create mode 100644 plugins/c9.ide.layout.classic/images/tabsave-flat.png create mode 100644 plugins/c9.ide.layout.classic/images/tabsave-flat@2x.png create mode 100644 plugins/c9.ide.layout.classic/images/tabsave.png create mode 100644 plugins/c9.ide.layout.classic/images/tabsave@2x.png create mode 100755 plugins/c9.ide.layout.classic/images/testing.png create mode 100755 plugins/c9.ide.layout.classic/images/textarea_background.png create mode 100755 plugins/c9.ide.layout.classic/images/textarea_background2.png create mode 100755 plugins/c9.ide.layout.classic/images/textarea_background_left.png create mode 100755 plugins/c9.ide.layout.classic/images/textarea_background_top.png create mode 100755 plugins/c9.ide.layout.classic/images/the_store.png create mode 100755 plugins/c9.ide.layout.classic/images/toolbar-arrows.png create mode 100755 plugins/c9.ide.layout.classic/images/toolbar-divider.png create mode 100755 plugins/c9.ide.layout.classic/images/toolbar.icons.gif create mode 100755 plugins/c9.ide.layout.classic/images/toolbar_a_down.png create mode 100755 plugins/c9.ide.layout.classic/images/toolbar_a_down_right.png create mode 100755 plugins/c9.ide.layout.classic/images/toolbar_a_hover.png create mode 100755 plugins/c9.ide.layout.classic/images/toolbar_a_hover_right.png create mode 100755 plugins/c9.ide.layout.classic/images/toolbar_a_small_hover.png create mode 100755 plugins/c9.ide.layout.classic/images/toolbar_a_small_sel.png create mode 100755 plugins/c9.ide.layout.classic/images/toolbar_btn.gif create mode 100755 plugins/c9.ide.layout.classic/images/toolbar_row.png create mode 100755 plugins/c9.ide.layout.classic/images/tools.png create mode 100755 plugins/c9.ide.layout.classic/images/tooltip_arrow.png create mode 100755 plugins/c9.ide.layout.classic/images/tree-shadow-left.png create mode 100755 plugins/c9.ide.layout.classic/images/tree-shadow-right.png create mode 100755 plugins/c9.ide.layout.classic/images/tree_backg.png create mode 100755 plugins/c9.ide.layout.classic/images/tree_checkbox.png create mode 100755 plugins/c9.ide.layout.classic/images/tree_close_arrow.png create mode 100755 plugins/c9.ide.layout.classic/images/tree_close_arrow_small.png create mode 100755 plugins/c9.ide.layout.classic/images/tree_close_arrow_small@2x.png create mode 100644 plugins/c9.ide.layout.classic/images/tree_close_arrow_small_dark.png create mode 100644 plugins/c9.ide.layout.classic/images/tree_close_arrow_small_dark@2x.png create mode 100755 plugins/c9.ide.layout.classic/images/tree_selected.png create mode 100644 plugins/c9.ide.layout.classic/images/tree_upload_icon.png create mode 100755 plugins/c9.ide.layout.classic/images/underline.png create mode 100755 plugins/c9.ide.layout.classic/images/undo.png create mode 100644 plugins/c9.ide.layout.classic/images/updatec9.png create mode 100644 plugins/c9.ide.layout.classic/images/versions_search_close.png create mode 100755 plugins/c9.ide.layout.classic/images/visual_editor.png create mode 100755 plugins/c9.ide.layout.classic/images/volume.gif create mode 100755 plugins/c9.ide.layout.classic/images/wide-view-icn.png create mode 100755 plugins/c9.ide.layout.classic/images/win16x.png create mode 100755 plugins/c9.ide.layout.classic/images/win19x.png create mode 100755 plugins/c9.ide.layout.classic/images/win28x.png create mode 100755 plugins/c9.ide.layout.classic/images/win32x.png create mode 100755 plugins/c9.ide.layout.classic/images/win64x.png create mode 100755 plugins/c9.ide.layout.classic/images/win_edit.gif create mode 100755 plugins/c9.ide.layout.classic/images/win_edit.png create mode 100755 plugins/c9.ide.layout.classic/images/win_max.gif create mode 100755 plugins/c9.ide.layout.classic/images/win_min.gif create mode 100755 plugins/c9.ide.layout.classic/images/win_restore.gif create mode 100755 plugins/c9.ide.layout.classic/images/win_x.gif create mode 100755 plugins/c9.ide.layout.classic/images/win_x.png create mode 100644 plugins/c9.ide.layout.classic/images/winc9.png create mode 100644 plugins/c9.ide.layout.classic/images/winc9_light.png create mode 100755 plugins/c9.ide.layout.classic/images/window_border.png create mode 100755 plugins/c9.ide.layout.classic/images/window_lb.png create mode 100755 plugins/c9.ide.layout.classic/images/window_lb_rounded.png create mode 100755 plugins/c9.ide.layout.classic/images/window_lb_small.png create mode 100755 plugins/c9.ide.layout.classic/images/window_lt.png create mode 100755 plugins/c9.ide.layout.classic/images/window_mb.png create mode 100755 plugins/c9.ide.layout.classic/images/window_mb_small.png create mode 100755 plugins/c9.ide.layout.classic/images/window_mt.png create mode 100755 plugins/c9.ide.layout.classic/images/window_rb.png create mode 100755 plugins/c9.ide.layout.classic/images/window_rb_rounded.png create mode 100755 plugins/c9.ide.layout.classic/images/window_rb_small.png create mode 100755 plugins/c9.ide.layout.classic/images/window_rt.png create mode 100755 plugins/c9.ide.layout.classic/images/wp_searchbox_clearbtn.png create mode 100755 plugins/c9.ide.layout.classic/images/wp_searchbox_icon.png create mode 100755 plugins/c9.ide.layout.classic/images/x.png create mode 100755 plugins/c9.ide.layout.classic/images/zen-buttons.png create mode 100755 plugins/c9.ide.layout.classic/images/zenbg.png create mode 100644 plugins/c9.ide.layout.classic/keyframes.css create mode 100644 plugins/c9.ide.layout.classic/layout.js create mode 100644 plugins/c9.ide.layout.classic/layout.xml create mode 100644 plugins/c9.ide.layout.classic/less/bar.less create mode 100644 plugins/c9.ide.layout.classic/less/bk-window.less create mode 100644 plugins/c9.ide.layout.classic/less/bk-window2.less create mode 100644 plugins/c9.ide.layout.classic/less/black_dropdown.less create mode 100644 plugins/c9.ide.layout.classic/less/blackbutton.less create mode 100644 plugins/c9.ide.layout.classic/less/blackdg.less create mode 100644 plugins/c9.ide.layout.classic/less/browser-btn.less create mode 100644 plugins/c9.ide.layout.classic/less/btn-default-css3.less create mode 100644 plugins/c9.ide.layout.classic/less/btn_console.less create mode 100644 plugins/c9.ide.layout.classic/less/btn_console_open.less create mode 100644 plugins/c9.ide.layout.classic/less/btn_icon_only.less create mode 100644 plugins/c9.ide.layout.classic/less/button.less create mode 100644 plugins/c9.ide.layout.classic/less/c9-divider-double.less create mode 100644 plugins/c9.ide.layout.classic/less/c9-divider-hor.less create mode 100644 plugins/c9.ide.layout.classic/less/c9-divider.less create mode 100644 plugins/c9.ide.layout.classic/less/c9-menu-bar.less create mode 100644 plugins/c9.ide.layout.classic/less/c9-menu-btn.less create mode 100644 plugins/c9.ide.layout.classic/less/c9-notification-bar.less create mode 100644 plugins/c9.ide.layout.classic/less/c9-simple-btn.less create mode 100644 plugins/c9.ide.layout.classic/less/c9-toolbarbutton-glossy.less create mode 100644 plugins/c9.ide.layout.classic/less/c9-toolbarbutton-light.less create mode 100644 plugins/c9.ide.layout.classic/less/c9-toolbarbutton.less create mode 100644 plugins/c9.ide.layout.classic/less/cboffline.less create mode 100644 plugins/c9.ide.layout.classic/less/checkbox.less create mode 100644 plugins/c9.ide.layout.classic/less/checkbox_black.less create mode 100644 plugins/c9.ide.layout.classic/less/checkbox_grey.less create mode 100644 plugins/c9.ide.layout.classic/less/codebox.less create mode 100644 plugins/c9.ide.layout.classic/less/colorbox.less create mode 100644 plugins/c9.ide.layout.classic/less/datagrid.less create mode 100644 plugins/c9.ide.layout.classic/less/divider.less create mode 100644 plugins/c9.ide.layout.classic/less/divider_console.less create mode 100644 plugins/c9.ide.layout.classic/less/dropdown-dark-glossy.less create mode 100644 plugins/c9.ide.layout.classic/less/dropdown.less create mode 100644 plugins/c9.ide.layout.classic/less/editor_tab.less create mode 100644 plugins/c9.ide.layout.classic/less/errorbox.less create mode 100644 plugins/c9.ide.layout.classic/less/frame.less create mode 100644 plugins/c9.ide.layout.classic/less/grouped_checkbox.less create mode 100644 plugins/c9.ide.layout.classic/less/header-btn.less create mode 100644 plugins/c9.ide.layout.classic/less/img.less create mode 100644 plugins/c9.ide.layout.classic/less/label.less create mode 100755 plugins/c9.ide.layout.classic/less/lesshat.less create mode 100644 plugins/c9.ide.layout.classic/less/lineselect.less create mode 100644 plugins/c9.ide.layout.classic/less/list.less create mode 100644 plugins/c9.ide.layout.classic/less/list_dark.less create mode 100644 plugins/c9.ide.layout.classic/less/main.less create mode 100644 plugins/c9.ide.layout.classic/less/menu.less create mode 100644 plugins/c9.ide.layout.classic/less/notification-bar.less create mode 100644 plugins/c9.ide.layout.classic/less/panel-bar.less create mode 100644 plugins/c9.ide.layout.classic/less/password.less create mode 100644 plugins/c9.ide.layout.classic/less/radiobutton.less create mode 100644 plugins/c9.ide.layout.classic/less/sbios.less create mode 100644 plugins/c9.ide.layout.classic/less/scrollbar.less create mode 100644 plugins/c9.ide.layout.classic/less/searchbox.less create mode 100644 plugins/c9.ide.layout.classic/less/simplebox.less create mode 100644 plugins/c9.ide.layout.classic/less/simpleimg.less create mode 100644 plugins/c9.ide.layout.classic/less/spinner.less create mode 100644 plugins/c9.ide.layout.classic/less/splitter.less create mode 100644 plugins/c9.ide.layout.classic/less/style.less create mode 100644 plugins/c9.ide.layout.classic/less/tbsimple.less create mode 100644 plugins/c9.ide.layout.classic/less/textarea.less create mode 100644 plugins/c9.ide.layout.classic/less/textbox.less create mode 100644 plugins/c9.ide.layout.classic/less/toolbar-bottom.less create mode 100644 plugins/c9.ide.layout.classic/less/toolbar-top.less create mode 100644 plugins/c9.ide.layout.classic/less/toolbar.less create mode 100644 plugins/c9.ide.layout.classic/less/tooltiplabel.less create mode 100644 plugins/c9.ide.layout.classic/loading.css create mode 100644 plugins/c9.ide.layout.classic/preload.js create mode 100644 plugins/c9.ide.layout.classic/skins.xml create mode 100644 plugins/c9.ide.layout.classic/themes/crazy.less create mode 100644 plugins/c9.ide.layout.classic/themes/default-dark-gray.less create mode 100644 plugins/c9.ide.layout.classic/themes/default-dark.less create mode 100644 plugins/c9.ide.layout.classic/themes/default-flat-light.less create mode 100644 plugins/c9.ide.layout.classic/themes/default-light-gray.less create mode 100644 plugins/c9.ide.layout.classic/themes/default-light.less create mode 100644 plugins/c9.ide.layout.classic/themes/flat-light.less create mode 100644 plugins/c9.ide.panels/area.js create mode 100644 plugins/c9.ide.panels/panel.js create mode 100644 plugins/c9.ide.panels/panels.js create mode 100644 plugins/c9.ide.panels/panels_test.js create mode 100644 plugins/c9.ide.panels/skin.xml create mode 100644 plugins/c9.ide.plugins/debug.js create mode 100644 plugins/c9.ide.plugins/installer.js create mode 100644 plugins/c9.ide.plugins/loader.js create mode 100644 plugins/c9.ide.plugins/manager.js create mode 100644 plugins/c9.ide.plugins/managerdp.js create mode 100644 plugins/c9.ide.plugins/market.js create mode 160000 plugins/c9.ide.plugins/mock/c9.ide.example create mode 100644 plugins/c9.ide.plugins/mock/c9.ide.example2/example.js create mode 100644 plugins/c9.ide.plugins/mock/c9.ide.example2/package.json create mode 100644 plugins/c9.ide.plugins/templates/plugin.default.tar.gz create mode 100644 plugins/c9.ide.plugins/templates/plugin.default/README.md create mode 100644 plugins/c9.ide.plugins/templates/plugin.default/images/puppy.jpg create mode 100644 plugins/c9.ide.plugins/templates/plugin.default/package.json create mode 100644 plugins/c9.ide.plugins/templates/plugin.default/plugin.html create mode 100644 plugins/c9.ide.plugins/templates/plugin.default/plugin.js create mode 100644 plugins/c9.ide.plugins/templates/plugin.default/plugin_test.js create mode 100644 plugins/c9.ide.plugins/templates/plugin.default/style.css create mode 100644 plugins/c9.ide.plugins/templates/plugin.simple.tar.gz create mode 100644 plugins/c9.ide.plugins/templates/plugin.simple/README.md create mode 100644 plugins/c9.ide.plugins/templates/plugin.simple/package.json create mode 100644 plugins/c9.ide.plugins/templates/plugin.simple/plugin.js create mode 100644 plugins/c9.ide.plugins/templates/plugin.simple/plugin_test.js create mode 100644 plugins/c9.ide.plugins/test.js create mode 100644 plugins/c9.ide.preferences/general.js create mode 100644 plugins/c9.ide.preferences/images/c9-noise.png create mode 100644 plugins/c9.ide.preferences/images/panelbg.png create mode 100644 plugins/c9.ide.preferences/images/preferences.png create mode 100755 plugins/c9.ide.preferences/images/tree_close_arrow_small.png create mode 100755 plugins/c9.ide.preferences/images/tree_close_arrow_small@2x.png create mode 100644 plugins/c9.ide.preferences/images/tree_close_arrow_small_dark.png create mode 100644 plugins/c9.ide.preferences/preferencepanel.js create mode 100644 plugins/c9.ide.preferences/preferences.css create mode 100644 plugins/c9.ide.preferences/preferences.js create mode 100644 plugins/c9.ide.preferences/preferences_test.js create mode 100644 plugins/c9.ide.preferences/project.js create mode 100644 plugins/c9.ide.server/plugins.js create mode 100644 plugins/c9.ide.server/www/require.js create mode 100644 plugins/c9.ide.server/www/text.js create mode 100644 plugins/c9.ide.terminal/aceterm/aceterm.js create mode 100644 plugins/c9.ide.terminal/aceterm/hover_link.js create mode 100644 plugins/c9.ide.terminal/aceterm/input.js create mode 100644 plugins/c9.ide.terminal/aceterm/libterm.js create mode 100644 plugins/c9.ide.terminal/aceterm/mouse.js create mode 100644 plugins/c9.ide.terminal/aceterm/scroll_buffer.js create mode 100644 plugins/c9.ide.terminal/aceterm/term_colors.js create mode 100644 plugins/c9.ide.terminal/images/tile.png create mode 100755 plugins/c9.ide.terminal/install-tmux.sh create mode 100644 plugins/c9.ide.terminal/link_handler.js create mode 100644 plugins/c9.ide.terminal/menu.xml create mode 100644 plugins/c9.ide.terminal/opentermhere.js create mode 100644 plugins/c9.ide.terminal/predict_echo.js create mode 100644 plugins/c9.ide.terminal/predict_echo_test.js create mode 100644 plugins/c9.ide.terminal/style.css create mode 100644 plugins/c9.ide.terminal/terminal.js create mode 100644 plugins/c9.ide.terminal/terminal.xml create mode 100644 plugins/c9.ide.terminal/terminal_test.js create mode 100644 plugins/c9.ide.terminal/tmux_connection.js create mode 100644 plugins/c9.ide.tree/favorites.js create mode 100644 plugins/c9.ide.tree/style.css create mode 100644 plugins/c9.ide.tree/tree.js create mode 100644 plugins/c9.ide.tree/tree.xml create mode 100644 plugins/c9.ide.tree/tree_test.js create mode 100644 plugins/c9.ide.ui/_docs.js create mode 100644 plugins/c9.ide.ui/anims.js create mode 100644 plugins/c9.ide.ui/codebox.js create mode 100644 plugins/c9.ide.ui/docklayout.js create mode 100644 plugins/c9.ide.ui/docklayout_test.js create mode 100644 plugins/c9.ide.ui/focus.js create mode 100644 plugins/c9.ide.ui/forms.js create mode 100644 plugins/c9.ide.ui/lib/core.js create mode 100644 plugins/c9.ide.ui/lib/dropdown.js create mode 100644 plugins/c9.ide.ui/lib/flexbox.js create mode 100644 plugins/c9.ide.ui/lib/menu/menu.js create mode 100644 plugins/c9.ide.ui/lib/page.js create mode 100644 plugins/c9.ide.ui/lib/splitbox.js create mode 100644 plugins/c9.ide.ui/lib_apf.js create mode 100644 plugins/c9.ide.ui/lib_firmin.js create mode 100644 plugins/c9.ide.ui/lib_less1.5.js create mode 100644 plugins/c9.ide.ui/menus.js create mode 100644 plugins/c9.ide.ui/menus_test.js create mode 100644 plugins/c9.ide.ui/style.css create mode 100644 plugins/c9.ide.ui/tooltip.js create mode 100644 plugins/c9.ide.ui/ui.js create mode 100644 plugins/c9.ide.ui/ui_test.js create mode 100644 plugins/c9.ide.watcher/gui.js create mode 100644 plugins/c9.ide.watcher/watcher.js create mode 100644 plugins/c9.ide.watcher/watcher_test.js create mode 100644 plugins/c9.logtimestamp/logtimestamp.js create mode 100644 plugins/c9.nodeapi/assert.js create mode 100644 plugins/c9.nodeapi/async.js create mode 100644 plugins/c9.nodeapi/events.js create mode 100644 plugins/c9.nodeapi/events_test.js create mode 100644 plugins/c9.nodeapi/http-error.js create mode 100644 plugins/c9.nodeapi/http.js create mode 100644 plugins/c9.nodeapi/lodash.js create mode 100644 plugins/c9.nodeapi/nodeapi.js create mode 100644 plugins/c9.nodeapi/path.js create mode 100644 plugins/c9.nodeapi/querystring.js create mode 100644 plugins/c9.nodeapi/sinon.js create mode 100644 plugins/c9.nodeapi/stream.js create mode 100644 plugins/c9.nodeapi/url.js create mode 100644 plugins/c9.nodeapi/util.js create mode 100644 plugins/c9.nodeapi/ws.js create mode 100644 plugins/c9.preview/preview.handler.js create mode 100644 plugins/c9.preview/preview.js create mode 100644 plugins/c9.preview/static/livecss.js create mode 100644 plugins/c9.preview/statics.js create mode 100644 plugins/c9.preview/views/listing.html.ejs create mode 100644 plugins/c9.preview/views/progress.html.ejs create mode 100644 plugins/c9.static/build.js create mode 100755 plugins/c9.static/build_test.js create mode 100644 plugins/c9.static/cdn.cli.js create mode 100644 plugins/c9.static/cdn.js create mode 100644 plugins/c9.static/connect-static.js create mode 100644 plugins/c9.static/connect.js create mode 100644 plugins/c9.static/makestatic.js create mode 100644 plugins/c9.vfs.client/endpoint.js create mode 100644 plugins/c9.vfs.client/ping-service.js create mode 100644 plugins/c9.vfs.client/vfs.cli.js create mode 100644 plugins/c9.vfs.client/vfs.ping.js create mode 100644 plugins/c9.vfs.client/vfs_client.js create mode 100644 plugins/c9.vfs.client/vfs_test.js create mode 100644 plugins/c9.vfs.server/cache.js create mode 100644 plugins/c9.vfs.server/download.js create mode 100755 plugins/c9.vfs.server/download_test.js create mode 100644 plugins/c9.vfs.server/filelist.js create mode 100644 plugins/c9.vfs.server/statics.js create mode 100644 plugins/c9.vfs.server/vfs.connect.local.js create mode 100644 plugins/c9.vfs.server/vfs.connect.standalone.js create mode 100644 plugins/c9.vfs.server/vfs.js create mode 100644 plugins/c9.vfs.server/vfs.server.js create mode 100644 plugins/c9.vfs.server/vfs_proxy.js create mode 100644 plugins/c9.vfs.server/vfs_wrapper.js create mode 100644 plugins/c9.vfs.standalone/standalone.js create mode 100644 plugins/c9.vfs.standalone/views/standalone.html.ejs create mode 100644 plugins/c9.vfs.standalone/www/html2canvas.js create mode 100644 plugins/c9.vfs.standalone/www/install.html create mode 100644 plugins/c9.vfs.standalone/www/packed.html create mode 100644 plugins/c9.vfs.standalone/www/places.html create mode 100644 plugins/c9.vfs.standalone/www/require.js create mode 100644 plugins/c9.vfs.standalone/www/test.html create mode 100644 plugins/c9.vfs.standalone/www/test.js create mode 100644 plugins/c9.vfs.standalone/www/testsuite.html create mode 100644 plugins/c9.vfs.standalone/www/text.js create mode 100755 scripts/initlocal.sh create mode 100755 scripts/install-sdk.sh create mode 100755 scripts/makelocal.sh create mode 100755 scripts/makestandalone.sh create mode 100755 scripts/makestatic.js create mode 100755 scripts/setup-local-dev.sh create mode 100755 scripts/uninstall-c9.sh create mode 100755 scripts/update-npm.sh create mode 100755 server.js create mode 100644 settings/local.js create mode 100644 settings/standalone.js create mode 100644 test/filefinder.js diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 00000000..38c2858d --- /dev/null +++ b/.eslintrc @@ -0,0 +1,46 @@ +env: + node: true + browser: true + amd: true + builtin: true + mocha: true + jasmine: false + +rules: + handle-callback-err: 1 + no-debugger: 1 + no-undef: 1 + no-inner-declarations: [1, "functions"] + no-native-reassign: 1 + no-new-func: 1 + no-new-wrappers: 1 + no-cond-assign: [1, "except-parens"] + no-debugger: 3 + no-dupe-keys: 3 + no-eval: 2 + no-func-assign: 1 + no-invalid-regexp: 1 + no-irregular-whitespace: 3 + no-negated-in-lhs: 1 + no-regex-spaces: 3 + no-reserved-keys: 3 + no-unreachable: 1 + use-isnan: 2 + valid-typeof: 1 + no-redeclare: 3 + no-with: 1 + radix: 3 + no-delete-var: 2 + no-label-var: 3 + no-shadow-restricted-names: 2 + handle-callback-err: 1 + no-new-require: 2 + no-unused-vars: [3, {vars: "all", args: "none"}] + no-undef: 1 + semi: 3 + no-extra-semi: 3 + + default-case: 3 + space-after-keywords: [1, "always"] + spaced-line-comment: 3 + // valid-jsdoc: [1, { requireReturn: false, requireParamDescription: false, prefer: { "return": "return" } }] diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..af2db3dc --- /dev/null +++ b/.gitignore @@ -0,0 +1,75 @@ +build/installer/ +build/win32 +build/node.exe +build/node*.zip +build/Cloud9-dev.app +docs/generate/lib/node_modules +plugins/c9.ide.layout.classic/less/*.css +plugins/c9.vfs.standalone/www/less.html +plugins/c9.ide.run/todo +plugins/c9.vfs.standalone/www/charts +scripts/build +build/output +build/standalone/ +build/standalonebuild/ +build/static +build/node_modules/ +build/webkitbuilds/ +plugins/c9.run/todo +docs/generate/output +docs/generate/lib/node_modules +plugins/c9.docker/bin/node_modules/ +node_modules/vfs-local/test/mock2/ +plugins/c9.fs/mock/ + +# ignore node_modules +node_modules/* +# except git subtrees +!node_modules/ace* +!node_modules/architect* +!node_modules/vfs* +!node_modules/build +!node_modules/c9 +!node_modules/frontdoor +!node_modules/kaefer +node_modules/kaefer/node_modules/ +!node_modules/nak +!node_modules/pivottable +!node_modules/smith +!node_modules/treehugger +!node_modules/logicblox +!node_modules/connect-architect +!node_modules/pty.js +!node_modules/ui +!node_modules/react-bootstrap +!node_modules/oldclient + +node_modules/oldclient/node_modules +node_modules/oldclient/plugins-server/c9.api.project/tmp* + +node_modules/vfs-local/test/mock +node_modules/vfs-ssh/__worker.js + +plugins/c9.fs/mock/helloworld.js +plugins/c9.fs/mock/run.watch + +node_modules/logicblox/plugins/logicblox.repl/lbfileserver/node_modules +node_modules/logicblox/plugins/logicblox.pivot/examples/query.json +node_modules/pivottable/node_modules +node_modules/c9/node_modules +plugins/c9.proxy/proxy.cfg +plugins/c9.proxy/haproxy +plugins/c9.proxy/haproxy-* +**/.module-cache/ + +.c9revisions +.settings +.c9config +.c9 +*.watch +*.pid +*.swp +*#* +npm-debug.log +foo.js +hello.js diff --git a/.nakignore b/.nakignore new file mode 100644 index 00000000..d4479eea --- /dev/null +++ b/.nakignore @@ -0,0 +1,7 @@ +build/output +build/standalone/ +build/static +build/node_modules/ +build/webkitbuilds/ +build/win32 +node_modules/logicblox/build/logicblox/static \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..bf84a3d8 --- /dev/null +++ b/LICENSE @@ -0,0 +1,239 @@ +Cloud9 Software Development Kit Non-commercial License Agreement + +1. Introduction +1.1 The Cloud9 Software Development Kit (referred to in this License Agreement +as the "SDK" and specifically including the Cloud9 system files, the Cloud9 +computer software source code, Cloud9’s Ace editor plugin and Cloud9’s +terminal plugin) is licensed to you subject to the terms of this Non-commercial +License Agreement. + +1.2 Any software provided along with the SDK (such as some of the files in the +node_modules directory) that is associated with a separate license agreement is +licensed to you under the terms of that separate license agreement. + +This License Agreement forms a legally binding contract between you and Cloud9 +in relation to your use of the SDK. + +1.2 “Cloud9†refers to Cloud9 IDE, Inc, registered Delaware corporation with +principal place of business 1663 McAllister Street #B, San Francisco, CA 94115, +United States. + +2. Accepting this license agreement +2.1 In order to use the SDK, you must first agree to this License Agreement. You +may not use the SDK if you do not accept this License Agreement. + +2.2 You agree to be bound by the terms of this SDK License by installing, +copying, downloading, accessing or otherwise using the SDK. + +2.3 You may not use the SDK and may not accept the License Agreement if you are +a person barred from receiving the SDK under the laws of the United States or +other countries including the country in which you are resident or from which +you use the SDK. + +2.4 If you are agreeing to be bound by this License Agreement on behalf of your +employer or other entity, you represent and warrant that you have full legal +authority to bind your employer or such entity to this License Agreement. If you +do not have the requisite authority, you may not accept the License Agreement or +use the SDK on behalf of your employer or other entity. + +3. The Cloud9 SDK +3.1 Cloud9 grants to you a non-exclusive, non-commercial, non-transferable, +personal license to do the following, all subject to the terms of this license: + +Copy and modify any SDK source code, and include such copies and modifications +in software that you create (“Derived Softwareâ€), and include SDK object +code in Derived Software; + +Use SDK source code, SDK object code, and Derived Software for your own +personal, noncommercial use; + +Distribute Derived Software and SDK documentation to others, provided that any +distribution is for noncommercial purposes only, is without charge or fee or +consideration of any kind, and that every recipient of the distribution agree to +and is bound by the terms of this SDK License. + +3.2 You agree that Cloud9 or third parties own all legal right, title and +interest in and to the SDK, including any Intellectual Property Rights that +subsist in the SDK. "Intellectual Property Rights" means any and all rights +under patent law, copyright law, trade secret law, trademark law, and any and +all other proprietary rights. Cloud9 reserves all rights not expressly granted +to you. + +3.3 You may not use the SDK for any purpose not expressly permitted by this +License Agreement. You do not have the right to: + +Reverse engineer or in any other way attempt to reproduce the operation of the +code in the SDK, or defeat or circumvent any security features of any code in +the SDK; +Use anything in the SDK or any Derived Software for any commercial purpose, +including without limitation for provision of programming, hosting, or any other +services for others; +Distribute anything in the SDK or any Derived Software to any other party that +is not bound by the terms of this SDK License; +Make any copies of anything in the SDK without including all copyright, license, +and other legal notices with the copy; +Transfer the SDK, this SDK License, or any part thereof, to any other party. Any +attempt at such a transfer is void. + +3.4 Use, reproduction and distribution of components of the SDK licensed under a +separate license agreement are governed solely by the terms of that separate +license agreement and not this License Agreement. + +3.5 You agree that the form and nature of the SDK that Cloud9 provides may +change without prior notice to you and that future versions of the SDK may be +incompatible with applications developed on previous versions of the SDK. You +agree that Cloud9 may stop (permanently or temporarily) providing the SDK (or +any features within the SDK) to you or to users generally at Cloud9's sole +discretion, without prior notice to you. + +3.6 Nothing in this License Agreement gives you a right to use any of Cloud9's +trade names, trademarks, service marks, logos, domain names, or other +distinctive brand features. + +3.7 You agree that you will not remove, obscure, or alter any proprietary rights +notices (including copyright and trademark notices) that may be affixed to or +contained within the SDK. + +4. Privacy and Information +4.1 In order to continually innovate and improve the SDK, Cloud9 may collect +certain usage statistics from the software including but not limited to a unique +identifier, associated IP address, version number of the software, and +information on which tools and/or services in the SDK are being used and how +they are being used. Before any of this information is collected, the SDK will +notify you and seek your consent. If you withhold consent, the information will +not be collected. + +4.2 The data collected is examined in the aggregate to improve the SDK and is +maintained in accordance with Cloud9's Privacy Policy. + +5. Your developer credentials +5.1 You agree that you are responsible for maintaining the confidentiality of +any developer credentials that may be issued to you by Cloud9 or which you may +choose yourself and that you will be solely responsible for all applications +that are developed under your developer credentials. + +6. Third party applications +6.1 If you use the SDK to run applications developed by a third party or that +access data, content or resources provided by a third party, you agree that +Cloud9 is not responsible for those applications, data, content, or resources. +You understand that all data, content or resources which you may access through +such third party applications are the sole responsibility of the person from +which they originated and that Cloud9 is not liable for any loss or damage that +you may experience as a result of the use or access of any of those third party +applications, data, content, or resources. + +6.2 You should be aware the data, content, and resources presented to you +through such a third party application may be protected by intellectual property +rights which are owned by the providers (or by other persons or companies on +their behalf). You may not modify, rent, lease, loan, sell, distribute or create +derivative works based on these data, content, or resources (either in whole or +in part) unless you have been specifically given permission to do so by the +relevant owners. + +6.3 You acknowledge that your use of such third party applications, data, +content, or resources may be subject to separate terms between you and the +relevant third party. In that case, this License Agreement does not affect your +legal relationship with these third parties. + +7. Termination of this license agreement +7.1 This License Agreement will continue to apply until terminated by either you +or Cloud9 as set out below. + +7.2 If you want to terminate this License Agreement, you may do so by ceasing +your use of the SDK and any relevant developer credentials. + +7.3 Cloud9 may at any time, terminate this License Agreement with you if: +a. you do not abide by the provisions of this License Agreement; or +b. at any time upon 72 hours notice to you; or +c. at any time upon post of a notice of termination to Cloud9’s website. In +such event, you must destroy all copies of the SDK and any Derived Software. +Termination of this SDK License shall terminate your rights and all obligations +of Cloud9 under this SDK License, but the remaining provisions shall survive +termination. + +8. DISCLAIMER OF WARRANTIES +8.1 THE ENTIRE RISK ARISING OUT OF USE OR PERFORMANCE OF THE SDK AND ANY DERIVED +SOFTWARE REMAINS WITH YOU, THE USER. CLOUD9 EXPRESSLY DISCLAIMS (I) ANY WARRANTY +FOR THE SDK AND ANY DERIVED SOFTWARE, AND (II) ANY COMMON LAW DUTIES WITH REGARD +TO SDK AND ANY DERIVED SOFTWARE, INCLUDING DUTIES OF LACK OF NEGLIGENCE AND LACK +OF WORKMANLIKE EFFORT. + +8.2 THE SDK AND ANY INFORMATION AVAILABLE IN CONNECTION THEREWITH ARE PROVIDED +ON AN "AS IS" AND "AS AVAILABLE" BASIS, "WITH ALL FAULTS" AND WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, THE +IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +NON-INFRINGEMENT. + +8.3 ANY WARRANTY AGAINST INFRINGEMENT THAT MAY BE PROVIDED IN SECTION 2-312(3) +OF THE UNIFORM COMMERCIAL CODE AND/OR IN ANY OTHER COMPARABLE STATE STATUTE IS +EXPRESSLY DISCLAIMED. ALSO, THERE IS NO WARRANTY OF TITLE, INTERFERENCE WITH +YOUR ENJOYMENT, OR AUTHORITY IN CONNECTION WITH THE SDK OR ANY DERIVED SOFTWARE +OR INFORMATION AVAILABLE IN CONNECTION THEREWITH. THIS SECTION WILL APPLY TO THE +MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW. + +9. LIMITATION OF LIABILITY AND EXCLUSIVE REMEDY +9.1 NEITHER CLOUD9, ITS LICENSORS, NOR THEIR AFFILIATES SHALL BE LIABLE IN ANY +WAY FOR LOSS OR DAMAGE OF ANY KIND RESULTING FROM THE USE OR INABILITY TO USE +THE SDK OR ANY DERIVED SOFTWARE INCLUDING, BUT NOT LIMITED TO, LOSS OF GOODWILL, +WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL +DAMAGES OR LOSSES. + +9.2 IN NO EVENT WILL CLOUD9 BE LIABLE FOR ANY INDIRECT, INCIDENTAL, +CONSEQUENTIAL, SPECIAL, PUNITIVE, EXEMPLARY DAMAGES, OR ANY OTHER DAMAGES +ARISING OUT OF OR IN ANY WAY CONNECTED WITH THE SDK, ANY DERIVED SOFTWARE, ANY +INFORMATION AVAILABLE IN CONNECTION THEREWITH, OR THE DELAY OR INABILITY TO USE +THE SDK, ANY DERIVED SOFTWARE, OR ANY INFORMATION, EVEN IN THE EVENT OF FAULT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY, BREACH OF CONTRACT, OR BREACH OF +ANY WARRANTY AND EVEN IF CLOUD9 HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + +THESE LIMITATIONS AND EXCLUSIONS REGARDING DAMAGES APPLY EVEN IF ANY REMEDY +FAILS. YOU ACKNOWLEDGE AND AGREE THAT YOUR SOLE AND EXCLUSIVE REMEDY FOR ANY +DISPUTE WITH CLOUD9 WITH REGARD TO THE SDK IS TO DISCONTINUE USE OF THE SDK AND +ANY DERIVED SOFTWARE. BECAUSE SOME STATES OR JURISDICTIONS DO NOT ALLOW THE +EXCLUSION OR THE LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL +DAMAGES, IN SUCH STATES OR JURISDICTIONS, CLOUD9, ITS LICENSORS, AND THEIR +AFFILIATES LIABILITY SHALL BE LIMITED TO THE FULL EXTENT PERMITTED BY LAW. + +10. Indemnification +10.1 You agree to defend, indemnify and hold harmless Cloud9, its licensors and +their affiliates from all liabilities, claims and expenses, including attorneys' +fees, that arise from or in connection with breach of this Agreement, use of the +SDK or any Derived Software, including, but not limited to, the creation, +distribution, promotion and use of any Derived Software. Cloud9 reserves the +right to assume the exclusive defense and control of any matter subject to +indemnification by you. + +11. Changes to the license agreement +11.1 Cloud9 may make changes to the License Agreement as it distributes new +versions of the SDK. When these changes are made, Cloud9 will make a new version +of the License Agreement available on the website where the SDK is made +available. + +12. Applicable law, jurisdiction +12.1 This License Agreement, and your relationship with Cloud9 under this +License Agreement, shall be governed by the laws of the State of California +without regard to its conflict of laws provisions. You and Cloud9 agree to +submit to the exclusive jurisdiction of the courts located within the county of +Santa Clara, California to resolve any legal matter arising from this License +Agreement. Notwithstanding this, you agree that Cloud9 shall still be allowed to +apply for injunctive remedies. + +13. General legal terms +13.1 This SDK License sets forth all rights for the user of the SDK and is the +entire agreement between the parties. This SDK License supersedes any other +communications with respect to the SDK. You agree that this SDK License is not +intended to confer and does not confer any rights or remedies upon any person +other than the parties to this SDK License. No provision hereof shall be deemed +waived unless such waiver shall be in writing and signed by Cloud9. If any +provision of this SDK License is held invalid or unenforceable, the remainder of +this SDK License shall continue in full force and effect, and such provision +shall be reformed only to the extent necessary to make it valid and enforceable. +The parties confirm that it is their wish that this Agreement has been written +in the English language only (or an equivalent type of urgent legal relief) in +any jurisdiction. + +13.2 EXPORT RESTRICTIONS. YOU ACKNOWLEDGE THAT THE SDK IS OF U.S. ORIGIN. YOU +AGREE TO COMPLY WITH ALL APPLICABLE INTERNATIONAL AND NATIONAL LAWS THAT APPLY +TO THESE PRODUCTS, INCLUDING THE U.S. EXPORT ADMINISTRATION REGULATIONS, AS WELL +AS END-USER, END-USE AND DESTINATION RESTRICTIONS BY U.S. AND OTHER GOVERNMENTS. diff --git a/README.md b/README.md new file mode 100644 index 00000000..95a2bf6f --- /dev/null +++ b/README.md @@ -0,0 +1,80 @@ +Cloud9 3.0 SDK for Plugin Development +======================================= + +This is the core repository for the Cloud9 v3 SDK. The SDK allows you to run a version of Cloud9 that allows you to develop plugins and create a custom IDE based on Cloud9. + +#### Project Status: *ALPHA* + +During the alpha stage, expect many things to break, not work or simply fail. + +#### Creating Plugins #### + +The best and easiest way to create plugins is on c9.io. Please check out this tutorial for how to [get started writing plugins.](http://cloud9-sdk.readme.io/v0.1/docs/getting-started) + +We also have a tutorial for how to get started working on the core plugins. [Check out that tutorial here.](http://cloud9-sdk.readme.io/v0.1/docs/contributing-to-existing-packages) + +#### Documentation #### + +We have several documentation resources for you: + + + + + +
SDK documentationhttp://cloud9-sdk.readme.io/v0.1/docs
API documentationhttp://docs.c9.io/api
User documentationhttp://docs.c9.io
+ +Please joing the mailinglist to get support or give support to the growing community of plugin developers: +https://groups.google.com/forum/#!forum/cloud9-sdk + +#### Installation #### + +Follow these steps to install the SDK: + + git clone git@github.com:c9/core.git c9sdk + cd c9sdk + scripts/install-sdk.sh + +To update the SDK to the latest version run: + + git pull origin master + scripts/install-sdk.sh + +#### Starting Cloud9 #### + +Start the Cloud9 as follows: + + node server.js + +The following options can be used: + + --settings Settings file to use + --help Show command line options. + -t Start in test mode + -k Kill tmux server in test mode + -b Start the bridge server - to receive commands from the cli [default: false] + -w Workspace directory + --port Port + --debug Turn debugging on + --listen IP address of the server + --readonly Run in read only mode + --packed Whether to use the packed version. + --auth Basic Auth username:password + --collab Whether to enable collab. + --no-cache Don't use the cached version of CSS + +Now visit [http://localhost:8181/ide.html](http://localhost:8181/ide.html) to load Cloud9. + +#### Contributing #### + +We actively encourage and support contributions. We accept pull requests to the core as well as to any of the open source plugins and libraries that we maintain under the c9 organization on GitHub. + +Feel free to fork and improve/enhance the Cloud9 SDK and the open source plugins in any way you want. Then please open a pull request. For more information on our contributing guidelines, see our contributing guide: http://cloud9-sdk.readme.io/v0.1/docs/contributing-to-cloud9 + +To protect the interests of the Cloud9 contributors and users we require contributors to sign a Contributors License Agreement (CLA) before we pull the changes into the main repository. Our CLA is the simplest of agreements, requiring that the contributions you make to an ajax.org project are only those you're allowed to make. This helps us significantly reduce future legal risk for everyone involved. It is easy, helps everyone, takes ten minutes, and only needs to be completed once. There are two versions of the agreement: + +1. [The Individual CLA](https://docs.google.com/a/c9.io/forms/d/1MfmfrxqD_PNlNsuK0lC2KSelRLxGLGfh_wEcG0ijVvo/viewform): use this version if you're working on the Cloud9 SDK or open source plugins in your spare time, or can clearly claim ownership of copyright in what you'll be submitting. +2. [The Corporate CLA](https://docs.google.com/a/c9.io/forms/d/1vFejn4111GdnCNuQ6BfnJDaxdsUEMD4KCo1ayovAfu0/viewform): have your corporate lawyer review and submit this if your company is going to be contributing to the Cloud9 SDK and/or open source plugins. + +If you want to contribute to the Cloud9 SDK and/or open source plugins please go to the online form, fill it out and submit it. + +Happy coding, Cloud9 \ No newline at end of file diff --git a/bin/c9 b/bin/c9 new file mode 100755 index 00000000..32d1f9e5 --- /dev/null +++ b/bin/c9 @@ -0,0 +1,29 @@ +#!/usr/bin/env node + +// Architect +var architect = require("architect"); + +// Add ability to load AMD modules +require("amd-loader"); + +var verbose = process.argv.indexOf("--verbose") + 1 + || process.argv.indexOf("-v") + 1; + +architect.resolveConfig(require("../configs/cli.js")(), + __dirname + "/../plugins", function (err, config) { + if (err) throw err.message; + + var cli; + var app = architect.createApp(config, function(err, app){ + if (err) throw err; + + cli.start(); + }); + app.on("service", function(name, plugin){ + if (name == "cli") + cli = plugin; + + if (!plugin.name) + plugin.name = name; + }); +}); \ No newline at end of file diff --git a/bin/launch.bat b/bin/launch.bat new file mode 100644 index 00000000..9b3619d3 --- /dev/null +++ b/bin/launch.bat @@ -0,0 +1,133 @@ +:: Do not use "echo off" to not affect any child calls. +@setlocal + +::——————————————————— fix ctrl c ——————————————————— +@set allargs= +@if ("%initialized%")==("1") ( + @if "%~1"=="-fix_ctrl_c" ( + @call:rest %* allargs + ) else ( + @call Ap>qI7qsG>Cu*EdAyE`47J5 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 literal 0 HcmV?d00001 diff --git a/build/browser_extensions/chrome/manifest.json b/build/browser_extensions/chrome/manifest.json new file mode 100644 index 00000000..7939147b --- /dev/null +++ b/build/browser_extensions/chrome/manifest.json @@ -0,0 +1,25 @@ +{ + "app": { + "launch": { + "web_url": "http://c9.io/" + }, + "urls": [ + "https://c9.io/", "https://www.c9.io/", "https://ide.c9.io/", + "http://c9.io/", "http://www.c9.io/", "http://ide.c9.io/", + "https://cloud9beta.com/", "https://ide.cloud9beta.com/", + "http://localhost:8181/", "http://localhost:5252/", + "https://c9.vm:8181/", "https://c9.vm:5252/", + "https://c9.dev/", "https://ide.c9.dev/" + ] + }, + "description": "Cloud9 is an online platform for development that makes developing applications more convenient than ever", + "icons": { + "128": "icon128.png" + }, + "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqAyKPE7bHjhrCtYRSqTtEd+IYhEV/h7MgtKN1DdiZzVmqZEkLDd5p4BpBTakiktr2VT1eU2aXoHHsi5gBdSGAkglXkGoo/wKmcEZCfPCGo6wIqBO9Jxs+NQeM3lrxgaNgaHfjqKj2sY/LqN0CFAY79BqOuwE5DProUeglaFmhKwIDAQAB", + "name": "Cloud9", + "permissions": [ "clipboardRead", "clipboardWrite" ], + "update_url": "http://clients2.google.com/service/update2/crx", + "version": "3.0.0", + "manifest_version": 2 +} diff --git a/build/build-local.sh b/build/build-local.sh new file mode 100755 index 00000000..920b3a84 --- /dev/null +++ b/build/build-local.sh @@ -0,0 +1,201 @@ +#!/bin/bash -e + +while [ "$1" ]; do + case "$1" in + --compress) COMPRESS=1 ;; + --obfuscate) OBFUSCATE=1 ;; + *) echo "Unknown option: $1" >&2; exit 1 ;; + esac + shift +done + +uname="$(uname -a)" +os= +arch="$(uname -m)" +case "$uname" in + Linux\ *) os=linux ;; + Darwin\ *) os=darwin ;; + SunOS\ *) os=sunos ;; + FreeBSD\ *) os=freebsd ;; + CYGWIN*) os=windows ;; + MINGW*) os=windows ;; +esac +case "$uname" in + *x86_64*) arch=x64 ;; + *i*86*) arch=x86 ;; + *armv6l*) arch=arm-pi ;; +esac + +showStatus () { printf "\e[1A\e[0K\r%s\n" $1; } + +cd `dirname $0`/.. +SOURCE=`pwd` + +LOCAL=$SOURCE/local +APPDIR=$SOURCE/build/webkitbuilds/app.nw +LOCALCFG=configs/client-default-local.js + +# init +rm -Rf $APPDIR +rm -Rf $SOURCE/build/webkitbuilds/releases + +# copy the C9 source into the package +mkdir -p $APPDIR +mkdir -p $APPDIR/bin +mkdir -p $APPDIR/build +mkdir -p $APPDIR/configs +mkdir -p $APPDIR/plugins +mkdir -p $APPDIR/settings +mkdir -p $APPDIR/scripts +mkdir -p $APPDIR/node_modules + +cp -a build/standalone $APPDIR/build +rm -Rf $APPDIR/build/standalone/static +cp -a $SOURCE/local $APPDIR +cp -a server.js $APPDIR + +# bin +cp -a bin/c9 $APPDIR/bin + +# configs +cp configs/standalone.js $APPDIR/configs +cp configs/local.js $APPDIR/configs +cp configs/cli.js $APPDIR/configs +cp configs/client-default.js $APPDIR/configs +cp configs/client-default-local.js $APPDIR/configs + +# settings +cp settings/standalone.js $APPDIR/settings +cp settings/local.js $APPDIR/settings + +# scripts +cp -a scripts/makest* $APPDIR/scripts +cp -a scripts/install-nw-pty.sh $APPDIR/scripts +cp -a scripts/checkforupdates.sh $APPDIR/scripts + + +node -e " + var fs = require('fs'); + var path = require('path'); + var copy = require('architect-build/copy'); + + function pluginDirs(plugins) { + var map = Object.create(null); + plugins.forEach(function(p) { + p = p.packagePath || p; + if (typeof p === 'string') + map[path.dirname(p)] = 1; + }); + return Object.keys(map); + } + +console.log('Client Plugins:'); + var plugins = require('./configs/client-default-local')(require('./settings/local')()); + // this isn't included in local config but is needed for loading remote projects + plugins.push('plugins/c9.ide.collab/collab'); + copy.dirs('$SOURCE', '$APPDIR', pluginDirs(plugins), { + include: /^(libmarkdown.js|loading.css|runners_list.js|builders_list.js)$/, + exclude: /\\.(js|css|less|xml)$|^mock$/, + onDir: function(e) { console.log('\x1b[1A\x1b[0K' + e) } + }); + +console.log('CLI Plugins:'); + plugins = require('./configs/cli')().concat('plugins/c9.login.client/bootstrap') + copy.dirs('$SOURCE', '$APPDIR', pluginDirs(plugins), { + exclude: /^mock$/, + }); + +console.log('Node Modules:'); + require('architect-build/npm_build')({ + root: '.', + dest: './build/webkitbuilds/app.nw', + args: ['local','-s', 'local'], + ignore: /^(pty.js)$/ + }, function(err, result) { + var deps = result.roots; + // add client plugins + deps.push('node_modules/rusha', 'node_modules/nak'); + deps = deps.filter(function(x){ + if (!require('fs').statSync(x).isDirectory()) + return false; + return true; + }); + copy.dirs('$SOURCE', '$APPDIR', deps, { + include: null, + exclude: /^(mock|tests?|examples?|samples|Readme.*|build|dist|LICENSE|\\.(idea|grunt|jshintrc|npmignore|gitignore|travis.yml))\$|_test\\.js/i + }); + }); + +console.log('local:'); + ['index.html', 'projectManager.html'].forEach(function(p) { + copy.file('$LOCAL/' + p, '$APPDIR/local/' + p, function(source) { + return source.replace(/\/[/*]::dev:(:.*|{[\s\S]*?\/[/*]::dev:}.*)/g, ''); + }); + }); + +" + +# copy the local package json to the root +node -e "p=require('./local/package.json'); p.name = 'Cloud9'; p.main = 'local/projectManager.html'; p.revision = '$(git rev-parse HEAD)'; console.log(JSON.stringify(p, null, 2));" > $APPDIR/package.json + +# remove unneeded files +rm $APPDIR/plugins/c9.vfs.server/vfs.connect.hosted* +rm $APPDIR/plugins/c9.vfs.server/last_access.js +rm $APPDIR/plugins/c9.vfs.server/registry.js + +cp $SOURCE/plugins/c9.connect.favicon/favicon.ico $APPDIR + +# remove debug symbols +cat $LOCALCFG | sed "s/options.debug *= .*/options.debug = false/" > $APPDIR/$LOCALCFG +cat $SOURCE/settings/local.js | sed "s/config.packed = false;/config.dev = false;config.packed = true;/" > $APPDIR/settings/local.js + +# set version +date +%s > $APPDIR/version + +# set nw version +NWVERSION=0.9.3 +echo $NWVERSION > $APPDIR/nwversion + +if [ "$COMPRESS" ]; then + if [ "$OBFUSCATE" ]; then + OPTS="{ obfuscate: true }" + else + OPTS="{}" + fi + node -e "require('architect-build/compress_folder')('$APPDIR', '$OPTS')" +fi + + + + +if [[ $os == "windows" ]]; then + echo done! +elif [ $os == "darwin" ]; then + if [ ! -d $SOURCE/build/webkitbuilds/cache/mac/$NWVERSION ]; then + mkdir -p $SOURCE/build/webkitbuilds/cache/mac/$NWVERSION/node-webkit.app + pushd $SOURCE/build/webkitbuilds/cache/mac/$NWVERSION + curl -O http://dl.node-webkit.org/v$NWVERSION/node-webkit-v$NWVERSION-pre8-osx-ia32.zip + unzip node-webkit-v$NWVERSION-pre8-osx-ia32.zip + popd + fi + + DEST="$SOURCE/build/webkitbuilds/releases/Cloud9/mac/Cloud9.app" + RES="$DEST/Contents/Resources" + + rm -rf "$DEST" + mkdir -p "$RES" + + cp -R $SOURCE/build/webkitbuilds/cache/mac/$NWVERSION/node-webkit.app/* $DEST + + cp -R "$SOURCE/build/webkitbuilds/app.nw" "$RES" + + # copy Infoplist + cat $SOURCE/local/Info.plist > $DEST/Contents/Info.plist + # copy icons + rm $DEST/Contents/Resources/nw.icns + cp $SOURCE/build/osx/c9.icns $DEST/Contents/Resources/nw.icns + # make cli executable + chmod +x $RES/app.nw/bin/c9 +else + echo TODO +fi diff --git a/build/build-standalone.sh b/build/build-standalone.sh new file mode 100755 index 00000000..37e1100c --- /dev/null +++ b/build/build-standalone.sh @@ -0,0 +1,145 @@ +#!/bin/bash -e + +while [ "$1" ]; do + case "$1" in + --compress) COMPRESS=1 ;; + --obfuscate) OBFUSCATE=1 ;; + *) echo "Unknown option: $1" >&2; exit 1 ;; + esac + shift +done + +uname="$(uname -a)" +os= +arch="$(uname -m)" +case "$uname" in + Linux\ *) os=linux ;; + Darwin\ *) os=darwin ;; + SunOS\ *) os=sunos ;; + FreeBSD\ *) os=freebsd ;; + CYGWIN*) os=windows ;; + MINGW*) os=windows ;; +esac +case "$uname" in + *x86_64*) arch=x64 ;; + *i*86*) arch=x86 ;; + *armv6l*) arch=arm-pi ;; +esac + +showStatus () { printf "\e[1A\e[0K\r%s\n" $1; } + +cd `dirname $0`/.. +SOURCE=`pwd` + +APPDIR=$SOURCE/build/standalonebuild + +# init +rm -Rf $APPDIR +rm -Rf $SOURCE/build/webkitbuilds/releases + +# copy the C9 source into the package +mkdir -p $APPDIR +mkdir -p $APPDIR/bin +mkdir -p $APPDIR/build +mkdir -p $APPDIR/configs +mkdir -p $APPDIR/plugins +mkdir -p $APPDIR/settings +mkdir -p $APPDIR/scripts +mkdir -p $APPDIR/node_modules + +cp -a build/standalone $APPDIR/build +cp -a server.js $APPDIR + +# bin +cp -a bin/c9 $APPDIR/bin + +# configs +cp configs/standalone.js $APPDIR/configs +cp configs/cli.js $APPDIR/configs +cp configs/client-default.js $APPDIR/configs + +# settings +cp settings/standalone.js $APPDIR/settings + +# scripts +cp -a scripts/makest* $APPDIR/scripts + + +node -e " + var fs = require('fs'); + var path = require('path'); + var copy = require('architect-build/copy'); + + function pluginDirs(plugins) { + var map = Object.create(null); + plugins.forEach(function(p) { + p = p.packagePath || p; + if (typeof p === 'string') + map[path.dirname(p)] = 1; + }); + return Object.keys(map); + } + +console.log('Client Plugins:'); + var plugins = require('./configs/client-default')(require('./settings/standalone')()); + copy.dirs('$SOURCE', '$APPDIR', pluginDirs(plugins), { + include: /^(libmarkdown.js|loading.css|runners_list.js|builders_list.js)$/, + exclude: /\\.(js|css|less|xml)$|^mock$/, + onDir: function(e) { console.log('\x1b[1A\x1b[0K' + e) } + }); + +console.log('CLI Plugins:'); + plugins = require('./configs/cli'); + copy.dirs('$SOURCE', '$APPDIR', pluginDirs(plugins), { + exclude: /^mock$/, + }); + +console.log('Node Modules:'); + require('architect-build/npm_build')({ + root: '.', + dest: '$APPDIR', + args: [], + ignore: /^(pty.js)$|c9.ide.language.jsonalyzer/ + }, function(err, result) { + var deps = result.roots; + // add client plugins + deps.push('node_modules/rusha', 'node_modules/nak'); + deps = deps.filter(function(x){ + if (!require('fs').statSync(x).isDirectory()) + return false; + return true; + }); + // console.log(deps) + copy.dirs('$SOURCE', '$APPDIR', deps, { + include: null, + exclude: /^(mock|tests?|examples?|samples|Readme.*|build|dist|\.(idea|grunt|jshintrc|npmignore|gitignore|travis.yml))$/i + }); + }); +" + +# add package.json +node -e "p=require('./package.json'); p.name = 'Cloud9'; p.revision = '$(git rev-parse HEAD)'; console.log(JSON.stringify(p, null, 2));" > $APPDIR/package.json + + +# remove unneeded files +rm -f $APPDIR/plugins/c9.vfs.server/vfs.connect.hosted* +rm -f $APPDIR/plugins/c9.vfs.server/last_access.js +rm -f $APPDIR/plugins/c9.vfs.server/registry.js + +cp $SOURCE/plugins/c9.connect.favicon/favicon.ico $APPDIR + +# remove debug symbols +cat $SOURCE/settings/standalone.js | sed "s/packed: false,/packed: true,/" | sed "s/collab: true,/collab: false,/" > $APPDIR/settings/standalone.js + +# set version +date +%s > $APPDIR/version + +# compress +if [ "$COMPRESS" ]; then + if [ "$OBFUSCATE" ]; then + OPTS="{ obfuscate: true }" + else + OPTS="" + fi + node -e "require('architect-build/compress_folder')('$APPDIR', '$OPTS')" +fi diff --git a/build/osx/c9.icns b/build/osx/c9.icns new file mode 100644 index 0000000000000000000000000000000000000000..bc4cf70a2aba5ae65f59dcaa11059a5923a262d5 GIT binary patch literal 126811 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,^X~SyhBhYe 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 WS(x0Q@9*nqo6m9hu^RV?fBXmJ`g#BW literal 0 HcmV?d00001 diff --git a/build/win32/Cloud9.ico b/build/win32/Cloud9.ico new file mode 100644 index 0000000000000000000000000000000000000000..1d8ac5d81128be8af0394b2beeb0f883ee54106f GIT binary patch literal 32038 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 Ucy++511;47%s0Kq|6>XKF9iHn-v9sr literal 0 HcmV?d00001 diff --git a/build/win32/icon.png b/build/win32/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..e0480ac808dbf6d3f62eb996572d6c83747cf46b GIT binary patch literal 4314 zcmbVQc{r5q_a8!bS+l*25y>`-b*8b686_c0Vyt5f#x~Q;U~FZJEQwT9c9s3LM3F2Z zYLX=?6&j>OqU>9K<9+M>eSg>WUf(}{_w_u_y*%f9&N-j^oa?@xC+U>cF#%p_UH||f zV168J%j%8yZf-8tvz&N#oYhIuFpe}kk~b|BM}XF~|V4(A)+B61@ySXLKwf zmSj_cFY$OdgdI=Z@0bs!7^g@GZgOIHJ`jnL6W!1RE> z8i-|$;^mF7MVtMy#hMv_d}%Z?0t^lf4b=?Q(j-xQz)(0GzJ~#WX|Nb!z$npkZO(C*21s8xO;e!JS zK{Ru;0f_ZR(~IbZfN1HnSk%*o=)oYm`cNobU)KaFJ{3TH3!c{!LdOt_?BO z#+blSFg+*~qh+FFq7TPFF=h}`6Bq=e^IO+Eh)Tl+;R(O(5?OYC>B9f3F2a;Tz|lw) zdlD(&cLtpDCDBM!UlJK;YNrcSvBcqtL3;~F_BQD6c+mt3F@)e{Mj-_P|6&+H{1*?* z;Cg2NCvq4H0>{A6XbcJh(?ywre(8Gse^>*voB{8p$A6^D?%dg?J2r_}!DTKqJ$;tAUFJBUusTTefpI<&n(fHh#>)%M3J|UVXVYabb zRO1JuhTDX=`E=Au$djVEX}pegD$2N>aqv=mi;@Fkim_vefK=Yc7_KOJ2T;H zzdtvKBiDoh?j9V8nOclYW4n$wNr8fkI^;5pIUZo$;(8o6Byl`m&S3*@D{FSzT#bv~ z$TYULw#w>hm1&JuPBcQrO8U%yEG^|4b=sVEjatiLFlHyOTp?x;qvVEpOY zZ0K}9;O&nIQEeK1@aChOk42>y`49G8Y!a%MjX9cY<}1VB2~mT2|z(LJAjU8`I~u+5n>XZD@@iV;4%4{#+nH_#Nel<1Qmbze~GhQTXy z@oDkX4Gj%y)AH%rJ_T2B!tZu$$XI^K+vt!`DXY=ONSveHxA?7;`E0R$irY!BX#Rea*4*a0fL zVy3s{&5EJlycIPHg)Xos9kq5oe;_;#G}4Rwsj2!wSe)%eP8GfY(XW#4bTcqs>4^iq z?FnC)w+2>TR5TXzy-tdrqj)!EGQHM$q;C2}Q(^j|)#=mM_8IwoF+hVdjP2~~dd6EK zjNZ0JZRrM7_6=GHHaFE$0obUW2>sF@_FuA7XH<`*2^Hig7B5GbYX;jxXWuO!jZ0w5 z^;S85l^|oBvQ{$W8+~q`?^t1{OoCdR@cN`Pc%6Nskqg>1mG(Aac6L_Q-bF?W5FT4w zROG2V{uBF=Utnu(!6?444pLYqEfXC)_qwHqt;bhFzP})-TBT~V#$}b9So{nu8S|5Q zYQ+1CBlj`%`d#;Evn)W?DXf9QhU{e^3cx0n79B5oS(#SpSUcI8mX>Di=jZ3vbs1iU zG~|g^vbe7PzVYmoyFy53=PCK>0o<^v_;uy`rIB`w>%|h?UyUT?*nu)lG4Bt?Qs2Z5 zfYAgyDQ!oM1L}y&ZqLg%FYjKa2&iVuXv?49{+=%v_A$d~N^C zWUOQLR6Xs#=k41sxE(V7C~S_b2Oboi1PoVIRD_Pq3nm?(s?$;^R!qmgGHJcAzYRM% zP%sc1v_mKn;sWsp1kEJGeSSAh6>|S}!P{DLE5^%B8GQ&2W&gx=)8c9T&-5cnyxfPa zav}x4AT-`M)#e;%n|x0qMaWnr$6@m!_{Md|Cbr93$Cs6?=V0cCC_90g#u0_3i?^JVG9j|{vOP7@-&Pe9 zg@(KtnA!{jkHI30(2E==Eb=zf7d5FAcqpl9d%Mic_nT1rv%Y8-@!m%w{ljB{2tk^I zOysO*d%skBtTx=nz@a$31XSVhLdh0cW@TSG=C(b>N8pN^VADAQg8|g!qiEt|FXod zK+2olt}94k9t`M*0rI}zE8cgl11@TZ;~2>dcyfOFZND2|$zCUgQkAsKTY&Q`Z@`-I zR&Cr7=`+1%;r`Q3E3)bShSQP!)SZ(ClA3KQu*ZQ;$|uOc+-fNBTHg~(;SULPl_?hF-fSNJauip#rTp7@5D%GMkm_KY3&kjX*b z;~L9%hz@IFV0|UGyb{daKf5_Ncsqy|X4sv^PpOul%A8xVE^4X0C+TOpEpX{f6AY4M z$rk+v9L@RMaV(a7{ly<_`tQ}AisN`~KR)PdoN%<}zALHCQ!gFi@{yfyNuZ{#m#0Y5 z!A1YlWu6ljKC|`!8VoSw343!$L~7{Ai47U{xGMrSSG>;1C7q4nob3>?>gX_wsjlK7St6t`DK1C~!3@NdQ@o8EzPKpuP2U}nP?d|ox&CtVXOaI|5a zWJyVBT~#I)N|raZ-zpt`HjFyFn1Gfv?oK@3`6@^+G8wt6+sx*gmvO-q7>*LzK9rbv z^NR#`BF8lLP!#G|L_`F~TIY9F^7=p_*OMakE^hMVg+!6}2P8qNRy<~3k;I&$c%GE8 z{QZa`>6)S~JD~#5S!wRcNByVuA75M^Iebx1dyO8S#&=MY+b>Hp!_?zLYgF@S)D9S) zE0}9^;G`p8%-lN{=@t91+07FRhK3L9q_JE%x&}GKZwcpv6AJYEHMRCTcqj8K9~bs3 zkztOrE7DsOHqKnRYWN{bR6DKu*3Ioko&le9*qR7Op+Lm0C`Br>=!gr#DjKSos30Of zMWc_#ChJ2cZyp_86j3&M=J`0Mz%j4q1hYFrZCI3k?z*KL7hke1)-|8kl~y>_(h}i( zcF4NLSSkO&Is8z!-gE+{+M3l!7yCu9 zgF}b7SUhmTbPK}?Ab)cRKxZ|~xm{HD_Tq8~X5B8dktBu@n>G-oSWM0T< z(_G}na5oNsr|;>{+@@sHy;wQ zbaJ`eMjJPWN9?8bv!be(W z?dI_NIh;b&DzPn_vt@QAhIaYtuEsomA`~%!{R_GM+wp$EvzwMlYEOE( zEpr`QbyaElvTc=BRZ(9_x5i6hI8b5n`!OK}ll0EmjXZa^q=sjeTvJFjwN{BHTxUYw zi(3!0!;w2aGxwaX4qaUqbXWE<`x4+348L(@?R}Ml|BJfm=kji}-JJ{8hE2*n0ru?$ zsqOLyYNV1GcCgIki<4^g?ggHZMf2y6_8V=6GMO<#tn>K8`G%^h`PA82_X?hBwFx*# zs()x=1nL%L@T78e03(qy{f)t3z?VLOvqL_+hQhtCy@1_RmuR|ug0>U*65{dkibNW^ zePIpb?2PUF5IOeIi2A7_W~jtEG&DF^XUaUcyzUQ`52Y)4ur}Xvf}nS=nqc6O5oK}y zS*fO3-Z`=Qa5ik0W@1{Mp|SE1AEa5d;l}rJM%ZcZ&kp(GtL6DSoq2MZNv-mb?MIFc zHKoqEyuA5E8QGNzWex&msHT?7uS0ZT&wP`umpPMaDczwfR`TY6nA9TRjZ%~-+sCc& zdzno(ceE6RTY7h;o1Yx}&rgkXHs -1 + ? "http://" + APIHOST + : "https://" + APIHOST; +var AUTHURL = APIHOST.indexOf("localhost") > -1 + ? "http://" + APIHOST + : "https://" + APIHOST.replace(/api\./, ""); + +return [ + "./c9.core/ext", + { + packagePath: "./c9.fs/fs", + baseProc: process.cwd(), + cli: true + }, + { + packagePath: "./c9.fs/net" + }, + { + packagePath: "./c9.fs/proc", + baseProc: process.cwd() + }, + "./c9.vfs.client/vfs.cli", + "./c9.cli/cli", + { + packagePath: "./c9.cli/auth.bootstrap", + authUrl: AUTHURL + }, + { + packagePath: "./c9.cli.publish/publish", + projectId: PID, + apiHost: APIHOST + }, + { + packagePath: "./c9.ide.auth/auth", + accessToken: "token", + ideBaseUrl: "", + apiUrl: APIURL + // userId: process.env.C9_USER + }, + { + packagePath: "./c9.core/api", + apiUrl: APIURL, + projectId: PID + }, + { + packagePath: "./c9.core/http-node" + // debug: !options.packed + }, + { + packagePath: "./c9.cli.bridge/bridge-client", + port: 17123 + }, + // "./c9.cli.mount/mount", + { + packagePath: "./c9.cli.open/open", + platform: process.platform + }, + { + packagePath: "./c9.cli.open/restart", + platform: process.platform + }, + // "./c9.cli.sync/sync", + //"./c9.ide.keys/commands", + { + consumes: [], + provides: ["settings", "workspace", "cli_commands", "c9"], + setup: function(options, imports, register) { + register(null, { + // @todo share with ace min + c9 : { + startdate: new Date(), + debug: true, + hosted: false, + local: true, + setStatus: function(){} + }, + workspace: (function(){ + var ws = new EventEmitter(); + ws.connect = function(name, callback) { + callback(null, { + hostname: "54.242.22.91", + username: "ubuntu", + rootPath: "/home/ubuntu/newclient/", + setupSshConnection: function(callback) { + callback(); + } + }); + }; + return ws; + })(), + cli_commands: (function(){ + var cmds = new EventEmitter(); + var commands = {}; + cmds.commands = commands; + cmds.addCommand = function(def) { + commands[def.name] = def; + }; + cmds.exec = function(name, args) { + if (!commands[name]) + throw new Error("Unknown command: " + name); + commands[name].exec(args); + }; + return cmds; + })(), + http: new EventEmitter(), + settings: (function(){ + var settings = new EventEmitter(); + var data = {}; + + settings.migrate = function(){}; + settings.setDefaults = function(type, def) { + var props = {}; + def.forEach(function(d){ props[d[0]] = d[1] }); + data[type] = props; + }; + + settings.getBool = function(p) { + return settings.get(p) == "true"; + }; + settings.get = function(p) { + var type = p.substr(0, p.lastIndexOf("/")); + var prop = p.substr(p.lastIndexOf("/") + 2); + return data[type] && data[type][prop] || ""; + }; + settings.getJson = function(p) { + try { + return JSON.parse(settings.get(p)); + }catch(e){ return false } + }; + settings.getNumber = function(p) { + return Number(settings.get(p)); + }; + + settings.emit("read"); + settings.on("newListener", function(event, listener) { + if (event == "read") listener(); + }); + + return settings; + })(), + auth: { + + } + }); + } + } +]; + +}; + +if (!module.parent) require("../server")([__filename].concat(process.argv.slice(2))); \ No newline at end of file diff --git a/configs/client-default.js b/configs/client-default.js new file mode 100644 index 00000000..3ad103b1 --- /dev/null +++ b/configs/client-default.js @@ -0,0 +1,689 @@ +var assert = require("assert"); + + +module.exports = function(options) { + assert(options.staticPrefix, "Option 'staticPrefix' must be set"); + assert(options.workspaceDir, "Option 'workspaceDir' must be set"); + assert(options.workspaceId, "Option 'workspaceId' must be set"); + assert(options.workspaceName, "Option 'workspaceName' must be set"); + assert(options.home, "Option 'home' must be set"); + assert(options.platform, "Option 'platform' must be set"); + + var workspaceDir = options.workspaceDir; + var debug = options.debug !== undefined ? options.debug : false; + var collab = options.collab; + var packaging = options.packaging; + var staticPrefix = options.staticPrefix; + var ssh = options.ssh; + + var nodeBin = options.nodeBin || ["node"]; + var nodePath = options.nodePath || ""; + + var runners = options.runners || {}; + var builders = options.builders || {}; + var hosted = !options.local && !options.dev; + var devel = options.standalone && !options.local || options.mode === "devel" || options.dev; + + var localExtendFiles = options.localExtend || options.standalone; + // allow extend code access only to C9-deveoped plugins + var extendToken = options.extendToken || "token"; + + var plugins = [ + // C9 + { + packagePath: "plugins/c9.core/c9", + + startdate: new Date(), + version: options.manifest.version + " (" + options.manifest.revision + ")", + debug: debug, + workspaceId: options.workspaceId, + workspaceDir: workspaceDir, + name: options.workspaceName, + readonly: options.readonly, + isAdmin: options.isAdmin, + staticUrl: staticPrefix, + hosted: hosted, + hostname: options.appHostname, + local: options.local, + env: options.env || "devel", + home: options.home, + platform: options.platform, + installed: options.installed, + projectId: options.project.id, + projectName: options.projectName || "Project", + configName: options.configName, + standalone: options.standalone + }, + { + packagePath: "plugins/c9.core/settings", + settings: options.settings, + userConfigPath: options.settingDir, + hosted: hosted + }, + "plugins/c9.core/ext", + { + packagePath: "plugins/c9.core/http-xhr", + debug: !options.packed + }, + // { + // packagePath: "plugins/c9.core/client", + // baseUrl: options.apiUrl + // }, + "plugins/c9.core/util", + { + packagePath: "plugins/c9.ide.plugins/loader", + plugins: options.plugins || [] + }, + { + packagePath: "plugins/c9.ide.plugins/installer", + updates: options.pluginUpdates || [] + }, + { + packagePath: "plugins/c9.ide.plugins/manager", + staticPrefix: staticPrefix + "/plugins/c9.ide.plugins" + }, + { + packagePath: "plugins/c9.ide.plugins/debug" + }, + { + packagePath: "plugins/c9.ide.plugins/market" + }, + + // VFS + "plugins/c9.vfs.client/vfs.ping", + { + packagePath: "plugins/c9.vfs.client/vfs_client", + withInstall: false, + debug: debug, + installPath: options.installPath, + dashboardUrl: options.dashboardUrl, + accountUrl: options.accountUrl + }, + { + packagePath: "plugins/c9.vfs.client/endpoint", + readonly: options.readonly, + region: options.region, + pid: options.project.id, + servers: options.vfsServers, + updateServers: hosted + }, + { + packagePath: "plugins/c9.ide.auth/auth", + accessToken: options.accessToken || "token", + ideBaseUrl: options.ideBaseUrl, + apiUrl: options.apiUrl, + userId: options.user.id + }, + { + packagePath: "plugins/c9.core/api", + apiUrl: options.apiUrl, + projectId: options.project.id + }, + + // Editors + "plugins/c9.ide.editors/document", + { + packagePath: "plugins/c9.ide.editors/editors", + defaultEditor: "ace" + }, + "plugins/c9.ide.editors/editor", + "plugins/c9.ide.editors/imgview", + { + packagePath: "plugins/c9.ide.imgeditor/imgeditor", + staticPrefix: staticPrefix + "/plugins/c9.ide.imgeditor" + }, + "plugins/c9.ide.editors/urlview", + // "plugins/c9.ide.editors/htmlview", + "plugins/c9.ide.editors/tab", + { + packagePath: "plugins/c9.ide.editors/tabmanager", + loadFilesAtInit: false + }, + { + packagePath: "plugins/c9.ide.editors/metadata" + }, + "plugins/c9.ide.editors/pane", + "plugins/c9.ide.editors/undomanager", + + "plugins/c9.ide.newresource/newresource", + "plugins/c9.ide.newresource/open", + "plugins/c9.ide.undo/undo", + { + packagePath: "plugins/c9.ide.closeconfirmation/closeconfirmation", + defaultValue: options.local + }, + { + packagePath: "plugins/c9.ide.openfiles/openfiles", + staticPrefix: staticPrefix + "/plugins/c9.ide.layout.classic", + defaultShow: options.local + }, + + // Ace && Commands + "plugins/c9.ide.keys/commands", + "plugins/c9.ide.keys/editor", + { + packagePath: "plugins/c9.ide.ace/ace", + staticPrefix: staticPrefix + "/plugins/c9.ide.layout.classic", + workerPrefix: options.workerPrefix + }, + "plugins/c9.ide.ace/themes", + "plugins/c9.ide.ace.stripws/stripws", + "plugins/c9.ide.ace.repl/editor", + // "plugins/c9.ide.ace.split/split", + { + packagePath: "plugins/c9.ide.ace.gotoline/gotoline", + staticPrefix: staticPrefix + "/plugins/c9.ide.ace.gotoline" + }, + { + packagePath: "plugins/c9.ide.ace.statusbar/statusbar", + staticPrefix: staticPrefix + "/plugins/c9.ide.layout.classic" + }, + "plugins/c9.ide.ace.keymaps/keymaps", + "plugins/c9.ide.ace.keymaps/cli", + + + "plugins/c9.ide.ace.emmet/emmet", + // Find + { + packagePath: "plugins/c9.ide.find/find", + basePath: workspaceDir + }, + { + packagePath: "plugins/c9.ide.find/find.nak", + ignore: "", + useHttp: true, + basePath: workspaceDir, + installPath: options.installPath, + nak: options.nakBin || "~/.c9/node_modules/nak/bin/nak", + node: options.nodeBin, + local: options.local, + installPath: options.installPath + }, + { + packagePath: "plugins/c9.ide.find.infiles/findinfiles", + staticPrefix: staticPrefix + "/plugins/c9.ide.find.infiles" + }, + { + packagePath: "plugins/c9.ide.find.replace/findreplace", + staticPrefix: staticPrefix + "/plugins/c9.ide.find.replace" + }, + + // UI + { + packagePath: "plugins/c9.ide.ui/ui", + staticPrefix: staticPrefix + "/plugins/c9.ide.ui" + }, + "plugins/c9.ide.ui/anims", + "plugins/c9.ide.ui/tooltip", + { + packagePath: "plugins/c9.ide.ui/menus", + autoInit: !options.local + }, + "plugins/c9.ide.ui/forms", + "plugins/c9.ide.ui/focus", + "plugins/c9.ide.ui/lib_apf", + + "plugins/c9.ide.dialog/dialog", + "plugins/c9.ide.dialog.common/alert", + "plugins/c9.ide.dialog.common/alert_internal", + "plugins/c9.ide.dialog.common/confirm", + "plugins/c9.ide.dialog.common/filechange", + "plugins/c9.ide.dialog.common/fileoverwrite", + "plugins/c9.ide.dialog.common/fileremove", + "plugins/c9.ide.dialog.common/question", + { + packagePath: "plugins/c9.ide.dialog.common/error", + staticPrefix: staticPrefix + "/plugins/c9.ide.layout.classic" + }, + { + packagePath: "plugins/c9.ide.dialog.common/notification", + staticPrefix: staticPrefix + "/plugins/c9.ide.layout.classic" + }, + { + packagePath: "plugins/c9.ide.dialog.login/login", + noLogout: !options.local + }, + "plugins/c9.ide.dialog.file/filesave", + "plugins/c9.ide.dialog.wizard/wizard", + + // VFS + "plugins/c9.fs/proc", + "plugins/c9.fs/proc.apigen", + "plugins/c9.fs/net", + { + packagePath: "plugins/c9.fs/fs", + baseProc: workspaceDir + }, + "plugins/c9.fs/fs.errors", + "plugins/c9.fs/fs.cache.xml", + { + packagePath: "plugins/c9.ide.readonly/access_control", + dashboardUrl: options.dashboardUrl, + readonly: options.readonly + }, + + // Watcher + "plugins/c9.ide.threewaymerge/threewaymerge", + "plugins/c9.ide.watcher/watcher", + { + packagePath: "plugins/c9.ide.watcher/gui", + collab: collab + }, + + // Language + { + packagePath: "plugins/c9.ide.language/language", + workspaceDir: workspaceDir, + workerPrefix: options.CORSWorkerPrefix // "/static/standalone/worker" + }, + "plugins/c9.ide.language/keyhandler", + "plugins/c9.ide.language/complete", + "plugins/c9.ide.language/marker", + "plugins/c9.ide.language/refactor", + "plugins/c9.ide.language/tooltip", + "plugins/c9.ide.language/jumptodef", + "plugins/c9.ide.language/worker_util_helper", + "plugins/c9.ide.language.generic/generic", + "plugins/c9.ide.language.css/css", + "plugins/c9.ide.language.html/html", + "plugins/c9.ide.language.javascript/javascript", + "plugins/c9.ide.language.javascript.immediate/immediate", + "plugins/c9.ide.language.javascript.infer/jsinfer", + "plugins/c9.ide.language.javascript.tern/tern", + "plugins/c9.ide.language.javascript.tern/architect_resolver", + "plugins/c9.ide.language.javascript.eslint/eslint", + { + packagePath: "plugins/c9.ide.language.jsonalyzer/jsonalyzer", + extendToken: extendToken, + workspaceDir: workspaceDir, + homeDir: options.home, + bashBin: options.bashBin, + useCollab: collab, + useSend: !collab && (options.local || options.standalone), + maxServerCallInterval: 2000 + }, + + // Run + { + packagePath: "plugins/c9.ide.run/run", + base: workspaceDir, + staticPrefix: staticPrefix + "/plugins/c9.ide.run", + tmux: options.tmux, + runners: runners, + installPath: options.correctedInstallPath, + local: options.local + }, + { + packagePath: "plugins/c9.ide.run/gui", + staticPrefix: staticPrefix + "/plugins/c9.ide.layout.classic", + defaultConfigs: {} + }, + { + packagePath: "plugins/c9.ide.run.build/build", + base: workspaceDir, + builders: builders + }, + { + packagePath: "plugins/c9.ide.run.build/gui" + }, + // "plugins/c9.ide.run.debug/debuggers/sourcemap", + { + packagePath: "plugins/c9.ide.run.debug/debuggers/debugger", + staticPrefix: staticPrefix + "/plugins/c9.ide.layout.classic" + }, + { + packagePath: "plugins/c9.ide.run.debug/debuggers/v8/v8debugger", + basePath: workspaceDir + }, + { + packagePath: "plugins/c9.ide.run.debug/debuggers/socket", + nodeBin: nodeBin + }, + "plugins/c9.ide.run.debug/breakpoints", + "plugins/c9.ide.run.debug/debugpanel", + "plugins/c9.ide.run.debug/callstack", + { + packagePath: "plugins/c9.ide.immediate/immediate", + staticPrefix: staticPrefix + "/plugins/c9.ide.layout.classic" + }, + "plugins/c9.ide.immediate/evaluator", + "plugins/c9.ide.immediate/evaluators/browserjs", + "plugins/c9.ide.immediate/evaluators/debugnode", + "plugins/c9.ide.run.debug/variables", + "plugins/c9.ide.run.debug/watches", + "plugins/c9.ide.run.debug/liveinspect", + + // Console + { + packagePath: "plugins/c9.ide.terminal/terminal", + tmux: options.tmux, + root: workspaceDir, + tmpdir: options.tmpdir, + shell: options.shell || "", + staticPrefix: staticPrefix + "/plugins/c9.ide.terminal", + installPath: options.correctedInstallPath + }, + { + packagePath: "plugins/c9.ide.terminal/predict_echo" + }, + { + packagePath: "plugins/c9.ide.terminal/link_handler", + previewUrl: options.previewUrl + }, + { + packagePath: "plugins/c9.ide.terminal.monitor/monitor", + bashBin: options.bashBin + }, + { + packagePath: "plugins/c9.ide.terminal.monitor/message_view", + staticPrefix: options.staticPrefix + "/plugins/c9.ide.layout.classic" + }, + "plugins/c9.ide.terminal/opentermhere", + { + packagePath: "plugins/c9.ide.run/output", + staticPrefix: options.staticPrefix + "/plugins/c9.ide.layout.classic", + tmux: options.tmux, + basePath: workspaceDir + }, + { + packagePath: "plugins/c9.ide.console/console", + staticPrefix: staticPrefix + "/plugins/c9.ide.layout.classic" + }, + + // Layout & Panels + { + packagePath: "plugins/c9.ide.layout.classic/layout", + staticPrefix: staticPrefix + "/plugins/c9.ide.layout.classic", + dashboardUrl: options.dashboardUrl, + cdn: options.useCdn + }, + "plugins/c9.ide.theme.flat/flat-light", + { + packagePath: "plugins/c9.ide.layout.classic/preload", + themePrefix: options.themePrefix + }, + { + packagePath: "plugins/c9.ide.tree/tree", + staticPrefix: staticPrefix + "/plugins/c9.ide.layout.classic", + defaultExpanded: true + }, + { + packagePath: "plugins/c9.ide.tree/favorites", + startEmpty: options.local, + alwaysScope: options.local, + realRoot: true, + home: options.local ? options.home : "~" + }, + "plugins/c9.ide.mount/mount", + { + packagePath: "plugins/c9.ide.mount/ftp", + curlftpfsBin: options.mount.curlftpfsBin, + fusermountBin: options.mount.fusermountBin + }, + { + packagePath: "plugins/c9.ide.mount/sftp", + sshfsBin: options.mount.sshfsBin, + fusermountBin: options.mount.fusermountBin + }, + { + packagePath: "plugins/c9.ide.upload/dragdrop", + treeAsPane: options.local + }, + { + packagePath: "plugins/c9.ide.upload/upload", + staticPrefix: staticPrefix + "/plugins/c9.ide.upload" + }, + { + packagePath: "plugins/c9.ide.upload/upload_manager", + workerPrefix: "plugins/c9.ide.upload" + }, + { + packagePath: "plugins/c9.ide.upload/upload_progress", + staticPrefix: staticPrefix + "/plugins/c9.ide.layout.classic" + }, + { + packagePath: "plugins/c9.ide.navigate/navigate", + loadListAtInit: false + }, + { + packagePath: "plugins/c9.ide.keys/panel" + }, + { + packagePath: "plugins/c9.ide.language/outline", + staticPrefix: staticPrefix + "/plugins/c9.ide.language" + }, + { + packagePath: "plugins/c9.ide.panels/panels", + staticPrefix: staticPrefix + "/plugins/c9.ide.layout.classic", + defaultActiveLeft: "tree" + }, + "plugins/c9.ide.panels/panel", + "plugins/c9.ide.panels/area", + "plugins/c9.ide.installer/installer_mock", + + // Previewer + { + packagePath: "plugins/c9.ide.preview/preview", + staticPrefix: staticPrefix + "/plugins/c9.ide.preview", + defaultPreviewer: "preview.browser", + previewUrl: options.previewUrl, + local: options.local + }, + "plugins/c9.ide.preview/previewer", + "plugins/c9.ide.preview/previewers/raw", + { + packagePath: "plugins/c9.ide.preview.browser/browser", + local: options.local + }, + { + packagePath: "plugins/c9.ide.preview.markdown/markdown", + staticPrefix: staticPrefix, + htmlPath: "/plugins/c9.ide.preview.markdown/markdown.html", + local: options.local + }, + "plugins/c9.ide.remote/manager", + "plugins/c9.ide.remote/documents/htmldocument", + "plugins/c9.ide.remote/documents/cssdocument", + "plugins/c9.ide.remote/documents/jsdocument", + { + packagePath: "plugins/c9.ide.remote/transports/postmessage", + previewBaseUrl: options.previewBaseUrl + }, + // "plugins/c9.ide.remote/transports/debugger", + // "plugins/c9.ide.remote/transports/websocket", + + // Formatters + "plugins/c9.ide.format/format", + "plugins/c9.ide.format/formatters/jsbeautify", + + // Other + { + packagePath: "plugins/c9.ide.info/info", + installPath: options.installPath, + user: { + id: options.user.id, + name: options.user.name, + fullname: options.user.fullname, + email: options.user.email, + pubkey: options.user.pubkey, + date_add: options.user.date_add, + active: options.user.active, + alpha: options.user.alpha, + beta: options.user.beta, + c9version: options.user.c9version, + no_newsletter: options.user.no_newsletter, + subscription_on_signup: options.user.subscription_on_signup, + premium: options.user.premium, + region: options.user.region + }, + project: { + id: options.project.id, + name: options.project.name, + contents: options.project.contents, + descr: options.project.descr, + remote: options.project.remote + } + }, + { + packagePath: "plugins/c9.ide.welcome/welcome", + staticPrefix: staticPrefix + "/plugins/c9.ide.welcome", + intro: "Welcome to Cloud9. Use this welcome screen " + + "to tweak the look & feel of the Cloud9 user interface. ", + checkOS: true + }, + { + packagePath: "plugins/c9.cli.bridge/bridge", + port: 17123, + startBridge: options.startBridge + }, + { + packagePath: "plugins/c9.cli.bridge/bridge_commands", + basePath: workspaceDir + }, + { + packagePath: "plugins/c9.ide.help.support/support", + baseurl: options.ideBaseUrl, + userSnapApiKey: options.support.userSnapApiKey, + screenshotSupport: true + }, + { + packagePath: "plugins/c9.ide.help/help", + staticPrefix: staticPrefix + "/plugins/c9.ide.help" + }, + { + packagePath: "plugins/c9.ide.configuration/configure" + }, + "plugins/c9.ide.save/save", + "plugins/c9.ide.recentfiles/recentfiles", + { + packagePath: "plugins/c9.ide.save/autosave" + }, + { + packagePath: "plugins/c9.ide.clipboard/clipboard", + local: options.local + }, + { + packagePath: "plugins/c9.ide.clipboard/html5" + }, + "plugins/c9.ide.behaviors/tabs", + // { + // packagePath: "plugins/c9.ide.behaviors/dashboard", + // staticPrefix : staticPrefix + "/plugins/c9.ide.behaviors" + // }, + { + packagePath: "plugins/c9.ide.behaviors/page", + staticPrefix: staticPrefix + "/plugins/c9.ide.behaviors" + }, + "plugins/c9.ide.browsersupport/browsersupport", + { + packagePath: "plugins/c9.ide.preferences/preferences", + staticPrefix: staticPrefix + "/plugins/c9.ide.preferences" + }, + "plugins/c9.ide.preferences/preferencepanel", + { + packagePath: "plugins/c9.ide.preferences/general", + installPath: options.installPath, + local: options.local + }, + { + packagePath: "plugins/c9.ide.preferences/project", + basePath: workspaceDir, + local: options.local + }, + { + packagePath: "plugins/c9.ide.pubsub/pubsub-client", + extendToken: extendToken + }, + { + packagePath: "plugins/c9.ide.collab/notifications/bubble", + staticPrefix: staticPrefix + "/plugins/c9.ide.collab/notifications" + }, + ]; + + if (packaging || !devel) { + plugins.push({ + packagePath: "plugins/c9.ide.errorhandler/raygun_error_handler", + version: options.manifest.version, + revision: options.manifest.revision, + apiKey: options.raygun.apiKey || options.raygun.client.apiKey + }); + } + if (packaging || devel) { + plugins.push({ + packagePath: "plugins/c9.ide.errorhandler/simple_error_handler", + version: options.manifest.version, + revision: options.manifest.revision + }); + } + + // Collab + if (packaging || !collab) { + plugins.push( + "plugins/c9.ide.language.jsonalyzer/mock_collab" + ); + } + if (packaging || collab) { + plugins.push( + { + packagePath: "plugins/c9.ide.collab/connect", + extendToken: extendToken, + enable: collab, + debug: debug, + localServerFile: localExtendFiles, + nodeBin: nodeBin, + nodePath: nodePath, + basePath: workspaceDir + }, + "plugins/c9.ide.collab/collab", + "plugins/c9.ide.collab/collabpanel", + { + packagePath: "plugins/c9.ide.collab/workspace", + hosted: hosted, + isAdmin: options.isAdmin + }, + "plugins/c9.ide.collab/util", + { + packagePath: "plugins/c9.ide.collab/ot/document", + minDelay: 500, + maxDelay: 10000 + }, + { + packagePath: "plugins/c9.ide.collab/cursor_layer", + staticPrefix: staticPrefix + "/plugins/c9.ide.collab" + }, + "plugins/c9.ide.collab/author_layer", + { + packagePath: "plugins/c9.ide.collab/timeslider/timeslider", + staticPrefix: staticPrefix + "/plugins/c9.ide.collab/timeslider" + }, + // Collab panels + { + packagePath: "plugins/c9.ide.collab/notifications/notifications", + hosted: hosted, + isAdmin: options.isAdmin + }, + "plugins/c9.ide.collab/members/members_panel", + { + packagePath: "plugins/c9.ide.collab/share/share", + previewUrl: options.previewUrl, + local: options.local + }, + { + packagePath: "plugins/c9.ide.collab/members/members", + staticPrefix: staticPrefix + "/plugins/c9.ide.layout.classic" + }, + { + packagePath: "plugins/c9.ide.collab/chat/chat", + staticPrefix: staticPrefix + "/plugins/c9.ide.collab/chat" + }); + } + + return plugins; +}; + + + + + + + diff --git a/configs/local.js b/configs/local.js new file mode 100644 index 00000000..321190cd --- /dev/null +++ b/configs/local.js @@ -0,0 +1,14 @@ +module.exports = function(options, optimist) { + var plugins = require("./standalone")(options, optimist); + + options.inProcessLocalFs = true; + + plugins.forEach(function(p) { + if (p.packagePath) + p.packagePath = p.packagePath.replace("vfs.connect.standalone", "vfs.connect.local"); + }); + + return plugins; +}; + +if (!module.parent) require("../server")([__filename].concat(process.argv.slice(2))); diff --git a/configs/standalone.js b/configs/standalone.js new file mode 100644 index 00000000..a2ea99d9 --- /dev/null +++ b/configs/standalone.js @@ -0,0 +1,214 @@ +module.exports = function(config, optimist) { + + var path = require("path"); + + if (!optimist.local) { + optimist + .boolean("t") + .describe("t", "Start in test mode") + .describe("k", "Kill tmux server in test mode") + .default("b", false) + .describe("b", "Start the bridge server - to receive commands from the cli") + .default("w", config.workspaceDir) + .describe("w", "Workspace directory") + .alias("p", "port") + .default("port", process.env.PORT || config.port) + .describe("port", "Port") + .alias("d", "debug") + .default("debug", false) + .describe("debug", "Turn debugging on") + .alias("l", "listen") + .default("listen", process.env.IP || config.host) + .describe("listen", "IP address of the server") + .boolean("help") + .describe("workspacetype", "The workspace type to use") + .alias("ws", "workspacetype") + .describe("readonly", "Run in read only mode") + .alias("ro", "readonly") + .describe("packed", "Whether to use the packed version.") + .boolean("packed") + .default("packed", config.packed) + .alias("a", "auth") + .boolean("hosted") + .describe("hosted", "Use default config of the hosted version") + .default("hosted", false) + .describe("auth", "Basic Auth username:password") + .default("auth", ":") + .describe("collab", "Whether to enable collab.") + .default("collab", config.collab) + .describe("cache", "use cached version of cdn files") + .default("cache", true) + .describe("setting-path", "The path to store the settings.") + .boolean("inProcessLocalFs") + .describe("inProcessLocalFs", "Whether to run localfs in same process for debugging.") + .default("inProcessLocalFs", config.inProcessLocalFs); + } + + var argv = optimist.argv; + if (argv.help) + return null; + + var testing = argv.t; + var baseProc = path.normalize(testing + ? __dirname + "/../plugins/c9.fs/mock" + : argv.w || (__dirname + "/../")); + + // if (testing && !argv["setting-path"]) + // argv["setting-path"] = "/tmp/.c9"; + + if (baseProc != "/" && baseProc != "\\") // special case / for windows + baseProc = path.resolve(baseProc); + + process.env.BASE_PROC = baseProc; + + var port = argv.p; + var host = argv.l; + var debug = argv.d; + var readonly = argv.readonly; + var startBridge = argv.b; + + config.port = port || argv.port; + config.host = host || argv.listen; + + if (argv.collab != null) + config.collab = argv.collab; + + var workspaceType = argv.workspacetype || null; + + if (argv.hosted) + config.client_config = "default-hosted"; + + config.workspaceDir = baseProc; + config.settingDir = argv["setting-path"]; + config.projectName = path.basename(baseProc); + config.testing = testing; + config.debug = debug; + + if (!config.startBridge) + config.startBridge = startBridge; + + if (testing && argv.k) + require("child_process").exec("tmux -L cloud91.9 kill-server", function(){}); + + var auth = argv.auth.split(":"); + + var plugins = [ + { + packagePath: "connect-architect/connect", + port: port, + host: host, + websocket: true + }, + { + packagePath: "connect-architect/connect.basicauth", + username: auth[0], + password: auth[1] + }, + { + packagePath: "connect-architect/connect.static", + prefix: "/static" + }, + { + packagePath: "./c9.error/error_handler", + scope: "standalone", + hostname: config.hostname + }, + "connect-architect/connect.remote-address", + "connect-architect/connect.render", + "connect-architect/connect.render.ejs", + "connect-architect/connect.redirect", + "connect-architect/connect.cors", + "./c9.connect.favicon/favicon", + //"connect-architect/connect.logger", + + "./c9.core/ext", + + { + packagePath: "./c9.ide.server/plugins", + // allow everything in standalone mode + blacklist: { + "c9.ide.server": true, + "c9.ide.test.selenium": true + }, + whitelist: { + "c9.core": true, + "c9.fs": true, + "c9.login.client": true, + "c9.vfs.client": true, + "c9.cli.bridge": true, + "c9.nodeapi": true, + "saucelabs.preview": true + } + }, + "./c9.preview/statics", + "./c9.nodeapi/nodeapi", + { + packagePath: "./c9.vfs.standalone/standalone", + local: config.local, + packed: argv.packed, + collab: config.collab, + version: config.cdn.version, + options: config, + installPath: config.installPath, + settingDir: config.settingDir, + correctedInstallPath: config.correctedInstallPath, + debug: debug, + workspaceDir: baseProc, + projectUrl: config.projectUrl, + homeUrl: config.homeUrl, + workspaceType: workspaceType, + readonly: readonly + }, + "./c9.vfs.server/vfs.server", + "./c9.preview/preview.handler", + "./c9.vfs.server/cache", + "./c9.vfs.server/download", + "./c9.vfs.server/filelist", + "./c9.vfs.server/statics", + { + packagePath: "./c9.vfs.server/vfs.connect.standalone", + workspaceDir: baseProc, + readonly: readonly, + extendDirectory: config.extendDirectory, + extendOptions: config.extendOptions, + installPath: config.installPath, + settingDir: config.settingDir, + collab: config.collab, + nakBin: config.nakBin, + nodeBin: config.nodeBin, + tmuxBin: config.tmux, + vfs: { + defaultEnv: { CUSTOM: 43 }, + local: config.local, + debug: debug, + inProcess: argv.inProcessLocalFs + } + /* ### BEGIN #*/ + }, { + packagePath: "./c9.static/cdn", + cacheFiles: argv.cache + }, { + packagePath: "./c9.static/build", + version: config.cdn.version, + cache: config.cdn.cacheDir, + compress: config.cdn.compress, + baseUrl: config.cdn.baseUrl, + virtual: config.cdn.virtual, + config: "standalone" + /* ### END #*/ + } + ]; + + if (config.collab && !config.mode && !config.local) { + try { + var addApi = require("./api.standalone").addApi; + } catch(e) {} + if (addApi) { + plugins = addApi(plugins, config); + } + } + + return plugins; +}; + +if (!module.parent) require("../server")([__filename].concat(process.argv.slice(2))); diff --git a/docs/CODING_STANDARDS.md b/docs/CODING_STANDARDS.md new file mode 100644 index 00000000..1a85839d --- /dev/null +++ b/docs/CODING_STANDARDS.md @@ -0,0 +1,702 @@ +Cloud9 IDE Coding Style +===================== + +Goals +===== + +1. readability/clarity +2. easy to maintain/change code +3. reduce risk of introducing errors +4. minimize typing + +Base +---- + +* [http://nodeguide.com/style.html]([http://nodeguide.com/style.html) +* [https://github.com/ajaxorg/apf/blob/master/CODING_STANDARDS](https://github.com/ajaxorg/apf/blob/master/CODING_STANDARDS) + + +Tabs vs Spaces +-------------- + +We use 4 spaces of indenteation. + +Line Termination +---------------- + +Always use UNIX style line termination with a single new line character `\n`. + +File names +---------- + +To avoid problems with non case sensitive file systems (Windows) only alphanumeric characters, underscores, and the dash character ("-") are permitted. Spaces are strictly prohibited. + +*Right:* + + elements/bar.js + core/parsers/aml.js + elements/teleport/rpc/jsonrpc.js + +*Wrong:* + + elements/Bar.js + rpc/Json Rpc.js + +Semicolons +---------- + +There are [rebellious forces][isaac] that try to steal your semicolons from you. But make no mistake, our traditional culture is still [well and truly alive][hnsemicolons]. So follow the community, and use those semicolons! + +[isaac]: community.html#isaac-schlueter +[hnsemicolons]: http://news.ycombinator.com/item?id=1547647 + +Trailing whitespace +------------------- + +Just like you brush your teeth after every meal, you clean up any trailing whitespace in your JavaScript files before committing. Otherwise the rotten smell of careless neglect will eventually drive away contributors and/or co-workers. + +Line length +----------- + +The target line length is 80 characters. That is to say, developers should strive keep each line of their code under 80 characters where possible and practical. However, longer lines are acceptable in some circumstances. The maximum length of any line of code is 120 characters. + +Quotes +------ + +When a string is literal (contains no variable substitutions), the quotation mark or "double quote" should always be used to demarcate the string: + +```javascript + var a = "Example String"; +``` + +When a literal string itself contains quotation marks, it is permitted to demarcate the string with apostrophes or "single quotes". This is especially useful for blocks of HTML: + +```javascript + var a = ''; +``` + +## Braces + +Your opening braces go on the same line as the statement. + +*Right:* + +```javascript + if (true) { + console.log("winning"); + } +``` + +*Wrong:* + +```javascript + if (true) + { + console.log("losing"); + } +``` + +Also, notice the use of whitespace before and after the condition statement. + +Closing braces are always followed by a new line. This is releavant for `else`, `catch` and `finally`. + +*Right*: + +```javascript + if (true) { + console.log("winning"); + } + else { + console.log("losing"); + } +``` + +*Wrong* + +```javascript + if (true) { + console.log("winning"); + } else { + console.log("losing"); + } +``` + +If the block inside the curlys consists only of one statement the curlys may be omitted. + +```javascript + if (err) + return callback(err); +``` + +However within one condition curlys must be used consistently. + +*Right:* + +```javascript + if (true) { + var msg = "winning" + name; + console.log(msg); + } + else { + console.log("Oh noo"); + } +``` + +*Wrong:* + +```javascript + if (true) { + var msg = "winning" + name; + console.log(msg); + } + else + console.log("Oh noo"); +``` + +Always use a new line after after `if`, `while`, `for`, `do` and `try`. + +*Right:* + +```javascript + if (err) + return callback(err); +``` + +*Wrong:* + +```javascript + if (err) return callbak(err); +``` + +Variable declarations +--------------------- + +Declare one variable per var statement, it makes it easier to re-order the lines. Ignore [Crockford][crockfordconvention] on this, and put those declarations wherever they make sense. + +*Right:* + +```javascript + var keys = ["foo", "bar"]; + var values = [23, 42]; + + var object = {}; + while (items.length) { + var key = keys.pop(); + object[key] = values.pop(); + } +``` + +*Wrong:* + +```javascript + var keys = ["foo", "bar"], + values = [23, 42], + object = {}, + key; + + while (items.length) { + key = keys.pop(); + object[key] = values.pop(); + } +``` + +[crockfordconvention]: http://javascript.crockford.com/code.html + +Variable and property names +--------------------------- + +Variables and properties should use [lower camel case][camelcase] capitalization. They should also be descriptive. Single character variables, uncommon abbreviations and hungarian notation should generally be avoided. + +*Right:* + +```javascript + var adminUser = db.query("SELECT * FROM users ..."); + var isAdmin = adminUser !== ""; +``` + +*Wrong:* + +```javascript + var admin_user = d.query("SELECT * FROM users ..."); + bAdmin = adminUser !== ""; +``` + +*Wrong:* + +```javascript + var ufm = d.query("SELECT * FROM users ..."); + bAdmin = ufm.getBrs(); +``` + +[camelcase]: http://en.wikipedia.org/wiki/camelCase#Variations_and_synonyms + +Class names +----------- + +Class names should be capitalized using [upper camel case][camelcase]. + +*Right:* + +```javascript + function BankAccount() { + } +``` + +*Wrong:* + +```javascript + function bank_Account() { + } +``` + +Constants +--------- + +Constants should be declared as regular variables or static class properties, using all uppercase letters. + +Node.js / V8 actually supports mozilla's [const][const] extension, but unfortunately that cannot be applied to class members, nor is it part of any ECMA standard. + +*Right:* + +```javascript + var SECOND = 1 * 1000; + + function File() { + } + File.FULL_PERMISSIONS = 0777; +``` + +*Wrong:* + +```javascript + const SECOND = 1 * 1000; + + function File() { + } + File.fullPermissions = 0777; +``` + +[const]: https://developer.mozilla.org/en/JavaScript/Reference/Statements/const + +Object / Array creation +----------------------- + +Use trailing commas and put *short* declarations on a single line. Only quote keys when your interpreter complains: + +*Right:* + +```javascript + var a = ["hello", "world"]; + var b = { + good: "code", + "is generally": "pretty" + }; +``` + +*Wrong:* + +```javascript + var a = [ + "hello", "world" + ]; + var b = {"good": "code" + is generally: "pretty" + }; +``` + +To initialize empty arrays or objects always use the literal form. + +*Right:* + +```javascript + var users = []; + var me = {}; +``` + +*Wrong:* + +```javascript + var users = new Array(); + var me = new Object(); +``` + +Equality operator +----------------- + +Programming is not about remembering [stupid rules][comparisonoperators]. Use the triple equality operator as it will work just as expected. + +*Right:* + +```javascript + var a = 0; + if (a === "") { + console.log("winning"); + } +``` + +*Wrong:* + +```javascript + var a = 0; + if (a == "") { + console.log("losing"); + } +``` + +[comparisonoperators]: https://developer.mozilla.org/en/JavaScript/Reference/Operators/Comparison_Operators + +Extending prototypes +-------------------- + +Do not extend the prototypes of any objects, especially native ones. There is a special place in hell waiting for you if you don't obey this rule. + +*Right:* + +```javascript + var a = []; + if (!a.length) { + console.log("winning"); + } +``` + +*Wrong:* + +```javascript + Array.prototype.empty = function() { + return !this.length; + } + + var a = []; + if (a.empty()) { + console.log("losing"); + } +``` + +Function length +--------------- + +Keep your functions short. A function that doesn't fit on a 13" Notebook screen is too long. Limit yourself to max. 30 lines. Less is better. + +Return statements +----------------- + +To avoid deep nesting of if-statements, always return a functions value as early +as possible. + +*Right:* + +```javascript + function isPercentage(val) { + if (val < 0) + return false; + + if (val > 100) + return false; + + return true; + } +``` + +*Wrong:* + +```javascript + function isPercentage(val) { + if (val >= 0) { + if (val < 100) { + return true; + } + else { + return false; + } + } + else { + return false; + } + } +``` + +Or for this particular example it may also be fine to shorten things even further: + +```javascript + function isPercentage(val) { + var isInRange = (val >= 0 && val <= 100); + return isInRange; + } +``` + +Named closures +-------------- + +Feel free to give your closures a name. It shows that you care about them, and will produce better stack traces: + +```javascript + req.on("end", function onEnd() { + console.log("winning"); + }); +``` + +Callbacks +--------- + +Since node is all about non-blocking I/O, functions generally return their results using callbacks. The convention used by the node core is to reserve the first parameter of any callback for an optional error object. + +You should use the same approach for your own callbacks. + +If a function takes a callback some limitations apply: + +1. the callback must be the last argument and the argument name should be 'callback' +2. the callback must be called exactly once +3. the function must now throw an exception. Exceptions must be caught and passed to the callback as first argument +4. the function is not allowed to return a value + + +Object.freeze, Object.preventExtensions, Object.seal, with, eval +---------------------------------------------------------------- + +Crazy shit that you will probably never need. Stay away from it. + +Getters and setters +------------------- + +Limit the use of (ES5) setters, they tend to cause more problems for people who try to use your software than they can solve. + +Feel free to use getters that are free from [side effects][sideeffect], like providing a length property for a collection class. + +[sideeffect]: http://en.wikipedia.org/wiki/Side_effect_(computer_science) + +EventEmitters +------------- + +Node.js ships with a simple EventEmitter class that can be included from the 'events' module: + +```javascript + var EventEmitter = require("events").EventEmitter; +``` + +When creating complex classes, it is common to inherit from this EventEmitter class to emit events. This is basically a simple implementation of the [Observer pattern][]. + +[Observer pattern]: http://en.wikipedia.org/wiki/Observer_pattern + +However, I strongly recommend that you never listen to the events of your own class from within it. It isn't natural for an object to observe itself. It often leads to undesirable exposure to implementation details, and makes your code more difficult to follow. + +Class Definition +---------------- + +```javascript + var Ide = module.exports = function() {}; + + (function() { + this.member = function() {}; + }).call(Ide.prototype); +``` + +Within a JavaScript file only one class definition is permitted. + +Inheritance +----------- + +```javascript + var RunvmPlugin = module.exports = function(ide, workspace) { + Plugin.call(this, ide, workspace); + // ... + } + sys.inherits(RunvmPlugin, Plugin); + + (function() { + this.member = function() {}; + }).call(RunvmPlugin.prototype); +``` + +Private function +---------------- + +Private functions attached to the constructor (static) of the prototype of a class must be prefixed with an underscore. + +```javascript + var Ide = module.exports = function() {}; + + Ide._privateField = "private data"; + + (function() { + this._privateMethod = function() {}; + }).call(Ide.prototype); +``` + +How to break long lines +----------------------- + +Treat parenthesis and square brackets like curly braces: + +* they start in the same line as the function +* the body (argument list) is indented one level +* the closing parenthesis is outdented and on a separate line + +*Right:* + +```javascript + foo( + very, long argument, + list, with lots, of, + different, stuff + ); +``` + +*Wrong:* + +```javascript + foo(very, long argument, list, with lots, of, + different, stuff); +``` + +The same applies for long array literals. + +*Right:* + +```javascript + var a = [ + '
', + ' Click me', + '
' + ].join(""); +``` + +*Wrong:* + +```javascript + var a = ['
', + ' Click me', + '
'].join(""); +``` + +When breaking up long expressions the operator should be on the new line and broken lines should be indented by one level. + +*Right:* + +```javascript + var isAdmin = isLoggedIn + && username === "admin" + && password === "secret"; +``` + +*Wrong:* + +```javascript + var isAdmin = isLoggedIn && + username === "admin" && + password === "secret"; +``` + +The same is true for the ternary operator: + +```javascript + var a = (value > 20 && otherValue < 10 && boolFoo === false) + ? this.foo(); + : this.bar(); +``` + +For Loops +--------- + +If statements are incredibly flexible. The condition, test and increment part of an if statement can contain any code. However to make it easy for others to understand the code you should stay away from the crazy shit and limit yourself to the straighforard cases: + +1. declare the loop and length variables inline. +2. Don't declare any other variables in the initializer + +*Right:* + +```javascript + for (var i = 0, l = users.length; i < l; i++) { + var user = users[i]; + // + } +``` + +*Wrong:* + +```javascript + var i, l; + for (i = 0, l = users.length; i < l; i++) { + var user = users[i]; + // + } + + for (var user, i = 0, l = users.length; i++ < l;) { + var user = users[i]; + // + } +``` + +Switch Statements +----------------- + +Control statements written with the "switch" statement must have a single space before the opening parenthesis of the conditional statement and after the closing parenthesis. + +All content within the "switch" statement must be indented using four spaces. Content under each "case" statement must be indented using an additional four spaces. + +```javascript + switch (numPeople) { + case 1: + break; + + case 2: + break; + + default: + break; + } +``` + +The construct default should never be omitted from a switch statement. + +NOTE: It is sometimes useful to write a case statement which falls through to the next case by not including a break or return within that case. To distinguish these cases from bugs, any case statement where break or return are omitted should contain a comment indicating that the break was intentionally omitted. + +Vertical alignment +------------------ + +Vertically aligning asignments can improve readability but also makes it harder to maintain the code. The style should be avoided. + +*Right*: + +```javascript + var foo = 12; + var firstName = "Peter"; + var options = { + name: firstName, + age: { + years: 12, + months: 1 + } + }; +``` + +*Wrong*: + +```javascript + var foo = 12; + var firstName = "Peter"; + var options = { + name : firstName, + age : { + years : 12, + months : 2 + } + }; +``` + +_self = this +----------- + +The alias to access `this` from within closures is `_self` or `that`. We do not use `self` to avoid confusion with `window.self` in client side code. + +API Documentation +----------------- + +All classes and public API should be documented using [JSDuck annotations](https://github.com/senchalabs/jsduck). + +Other Resources +=============== + +* [https://github.com/ajaxorg/apf/blob/master/CODING_STANDARDS](https://github.com/ajaxorg/apf/blob/master/CODING_STANDARDS) +* [http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml](http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml) diff --git a/local/Info.plist b/local/Info.plist new file mode 100644 index 00000000..994216f2 --- /dev/null +++ b/local/Info.plist @@ -0,0 +1,210 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + Cloud9 + CFBundleDocumentTypes + + + CFBundleTypeExtensions + + txt + text + utf8 + + CFBundleTypeIconFile + nw.icns + CFBundleTypeMIMETypes + + text/plain + + CFBundleTypeName + Plain Text File + CFBundleTypeRole + Editor + LSIsAppleDefaultForType + + + + CFBundleTypeExtensions + + html + phtml + shtml + xhtml + htm + pht + sht + xht + phtm + shtm + xhtm + + CFBundleTypeIconFile + nw.icns + CFBundleTypeMIMETypes + + text/html + + CFBundleTypeName + HTML Source File + CFBundleTypeRole + Editor + LSIsAppleDefaultForType + + LSItemContentTypes + + public.html + + + + CFBundleTypeExtensions + + js + htc + jscript + javascript + + CFBundleTypeIconFile + nw.icns + CFBundleTypeMIMETypes + + text/javascript + + CFBundleTypeName + JavaScript Source File + CFBundleTypeRole + Editor + LSIsAppleDefaultForType + + LSItemContentTypes + + com.netscape.javascript-source + + + + CFBundleTypeExtensions + + py + rpy + cpy + python + + CFBundleTypeIconFile + nw.icns + CFBundleTypeMIMETypes + + text/x-python-script + + CFBundleTypeName + Python Source File + CFBundleTypeRole + Editor + LSItemContentTypes + + public.python-script + + + + CFBundleTypeExtensions + + gem + rb + ru + rz + + CFBundleTypeIconFile + nw.icns + CFBundleTypeMIMETypes + + text/x-ruby + text/ruby-script + application/x-rzip + application/x-ruby-gem + + CFBundleTypeName + Ruby Source File + CFBundleTypeRole + Editor + LSItemContentTypes + + public.ruby-script + + + + CFBundleTypeExtensions + + css + + CFBundleTypeIconFile + nw.icns + CFBundleTypeName + Cascading style sheet + CFBundleTypeRole + Editor + + + CFBundleTypeExtensions + + markdown + markd + mdown + md + + CFBundleTypeIconFile + nw.icns + CFBundleTypeName + Markdown document + CFBundleTypeRole + Editor + + + CFBundleTypeExtensions + + clj + cljs + edn + + CFBundleTypeIconFile + nw.icns + CFBundleTypeName + Clojure Source + CFBundleTypeRole + Editor + LSIsAppleDefaultForType + + + + CFBundleExecutable + node-webkit + CFBundleIconFile + nw.icns + CFBundleIdentifier + io.c9.desktop + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + Cloud9 + CFBundlePackageType + APPL + CFBundleShortVersionString + Version 3.0 + CFBundleVersion + 3.0 + LSFileQuarantineEnabled + + LSMinimumSystemVersion + 10.6.0 + NSPrincipalClass + NSApplication + NSSupportsAutomaticGraphicsSwitching + + SCMRevision + 213023 + UTExportedTypeDeclarations + + + diff --git a/local/favicon.ico b/local/favicon.ico new file mode 120000 index 00000000..176408fd --- /dev/null +++ b/local/favicon.ico @@ -0,0 +1 @@ +../plugins/c9.connect.favicon/favicon.ico \ No newline at end of file diff --git a/local/index.html b/local/index.html new file mode 100644 index 00000000..e40d3c4f --- /dev/null +++ b/local/index.html @@ -0,0 +1,499 @@ + + + + + + +
+ + + + +
+
Cloud9
+
+ +
+
+ Loading your workspace +
+
+
It will be just as you left it
+ + +
+ +
+ + + + + + diff --git a/local/install.sh b/local/install.sh new file mode 100755 index 00000000..4075cb6c --- /dev/null +++ b/local/install.sh @@ -0,0 +1,242 @@ +#!/bin/bash -e +set -e +has() { + type "$1" > /dev/null 2>&1 + return $? +} + +# Redirect stdout ( > ) into a named pipe ( >() ) running "tee" +exec > >(tee /tmp/installlog.txt) + +# Without this, only stdout would be captured - i.e. your +# log file would not contain any error messages. +exec 2>&1 + +NODE_VERSION=v0.10.28 +APPSUPPORT_USER=$HOME/.c9 +SCRIPT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +RUNTIME=$SCRIPT/.. +INSTALL_DIR=/tmp/c9-`date '+%s'` +ORIGINAL_USER=`basename $HOME` +OSX_INSTALLER_PATH=$2 + +start() { + if [ $# -lt 1 ]; then + start base + return + fi + + # Try to figure out the os and arch for binary fetching + local uname="$(uname -a)" + local os= + local arch="$(uname -m)" + case "$uname" in + Linux\ *) os=linux ;; + Darwin\ *) os=darwin ;; + SunOS\ *) os=sunos ;; + FreeBSD\ *) os=freebsd ;; + esac + case "$uname" in + *x86_64*) arch=x64 ;; + *i*86*) arch=x86 ;; + *armv6l*) arch=arm-pi ;; + esac + + if [ $os != "linux" ] && [ $os != "darwin" ]; then + echo "Unsupported Platform: $os $arch" 1>&2 + exit 1 + fi + + if [ $arch != "x64" ] && [ $arch != "x86" ]; then + echo "Unsupported Architecture: $os $arch" 1>&2 + exit 1 + fi + + if [ $os == "darwin" ]; then + APPSUPPORT_USER="$HOME/Library/Application Support/Cloud9" + APPTARGET=$OSX_INSTALLER_PATH + APPSUPPORT="/Library/Application Support/Cloud9" + RUNTIME="${APPTARGET}/Contents/Resources/app.nw" + fi + + case $1 in + "help" ) + echo + echo "Cloud9 Installer" + echo + echo "Usage:" + echo " install help Show this message" + echo " install install [name [name ...]] Download and install a set of packages" + echo " install ls List available packages" + echo + ;; + + "ls" ) + echo "!node - Node.js" + echo "!tmux_install - TMUX" + echo "!nak - NAK" + echo "!vfsextend - VFS extend" + echo "!ptyjs - pty.js" + echo "!c9cli - C9 CLI" + echo "!sc - Sauce Connect" + echo "coffee - Coffee Script" + echo "less - Less" + echo "sass - Sass" + echo "typescript - TypeScript" + echo "stylus - Stylus" + # echo "go - Go" + # echo "heroku - Heroku" + # echo "rhc - RedHat OpenShift" + # echo "gae - Google AppEngine" + ;; + + "install" ) + shift + + # make sure dirs are around + mkdir -p "$APPSUPPORT/bin" + mkdir -p "$APPSUPPORT/node_modules" + cd "$APPSUPPORT" + + cp -a "$SCRIPT" "$INSTALL_DIR" + + # install packages + while [ $# -ne 0 ] + do + time eval ${1} $os $arch + shift + done + + # finalize + #pushd $APPSUPPORT/node_modules/.bin + #for FILE in $APPSUPPORT/node_modules/.bin/*; do + # if [ `uname` == Darwin ]; then + # sed -i "" -E s:'#!/usr/bin/env node':"#!$NODE":g $(readlink $FILE) + # else + # sed -i -E s:'#!/usr/bin/env node':"#!$NODE":g $(readlink $FILE) + # fi + #done + #popd + + VERSION=`cat $RUNTIME/version || echo 1` + echo 1 > "$APPSUPPORT/installed" + echo $VERSION > "$APPSUPPORT/version" + + # set chown/chmod of application dirs for update + echo "Testing existence of APPTARGET (${APPTARGET})" + if [ -d "$APPTARGET" ]; then + echo "Updating permissions of APPTARGET (${APPTARGET})" + chown -R root:admin "$APPTARGET" || chown -R root:staff "$APPTARGET" + chmod -R 775 "$APPTARGET" + fi + + echo "Testing existence of APPSUPPORT (${APPSUPPORT})" + if [ -d "$APPSUPPORT" ]; then + echo "Updating permissions of APPSUPPORT (${APPSUPPORT})" + chown -R root:admin "$APPSUPPORT" || chown -R root:staff "$APPSUPPORT" + chmod -R 775 "$APPSUPPORT" + fi + + echo "Testing existence of APPSUPPORT_USER (${APPSUPPORT_USER})" + if [ -n "$ORIGINAL_USER" ] && [ -d "$APPSUPPORT_USER" ]; then + echo "Updating permissions of APPSUPPORT_USER (${APPSUPPORT_USER})" + chown -R $ORIGINAL_USER "$APPSUPPORT_USER" + fi + + rm -Rf $INSTALL_DIR + + echo :Done. + ;; + + "base" ) + echo "Installing base packages. Use '`basename $0` help' for more options" + start install node tmux_install nak ptyjs sc vfsextend c9cli + ;; + + * ) + start base + ;; + esac +} + +# NodeJS + +node(){ + # clean up + rm -rf node + rm -rf node-$NODE_VERSION* + + echo :Installing Node $NODE_VERSION + + cd "$INSTALL_DIR" + tar xvfz node-$NODE_VERSION-$1-$2.tar.gz + rm -Rf "$APPSUPPORT/node" + mv node-$NODE_VERSION-$1-$2 "$APPSUPPORT/node" +} + +tmux_install(){ + echo :Installing TMUX + mkdir -p "$APPSUPPORT/bin" + + if [ $os = "darwin" ]; then + cd "$INSTALL_DIR" + python rudix.py -i libevent-2.0.21-0.pkg + python rudix.py -i tmux-1.9-0.pkg + + if ! type "/usr/local/bin/tmux"; then + echo "Installation Failed" + exit 100 + fi + + ln -sf "/usr/local/bin/tmux" "$APPSUPPORT/bin/tmux" + # Linux + else + echo "Unsupported" + fi +} + +vfsextend(){ + echo :Installing VFS extend + cd "$INSTALL_DIR" + tar xvfz c9-vfs-extend.tar.gz + rm -Rf "$APPSUPPORT/c9-vfs-extend" + mv c9-vfs-extend "$APPSUPPORT" +} + +sc(){ + echo :Installing Sauce Connect + cd "$INSTALL_DIR" + tar xvzf sc-4.0-latest.tar.gz + rm -rf "$APPSUPPORT/sc" + mv sc-4.0-latest "$APPSUPPORT/sc" +} + +nak(){ + echo :Installing Nak + cd "$INSTALL_DIR" + tar -zxvf nak.tar.gz + mkdir -p "$APPSUPPORT/node_modules/.bin" + rm -Rf "$APPSUPPORT/node_modules/nak" + mv nak "$APPSUPPORT/node_modules" + ln -s "$APPSUPPORT/node_modules/nak/bin/nak" "$APPSUPPORT/node_modules/.bin/nak" &2> /dev/null +} + +ptyjs(){ + echo :Installing pty.js + cd "$INSTALL_DIR" + tar -zxvf pty-$NODE_VERSION-$1-$2.tar.gz + mkdir -p "$APPSUPPORT/node_modules" + rm -Rf "$APPSUPPORT/node_modules/pty.js" + mv pty.js "$APPSUPPORT/node_modules" +} + +c9cli(){ + if [ -d "/usr/local/bin/" ]; then + chmod +x "$RUNTIME/bin/c9" + ln -s -f "$RUNTIME/bin/c9" /usr/local/bin/c9 + else + echo "unable to add c9cli to the path" + fi +} + +start $@ diff --git a/local/logger.js b/local/logger.js new file mode 100644 index 00000000..5221112e --- /dev/null +++ b/local/logger.js @@ -0,0 +1,39 @@ +var sysLog = console.log; +var sysWarn = console.warn; +var sysError = console.error; +var server = require("./server"); + +console.log = function() { + writeLog.apply(null, arguments); + sysLog.apply(console, arguments); +}; +console.warn = function() { + writeLog.apply(null, arguments); + sysWarn.apply(console, arguments); +}; +console.error = function() { + writeLog.apply(null, arguments); + sysError.apply(console, arguments); +}; + +function writeLog(varargs) { + var args = []; + for (var i = 0; i < arguments.length; i++) { + args[i] = typeof arguments[i] == "string" + ? arguments[i] + : tryStringify(arguments[i]); + } + server.appendLog(args.join(" ") + "\n"); +} + +function tryStringify(o) { + try { + return JSON.stringify(o); + } catch (e) { + return "" + o; + } +} + +window.onerror = function(message, url, line, errorObj) { + writeLog("ERROR:", message, "at", url, ":", line, errorObj.stack); +}; diff --git a/local/menus.js b/local/menus.js new file mode 100644 index 00000000..b28c4559 --- /dev/null +++ b/local/menus.js @@ -0,0 +1,333 @@ + +function MenuManager(){ + var windowManager, connection, win, gui; + var nativeMenuBar; + + // Lookup table for the menus + var menus = {}; + var timers = {}; + + var TIMEOUT = 500; + + function checkNativeItems(menu, name) { + var id = windowManager.activeWindowId; + if (id === 0) { + menu.items.forEach(function(item){ + if (item.key != "q") + item.enabled = false; + }); + gui.App.doneMenuShow(); + return; + } + + // Lets wait TIMEOUT ms before we force show the window + clearTimeout(timers[name]); + timers[name] = setTimeout(function(){ + var menu = menus[name].submenu; + var nodes = menu.items.map(function(i){ + return { + name: i.originalName, + disabled: i.originalName != "Cloud9/Quit Cloud9", + visible: true + } + }); + updateMenu(name, nodes); + }, TIMEOUT); + + // The window needs to send "showMenu" back - which calls updateMenu + connection.sendToWindow(id, "menuShow", { name: name }); + } + + function menuReady(name){ + clearTimeout(timers[name]); + gui.App.doneMenuShow(); + } + + function updateMenu(name, nodes){ + var menu = menus[name].submenu; + var item; + + var found = {}; + + for (var n, i = nodes.length - 1; i >= 0; i--) { + n = nodes[i]; + item = menus[n.name]; + found[n.name] = true; + + if (!item) { + if (n.submenu) + setSubMenu(n); + else + setMenuItem(n); + continue; + } + + // Disabled + item.enabled = !n.disabled; + + // This is for internal use + if (!n.caption) + continue; + + // Toggle visibility + if (n.visible && menu.items.indexOf(item) == -1) { + nativeInsertByIndex(menu, item, n.index); + item.index = n.index; + } + else if (!n.visible && menu.items.indexOf(item) != -1) { + item.visible = false; + menu.remove(item); + } + + // Don't update items that are not visible + if (!n.visible) + continue; + + if (item.label != n.caption) + item.label = n.caption.replace(/\u2044/g, "/").trim(); + + // Update hotkey if needed + if (n.key != item.key || n.modifiers != item.modifiers) { + item.key = n.key; + item.modifiers = n.modifiers; + } + + // Checkboxes and Radiobuttons + if (item.type == "checkbox") + item.checked = n.checked; + } + + // Hide the menu items that are not found + var items = menu.items; + for (var i = items.length - 1; i >= 0; i--) { + if (!found[items[i].originalName]) { + items[i].visible = false; + menu.remove(items[i]); + } + } + + menuReady(name); + } + + function decorateMenu(menu, path) { + // Add show event + menu.on("show", checkNativeItems.bind(this, menu, path)); + } + + function nativeInsertByIndex(parent, item, index) { + item.$position = index; + + var beforeNode, diff = 100000000, nodes = parent.items; + for (var i = 0, l = nodes.length; i < l; i++) { + var d = nodes[i].$position - index; + if (d > 0 && d < diff) { + beforeNode = i; + diff = d; + } + } + + parent.insert(item, isNaN(beforeNode) ? nodes.length : beforeNode); + + item.visible = true; + + return item; + } + + function incrementIfExist(name, forceVisible) { + if (!menus[name]) return false; + var item = menus[name]; + item.increment++; + + if (forceVisible && !item.visible) + nativeInsertByIndex(findParent(name), item, forceVisible.index); + + return true; + } + + function addItem(name, item) { + menus[name] = item; + item.increment = 1; + item.originalName = name; + } + + function setRootMenu(e){ + var item = nativeInsertByIndex(nativeMenuBar, new gui.MenuItem({ + label: e.name, + submenu: new gui.Menu() + }), e.index); + + decorateMenu(item.submenu, e.name); + + addItem(e.name, item); + + // Assign Menu Bar to Window + if (!win.menu) + win.menu = nativeMenuBar; + } + + function setSubMenu(e){ + var parent = findParent(e.name); + var item = nativeInsertByIndex(parent, new gui.MenuItem({ + label: e.name.split("/").pop(), + submenu: new gui.Menu() + }), e.index); + + decorateMenu(item.submenu, e.name); + + addItem(e.name, item); + } + + function setMenuItem(e){ + var item; + var itemName = e.name.split("/").pop(); + var parent = findParent(e.name); + + if (itemName.charAt(0) == "~") { + item = new gui.MenuItem({ type: "separator" }); + } else { + // Special Cases see https://github.com/rogerwang/node-webkit/compare/mac#diff-945bfbb0fd440b87cfe8ebf76f11c970R161 + if (e.name.slice(0, 4) == "Edit") { + if (itemName == "Cut") { + e.selector = "cut:"; + e.key = "x"; + } + else if (itemName == "Copy") { + e.selector = "copy:"; + e.key = "c"; + } + else if (itemName == "Paste") { + e.selector = "paste:"; + e.key = "v"; + } + else if (itemName == "Select All") { + e.selector = "selectAll:"; + e.key = "a"; + } + else if (itemName == "Undo") { + e.selector = "undo:"; + e.key = "z"; + } + else if (itemName == "Redo") { + e.selector = "redo:"; + e.key = "z"; + e.modifiers = "cmd-shift"; + } + } + + var options = { + label: itemName.replace(/\u2044/g, "-"), + enabled: !e.disabled, + type: e.itemtype == "check" + || e.itemtype == "radio" ? "checkbox" : "normal", + selector: e.selector, + key: e.key, + modifiers: e.modifiers, + click: function(){ + var id = windowManager.activeWindowId; + if (id === undefined) return; + + connection.sendToWindow(id, "menuClick", { + name: e.name + }); + } + }; + + item = new gui.MenuItem(options); + item.index = e.index; + } + + nativeInsertByIndex(parent, item, e.index); + + addItem(e.name, item); + } + + function removeItem(path) { + if (menus[path] && --menus[path].increment === 0) { + menus[path].menu.remove(menus[path]); + delete menus[path]; + } + } + + function findParent(path) { + var p = path.split("/"); p.pop(); + var parent = menus[p.join("/")]; + return parent.submenu; + } + + this.init = function(wm) { + windowManager = wm; + + windowManager.registerSharedModule("nativeMenuBar", function(windowManager, cn) { + win = windowManager.$allWindows.root; + gui = win.window.nwGui; + + // Assign Connection + connection = cn; + + // Create Menu Bar + nativeMenuBar = new gui.Menu({ type: "menubar" }); + + setRootMenu({name: "Cloud9", index: 50}); + setRootMenu({name: "File", index: 100}); + setRootMenu({name: "Edit", index: 200}); + setRootMenu({name: "Find", index: 300}); + setRootMenu({name: "View", index: 400}); + setRootMenu({name: "Goto", index: 500}); + setRootMenu({name: "Run", index: 600}); + setRootMenu({name: "Tools", index: 700}); + setRootMenu({name: "Window", index: 800}); + setRootMenu({name: "Help", index: 900}); + + // Set Up Message Listeners + connection.on("setRoot", function(e) { + if (incrementIfExist(e.name)) return; + + setRootMenu(e); + }); + + connection.on("setSubMenu", function(e) { + if (incrementIfExist(e.name)) return; + + setSubMenu(e); + }); + + connection.on("setMenuItem", function(e) { + if (incrementIfExist(e.name, e)) return; + + setMenuItem(e); + }); + + connection.on("remove", function(e) { + removeItem(e.name); + }); + + connection.on("showMenu", function(e) { + updateMenu(e.name, e.items); + }); + + connection.on("enableUndoRedo", function(e) { + var menu = menus["Edit"].submenu; + + ["Edit/Undo", "Edit/Redo"].forEach(function(path){ + var item = menus[path]; + if (item && menu.items.indexOf(item) == -1) + nativeInsertByIndex(menu, item, item.index); + }); + }); + + connection.on("builtin", function(e) { + if (!win.hasBuiltIn) { + while (nativeMenuBar.items.length) { + nativeMenuBar.remove(nativeMenuBar.items[0]); + } + + nativeMenuBar.createMacBuiltin("Cloud9"); + win.menu = nativeMenuBar; + win.hasBuiltIn = true; + } + }); + }); + }; +} + +module.exports = new MenuManager(); \ No newline at end of file diff --git a/local/package.json b/local/package.json new file mode 100644 index 00000000..096e462d --- /dev/null +++ b/local/package.json @@ -0,0 +1,19 @@ +{ + "name": "Cloud9dev", + "version": "0.0.1", + "main": "projectManager.html", + "node-remote": "localhost", + "window": { + "title": "Cloud9", + "toolbar": false, + "width": 1100, + "height": 800, + "show": false, + "frame": true + }, + "win_bg": "#000000", + "chromium-args" : "--disable-web-security --ignore-certificate-errors --auth-schemes='digest,ntlm,negotiate,basic'", + "webkit": { + "page-cache": false + } +} \ No newline at end of file diff --git a/local/projectManager.html b/local/projectManager.html new file mode 100644 index 00000000..07f77aa5 --- /dev/null +++ b/local/projectManager.html @@ -0,0 +1,27 @@ + + + + + diff --git a/local/server.js b/local/server.js new file mode 100644 index 00000000..ac7c4a62 --- /dev/null +++ b/local/server.js @@ -0,0 +1,1264 @@ +var fs = require("fs"); +var join = require("path").join; +var proc = require("child_process"); +var path = require("path"); + +// set up env variables for windows +if (process.platform == "win32") { + // HOME usually isn't defined on windows + if (!process.env.HOME) + process.env.HOME = process.env.HOMEDRIVE + process.env.HOMEPATH; + // add cloud9 cygwin to path + var msysBin = join(process.execPath, "/../../msys/bin"); + process.env.Path = msysBin + ";" + process.env.path; + process.env.C9_BASH_BIN = msysBin + "/bash.exe"; + process.env.CYGWIN = "nodosfilewarning " + (process.env.CYGWIN || ""); + process.env.CHERE_INVOKING = 1; // prevent cygwin from changing bash path +} + +// Ports on which we'd like to run preview (see http://saucelabs.com/docs/connect#localhost) +var SAFE_PORTS = [2222, 2310, 3000, 3001, 3030, 3210, 3333, 4000, 4001, + 4040, 4321, 4502, 4503, 4567, 5000, 5001, 5050, 5555, + 5432, 6000, 6001, 6060, 6666, 6543, 7000, 7070, 7774, + 7777, 8000, 8001, 8003, 8031, 8080, 8081, 8765, 8777, + 8888, 9000, 9001, 9080, 9090, 9876, 9877, 9999, 49221]; + +var installPath = process.platform == "darwin" + ? "/Library/Application Support/Cloud9" + : join(process.env.HOME, ".c9"); + +// Support legacy installations +if (installPath === "/Library/Application Support/Cloud9" + && !fs.existsSync(join(installPath, "version")) + && fs.existsSync(join(process.env.HOME, installPath, "version"))) + installPath = join(process.env.HOME, installPath); + +var nodePath = process.platform == "win32" + ? join(process.execPath, "..\\node.exe") + : installPath + "/node/bin/node"; + +var logStream; + +// this seems to be needed in both window and server +process.on("uncaughtException", function(err) { + console.error(err); +}); + +function toInternalPath(path) { + if (process.platform == "win32") + path = path.replace(/^[/]*/, "/").replace(/[\\/]+/g, "/"); + return path; +} + +var App = window.nwGui.App; +var argv = App.argv; +argv.parsed = parseArgs(argv); + +var settingDir = argv.parsed["--setting-path"] + ? path.resolve(argv.parsed["--setting-path"]) + : (installPath === "/Library/Application Support/Cloud9" + ? path.join(process.env.HOME, installPath) + : installPath); + +function parseArgs(argv) { + if (typeof argv == "string") + argv = argv.match(/(?:"((?:[^"\\]|\\.)*)"|'((?:[^'\\]|\\.)*)'|((?:[^ \\]|\\.)+))/g) + .map(function(x) { return x.replace(/^["']|["']$/g, ""); }); + var parsed = { + _: [], + "--setting-path": "", + "-w": "" + }; + var argname; + for (var i = 0; i < argv.length; i++) { + var arg = argv[i]; + if (arg[0] === "-") { + argname = arg; + if (!(argname in parsed)) { + parsed[argname] = true; + argname = ""; + } + } else if (argname) { + parsed[argname] = arg; + argname = ""; + } else { + parsed._.push(arg); + } + } + return parsed; +} + + +var server = { + writePIDFile : function(path){ + function write(pid){ + fs.writeFile(process.env.HOME + "/.c9/pid", pid + ":" + path, + function(err){}); + } + + // In OSX the pid is not the nw process, but a child + // We'll look up the parent + if (process.platform == "darwin") { + proc.execFile("ps", ["-axf"], function(err, stdout, stderr){ + if (err) return console.log("Could not write PID file: ", + (err.message || err) ); + + var re = new RegExp("[ \\d]*?\\s" + process.pid + + "\\s+(\\d+)\\s+.*Contents\\/Frameworks\\/node\\-webkit"); + + var m = stdout.match(re); + if (!m) return console.log("Could not write PID file"); + + write(m[1]); + }); + } + else + write(process.pid); + }, + + start : function(options, callback){ + if (nwProcessId) { + return windowManager.connection.call(0, { + type: "serverStart", + options: options, + }, callback); + } + + var self = this; + if (this.process) { + return process.nextTick(function() { + callback(null, self.options.port); + }); + } + // console.log("Starting Cloud9...", port); + var allowExit; + var path = options.path; + if (!path) + path = process.env.HOME || "/"; + + // Write PID file + this.writePIDFile(path); + + // Listen for exit signals + process.on("exit", function(){ + if (p) p.kill(); + + fs.unlink(process.env.HOME + "/.c9/pid", function(){}); + }); + + var args = [ + join(__dirname, "../server.js"), + "local", + "--setting-path", settingDir, + "-s", "local", + "--listen", options.host, + "-w", path, + "-p", options.port, + "--collab", options.collab + ]; + + if (options.wsType) + args.push("--workspacetype", options.wsType); + + if (options.inProcess) { + var server = require("../server"); + args.shift(); + return server(args, "local", function() { + callback(null, options.port); + }); + } + + var env = {}; + Object.keys(process.env).forEach(function(name){ + env[name] = process.env[name]; + }); + env["NODE_PATH"] = (process.platform == "win32" + ? join(nodePath, "../deps") + : installPath) + "/node_modules"; + + var p = proc.spawn(nodePath, args, { env: env }); + + // Do Nothing + function done(){ + p.stderr.removeListener("data", waitErr); + p.stdout.removeListener("data", waitOut); + } + function waitErr(chunk){ + chunk = chunk.toString(); + if (chunk.indexOf("EADDRINUSE") > -1) { + done(); + p.kill(); + + var err = new Error(chunk); + err.code = "EADDRINUSE"; + err.options = options; + allowExit = true; + callback(err); + } + } + function waitOut(chunk){ + chunk = chunk.toString(); + console.warn("SERVER:", chunk); + if (chunk.indexOf("Started") > -1) { + done(); + callback(null, options.port); + } + } + p.stderr.on("data", waitErr); + p.stdout.on("data", waitOut); + + p.stderr.on("data", function(e) { + console.error(e+""); + }); + p.stdout.on("data", function(e) { + console.log(e+""); + }); + p.on("exit", function() { + self.process = null; + setTimeout(function() { + if (p.exitCode && !allowExit && !self.process) + self.start(options, function(){}); + }, 1000); + }); + self.options = options; + self.process = p; + }, + + findFreePort : function(host, callback) { + var ports = SAFE_PORTS.slice(); + find(); + + function find() { + var port = ports.pop(); + if (!port) + return callback(new Error("Could not find an available port")); + require("netutil").isPortOpen(host, port, 2000, function(open) { + if (!open) + return callback(null, port); + find(); + }); + } + }, + + stop : function() { + this.process.kill(); + }, + + restart : function() { + this.stop(); + this.start(this.options); + }, + + getPlugins : function(options, cb, restoreWindow) { + var windowConfig = options.windowConfig || {}; + var configPath = join(__dirname, "../configs/client-default-local.js"); + var settingsPath = join(__dirname, "../settings/local.js"); + var themeDir = join(__dirname, "../build/standalone/skin/" + + (windowConfig.isRemote ? "full" : "default-local")); + + var stateConfigFilePath = windowConfig.id + ? join(settingDir, "windows/" + windowConfig.id + "-state.settings") + : join(settingDir, "state.settings"); + + function getConfig(options) { + options.installed = true; + options.settingDir = settingDir; + var settings = { + "user": join(settingDir, "user.settings"), + "profile": join(settingDir, "profile.settings"), + "project": join(settingDir, "project.settings"), + "state": stateConfigFilePath + }; + + for (var type in settings) { + settings[type] = readJSONFile(settings[type]); + } + + if (windowConfig.stateSettings) { + settings.state = windowConfig.stateSettings; + delete windowConfig.stateSettings; + } + + options.settings = settings; + + if (settings.profile.id) { + options.user = settings.profile; + if (settings.profile.saucelabs) { + options.saucelabs.account = settings.profile.saucelabs; + } + } + else { + options.user = { + id: -1, + name: "Anonymous", + fullname: "Anonymous", + email: "", + pubkey: null + }; + } + + if (process.platform == "win32") + options.sauceConnectPath = join(nodePath, "../deps"); + + + return require(configPath)(options); + } + + function updateFilePaths(plugins, cb) { + var stateSettings, userSettings, preloadPlugin; + + function fixCssStaticPath(str) { + if (options.windowLocation && str) + return str.replace(/(url\(["']?)\/(?:standalone\/)?static/g, "$1" + options.windowLocation); + return str; + } + function loadTheme(name, cb) { + if (preloadPlugin[name]) + return cb(null, preloadPlugin[name]); + fs.readFile(themeDir + "/" + name + ".css", "utf8", function(err, data) { + // todo rebuild missing themes + data = fixCssStaticPath(data); + preloadPlugin[name] = data; + cb && cb(err, data); + }); + } + var isRemote = windowConfig.isRemote; + for (var i = 0; i < plugins.length; i++) { + var p = plugins[i]; + if (p.packagePath === "plugins/c9.ide.layout.classic/preload") { + preloadPlugin = p; + if (options.packed || isRemote) + p.loadTheme = loadTheme; + else + p.themePrefix = "/static/standalone/skin/default-local"; + } + else if (p.packagePath === "plugins/c9.vfs.client/endpoint") { + p.getServers = options.getServers; + } + else if (p.packagePath == "plugins/c9.ide.language/language") { + p.useUIWorker = options.noWorker; + if (options.packed) { + p.staticPrefix = options.windowLocation; + p.workerPrefix = settings.CORSWorkerPrefix; + } else { + p.staticPrefix = p.workerPrefix = null; + } + } + else if (p.packagePath == "plugins/c9.core/settings") { + if (!isRemote) + p.stateConfigFilePath = stateConfigFilePath; + stateSettings = p.settings.state; + if (typeof stateSettings == "string") { + try { + stateSettings = JSON.parse(stateSettings); + } catch(e) {} + } + userSettings = p.settings.user; + if (typeof userSettings == "string") { + try { + userSettings = JSON.parse(userSettings); + } catch(e) {} + } + } + + if (p.staticPrefix && options.windowLocation && options.packed) { + p.staticPrefix = p.staticPrefix.replace(/^\/static/, options.windowLocation); + } + } + var themeName = userSettings && userSettings.general && userSettings.general["@skin"] || "dark"; + restoreWindow && restoreWindow(stateSettings); + loadTheme(themeName, cb); + } + + var settings = require(settingsPath)(null, null, settingDir); + settings.packed = options.packed; + + settings.vfsServers = options.vfsServers; + settings.workspaceDir = options.workspaceDir; + settings.CORSWorkerPrefix = ( + options.windowLocation && options.packed ? options.windowLocation + "/build/" : "/static/" + ) + "standalone/worker"; + + if (windowConfig.isRemote) + settings.remoteWorkspace = windowConfig.name; + + if (settings.remoteWorkspace) { + getRemoteWorkspaceConfig(windowConfig.name, function(err, config) { + if (err) { + plugins = getConfig(settings); + addErrorHandlerPlugin(plugins, windowConfig); + } + else { + plugins = require(configPath).makeLocal(config.plugins, settings); + settings.url = config.url; + } + updateFilePaths(plugins, function(){ + cb(plugins, settings); + }); + }); + } else { + var plugins = getConfig(settings); + updateFilePaths(plugins, function(){ + cb(plugins, settings); + }); + } + }, + + appendLog : function(message) { + logStream && logStream.write(message); + }, + + __dirname : __dirname, + installPath : installPath, + argv: argv, + + openWindow : openWindow, + parseArgs : parseArgs, + getRecentWindows: getRecentWindows, + listC9Projects: listC9Projects, + getRemoteWorkspaceConfig: getRemoteWorkspaceConfig +}; + +function addErrorHandlerPlugin(plugins, windowConfig) { + plugins.push({ + provides: [], + consumes: ["c9", "auth", "restore", "dialog.alert", "commands"], + setup: function(options, imports, register) { + imports.auth.on("login", function() { + getRemoteWorkspaceConfig(windowConfig.name, function(err, config) { + if (err) { + + return imports["dialog.alert"].alert( + "Error loading remote workspace", + "Couldn't load config for " + windowConfig.name + ); + } + imports.commands.exec("restartc9"); + }); + }); + + register(null, {}); + } + }); +} + +/*****************************************************************/ +/* windowManager: move to own file once build tool supports that */ +/*****************************************************************/ + +var MAX_RECENT_WINDOWS = 20; +var MAX_SAME_PROCESS = 1; +var processIdCounter = 1; +var activeWindowId = null; +var nwProcessId = 0; +var allWindows = Object.create(null); +var windowData = Object.create(null); +var connection = null; + +var windowManager = server.windowManager = { + quit: quit, + quitAll: quitAll, + unquit: unquit, + onClose: onClose, + save: scheduleSave, + statePath: join(settingDir, "window.settings"), + openWindow: openWindow, + $allWindows: allWindows, + $windowData: windowData, + onShowWindow: onShowWindow, + restoreSession: restoreSession, + registerWindow: registerWindow, + getRecentWindows: getRecentWindows, + findWindowForPath: findWindowForPath, + registerSharedModule: registerSharedModule, + signalToAll: signalToAll, + setFavorites: setFavorites, + forEachWindow: forEachWindow, + isPrimaryWindow: isPrimaryWindow, + get connection() { return connection }, + get activeWindow() { return allWindows[activeWindowId] }, + get activeWindowId() { return activeWindowId }, +}; + +function forEachWindow(fn) { + getRecentWindows().forEach(function(data) { + fn(data, allWindows[data.id]); + }); +} + + +function signalToAll(name, e) { + if (nwProcessId) + return connection.call(0, {type: "signalToAll", arg: [name, e]}); + + forEachWindow(function(data, win) { + if (win && win.emit) win.emit(name, e); + }); +} + +function isPrimaryWindow(window) { + if (nwProcessId) return false; + var win = window.win; + if (win.options.nwProcessId) + return false; + return true; +} + +function findWindowForPath(path) { + var matches = []; + path = toInternalPath(path); + for (var id in windowData) { + var win = windowData[id]; + win.favorites && win.favorites.forEach(function(p, i) { + if (path.indexOf(p) === 0 && (path[p.length] == "/" || !path[p.length])) { + matches.push({ + win: win, + dist: path.substr(p.length).split("/").length + (i ? 1 : 0) + }); + return true; + } + }); + } + matches.sort(function(a, b) { + return a.dist - b.dist; + }); + + return matches[0] && matches[0].win; +} + +function restoreSession(win) { + var state = readJSONFile(this.statePath); + var toOpen = []; + Object.keys(state).forEach(function(id) { + var data = state[id]; + if (data.isOpen) { + data.isOpen = false; + toOpen.push(data); + } + if (!data.favorites) + data.favorites = []; + windowData[id] = data; + }); + + // Deal with user reopening app on osx + App.on("reopen", function(){ + openWindow({id: activeWindowId || "latest", focus: true}); + }); + // Event to open additional files (I hope) + App.on("open", function(cmdLine) { + // console.log(cmdLine); + var parsed = parseArgs(cmdLine); + var path = parsed._.pop(); + openWindowForPath(path); + }); + + var path = argv.parsed._.pop(); + if (path) { + // todo handle folders? + openWindowForPath(path); + } else { + if (!toOpen.length) + toOpen.push({id: "latest"}); + toOpen.sort(function(a, b) { + return b.time - a.time; + }); + toOpen[0].focus = true; + openWindow(toOpen[0]); + } +} + +function setFavorites(id, favorites) { + if (windowData[id]) { + windowData[id].favorites = favorites; + scheduleSave(); + } + updateTitle(id); + if (nwProcessId) + connection.call(0, {id: id, favorites: favorites, type: "setFavorites"}); +} + +function updateTitle(id) { + var winData = windowData[id]; + var win = allWindows[id]; + if (win && winData) { + var favs = winData.favorites; + if (winData.isRemote) { + win.displayName = "Remote " + /[^\/]*\/?$/.exec(winData.name || "")[0]; + } else { + win.displayName = /[^\/]*\/?$/.exec(favs[0] || "")[0]; + } + } +} + +function openWindowForPath(path, forceNew) { + var data = windowManager.findWindowForPath(path); + if (!data && !forceNew) + data = {id : "latest", isRemote: false, isEmpty: true}; + + data.focus = true; + data.filePath = path; + openWindow(data); +} + +function registerWindow(win, id) { + if (typeof id == "string") { + if (id[0] == "{") { + win.options = JSON.parse(id); + id = win.options.id; + } + } + + if (!win.options) + win.options = {id: id}; + + allWindows[id] = win; + activeWindowId = id; + win.on("close", function() { + if (win.listeners("close").length == 1) { + onClose(id); + win.close(true); + } + }); + win.on("focus", function() { + onFocus(id); + }); + + win.on("savePosition", function() { + savePosition(id); + }); + + if (id != "root") + scheduleSave(); + + if (win.options.nwProcessId && !allWindows.root) + nwProcessId = win.options.nwProcessId; + + if (nwProcessId) + updateWindowData(win.options); + + if (!connection) + connection = new MsgChannel(); + + if (!logStream) { + try { + logStream = fs.createWriteStream(settingDir + '/log.txt', nwProcessId ? {flags: 'a'} : undefined); + } catch (e) {} + } + + // if (id != "root") { + // setTimeout(function() { + // windowManager.registerWindow(); + // }); + // } +} + +function onClose(id) { + delete allWindows[id]; + var winState = windowData[id]; + + if (nwProcessId) { + return connection.call(0, {type: "onClose", id: id}); + } + + if (Object.keys(allWindows).length <= 1 && allWindows.root) { + if (process.platform != "darwin" || allWindows.root.quitting) { + allWindows.root.close(true); + allWindows.root.quitting = true; + } + } + + // Only save state when not quitting the application + if (allWindows.root && !allWindows.root.quitting) { + winState.isOpen = false; + savestate(); + } + + if (activeWindowId == id) + activeWindowId = 0; +} + +function quit() { + if (nwProcessId) + return connection.call(0, {type: "quit"}); + + var active = allWindows[activeWindowId]; + + forEachWindow(function(data, win) { + if (win && win != active && win.hide) + win.hide(); + }); + + if (active) { + active.emit("askForQuit", true); + } +} + +function quitAll(){ + if (nwProcessId) + return connection.call(0, {type: "quitAll"}); + + if (allWindows.root) + allWindows.root.quitting = true; + + forEachWindow(function(data, win) { + if (win && win.emit) win.emit("saveAndQuit"); + }); +} + +function unquit(){ + if (nwProcessId) + return connection.call(0, {type: "unquit"}); + + var active = allWindows[activeWindowId]; + forEachWindow(function(data, win) { + if (win && win != active && win.show) + win.show(); + }); + + active && active.show(); +} + +function onFocus(id) { + if (nwProcessId) + return connection.call(0, {type: "onFocus", id: id}); + activeWindowId = id; + if (windowData[id]) + windowData[id].time = Date.now(); +} + +function onShowWindow(win) { + if (win.options && win.options.focus) { + delete win.options.focus; + win.focus(); + } + if (win.$onShow) { + win.$onShow(null, win); + win.$onShow = undefined; + } +} + +function savePosition(id, position) { + var win = allWindows[id]; + if (!position) { + if (!win || win.isMinimized) + return; + position = [win.x, win.y, win.width, win.height]; + } + + if (nwProcessId) + return connection.call(0, {type: "savePosition", id: id, position: position}); + var winData = windowData[id]; + if (winData) { + winData.position = position; + scheduleSave(); + } +} + +function openQuitSure(callback){ + +} + +function openWindow(options, callback) { + if (nwProcessId) + return connection.call(0, {type: "openWindow", options: options}, callback); + + options = validateWindowOptions(options); + var id = options.id; + + if (allWindows[id]) { + if (options.duplicate && id == activeWindowId) { + id = options.id = options.id + ".1"; + } else { + win = allWindows[id]; + win.emit("focusWindow"); + if (options.filePath) + win.emit("openFile", {path: options.filePath}); + return callback && callback(); + } + } + + var window = allWindows.root.window; + var nwGui = window.require("nw.gui"); + + var isNewInstance = false; + var inProcessWindows = 0; + for (var i in allWindows) { + if (allWindows[i].options && allWindows[i].options.nwProcessId === 0) { + if (++inProcessWindows >= MAX_SAME_PROCESS) { + isNewInstance = true; + break; + } + } + } + options.nwProcessId = isNewInstance ? processIdCounter++ : 0; + + var url = "index.html?id=" + (isNewInstance ? escape(JSON.stringify(options)) : id); + if (options.reset) { + url += "&reset=state"; + delete options.reset; + } + var sc = window.screen; + var ah = sc.availHeight, aw = sc.availWidth, ax = sc.availLeft, ay = sc.availTop; + var h, w, x, y; + var position = options.position; + + if (!position) { + w = Math.min(1200, Math.round(0.7 * aw)); + h = Math.min(960, Math.round(0.8 * ah)); + x = Math.round(ax + (aw - w)/2); + y = Math.round(ay + (ah - h)/2); + } else { + x = Math.max(ax - 10, position[0]); + y = Math.max(ay - 10, position[1]); + w = Math.min(aw, position[2]); + h = Math.min(ah, position[3]); + } + + var win = nwGui.Window.open(url, { + "new-instance": !!isNewInstance, + height: h, + width: w, + left: x, + top: y, + show: false, + frame: false, + toolbar: false, + title: "Cloud9", + icon: "icon.png", + "win_bg": "#000000" + }); + win.moveTo(x, y); + win.options = options; + allWindows[id] = win; + win.$onShow = callback; + + if (isNewInstance) { + win.emit = function() { + connection.call(win.options.nwProcessId, { + type: "winEvent", + id: id, + arguments: Array.apply(null, arguments) + }); + }; + } + updateWindowData(options); +} + +function updateWindowData(options) { + var id = options.id; + var winState = windowData[id] || {}; + winState.id = id; + if (!winState.favorites) + winState.favorites = []; + + winState.isRemote = options.isRemote; + winState.time = Date.now(); + winState.isOpen = true; + + if (winState.isRemote) { + winState.name = options.name; + } + + windowData[id] = winState; +} + +function validateWindowOptions(options) { + options = options || {}; + if (options.isRemote) { + options.id = "remote/" + options.name; + } else { + var windows = Object.keys(windowData).map(function(id) { + return windowData[id]; + }).filter(function(x) { + return !x.isRemote; + }).sort(function(a, b) { + if (Boolean(b.isOpen) !== Boolean(a.isOpen)) + return b.isOpen ? 1 : -1; + if (b.isOpen || (a.favorites.length && b.favorites.length)) + return b.time - a.time; + return b.favorites.length ? 1 : -1; + }); + + if (options.id == "latest") { + for (var i = 0; i < windows.length; i++) { + var d = windows[i]; + if (options.isOpen === false && d.isOpen) + continue; + if (options.isRemote === false && d.isRemote) + continue; + if (options.isEmpty && d.favorites.length) + continue; + + d.filePath = options.filePath; + options = d; + break; + } + if (options.id == "latest") + options.id = 0; + } + if (!options.id) { + var id = 0; + if (windows.length > MAX_RECENT_WINDOWS) { + var last = windows[windows.length - 1]; + id = last.isOpen ? 0 : last.id; + } + + if (!id) { + do id++; + while (windowData[id]); + } + + if (!options.stateSettings) + options.reset = true; + options.id = id; + delete windowData[id]; + } + } + + if (windowData[options.id] && !options.position) + options.position = windowData[options.id].position; + + return options; +} + +function readJSONFile(path) { + try { + var data = fs.readFileSync(path, "utf8"); + return JSON.parse(data) || {}; + } + catch(e){ + console.log("Could not parse JSON", e); + return {}; + } +} + +function getRecentWindows(callback) { + if (nwProcessId && callback) + return connection.call(0, {type: "getRecentWindows"}, callback); + var names = Object.create(null); + var recentWindows = Object.keys(windowData).map(function(id) { + var data = windowData[id]; + var name = data.name; + if (!name && data.favorites[0]) + name = data.favorites[0].match(/[^\/]*\/?$/)[0]; + if (!name) + name = "[Untitled" + (id < 10 ? " " : "") + id + "]"; + // todo better handling for duplicate windows + if (names[name]) { + name += " (" + names[name] + ")"; + names[name]++; + } else { + names[name] = 1; + } + return { + name: name, + id: id, + time: data.time, + isRemote: !!data.isRemote, + isOpen: !!data.isOpen, + isEmpty: !data.isRemote && !data.favorites.length, + favorites: data.favorites.slice() + }; + }); + callback && callback(null, recentWindows); + return recentWindows; +} + +function registerSharedModule(name, construct) { + if (nwProcessId) return; + var root = allWindows.root; + if (!root.modules) + root.modules = Object.create(null); + if (!root.modules[name]) { + root.modules[name] = construct(windowManager, connection); + //@nightwing why eval? + // root.modules[name] = "(" + global.eval("(" + construct + ")")(windowManager, connection); + } +} + +var saveTimer, saving; +function savestate() { + if (nwProcessId) + return connection.call(0, {type: "windowManagerSave"}); + if (saving) + return scheduleSave(); + var content = JSON.stringify(windowData, function(x,y) { return y || undefined}); + saving = true; + var tmp = windowManager.statePath + "~"; + fs.writeFile(tmp, content, "utf8", function(err, result) { + saving = false; + fs.rename(tmp, windowManager.statePath, function(err, result) { + saving = false; + }); + }); +} +function scheduleSave() { + if (nwProcessId) + return connection.call(0, {type: "windowManagerSave"}); + if (!saveTimer) { + saveTimer = setTimeout(function() { + saveTimer = null; + savestate(); + }, 500); + } +} + +// remote projects +function loadData(url, callback) { + var xhr = new window.XMLHttpRequest(); + xhr.open("GET", url + "?access_token=fake_token", true); + xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"); + xhr.onload = function(e) { + callback(null, xhr.responseText); + }; + xhr.onabort = xhr.onerror = function(e) { + callback(e); + }; + xhr.send(""); +} + +// TODO add proper api to c9 server +function listC9Projects(user, callback) { + if (!user) + return callback(null, []); + + var url = "https://c9.io/" + user.name; + loadData(url, function(err, result) { + if (err) return callback(err); + var ownProjects = []; + var sharedProjects = []; + try { + var pids = Object.create(null); + JSON.parse(result.match(/projects:\s*(.*),/)[1]).forEach(function(x) { + var userName = x.owner_username || user.name; + + var project = { + name: userName + "/" + x.name, + projectName: x.name, + pid: x.pid, + isRemote: true, + }; + + if (pids[project.pid]) + return; + + pids[project.pid] = project; + + if (userName == user.name) + ownProjects.push(project); + else + sharedProjects.push(project); + }); + } catch(e) { + console.error(e); + return callback(e); + } + callback(null, { + shared: sharedProjects, + own: ownProjects + }); + }); +} + +function getRemoteWorkspaceConfig(projectName, callback) { + var url = "https://ide.c9.io/" + projectName + "?config=1"; + loadData(url, function(err, result, xhr) { + try { + var config = JSON.parse(result); + } catch(e) { + err = err || e; + } + callback(err, { + url: url, + plugins: config && config.architectConfig, + raw: config + }); + }); +} + + +var net = require('net'); +var projectWD = window.nwGui.App.dataPath; +var sockPath = process.platform == "win32" + ? "\\\\.\\pipe\\"+ projectWD +"\\c9.windowManager.socket" + : join(projectWD, "c9.windowManager.socket"); + +function MsgChannel() { + this.callbacks = {}; + this.callbackId = 0; + this.sockets = {}; + this.handlers = {}; + var self = this; + var buffer = ""; + function read(e, fn) { + e = e + ""; + var i; + while ((i = e.indexOf("\x01")) != -1) { + buffer += e.substring(0, i); + e = e.substr(i + 1); + try { + var msg = JSON.parse(buffer); + fn(msg); + } catch(e) { + console.error(buffer); + console.error(e); + } + buffer = ""; + } + buffer += e; + } + + if (nwProcessId) { + var client = net.connect(sockPath, function () {}); + this.client = client; + this.send(0, {type: "init"}); + client.on("data", function(e) { + read(e, function(msg) {self.onMessage(msg)}); + }); + client.on("error", function(e){ + console.error(e); + }); + } else { + var server = net.createServer(function(socket) { + socket.on("data", function(e){ + read(e, function(msg) { + if (msg.type == "init") + self.sockets[msg.$from] = socket; + else + self.onMessage(msg); + }); + }); + }); + + var startServer = function() { + try { + server.listen(sockPath); + } catch(e) { + console.error(e); + } + }; + if (process.platform == "win32") { + startServer(); + } else { + // Remove the stale socket, if it exists at sockPath + fs.unlink(sockPath, startServer); + } + } +} +(function(){ + this.send = function(processId, msg) { + msg.$from = nwProcessId; + if (nwProcessId) { + this.client.write(JSON.stringify(msg) + "\x01", "utf8"); + } else if (processId) { + this.sockets[processId].write(JSON.stringify(msg) + "\x01", "utf8"); + } else { + this.onMessage(msg); + } + }; + + this.call = function(processId, args, callback) { + if (callback) { + var id = this.callbackId++; + this.callbacks[id] = callback; + args.callbackId = id; + } + this.send(processId, args); + }; + + this.onMessage = function(msg) { + switch(msg.type) { + case "callback": + var callback = this.callbacks[msg.callbackId]; + if (callback) { + callback(msg.err, msg.data); + delete this.callbacks[msg.callbackId]; + } + break; + case "serverStart": + server.start(msg.options, function(err, data) { + connection.call(msg.$from, { + err: err, + data: data, + type: "callback", + callbackId: msg.callbackId + }); + }); + break; + case "openWindow": + openWindow(msg.options, function() { + connection.call(msg.$from, { + type: "callback", + callbackId: msg.callbackId + }); + }); + break; + case "windowManagerSave": + scheduleSave(); + break; + + case "quit": + quit(); + break; + case "unquit": + unquit(); + break; + case "quitAll": + quitAll(); + break; + case "onClose": + onClose(msg.id); + break; + case "onFocus": + onFocus(msg.id); + break; + case "savePosition": + savePosition(msg.id, msg.position); + return; + case "getRecentWindows": + getRecentWindows(function(err, data) { + connection.call(msg.$from, { + err: err, + data: data, + type: "callback", + callbackId: msg.callbackId + }); + }); + break; + case "setFavorites": + setFavorites(msg.id, msg.favorites); + break; + case "winEvent": + var win = allWindows[msg.id]; + if (win) { + win.emit.apply(win, msg.arguments); + } + break; + case "signalToAll": + signalToAll.apply(null, msg.arg); + break; + default: + if (this.handlers[msg.type]) + this.handlers[msg.type](msg); + } + }; + + this.sendToWindow = function(id, type, msg) { + var win = allWindows[id]; + var processId = win.options.nwProcessId; + this.send(processId, { + id: id, + type: "winEvent", + arguments: [type, msg] + }); + }; + + this.on = function(type, handler) { + this.handlers[type] = handler; + }; + +}).call(MsgChannel.prototype); + + +// +module.exports = server; diff --git a/node_modules/ace/.gitignore b/node_modules/ace/.gitignore new file mode 100644 index 00000000..5f8ec711 --- /dev/null +++ b/node_modules/ace/.gitignore @@ -0,0 +1,23 @@ +# Junk that could exist anywhere: +.DS_Store +*.swp +*.tmp +*~ + +# Project files that should not be in the repo +.* +\#* +!/.gitignore +.*.gz +*.tmTheme.js + +# A handy place to put stuff that git should ignore: +/ignore/ +node_modules/ +jam/ +* * + +.git-ref +npm-debug.log +deps/ +build/* diff --git a/node_modules/ace/.gitmodules b/node_modules/ace/.gitmodules new file mode 100644 index 00000000..07bbe371 --- /dev/null +++ b/node_modules/ace/.gitmodules @@ -0,0 +1,6 @@ +[submodule "doc/wiki"] + path = doc/wiki + url = https://github.com/ajaxorg/ace.wiki.git +[submodule "build"] + path = build + url = https://github.com/ajaxorg/ace-builds.git diff --git a/node_modules/ace/.travis.yml b/node_modules/ace/.travis.yml new file mode 100644 index 00000000..d2f32091 --- /dev/null +++ b/node_modules/ace/.travis.yml @@ -0,0 +1 @@ +language: node_js \ No newline at end of file diff --git a/node_modules/ace/CNAME b/node_modules/ace/CNAME new file mode 100644 index 00000000..75431b15 --- /dev/null +++ b/node_modules/ace/CNAME @@ -0,0 +1 @@ +ace.c9.io diff --git a/node_modules/ace/CONTRIBUTING.md b/node_modules/ace/CONTRIBUTING.md new file mode 100644 index 00000000..c44edcb0 --- /dev/null +++ b/node_modules/ace/CONTRIBUTING.md @@ -0,0 +1,22 @@ +Contributing +------------ + +Ace is a community project and wouldn't be what it is without contributions! We actively encourage and support contributions. The Ace source code is released under the BSD License. This license is very simple, and is friendly to all kinds of projects, whether open source or not. Take charge of your editor and add your favorite language highlighting and keybindings! + +Feel free to fork and improve/enhance Ace any way you want. If you feel that the editor or the Ace community will benefit from your changes, please open a pull request. To protect the interests of the Ace contributors and users we require contributors to sign a Contributors License Agreement (CLA) before we pull the changes into the main repository. Our CLA is the simplest of agreements, requiring that the contributions you make to an ajax.org project are only those you're allowed to make. This helps us significantly reduce future legal risk for everyone involved. It is easy, helps everyone, takes ten minutes, and only needs to be completed once. + +There are two versions of the agreement: + +1. [The Individual CLA](https://github.com/ajaxorg/ace/raw/master/doc/Contributor_License_Agreement-v2.pdf): use this version if you're working on an ajax.org in your spare time, or can clearly claim ownership of copyright in what you'll be submitting. +2. [The Corporate CLA](https://github.com/ajaxorg/ace/raw/master/doc/Corporate_Contributor_License_Agreement-v2.pdf): have your corporate lawyer review and submit this if your company is going to be contributing to ajax.org projects + +If you want to contribute to an ajax.org project please print the CLA and fill it out and sign it. Then either send it by snail mail or fax to us or send it back scanned (or as a photo) by email. + +Email: ace+cla@c9.io + +Fax: +31 (0) 206388953 + +Address: Ajax.org B.V. + Keizersgracht 241 + 1016 EA, Amsterdam + the Netherlands \ No newline at end of file diff --git a/node_modules/ace/ChangeLog.txt b/node_modules/ace/ChangeLog.txt new file mode 100644 index 00000000..cad1e517 --- /dev/null +++ b/node_modules/ace/ChangeLog.txt @@ -0,0 +1,325 @@ +2014.11.08 Version 1.1.8 + +* API Changes + - `editor.commands.commandKeyBinding` now contains direct map from keys to commands instead of grouping them by hashid + +* New Features + - Improved autoindent for html and php modes (Adam Jimenez) + - Find All from searchbox (Colton Voege) + +* new language modes + - Elixir, Elm + +2014.09.21 Version 1.1.7 + +* Bugfixes + - fix several bugs in autocompletion + - workaround for inaccurate getBoundingClientRect on chrome 37 + +2014.08.17 Version 1.1.6 + +* Bugfixes + - fix regression in double tap to highlight + - Improved Latex Mode (Daniel Felder) + +* API Changes + - editor.destroy destroys editor.session too (call editor.setSession(null) to prevent that) + +* new language modes + - Praat (José Joaquín Atria) + - Eiffel (Victorien Elvinger) + - G-code (Adam Joseph Cook) + +2014.07.09 Version 1.1.5 + +* Bugfixes + - fix regression in autocomplete popup + +* new language modes + - gitignore (Devon Carew) + +2014.07.01 Version 1.1.4 + +* New Features + - Highlight matching tags (Adam Jimenez) + - Improved jump to matching command (Adam Jimenez) + +* new language modes + - AppleScript (Yaogang Lian) + - Vala + +2014.03.08 Version 1.1.3 + +* New Features + - Allow syntax checkers to be loaded from CDN (Derk-Jan Hartman) + - Add ColdFusion behavior (Abram Adams) + - add showLineNumbers option + - Add html syntax checker (danyaPostfactum) + +* new language modes + - Gherkin (Patrick Nevels) + - Smarty + +2013.12.02 Version 1.1.2 + +* New Features + - Accessibility Theme for Ace (Peter Xiao) + - use snipetManager for expanding emmet snippets + - update jshint to 2.1.4 + - improve php syntax checker (jdalegonzalez) + - add option for autoresizing + - add option for autohiding vertical scrollbar + - improvements to highlighting of xml like languages (danyaPostfactum) + - add support for autocompletion and snippets (gjtorikyan danyaPostfactum and others) + - add option to merge similar changes in undo history + - add scrollPastEnd option + - use html5 dragndrop for text dragging (danyaPostfactum) + +* API Changes + - fixed typo in HashHandler commmandManager + +* new language modes + - Nix (Zef Hemel) + - Protobuf (Zef Hemel) + - Soy + - Handlebars + +2013.06.04 Version 1.1.1 + + - Improved emacs keybindings (Robert Krahn) + - Added markClean, isClean methods to UndoManager (Joonsoo Jeon) + - Do not allow `Toggle comments` command to remove spaces from indentation + - Softer colors for indent guides in dark themes + +* new language modes + - Ada + - Assembly_x86 + - Cobol + - D + - ejs + - MATLAB + - MySQL + - Twig + - Verilog + +2013.05.01, Version 1.1.0 + +* API Changes + - Default position of the editor container is changed to relative. Add `.ace_editor {position: absolute}` css rule to restore old behavior + - Changed default line-height to `normal` to not conflict with bootstrap. Use `line-height: inherit` for old behavior. + - Changed marker types accepted by session.addMarker. It now accepts "text"|"line"|"fullLine"|"screenLine" + - Internal classnames used by editor were made more consistent + - Introduced `editor.setOption/getOption/setOptions/getOptions` methods + - Introduced positionToIndex, indexToPosition methods + +* New Features + - Improved emacs mode (chetstone) + with Incremental search and Occur modes (Robert Krahn) + + - Improved ime handling + - Searchbox (Vlad Zinculescu) + + - Added elastic tabstops lite extension (Garen Torikian) + - Added extension for whitespace manipulation + - Added extension for enabling spellchecking from contextmenu + - Added extension for displaying available keyboard shortcuts (Matthew Christopher Kastor-Inare III) + - Added extension for displaying options panel (Matthew Christopher Kastor-Inare III) + - Added modelist extension (Matthew Christopher Kastor-Inare III) + + - Improved toggleCommentLines and added ToggleCommentBlock command + - `:;` pairing in CSS mode (danyaPostfactum) + + - Added suppoert for Delete and SelectAll from context menu (danyaPostfactum) + + - Make wrapping behavior optional + - Selective bracket insertion/skipping + + - Added commands for increase/decrease numbers, sort lines (Vlad Zinculescu) + - Folding for Markdown, Lua, LaTeX + - Selective bracket insertion/skipping for C-like languages + +* Many new languages + - Scheme (Mu Lei) + - Dot (edwardsp) + - FreeMarker (nguillaumin) + - Tiny Mushcode (h3rb) + - Velocity (Ryan Griffith) + - TOML (Garen Torikian) + - LSL (Nemurimasu Neiro, Builders Brewery) + - Curly (Libo Cannici) + - vbScript (Jan Jongboom) + - R (RStudio) + - ABAP + - Lucene (Graham Scott) + - Haml (Garen Torikian) + - Objective-C (Garen Torikian) + - Makefile (Garen Torikian) + - TypeScript (Garen Torikian) + - Lisp (Garen Torikian) + - Stylus (Garen Torikian) + - Dart (Garen Torikian) + +* Live syntax checks + - PHP (danyaPostfactum) + - Lua + +* New Themes + - Chaos + - Terminal + +2012.09.17, Version 1.0.0 + +* New Features + - Multiple cursors and selections (https://c9.io/site/blog/2012/08/be-an-armenian-warrior-with-block-selection-on-steroids/) + - Fold buttons displayed in the gutter + - Indent Guides + - Completely reworked vim mode (Sergi Mansilla) + - Improved emacs keybindings + - Autoclosing of html tags (danyaPostfactum) + +* 20 New language modes + - Coldfusion (Russ) + - Diff + - GLSL (Ed Mackey) + - Go (Davide Saurino) + - Haxe (Jason O'Neil) + - Jade (Garen Torikian) + - jsx (Syu Kato) + - LaTeX (James Allen) + - Less (John Roepke) + - Liquid (Bernie Telles) + - Lua (Lee Gao) + - LuaPage (Choonster) + - Markdown (Chris Spencer) + - PostgreSQL (John DeSoi) + - Powershell (John Kane) + - Sh (Richo Healey) + - SQL (Jonathan Camile) + - Tcl (Cristoph Hochreiner) + - XQuery (William Candillion) + - Yaml (Meg Sharkey) + + * Live syntax checks + - for XQuery and JSON + +* New Themes + - Ambiance (Irakli Gozalishvili) + - Dreamweaver (Adam Jimenez) + - Github (bootstraponline) + - Tommorrow themes (https://github.com/chriskempson/tomorrow-theme) + - XCode + +* Many Small Enhancements and Bugfixes + +2011.08.02, Version 0.2.0 + +* Split view (Julian Viereck) + - split editor area horizontally or vertivally to show two files at the same + time + +* Code Folding (Julian Viereck) + - Unstructured code folding + - Will be the basis for language aware folding + +* Mode behaviours (Chris Spencer) + - Adds mode specific hooks which allow transformations of entered text + - Autoclosing of braces, paranthesis and quotation marks in C style modes + - Autoclosing of angular brackets in XML style modes + +* New language modes + - Clojure (Carin Meier) + - C# (Rob Conery) + - Groovy (Ben Tilford) + - Scala (Ben Tilford) + - JSON + - OCaml (Sergi Mansilla) + - Perl (Panagiotis Astithas) + - SCSS/SASS (Andreas Madsen) + - SVG + - Textile (Kelley van Evert) + - SCAD (Jacob Hansson) + +* Live syntax checks + - Lint for CSS using CSS Lint + - CoffeeScript + +* New Themes + - Crimson Editor (iebuggy) + - Merbivore (Michael Schwartz) + - Merbivore soft (Michael Schwartz) + - Solarized dark/light (David Alan Hjelle) + - Vibrant Ink (Michael Schwartz) + +* Small Features/Enhancements + - Lots of render performance optimizations (Harutyun Amirjanyan) + - Improved Ruby highlighting (Chris Wanstrath, Trent Ogren) + - Improved PHP highlighting (Thomas Hruska) + - Improved CSS highlighting (Sean Kellogg) + - Clicks which cause the editor to be focused don't reset the selection + - Make padding text layer specific so that print margin and active line + highlight are not affected (Irakli Gozalishvili) + - Added setFontSize method + - Improved vi keybindings (Trent Ogren) + - When unfocused make cursor transparent instead of removing it (Harutyun Amirjanyan) + - Support for matching groups in tokenizer with arrays of tokens (Chris Spencer) + +* Bug fixes + - Add support for the new OSX scroll bars + - Properly highlight JavaScript regexp literals + - Proper handling of unicode characters in JavaScript identifiers + - Fix remove lines command on last line (Harutyun Amirjanyan) + - Fix scroll wheel sluggishness in Safari + - Make keyboard infrastructure route keys like []^$ the right way (Julian Viereck) + +2011.02.14, Version 0.1.6 + +* Floating Anchors + - An Anchor is a floating pointer in the document. + - Whenever text is inserted or deleted before the cursor, the position of + the cursor is updated + - Usesd for the cursor and selection + - Basis for bookmarks, multiple cursors and snippets in the future +* Extensive support for Cocoa style keybindings on the Mac +* New commands: + - center selection in viewport + - remove to end/start of line + - split line + - transpose letters +* Refator markers + - Custom code can be used to render markers + - Markers can be in front or behind the text + - Markers are now stored in the session (was in the renderer) +* Lots of IE8 fixes including copy, cut and selections +* Unit tests can also be run in the browser + +* Soft wrap can adapt to the width of the editor (Mike Ratcliffe, Joe Cheng) +* Add minimal node server server.js to run the Ace demo in Chrome +* The top level editor.html demo has been renamed to index.html +* Bug fixes + - Fixed gotoLine to consider wrapped lines when calculating where to scroll to (James Allen) + - Fixed isues when the editor was scrolled in the web page (Eric Allam) + - Highlighting of Python string literals + - Syntax rule for PHP comments + +2011.02.08, Version 0.1.5 + +* Add Coffeescript Mode (Satoshi Murakami) +* Fix word wrap bug (Julian Viereck) +* Fix packaged version of the Eclipse mode +* Loading of workers is more robust +* Fix "click selection" +* Allow tokizing empty lines (Daniel Krech) +* Make PageUp/Down behavior more consistent with native OS (Joe Cheng) + +2011.02.04, Version 0.1.4 + +* Add C/C++ mode contributed by Gastón Kleiman +* Fix exception in key input + +2011.02.04, Version 0.1.3 + +* Let the packaged version play nice with requireJS +* Add Ruby mode contributed by Shlomo Zalman Heigh +* Add Java mode contributed by Tom Tasche +* Fix annotation bug +* Changing a document added a new empty line at the end diff --git a/node_modules/ace/LICENSE b/node_modules/ace/LICENSE new file mode 100644 index 00000000..4760be2a --- /dev/null +++ b/node_modules/ace/LICENSE @@ -0,0 +1,24 @@ +Copyright (c) 2010, Ajax.org B.V. +All rights reserved. + +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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. diff --git a/node_modules/ace/Makefile b/node_modules/ace/Makefile new file mode 100644 index 00000000..29cf0495 --- /dev/null +++ b/node_modules/ace/Makefile @@ -0,0 +1,44 @@ +.PHONY : doc build clean dist + +pre_build: + git rev-parse HEAD > .git-ref + mkdir -p build/src + mkdir -p build/demo/kitchen-sink + mkdir -p build/textarea/src + + cp -r demo/kitchen-sink/styles.css build/demo/kitchen-sink/styles.css + cp demo/kitchen-sink/logo.png build/demo/kitchen-sink/logo.png + cp -r doc/site/images build/textarea + +build: pre_build + ./Makefile.dryice.js normal + ./Makefile.dryice.js demo + +# Minimal build: call Makefile.dryice.js only if our sources changed +basic: build/src/ace.js + +build/src/ace.js : ${wildcard lib/*} \ + ${wildcard lib/*/*} \ + ${wildcard lib/*/*/*} \ + ${wildcard lib/*/*/*/*} \ + ${wildcard lib/*/*/*/*/*} \ + ${wildcard lib/*/*/*/*/*/*} + ./Makefile.dryice.js + +doc: + cd doc;\ + (test -d node_modules && npm update) || npm install;\ + node build.js + +clean: + rm -rf build + rm -rf ace-* + rm -f ace-*.tgz + +ace.tgz: build + mv build ace-`./version.js`/ + cp Readme.md ace-`./version.js`/ + cp LICENSE ace-`./version.js`/ + tar cvfz ace-`./version.js`.tgz ace-`./version.js`/ + +dist: clean build ace.tgz diff --git a/node_modules/ace/Makefile.dryice.js b/node_modules/ace/Makefile.dryice.js new file mode 100755 index 00000000..f6f4b42f --- /dev/null +++ b/node_modules/ace/Makefile.dryice.js @@ -0,0 +1,566 @@ +#!/usr/bin/env node +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +var fs = require("fs"); +var path = require("path"); +var copy = require('architect-build/copy'); +var build = require('architect-build/build'); + +var ACE_HOME = __dirname; +var BUILD_DIR = ACE_HOME + "/build"; +var CACHE = {}; + +function main(args) { + if (args.indexOf("updateModes") !== -1) { + return updateModes(); + } + var type = "minimal"; + args = args.map(function(x) { + if (x[0] == "-" && x[1] != "-") + return "-" + x; + return x; + }).filter(Boolean); + + if (args[2] && (args[2][0] != "-" || args[2].indexOf("h") != -1)) + type = args[2]; + + var i = args.indexOf("--target"); + if (i != -1 && args[i+1]) + BUILD_DIR = args[i+1]; + + if (args.indexOf("--h") == -1) { + if (type == "minimal") { + buildAce({ + compress: args.indexOf("--m") != -1, + noconflict: args.indexOf("--nc") != -1, + shrinkwrap: args.indexOf("--s") != -1 + }); + } else if (type == "normal") { + ace(); + } else if (type == "demo") { + demo(); + } else if (type == "full") { + ace(); + demo(); + } else if (type == "highlighter") { + // TODO + } + } +} + +function showHelp(type) { + console.log("--- Ace Dryice Build Tool ---"); + console.log(""); + console.log("Options:"); + console.log(" minimal Places necessary Ace files out in build dir; uses configuration flags below [default]"); + console.log(" normal Runs four Ace builds--minimal, minimal-noconflict, minimal-min, and minimal-noconflict-min"); + console.log(" demo Runs demo build of Ace"); + console.log(" full all of above"); + console.log(" highlighter "); + console.log("args:"); + console.log(" --target ./path path to build folder"); + console.log("flags:"); + console.log(" --h print this help"); + console.log(" --m minify"); + console.log(" --nc namespace require"); + console.log(" --s shrinkwrap (combines all output files into one)"); + console.log(""); + if (type) + console.log(" output for " + type + " generated in " + BUILD_DIR); +} + +function ace() { + console.log('# ace License | Readme | Changelog ---------'); + + copy.file(ACE_HOME + "/build_support/editor.html", BUILD_DIR + "/editor.html"); + copy.file(ACE_HOME + "/LICENSE", BUILD_DIR + "/LICENSE"); + copy.file(ACE_HOME + "/ChangeLog.txt", BUILD_DIR + "/ChangeLog.txt"); + + console.log('# ace ---------'); + for (var i = 0; i < 4; i++) + buildAce({compress: i & 2, noconflict: i & 1}); +} + +function demo() { + console.log('# kitchen sink ---------'); + + var version = "", ref = ""; + try { + version = JSON.parse(fs.readFileSync(ACE_HOME + "/package.json")).version; + ref = fs.readFileSync(ACE_HOME + "/.git-ref").toString(); + } catch(e) {} + + function changeComments(data) { + return (data + .replace("doc/site/images/ace-logo.png", "demo/kitchen-sink/ace-logo.png") + .replace(//g, "") + .replace(/PACKAGE\-\->|")} + function script(str) {result.push('')} + scripts.forEach(function(s) { + s = s.replace(/"/g, ""); + if (s == "ace/ace") { + comment("load ace"); + script("ace"); + } else { + var extName = s.match(/[^/]*$/)[0]; + comment("load ace " + extName + " extension"); + script("ext-" + extName); + } + }); + result.push(" + +``` + +With "editor" being the id of the DOM element, which should be converted to an editor. Note that this element must be explicitly sized and positioned `absolute` or `relative` for Ace to work. e.g. + +```css + #editor { + position: absolute; + width: 500px; + height: 400px; + } +``` + +To change the theme simply include the Theme's JavaScript file + +```html + +``` + +and configure the editor to use the theme: + +```javascript + editor.setTheme("ace/theme/twilight"); +``` + +By default the editor only supports plain text mode; many other languages are available as separate modules. After including the mode's JavaScript file: + +```html + +``` + +The mode can then be used like this: + +```javascript + var JavaScriptMode = require("ace/mode/javascript").Mode; + editor.getSession().setMode(new JavaScriptMode()); +``` + +Documentation +------------- + +Additional usage information, including events to listen to and extending syntax highlighters, can be found [on the main Ace website](http://ace.c9.io). + +You can also find API documentation at [http://ace.c9.io/#nav=api](http://ace.c9.io/#nav=api). + +Also check out the sample code for the kitchen sink [demo app](https://github.com/ajaxorg/ace/blob/master/demo/kitchen-sink/demo.js). + +If you still need help, feel free to drop a mail on the [ace mailing list](http://groups.google.com/group/ace-discuss), or at `irc.freenode.net#ace`. + +Running Ace +----------- + +After the checkout Ace works out of the box. No build step is required. To try it out, simply start the bundled mini HTTP server: + +```bash + ./static.py +``` + +Or using Node.JS + +```bash + npm install mime + node ./static.js +``` + +The editor can then be opened at http://localhost:8888/kitchen-sink.html. + +To open the editor with a file:/// URL see [the wiki](https://github.com/ajaxorg/ace/wiki/Running-Ace-from-file). + +Building Ace +----------- + +You do not generally need to build ACE. The [ace-builds repository](https://github.com/ajaxorg/ace-builds/) endeavours to maintain the latest build, and you can just copy one of _src*_ subdirectories somewhere into your project. + +However, all you need is Node.js and npm installed to package ACE. Just run `npm install` in the ace folder to install dependencies: + +```bash + npm install + node ./Makefile.dryice.js +``` + +To package Ace, we use the dryice build tool developed by the Mozilla Skywriter team. Call `node Makefile.dryice.js` on the command-line to start the packing. This build script accepts the following options + +```bash +-m minify build files with uglify-js +-nc namespace require and define calls with "ace" +-bm builds the bookmarklet version +--target ./path specify relative path for output folder (default value is "./build") +``` + +To generate all the files in the ace-builds repository, run `node Makefile.dryice.js full --target ../ace-builds` + +Running the Unit Tests +---------------------- + +The Ace unit tests can run on node.js. Assuming you have already done `npm install`, just call: + +```bash + node lib/ace/test/all.js +``` + +You can also run the tests in your browser by serving: + + http://localhost:8888/lib/ace/test/tests.html + +This makes debugging failing tests way more easier. + +Contributing +----------------------------- + +Ace is a community project and wouldn't be what it is without contributions! We actively encourage and support contributions. The Ace source code is released under the BSD License. This license is very simple, and is friendly to all kinds of projects, whether open source or not. Take charge of your editor and add your favorite language highlighting and keybindings! + +Feel free to fork and improve/enhance Ace any way you want. If you feel that the editor or the Ace community will benefit from your changes, please open a pull request. For more information on our contributing guidelines, see [CONTRIBUTING.md](https://github.com/ajaxorg/ace/blob/master/CONTRIBUTING.md). + +Continuous Integration status +----------------------------- + +This project is tested with [Travis CI](http://travis-ci.org) +[![Build Status](https://secure.travis-ci.org/ajaxorg/ace.png?branch=master)](http://travis-ci.org/ajaxorg/ace) + + diff --git a/node_modules/ace/api/ace.html b/node_modules/ace/api/ace.html new file mode 100644 index 00000000..c0f40b1d --- /dev/null +++ b/node_modules/ace/api/ace.html @@ -0,0 +1,149 @@ + +
+
+
+
+
+

Ace +

+ +
+
+
+
+

The main class required to set up an Ace instance in the browser.

+ +
+
+
+

Methods

+
+
+
+
+ +
+
+

Creates a new EditSession, and returns the associated Document.

+ +
+

Creates a new EditSession, and returns the associated Document.

+ +

Arguments

textDocument | String

Required. If text is a Document, it associates the EditSession with it. Otherwise, a new Document is created, with the initial text

+
modeTextMode

Required. The inital language mode to use for the document

+
+
+
+
+
+
+
+
+
+
+ +
+
+

Embeds the Ace editor into the DOM, at the element provided by el.

+ +
+

Embeds the Ace editor into the DOM, at the element provided by el.

+ +

Arguments

elString | DOMElement

Required. Either the id of an element, or the element itself

+
+
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Provides access to require in packed noconflict mode

+ +
+

Provides access to require in packed noconflict mode

+ +

Arguments

moduleNameString

Required.

+
+
+
+
+
+
+
+ + + + + +
+
\ No newline at end of file diff --git a/node_modules/ace/api/anchor.html b/node_modules/ace/api/anchor.html new file mode 100644 index 00000000..727c1cb8 --- /dev/null +++ b/node_modules/ace/api/anchor.html @@ -0,0 +1,272 @@ + +
+
+
+
+
+

Anchor +

+ +
+
+
+
+

Defines the floating pointer in the document. Whenever text is inserted or deleted before the cursor, the position of the cursor is updated.

+ +
+
+
+

Constructors

+
+
+
+
+ +
+
+

Creates a new Anchor and associates it with a document.

+ +
+

Creates a new Anchor and associates it with a document.

+ +

Arguments

docDocument

Required. The document to associate with the anchor

+
rowNumber

Required. The starting row position

+
columnNumber

Required. The starting column position

+
+
+
+
+
+
+

Events

+
+
+
+
+
    +
  • +
      +
    • Anchor.on("change", function(Object e))
    • +
    +
      +
    +
  • +
+
+
+

Fires whenever the anchor position changes.

+ +
+

Fires whenever the anchor position changes.

+

Both of these objects have a row and column property corresponding to the position.

+

Events that can trigger this function include setPosition().

+ +

Arguments

eObject

Required. An object containing information about the anchor position. It has two properties:

+
    +
  • old: An object describing the old Anchor position
  • +
  • value: An object describing the new Anchor position
  • +
+
+
+
+
+
+
+

Methods

+
+
+
+
+
    +
  • +
      +
    • Anchor.detach()
    • +
    +
      +
    +
  • +
+
+
+

When called, the 'change' event listener is removed.

+ +
+

When called, the 'change' event listener is removed.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Anchor.getDocument() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the current document.

+ +
+

Returns the current document.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Anchor.getPosition() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns an object identifying the row and column position of the current anchor.

+ +
+

Returns an object identifying the row and column position of the current anchor.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Anchor.onChange()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+

Sets the anchor position to the specified row and column. If noClip is true, the position is not clipped.

+ +
+

Sets the anchor position to the specified row and column. If noClip is true, the position is not clipped.

+ +

Arguments

rowNumber

Required. The row index to move the anchor to

+
columnNumber

Required. The column index to move the anchor to

+
noClipBoolean

Required. Identifies if you want the position to be clipped

+
+
+
+
+
+
+
+ + + + + +
+
\ No newline at end of file diff --git a/node_modules/ace/api/background_tokenizer.html b/node_modules/ace/api/background_tokenizer.html new file mode 100644 index 00000000..a4ef22c2 --- /dev/null +++ b/node_modules/ace/api/background_tokenizer.html @@ -0,0 +1,320 @@ + +
+
+
+
+
+

BackgroundTokenizer +

+ +
+
+
+
+

Tokenizes the current Document in the background, and caches the tokenized rows for future use.

+

If a certain row is changed, everything below that row is re-tokenized.

+ +
+
+
+

Constructors

+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Creates a new BackgroundTokenizer object.

+ +
+

Creates a new BackgroundTokenizer object.

+ +

Arguments

tokenizerTokenizer

Required. The tokenizer to use

+
editorEditor

Required. The editor to associate with

+
+
+
+
+
+
+

Events

+
+
+
+
+
    +
  • +
      +
    • BackgroundTokenizer.on("update", function(Object e))
    • +
    +
      +
    +
  • +
+
+
+

Fires whenever the background tokeniziers between a range of rows are going to be updated.

+ +
+

Fires whenever the background tokeniziers between a range of rows are going to be updated.

+ +

Arguments

eObject

Required. An object containing two properties, first and last, which indicate the rows of the region being updated.

+
+
+
+
+
+
+

Methods

+
+
+
+
+
    +
  • +
      +
    • BackgroundTokenizer.fireUpdateEvent(Number firstRow, Number lastRow)
    • +
    +
      +
    +
  • +
+
+
+

Emits the 'update' event. firstRow and lastRow are used to define the boundaries of the region to be updated.

+ +
+

Emits the 'update' event. firstRow and lastRow are used to define the boundaries of the region to be updated.

+ +

Arguments

firstRowNumber

Required. The starting row region

+
lastRowNumber

Required. The final row region

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • BackgroundTokenizer.getState(Number row)
    • +
    +
      +
    +
  • +
+
+
+

Returns the state of tokenization at the end of a row.

+ +
+

Returns the state of tokenization at the end of a row.

+ +

Arguments

rowNumber

Required. The row to get state at

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • BackgroundTokenizer.getTokens(Number row)
    • +
    +
      +
    +
  • +
+
+
+

Gives list of tokens of the row. (tokens are cached)

+ +
+

Gives list of tokens of the row. (tokens are cached)

+ +

Arguments

rowNumber

Required. The row to get tokens at

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • BackgroundTokenizer.setDocument(Document doc)
    • +
    +
      +
    +
  • +
+
+
+

Sets a new document to associate with this object.

+ +
+

Sets a new document to associate with this object.

+ +

Arguments

docDocument

Required. The new document to associate with

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • BackgroundTokenizer.setTokenizer(Tokenizer tokenizer)
    • +
    +
      +
    +
  • +
+
+
+

Sets a new tokenizer for this object.

+ +
+

Sets a new tokenizer for this object.

+ +

Arguments

tokenizerTokenizer

Required. The new tokenizer to use

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • BackgroundTokenizer.start(Number startRow)
    • +
    +
      +
    +
  • +
+
+
+

Starts tokenizing at the row indicated.

+ +
+

Starts tokenizing at the row indicated.

+ +

Arguments

startRowNumber

Required. The row to start at

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • BackgroundTokenizer.stop()
    • +
    +
      +
    +
  • +
+
+
+

Stops tokenizing.

+ +
+

Stops tokenizing.

+ +
+
+
+
+
+
+ + + + + +
+
\ No newline at end of file diff --git a/node_modules/ace/api/command_manager.html b/node_modules/ace/api/command_manager.html new file mode 100644 index 00000000..142ca741 --- /dev/null +++ b/node_modules/ace/api/command_manager.html @@ -0,0 +1,55 @@ + +
+
+
+
+
+

CommandManager +

+ +
+
+
+
+

new CommandManager(platform, commands)

+ +
+
+
+
+ + + + + +
+
\ No newline at end of file diff --git a/node_modules/ace/api/document.html b/node_modules/ace/api/document.html new file mode 100644 index 00000000..f1fc2ff5 --- /dev/null +++ b/node_modules/ace/api/document.html @@ -0,0 +1,927 @@ + +
+
+
+
+ +
+
+
+

Contains the text of the document. Document can be attached to several EditSessions.

+

At its core, Documents are just an array of strings, with each row in the document matching up to the array index.

+ +
+
+
+

Constructors

+
+
+
+
+ +
+
+

Creates a new Document. If text is included, the Document contains those strings; otherwise, it's empty.

+ +
+

Creates a new Document. If text is included, the Document contains those strings; otherwise, it's empty.

+ +

Arguments

textString | Array

Required. The starting text

+
+
+
+
+
+
+

Events

+
+
+
+
+
    +
  • +
      +
    • Document.on("change", function(Object e))
    • +
    +
      +
    +
  • +
+
+
+

Fires whenever the document changes.

+ +
+

Fires whenever the document changes.

+

Several methods trigger different "change" events. Below is a list of each action type, followed by each property that's also available:

+ + +

Arguments

eObject

Required. Contains at least one property called "action". "action" indicates the action that triggered the change. Each action also has a set of additional properties.

+
+
+
+
+
+
+

Methods

+
+
+
+
+
    +
  • +
      +
    • Document.applyDeltas(Object deltas)
    • +
    +
      +
    +
  • +
+
+
+

Applies all the changes previously accumulated. These can be either 'includeText', 'insertLines', 'removeText', and 'removeLines'.

+ +
+

Applies all the changes previously accumulated. These can be either 'includeText', 'insertLines', 'removeText', and 'removeLines'.

+ +

Arguments

deltasObject

Required.

+
+
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Creates a new Anchor to define a floating point in the document.

+ +
+

Creates a new Anchor to define a floating point in the document.

+ +

Arguments

rowNumber

Required. The row number to use

+
columnNumber

Required. The column number to use

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Document.getAllLines()
    • +
    +
      +
    +
  • +
+
+
+

Returns all lines in the document as string array.

+ +
+

Returns all lines in the document as string array. Warning: The caller should not modify this array!

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Document.getLength()
    • +
    +
      +
    +
  • +
+
+
+

Returns the number of rows in the document.

+ +
+

Returns the number of rows in the document.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Document.getLine(Number row)
    • +
    +
      +
    +
  • +
+
+
+

Returns a verbatim copy of the given line as it is in the document

+ +
+

Returns a verbatim copy of the given line as it is in the document

+ +

Arguments

rowNumber

Required. The row index to retrieve

+
+
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Returns an array of strings of the rows between firstRow and lastRow. This function is inclusive of lastRow.

+ +
+

Returns an array of strings of the rows between firstRow and lastRow. This function is inclusive of lastRow.

+ +

Arguments

firstRowNumber

Required. The first row index to retrieve

+
lastRowNumber

Required. The final row index to retrieve

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Document.getNewLineCharacter() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the newline character that's being used, depending on the value of newLineMode.

+ +
+

Returns the newline character that's being used, depending on the value of newLineMode.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Document.getNewLineMode() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the type of newlines being used; either windows, unix, or auto

+ +
+

Returns the type of newlines being used; either windows, unix, or auto

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Document.getTextRange(Range range)
    • +
    +
      +
    +
  • +
+
+
+

Given a range within the document, this function returns all the text within that range as a single string.

+ +
+

Given a range within the document, this function returns all the text within that range as a single string.

+ +

Arguments

rangeRange

Required. The range to work with

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Document.getValue()
    • +
    +
      +
    +
  • +
+
+
+

Returns all the lines in the document as a single string, split by the new line character.

+ +
+

Returns all the lines in the document as a single string, split by the new line character.

+ +
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Converts an index position in a document to a {row, column} object.

+ +
+

Converts an index position in a document to a {row, column} object.

+

Index refers to the "absolute position" of a character in the document. For example:

+
var x = 0; // 10 characters, plus one for newline
+var y = -1;
+

Here, y is an index 15: 11 characters for the first row, and 5 characters until y in the second.

+ +

Arguments

indexNumber

Required. An index to convert

+
startRowNumber

Required. =0 The row from which to start the conversion

+
+
+
+
+
+
+
+
+
+
+ +
+
+

Inserts a block of text and the indicated position.

+ +
+

Inserts a block of text and the indicated position.

+ +

Arguments

positionObject

Required. The position to start inserting at

+
textString

Required. A chunk of text to insert

+
+
+
+
+
+
+
+
+
+
+ +
+
+

Inserts text into the position at the current row. This method also triggers the 'change' event.

+ +
+

Inserts text into the position at the current row. This method also triggers the 'change' event.

+ +

Arguments

positionObject

Required. The position to insert at

+
textString

Required. A chunk of text

+
+
+
+
+
+
+
+
+
+
+ +
+
+

Inserts the elements in lines into the document, starting at the row index given by row. This method also triggers the 'change' event.

+ +
+

Inserts the elements in lines into the document, starting at the row index given by row. This method also triggers the 'change' event.

+ +

Arguments

rowNumber

Required. The index of the row to insert at

+
linesArray

Required. An array of strings

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Document.insertNewLine(Object position) +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Inserts a new line into the document at the current row's position. This method also triggers the 'change' event.

+ +
+

Inserts a new line into the document at the current row's position. This method also triggers the 'change' event.

+ +

Arguments

positionObject

Required. The position to insert at

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Document.isNewLine(String text)
    • +
    +
      +
    +
  • +
+
+
+

Returns true if text is a newline character (either \r\n, \r, or \n).

+ +
+

Returns true if text is a newline character (either \r\n, \r, or \n).

+ +

Arguments

textString

Required. The text to check

+
+
+
+
+
+
+
+
+
+
+ +
+
+

Converts the {row, column} position in a document to the character's index.

+ +
+

Converts the {row, column} position in a document to the character's index.

+

Index refers to the "absolute position" of a character in the document. For example:

+
var x = 0; // 10 characters, plus one for newline
+var y = -1;
+

Here, y is an index 15: 11 characters for the first row, and 5 characters until y in the second.

+ +

Arguments

posObject

Required. The {row, column} to convert

+
startRowNumber

Required. =0 The row from which to start the conversion

+
+
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Removes the range from the document.

+ +
+

Removes the range from the document.

+ +

Arguments

rangeRange

Required. A specified Range to remove

+
+
+
+
+
+
+
+
+
+
+ +
+
+

Removes the specified columns from the row. This method also triggers the 'change' event.

+ +
+

Removes the specified columns from the row. This method also triggers the 'change' event.

+ +

Arguments

rowNumber

Required. The row to remove from

+
startColumnNumber

Required. The column to start removing at

+
endColumnNumber

Required. The column to stop removing at

+
+
+
+
+
+
+
+
+
+
+ +
+
+

Removes a range of full lines. This method also triggers the 'change' event.

+ +
+

Removes a range of full lines. This method also triggers the 'change' event.

+ +

Arguments

firstRowNumber

Required. The first row to be removed

+
lastRowNumber

Required. The last row to be removed

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Document.removeNewLine(Number row)
    • +
    +
      +
    +
  • +
+
+
+

Removes the new line between row and the row immediately following it. This method also triggers the 'change' event.

+ +
+

Removes the new line between row and the row immediately following it. This method also triggers the 'change' event.

+ +

Arguments

rowNumber

Required. The row to check

+
+
+
+
+
+
+
+
+
+
+ +
+
+

Replaces a range in the document with the new text.

+ +
+

Replaces a range in the document with the new text.

+ +

Arguments

rangeRange

Required. A specified Range to replace

+
textString

Required. The new text to use as a replacement

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Document.revertDeltas(Object deltas)
    • +
    +
      +
    +
  • +
+
+
+

Reverts any changes previously applied. These can be either 'includeText', 'insertLines', 'removeText', and 'removeLines'.

+ +
+

Reverts any changes previously applied. These can be either 'includeText', 'insertLines', 'removeText', and 'removeLines'.

+ +

Arguments

deltasObject

Required.

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Document.setNewLineMode(String newLineMode)
    • +
    +
      +
    +
  • +
+
+
+

Sets the new line mode.

+ +
+

Sets the new line mode.

+ +

Arguments

newLineModeString

Required. The newline mode to use; can be either windows, unix, or auto

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Document.setValue(String text)
    • +
    +
      +
    +
  • +
+
+
+

Replaces all the lines in the current Document with the value of text.

+ +
+

Replaces all the lines in the current Document with the value of text.

+ +

Arguments

textString

Required. The text to use

+
+
+
+
+
+
+
+ + + + + +
+
\ No newline at end of file diff --git a/node_modules/ace/api/edit_session.html b/node_modules/ace/api/edit_session.html new file mode 100644 index 00000000..11e79ed0 --- /dev/null +++ b/node_modules/ace/api/edit_session.html @@ -0,0 +1,3235 @@ + +
+
+
+
+
+

EditSession +

+ +
+
+
+
+

Stores all the data about Editor state providing easy way to change editors state.

+

EditSession can be attached to only one Document. Same Document can be attached to several EditSessions.

+ +
+
+
+

Constructors

+
+
+
+
+ +
+
+

Sets up a new EditSession and associates it with the given Document and TextMode.

+ +
+

Sets up a new EditSession and associates it with the given Document and TextMode.

+ +

Arguments

textDocument | String

Required. If text is a Document, it associates the EditSession with it. Otherwise, a new Document is created, with the initial text

+
modeTextMode

Required. The inital language mode to use for the document

+
+
+
+
+
+
+

Events

+
+
+
+
+
    +
  • +
      +
    • EditSession.on("change", function(Object e))
    • +
    +
      +
    +
  • +
+
+
+

Emitted when the document changes.

+ +
+

Emitted when the document changes.

+ +

Arguments

eObject

Required. An object containing a delta of information about the change.

+
+
+
+
+
+
+ +
+
+
+
+
    +
  • +
      +
    • EditSession.on("changeBackMarker", function())
    • +
    +
      +
    +
  • +
+
+
+

Emitted when a back marker changes.

+ +
+

Emitted when a back marker changes.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.on("changeBreakpoint", function())
    • +
    +
      +
    +
  • +
+
+
+

Emitted when the gutter changes, either by setting or removing breakpoints, or when the gutter decorations change.

+ +
+

Emitted when the gutter changes, either by setting or removing breakpoints, or when the gutter decorations change.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.on("changeFold", function())
    • +
    +
      +
    +
  • +
+
+
+

Emitted when a code fold is added or removed.

+ +
+

Emitted when a code fold is added or removed.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.on("changeFrontMarker", function())
    • +
    +
      +
    +
  • +
+
+
+

Emitted when a front marker changes.

+ +
+

Emitted when a front marker changes.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.on("changeMode", function())
    • +
    +
      +
    +
  • +
+
+
+

Emitted when the current mode changes.

+ +
+

Emitted when the current mode changes.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.on("changeOverwrite", function())
    • +
    +
      +
    +
  • +
+
+
+

Emitted when the ability to overwrite text changes, via EditSession.setOverwrite().

+ +
+

Emitted when the ability to overwrite text changes, via EditSession.setOverwrite().

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.on("changeScrollLeft", function(Number scrollLeft))
    • +
    +
      +
    +
  • +
+
+
+

Emitted when the scroll left changes.

+ +
+

Emitted when the scroll left changes.

+ +

Arguments

scrollLeftNumber

Required. The new scroll left value

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.on("changeScrollTop", function(Number scrollTop))
    • +
    +
      +
    +
  • +
+
+
+

Emitted when the scroll top changes.

+ +
+

Emitted when the scroll top changes.

+ +

Arguments

scrollTopNumber

Required. The new scroll top value

+
+
+
+
+
+
+ +
+
+
+
+
    +
  • +
      +
    • EditSession.on("changeWrapLimit", function())
    • +
    +
      +
    +
  • +
+
+
+

Emitted when the wrapping limit changes.

+ +
+

Emitted when the wrapping limit changes.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.on("changeWrapMode", function())
    • +
    +
      +
    +
  • +
+
+
+

Emitted when the wrap mode changes.

+ +
+

Emitted when the wrap mode changes.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.on("tokenizerUpdate", function(Object e))
    • +
    +
      +
    +
  • +
+
+
+

Emitted when a background tokenizer asynchronously processes new rows.

+ +
+

Emitted when a background tokenizer asynchronously processes new rows.

+ +

Arguments

eObject

Required. An object containing one property, "data", that contains information about the changing rows

+
+
+
+
+
+
+

Methods

+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Adds a dynamic marker to the session.

+ +
+

Adds a dynamic marker to the session.

+ +

Arguments

markerObject

Required. object with update method

+
inFrontBoolean

Required. Set to true to establish a front marker

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.addGutterDecoration(Number row, String className)
    • +
    +
      +
    +
  • +
+
+
+

Adds className to the row, to be used for CSS stylings and whatnot.

+ +
+

Adds className to the row, to be used for CSS stylings and whatnot.

+ +

Arguments

rowNumber

Required. The row number

+
classNameString

Required. The class to add

+
+
+
+
+
+
+
+
+
+
+ +
+
+

Adds a new marker to the given Range. If inFront is true, a front marker is defined, and the 'changeFrontMarker' event fires; otherwise, the 'changeBackMarker' event fires.

+ +
+

Adds a new marker to the given Range. If inFront is true, a front marker is defined, and the 'changeFrontMarker' event fires; otherwise, the 'changeBackMarker' event fires.

+ +

Arguments

rangeRange

Required. Define the range of the marker

+
clazzString

Required. Set the CSS class for the marker

+
typeFunction | String

Required. Identify the type of the marker

+
inFrontBoolean

Required. Set to true to establish a front marker

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.clearAnnotations()
    • +
    +
      +
    +
  • +
+
+
+

Clears all the annotations for this session. This function also triggers the 'changeAnnotation' event.

+ +
+

Clears all the annotations for this session. This function also triggers the 'changeAnnotation' event.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.clearBreakpoint(Number row)
    • +
    +
      +
    +
  • +
+
+
+

Removes a breakpoint on the row number given by rows. This function also emites the 'changeBreakpoint' event.

+ +
+

Removes a breakpoint on the row number given by rows. This function also emites the 'changeBreakpoint' event.

+ +

Arguments

rowNumber

Required. A row index

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.clearBreakpoints()
    • +
    +
      +
    +
  • +
+
+
+

Removes all breakpoints on the rows. This function also emites the 'changeBreakpoint' event.

+ +
+

Removes all breakpoints on the rows. This function also emites the 'changeBreakpoint' event.

+ +
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

For the given document row and column, returns the screen column.

+ +
+

For the given document row and column, returns the screen column.

+ +

Arguments

rowNumber

Required.

+
docColumnNumber

Required.

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.documentToScreenPosition(Number docRow, Number docColumn) +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Converts document coordinates to screen coordinates. This takes into account code folding, word wrap, tab size, and any other visual modifications.

+ +
+

Converts document coordinates to screen coordinates. This takes into account code folding, word wrap, tab size, and any other visual modifications.

+ +

Arguments

docRowNumber

Required. The document row to check

+
docColumnNumber

Required. The document column to check

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.documentToScreenRow(Number docRow, Number docColumn)
    • +
    +
      +
    +
  • +
+
+
+

For the given document row and column, returns the screen row.

+ +
+

For the given document row and column, returns the screen row.

+ +

Arguments

docRowNumber

Required.

+
docColumnNumber

Required.

+
+
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Duplicates all the text between firstRow and lastRow.

+ +
+

Duplicates all the text between firstRow and lastRow.

+ +

Arguments

firstRowNumber

Required. The starting row to duplicate

+
lastRowNumber

Required. The final row to duplicate

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.getAnnotations() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the annotations for the EditSession.

+ +
+

Returns the annotations for the EditSession.

+ +
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Gets the range of a word, including its right whitespace.

+ +
+

Gets the range of a word, including its right whitespace.

+ +

Arguments

rowNumber

Required. The row number to start from

+
columnNumber

Required. The column number to start from

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.getBreakpoints() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns an array of numbers, indicating which rows have breakpoints.

+ +
+

Returns an array of numbers, indicating which rows have breakpoints.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.getDocument() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the Document associated with this session.

+ +
+

Returns the Document associated with this session.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.getDocumentLastRowColumn(Number docRow, Number docColumn)
    • +
    +
      +
    +
  • +
+
+
+

For the given document row and column, this returns the column position of the last screen row.

+ +
+

For the given document row and column, this returns the column position of the last screen row.

+ +

Arguments

docRowNumber

Required.

+
docColumnNumber

Required.

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.getDocumentLastRowColumnPosition(Number docRow, Number docColumn)
    • +
    +
      +
    +
  • +
+
+
+

For the given document row and column, this returns the document position of the last row.

+ +
+

For the given document row and column, this returns the document position of the last row.

+ +

Arguments

docRowNumber

Required.

+
docColumnNumber

Required.

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.getLength() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the number of rows in the document.

+ +
+

Returns the number of rows in the document.

+ +
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Returns a verbatim copy of the given line as it is in the document

+ +
+

Returns a verbatim copy of the given line as it is in the document

+ +

Arguments

rowNumber

Required. The row to retrieve from

+
+
+
+
+
+
+
+
+
+
+ +
+
+

Returns an array of strings of the rows between firstRow and lastRow. This function is inclusive of lastRow.

+ +
+

Returns an array of strings of the rows between firstRow and lastRow. This function is inclusive of lastRow.

+ +

Arguments

firstRowNumber

Required. The first row index to retrieve

+
lastRowNumber

Required. The final row index to retrieve

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.getMarkers(Boolean inFront) +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns an array containing the IDs of all the markers, either front or back.

+ +
+

Returns an array containing the IDs of all the markers, either front or back.

+ +

Arguments

inFrontBoolean

Required. If true, indicates you only want front markers; false indicates only back markers

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.getMode() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the current text mode.

+ +
+

Returns the current text mode.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.getNewLineMode() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the current new line mode.

+ +
+

Returns the current new line mode.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.getOverwrite()
    • +
    +
      +
    +
  • +
+
+
+

Returns true if overwrites are enabled; false otherwise.

+ +
+

Returns true if overwrites are enabled; false otherwise.

+ +
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Returns number of screenrows in a wrapped line.

+ +
+

Returns number of screenrows in a wrapped line.

+ +

Arguments

rowNumber

Required. The row number to check

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.getRowSplitData(Object row) +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

For the given row, this returns the split data.

+ +
+

For the given row, this returns the split data.

+ +

Arguments

rowObject

Required.

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.getScreenLastRowColumn(Number screenRow) +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the position (on screen) for the last character in the provided screen row.

+ +
+

Returns the position (on screen) for the last character in the provided screen row.

+ +

Arguments

screenRowNumber

Required. The screen row to check

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.getScreenLength() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the length of the screen.

+ +
+

Returns the length of the screen.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.getScreenTabSize(Number screenColumn) +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

The distance to the next tab stop at the specified screen column.

+ +
+

The distance to the next tab stop at the specified screen column.

+ +

Arguments

screenColumnNumber

Required. The screen column to check

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.getScreenWidth() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the width of the screen.

+ +
+

Returns the width of the screen.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.getScrollLeft() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the value of the distance between the left of the editor and the leftmost part of the visible content.

+ +
+

Returns the value of the distance between the left of the editor and the leftmost part of the visible content.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.getScrollTop() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the value of the distance between the top of the editor and the topmost part of the visible content.

+ +
+

Returns the value of the distance between the top of the editor and the topmost part of the visible content.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.getSelection()
    • +
    +
      +
    +
  • +
+
+
+

Returns the string of the current selection.

+ +
+

Returns the string of the current selection.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.getState(Number row)
    • +
    +
      +
    +
  • +
+
+
+

Returns the state of tokenization at the end of a row.

+ +
+

Returns the state of tokenization at the end of a row.

+ +

Arguments

rowNumber

Required. The row to start at

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.getTabSize()
    • +
    +
      +
    +
  • +
+
+
+

Returns the current tab size.

+ +
+

Returns the current tab size.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.getTabString()
    • +
    +
      +
    +
  • +
+
+
+

Returns the current value for tabs. If the user is using soft tabs, this will be a series of spaces (defined by getTabSize()); otherwise it's simply '\t'.

+ +
+

Returns the current value for tabs. If the user is using soft tabs, this will be a series of spaces (defined by getTabSize()); otherwise it's simply '\t'.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.getTextRange(Range range) +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Given a range within the document, this function returns all the text within that range as a single string.

+ +
+

Given a range within the document, this function returns all the text within that range as a single string.

+ +

Arguments

rangeRange

Required. The range to work with

+
+
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Returns an object indicating the token at the current row. The object has two properties: index and start.

+ +
+

Returns an object indicating the token at the current row. The object has two properties: index and start.

+ +

Arguments

rowNumber

Required. The row number to retrieve from

+
columnNumber

Required. The column number to retrieve from

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.getTokens(Number row)
    • +
    +
      +
    +
  • +
+
+
+

Starts tokenizing at the row indicated. Returns a list of objects of the tokenized rows.

+ +
+

Starts tokenizing at the row indicated. Returns a list of objects of the tokenized rows.

+ +

Arguments

rowNumber

Required. The row to start at

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.getUndoManager()
    • +
    +
      +
    +
  • +
+
+
+

Returns the current undo manager.

+ +
+

Returns the current undo manager.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.getUseSoftTabs() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns true if soft tabs are being used, false otherwise.

+ +
+

Returns true if soft tabs are being used, false otherwise.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.getUseWorker()
    • +
    +
      +
    +
  • +
+
+
+

Returns true if workers are being used.

+ +
+

Returns true if workers are being used.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.getUseWrapMode() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns true if wrap mode is being used; false otherwise.

+ +
+

Returns true if wrap mode is being used; false otherwise.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.getValue() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the current Document as a string.

+ +
+

Returns the current Document as a string.

+ +
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Given a starting row and column, this method returns the Range of the first word boundary it finds.

+ +
+

Given a starting row and column, this method returns the Range of the first word boundary it finds.

+ +

Arguments

rowNumber

Required. The row to start at

+
columnNumber

Required. The column to start at

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.getWrapLimit() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the value of wrap limit.

+ +
+

Returns the value of wrap limit.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.getWrapLimitRange() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns an object that defines the minimum and maximum of the wrap limit; it looks something like this:

+ +
+

Returns an object that defines the minimum and maximum of the wrap limit; it looks something like this:

+

{ min: wrapLimitRange_min, max: wrapLimitRange_max }

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.highlight()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.highlightLines()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Indents all the rows, from startRow to endRow (inclusive), by prefixing each row with the token in indentString.

+ +
+

Indents all the rows, from startRow to endRow (inclusive), by prefixing each row with the token in indentString.

+

If indentString contains the '\t' character, it's replaced by whatever is defined by getTabString().

+ +

Arguments

startRowNumber

Required. Starting row

+
endRowNumber

Required. Ending row

+
indentStringString

Required. The indent token

+
+
+
+
+
+
+
+
+
+
+ +
+
+

Inserts a block of text and the indicated position.

+ +
+

Inserts a block of text and the indicated position.

+ +

Arguments

positionObject

Required. The position {row, column} to start inserting at

+
textString

Required. A chunk of text to insert

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.isTabStop(Object position)
    • +
    +
      +
    +
  • +
+
+
+

Returns true if the character at the position is a soft tab.

+ +
+

Returns true if the character at the position is a soft tab.

+ +

Arguments

positionObject

Required. The position to check

+
+
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Shifts all the lines in the document down one, starting from firstRow and ending at lastRow.

+ +
+

Shifts all the lines in the document down one, starting from firstRow and ending at lastRow.

+ +

Arguments

firstRowNumber

Required. The starting row to move down

+
lastRowNumber

Required. The final row to move down

+
+
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Shifts all the lines in the document up one, starting from firstRow and ending at lastRow.

+ +
+

Shifts all the lines in the document up one, starting from firstRow and ending at lastRow.

+ +

Arguments

firstRowNumber

Required. The starting row to move up

+
lastRowNumber

Required. The final row to move up

+
+
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Moves a range of text from the given range to the given position. toPosition is an object that looks like this:

+
   { row: newRowLocation, column: newColumnLocation }
+ +
+

Moves a range of text from the given range to the given position. toPosition is an object that looks like this:

+
   { row: newRowLocation, column: newColumnLocation }
+ +

Arguments

fromRangeRange

Required. The range of text you want moved within the document

+
toPositionObject

Required. The location (row and column) where you want to move the text to

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.onChange()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.onChangeFold()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.onReloadTokenizer(Object e)
    • +
    +
      +
    +
  • +
+
+
+

Reloads all the tokens on the current session. This function calls BackgroundTokenizer.start () to all the rows; it also emits the 'tokenizerUpdate' event.

+ +
+

Reloads all the tokens on the current session. This function calls BackgroundTokenizer.start () to all the rows; it also emits the 'tokenizerUpdate' event.

+ +

Arguments

eObject

Required.

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.outdentRows(Range range)
    • +
    +
      +
    +
  • +
+
+
+

Outdents all the rows defined by the start and end properties of range.

+ +
+

Outdents all the rows defined by the start and end properties of range.

+ +

Arguments

rangeRange

Required. A range of rows

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.redo()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Re-implements a previously undone change to your document.

+ +
+

Re-implements a previously undone change to your document.

+ +

Arguments

deltasArray

Required. An array of previous changes

+
dontSelectBoolean

Required. If true, doesn't select the range of where the change occured

+
+
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Removes the range from the document.

+ +
+

Removes the range from the document.

+ +

Arguments

rangeRange

Required. A specified Range to remove

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.removeGutterDecoration(Number row, String className)
    • +
    +
      +
    +
  • +
+
+
+

Removes className from the row.

+ +
+

Removes className from the row.

+ +

Arguments

rowNumber

Required. The row number

+
classNameString

Required. The class to add

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.removeMarker(Number markerId)
    • +
    +
      +
    +
  • +
+
+
+

Removes the marker with the specified ID. If this marker was in front, the 'changeFrontMarker' event is emitted. If the marker was in the back, the 'changeBackMarker' event is emitted.

+ +
+

Removes the marker with the specified ID. If this marker was in front, the 'changeFrontMarker' event is emitted. If the marker was in the back, the 'changeBackMarker' event is emitted.

+ +

Arguments

markerIdNumber

Required. A number representing a marker

+
+
+
+
+
+
+
+
+
+
+ +
+
+

Replaces a range in the document with the new text.

+ +
+

Replaces a range in the document with the new text.

+ +

Arguments

rangeRange

Required. A specified Range to replace

+
textString

Required. The new text to use as a replacement

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.reset()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.resetCaches()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.screenToDocumentColumn()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.screenToDocumentPosition(Number screenRow, Number screenColumn) +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Converts characters coordinates on the screen to characters coordinates within the document. This takes into account code folding, word wrap, tab size, and any other visual modifications.

+ +
+

Converts characters coordinates on the screen to characters coordinates within the document. This takes into account code folding, word wrap, tab size, and any other visual modifications.

+ +

Arguments

screenRowNumber

Required. The screen row to check

+
screenColumnNumber

Required. The screen column to check

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.screenToDocumentRow()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.setAnnotations(Array annotations)
    • +
    +
      +
    +
  • +
+
+
+

Sets annotations for the EditSession. This functions emits the 'changeAnnotation' event.

+ +
+

Sets annotations for the EditSession. This functions emits the 'changeAnnotation' event.

+ +

Arguments

annotationsArray

Required. A list of annotations

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.setBreakpoint(Number row, String className)
    • +
    +
      +
    +
  • +
+
+
+

Sets a breakpoint on the row number given by rows. This function also emites the 'changeBreakpoint' event.

+ +
+

Sets a breakpoint on the row number given by rows. This function also emites the 'changeBreakpoint' event.

+ +

Arguments

rowNumber

Required. A row index

+
classNameString

Required. Class of the breakpoint

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.setBreakpoints(Array rows)
    • +
    +
      +
    +
  • +
+
+
+

Sets a breakpoint on every row number given by rows. This function also emites the 'changeBreakpoint' event.

+ +
+

Sets a breakpoint on every row number given by rows. This function also emites the 'changeBreakpoint' event.

+ +

Arguments

rowsArray

Required. An array of row indices

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.setDocument(Document doc)
    • +
    +
      +
    +
  • +
+
+
+

Sets the EditSession to point to a new Document. If a BackgroundTokenizer exists, it also points to doc.

+ +
+

Sets the EditSession to point to a new Document. If a BackgroundTokenizer exists, it also points to doc.

+ +

Arguments

docDocument

Required. The new Document to use

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.setMode()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.setNewLineMode(String newLineMode)
    • +
    +
      +
    +
  • +
+
+
+

Sets the new line mode.

+ +
+

Sets the new line mode.

+ +

Arguments

newLineModeString

Required. The newline mode to use; can be either windows, unix, or auto

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.setOverwrite(Boolean overwrite)
    • +
    +
      +
    +
  • +
+
+
+

Pass in true to enable overwrites in your session, or false to disable.

+ +
+

Pass in true to enable overwrites in your session, or false to disable.

+

If overwrites is enabled, any text you enter will type over any text after it. If the value of overwrite changes, this function also emites the changeOverwrite event.

+ +

Arguments

overwriteBoolean

Required. Defines wheter or not to set overwrites

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.setScrollLeft(Object scrollLeft)
    • +
    +
      +
    +
  • +
+
+
+

Sets the value of the distance between the left of the editor and the leftmost part of the visible content.

+ +
+

Sets the value of the distance between the left of the editor and the leftmost part of the visible content.

+ +

Arguments

scrollLeftObject

Required.

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.setScrollTop(Number scrollTop)
    • +
    +
      +
    +
  • +
+
+
+

This function sets the scroll top value. It also emits the 'changeScrollTop' event.

+ +
+

This function sets the scroll top value. It also emits the 'changeScrollTop' event.

+ +

Arguments

scrollTopNumber

Required. The new scroll top value

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.setTabSize(Number tabSize)
    • +
    +
      +
    +
  • +
+
+
+

Set the number of spaces that define a soft tab; for example, passing in 4 transforms the soft tabs to be equivalent to four spaces. This function also emits the changeTabSize event.

+ +
+

Set the number of spaces that define a soft tab; for example, passing in 4 transforms the soft tabs to be equivalent to four spaces. This function also emits the changeTabSize event.

+ +

Arguments

tabSizeNumber

Required. The new tab size

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.setUndoManager(UndoManager undoManager)
    • +
    +
      +
    +
  • +
+
+
+

Sets the undo manager.

+ +
+

Sets the undo manager.

+ +

Arguments

undoManagerUndoManager

Required. The new undo manager

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.setUndoSelect(Boolean enable)
    • +
    +
      +
    +
  • +
+
+
+

Enables or disables highlighting of the range where an undo occured.

+ +
+

Enables or disables highlighting of the range where an undo occured.

+ +

Arguments

enableBoolean

Required. If true, selects the range of the reinserted change

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.setUseSoftTabs(Boolean useSoftTabs)
    • +
    +
      +
    +
  • +
+
+
+

Pass true to enable the use of soft tabs. Soft tabs means you're using spaces instead of the tab character ('\t').

+ +
+

Pass true to enable the use of soft tabs. Soft tabs means you're using spaces instead of the tab character ('\t').

+ +

Arguments

useSoftTabsBoolean

Required. Value indicating whether or not to use soft tabs

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.setUseWorker(Boolean useWorker)
    • +
    +
      +
    +
  • +
+
+
+

Identifies if you want to use a worker for the EditSession.

+ +
+

Identifies if you want to use a worker for the EditSession.

+ +

Arguments

useWorkerBoolean

Required. Set to true to use a worker

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.setUseWrapMode(Boolean useWrapMode)
    • +
    +
      +
    +
  • +
+
+
+

Sets whether or not line wrapping is enabled. If useWrapMode is different than the current value, the 'changeWrapMode' event is emitted.

+ +
+

Sets whether or not line wrapping is enabled. If useWrapMode is different than the current value, the 'changeWrapMode' event is emitted.

+ +

Arguments

useWrapModeBoolean

Required. Enable (or disable) wrap mode

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.setValue(String text)
    • +
    +
      +
    +
  • +
+
+
+

Sets the session text.

+ +
+

Sets the session text.

+ +

Arguments

textString

Required. The new text to place

+
+
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Sets the boundaries of wrap. Either value can be null to have an unconstrained wrap, or, they can be the same number to pin the limit. If the wrap limits for min or max are different, this method also emits the 'changeWrapMode' event.

+ +
+

Sets the boundaries of wrap. Either value can be null to have an unconstrained wrap, or, they can be the same number to pin the limit. If the wrap limits for min or max are different, this method also emits the 'changeWrapMode' event.

+ +

Arguments

minNumber

Required. The minimum wrap value (the left side wrap)

+
maxNumber

Required. The maximum wrap value (the right side wrap)

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.toggleOverwrite()
    • +
    +
      +
    +
  • +
+
+
+

Sets the value of overwrite to the opposite of whatever it currently is.

+ +
+

Sets the value of overwrite to the opposite of whatever it currently is.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.toString() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the current Document as a string.

+ +
+

Returns the current Document as a string.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • EditSession.undo()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Reverts previous changes to your document.

+ +
+

Reverts previous changes to your document.

+ +

Arguments

deltasArray

Required. An array of previous changes

+
dontSelectBoolean

Required. If true, doesn't select the range of where the change occured

+
+
+
+
+
+
+
+ + + + + +
+
\ No newline at end of file diff --git a/node_modules/ace/api/editor.html b/node_modules/ace/api/editor.html new file mode 100644 index 00000000..6ffe4369 --- /dev/null +++ b/node_modules/ace/api/editor.html @@ -0,0 +1,4689 @@ + +
+
+
+
+
+

Editor +

+ +
+
+
+
+

The main entry point into the Ace functionality.

+

The Editor manages the EditSession (which manages Documents), as well as the VirtualRenderer, which draws everything to the screen.

+

Event sessions dealing with the mouse and keyboard are bubbled up from Document to the Editor, which decides what to do with them.

+ +
+
+
+

Constructors

+
+
+
+
+ +
+
+

Creates a new Editor object.

+ +
+

Creates a new Editor object.

+ +

Arguments

rendererVirtualRenderer

Required. Associated VirtualRenderer that draws everything

+
sessionEditSession

Required. The EditSession to refer to

+
+
+
+
+
+
+

Events

+
+
+
+
+
    +
  • +
      +
    • Editor.on("blur", function())
    • +
    +
      +
    +
  • +
+
+
+

Emitted once the editor has been blurred.

+ +
+

Emitted once the editor has been blurred.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.on("change", function(Object e))
    • +
    +
      +
    +
  • +
+
+
+

Emitted whenever the document is changed.

+ +
+

Emitted whenever the document is changed.

+ +

Arguments

eObject

Required. Contains a single property, data, which has the delta of changes

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.on("changeSelectionStyle", function(Object data))
    • +
    +
      +
    +
  • +
+
+
+

Emitted when the selection style changes, via Editor.setSelectionStyle().

+ +
+

Emitted when the selection style changes, via Editor.setSelectionStyle().

+ +

Arguments

dataObject

Required. Contains one property, data, which indicates the new selection style

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.on("changeSession", function(Object e))
    • +
    +
      +
    +
  • +
+
+
+

Emitted whenever the EditSession changes.

+ +
+

Emitted whenever the EditSession changes.

+ +

Arguments

eObject

Required. An object with two properties, oldSession and session, that represent the old and new EditSessions.

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.on("copy", function(String text))
    • +
    +
      +
    +
  • +
+
+
+

Emitted when text is copied.

+ +
+

Emitted when text is copied.

+ +

Arguments

textString

Required. The copied text

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.on("focus", function())
    • +
    +
      +
    +
  • +
+
+
+

Emitted once the editor comes into focus.

+ +
+

Emitted once the editor comes into focus.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.on("paste", function(Object e))
    • +
    +
      +
    +
  • +
+
+
+

Emitted when text is pasted.

+ +
+

Emitted when text is pasted.

+ +

Arguments

eObject

Required. An object which contains one property, text, that represents the text to be pasted. Editing this property will alter the text that is pasted.

+
+
+
+
+
+
+

Methods

+
+
+
+
+
    +
  • +
      +
    • Editor.addSelectionMarker(Range orientedRange) +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Adds the selection and cursor.

+ +
+

Adds the selection and cursor.

+ +

Arguments

orientedRangeRange

Required. A range containing a cursor

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.alignCursors()
    • +
    +
      +
    +
  • +
+
+
+

Aligns the cursors or selected text.

+ +
+

Aligns the cursors or selected text.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.blockOutdent()
    • +
    +
      +
    +
  • +
+
+
+

Outdents the current line.

+ +
+

Outdents the current line.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.blur()
    • +
    +
      +
    +
  • +
+
+
+

Blurs the current textInput.

+ +
+

Blurs the current textInput.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.centerSelection()
    • +
    +
      +
    +
  • +
+
+
+

Attempts to center the current selection on the screen.

+ +
+

Attempts to center the current selection on the screen.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.clearSelection()
    • +
    +
      +
    +
  • +
+
+
+

Empties the selection (by de-selecting it). This function also emits the 'changeSelection' event.

+ +
+

Empties the selection (by de-selecting it). This function also emits the 'changeSelection' event.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.copyLinesDown() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Copies all the selected lines down one row.

+ +
+

Copies all the selected lines down one row.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.copyLinesUp() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Copies all the selected lines up one row.

+ +
+

Copies all the selected lines up one row.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.destroy()
    • +
    +
      +
    +
  • +
+
+
+

Cleans up the entire editor.

+ +
+

Cleans up the entire editor.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.duplicateSelection()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.execCommand()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.exitMultiSelectMode()
    • +
    +
      +
    +
  • +
+
+
+

Removes all the selections except the last added one.

+ +
+

Removes all the selections except the last added one.

+ +
+
+
+
+
+
+
+
+
+ +
+
+

Attempts to find needle within the document. For more information on options, see Search.

+ +
+

Attempts to find needle within the document. For more information on options, see Search.

+ +

Arguments

needleString

Required. The text to search for (optional)

+
optionsObject

Required. An object defining various search properties

+
animateBoolean

Required. If true animate scrolling

+
+
+
+
+
+
+
+
+
+
+ +
+
+

Finds and selects all the occurences of needle.

+ +
+

Finds and selects all the occurences of needle.

+ +

Arguments

TheString

Required. text to find

+
TheObject

Required. search options

+
keepsBoolean

Required.

+
+
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Performs another search for needle in the document. For more information on options, see Search.

+ +
+

Performs another search for needle in the document. For more information on options, see Search.

+ +

Arguments

optionsObject

Required. search options

+
animateBoolean

Required. If true animate scrolling

+
+
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Performs a search for needle backwards. For more information on options, see Search.

+ +
+

Performs a search for needle backwards. For more information on options, see Search.

+ +

Arguments

optionsObject

Required. search options

+
animateBoolean

Required. If true animate scrolling

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.focus()
    • +
    +
      +
    +
  • +
+
+
+

Brings the current textInput into focus.

+ +
+

Brings the current textInput into focus.

+ +
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Executes a command for each selection range.

+ +
+

Executes a command for each selection range.

+ +

Arguments

cmdString

Required. The command to execute

+
argsString

Required. Any arguments for the command

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.getAnimatedScroll()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.getBehavioursEnabled() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns true if the behaviors are currently enabled. "Behaviors" in this case is the auto-pairing of special characters, like quotation marks, parenthesis, or brackets.

+ +
+

Returns true if the behaviors are currently enabled. "Behaviors" in this case is the auto-pairing of special characters, like quotation marks, parenthesis, or brackets.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.getCopyText() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the string of text currently highlighted.

+ +
+

Returns the string of text currently highlighted.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.getCursorPosition() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Gets the current position of the cursor.

+ +
+

Gets the current position of the cursor.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.getCursorPositionScreen() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the screen position of the cursor.

+ +
+

Returns the screen position of the cursor.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.getDisplayIndentGuides()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.getDragDelay() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the current mouse drag delay.

+ +
+

Returns the current mouse drag delay.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.getFadeFoldWidgets()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.getFirstVisibleRow() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the index of the first visible row.

+ +
+

Returns the index of the first visible row.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.getHighlightActiveLine() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns true if current lines are always highlighted.

+ +
+

Returns true if current lines are always highlighted.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.getHighlightGutterLine()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.getHighlightSelectedWord() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns true if currently highlighted words are to be highlighted.

+ +
+

Returns true if currently highlighted words are to be highlighted.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.getKeyboardHandler() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the keyboard handler, such as "vim" or "windows".

+ +
+

Returns the keyboard handler, such as "vim" or "windows".

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.getLastSearchOptions() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns an object containing all the search options. For more information on options, see Search.

+ +
+

Returns an object containing all the search options. For more information on options, see Search.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.getLastVisibleRow() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the index of the last visible row.

+ +
+

Returns the index of the last visible row.

+ +
+
+
+
+
+ +
+
+
+
+
    +
  • +
      +
    • Editor.getOverwrite() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns true if overwrites are enabled; false otherwise.

+ +
+

Returns true if overwrites are enabled; false otherwise.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.getPrintMarginColumn() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the column number of where the print margin is.

+ +
+

Returns the column number of where the print margin is.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.getReadOnly() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns true if the editor is set to read-only mode.

+ +
+

Returns true if the editor is set to read-only mode.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.getScrollSpeed() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the value indicating how fast the mouse scroll speed is (in milliseconds).

+ +
+

Returns the value indicating how fast the mouse scroll speed is (in milliseconds).

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.getSelection() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the currently highlighted selection.

+ +
+

Returns the currently highlighted selection.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.getSelectionRange() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the Range for the selected text.

+ +
+

Returns the Range for the selected text.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.getSelectionStyle() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the current selection style.

+ +
+

Returns the current selection style.

+ +
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Returns the current session being used.

+ +
+

Returns the current session being used.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.getShowFoldWidgets() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns true if the fold widgets are shown.

+ +
+

Returns true if the fold widgets are shown.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.getShowInvisibles() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns true if invisible characters are being shown.

+ +
+

Returns true if invisible characters are being shown.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.getShowPrintMargin() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns true if the print margin is being shown.

+ +
+

Returns true if the print margin is being shown.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.getTheme() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the path of the current theme.

+ +
+

Returns the path of the current theme.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.getValue() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the current session's content.

+ +
+

Returns the current session's content.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.getWrapBehavioursEnabled()
    • +
    +
      +
    +
  • +
+
+
+

Returns true if the wrapping behaviors are currently enabled.

+ +
+

Returns true if the wrapping behaviors are currently enabled.

+ +
+
+
+
+
+
+
+
+
+ +
+
+

Moves the cursor to the specified line number, and also into the indiciated column.

+ +
+

Moves the cursor to the specified line number, and also into the indiciated column.

+ +

Arguments

lineNumberNumber

Required. The line number to go to

+
columnNumber

Required. A column number to go to

+
animateBoolean

Required. If true animates scolling

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.gotoPageDown()
    • +
    +
      +
    +
  • +
+
+
+

Shifts the document to wherever "page down" is, as well as moving the cursor position.

+ +
+

Shifts the document to wherever "page down" is, as well as moving the cursor position.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.gotoPageUp()
    • +
    +
      +
    +
  • +
+
+
+

Shifts the document to wherever "page up" is, as well as moving the cursor position.

+ +
+

Shifts the document to wherever "page up" is, as well as moving the cursor position.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.indent()
    • +
    +
      +
    +
  • +
+
+
+

Indents the current line.

+ +
+

Indents the current line.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.insert(String text)
    • +
    +
      +
    +
  • +
+
+
+

Inserts text into wherever the cursor is pointing.

+ +
+

Inserts text into wherever the cursor is pointing.

+ +

Arguments

textString

Required. The new text to add

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.isFocused() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns true if the current textInput is in focus.

+ +
+

Returns true if the current textInput is in focus.

+ +
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Indicates if the entire row is currently visible on the screen.

+ +
+

Indicates if the entire row is currently visible on the screen.

+ +

Arguments

rowNumber

Required. The row to check

+
+
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Indicates if the row is currently visible on the screen.

+ +
+

Indicates if the row is currently visible on the screen.

+ +

Arguments

rowNumber

Required. The row to check

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.jumpToMatching(Object select)
    • +
    +
      +
    +
  • +
+
+
+

Moves the cursor's row and column to the next matching bracket.

+ +
+

Moves the cursor's row and column to the next matching bracket.

+ +

Arguments

selectObject

Required.

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.modifyNumber(Number amount)
    • +
    +
      +
    +
  • +
+
+
+

If the character before the cursor is a number, this functions changes its value by amount.

+ +
+

If the character before the cursor is a number, this functions changes its value by amount.

+ +

Arguments

amountNumber

Required. The value to change the numeral by (can be negative to decrease value)

+
+
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Moves the cursor to the specified row and column. Note that this does not de-select the current selection.

+ +
+

Moves the cursor to the specified row and column. Note that this does not de-select the current selection.

+ +

Arguments

rowNumber

Required. The new row number

+
columnNumber

Required. The new column number

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.moveCursorToPosition(Object pos)
    • +
    +
      +
    +
  • +
+
+
+

Moves the cursor to the position indicated by pos.row and pos.column.

+ +
+

Moves the cursor to the position indicated by pos.row and pos.column.

+ +

Arguments

posObject

Required. An object with two properties, row and column

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.moveLinesDown() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Shifts all the selected lines down one row.

+ +
+

Shifts all the selected lines down one row.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.moveLinesUp() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Shifts all the selected lines up one row.

+ +
+

Shifts all the selected lines up one row.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.moveText()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.navigateDown(Number times)
    • +
    +
      +
    +
  • +
+
+
+

Moves the cursor down in the document the specified number of times. Note that this does de-select the current selection.

+ +
+

Moves the cursor down in the document the specified number of times. Note that this does de-select the current selection.

+ +

Arguments

timesNumber

Required. The number of times to change navigation

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.navigateFileEnd()
    • +
    +
      +
    +
  • +
+
+
+

Moves the cursor to the end of the current file. Note that this does de-select the current selection.

+ +
+

Moves the cursor to the end of the current file. Note that this does de-select the current selection.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.navigateFileStart()
    • +
    +
      +
    +
  • +
+
+
+

Moves the cursor to the start of the current file. Note that this does de-select the current selection.

+ +
+

Moves the cursor to the start of the current file. Note that this does de-select the current selection.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.navigateLeft(Number times)
    • +
    +
      +
    +
  • +
+
+
+

Moves the cursor left in the document the specified number of times. Note that this does de-select the current selection.

+ +
+

Moves the cursor left in the document the specified number of times. Note that this does de-select the current selection.

+ +

Arguments

timesNumber

Required. The number of times to change navigation

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.navigateLineEnd()
    • +
    +
      +
    +
  • +
+
+
+

Moves the cursor to the end of the current line. Note that this does de-select the current selection.

+ +
+

Moves the cursor to the end of the current line. Note that this does de-select the current selection.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.navigateLineStart()
    • +
    +
      +
    +
  • +
+
+
+

Moves the cursor to the start of the current line. Note that this does de-select the current selection.

+ +
+

Moves the cursor to the start of the current line. Note that this does de-select the current selection.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.navigateRight(Number times)
    • +
    +
      +
    +
  • +
+
+
+

Moves the cursor right in the document the specified number of times. Note that this does de-select the current selection.

+ +
+

Moves the cursor right in the document the specified number of times. Note that this does de-select the current selection.

+ +

Arguments

timesNumber

Required. The number of times to change navigation

+
+
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Moves the cursor to the specified row and column. Note that this does de-select the current selection.

+ +
+

Moves the cursor to the specified row and column. Note that this does de-select the current selection.

+ +

Arguments

rowNumber

Required. The new row number

+
columnNumber

Required. The new column number

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.navigateUp(Number times)
    • +
    +
      +
    +
  • +
+
+
+

Moves the cursor up in the document the specified number of times. Note that this does de-select the current selection.

+ +
+

Moves the cursor up in the document the specified number of times. Note that this does de-select the current selection.

+ +

Arguments

timesNumber

Required. The number of times to change navigation

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.navigateWordLeft()
    • +
    +
      +
    +
  • +
+
+
+

Moves the cursor to the word immediately to the left of the current position. Note that this does de-select the current selection.

+ +
+

Moves the cursor to the word immediately to the left of the current position. Note that this does de-select the current selection.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.navigateWordRight()
    • +
    +
      +
    +
  • +
+
+
+

Moves the cursor to the word immediately to the right of the current position. Note that this does de-select the current selection.

+ +
+

Moves the cursor to the word immediately to the right of the current position. Note that this does de-select the current selection.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.onBlur()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.onChangeAnnotation()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.onChangeBackMarker()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.onChangeBreakpoint()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.onChangeFold()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.onChangeFrontMarker()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.onChangeMode()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.onChangeWrapLimit()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.onChangeWrapMode()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.onCommandKey()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.onCompositionEnd()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.onCompositionStart()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.onCompositionUpdate()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.onCopy()
    • +
    +
      +
    +
  • +
+
+
+

Called whenever a text "copy" happens.

+ +
+

Called whenever a text "copy" happens.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.onCursorChange()
    • +
    +
      +
    +
  • +
+
+
+

Emitted when the selection changes.

+ +
+

Emitted when the selection changes.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.onCut()
    • +
    +
      +
    +
  • +
+
+
+

Called whenever a text "cut" happens.

+ +
+

Called whenever a text "cut" happens.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.onDocumentChange()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.onFocus()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.onPaste(String text)
    • +
    +
      +
    +
  • +
+
+
+

Called whenever a text "paste" happens.

+ +
+

Called whenever a text "paste" happens.

+ +

Arguments

textString

Required. The pasted text

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.onScrollLeftChange()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.onScrollTopChange()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.onSelectionChange()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.onTextInput()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.onTokenizerUpdate()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.redo()
    • +
    +
      +
    +
  • +
+
+
+

Perform a redo operation on the document, reimplementing the last change.

+ +
+

Perform a redo operation on the document, reimplementing the last change.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.remove(String dir)
    • +
    +
      +
    +
  • +
+
+
+

Removes words of text from the editor. A "word" is defined as a string of characters bookended by whitespace.

+ +
+

Removes words of text from the editor. A "word" is defined as a string of characters bookended by whitespace.

+ +

Arguments

dirString

Required. The direction of the deletion to occur, either "left" or "right"

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.removeLines()
    • +
    +
      +
    +
  • +
+
+
+

Removes all the lines in the current selection

+ +
+

Removes all the lines in the current selection

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.removeSelectionMarker(Range The)
    • +
    +
      +
    +
  • +
+
+
+

Removes the selection marker.

+ +
+

Removes the selection marker.

+ +

Arguments

TheRange

Required. selection range added with addSelectionMarker().

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.removeToLineEnd()
    • +
    +
      +
    +
  • +
+
+
+

Removes all the words to the right of the current selection, until the end of the line.

+ +
+

Removes all the words to the right of the current selection, until the end of the line.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.removeToLineStart()
    • +
    +
      +
    +
  • +
+
+
+

Removes all the words to the left of the current selection, until the start of the line.

+ +
+

Removes all the words to the left of the current selection, until the start of the line.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.removeWordLeft()
    • +
    +
      +
    +
  • +
+
+
+

Removes the word directly to the left of the current selection.

+ +
+

Removes the word directly to the left of the current selection.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.removeWordRight()
    • +
    +
      +
    +
  • +
+
+
+

Removes the word directly to the right of the current selection.

+ +
+

Removes the word directly to the right of the current selection.

+ +
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Replaces the first occurance of options.needle with the value in replacement.

+ +
+

Replaces the first occurance of options.needle with the value in replacement.

+ +

Arguments

replacementString

Required. The text to replace with

+
optionsObject

Required. The Search options to use

+
+
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Replaces all occurances of options.needle with the value in replacement.

+ +
+

Replaces all occurances of options.needle with the value in replacement.

+ +

Arguments

replacementString

Required. The text to replace with

+
optionsObject

Required. The Search options to use

+
+
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Triggers a resize of the editor.

+ +
+

Triggers a resize of the editor.

+ +

Arguments

forceBoolean

Required. If true, recomputes the size, even if the height and width haven't changed

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.revealRange()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.scrollPageDown()
    • +
    +
      +
    +
  • +
+
+
+

Scrolls the document to wherever "page down" is, without changing the cursor position.

+ +
+

Scrolls the document to wherever "page down" is, without changing the cursor position.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.scrollPageUp()
    • +
    +
      +
    +
  • +
+
+
+

Scrolls the document to wherever "page up" is, without changing the cursor position.

+ +
+

Scrolls the document to wherever "page up" is, without changing the cursor position.

+ +
+
+
+
+
+
+
+
+
+ +
+
+

Scrolls to a line. If center is true, it puts the line in middle of screen (or attempts to).

+ +
+

Scrolls to a line. If center is true, it puts the line in middle of screen (or attempts to).

+ +

Arguments

lineNumber

Required. The line to scroll to

+
centerBoolean

Required. If true

+
animateBoolean

Required. If true animates scrolling

+
callbackFunction

Required. Function to be called when the animation has finished

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.scrollToRow(Object row)
    • +
    +
      +
    +
  • +
+
+
+

Moves the editor to the specified row.

+ +
+

Moves the editor to the specified row.

+ +

Arguments

rowObject

Required.

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.selectAll()
    • +
    +
      +
    +
  • +
+
+
+

Selects all the text in editor.

+ +
+

Selects all the text in editor.

+ +
+
+
+
+
+
+
+
+
+ +
+
+

Finds the next occurence of text in an active selection and adds it to the selections.

+ +
+

Finds the next occurence of text in an active selection and adds it to the selections.

+ +

Arguments

dirNumber

Required. The direction of lines to select: -1 for up, 1 for down

+
skipBoolean

Required. If true, removes the active selection range

+
+
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Adds a cursor above or below the active cursor.

+ +
+

Adds a cursor above or below the active cursor.

+ +

Arguments

dirNumber

Required. The direction of lines to select: -1 for up, 1 for down

+
skipBoolean

Required. If true, removes the active selection range

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.selectPageDown()
    • +
    +
      +
    +
  • +
+
+
+

Selects the text from the current position of the document until where a "page down" finishes.

+ +
+

Selects the text from the current position of the document until where a "page down" finishes.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.selectPageUp()
    • +
    +
      +
    +
  • +
+
+
+

Selects the text from the current position of the document until where a "page up" finishes.

+ +
+

Selects the text from the current position of the document until where a "page up" finishes.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.setAnimatedScroll()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.setBehavioursEnabled(Boolean enabled)
    • +
    +
      +
    +
  • +
+
+
+

Specifies whether to use behaviors or not. "Behaviors" in this case is the auto-pairing of special characters, like quotation marks, parenthesis, or brackets.

+ +
+

Specifies whether to use behaviors or not. "Behaviors" in this case is the auto-pairing of special characters, like quotation marks, parenthesis, or brackets.

+ +

Arguments

enabledBoolean

Required. Enables or disables behaviors

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.setDisplayIndentGuides()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.setDragDelay(Number dragDelay)
    • +
    +
      +
    +
  • +
+
+
+

Sets the delay (in milliseconds) of the mouse drag.

+ +
+

Sets the delay (in milliseconds) of the mouse drag.

+ +

Arguments

dragDelayNumber

Required. A value indicating the new delay

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.setFadeFoldWidgets()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.setFontSize(Number size)
    • +
    +
      +
    +
  • +
+
+
+

Set a new font size (in pixels) for the editor text.

+ +
+

Set a new font size (in pixels) for the editor text.

+ +

Arguments

sizeNumber

Required. A font size

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.setHighlightActiveLine(Boolean shouldHighlight)
    • +
    +
      +
    +
  • +
+
+
+

Determines whether or not the current line should be highlighted.

+ +
+

Determines whether or not the current line should be highlighted.

+ +

Arguments

shouldHighlightBoolean

Required. Set to true to highlight the current line

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.setHighlightGutterLine()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.setHighlightSelectedWord(Boolean shouldHighlight)
    • +
    +
      +
    +
  • +
+
+
+

Determines if the currently selected word should be highlighted.

+ +
+

Determines if the currently selected word should be highlighted.

+ +

Arguments

shouldHighlightBoolean

Required. Set to true to highlight the currently selected word

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.setKeyboardHandler(String keyboardHandler)
    • +
    +
      +
    +
  • +
+
+
+

Sets a new key handler, such as "vim" or "windows".

+ +
+

Sets a new key handler, such as "vim" or "windows".

+ +

Arguments

keyboardHandlerString

Required. The new key handler

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.setOverwrite(Boolean overwrite)
    • +
    +
      +
    +
  • +
+
+
+

Pass in true to enable overwrites in your session, or false to disable. If overwrites is enabled, any text you enter will type over any text after it. If the value of overwrite changes, this function also emites the changeOverwrite event.

+ +
+

Pass in true to enable overwrites in your session, or false to disable. If overwrites is enabled, any text you enter will type over any text after it. If the value of overwrite changes, this function also emites the changeOverwrite event.

+ +

Arguments

overwriteBoolean

Required. Defines wheter or not to set overwrites

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.setPrintMarginColumn(Number showPrintMargin)
    • +
    +
      +
    +
  • +
+
+
+

Sets the column defining where the print margin should be.

+ +
+

Sets the column defining where the print margin should be.

+ +

Arguments

showPrintMarginNumber

Required. Specifies the new print margin

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.setReadOnly(Boolean readOnly)
    • +
    +
      +
    +
  • +
+
+
+

If readOnly is true, then the editor is set to read-only mode, and none of the content can change.

+ +
+

If readOnly is true, then the editor is set to read-only mode, and none of the content can change.

+ +

Arguments

readOnlyBoolean

Required. Specifies whether the editor can be modified or not

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.setScrollSpeed(Number speed)
    • +
    +
      +
    +
  • +
+
+
+

Sets how fast the mouse scrolling should do.

+ +
+

Sets how fast the mouse scrolling should do.

+ +

Arguments

speedNumber

Required. A value indicating the new speed (in milliseconds)

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.setSelectionStyle(String style)
    • +
    +
      +
    +
  • +
+
+
+

Indicates how selections should occur.

+ +
+

Indicates how selections should occur.

+

By default, selections are set to "line". There are no other styles at the moment, +although this code change in the future.

+

This function also emits the 'changeSelectionStyle' event.

+ +

Arguments

styleString

Required. The new selection style

+
+
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Sets a new editsession to use. This method also emits the 'changeSession' event.

+ +
+

Sets a new editsession to use. This method also emits the 'changeSession' event.

+ +

Arguments

sessionEditSession

Required. The new session to use

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.setShowFoldWidgets(Boolean show)
    • +
    +
      +
    +
  • +
+
+
+

Indicates whether the fold widgets are shown or not.

+ +
+

Indicates whether the fold widgets are shown or not.

+ +

Arguments

showBoolean

Required. Specifies whether the fold widgets are shown

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.setShowInvisibles(Boolean showInvisibles)
    • +
    +
      +
    +
  • +
+
+
+

If showInvisibles is set to true, invisible characters—like spaces or new lines—are show in the editor.

+ +
+

If showInvisibles is set to true, invisible characters—like spaces or new lines—are show in the editor.

+ +

Arguments

showInvisiblesBoolean

Required. Specifies whether or not to show invisible characters

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.setShowPrintMargin(Boolean showPrintMargin)
    • +
    +
      +
    +
  • +
+
+
+

If showPrintMargin is set to true, the print margin is shown in the editor.

+ +
+

If showPrintMargin is set to true, the print margin is shown in the editor.

+ +

Arguments

showPrintMarginBoolean

Required. Specifies whether or not to show the print margin

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.setStyle(String style)
    • +
    +
      +
    +
  • +
+
+
+

Adds a new class, style, to the editor.

+ +
+

Adds a new class, style, to the editor.

+ +

Arguments

styleString

Required. A class name

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.setTheme(String theme)
    • +
    +
      +
    +
  • +
+
+
+

Sets a new theme for the editor. theme should exist, and be a directory path, like ace/theme/textmate.

+ +
+

Sets a new theme for the editor. theme should exist, and be a directory path, like ace/theme/textmate.

+ +

Arguments

themeString

Required. The path to a theme

+
+
+
+
+
+
+
+
+
+
+ +
+
+

Sets the current document to val.

+ +
+

Sets the current document to val.

+ +

Arguments

valString

Required. The new value to set for the document

+
cursorPosNumber

Required. Where to set the new value. undefined or 0 is selectAll, -1 is at the document start, and 1 is at the end

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.setWrapBehavioursEnabled(Boolean enabled)
    • +
    +
      +
    +
  • +
+
+
+

Specifies whether to use wrapping behaviors or not, i.e. automatically wrapping the selection with characters such as brackets +when such a character is typed in.

+ +
+

Specifies whether to use wrapping behaviors or not, i.e. automatically wrapping the selection with characters such as brackets +when such a character is typed in.

+ +

Arguments

enabledBoolean

Required. Enables or disables wrapping behaviors

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.sortLines()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.splitLine()
    • +
    +
      +
    +
  • +
+
+
+

Splits the line at the current selection (by inserting an '\n').

+ +
+

Splits the line at the current selection (by inserting an '\n').

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.toggleCommentLines()
    • +
    +
      +
    +
  • +
+
+
+

Given the currently selected range, this function either comments all the lines, or uncomments all of them.

+ +
+

Given the currently selected range, this function either comments all the lines, or uncomments all of them.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.toggleOverwrite()
    • +
    +
      +
    +
  • +
+
+
+

Sets the value of overwrite to the opposite of whatever it currently is.

+ +
+

Sets the value of overwrite to the opposite of whatever it currently is.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.toLowerCase()
    • +
    +
      +
    +
  • +
+
+
+

Converts the current selection entirely into lowercase.

+ +
+

Converts the current selection entirely into lowercase.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.toUpperCase()
    • +
    +
      +
    +
  • +
+
+
+

Converts the current selection entirely into uppercase.

+ +
+

Converts the current selection entirely into uppercase.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.transposeLetters()
    • +
    +
      +
    +
  • +
+
+
+

Transposes current line.

+ +
+

Transposes current line.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.transposeSelections(Number dir)
    • +
    +
      +
    +
  • +
+
+
+

Transposes the selected ranges.

+ +
+

Transposes the selected ranges.

+ +

Arguments

dirNumber

Required. The direction to rotate selections

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.undo()
    • +
    +
      +
    +
  • +
+
+
+

Perform an undo operation on the document, reverting the last change.

+ +
+

Perform an undo operation on the document, reverting the last change.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.unsetStyle(Object style)
    • +
    +
      +
    +
  • +
+
+
+

Removes the class style from the editor.

+ +
+

Removes the class style from the editor.

+ +

Arguments

styleObject

Required.

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Editor.updateSelectionMarkers()
    • +
    +
      +
    +
  • +
+
+
+

Updates the cursor and marker layers.

+ +
+

Updates the cursor and marker layers.

+ +
+
+
+
+
+
+ + + + + +
+
\ No newline at end of file diff --git a/node_modules/ace/api/index.html b/node_modules/ace/api/index.html new file mode 100644 index 00000000..cccaab54 --- /dev/null +++ b/node_modules/ace/api/index.html @@ -0,0 +1,12 @@ + +

Ace API Reference

+

Welcome to the Ace API Reference Guide. Ace is a standalone code editor written in JavaScript that you can embed onto any website. We're used in a bunch of places already, like GitHub, Google, and Facebook.

+

On the left, you'll find a list of all of our currently documented classes. There are plenty more to do, but these represent the "core" set. For more information on how to work with Ace, check out the main Ace website.

+ + + + + + +
+
\ No newline at end of file diff --git a/node_modules/ace/api/placeholder.html b/node_modules/ace/api/placeholder.html new file mode 100644 index 00000000..fa12a958 --- /dev/null +++ b/node_modules/ace/api/placeholder.html @@ -0,0 +1,293 @@ + +
+
+
+
+
+

PlaceHolder +

+ +
+
+
+
+

Constructors

+
+
+
+
+
    +
  • +
      +
    • new PlaceHolder()
    • +
    +
      +
    +
  • +
+
+
+
    +
  • session (Document): The document to associate with the anchor
  • +
  • length (Number): The starting row position
  • +
  • pos (Number): The starting column position
  • +
  • others (String):
  • +
  • mainClass (String):
  • +
  • othersClass (String):
  • +
+ +
+
    +
  • session (Document): The document to associate with the anchor
  • +
  • length (Number): The starting row position
  • +
  • pos (Number): The starting column position
  • +
  • others (String):
  • +
  • mainClass (String):
  • +
  • othersClass (String):
  • +
+ +
+
+
+
+
+

Methods

+
+
+
+
+
    +
  • +
      +
    • PlaceHolder.cancel()
    • +
    +
      +
    +
  • +
+
+
+

PlaceHolder.cancel()

+ +
+

PlaceHolder.cancel()

+

TODO

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • PlaceHolder.detach()
    • +
    +
      +
    +
  • +
+
+
+

PlaceHolder.detach()

+ +
+

PlaceHolder.detach()

+

TODO

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • PlaceHolder.hideOtherMarkers()
    • +
    +
      +
    +
  • +
+
+
+

PlaceHolder.hideOtherMarkers()

+ +
+

PlaceHolder.hideOtherMarkers()

+

Hides all over markers in the EditSession that are not the currently selected one.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • PlaceHolder.onCursorChange(Object event)
    • +
    +
      +
    +
  • +
+
+
+

PlaceHolder@onCursorChange(e)

+ +
+

PlaceHolder@onCursorChange(e)

+

Emitted when the cursor changes.

+ +

Arguments

eventObject

Required.

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • PlaceHolder.onUpdate(Object event)
    • +
    +
      +
    +
  • +
+
+
+

PlaceHolder@onUpdate(e)

+ +
+

PlaceHolder@onUpdate(e)

+

Emitted when the place holder updates.

+ +

Arguments

eventObject

Required.

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • PlaceHolder.setup()
    • +
    +
      +
    +
  • +
+
+
+

PlaceHolder.setup()

+ +
+

PlaceHolder.setup()

+

TODO

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • PlaceHolder.showOtherMarkers()
    • +
    +
      +
    +
  • +
+
+
+

PlaceHolder.showOtherMarkers()

+ +
+

PlaceHolder.showOtherMarkers()

+

TODO

+ +
+
+
+
+
+
+ + + + + +
+
\ No newline at end of file diff --git a/node_modules/ace/api/range.html b/node_modules/ace/api/range.html new file mode 100644 index 00000000..9779fe27 --- /dev/null +++ b/node_modules/ace/api/range.html @@ -0,0 +1,968 @@ + +
+
+
+
+
+

Range +

+ +
+
+
+
+

This object is used in various places to indicate a region within the editor. To better visualize how this works, imagine a rectangle. Each quadrant of the rectangle is analogus to a range, as ranges contain a starting row and starting column, and an ending row, and ending column.

+ +
+
+
+

Constructors

+
+
+
+
+ +
+
+

Creates a new Range object with the given starting and ending row and column points.

+ +
+

Creates a new Range object with the given starting and ending row and column points.

+ +

Arguments

startRowNumber

Required. The starting row

+
startColumnNumber

Required. The starting column

+
endRowNumber

Required. The ending row

+
endColumnNumber

Required. The ending column

+
+
+
+
+
+
+

Methods

+
+
+
+
+ +
+
+

Returns the part of the current Range that occurs within the boundaries of firstRow and lastRow as a new Range object.

+ +
+

Returns the part of the current Range that occurs within the boundaries of firstRow and lastRow as a new Range object.

+ +

Arguments

firstRowNumber

Required. The starting row

+
lastRowNumber

Required. The ending row

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Range.clone() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns a duplicate of the calling range.

+ +
+

Returns a duplicate of the calling range.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Range.collapseRows() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns a range containing the starting and ending rows of the original range, but with a column value of 0.

+ +
+

Returns a range containing the starting and ending rows of the original range, but with a column value of 0.

+ +
+
+
+
+
+
+
+
+
+ +
+
+

Checks the row and column points with the row and column points of the calling range.

+ +
+

Checks the row and column points with the row and column points of the calling range.

+ +

Arguments

rowNumber

Required. A row point to compare with

+
columnNumber

Required. A column point to compare with

+
+
+
+
+
+
+
+
+
+
+ +
+
+

Checks the row and column points with the row and column points of the calling range.

+ +
+

Checks the row and column points with the row and column points of the calling range.

+ +

Arguments

rowNumber

Required. A row point to compare with

+
columnNumber

Required. A column point to compare with

+
+
+
+
+
+
+
+
+
+
+ +
+
+

Checks the row and column points with the row and column points of the calling range.

+ +
+

Checks the row and column points with the row and column points of the calling range.

+ +

Arguments

rowNumber

Required. A row point to compare with

+
columnNumber

Required. A column point to compare with

+
+
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Checks the row and column points of p with the row and column points of the calling range.

+ +
+

Checks the row and column points of p with the row and column points of the calling range.

+ +

Arguments

pRange

Required. A point to compare with

+
+
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Compares this range (A) with another range (B).

+ +
+

Compares this range (A) with another range (B).

+ +

Arguments

rangeRange

Required. A range to compare with

+
+
+
+
+
+
+
+
+
+
+ +
+
+

Checks the row and column points with the row and column points of the calling range.

+ +
+

Checks the row and column points with the row and column points of the calling range.

+ +

Arguments

rowNumber

Required. A row point to compare with

+
columnNumber

Required. A column point to compare with

+
+
+
+
+
+
+
+
+
+
+ +
+
+

Returns true if the row and column provided are within the given range. This can better be expressed as returning true if:

+
   this.start.row <= row <= this.end.row &&
+   this.start.column <= column <= this.end.column
+ +
+

Returns true if the row and column provided are within the given range. This can better be expressed as returning true if:

+
   this.start.row <= row <= this.end.row &&
+   this.start.column <= column <= this.end.column
+ +

Arguments

rowNumber

Required. A row to check for

+
columnNumber

Required. A column to check for

+
+
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Checks the start and end points of range and compares them to the calling range. Returns true if the range is contained within the caller's range.

+ +
+

Checks the start and end points of range and compares them to the calling range. Returns true if the range is contained within the caller's range.

+ +

Arguments

rangeRange

Required. A range to compare with

+
+
+
+
+
+
+
+
+
+
+ +
+
+

Changes the row and column points for the calling range for both the starting and ending points.

+ +
+

Changes the row and column points for the calling range for both the starting and ending points.

+ +

Arguments

rowNumber

Required. A new row to extend to

+
columnNumber

Required. A new column to extend to

+
+
+
+
+
+
+
+
+
+
+ +
+
+

Creates and returns a new Range based on the row and column of the given parameters.

+ +
+

Creates and returns a new Range based on the row and column of the given parameters.

+ +

Arguments

startRange

Required. A starting point to use

+
endRange

Required. An ending point to use

+
+
+
+
+
+
+
+
+
+
+ +
+
+

Returns true if the row and column are within the given range.

+ +
+

Returns true if the row and column are within the given range.

+ +

Arguments

rowNumber

Required. A row point to compare with

+
columnNumber

Required. A column point to compare with

+
+
+
+
+
+
+
+
+
+
+ +
+
+

Returns true if the row and column are within the given range's ending points.

+ +
+

Returns true if the row and column are within the given range's ending points.

+ +

Arguments

rowNumber

Required. A row point to compare with

+
columnNumber

Required. A column point to compare with

+
+
+
+
+
+
+
+
+
+
+ +
+
+

Returns true if the row and column are within the given range's starting points.

+ +
+

Returns true if the row and column are within the given range's starting points.

+ +

Arguments

rowNumber

Required. A row point to compare with

+
columnNumber

Required. A column point to compare with

+
+
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Returns true if passed in range intersects with the one calling this method.

+ +
+

Returns true if passed in range intersects with the one calling this method.

+ +

Arguments

rangeRange

Required. A range to compare with

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Range.isEmpty()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+

Returns true if the caller's ending row point is the same as row, and if the caller's ending column is the same as column.

+ +
+

Returns true if the caller's ending row point is the same as row, and if the caller's ending column is the same as column.

+ +

Arguments

rowNumber

Required. A row point to compare with

+
columnNumber

Required. A column point to compare with

+
+
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Returns true if and only if the starting row and column, and ending row and column, are equivalent to those given by range.

+ +
+

Returns true if and only if the starting row and column, and ending row and column, are equivalent to those given by range.

+ +

Arguments

rangeRange

Required. A range to check against

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Range.isMultiLine() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns true if the range spans across multiple lines.

+ +
+

Returns true if the range spans across multiple lines.

+ +
+
+
+
+
+
+
+
+
+ +
+
+

Returns true if the caller's starting row point is the same as row, and if the caller's starting column is the same as column.

+ +
+

Returns true if the caller's starting row point is the same as row, and if the caller's starting column is the same as column.

+ +

Arguments

rowNumber

Required. A row point to compare with

+
columnNumber

Required. A column point to compare with

+
+
+
+
+
+
+
+
+
+
+ +
+
+

Sets the starting row and column for the range.

+ +
+

Sets the starting row and column for the range.

+ +

Arguments

rowNumber

Required. A row point to set

+
columnNumber

Required. A column point to set

+
+
+
+
+
+
+
+
+
+
+ +
+
+

Sets the starting row and column for the range.

+ +
+

Sets the starting row and column for the range.

+ +

Arguments

rowNumber

Required. A row point to set

+
columnNumber

Required. A column point to set

+
+
+
+
+
+
+
+
+
+
+ +
+
+

Given the current Range, this function converts those starting and ending points into screen positions, and then returns a new Range object.

+ +
+

Given the current Range, this function converts those starting and ending points into screen positions, and then returns a new Range object.

+ +

Arguments

sessionEditSession

Required. The EditSession to retrieve coordinates from

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Range.toString() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns a string containing the range's row and column information, given like this:

+
   [start.row/start.column] -> [end.row/end.column]
+ +
+

Returns a string containing the range's row and column information, given like this:

+
   [start.row/start.column] -> [end.row/end.column]
+ +
+
+
+
+
+
+ + + + + +
+
\ No newline at end of file diff --git a/node_modules/ace/api/renderloop.html b/node_modules/ace/api/renderloop.html new file mode 100644 index 00000000..59c98a0c --- /dev/null +++ b/node_modules/ace/api/renderloop.html @@ -0,0 +1,55 @@ + +
+
+
+
+
+

RenderLoop +

+ +
+
+
+
+

Batches changes (that force something to be redrawn) in the background.

+ +
+
+
+
+ + + + + +
+
\ No newline at end of file diff --git a/node_modules/ace/api/resources/csses/ace_api.css b/node_modules/ace/api/resources/csses/ace_api.css new file mode 100644 index 00000000..7a90b4c3 --- /dev/null +++ b/node_modules/ace/api/resources/csses/ace_api.css @@ -0,0 +1,912 @@ +/* + Generic "affects everything" stuff +*/ + +#wrapper .content .column2 { + float: none; +} + +#documentation ul { + font-size: 13px; +} + +#documentation li { + color: black; +} + +pre { + background-color: #FFFFFF; +} + +code { + font-size: 12px; + line-height: 16px; + font-family: 'Ubuntu Mono',Monaco,Consolas,monospace !important; + background-color: #F9F9F9; + border-radius: 3px 3px 3px 3px; + display: inline-block; + padding: 0 4px; + margin: 2px 1px; + color: inherit; +} + +#documentation pre { + margin-top: 10px; + border-radius: none; + box-shadow: none; + background : white; + /*background : #f5f5f5; + border: 0;*/ + + -webkit-border-radius: 6px 6px 0 0; + -moz-border-radius: 6px 6px 0 0; + border-radius: 6px 6px 0 0; + + padding: 5px; +} + +.method pre, .event pre, .property pre { + background : white; +} + +#documentation pre code { + background-color: transparent; + border-radius: none; + box-shadow: none; +} + +#documentation a code { + color: #00438a; +} + +#documentation h2 { + font-size: 26px; +} +#documentation p { + font-size: 13px; +} +#documentation li p:last-child { + margin-bottom : 5px; +} + +#documentation blockquote p{ + font-size: 14px; + font-weight: 500; + line-height: 23px; + font-style: italic; +} + +.alert-message{ + margin-bottom : 13px; +} +/* + Header and shoulders +*/ + +.navbar .nav > li { + float:none; + display:inline-block; + *display:inline; /* ie7 fix */ + zoom:1; /* hasLayout ie7 trigger */ +} + +.navbar .nav > li > a { + padding: 10px 15px 11px; +} + +.navbar { + text-align:center; +} + +#topSection { + width: 1000px; +} +.small_win #topSection { + width: 100%; +} +.small_win #topSection .dropdown { + margin-right: 40%; +} +.navbar .brand { + margin-left: 0px; +} +.brand { + background: transparent url(../images/ace_logo_menu.png) no-repeat 33px 5px; + width: 80px; + outline: none; + height: 40px; + padding: 0 10px !important; + border: none; +} +.brand.dropdown-toggle:after { + content: none; + display: block; + height: 40px; + border: none; +} + +.ace_logo { + position: absolute; + top: 45px; + z-index: 20000; + left: 210px; +} + +.headerTitle { + position: relative; + top: 100px; + left: 250px; +} + +/* + Menu venue +*/ + + +h3.api_title { + padding-top: 10px; +} + +ul.menu { + margin-left: 2px; +} + +.menu li { + list-style-image: url(../images/menu_disc.png); + margin-bottom: 4px; + font-weight: 700; + padding-left: 10px; + margin-left: 0; +} + +.menu li .menu-item a.menuLink, .menu li .menu-item span.menuLink { + color: #3E7096; + font-weight: 100; +} +.menuTwo { + margin-bottom: 5px; + margin-top: 2px; +} +.menuTwo li .menu-item a.menuLink { + color: #3E7096; + font-weight: 100; +} + +/* need specificity to "beat" the above colors */ +.menu li .menu-item a.currentItem, .menuTwo li .menu-item { + color: #0072bc; +} + +/* + Members and the tabs that represent them +*/ + +.srolled .members { + width: 100%; +/* -webkit-box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.35); + -moz-box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.35); + box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.35); */ + padding-bottom: 15px; +/* height: 31px;*/ + position: fixed; +} +.shadow.members{ + background: #edf8fd; + box-shadow: 0 0.1em 1em rgba(0,0,0, 0.3); + -moz-box-shadow: 0 0.1em 1em rgba(0,0,0, 0.3); + -o-box-shadow: 0 0.1em 1em rgba(0,0,0, 0.3); + -webkit-box-shadow: 0 0.1em 1em rgba(0,0,0, 0.3); +} + +.membersContent { + +/* border-bottom: 0.1em solid #FFF;*/ + height: 3em; + padding-top: 4px; +/* line-height: 4;*/ +/* margin-top: -0.1em;*/ + position: relative; +/* transition-property: border-color, line-height; + transition-duration: 125ms, 250ms; + transition-timing-function: ease-out, ease-out; + -moz-transition-property: border-color, line-height; + -moz-transition-duration: 125ms, 250ms; + -moz-transition-timing-function: ease-out, ease-out; + -o-transition-property: border-color, line-height; + -o-transition-duration: 125ms, 250ms; + -o-transition-timing-function: ease-out, ease-out; + -webkit-transition-property: border-color, line-height; + -webkit-transition-duration: 125ms, 250ms; + -webkit-transition-timing-function: ease-out, ease-out;*/ + + /*transition-duration: 125ms; + transition-property: top; + transition-timing-function: ease-out; + + top : 11px;*/ + z-index: 103; + padding-right: 10px; + margin-right: -5px; + /*width: 700px;*/ +} +.srolledHeader .membersContent { + line-height: 3; +} +.srolled .membersContent { + /*top : 0;*/ + width: 625px; + padding-left: 327px; + margin : 0 auto 0 auto; +} + +.srolled ul.nav { + padding-right: 10px; +} + +.membersBackground { +/* background-color: white; + position: fixed; + z-index: 2; + top: 40px; + left: 0px; + right: 0px; + width: 100%; + height: 55px; + opacity: 0; + display: none; + box-shadow: rgba(0, 0, 0, 0.398438) 1px 4px 6px;*/ + + background-color: transparent; + height: 47px; + /*width: 700px;*/ + position: absolute; +} +.srolled .membersBackground { + position: relative; +} +.srolledHeader .membersBackground { +/* display: block;*/ +} +.memberHeader { + float: left; + padding-right: 10px; + margin-bottom: 5px; + position: absolute; + padding-top: 4px; + +} + +ul.tabs li:first-child ul{ + left: -63px; +} + +.tabs a.menu:after, .tabs .dropdown-toggle:after { + margin-top: 22px; +} + +.nav .dropdown-toggle .caret { + margin-top: 12px; + border-top-color: #6D8CA0; + border-bottom-color: #6D8CA0; +} + +li.dropdown { + color: #2D2D2D; + font-weight: bold; +} + +.editInC9 { + font-size: 11px; + color: #657383; +} + +.editInC9 a { + color: #657383; + font-weight: normal; + position : relative; + top : -2px; +} + +.tabs { + padding-top: 14px; + /*border-bottom: 1px solid #848484;*/ + min-height : 27px; + padding-bottom : 5px; +} +.tabsSansBorder { + border: 0; +} +.tabs, .pills { + margin-bottom: 0; +} +.srolledHeader .members .tabs { + background-color: white; +} + +li.dropdown { + color: #2D2D2D; + font-weight: bold; +} + +.members .tabs .dropdown a, +.members .tabs a.menu:after, +.members .tabs .dropdown-toggle:after { + margin-right: 0; + margin-left: 6px; +} + +.memberLink a { + margin-left: 0 !important; +} +.menu-dropdown { + min-width : 105px; + max-height: 350px; + overflow: auto; + border-color : rgba(0, 0, 0, 0.1); +} +.topbar div > ul .menu-dropdown li a:hover, +.nav .menu-dropdown li a:hover, +.topbar div > ul .dropdown-menu li a:hover, +.nav .dropdown-menu li a:hover { + background-color: #ffffff; + color: #000000; +} + +.tabs a.menu:after, .tabs .dropdown-toggle:after { + margin-top: 13px; + line-height: 28px; +} +.open .menu, .dropdown.open .menu, .open .dropdown-toggle, .dropdown.open .dropdown-toggle { + background: transparent; + color: black; +/* font-weight: bold;*/ +} +#topSection .open .menu, #topSection .dropdown.open .menu, #topSection .open .dropdown-toggle, +#topSection .dropdown.open .dropdown-toggle { + color: #bfbfbf; +} + +.tabs > li { + font-weight: bold; +} + +.tabs > li > a { + border: none; + outline: none; + line-height: 28px; + font-size: 11px; + padding: 0 5px; +} +.tabs > li > a:hover { + color: #000000; + text-decoration: none; + background-color: transparent; + border: none; +} +.tabs > li, .pills > li { + float: right; +} +.topbar .dropdown-menu a, .dropdown-menu a { + font-size: 11px; +/* padding: 2px 12px;*/ + line-height: 14px; +} +.tabs .active > a, .tabs .active > a:hover { + color: #000000; + border: none; + cursor: default; +} +.tabs .menu-dropdown, .tabs .dropdown-menu { + border-radius: 0 0 6px 6px; + left: 10px; + width: 160px; +} +.srolled .tabs .menu-dropdown, .srolled .tabs .dropdown-menu { + top: 32px; +} +.dropdown-toggle { + color: #6D8CA0; +} + +ul.tabs .double ul, ul.tabs .triple ul, ul.tabs .quad ul{ + width:760px; + margin-bottom:20px; + overflow:hidden; + border-top:1px solid #ccc; +} +/*ul.tabs .double li, ul.tabs .triple li, ul.tabs .quad li{ + line-height:1.5em; + border-bottom:1px solid #ccc; + float:left; + display:inline; +}*/ + +/* + Center content (the "real stuff") +*/ + +#nonFooter { + padding-top: 40px; +} +#wrapper { + height: 100%; +} + +.content { + height: 100%; +} + +header.filler { + position: relative; + height: 40px; + width: 100%; +} + +/* +.container-fluid .row-fluid { + width: 1000px; + margin-left: auto; + margin-right: auto; +}*/ + +.divider { + height: 3px; + background-color: #BEDAEA; + margin-bottom: 3px; +} + +#sidebar h3 a, +#sidebar h3 a:hover { + color: #404040; +} + +#sidebarContainer { + padding-top: 20px; +} + +#mainContent { + margin-left: 30px; +} + +#documentation { + padding-top: 35px; + padding-bottom: 10px; +} + +#documentation article.article { + border-top: 1px solid #e9e9e9; + padding: 16px 10px 2px; + -webkit-transition: padding 0.2s; + -moz-transition: padding 0.2s; + -o-transition: padding 0.2s; +} + +#documentation h3.sectionHeader + article.article { + border-top: none; +} + +div#documentation article:last-child { + border-bottom: 1px solid #e9e9e9; + padding-bottom: 40px; +} +#documentation article.article.methodToggleOpen { + background: rgba(255, 255, 255, 0.5); + font-size: 13px; + line-height: 24px; + margin: 0 0 10px 0; +} + +#documentation article:first-child { + border:none; +} + +.site_logo { + display: block; + margin-left: auto; + margin-right: auto; +} +/* + Edit in Cloud9, sucka +*/ + +.snippet pre { + margin-bottom: 0; +} + +.snippet .toolbar { + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; + + text-align: right; + padding: 3px 10px; + margin-top : -1px; +} + +.snippet .filename, .snippet .toolbar { + font-family: Ubuntu, sans-serif; + font-size: 12px; + color: #EEE; +} + +.snippet .filename { + padding: 0 5px 2px 5px; + font-size: 10px; + background: rgba(230,230,230,0.5); + padding: 0 5px 2px 5px; + border-radius: 0 6px 0 6px; + margin : 1px; + position : absolute; + right : 0; + top : 0; +} + +.snippet .filename span{ + color : #666; +} + +.snippet .toolbar { + background-color: rgba(30,30,30,0.5); +} + +div.snippet { + margin-bottom: 18px; + position : relative; +} + +div.snippet a, div.toolbar a { + color: #FFF; +} + +/* + All about signatures +*/ + +.signatures { +/* width: 800px;*/ + margin-left: 20px; + margin-bottom: 5px; +} +.sideToggler { + padding-left: 20px; +} +ul.signatures ul { + list-style: none; + display: inline; +} + +li.signature { + list-style: none; +} + +.signature ul { + padding: 0; + margin: 0; +} + +.signature li { + display: inline; +} + +.signature ul.argument-types::before { + content: '→'; + margin: 0 5px; +} + +.signature li.argument-type::after { + content: '|'; + padding: 0 5px 0 5px; +} + +.signature li.argument-type:last-child:after { + content: ''; + padding: 0 5px 0 5px; +} + +.member-name { + color: #4397cd; + font-weight: bold; + text-decoration: none; + cursor: pointer; + padding-right: 3px; +} + +.signature-call { + cursor: pointer; +} + +#documentation .signature-call a { + color: #8e487e; +} + +.sigClassName { + display: none; +} + +.eventObjName { + font-style: italic; +} +.eventListenerStart, .eventListenerClose, .eventFunctionOpen, .eventFunctionClose { + color: #999999; +} +.eventMember { + padding-right: 0px; +} + +.metaInfo { + float: right; + z-index: 1; + position: relative; +} + +.chainable { + background-color: #0072bc; + color: #ffffff; +} + +.deprecated { + background-color: #f7941d; + color: #ffffff; +} + +.alias { + background-color: #6c951e; + color: #ffffff; +} + +.related-to { + background-color: #89289a; + color: #ffffff; + font-size: 10px; + padding: 2px 5px 3px; + text-transform: capitalize; +} + +.undocumented { + background-color: #B94A48; + color: #ffffff; +} + +#documentation .alias a, #documentation .related-to a { + color: #ffffff; + /* text-decoration: underline; */ +} +#documentation .alias a:hover, #documentation .related-to a:hover { + text-decoration: none; +} +.#documentation alias:hover, #documentation .related-to:hover { + opacity: 0.8; + cursor: pointer; +} +.memberContent .title { + +} +.memberContent .description { + position:relative; + /*top: -13px;*/ + display: none; +} +.snip-container .actions .toggle-plaintext label { + margin-top: 1px; + padding-top: 0; + text-align: left; +} +.snip-container .actions .toggle-plaintext input { + margin-top: 4px !important; +} +.snip-container label { + color: #ffffff; +} +.description h4 { + padding-top: 10px; + font-size: 18px; + line-height : 18px; +} + +.table-striped tbody tr:nth-child(odd) td, .table-striped tbody tr:nth-child(odd) th { + background-color: #F9F9F9; +} +.table-striped tbody tr:nth-child(even) td, .table-striped tbody tr:nth-child(even) th { + background-color: #fbfbfb; +} + +.argument-list { + margin-bottom : 13px; +} +.argName { + font-style: italic; +} + + +/* + Everyday I'm togglin' +*/ + +#documentation i.methodToggle { + cursor: pointer; + color: #9f9f9f; + padding-top: 2px; + float: left; +} +#documentation i.methodToggle.methodToggleHover { + text-shadow: 0 0 10px #4699d5; + color: #4699d5; +} +#documentation i.methodToggle.active { + text-shadow: 0 0 10px #4699d5; + color: #4699d5; + /* Safari */ + -webkit-transform: rotate(45deg); + + /* Firefox */ + -moz-transform: rotate(45deg); + + /* IE */ + -ms-transform: rotate(45deg); + + /* Opera */ + -o-transform: rotate(45deg); + padding-top: 9px; +} + +#documentation h3.sectionHeader { + line-height : 24px; +} + +div.method { + position: relative; +} + +.methodToggle a { + color: #fff; + border-bottom: 0px; + text-decoration: none; +} + +h3.methodToggle { + height : 13px; + width : 8px; + background-position : 0px 0px; + position: absolute; + top: -20px; + background-image : url(../images/member-sprites.png); + background-color : transparent; + background-repeat : no-repeat; + overflow: hidden; + left: 0px; +} + +h3.methodToggleHover { + /* background-position : 0px -28px; */ +} + +h3.methodToggle.inactive { + top: 4px; +} + +h3.methodToggle.active { + top: 6px; + height : 13px; + width : 8px; + background-position : 0px -59px; +} + +.hidden { + display: none; + visibility: hidden; +} + +.hiddenSpan { + display: none; +} + +.ellipsis_description, .short_description { +/* width: 800px;*/ +} +.methodToggleOpen .ellipsis_description { + display: none; +} +.sideToggler .short_description, +.sideToggler .description{ + display: none; +} +.methodToggleOpen .short_description, +.methodToggleOpen .description { + display: block; +} +.description td p { + margin: 0; +} +/* + Footer? I hardly know her +*/ + +#footer { + width:100%; + background: #101010 url(../images/dashed_back.png) repeat 0 0; + font-size: 12px; + color: white; + height: 40px; +} +#footer .footerInner { + padding-left: 300px; + margin-left: auto; + margin-right: auto; + min-height: 40px; +} +#footer .footer-text { + display: block; + font-size: 12px; + float: right; +} +#footer div.footerInner div.footer-text p { + font-size: 12px; + font-family: Arial; + line-height: 18px; + margin: 10px 15px 0px 1px; +} + +#footer a, #footer a:hover { + color: #8DD0FF; +} + +.logoText, .logoImg { + /*position: absolute;*/ + margin-bottom: 5px; +} + +.logoImg { + top: 40px; +} +.topbar div > ul .menu-dropdown li a:hover, +.nav .menu-dropdown li a:hover, +.topbar div > ul .dropdown-menu li a:hover, +.nav .dropdown-menu li a:hover { + background-color: #191919; + background-repeat: repeat-x; + background-image: -khtml-gradient(linear, left top, left bottom, from(#292929), to(#191919)); + background-image: -moz-linear-gradient(top, #292929, #191919); + background-image: -ms-linear-gradient(top, #292929, #191919); + background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #292929), color-stop(100%, #191919)); + background-image: -webkit-linear-gradient(top, #292929, #191919); + background-image: -o-linear-gradient(top, #292929, #191919); + background-image: linear-gradient(top, #292929, #191919); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#292929', endColorstr='#191919', GradientType=0); + color: #ffffff; +} + +.alert-message.block-message { + background: #fefaca; + border-color : #fefaca; + padding : 8px 14px 8px 14px; +} + +body .dsq-reply{ + margin-top : 10px; +} + +#disqus_thread{ + border-top : 1px solid #ddd; + margin-top : 30px; +} + +#disqus_thread h3, body #dsq-content h3 { + font-size : 12px; + margin : 0 0 20px 0; + line-height : 12px; +} +body #dsq-reply h3{ + font-size : 18px; + line-height : 18px; + margin : 15px 0 20px 0; +} + +#disqus_thread select{ + font-size : 11px; + height : 20px; + color : #444; +} + +#dsq-global-toolbar, #dsq-pagination, .dsq-trackback-url{ + display : none; +} diff --git a/node_modules/ace/api/resources/font/fontawesome-webfont.eot b/node_modules/ace/api/resources/font/fontawesome-webfont.eot new file mode 100644 index 0000000000000000000000000000000000000000..89070c1e63c2703b2334023922ecc1664f759b55 GIT binary patch literal 38708 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/node_modules/ace/api/resources/font/fontawesome-webfont.ttf b/node_modules/ace/api/resources/font/fontawesome-webfont.ttf new file mode 100644 index 0000000000000000000000000000000000000000..c17e9f8d100d01a002029b5b93cc081062618bf3 GIT binary patch literal 68476 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 literal 0 HcmV?d00001 diff --git a/node_modules/ace/api/resources/images/Ace_ERD.png b/node_modules/ace/api/resources/images/Ace_ERD.png new file mode 100644 index 0000000000000000000000000000000000000000..78fb8dab6a25315303e12b6653b480886ad85578 GIT binary patch literal 59424 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 E1vXzqcmMzZ literal 0 HcmV?d00001 diff --git a/node_modules/ace/api/resources/images/ace_logo.png b/node_modules/ace/api/resources/images/ace_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..4dab4f66ebffb0816dc8968ea52f64773970bedb GIT binary patch literal 42538 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 PelKaN>Z(*J*+l#o=FgAV literal 0 HcmV?d00001 diff --git a/node_modules/ace/api/resources/images/c9-sponsor.png b/node_modules/ace/api/resources/images/c9-sponsor.png new file mode 100644 index 0000000000000000000000000000000000000000..599d3b49b07be4610d0ce3c808b47c7218eb2257 GIT binary patch literal 12244 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
 
+// elements on the page and add the "prettyprint" style. If at least one 
+// prettyprint element was found, call the Google Prettify prettyPrint() API.
+//http://sstatic.net/so/js/master.js?v=6523
+function styleCode() 
+{
+    if (typeof disableStyleCode != "undefined") 
+    {
+        return;
+    }
+
+    var a = false;
+
+    $("pre code").parent().each(function() 
+    {
+        if (!$(this).hasClass("prettyprint")) 
+        {
+            $(this).addClass("prettyprint");
+            a = true
+        }
+    });
+    
+    if (a) { prettyPrint() } 
+}
\ No newline at end of file
diff --git a/node_modules/ace/api/resources/javascripts/prettify.js b/node_modules/ace/api/resources/javascripts/prettify.js
new file mode 100644
index 00000000..eef5ad7e
--- /dev/null
+++ b/node_modules/ace/api/resources/javascripts/prettify.js
@@ -0,0 +1,28 @@
+var q=null;window.PR_SHOULD_USE_CONTINUATION=!0;
+(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a=
+[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;ci[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m),
+l=[],p={},d=0,g=e.length;d=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/,
+q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/,
+q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g,
+"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a),
+a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e}
+for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],
+"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"],
+H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],
+J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+
+I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),
+["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css",
+/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}),
+["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes",
+hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p=0){var k=k.match(g),f,b;if(b=
+!k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p 1010) sx = 1010 - document.documentElement.offsetWidth;
+    }
+    else sx = 0;
+
+    $('span.methodClicker, article.article, i.methodClicker').each(function () {
+        var a = $(this);
+        var constructorPos = a.attr("id").indexOf("new ");
+
+        var objName = a.attr("id");
+        if (constructorPos >= 0) {
+            objName = objName.substring(constructorPos + 4);
+            objName += ".new";
+        }
+
+        a.attr("id", objName);
+    });
+    
+    function showMethodContent() {
+        var locationHash = location.hash.replace(/^#/, '').replace(/\./g, '\\.');
+        var equalsPos = location.hash.indexOf("=");
+        
+        if (equalsPos >=0) {
+            locationHash = locationHash.substring(0, location.hash.indexOf("="));
+        }
+        
+        var $clickerEl = $('span#' + locationHash);
+        if ($clickerEl.length > 0 && $clickerEl.hasClass('methodClicker')) {
+            var p = $clickerEl.parent();
+            p[0].force = true;
+            p.trigger('click');
+            p[0].force = false;
+        }
+    }
+
+    if (location.hash.indexOf("section") >= 1) {
+        showMethodContent();
+        var data = location.hash;
+        scrollTo(null, data.substr(1));
+    }
+
+    window.onhashchange = function () {
+        showMethodContent();
+    }
+};
+
+function scrollTo(el, data) {
+    if (!data) {
+        data = el.getAttribute("data-id");
+        //location.hash = data;
+    }
+    var el = $("span#" + data.replace(/\./g, "\\."))[0];
+    if (!el) return;
+
+    var article = $(el).closest('.article')[0];
+
+    var top = article.offsetTop - 100;
+
+    if (document.body.scrollTop > top || document.body.scrollTop != top && document.body.scrollTop + (window.innerHeight || document.documentElement.offsetHeight) < top + article.offsetHeight) {
+        $('body').animate({
+            scrollTop: top
+        }, {
+            duration: 200,
+            easing: "swing"
+        });
+    }
+}
\ No newline at end of file
diff --git a/node_modules/ace/api/scrollbar.html b/node_modules/ace/api/scrollbar.html
new file mode 100644
index 00000000..5f311060
--- /dev/null
+++ b/node_modules/ace/api/scrollbar.html
@@ -0,0 +1,261 @@
+
+
+
+
+
+
+

ScrollBar +

+ +
+
+
+
+

A set of methods for setting and retrieving the editor's scrollbar.

+ +
+
+
+

Constructors

+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Creates a new ScrollBar. parent is the owner of the scroll bar.

+ +
+

Creates a new ScrollBar. parent is the owner of the scroll bar.

+ +

Arguments

parentDOMElement

Required. A DOM element

+
+
+
+
+
+
+

Events

+
+
+
+
+
    +
  • +
      +
    • ScrollBar.on("scroll", function(Object e))
    • +
    +
      +
    +
  • +
+
+
+

Emitted when the scroll bar, well, scrolls.

+ +
+

Emitted when the scroll bar, well, scrolls.

+ +

Arguments

eObject

Required. Contains one property, "data", which indicates the current scroll top position

+
+
+
+
+
+
+

Methods

+
+
+
+
+
    +
  • +
      +
    • ScrollBar.getWidth() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the width of the scroll bar.

+ +
+

Returns the width of the scroll bar.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • ScrollBar.onScroll()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • ScrollBar.setHeight(Number height)
    • +
    +
      +
    +
  • +
+
+
+

Sets the height of the scroll bar, in pixels.

+ +
+

Sets the height of the scroll bar, in pixels.

+ +

Arguments

heightNumber

Required. The new height

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • ScrollBar.setInnerHeight(Number height)
    • +
    +
      +
    +
  • +
+
+
+

Sets the inner height of the scroll bar, in pixels.

+ +
+

Sets the inner height of the scroll bar, in pixels.

+ +

Arguments

heightNumber

Required. The new inner height

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • ScrollBar.setScrollTop(Number scrollTop)
    • +
    +
      +
    +
  • +
+
+
+

Sets the scroll top of the scroll bar.

+ +
+

Sets the scroll top of the scroll bar.

+ +

Arguments

scrollTopNumber

Required. The new scroll top

+
+
+
+
+
+
+
+ + + + + +
+
\ No newline at end of file diff --git a/node_modules/ace/api/search.html b/node_modules/ace/api/search.html new file mode 100644 index 00000000..61616063 --- /dev/null +++ b/node_modules/ace/api/search.html @@ -0,0 +1,295 @@ + +
+
+
+
+
+

Search +

+ +
+
+
+
+

A class designed to handle all sorts of text searches within a Document.

+ +
+
+
+

Constructors

+
+
+
+
+
    +
  • +
      +
    • new Search()
    • +
    +
      +
    +
  • +
+
+
+

Creates a new Search object. The following search options are avaliable:

+ +
+

Creates a new Search object. The following search options are avaliable:

+
    +
  • needle: The string or regular expression you're looking for
  • +
  • backwards: Whether to search backwards from where cursor currently is. Defaults to false.
  • +
  • wrap: Whether to wrap the search back to the beginning when it hits the end. Defaults to false.
  • +
  • caseSensitive: Whether the search ought to be case-sensitive. Defaults to false.
  • +
  • wholeWord: Whether the search matches only on whole words. Defaults to false.
  • +
  • range: The Range to search within. Set this to null for the whole document
  • +
  • regExp: Whether the search is a regular expression or not. Defaults to false.
  • +
  • start: The starting Range or cursor position to begin the search
  • +
  • skipCurrent: Whether or not to include the current line in the search. Default to false.
  • +
+ +
+
+
+
+
+

Methods

+
+
+
+
+ +
+
+

Searches for options.needle. If found, this method returns the Range where the text first occurs. If options.backwards is true, the search goes backwards in the session.

+ +
+

Searches for options.needle. If found, this method returns the Range where the text first occurs. If options.backwards is true, the search goes backwards in the session.

+ +

Arguments

sessionEditSession

Required. The session to search with

+
+
+
+
+
+
+
+
+
+
+ +
+
+

Searches for all occurances options.needle. If found, this method returns an array of Ranges where the text first occurs. If options.backwards is true, the search goes backwards in the session.

+ +
+

Searches for all occurances options.needle. If found, this method returns an array of Ranges where the text first occurs. If options.backwards is true, the search goes backwards in the session.

+ +

Arguments

sessionEditSession

Required. The session to search with

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Search.getOptions() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns an object containing all the search options.

+ +
+

Returns an object containing all the search options.

+ +
+
+
+
+
+
+
+
+
+ +
+
+

Searches for options.needle in input, and, if found, replaces it with replacement.

+ +
+

Searches for options.needle in input, and, if found, replaces it with replacement.

+ +

Arguments

inputString

Required. The text to search in

+
replacementString

Required. The replacing text

+
    +
  • (String): If options.regExp is true, this function returns input with the replacement already made. Otherwise, this function just returns replacement.
    +If options.needle was not found, this function returns null.
  • +
+
+
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    • Chainable
    • +
    +
  • +
+
+
+

Sets the search options via the options parameter.

+ +
+

Sets the search options via the options parameter.

+ +

Arguments

optionsObject

Required. An object containing all the new search properties

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Search.setOptions()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+ + + + + +
+
\ No newline at end of file diff --git a/node_modules/ace/api/selection.html b/node_modules/ace/api/selection.html new file mode 100644 index 00000000..4da8f771 --- /dev/null +++ b/node_modules/ace/api/selection.html @@ -0,0 +1,1781 @@ + +
+
+
+ +
+
+

Contains the cursor position and the text selection of an edit session.

+

The row/columns used in the selection are in document coordinates representing the coordinates as they appear in the document before applying soft wrap and folding.

+ +
+
+
+

Constructors

+
+
+
+
+ +
+
+

Creates a new Selection object.

+ +
+

Creates a new Selection object.

+ +

Arguments

sessionEditSession

Required. The session to use

+
+
+
+
+
+
+

Events

+
+
+
+
+
    +
  • +
      +
    • Selection.on("changeCursor", function())
    • +
    +
      +
    +
  • +
+
+
+

Emitted when the cursor position changes.

+ +
+

Emitted when the cursor position changes.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.on("changeSelection", function())
    • +
    +
      +
    +
  • +
+
+
+

Emitted when the cursor selection changes.

+ +
+

Emitted when the cursor selection changes.

+ +
+
+
+
+
+

Methods

+
+
+
+
+
    +
  • +
      +
    • Selection.addRange(Range range, Boolean $blockChangeEvents)
    • +
    +
      +
    +
  • +
+
+
+

Adds a range to a selection by entering multiselect mode, if necessary.

+ +
+

Adds a range to a selection by entering multiselect mode, if necessary.

+ +

Arguments

rangeRange

Required. The new range to add

+
$blockChangeEventsBoolean

Required. Whether or not to block changing events

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.clearSelection()
    • +
    +
      +
    +
  • +
+
+
+

Empties the selection (by de-selecting it). This function also emits the 'changeSelection' event.

+ +
+

Empties the selection (by de-selecting it). This function also emits the 'changeSelection' event.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.detach()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.fromOrientedRange()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.getAllRanges() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns a concatenation of all the ranges.

+ +
+

Returns a concatenation of all the ranges.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.getCursor() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Gets the current position of the cursor.

+ +
+

Gets the current position of the cursor.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.getLineRange()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.getRange() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the Range for the selected text.

+ +
+

Returns the Range for the selected text.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.getSelectionAnchor() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns an object containing the row and column of the calling selection anchor.

+ +
+

Returns an object containing the row and column of the calling selection anchor.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.getSelectionLead() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns an object containing the row and column of the calling selection lead.

+ +
+

Returns an object containing the row and column of the calling selection lead.

+ +
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Moves the selection to highlight the entire word.

+ +
+

Moves the selection to highlight the entire word.

+ +

Arguments

rowObject

Required.

+
columnObject

Required.

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.isBackwards() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns true if the selection is going backwards in the document.

+ +
+

Returns true if the selection is going backwards in the document.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.isEmpty() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns true if the selection is empty.

+ +
+

Returns true if the selection is empty.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.isMultiLine() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns true if the selection is a multi-line.

+ +
+

Returns true if the selection is a multi-line.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.mergeOverlappingRanges()
    • +
    +
      +
    +
  • +
+
+
+

Merges overlapping ranges ensuring consistency after changes

+ +
+

Merges overlapping ranges ensuring consistency after changes

+ +
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Moves the cursor to position indicated by the parameters. Negative numbers move the cursor backwards in the document.

+ +
+

Moves the cursor to position indicated by the parameters. Negative numbers move the cursor backwards in the document.

+ +

Arguments

rowsNumber

Required. The number of rows to move by

+
charsNumber

Required. The number of characters to move by

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.moveCursorDown()
    • +
    +
      +
    +
  • +
+
+
+

Moves the cursor down one row.

+ +
+

Moves the cursor down one row.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.moveCursorFileEnd()
    • +
    +
      +
    +
  • +
+
+
+

Moves the cursor to the end of the file.

+ +
+

Moves the cursor to the end of the file.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.moveCursorFileStart()
    • +
    +
      +
    +
  • +
+
+
+

Moves the cursor to the start of the file.

+ +
+

Moves the cursor to the start of the file.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.moveCursorLeft()
    • +
    +
      +
    +
  • +
+
+
+

Moves the cursor left one column.

+ +
+

Moves the cursor left one column.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.moveCursorLineEnd()
    • +
    +
      +
    +
  • +
+
+
+

Moves the cursor to the end of the line.

+ +
+

Moves the cursor to the end of the line.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.moveCursorLineStart()
    • +
    +
      +
    +
  • +
+
+
+

Moves the cursor to the start of the line.

+ +
+

Moves the cursor to the start of the line.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.moveCursorLongWordLeft()
    • +
    +
      +
    +
  • +
+
+
+

Moves the cursor to the word on the left.

+ +
+

Moves the cursor to the word on the left.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.moveCursorLongWordRight()
    • +
    +
      +
    +
  • +
+
+
+

Moves the cursor to the word on the right.

+ +
+

Moves the cursor to the word on the right.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.moveCursorRight()
    • +
    +
      +
    +
  • +
+
+
+

Moves the cursor right one column.

+ +
+

Moves the cursor right one column.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.moveCursorShortWordLeft()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.moveCursorShortWordRight()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+

Moves the cursor to the row and column provided. If preventUpdateDesiredColumn is true, then the cursor stays in the same column position as its original point.

+ +
+

Moves the cursor to the row and column provided. If preventUpdateDesiredColumn is true, then the cursor stays in the same column position as its original point.

+ +

Arguments

rowNumber

Required. The row to move to

+
columnNumber

Required. The column to move to

+
keepDesiredColumnBoolean

Required. If true, the cursor move does not respect the previous column

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.moveCursorToPosition(Object position)
    • +
    +
      +
    +
  • +
+
+
+

Moves the selection to the position indicated by its row and column.

+ +
+

Moves the selection to the position indicated by its row and column.

+ +

Arguments

positionObject

Required. The position to move to

+
+
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Moves the cursor to the screen position indicated by row and column. If preventUpdateDesiredColumn is true, then the cursor stays in the same column position as its original point.

+ +
+

Moves the cursor to the screen position indicated by row and column. If preventUpdateDesiredColumn is true, then the cursor stays in the same column position as its original point.

+ +

Arguments

rowNumber

Required. The row to move to

+
columnNumber

Required. The column to move to

+
keepDesiredColumnBoolean

Required. If true, the cursor move does not respect the previous column

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.moveCursorUp()
    • +
    +
      +
    +
  • +
+
+
+

Moves the cursor up one row.

+ +
+

Moves the cursor up one row.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.moveCursorWordLeft()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.moveCursorWordRight()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.rectangularRangeBlock(Cursor screenCursor, Anchor screenAnchor, Boolean includeEmptyLines) +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Gets list of ranges composing rectangular block on the screen

+ +
+

Gets list of ranges composing rectangular block on the screen

+ +

Arguments

screenCursorCursor

Required. The cursor to use

+
screenAnchorAnchor

Required. The anchor to use

+
includeEmptyLinesBoolean

Required. If true, this includes ranges inside the block which are empty due to clipping

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.selectAll()
    • +
    +
      +
    +
  • +
+
+
+

Selects all the text in the document.

+ +
+

Selects all the text in the document.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.selectAWord()
    • +
    +
      +
    +
  • +
+
+
+

Selects a word, including its right whitespace.

+ +
+

Selects a word, including its right whitespace.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.selectDown()
    • +
    +
      +
    +
  • +
+
+
+

Moves the selection down one row.

+ +
+

Moves the selection down one row.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.selectFileEnd()
    • +
    +
      +
    +
  • +
+
+
+

Moves the selection to the end of the file.

+ +
+

Moves the selection to the end of the file.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.selectFileStart()
    • +
    +
      +
    +
  • +
+
+
+

Moves the selection to the start of the file.

+ +
+

Moves the selection to the start of the file.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.selectLeft()
    • +
    +
      +
    +
  • +
+
+
+

Moves the selection left one column.

+ +
+

Moves the selection left one column.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.selectLine()
    • +
    +
      +
    +
  • +
+
+
+

Selects the entire line.

+ +
+

Selects the entire line.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.selectLineEnd()
    • +
    +
      +
    +
  • +
+
+
+

Moves the selection to the end of the current line.

+ +
+

Moves the selection to the end of the current line.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.selectLineStart()
    • +
    +
      +
    +
  • +
+
+
+

Moves the selection to the beginning of the current line.

+ +
+

Moves the selection to the beginning of the current line.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.selectRight()
    • +
    +
      +
    +
  • +
+
+
+

Moves the selection right one column.

+ +
+

Moves the selection right one column.

+ +
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Moves the selection cursor to the indicated row and column.

+ +
+

Moves the selection cursor to the indicated row and column.

+ +

Arguments

rowNumber

Required. The row to select to

+
columnNumber

Required. The column to select to

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.selectToPosition(Object pos)
    • +
    +
      +
    +
  • +
+
+
+

Moves the selection cursor to the row and column indicated by pos.

+ +
+

Moves the selection cursor to the row and column indicated by pos.

+ +

Arguments

posObject

Required. An object containing the row and column

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.selectUp()
    • +
    +
      +
    +
  • +
+
+
+

Moves the selection up one row.

+ +
+

Moves the selection up one row.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.selectWord()
    • +
    +
      +
    +
  • +
+
+
+

Selects an entire word boundary.

+ +
+

Selects an entire word boundary.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.selectWordLeft()
    • +
    +
      +
    +
  • +
+
+
+

Moves the selection to the first word on the left.

+ +
+

Moves the selection to the first word on the left.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.selectWordRight()
    • +
    +
      +
    +
  • +
+
+
+

Moves the selection to the first word on the right.

+ +
+

Moves the selection to the first word on the right.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.setSelectionAnchor(Number row, Number column)
    • +
    +
      +
    +
  • +
+
+
+

Sets the row and column position of the anchor. This function also emits the 'changeSelection' event.

+ +
+

Sets the row and column position of the anchor. This function also emits the 'changeSelection' event.

+ +

Arguments

rowNumber

Required. The new row

+
columnNumber

Required. The new column

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.setSelectionRange(Range range, Boolean reverse)
    • +
    +
      +
    +
  • +
+
+
+

Sets the selection to the provided range.

+ +
+

Sets the selection to the provided range.

+ +

Arguments

rangeRange

Required. The range of text to select

+
reverseBoolean

Required. Indicates if the range should go backwards (true) or not

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.shiftSelection(Number columns)
    • +
    +
      +
    +
  • +
+
+
+

Shifts the selection up (or down, if isBackwards() is true) the given number of columns.

+ +
+

Shifts the selection up (or down, if isBackwards() is true) the given number of columns.

+ +

Arguments

columnsNumber

Required. The number of columns to shift by

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.splitIntoLines()
    • +
    +
      +
    +
  • +
+
+
+

Splits all the ranges into lines.

+ +
+

Splits all the ranges into lines.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.substractPoint(Range pos)
    • +
    +
      +
    +
  • +
+
+
+

Removes a Range containing pos (if it exists).

+ +
+

Removes a Range containing pos (if it exists).

+ +

Arguments

posRange

Required. The position to remove, as a {row, column} object

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.toggleBlockSelection()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.toOrientedRange()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Selection.toSingleRange()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+ + + + + +
+
diff --git a/node_modules/ace/api/split.html b/node_modules/ace/api/split.html new file mode 100644 index 00000000..fd75edce --- /dev/null +++ b/node_modules/ace/api/split.html @@ -0,0 +1,640 @@ + +
+
+
+
+
+

Split +

+ +
+
+
+
+

Methods

+
+
+
+
+
    +
  • +
      +
    • Split.blur()
    • +
    +
      +
    +
  • +
+
+
+

Blurs the current editor.

+ +
+

Blurs the current editor.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Split.execute()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Split.focus()
    • +
    +
      +
    +
  • +
+
+
+

Focuses the current editor.

+ +
+

Focuses the current editor.

+ +
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+

Arguments

callbackFunction

Required. A callback function to execute

+
scopeString

Required. The default scope for the callback

+

Executes callback on all of the available editors.

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Split.getCurrentEditor() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the current editor.

+ +
+

Returns the current editor.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Split.getEditor(Number idx)
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+

Arguments

idxNumber

Required. The index of the editor you want

+

Returns the editor identified by the index idx.

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Split.getOrientation() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the orientation.

+ +
+

Returns the orientation.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Split.getSplits() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the number of splits.

+ +
+

Returns the number of splits.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Split.hasRedo()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Split.hasUndo()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Split.redo()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Split.reset()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Split.resize()
    • +
    +
      +
    +
  • +
+
+
+

Resizes the editor.

+ +
+

Resizes the editor.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Split.setFontSize(Number size)
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+

Arguments

sizeNumber

Required. The new font size

+

Sets the font size, in pixels, for all the available editors.

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Split.setKeyboardHandler(String keybinding)
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+

Arguments

keybindingString

Required. Sets the keyboard handler for the editor.

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Split.setOrientation(Number orientation)
    • +
    +
      +
    +
  • +
+
+
+

Sets the orientation.

+ +
+

Sets the orientation.

+ +

Arguments

orientationNumber

Required. The new orientation value

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+

Arguments

sessionEditSession

Required. The new edit session

+
idxNumber

Required. The editor's index you're interested in

+

Sets a new EditSession for the indicated editor.

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Split.setSplits()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Split.setTheme(String theme)
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+

Arguments

themeString

Required. The name of the theme to set

+

Sets a theme for each of the available editors.

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Split.undo()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • Split.UndoManagerProxy()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+ + + + + +
+
\ No newline at end of file diff --git a/node_modules/ace/api/token_iterator.html b/node_modules/ace/api/token_iterator.html new file mode 100644 index 00000000..7c025da0 --- /dev/null +++ b/node_modules/ace/api/token_iterator.html @@ -0,0 +1,248 @@ + +
+
+
+
+
+

TokenIterator +

+ +
+
+
+
+

This class provides an essay way to treat the document as a stream of tokens, and provides methods to iterate over these tokens.

+ +
+
+
+

Constructors

+
+
+
+
+ +
+
+

Creates a new token iterator object. The inital token index is set to the provided row and column coordinates.

+ +
+

Creates a new token iterator object. The inital token index is set to the provided row and column coordinates.

+ +

Arguments

sessionEditSession

Required. The session to associate with

+
initialRowNumber

Required. The row to start the tokenizing at

+
initialColumnNumber

Required. The column to start the tokenizing at

+
+
+
+
+
+
+

Methods

+
+
+
+
+
    +
  • +
      +
    • TokenIterator.getCurrentToken() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the current tokenized string.

+ +
+

Returns the current tokenized string.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • TokenIterator.getCurrentTokenColumn() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the current column.

+ +
+

Returns the current column.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • TokenIterator.getCurrentTokenRow() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the current row.

+ +
+

Returns the current row.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • TokenIterator.stepBackward() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Tokenizes all the items from the current point to the row prior in the document.

+ +
+

Tokenizes all the items from the current point to the row prior in the document.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • TokenIterator.stepForward() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Tokenizes all the items from the current point until the next row in the document. If the current point is at the end of the file, this function returns null. Otherwise, it returns the tokenized string.

+ +
+

Tokenizes all the items from the current point until the next row in the document. If the current point is at the end of the file, this function returns null. Otherwise, it returns the tokenized string.

+ +
+
+
+
+
+
+ + + + + +
+
\ No newline at end of file diff --git a/node_modules/ace/api/tokenizer.html b/node_modules/ace/api/tokenizer.html new file mode 100644 index 00000000..b45bd58d --- /dev/null +++ b/node_modules/ace/api/tokenizer.html @@ -0,0 +1,122 @@ + +
+
+
+
+
+

Tokenizer +

+ +
+
+ +

Constructors

+
+
+
+
+ +
+
+

Constructs a new tokenizer based on the given rules and flags.

+ +
+

Constructs a new tokenizer based on the given rules and flags.

+ +

Arguments

rulesObject

Required. The highlighting rules

+
flagString

Required. Any additional regular expression flags to pass (like "i" for case insensitive)

+
+
+
+
+
+
+

Methods

+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Returns an object containing two properties: tokens, which contains all the tokens; and state, the current state.

+ +
+

Returns an object containing two properties: tokens, which contains all the tokens; and state, the current state.

+ +

Arguments

lineObject

Required.

+
startStateObject

Required.

+
+
+
+
+
+
+
+ + + + + +
+
\ No newline at end of file diff --git a/node_modules/ace/api/undomanager.html b/node_modules/ace/api/undomanager.html new file mode 100644 index 00000000..fafd4131 --- /dev/null +++ b/node_modules/ace/api/undomanager.html @@ -0,0 +1,271 @@ + +
+
+
+
+
+

UndoManager +

+ +
+
+
+
+

This object maintains the undo stack for an EditSession.

+ +
+
+
+

Constructors

+
+
+
+
+
    +
  • +
      +
    • new UndoManager()
    • +
    +
      +
    +
  • +
+
+
+

Resets the current undo state and creates a new UndoManager.

+ +
+

Resets the current undo state and creates a new UndoManager.

+ +
+
+
+
+
+

Methods

+
+
+
+
+
    +
  • +
      +
    • UndoManager.execute(Object options)
    • +
    +
      +
    +
  • +
+
+
+

Provides a means for implementing your own undo manager. options has one property, args, an Array, with two elements:

+ +
+

Provides a means for implementing your own undo manager. options has one property, args, an Array, with two elements:

+
    +
  • args[0] is an array of deltas
  • +
  • args[1] is the document to associate with
  • +
+ +

Arguments

optionsObject

Required. Contains additional properties

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • UndoManager.hasRedo() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns true if there are redo operations left to perform.

+ +
+

Returns true if there are redo operations left to perform.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • UndoManager.hasUndo() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns true if there are undo operations left to perform.

+ +
+

Returns true if there are undo operations left to perform.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • UndoManager.redo(Boolean dontSelect)
    • +
    +
      +
    +
  • +
+
+
+

Perform a redo operation on the document, reimplementing the last change.

+ +
+

Perform a redo operation on the document, reimplementing the last change.

+ +

Arguments

dontSelectBoolean

Required. If true, doesn't select the range of where the change occured

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • UndoManager.reset()
    • +
    +
      +
    +
  • +
+
+
+

Destroys the stack of undo and redo redo operations.

+ +
+

Destroys the stack of undo and redo redo operations.

+ +
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Perform an undo operation on the document, reverting the last change.

+ +
+

Perform an undo operation on the document, reverting the last change.

+ +

Arguments

dontSelectBoolean

Required. If true, doesn't select the range of where the change occured

+
+
+
+
+
+
+
+ + + + + +
+
\ No newline at end of file diff --git a/node_modules/ace/api/virtual_renderer.html b/node_modules/ace/api/virtual_renderer.html new file mode 100644 index 00000000..952e6ae6 --- /dev/null +++ b/node_modules/ace/api/virtual_renderer.html @@ -0,0 +1,2190 @@ + +
+
+
+
+
+

VirtualRenderer +

+ +
+
+
+
+

The class that is responsible for drawing everything you see on the screen!

+ +
+
+
+

Constructors

+
+
+
+
+ +
+
+

Constructs a new VirtualRenderer within the container specified, applying the given theme.

+ +
+

Constructs a new VirtualRenderer within the container specified, applying the given theme.

+ +

Arguments

containerDOMElement

Required. The root element of the editor

+
themeString

Required. The starting theme

+
+
+
+
+
+
+

Methods

+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer._loadTheme()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.addGutterDecoration(Object row, Object className)
    • +
    +
      +
    +
  • +
+
+
+

Deprecated; (moved to EditSession)

+ +
+

Deprecated; (moved to EditSession)

+ +

Arguments

rowObject

Required.

+
classNameObject

Required.

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.adjustWrapLimit()
    • +
    +
      +
    +
  • +
+
+
+

Adjusts the wrap limit, which is the number of characters that can fit within the width of the edit area on screen.

+ +
+

Adjusts the wrap limit, which is the number of characters that can fit within the width of the edit area on screen.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.alignCursor()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.animateScrolling()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.destroy()
    • +
    +
      +
    +
  • +
+
+
+

Destroys the text and cursor layers for this renderer.

+ +
+

Destroys the text and cursor layers for this renderer.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.getAnimatedScroll() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns whether an animated scroll happens or not.

+ +
+

Returns whether an animated scroll happens or not.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.getContainerElement() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the root element containing this renderer.

+ +
+

Returns the root element containing this renderer.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.getDisplayIndentGuides()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.getFadeFoldWidgets()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.getFirstFullyVisibleRow() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the index of the first fully visible row. "Fully" here means that the characters in the row are not truncated; that the top and the bottom of the row are on the screen.

+ +
+

Returns the index of the first fully visible row. "Fully" here means that the characters in the row are not truncated; that the top and the bottom of the row are on the screen.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.getFirstVisibleRow() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the index of the first visible row.

+ +
+

Returns the index of the first visible row.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.getHighlightGutterLine()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.getHScrollBarAlwaysVisible() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns whether the horizontal scrollbar is set to be always visible.

+ +
+

Returns whether the horizontal scrollbar is set to be always visible.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.getLastFullyVisibleRow() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the index of the last fully visible row. "Fully" here means that the characters in the row are not truncated; that the top and the bottom of the row are on the screen.

+ +
+

Returns the index of the last fully visible row. "Fully" here means that the characters in the row are not truncated; that the top and the bottom of the row are on the screen.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.getLastVisibleRow() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the index of the last visible row.

+ +
+

Returns the index of the last visible row.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.getMouseEventTarget() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the element that the mouse events are attached to

+ +
+

Returns the element that the mouse events are attached to

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.getPrintMarginColumn() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns whether the print margin column is being shown or not.

+ +
+

Returns whether the print margin column is being shown or not.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.getScrollBottomRow() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the last visible row, regardless of whether it's fully visible or not.

+ +
+

Returns the last visible row, regardless of whether it's fully visible or not.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.getScrollLeft() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the value of the distance between the left of the editor and the leftmost part of the visible content.

+ +
+

Returns the value of the distance between the left of the editor and the leftmost part of the visible content.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.getScrollTop() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the value of the distance between the top of the editor and the topmost part of the visible content.

+ +
+

Returns the value of the distance between the top of the editor and the topmost part of the visible content.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.getScrollTopRow() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the first visible row, regardless of whether it's fully visible or not.

+ +
+

Returns the first visible row, regardless of whether it's fully visible or not.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.getShowGutter() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns true if the gutter is being shown.

+ +
+

Returns true if the gutter is being shown.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.getShowInvisibles() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns whether invisible characters are being shown or not.

+ +
+

Returns whether invisible characters are being shown or not.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.getShowPrintMargin() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns whether the print margin is being shown or not.

+ +
+

Returns whether the print margin is being shown or not.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.getTextAreaContainer() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the element to which the hidden text area is added.

+ +
+

Returns the element to which the hidden text area is added.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.getTheme() +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Returns the path of the current theme.

+ +
+

Returns the path of the current theme.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.hideComposition()
    • +
    +
      +
    +
  • +
+
+
+

Hides the current composition.

+ +
+

Hides the current composition.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.hideCursor()
    • +
    +
      +
    +
  • +
+
+
+

Hides the cursor icon.

+ +
+

Hides the cursor icon.

+ +
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Returns true if you can still scroll by either parameter; in other words, you haven't reached the end of the file or line.

+ +
+

Returns true if you can still scroll by either parameter; in other words, you haven't reached the end of the file or line.

+ +

Arguments

deltaXNumber

Required. The x value to scroll by

+
deltaYNumber

Required. The y value to scroll by

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.onChangeTabSize()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.onGutterResize()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+

Triggers a resize of the editor.

+ +
+

Triggers a resize of the editor.

+ +

Arguments

forceBoolean

Required. If true, recomputes the size, even if the height and width haven't changed

+
gutterWidthNumber

Required. The width of the gutter in pixels

+
widthNumber

Required. The width of the editor in pixels

+
heightNumber

Required. The hiehgt of the editor, in pixels

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.pixelToScreenCoordinates()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.removeGutterDecoration(Object row, Object className)
    • +
    +
      +
    +
  • +
+
+
+

Deprecated; (moved to EditSession)

+ +
+

Deprecated; (moved to EditSession)

+ +

Arguments

rowObject

Required.

+
classNameObject

Required.

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.screenToTextCoordinates()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.scrollBy(Number deltaX, Number deltaY)
    • +
    +
      +
    +
  • +
+
+
+

Scrolls the editor across both x- and y-axes.

+ +
+

Scrolls the editor across both x- and y-axes.

+ +

Arguments

deltaXNumber

Required. The x value to scroll by

+
deltaYNumber

Required. The y value to scroll by

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.scrollCursorIntoView(Object cursor, Object offset)
    • +
    +
      +
    +
  • +
+
+
+

Scrolls the cursor into the first visibile area of the editor

+ +
+

Scrolls the cursor into the first visibile area of the editor

+ +

Arguments

cursorObject

Required.

+
offsetObject

Required.

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.scrollSelectionIntoView()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+

Gracefully scrolls the editor to the row indicated.

+ +
+

Gracefully scrolls the editor to the row indicated.

+ +

Arguments

lineNumber

Required. A line number

+
centerBoolean

Required. If true, centers the editor the to indicated line

+
animateBoolean

Required. If true animates scrolling

+
callbackFunction

Required. Function to be called after the animation has finished

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.scrollToRow(Number row)
    • +
    +
      +
    +
  • +
+
+
+

Gracefully scrolls from the top of the editor to the row indicated.

+ +
+

Gracefully scrolls from the top of the editor to the row indicated.

+ +

Arguments

rowNumber

Required. A row id

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.scrollToX(Number scrollLeft) +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Scrolls the editor across the x-axis to the pixel indicated.

+ +
+

Scrolls the editor across the x-axis to the pixel indicated.

+ +

Arguments

scrollLeftNumber

Required. The position to scroll to

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.scrollToY(Number scrollTop) +
    • + +
    • +
    +
      +
    +
  • +
+
+
+

Scrolls the editor to the y pixel indicated.

+ +
+

Scrolls the editor to the y pixel indicated.

+ +

Arguments

scrollTopNumber

Required. The position to scroll to

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.setAnimatedScroll(Boolean shouldAnimate)
    • +
    +
      +
    +
  • +
+
+
+

Identifies whether you want to have an animated scroll or not.

+ +
+

Identifies whether you want to have an animated scroll or not.

+ +

Arguments

shouldAnimateBoolean

Required. Set to true to show animated scrolls

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.setAnnotations(Array annotations)
    • +
    +
      +
    +
  • +
+
+
+

Sets annotations for the gutter.

+ +
+

Sets annotations for the gutter.

+ +

Arguments

annotationsArray

Required. An array containing annotations

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.setCompositionText(String text)
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+

Arguments

textString

Required. A string of text to use

+

Sets the inner text of the current composition to text.

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.setDisplayIndentGuides()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.setFadeFoldWidgets()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.setHighlightGutterLine()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.setHScrollBarAlwaysVisible(Boolean alwaysVisible)
    • +
    +
      +
    +
  • +
+
+
+

Identifies whether you want to show the horizontal scrollbar or not.

+ +
+

Identifies whether you want to show the horizontal scrollbar or not.

+ +

Arguments

alwaysVisibleBoolean

Required. Set to true to make the horizontal scroll bar visible

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.setPadding(Number padding)
    • +
    +
      +
    +
  • +
+
+
+

Sets the padding for all the layers.

+ +
+

Sets the padding for all the layers.

+ +

Arguments

paddingNumber

Required. A new padding value (in pixels)

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.setPrintMarginColumn(Boolean showPrintMargin)
    • +
    +
      +
    +
  • +
+
+
+

Identifies whether you want to show the print margin column or not.

+ +
+

Identifies whether you want to show the print margin column or not.

+ +

Arguments

showPrintMarginBoolean

Required. Set to true to show the print margin column

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.setSession(Object session)
    • +
    +
      +
    +
  • +
+
+
+

Associates the renderer with an EditSession.

+ +
+

Associates the renderer with an EditSession.

+ +

Arguments

sessionObject

Required.

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.setShowGutter(Boolean show)
    • +
    +
      +
    +
  • +
+
+
+

Identifies whether you want to show the gutter or not.

+ +
+

Identifies whether you want to show the gutter or not.

+ +

Arguments

showBoolean

Required. Set to true to show the gutter

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.setShowInvisibles(Boolean showInvisibles)
    • +
    +
      +
    +
  • +
+
+
+

Identifies whether you want to show invisible characters or not.

+ +
+

Identifies whether you want to show invisible characters or not.

+ +

Arguments

showInvisiblesBoolean

Required. Set to true to show invisibles

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.setShowPrintMargin(Boolean showPrintMargin)
    • +
    +
      +
    +
  • +
+
+
+

Identifies whether you want to show the print margin or not.

+ +
+

Identifies whether you want to show the print margin or not.

+ +

Arguments

showPrintMarginBoolean

Required. Set to true to show the print margin

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.setStyle()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.setTheme(String theme)
    • +
    +
      +
    +
  • +
+
+
+

Sets a new theme for the editor. theme should exist, and be a directory path, like ace/theme/textmate.

+ +
+

Sets a new theme for the editor. theme should exist, and be a directory path, like ace/theme/textmate.

+ +

Arguments

themeString

Required. The path to a theme

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.showCursor()
    • +
    +
      +
    +
  • +
+
+
+

Shows the cursor icon.

+ +
+

Shows the cursor icon.

+ +
+
+
+
+
+
+
+
+
+
    +
  • + +
      +
    +
  • +
+
+
+

Returns an object containing the pageX and pageY coordinates of the document position.

+ +
+

Returns an object containing the pageX and pageY coordinates of the document position.

+ +

Arguments

rowNumber

Required. The document row position

+
columnNumber

Required. The document column position

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.unsetStyle(String style)
    • +
    +
      +
    +
  • +
+
+
+

Removes the class style from the editor.

+ +
+

Removes the class style from the editor.

+ +

Arguments

styleString

Required. A class name

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.updateBackMarkers()
    • +
    +
      +
    +
  • +
+
+
+

Schedules an update to all the back markers in the document.

+ +
+

Schedules an update to all the back markers in the document.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.updateBreakpoints(Object rows)
    • +
    +
      +
    +
  • +
+
+
+

Redraw breakpoints.

+ +
+

Redraw breakpoints.

+ +

Arguments

rowsObject

Required.

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.updateCharacterSize()
    • +
    +
      +
    • Undocumented
    • +
    +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.updateCursor()
    • +
    +
      +
    +
  • +
+
+
+

Updates the cursor icon.

+ +
+

Updates the cursor icon.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.updateFontSize()
    • +
    +
      +
    +
  • +
+
+
+

Updates the font size.

+ +
+

Updates the font size.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.updateFrontMarkers()
    • +
    +
      +
    +
  • +
+
+
+

Schedules an update to all the front markers in the document.

+ +
+

Schedules an update to all the front markers in the document.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.updateFull(Boolean force)
    • +
    +
      +
    +
  • +
+
+
+

Triggers a full update of all the layers, for all the rows.

+ +
+

Triggers a full update of all the layers, for all the rows.

+ +

Arguments

forceBoolean

Required. If true, forces the changes through

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.updateLines(Number firstRow, Number lastRow)
    • +
    +
      +
    +
  • +
+
+
+

Triggers a partial update of the text, from the range given by the two parameters.

+ +
+

Triggers a partial update of the text, from the range given by the two parameters.

+ +

Arguments

firstRowNumber

Required. The first row to update

+
lastRowNumber

Required. The last row to update

+
+
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.updateText()
    • +
    +
      +
    +
  • +
+
+
+

Triggers a full update of the text, for all the rows.

+ +
+

Triggers a full update of the text, for all the rows.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.visualizeBlur()
    • +
    +
      +
    +
  • +
+
+
+

Blurs the current container.

+ +
+

Blurs the current container.

+ +
+
+
+
+
+
+
+
+
+
    +
  • +
      +
    • VirtualRenderer.visualizeFocus()
    • +
    +
      +
    +
  • +
+
+
+

Focuses the current container.

+ +
+

Focuses the current container.

+ +
+
+
+
+
+
+ + + + + +
+
\ No newline at end of file diff --git a/node_modules/ace/build_support/bookmarklet.html b/node_modules/ace/build_support/bookmarklet.html new file mode 100644 index 00000000..88355f78 --- /dev/null +++ b/node_modules/ace/build_support/bookmarklet.html @@ -0,0 +1,112 @@ + + + + + + + Ace Bookmarklet Builder + + + +
+ +
+
+
+ SourceUrl:
+
+
+ +
+
+
+
+

Ace Bookmarklet Builder

+ +

+ WARNING: Currently, this is only supported in non IE browsers. +

+ +

How to use it:

+
    +
  • Select the options as you want them to be by default.
  • +
  • Enter the "SourceUrl". This has to be the URL pointing to build/textarea/src/ (you can leave the default to server the scripts from GitHub).
  • +
  • Click the "Build Link" button to generate your custom Ace Bookmarklet.
  • +
  • Drag the generated link to your toolbar or store it somewhere else.
  • +
  • Go to a page with a textarea element and click the bookmarklet - wait a little bit till the files are loaded.
  • +
  • Click three times on the textarea you want to replace - Ace will replace it.
  • +
  • To change settings, just click the red icon in the bottom right corner.
  • +
+
+
+
+ + + + + diff --git a/node_modules/ace/build_support/editor.html b/node_modules/ace/build_support/editor.html new file mode 100644 index 00000000..1d972cf9 --- /dev/null +++ b/node_modules/ace/build_support/editor.html @@ -0,0 +1,39 @@ + + + + + + Editor + + + + +
function foo(items) {
+    var i;
+    for (i = 0; i < items.length; i++) {
+        alert("Ace Rocks " + items[i]);
+    }
+}
+ + + + + + diff --git a/node_modules/ace/build_support/mini_require.js b/node_modules/ace/build_support/mini_require.js new file mode 100644 index 00000000..88937f35 --- /dev/null +++ b/node_modules/ace/build_support/mini_require.js @@ -0,0 +1,187 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +/** + * Define a module along with a payload + * @param module a name for the payload + * @param payload a function to call with (require, exports, module) params + */ + +(function() { + +var ACE_NAMESPACE = ""; + +var global = (function() { + return this; +})(); + + +if (!ACE_NAMESPACE && typeof requirejs !== "undefined") + return; + + +var _define = function(module, deps, payload) { + if (typeof module !== 'string') { + if (_define.original) + _define.original.apply(window, arguments); + else { + console.error('dropping module because define wasn\'t a string.'); + console.trace(); + } + return; + } + + if (arguments.length == 2) + payload = deps; + + if (!_define.modules) { + _define.modules = {}; + _define.payloads = {}; + } + + _define.payloads[module] = payload; + _define.modules[module] = null; +}; + +/** + * Get at functionality define()ed using the function above + */ +var _require = function(parentId, module, callback) { + if (Object.prototype.toString.call(module) === "[object Array]") { + var params = []; + for (var i = 0, l = module.length; i < l; ++i) { + var dep = lookup(parentId, module[i]); + if (!dep && _require.original) + return _require.original.apply(window, arguments); + params.push(dep); + } + if (callback) { + callback.apply(null, params); + } + } + else if (typeof module === 'string') { + var payload = lookup(parentId, module); + if (!payload && _require.original) + return _require.original.apply(window, arguments); + + if (callback) { + callback(); + } + + return payload; + } + else { + if (_require.original) + return _require.original.apply(window, arguments); + } +}; + +var normalizeModule = function(parentId, moduleName) { + // normalize plugin requires + if (moduleName.indexOf("!") !== -1) { + var chunks = moduleName.split("!"); + return normalizeModule(parentId, chunks[0]) + "!" + normalizeModule(parentId, chunks[1]); + } + // normalize relative requires + if (moduleName.charAt(0) == ".") { + var base = parentId.split("/").slice(0, -1).join("/"); + moduleName = base + "/" + moduleName; + + while(moduleName.indexOf(".") !== -1 && previous != moduleName) { + var previous = moduleName; + moduleName = moduleName.replace(/\/\.\//, "/").replace(/[^\/]+\/\.\.\//, ""); + } + } + + return moduleName; +}; + +/** + * Internal function to lookup moduleNames and resolve them by calling the + * definition function if needed. + */ +var lookup = function(parentId, moduleName) { + + moduleName = normalizeModule(parentId, moduleName); + + var module = _define.modules[moduleName]; + if (!module) { + module = _define.payloads[moduleName]; + if (typeof module === 'function') { + var exports = {}; + var mod = { + id: moduleName, + uri: '', + exports: exports, + packaged: true + }; + + var req = function(module, callback) { + return _require(moduleName, module, callback); + }; + + var returnValue = module(req, exports, mod); + exports = returnValue || mod.exports; + _define.modules[moduleName] = exports; + delete _define.payloads[moduleName]; + } + module = _define.modules[moduleName] = exports || module; + } + return module; +}; + +function exportAce(ns) { + var require = function(module, callback) { + return _require("", module, callback); + }; + + var root = global; + if (ns) { + if (!global[ns]) + global[ns] = {}; + root = global[ns]; + } + + if (!root.define || !root.define.packaged) { + _define.original = root.define; + root.define = _define; + root.define.packaged = true; + } + + if (!root.require || !root.require.packaged) { + _require.original = root.require; + root.require = require; + root.require.packaged = true; + } +} + +exportAce(ACE_NAMESPACE); + +})(); diff --git a/node_modules/ace/build_support/style.css b/node_modules/ace/build_support/style.css new file mode 100644 index 00000000..3ca603b1 --- /dev/null +++ b/node_modules/ace/build_support/style.css @@ -0,0 +1,226 @@ +@import url(//fonts.googleapis.com/css?family=Droid+Sans+Mono); + +body { + margin:0; + padding:0; + background-color:#e6f5fc; + +} + +H2, H3, H4 { + font-family:Trebuchet MS; + font-weight:bold; + margin:0; + padding:0; +} + +H2 { + font-size:28px; + color:#263842; + padding-bottom:6px; +} + +H3 { + font-family:Trebuchet MS; + font-weight:bold; + font-size:22px; + color:#253741; + margin-top:43px; + margin-bottom:8px; +} + +H4 { + font-family:Trebuchet MS; + font-weight:bold; + font-size:21px; + color:#222222; + margin-bottom:4px; +} + +P { + padding:13px 0; + margin:0; + line-height:22px; +} + +UL{ + line-height : 22px; +} + +PRE{ + background : #333; + color : white; + padding : 10px; +} + +#header { + height : 227px; + position:relative; + overflow:hidden; + background: url(images/background.png) repeat-x 0 0; + border-bottom:1px solid #c9e8fa; +} + +#header .content .signature { + font-family:Trebuchet MS; + font-size:11px; + color:#ebe4d6; + position:absolute; + bottom:5px; + right:42px; + letter-spacing : 1px; +} + +.content { + width:970px; + position:relative; + margin:0 auto; +} + +#header .content { + height:184px; + margin-top:22px; +} + +#header .content .logo { + width : 282px; + height : 184px; + background:url(images/logo.png) no-repeat 0 0; + position:absolute; + top:0; + left:0; +} + +#header .content .title { + width : 605px; + height : 58px; + background:url(images/ace.png) no-repeat 0 0; + position:absolute; + top:98px; + left:329px; +} + +#wrapper { + background:url(images/body_background.png) repeat-x 0 0; + min-height:250px; +} + +#wrapper .content { + font-family:Arial; + font-size:14px; + color:#222222; + width:1000px; +} + +#wrapper .content .column1 { + position:relative; + float:left; + width:315px; + margin-right:31px; +} + +#wrapper .content .column2 { + position:relative; + overflow:hidden; + float:left; + width:600px; + padding-top:47px; +} + +.fork_on_github { + width:310px; + height:80px; + background:url(images/fork_on_github.png) no-repeat 0 0; + position:relative; + overflow:hidden; + margin-top:49px; + cursor:pointer; +} + +.fork_on_github:hover { + background-position:0 -80px; +} + +.divider { + height:3px; + background-color:#bedaea; + margin-bottom:3px; +} + +.menu { + padding:23px 0 0 24px; +} + +UL.content-list { + padding:15px; + margin:0; +} + +UL.menu-list { + padding:0; + margin:0 0 20px 0; + list-style-type:none; + line-height : 16px; +} + +UL.menu-list LI { + color:#2557b4; + font-family:Trebuchet MS; + font-size:14px; + padding:7px 0; + border-bottom:1px dotted #d6e2e7; +} + +UL.menu-list LI:last-child { + border-bottom:0; +} + +A { + color:#2557b4; + text-decoration:none; +} + +A:hover { + text-decoration:underline; +} + +P#first{ + background : rgba(255,255,255,0.5); + padding : 20px; + font-size : 16px; + line-height : 24px; + margin : 0 0 20px 0; +} + +#footer { + height:40px; + position:relative; + overflow:hidden; + background:url(images/bottombar.png) repeat-x 0 0; + position:relative; + margin-top:40px; +} + +UL.menu-footer { + padding:0; + margin:8px 11px 0 0; + list-style-type:none; + float:right; +} + +UL.menu-footer LI { + color:white; + font-family:Arial; + font-size:12px; + display:inline-block; + margin:0 1px; +} + +UL.menu-footer LI A { + color:#8dd0ff; + text-decoration:none; +} + +UL.menu-footer LI A:hover { + text-decoration:underline; +} diff --git a/node_modules/ace/demo/autocompletion.html b/node_modules/ace/demo/autocompletion.html new file mode 100644 index 00000000..e0de5ef3 --- /dev/null +++ b/node_modules/ace/demo/autocompletion.html @@ -0,0 +1,45 @@ + + + + + ACE Autocompletion demo + + + + +

+
+
+
+
+
+
+
+
+
+
diff --git a/node_modules/ace/demo/autoresize.html b/node_modules/ace/demo/autoresize.html
new file mode 100644
index 00000000..73a87599
--- /dev/null
+++ b/node_modules/ace/demo/autoresize.html
@@ -0,0 +1,60 @@
+
+
+
+  
+  
+  Editor
+  
+
+
+
autoresizing editor
+
+
minHeight = 2 lines
+
+

+
+
+
+
+
+
+
+
diff --git a/node_modules/ace/demo/chromevox.html b/node_modules/ace/demo/chromevox.html
new file mode 100644
index 00000000..9aa65bae
--- /dev/null
+++ b/node_modules/ace/demo/chromevox.html
@@ -0,0 +1,39 @@
+
+
+
+  
+  ACE ChromeVox demo
+  
+
+
+
+

+
+
+
+
+
+
+
+
+
+
diff --git a/node_modules/ace/demo/emmet.html b/node_modules/ace/demo/emmet.html
new file mode 100644
index 00000000..122085d9
--- /dev/null
+++ b/node_modules/ace/demo/emmet.html
@@ -0,0 +1,43 @@
+
+
+
+  
+  ACE Emmet demo
+  
+
+
+
+

+
+
+
+
+
+
+
+
+
+
diff --git a/node_modules/ace/demo/ie7.html b/node_modules/ace/demo/ie7.html
new file mode 100644
index 00000000..f5db8667
--- /dev/null
+++ b/node_modules/ace/demo/ie7.html
@@ -0,0 +1,44 @@
+
+
+
+  
+  
+  ACE Editor StatusBar Demo
+  
+
+
+
+
+require("ace/ext/old_ie");
+// now ace will work even on ie7!
+var editor = ace.edit("editor");
+
+ + + + + + + + diff --git a/node_modules/ace/demo/keyboard_shortcuts.html b/node_modules/ace/demo/keyboard_shortcuts.html new file mode 100644 index 00000000..3d01f559 --- /dev/null +++ b/node_modules/ace/demo/keyboard_shortcuts.html @@ -0,0 +1,51 @@ + + + + + + Editor + + + + +

+    
+
+
+
+
+
+
diff --git a/node_modules/ace/demo/kitchen-sink/demo.js b/node_modules/ace/demo/kitchen-sink/demo.js
new file mode 100644
index 00000000..c7beb3d0
--- /dev/null
+++ b/node_modules/ace/demo/kitchen-sink/demo.js
@@ -0,0 +1,585 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Distributed under the BSD license:
+ *
+ * Copyright (c) 2010, Ajax.org B.V.
+ * All rights reserved.
+ *
+ * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+
+define(function(require, exports, module) {
+"use strict";
+
+require("ace/lib/fixoldbrowsers");
+
+require("ace/multi_select");
+require("ace/ext/spellcheck");
+require("./inline_editor");
+require("./dev_util");
+require("./file_drop");
+
+var config = require("ace/config");
+config.init();
+var env = {};
+
+var dom = require("ace/lib/dom");
+var net = require("ace/lib/net");
+var lang = require("ace/lib/lang");
+var useragent = require("ace/lib/useragent");
+
+var event = require("ace/lib/event");
+var theme = require("ace/theme/textmate");
+var EditSession = require("ace/edit_session").EditSession;
+var UndoManager = require("ace/undomanager").UndoManager;
+
+var HashHandler = require("ace/keyboard/hash_handler").HashHandler;
+
+var Renderer = require("ace/virtual_renderer").VirtualRenderer;
+var Editor = require("ace/editor").Editor;
+
+var whitespace = require("ace/ext/whitespace");
+
+
+
+var doclist = require("./doclist");
+var modelist = require("ace/ext/modelist");
+var themelist = require("ace/ext/themelist");
+var layout = require("./layout");
+var TokenTooltip = require("./token_tooltip").TokenTooltip;
+var util = require("./util");
+var saveOption = util.saveOption;
+var fillDropdown = util.fillDropdown;
+var bindCheckbox = util.bindCheckbox;
+var bindDropdown = util.bindDropdown;
+
+var ElasticTabstopsLite = require("ace/ext/elastic_tabstops_lite").ElasticTabstopsLite;
+
+var IncrementalSearch = require("ace/incremental_search").IncrementalSearch;
+
+
+var workerModule = require("ace/worker/worker_client");
+if (location.href.indexOf("noworker") !== -1) {
+    workerModule.WorkerClient = workerModule.UIWorkerClient;
+}
+
+/*********** create editor ***************************/
+var container = document.getElementById("editor-container");
+
+// Splitting.
+var Split = require("ace/split").Split;
+var split = new Split(container, theme, 1);
+env.editor = split.getEditor(0);
+split.on("focus", function(editor) {
+    env.editor = editor;
+    updateUIEditorOptions();
+});
+env.split = split;
+window.env = env;
+
+
+var consoleEl = dom.createElement("div");
+container.parentNode.appendChild(consoleEl);
+consoleEl.style.cssText = "position:fixed; bottom:1px; right:0;\
+border:1px solid #baf; z-index:100";
+
+var cmdLine = new layout.singleLineEditor(consoleEl);
+cmdLine.editor = env.editor;
+env.editor.cmdLine = cmdLine;
+
+env.editor.showCommandLine = function(val) {
+    this.cmdLine.focus();
+    if (typeof val == "string")
+        this.cmdLine.setValue(val, 1);
+};
+
+/**
+ * This demonstrates how you can define commands and bind shortcuts to them.
+ */
+env.editor.commands.addCommands([{
+    name: "gotoline",
+    bindKey: {win: "Ctrl-L", mac: "Command-L"},
+    exec: function(editor, line) {
+        if (typeof line == "object") {
+            var arg = this.name + " " + editor.getCursorPosition().row;
+            editor.cmdLine.setValue(arg, 1);
+            editor.cmdLine.focus();
+            return;
+        }
+        line = parseInt(line, 10);
+        if (!isNaN(line))
+            editor.gotoLine(line);
+    },
+    readOnly: true
+}, {
+    name: "snippet",
+    bindKey: {win: "Alt-C", mac: "Command-Alt-C"},
+    exec: function(editor, needle) {
+        if (typeof needle == "object") {
+            editor.cmdLine.setValue("snippet ", 1);
+            editor.cmdLine.focus();
+            return;
+        }
+        var s = snippetManager.getSnippetByName(needle, editor);
+        if (s)
+            snippetManager.insertSnippet(editor, s.content);
+    },
+    readOnly: true
+}, {
+    name: "focusCommandLine",
+    bindKey: "shift-esc|ctrl-`",
+    exec: function(editor, needle) { editor.cmdLine.focus(); },
+    readOnly: true
+}, {
+    name: "nextFile",
+    bindKey: "Ctrl-tab",
+    exec: function(editor) { doclist.cycleOpen(editor, 1); },
+    readOnly: true
+}, {
+    name: "previousFile",
+    bindKey: "Ctrl-shift-tab",
+    exec: function(editor) { doclist.cycleOpen(editor, -1); },
+    readOnly: true
+}, {
+    name: "execute",
+    bindKey: "ctrl+enter",
+    exec: function(editor) {
+        try {
+            var r = window.eval(editor.getCopyText() || editor.getValue());
+        } catch(e) {
+            r = e;
+        }
+        editor.cmdLine.setValue(r + "");
+    },
+    readOnly: true
+}, {
+    name: "showKeyboardShortcuts",
+    bindKey: {win: "Ctrl-Alt-h", mac: "Command-Alt-h"},
+    exec: function(editor) {
+        config.loadModule("ace/ext/keybinding_menu", function(module) {
+            module.init(editor);
+            editor.showKeyboardShortcuts();
+        });
+    }
+}, {
+    name: "increaseFontSize",
+    bindKey: "Ctrl-=|Ctrl-+",
+    exec: function(editor) {
+        var size = parseInt(editor.getFontSize(), 10) || 12;
+        editor.setFontSize(size + 1);
+    }
+}, {
+    name: "decreaseFontSize",
+    bindKey: "Ctrl+-|Ctrl-_",
+    exec: function(editor) {
+        var size = parseInt(editor.getFontSize(), 10) || 12;
+        editor.setFontSize(Math.max(size - 1 || 1));
+    }
+}, {
+    name: "resetFontSize",
+    bindKey: "Ctrl+0|Ctrl-Numpad0",
+    exec: function(editor) {
+        editor.setFontSize(12);
+    }
+}]);
+
+
+env.editor.commands.addCommands(whitespace.commands);
+
+cmdLine.commands.bindKeys({
+    "Shift-Return|Ctrl-Return|Alt-Return": function(cmdLine) { cmdLine.insert("\n"); },
+    "Esc|Shift-Esc": function(cmdLine){ cmdLine.editor.focus(); },
+    "Return": function(cmdLine){
+        var command = cmdLine.getValue().split(/\s+/);
+        var editor = cmdLine.editor;
+        editor.commands.exec(command[0], editor, command[1]);
+        editor.focus();
+    }
+});
+
+cmdLine.commands.removeCommands(["find", "gotoline", "findall", "replace", "replaceall"]);
+
+var commands = env.editor.commands;
+commands.addCommand({
+    name: "save",
+    bindKey: {win: "Ctrl-S", mac: "Command-S"},
+    exec: function(arg) {
+        var session = env.editor.session;
+        var name = session.name.match(/[^\/]+$/);
+        localStorage.setItem(
+            "saved_file:" + name,
+            session.getValue()
+        );
+        env.editor.cmdLine.setValue("saved "+ name);
+    }
+});
+
+commands.addCommand({
+    name: "load",
+    bindKey: {win: "Ctrl-O", mac: "Command-O"},
+    exec: function(arg) {
+        var session = env.editor.session;
+        var name = session.name.match(/[^\/]+$/);
+        var value = localStorage.getItem("saved_file:" + name);
+        if (typeof value == "string") {
+            session.setValue(value);
+            env.editor.cmdLine.setValue("loaded "+ name);
+        } else {
+            env.editor.cmdLine.setValue("no previuos value saved for "+ name);
+        }
+    }
+});
+
+var keybindings = {
+    ace: null, // Null = use "default" keymapping
+    vim: require("ace/keyboard/vim").handler,
+    emacs: "ace/keyboard/emacs",
+    // This is a way to define simple keyboard remappings
+    custom: new HashHandler({
+        "gotoright":      "Tab",
+        "indent":         "]",
+        "outdent":        "[",
+        "gotolinestart":  "^",
+        "gotolineend":    "$"
+    })
+};
+
+
+
+/*********** manage layout ***************************/
+var consoleHeight = 20;
+function onResize() {
+    var left = env.split.$container.offsetLeft;
+    var width = document.documentElement.clientWidth - left;
+    container.style.width = width + "px";
+    container.style.height = document.documentElement.clientHeight - consoleHeight + "px";
+    env.split.resize();
+
+    consoleEl.style.width = width + "px";
+    cmdLine.resize();
+}
+
+window.onresize = onResize;
+onResize();
+
+/*********** options panel ***************************/
+var docEl = document.getElementById("doc");
+var modeEl = document.getElementById("mode");
+var wrapModeEl = document.getElementById("soft_wrap");
+var themeEl = document.getElementById("theme");
+var foldingEl = document.getElementById("folding");
+var selectStyleEl = document.getElementById("select_style");
+var highlightActiveEl = document.getElementById("highlight_active");
+var showHiddenEl = document.getElementById("show_hidden");
+var showGutterEl = document.getElementById("show_gutter");
+var showPrintMarginEl = document.getElementById("show_print_margin");
+var highlightSelectedWordE = document.getElementById("highlight_selected_word");
+var showHScrollEl = document.getElementById("show_hscroll");
+var showVScrollEl = document.getElementById("show_vscroll");
+var animateScrollEl = document.getElementById("animate_scroll");
+var softTabEl = document.getElementById("soft_tab");
+var behavioursEl = document.getElementById("enable_behaviours");
+
+fillDropdown(docEl, doclist.all);
+
+fillDropdown(modeEl, modelist.modes);
+var modesByName = modelist.modesByName;
+bindDropdown("mode", function(value) {
+    env.editor.session.setMode(modesByName[value].mode || modesByName.text.mode);
+    env.editor.session.modeName = value;
+});
+
+doclist.history = doclist.docs.map(function(doc) {
+    return doc.name;
+});
+doclist.history.index = 0;
+doclist.cycleOpen = function(editor, dir) {
+    var h = this.history;
+    h.index += dir;
+    if (h.index >= h.length)
+        h.index = 0;
+    else if (h.index <= 0)
+        h.index = h.length - 1;
+    var s = h[h.index];
+    docEl.value = s;
+    docEl.onchange();
+};
+doclist.addToHistory = function(name) {
+    var h = this.history;
+    var i = h.indexOf(name);
+    if (i != h.index) {
+        if (i != -1)
+            h.splice(i, 1);
+        h.index = h.push(name);
+    }
+};
+
+bindDropdown("doc", function(name) {
+    doclist.loadDoc(name, function(session) {
+        if (!session)
+            return;
+        doclist.addToHistory(session.name);
+        session = env.split.setSession(session);
+        whitespace.detectIndentation(session);
+        updateUIEditorOptions();
+        env.editor.focus();
+    });
+});
+
+
+function updateUIEditorOptions() {
+    var editor = env.editor;
+    var session = editor.session;
+
+    session.setFoldStyle(foldingEl.value);
+
+    saveOption(docEl, session.name);
+    saveOption(modeEl, session.modeName || "text");
+    saveOption(wrapModeEl, session.getUseWrapMode() ? session.getWrapLimitRange().min || "free" : "off");
+
+    saveOption(selectStyleEl, editor.getSelectionStyle() == "line");
+    saveOption(themeEl, editor.getTheme());
+    saveOption(highlightActiveEl, editor.getHighlightActiveLine());
+    saveOption(showHiddenEl, editor.getShowInvisibles());
+    saveOption(showGutterEl, editor.renderer.getShowGutter());
+    saveOption(showPrintMarginEl, editor.renderer.getShowPrintMargin());
+    saveOption(highlightSelectedWordE, editor.getHighlightSelectedWord());
+    saveOption(showHScrollEl, editor.renderer.getHScrollBarAlwaysVisible());
+    saveOption(animateScrollEl, editor.getAnimatedScroll());
+    saveOption(softTabEl, session.getUseSoftTabs());
+    saveOption(behavioursEl, editor.getBehavioursEnabled());
+}
+
+themelist.themes.forEach(function(x){ x.value = x.theme });
+fillDropdown(themeEl, {
+    Bright: themelist.themes.filter(function(x){return !x.isDark}),
+    Dark: themelist.themes.filter(function(x){return x.isDark}),
+});
+
+event.addListener(themeEl, "mouseover", function(e){
+    themeEl.desiredValue = e.target.value;
+    if (!themeEl.$timer)
+        themeEl.$timer = setTimeout(themeEl.updateTheme);
+});
+
+event.addListener(themeEl, "mouseout", function(e){
+    themeEl.desiredValue = null;
+    if (!themeEl.$timer)
+        themeEl.$timer = setTimeout(themeEl.updateTheme, 20);
+});
+
+themeEl.updateTheme = function(){
+    env.split.setTheme((themeEl.desiredValue || themeEl.selectedValue));
+    themeEl.$timer = null;
+};
+
+bindDropdown("theme", function(value) {
+    if (!value)
+        return;
+    env.editor.setTheme(value);
+    themeEl.selectedValue = value;
+});
+
+bindDropdown("keybinding", function(value) {
+    env.editor.setKeyboardHandler(keybindings[value]);
+});
+
+bindDropdown("fontsize", function(value) {
+    env.split.setFontSize(value);
+});
+
+bindDropdown("folding", function(value) {
+    env.editor.session.setFoldStyle(value);
+    env.editor.setShowFoldWidgets(value !== "manual");
+});
+
+bindDropdown("soft_wrap", function(value) {
+    env.editor.setOption("wrap", value);
+});
+
+bindCheckbox("select_style", function(checked) {
+    env.editor.setOption("selectionStyle", checked ? "line" : "text");
+});
+
+bindCheckbox("highlight_active", function(checked) {
+    env.editor.setHighlightActiveLine(checked);
+});
+
+bindCheckbox("show_hidden", function(checked) {
+    env.editor.setShowInvisibles(checked);
+});
+
+bindCheckbox("display_indent_guides", function(checked) {
+    env.editor.setDisplayIndentGuides(checked);
+});
+
+bindCheckbox("show_gutter", function(checked) {
+    env.editor.renderer.setShowGutter(checked);
+});
+
+bindCheckbox("show_print_margin", function(checked) {
+    env.editor.renderer.setShowPrintMargin(checked);
+});
+
+bindCheckbox("highlight_selected_word", function(checked) {
+    env.editor.setHighlightSelectedWord(checked);
+});
+
+bindCheckbox("show_hscroll", function(checked) {
+    env.editor.setOption("hScrollBarAlwaysVisible", checked);
+});
+
+bindCheckbox("show_vscroll", function(checked) {
+    env.editor.setOption("vScrollBarAlwaysVisible", checked);
+});
+
+bindCheckbox("animate_scroll", function(checked) {
+    env.editor.setAnimatedScroll(checked);
+});
+
+bindCheckbox("soft_tab", function(checked) {
+    env.editor.session.setUseSoftTabs(checked);
+});
+
+bindCheckbox("enable_behaviours", function(checked) {
+    env.editor.setBehavioursEnabled(checked);
+});
+
+bindCheckbox("fade_fold_widgets", function(checked) {
+    env.editor.setFadeFoldWidgets(checked);
+});
+bindCheckbox("read_only", function(checked) {
+    env.editor.setReadOnly(checked);
+});
+bindCheckbox("scrollPastEnd", function(checked) {
+    env.editor.setOption("scrollPastEnd", checked);
+});
+
+bindDropdown("split", function(value) {
+    var sp = env.split;
+    if (value == "none") {
+        sp.setSplits(1);
+    } else {
+        var newEditor = (sp.getSplits() == 1);
+        sp.setOrientation(value == "below" ? sp.BELOW : sp.BESIDE);
+        sp.setSplits(2);
+
+        if (newEditor) {
+            var session = sp.getEditor(0).session;
+            var newSession = sp.setSession(session, 1);
+            newSession.name = session.name;
+        }
+    }
+});
+
+
+bindCheckbox("elastic_tabstops", function(checked) {
+    env.editor.setOption("useElasticTabstops", checked);
+});
+
+var iSearchCheckbox = bindCheckbox("isearch", function(checked) {
+    env.editor.setOption("useIncrementalSearch", checked);
+});
+
+env.editor.addEventListener('incrementalSearchSettingChanged', function(event) {
+    iSearchCheckbox.checked = event.isEnabled;
+});
+
+
+function synchroniseScrolling() {
+    var s1 = env.split.$editors[0].session;
+    var s2 = env.split.$editors[1].session;
+    s1.on('changeScrollTop', function(pos) {s2.setScrollTop(pos)});
+    s2.on('changeScrollTop', function(pos) {s1.setScrollTop(pos)});
+    s1.on('changeScrollLeft', function(pos) {s2.setScrollLeft(pos)});
+    s2.on('changeScrollLeft', function(pos) {s1.setScrollLeft(pos)});
+}
+
+bindCheckbox("highlight_token", function(checked) {
+    var editor = env.editor;
+    if (editor.tokenTooltip && !checked) {
+        editor.tokenTooltip.destroy();
+        delete editor.tokenTooltip;
+    } else if (checked) {
+        editor.tokenTooltip = new TokenTooltip(editor);
+    }
+});
+
+var StatusBar = require("ace/ext/statusbar").StatusBar;
+new StatusBar(env.editor, cmdLine.container);
+
+
+var Emmet = require("ace/ext/emmet");
+net.loadScript("https://nightwing.github.io/emmet-core/emmet.js", function() {
+    Emmet.setCore(window.emmet);
+    env.editor.setOption("enableEmmet", true);
+});
+
+
+// require("ace/placeholder").PlaceHolder;
+
+var snippetManager = require("ace/snippets").snippetManager;
+
+env.editSnippets = function() {
+    var sp = env.split;
+    if (sp.getSplits() == 2) {
+        sp.setSplits(1);
+        return;
+    }
+    sp.setSplits(1);
+    sp.setSplits(2);
+    sp.setOrientation(sp.BESIDE);
+    var editor = sp.$editors[1];
+    var id = sp.$editors[0].session.$mode.$id || "";
+    var m = snippetManager.files[id];
+    if (!doclist["snippets/" + id]) {
+        var text = m.snippetText;
+        var s = doclist.initDoc(text, "", {});
+        s.setMode("ace/mode/snippets");
+        doclist["snippets/" + id] = s;
+    }
+    editor.on("blur", function() {
+        m.snippetText = editor.getValue();
+        snippetManager.unregister(m.snippets);
+        m.snippets = snippetManager.parseSnippetFile(m.snippetText, m.scope);
+        snippetManager.register(m.snippets);
+    });
+    sp.$editors[0].once("changeMode", function() {
+        sp.setSplits(1);
+    });
+    editor.setSession(doclist["snippets/" + id], 1);
+    editor.focus();
+};
+
+require("ace/ext/language_tools");
+env.editor.setOptions({
+    enableBasicAutocompletion: true,
+    enableLiveAutocompletion: false,
+    enableSnippets: true
+});
+
+var beautify = require("ace/ext/beautify");
+env.editor.commands.addCommands(beautify.commands);
+
+});
diff --git a/node_modules/ace/demo/kitchen-sink/dev_util.js b/node_modules/ace/demo/kitchen-sink/dev_util.js
new file mode 100644
index 00000000..8dab857c
--- /dev/null
+++ b/node_modules/ace/demo/kitchen-sink/dev_util.js
@@ -0,0 +1,217 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Distributed under the BSD license:
+ *
+ * Copyright (c) 2010, Ajax.org B.V.
+ * All rights reserved.
+ *
+ * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+define(function(require, exports, module) {
+var dom = require("ace/lib/dom");
+var Range = require("ace/range").Range;
+function warn() {
+    var s = (new Error()).stack || "";
+    s = s.split("\n");
+    if (s[1] == "Error") s.shift(); // remove error description on chrome
+    s.shift(); // remove warn
+    s.shift(); // remove the getter
+    s = s.join("\n");
+    // allow easy access to ace in console, but not in ace code
+    if (!/at Object.InjectedScript.|@debugger eval|snippets:\/{3}/.test(s)) {
+        console.error("trying to access to global variable");
+    }
+}
+function def(o, key, get) {
+    try {
+        Object.defineProperty(o, key, {
+            configurable: true, 
+            get: get,
+            set: function(val) {
+                delete o[key];
+                o[key] = val;
+            }
+        });
+    } catch(e) {
+        console.error(e);
+    }
+}
+def(window, "ace", function(){ warn(); return window.env.editor });
+def(window, "editor", function(){ warn(); return window.env.editor });
+def(window, "session", function(){ warn(); return window.env.editor.session });
+def(window, "split", function(){ warn(); return window.env.split });
+
+
+def(window, "devUtil", function(){ warn(); return exports });
+exports.showTextArea = function(argument) {
+    dom.importCssString("\
+      .ace_text-input {\
+        position: absolute;\
+        z-index: 10!important;\
+        width: 6em!important;\
+        height: 1em;\
+        opacity: 1!important;\
+        background: rgba(0, 92, 255, 0.11);\
+        border: none;\
+        font: inherit;\
+        padding: 0 1px;\
+        margin: 0 -1px;\
+        text-indent: 0em;\
+    }\
+    ");
+};
+
+exports.addGlobals = function() {
+    window.oop = require("ace/lib/oop");
+    window.dom = require("ace/lib/dom");
+    window.Range = require("ace/range").Range;
+    window.Editor = require("ace/editor").Editor;
+    window.assert = require("ace/test/asyncjs/assert");
+    window.asyncjs = require("ace/test/asyncjs/async");
+    window.UndoManager = require("ace/undomanager").UndoManager;
+    window.EditSession = require("ace/edit_session").EditSession;
+    window.MockRenderer = require("ace/test/mockrenderer").MockRenderer;
+    window.EventEmitter = require("ace/lib/event_emitter").EventEmitter;
+    
+    window.getSelection = getSelection;
+    window.setSelection = setSelection;
+    window.testSelection = testSelection;
+};
+
+function getSelection(editor) {
+    var data = editor.multiSelect.toJSON();
+    if (!data.length) data = [data];
+    data = data.map(function(x) {
+        var a, c;
+        if (x.isBackwards) {
+            a = x.end;
+            c = x.start;
+        } else {
+            c = x.end;
+            a = x.start;
+        }
+        return Range.comparePoints(a, c) 
+            ? [a.row, a.column, c.row, c.column]
+            : [a.row, a.column];
+    });
+    return data.length > 1 ? data : data[0];
+}
+function setSelection(editor, data) {
+    if (typeof data[0] == "number")
+        data = [data];
+    editor.selection.fromJSON(data.map(function(x) {
+        var start = {row: x[0], column: x[1]};
+        var end = x.length == 2 ? start : {row: x[2], column: x[3]};
+        var isBackwards = Range.comparePoints(start, end) > 0;
+        return isBackwards ? {
+            start: end,
+            end: start,
+            isBackwards: true
+        } : {
+            start: start,
+            end: end,
+            isBackwards: true
+        };
+    }));
+}
+function testSelection(editor, data) {
+    assert.equal(getSelection(editor) + "", data + "");
+}
+
+exports.recordTestCase = function() {
+    exports.addGlobals();
+    var editor = window.editor;
+    var testcase = window.testcase = [];
+    var assert;
+
+    testcase.push({
+        type: "setValue",
+        data: editor.getValue()
+    }, {
+        type: "setSelection",
+        data: getSelection(editor)
+    });
+    editor.commands.on("afterExec", function(e) {
+        testcase.push({
+            type: "exec",
+            data: e
+        });
+        testcase.push({
+            type: "value",
+            data: editor.getValue()
+        });
+        testcase.push({
+            type: "selection",
+            data: getSelection(editor)
+        });
+    });
+    editor.on("mouseup", function() {
+        testcase.push({
+            type: "setSelection",
+            data: getSelection(editor)
+        });
+    });
+    
+    testcase.toString = function() {
+        var lastValue = "";
+        // var lastSelection = ""
+        var str = this.map(function(x) {
+            var data = x.data;
+            switch (x.type) {
+                case "exec": 
+                    return 'editor.execCommand("' 
+                        + data.command.name
+                        + (data.args ? '", ' + JSON.stringify(data.args) : '"')
+                    + ')';
+                case "setSelection":
+                    return 'setSelection(editor, ' + JSON.stringify(data)  + ')';
+                case "setValue":
+                    if (lastValue != data) {
+                        lastValue = data;
+                        return 'editor.setValue(' + JSON.stringify(data) + ', -1)';
+                    }
+                    return;
+                case "selection":
+                    return 'testSelection(editor, ' + JSON.stringify(data) + ')';
+                case "value":
+                    if (lastValue != data) {
+                        lastValue = data;
+                        return 'assert.equal('
+                            + 'editor.getValue(),'
+                            + JSON.stringify(data)
+                        + ')';
+                    }
+                    return;
+            }
+        }).filter(Boolean).join("\n");
+        
+        return getSelection + "\n"
+            + testSelection + "\n"
+            + setSelection + "\n"
+            + "\n" + str + "\n";
+    };
+};
+
+
+});
diff --git a/node_modules/ace/demo/kitchen-sink/doclist.js b/node_modules/ace/demo/kitchen-sink/doclist.js
new file mode 100644
index 00000000..a4848d50
--- /dev/null
+++ b/node_modules/ace/demo/kitchen-sink/doclist.js
@@ -0,0 +1,218 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Distributed under the BSD license:
+ *
+ * Copyright (c) 2010, Ajax.org B.V.
+ * All rights reserved.
+ *
+ * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+ define(function(require, exports, module) {
+"use strict";
+
+var EditSession = require("ace/edit_session").EditSession;
+var UndoManager = require("ace/undomanager").UndoManager;
+var net = require("ace/lib/net");
+
+var modelist = require("ace/ext/modelist");
+/*********** demo documents ***************************/
+var fileCache = {};
+
+function initDoc(file, path, doc) {
+    if (doc.prepare)
+        file = doc.prepare(file);
+
+    var session = new EditSession(file);
+    session.setUndoManager(new UndoManager());
+    doc.session = session;
+    doc.path = path;
+    session.name = doc.name;
+    if (doc.wrapped) {
+        session.setUseWrapMode(true);
+        session.setWrapLimitRange(80, 80);
+    }
+    var mode = modelist.getModeForPath(path);
+    session.modeName = mode.name;
+    session.setMode(mode.mode);
+    return session;
+}
+
+
+function makeHuge(txt) {
+    for (var i = 0; i < 5; i++)
+        txt += txt;
+    return txt;
+}
+
+var docs = {
+    "docs/javascript.js": {order: 1, name: "JavaScript"},
+
+    "docs/latex.tex": {name: "LaTeX", wrapped: true},
+    "docs/markdown.md": {name: "Markdown", wrapped: true},
+    "docs/mushcode.mc": {name: "MUSHCode", wrapped: true},
+    "docs/pgsql.pgsql": {name: "pgSQL", wrapped: true},
+    "docs/plaintext.txt": {name: "Plain Text", prepare: makeHuge, wrapped: true},
+    "docs/sql.sql": {name: "SQL", wrapped: true},
+
+    "docs/textile.textile": {name: "Textile", wrapped: true},
+
+    "docs/c9search.c9search_results": "C9 Search Results",
+    "docs/mel.mel": "MEL",
+    "docs/Nix.nix": "Nix"
+};
+
+var ownSource = {
+    /* filled from require*/
+};
+
+var hugeDocs = require.toUrl ? {
+    "build/src/ace.js": "",
+    "build/src-min/ace.js": ""
+} : {
+    "src/ace.js": "",
+    "src-min/ace.js": ""
+};
+
+modelist.modes.forEach(function(m) {
+    var ext = m.extensions.split("|")[0];
+    if (ext[0] === "^") {
+        path = ext.substr(1);
+    } else {
+        var path = m.name + "." + ext;
+    }
+    path = "docs/" + path;
+    if (!docs[path]) {
+        docs[path] = {name: m.caption};
+    } else if (typeof docs[path] == "object" && !docs[path].name) {
+        docs[path].name = m.caption;
+    }
+});
+
+
+
+if (window.require && window.require.s) try {
+    for (var path in window.require.s.contexts._.defined) {
+        if (path.indexOf("!") != -1)
+            path = path.split("!").pop();
+        else
+            path = path + ".js";
+        ownSource[path] = "";
+    }
+} catch(e) {}
+
+function sort(list) {
+    return list.sort(function(a, b) {
+        var cmp = (b.order || 0) - (a.order || 0);
+        return cmp || a.name && a.name.localeCompare(b.name);
+    });
+}
+
+function prepareDocList(docs) {
+    var list = [];
+    for (var path in docs) {
+        var doc = docs[path];
+        if (typeof doc != "object")
+            doc = {name: doc || path};
+
+        doc.path = path;
+        doc.desc = doc.name.replace(/^(ace|docs|demo|build)\//, "");
+        if (doc.desc.length > 18)
+            doc.desc = doc.desc.slice(0, 7) + ".." + doc.desc.slice(-9);
+
+        fileCache[doc.name] = doc;
+        list.push(doc);
+    }
+
+    return list;
+}
+
+function loadDoc(name, callback) {
+    var doc = fileCache[name];
+    if (!doc)
+        return callback(null);
+
+    if (doc.session)
+        return callback(doc.session);
+
+    // TODO: show load screen while waiting
+    var path = doc.path;
+    var parts = path.split("/");
+    if (parts[0] == "docs")
+        path = "demo/kitchen-sink/" + path;
+    else if (parts[0] == "ace")
+        path = "lib/" + path;
+
+    net.get(path, function(x) {
+        initDoc(x, path, doc);
+        callback(doc.session);
+    });
+}
+
+function saveDoc(name, callback) {
+    var doc = fileCache[name] || name;
+    if (!doc || !doc.session)
+        return callback("Unknown document: " + name);
+
+    var path = doc.path;
+    var parts = path.split("/");
+    if (parts[0] == "docs")
+        path = "demo/kitchen-sink/" + path;
+    else if (parts[0] == "ace")
+        path = "lib/" + path;
+
+    upload(path, doc.session.getValue(), callback);
+}
+
+function upload(url, data, callback) {
+    url = net.qualifyURL(url);
+    if (!/https?:/.test(url))
+        return callback(new Error("Unsupported url scheme"));
+    var xhr = new XMLHttpRequest();
+    xhr.open("PUT", url, true);
+    xhr.onreadystatechange = function () {
+        if (xhr.readyState === 4) {
+            callback(!/^2../.test(xhr.status));
+        }
+    };
+    xhr.send(data);
+};
+
+
+module.exports = {
+    fileCache: fileCache,
+    docs: sort(prepareDocList(docs)),
+    ownSource: prepareDocList(ownSource),
+    hugeDocs: prepareDocList(hugeDocs),
+    initDoc: initDoc,
+    loadDoc: loadDoc,
+    saveDoc: saveDoc,
+};
+module.exports.all = {
+    "Mode Examples": module.exports.docs,
+    "Huge documents": module.exports.hugeDocs,
+    "own source": module.exports.ownSource
+};
+
+});
+
diff --git a/node_modules/ace/demo/kitchen-sink/docs/.gitignore b/node_modules/ace/demo/kitchen-sink/docs/.gitignore
new file mode 100644
index 00000000..56ec8fd9
--- /dev/null
+++ b/node_modules/ace/demo/kitchen-sink/docs/.gitignore
@@ -0,0 +1,11 @@
+# A sample .gitignore file.
+
+.buildlog
+.DS_Store
+.svn
+
+# Negated patterns:
+!foo.bar
+
+# Also ignore user settings...
+/.settings
diff --git a/node_modules/ace/demo/kitchen-sink/docs/Dockerfile b/node_modules/ace/demo/kitchen-sink/docs/Dockerfile
new file mode 100644
index 00000000..70270cbf
--- /dev/null
+++ b/node_modules/ace/demo/kitchen-sink/docs/Dockerfile
@@ -0,0 +1,53 @@
+#
+# example Dockerfile for http://docs.docker.io/en/latest/examples/postgresql_service/
+#
+
+FROM ubuntu
+MAINTAINER SvenDowideit@docker.com
+
+# Add the PostgreSQL PGP key to verify their Debian packages.
+# It should be the same key as https://www.postgresql.org/media/keys/ACCC4CF8.asc 
+RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys B97B0AFCAA1A47F044F244A07FCC7D46ACCC4CF8
+
+# Add PostgreSQL's repository. It contains the most recent stable release
+#     of PostgreSQL, ``9.3``.
+RUN echo "deb http://apt.postgresql.org/pub/repos/apt/ precise-pgdg main" > /etc/apt/sources.list.d/pgdg.list
+
+# Update the Ubuntu and PostgreSQL repository indexes
+RUN apt-get update
+
+# Install ``python-software-properties``, ``software-properties-common`` and PostgreSQL 9.3
+#  There are some warnings (in red) that show up during the build. You can hide
+#  them by prefixing each apt-get statement with DEBIAN_FRONTEND=noninteractive
+RUN apt-get -y -q install python-software-properties software-properties-common
+RUN apt-get -y -q install postgresql-9.3 postgresql-client-9.3 postgresql-contrib-9.3
+
+# Note: The official Debian and Ubuntu images automatically ``apt-get clean``
+# after each ``apt-get`` 
+
+# Run the rest of the commands as the ``postgres`` user created by the ``postgres-9.3`` package when it was ``apt-get installed``
+USER postgres
+
+# Create a PostgreSQL role named ``docker`` with ``docker`` as the password and
+# then create a database `docker` owned by the ``docker`` role.
+# Note: here we use ``&&\`` to run commands one after the other - the ``\``
+#       allows the RUN command to span multiple lines.
+RUN    /etc/init.d/postgresql start &&\
+    psql --command "CREATE USER docker WITH SUPERUSER PASSWORD 'docker';" &&\
+    createdb -O docker docker
+
+# Adjust PostgreSQL configuration so that remote connections to the
+# database are possible. 
+RUN echo "host all  all    0.0.0.0/0  md5" >> /etc/postgresql/9.3/main/pg_hba.conf
+
+# And add ``listen_addresses`` to ``/etc/postgresql/9.3/main/postgresql.conf``
+RUN echo "listen_addresses='*'" >> /etc/postgresql/9.3/main/postgresql.conf
+
+# Expose the PostgreSQL port
+EXPOSE 5432
+
+# Add VOLUMEs to allow backup of config, logs and databases
+VOLUME	["/etc/postgresql", "/var/log/postgresql", "/var/lib/postgresql"]
+
+# Set the default command to run when starting the container
+CMD ["/usr/lib/postgresql/9.3/bin/postgres", "-D", "/var/lib/postgresql/9.3/main", "-c", "config_file=/etc/postgresql/9.3/main/postgresql.conf"]
\ No newline at end of file
diff --git a/node_modules/ace/demo/kitchen-sink/docs/Haxe.hx b/node_modules/ace/demo/kitchen-sink/docs/Haxe.hx
new file mode 100644
index 00000000..ab205bba
--- /dev/null
+++ b/node_modules/ace/demo/kitchen-sink/docs/Haxe.hx
@@ -0,0 +1,17 @@
+class Haxe 
+{
+    public static function main() 
+    {
+        // Say Hello!
+        var greeting:String = "Hello World";
+        trace(greeting);
+        
+        var targets:Array = ["Flash","Javascript","PHP","Neko","C++","iOS","Android","webOS"];
+        trace("Haxe is a great language that can target:");
+        for (target in targets)
+        {
+            trace (" - " + target);
+        }
+        trace("And many more!");
+    }
+}
\ No newline at end of file
diff --git a/node_modules/ace/demo/kitchen-sink/docs/Jack.jack b/node_modules/ace/demo/kitchen-sink/docs/Jack.jack
new file mode 100644
index 00000000..15acf743
--- /dev/null
+++ b/node_modules/ace/demo/kitchen-sink/docs/Jack.jack
@@ -0,0 +1,247 @@
+vars it, p
+
+p = {label, value|
+  print("\n" + label)
+  print(inspect(value))
+}
+-- Create an array from 0 to 15
+p("range", i-collect(range(5)))
+
+-- Create an array from 0 to 15 and break up in chunks of 4
+p("chunked range", i-collect(i-chunk(4, range(16))))
+
+-- Check if all or none items in stream pass test.
+p("all < 60 in range(60)", i-all?({i|i<60}, range(60)))
+p("any < 60 in range(60)", i-any?({i|i>60}, range(60)))
+p("all < 60 in range(70)", i-all?({i|i<60}, range(70)))
+p("any < 60 in range(70)", i-any?({i|i>60}, range(70)))
+
+-- Zip three different collections together
+p("zipped", i-collect(i-zip(
+  range(10),
+  [1,2,3,4,5],
+  i-map({i|i*i}, range(10))
+)))
+
+vars names, person, i, doubles, lengths, cubeRange
+names = ["Thorin", "Dwalin", "Balin", "Bifur", "Bofur", "Bombur", "Oin",
+         "Gloin", "Ori", "Nori", "Dori", "Fili", "Kili", "Bilbo", "Gandalf"]
+
+for name in names {
+  if name != "Bilbo" && name != "Gandalf" {
+    print(name)
+  }
+}
+
+person = {name: "Tim", age: 30}
+for key, value in person {
+  print(key + " = " + value)
+}
+
+i = 0
+while i < 10 {
+  i = i + 1
+  print(i)
+}
+
+print("range")
+for i in range(10) {
+  print(i + 1)
+}
+for i in range(10) {
+  print(10 - i)
+}
+
+-- Dynamic object that gives the first 10 doubles
+doubles = {
+  @len: {| 10 }
+  @get: {key|
+    if key is Integer { key * key }
+  }
+}
+print("#doubles", #doubles)
+
+print("Doubles")
+for k, v in doubles {
+  print([k, v])
+}
+
+-- Dynamic object that has names list as keys and string lenth as values
+lengths = {
+  @keys: {| names }
+  @get: {key|
+    if key is String { #key }
+  }
+}
+
+print ("Lengths")
+for k, v in lengths {
+  print([k, v])
+}
+
+
+cubeRange = {n|
+  vars i, v
+  i = 0
+  {
+    @call: {|
+      v = i
+      i = i + 1
+      if v < n { v * v * v }
+    }
+  }
+}
+
+print("Cubes")
+for k, v in cubeRange(5) {
+  print([k, v])
+}
+print("String")
+for k, v in "Hello World" {
+  print([k, v])
+}
+
+
+print([i for i in range(10)])
+print([i for i in range(20) if i % 3])
+
+
+
+-- Example showing how to do parallel work using split..and
+base = {bootstrap, target-dir|
+  split {
+    copy("res", target-dir)
+  } and {
+    if newer("src/*.less", target-dir + "/style.css") {
+      lessc("src/" + bootstrap + ".less", target-dir + "/style.css")
+    }
+  } and {
+    build("src/" + bootstrap + ".js", target-dir + "/app.js")
+  }
+}
+
+
+vars Dragon, pet
+
+Dragon = {name|
+  vars asleep, stuff-in-belly, stuff-in-intestine,
+       feed, walk, put-to-bed, toss, rock,
+       hungry?, poopy?, passage-of-time
+
+  asleep = false
+  stuff-in-belly     = 10 -- He's full.
+  stuff-in-intestine =  0 -- He doesn't need to go.
+
+  print(name + ' is born.')
+
+  feed = {|
+    print('You feed ' + name + '.')
+    stuff-in-belly = 10
+    passage-of-time()
+  }
+
+  walk = {|
+    print('You walk ' + name + ".")
+    stuff-in-intestine = 0
+    passage-of-time
+  }
+
+  put-to-bed = {|
+    print('You put ' + name + ' to bed.')
+    asleep = true
+    for i in range(3) {
+      if asleep {
+        passage-of-time()
+      }
+      if asleep {
+        print(name + ' snores, filling the room with smoke.')
+      }
+    }
+    if asleep {
+      asleep = false
+      print(name + ' wakes up slowly.')
+    }
+  }
+
+  toss = {|
+    print('You toss ' + name + ' up into the air.')
+    print('He giggles, which singes your eyebrows.')
+    passage-of-time()
+  }
+
+  rock = {|
+    print('You rock ' + name + ' gently.')
+    asleep = true
+    print('He briefly dozes off...')
+    passage-of-time()
+    if asleep {
+      asleep = false
+      print('...but wakes when you stop.')
+    }
+  }
+
+  hungry? = {|
+    stuff-in-belly <= 2
+  }
+
+  poopy? = {|
+    stuff-in-intestine >= 8
+  }
+
+  passage-of-time = {|
+    if stuff-in-belly > 0 {
+      -- Move food from belly to intestine
+      stuff-in-belly     = stuff-in-belly     - 1
+      stuff-in-intestine = stuff-in-intestine + 1
+    } else { -- Our dragon is starving!
+      if asleep {
+        asleep = false
+        print('He wakes up suddenly!')
+      }
+      print(name + ' is starving! In desperation, he ate YOU!')
+      abort "died"
+    }
+
+    if stuff-in-intestine >= 10 {
+      stuff-in-intestine = 0
+      print('Whoops! ' + name + ' had an accident...')
+    }
+
+    if hungry?() {
+      if asleep {
+        asleep = false
+        print('He wakes up suddenly!')
+      }
+      print(name + "'s stomach grumbles...")
+    }
+
+    if poopy?() {
+      if asleep {
+        asleep = false
+        print('He wakes up suddenly!')
+      }
+      print(name + ' does the potty dance...')
+    }
+  }
+
+  -- Export the public interface to this closure object.
+  {
+   feed: feed
+   walk: walk
+   put-to-bed: put-to-bed
+   toss: toss
+   rock: rock
+  }
+
+}
+
+pet = Dragon('Norbert')
+pet.feed()
+pet.toss()
+pet.walk()
+pet.put-to-bed()
+pet.rock()
+pet.put-to-bed()
+pet.put-to-bed()
+pet.put-to-bed()
+pet.put-to-bed()
diff --git a/node_modules/ace/demo/kitchen-sink/docs/Makefile b/node_modules/ace/demo/kitchen-sink/docs/Makefile
new file mode 100644
index 00000000..9b0b31ac
--- /dev/null
+++ b/node_modules/ace/demo/kitchen-sink/docs/Makefile
@@ -0,0 +1,122 @@
+.PHONY:    apf ext worker mode theme package test
+
+default: apf worker
+
+update: worker
+
+# packages apf
+
+# This is the first line of a comment \
+and this is still part of the comment \
+as is this, since I keep ending each line \
+with a backslash character
+
+apf:
+    cd node_modules/packager; node package.js projects/apf_cloud9.apr
+	cd node_modules/packager; cat build/apf_release.js | sed 's/\(\/\*FILEHEAD(\).*//g' > ../../plugins-client/lib.apf/www/apf-packaged/apf_release.js
+
+# package debug version of apf
+apfdebug:
+	cd node_modules/packager/projects; cat apf_cloud9.apr | sed 's///g' > apf_cloud9_debug2.apr
+	cd node_modules/packager/projects; cat apf_cloud9_debug2.apr | sed 's/apf_release/apf_debug/g' > apf_cloud9_debug.apr; rm apf_cloud9_debug2.apr
+	cd node_modules/packager; node package.js projects/apf_cloud9_debug.apr
+	cd node_modules/packager; cat build/apf_debug.js | sed 's/\(\/\*FILEHEAD(\).*\/apf\/\(.*\)/\1\2/g' > ../../plugins-client/lib.apf/www/apf-packaged/apf_debug.js
+
+# package_apf--temporary fix for non-workering infra
+pack_apf:
+	mkdir -p build/src
+	mv plugins-client/lib.apf/www/apf-packaged/apf_release.js build/src/apf_release.js
+	node build/r.js -o name=./build/src/apf_release.js out=./plugins-client/lib.apf/www/apf-packaged/apf_release.js baseUrl=.
+
+# makes ace; at the moment, requires dryice@0.4.2
+ace:
+	cd node_modules/ace; make clean pre_build; ./Makefile.dryice.js minimal
+
+
+# packages core
+core: ace
+	mkdir -p build/src
+	node build/r.js -o build/core.build.js
+
+# generates packed template
+helper: 
+	node build/packed_helper.js
+
+helper_clean:
+	mkdir -p build/src
+	node build/packed_helper.js 1
+
+# packages ext
+ext: 
+	node build/r.js -o build/app.build.js
+
+# calls dryice on worker & packages it
+worker: plugins-client/lib.ace/www/worker/worker-language.js
+
+plugins-client/lib.ace/www/worker/worker-language.js plugins-client/lib.ace/www/worker/worker-javascript.js : \
+        $(wildcard node_modules/ace/*) $(wildcard node_modules/ace/*/*) $(wildcard node_modules/ace/*/*/mode/*) \
+        $(wildcard plugins-client/ext.language/*) \
+        $(wildcard plugins-client/ext.language/*/*) \
+        $(wildcard plugins-client/ext.linereport/*) \
+        $(wildcard plugins-client/ext.codecomplete/*) \
+        $(wildcard plugins-client/ext.codecomplete/*/*) \
+        $(wildcard plugins-client/ext.jslanguage/*) \
+        $(wildcard plugins-client/ext.jslanguage/*/*) \
+        $(wildcard plugins-client/ext.csslanguage/*) \
+        $(wildcard plugins-client/ext.csslanguage/*/*) \
+        $(wildcard plugins-client/ext.htmllanguage/*) \
+        $(wildcard plugins-client/ext.htmllanguage/*/*) \
+        $(wildcard plugins-client/ext.jsinfer/*) \
+        $(wildcard plugins-client/ext.jsinfer/*/*) \
+        $(wildcard node_modules/treehugger/lib/*) \
+        $(wildcard node_modules/treehugger/lib/*/*) \
+        $(wildcard node_modules/ace/lib/*) \
+        $(wildcard node_modules/ace/*/*) \
+        Makefile.dryice.js
+	mkdir -p plugins-client/lib.ace/www/worker
+	rm -rf /tmp/c9_worker_build
+	mkdir -p /tmp/c9_worker_build/ext
+	ln -s `pwd`/plugins-client/ext.language /tmp/c9_worker_build/ext/language
+	ln -s `pwd`/plugins-client/ext.codecomplete /tmp/c9_worker_build/ext/codecomplete
+	ln -s `pwd`/plugins-client/ext.jslanguage /tmp/c9_worker_build/ext/jslanguage
+	ln -s `pwd`/plugins-client/ext.csslanguage /tmp/c9_worker_build/ext/csslanguage
+	ln -s `pwd`/plugins-client/ext.htmllanguage /tmp/c9_worker_build/ext/htmllanguage
+	ln -s `pwd`/plugins-client/ext.linereport /tmp/c9_worker_build/ext/linereport
+	ln -s `pwd`/plugins-client/ext.linereport_php /tmp/c9_worker_build/ext/linereport_php
+	node Makefile.dryice.js worker
+	cp node_modules/ace/build/src/worker* plugins-client/lib.ace/www/worker
+
+define 
+
+ifeq
+
+override
+
+# copies built ace modes
+mode:
+	mkdir -p plugins-client/lib.ace/www/mode
+	cp `find node_modules/ace/build/src | grep -E "mode-[a-zA-Z_0-9]+.js"`  plugins-client/lib.ace/www/mode
+
+# copies built ace themes
+theme:
+	mkdir -p plugins-client/lib.ace/www/theme
+	cp `find node_modules/ace/build/src | grep -E "theme-[a-zA-Z_0-9]+.js"` plugins-client/lib.ace/www/theme
+
+gzip_safe:
+	for i in `ls ./plugins-client/lib.packed/www/*.js`; do \
+		gzip -9 -v -c -q -f $$i > $$i.gz ; \
+	done
+
+gzip:
+	for i in `ls ./plugins-client/lib.packed/www/*.js`; do \
+		gzip -9 -v -q -f $$i ; \
+	done
+
+c9core: apf ace core worker mode theme
+    
+package_clean: helper_clean c9core ext
+
+package: helper c9core ext
+
+test check:
+	test/run-tests.sh	
\ No newline at end of file
diff --git a/node_modules/ace/demo/kitchen-sink/docs/Nix.nix b/node_modules/ace/demo/kitchen-sink/docs/Nix.nix
new file mode 100644
index 00000000..9476db3b
--- /dev/null
+++ b/node_modules/ace/demo/kitchen-sink/docs/Nix.nix
@@ -0,0 +1,57 @@
+{
+  # Name of our deployment
+  network.description = "HelloWorld";
+  # Enable rolling back to previous versions of our infrastructure
+  network.enableRollback = true;
+
+  # It consists of a single server named 'helloserver'
+  helloserver =
+    # Every server gets passed a few arguments, including a reference
+    # to nixpkgs (pkgs)
+    { config, pkgs, ... }:
+    let
+      # We import our custom packages from ./default passing pkgs as argument
+      packages = import ./default.nix { pkgs = pkgs; };
+      # This is the nodejs version specified in default.nix
+      nodejs   = packages.nodejs;
+      # And this is the application we'd like to deploy
+      app      = packages.app;
+    in
+    {
+      # We'll be running our application on port 8080, because a regular
+      # user cannot bind to port 80
+      # Then, using some iptables magic we'll forward traffic designated to port 80 to 8080
+      networking.firewall.enable = true;
+      # We will open up port 22 (SSH) as well otherwise we're locking ourselves out
+      networking.firewall.allowedTCPPorts = [ 80 8080 22 ];
+      networking.firewall.allowPing = true;
+
+      # Port forwarding using iptables
+      networking.firewall.extraCommands = ''
+        iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
+      '';
+
+      # To run our node.js program we're going to use a systemd service
+      # We can configure the service to automatically start on boot and to restart
+      # the process in case it crashes
+      systemd.services.helloserver = {
+        description = "Hello world application";
+        # Start the service after the network is available
+        after = [ "network.target" ];
+        # We're going to run it on port 8080 in production
+        environment = { PORT = "8080"; };
+        serviceConfig = {
+          # The actual command to run
+          ExecStart = "${nodejs}/bin/node ${app}/server.js";
+          # For security reasons we'll run this process as a special 'nodejs' user
+          User = "nodejs";
+          Restart = "always";
+        };
+      };
+
+      # And lastly we ensure the user we run our application as is created
+      users.extraUsers = {
+        nodejs = { };
+      };
+    };
+}
\ No newline at end of file
diff --git a/node_modules/ace/demo/kitchen-sink/docs/abap.abap b/node_modules/ace/demo/kitchen-sink/docs/abap.abap
new file mode 100644
index 00000000..f66bfdfa
--- /dev/null
+++ b/node_modules/ace/demo/kitchen-sink/docs/abap.abap
@@ -0,0 +1,36 @@
+***************************************
+** Program: EXAMPLE                  **
+** Author: Joe Byte, 07-Jul-2007     **
+***************************************
+ 
+REPORT BOOKINGS.
+ 
+* Read flight bookings from the database
+SELECT * FROM FLIGHTINFO
+  WHERE CLASS = 'Y'       "Y = economy
+  OR    CLASS = 'C'.      "C = business
+(...)
+
+REPORT TEST.
+WRITE 'Hello World'.
+
+USERPROMPT = 'Please double-click on a line in the output list ' &
+             'to see the complete details of the transaction.'.
+
+
+DATA LAST_EOM    TYPE D.  "last end-of-month date
+ 
+* Start from today's date
+  LAST_EOM = SY-DATUM.
+* Set characters 6 and 7 (0-relative) of the YYYYMMDD string to "01",
+* giving the first day of the current month
+  LAST_EOM+6(2) = '01'.
+* Subtract one day
+  LAST_EOM = LAST_EOM - 1.
+ 
+  WRITE: 'Last day of previous month was', LAST_EOM.
+  
+DATA : BEGIN OF I_VBRK OCCURS 0,
+         VBELN LIKE VBRK-VBELN,
+         ZUONR LIKE VBRK-ZUONR,
+       END OF I_VBRK.
\ No newline at end of file
diff --git a/node_modules/ace/demo/kitchen-sink/docs/abc.abc b/node_modules/ace/demo/kitchen-sink/docs/abc.abc
new file mode 100644
index 00000000..d8ac326e
--- /dev/null
+++ b/node_modules/ace/demo/kitchen-sink/docs/abc.abc
@@ -0,0 +1,171 @@
+%abc-2.1
+H:This file contains some example English tunes
+% note that the comments (like this one) are to highlight usages
+%  and would not normally be included in such detail
+O:England             % the origin of all tunes is England
+
+X:1                   % tune no 1
+T:Dusty Miller, The   % title
+T:Binny's Jig         % an alternative title
+C:Trad.               % traditional
+R:DH                  % double hornpipe
+M:3/4                 % meter
+K:G                   % key
+B>cd BAG|FA Ac BA|B>cd BAG|DG GB AG:|
+Bdd gfg|aA Ac BA|Bdd gfa|gG GB AG:|
+BG G/2G/2G BG|FA Ac BA|BG G/2G/2G BG|DG GB AG:|
+W:Hey, the dusty miller, and his dusty coat;
+W:He will win a shilling, or he spend a groat.
+W:Dusty was the coat, dusty was the colour;
+W:Dusty was the kiss, that I got frae the miller.
+
+X:2
+T:Old Sir Simon the King
+C:Trad.
+S:Offord MSS          % from Offord manuscript
+N:see also Playford   % reference note
+M:9/8
+R:SJ                  % slip jig
+N:originally in C     % transcription note
+K:G
+D|GFG GAG G2D|GFG GAG F2D|EFE EFE EFG|A2G F2E D2:|
+D|GAG GAB d2D|GAG GAB c2D|[1 EFE EFE EFG|[A2G] F2E D2:|\ % no line-break in score
+M:12/8                % change of meter
+[2 E2E EFE E2E EFG|\  % no line-break in score
+M:9/8                 % change of meter
+A2G F2E D2|]
+
+X:3
+T:William and Nancy
+T:New Mown Hay
+T:Legacy, The
+C:Trad.
+O:England; Gloucs; Bledington % place of origin
+B:Sussex Tune Book            % can be found in these books
+B:Mally's Cotswold Morris vol.1 2
+D:Morris On                   % can be heard on this record
+P:(AB)2(AC)2A                 % play the parts in this order
+M:6/8
+K:G                        
+[P:A] D|"G"G2G GBd|"C"e2e "G"dBG|"D7"A2d "G"BAG|"C"E2"D7"F "G"G2:|
+[P:B] d|"G"e2d B2d|"C"gfe "G"d2d| "G"e2d    B2d|"C"gfe    "D7"d2c|
+        "G"B2B Bcd|"C"e2e "G"dBG|"D7"A2d "G"BAG|"C"E2"D7"F "G"G2:|
+% changes of meter, using inline fields
+[T:Slows][M:4/4][L:1/4][P:C]"G"d2|"C"e2 "G"d2|B2 d2|"Em"gf "A7"e2|"D7"d2 "G"d2|\
+       "C"e2 "G"d2|[M:3/8][L:1/8] "G"B2 d |[M:6/8] "C"gfe "D7"d2c|
+        "G"B2B Bcd|"C"e2e "G"dBG|"D7"A2d "G"BAG|"C"E2"D7"F "G"G2:|
+
+X:4
+T:South Downs Jig
+R:jig
+S:Robert Harbron
+M:6/8
+L:1/8
+K:G
+|: d | dcA G3 | EFG AFE | DEF GAB | cde d2d |
+dcA G3 | EFG AFE | DEF GAB | cAF G2 :|
+B | Bcd e2c | d2B c2A | Bcd e2c | [M:9/8]d2B c2B A3 |
+[M:6/8]DGF E3 | cBA FED | DEF GAB |1 cAF G2 :|2 cAF G3 |]
+
+X:5
+T:Atholl Brose
+% in this example, which reproduces Highland Bagpipe gracing,
+%  the large number of grace notes mean that it is more convenient to be specific about
+%  score line-breaks (using the $ symbol), rather than using code line breaks to indicate them
+I:linebreak $
+K:D
+{gcd}c<{e}A {gAGAG}A2 {gef}e>A {gAGAG}Ad|
+{gcd}c<{e}A {gAGAG}A>e {ag}a>f {gef}e>d|
+{gcd}c<{e}A {gAGAG}A2 {gef}e>A {gAGAG}Ad|
+{g}c/d/e {g}G>{d}B {gf}gG {dc}d>B:|$
+{g}ce {ag}a>e {gf}g>e|
+{g}ce {ag}a2 {GdG}a>d|
+{g}ce {ag}a>e {gf}g>f|
+{gef}e>d {gf}g>d {gBd}B<{e}G {dc}d>B|
+{g}ce {ag}a>e {gf}g>e|
+{g}ce {ag}a2 {GdG}ad|
+{g}c<{GdG}e {gf}ga {f}g>e {g}f>d|
+{g}e/f/g {Gdc}d>c {gBd}B<{e}G {dc}d2|]
+
+X:6
+T:Untitled Reel
+C:Trad.
+K:D
+eg|a2ab ageg|agbg agef|g2g2 fgag|f2d2 d2:|\
+ed|cecA B2ed|cAcA E2ed|cecA B2ed|c2A2 A2:|
+K:G
+AB|cdec BcdB|ABAF GFE2|cdec BcdB|c2A2 A2:|
+
+X:7
+T:Kitchen Girl
+C:Trad.
+K:D
+[c4a4] [B4g4]|efed c2cd|e2f2 gaba|g2e2 e2fg|
+a4 g4|efed cdef|g2d2 efed|c2A2 A4:|
+K:G
+ABcA BAGB|ABAG EDEG|A2AB c2d2|e3f edcB|ABcA BAGB|
+ABAG EGAB|cBAc BAG2|A4 A4:|
+
+%abc-2.1
+%%pagewidth      21cm
+%%pageheight     29.7cm
+%%topspace       0.5cm
+%%topmargin      1cm
+%%botmargin      0cm
+%%leftmargin     1cm
+%%rightmargin    1cm
+%%titlespace     0cm
+%%titlefont      Times-Bold 32
+%%subtitlefont   Times-Bold 24
+%%composerfont   Times 16
+%%vocalfont      Times-Roman 14
+%%staffsep       60pt
+%%sysstaffsep    20pt
+%%musicspace     1cm
+%%vocalspace     5pt
+%%measurenb      0
+%%barsperstaff   5
+%%scale          0.7
+X: 1
+T: Canzonetta a tre voci
+C: Claudio Monteverdi (1567-1643)
+M: C
+L: 1/4
+Q: "Andante mosso" 1/4 = 110
+%%score [1 2 3]
+V: 1 clef=treble name="Soprano"sname="A"
+V: 2 clef=treble name="Alto"   sname="T"
+V: 3 clef=bass middle=d name="Tenor"  sname="B"
+%%MIDI program 1 75 % recorder
+%%MIDI program 2 75
+%%MIDI program 3 75
+K: Eb
+% 1 - 4
+[V: 1] |:z4  |z4  |f2ec         |_ddcc        |
+w: Son que-sti~i cre-spi cri-ni~e
+w: Que-sti son gli~oc-chi che mi-
+[V: 2] |:c2BG|AAGc|(F/G/A/B/)c=A|B2AA         |
+w: Son que-sti~i cre-spi cri-ni~e que - - - - sto~il vi-so e
+w: Que-sti son~gli oc-chi che mi-ran - - - - do fi-so mi-
+[V: 3] |:z4  |f2ec|_ddcf        |(B/c/_d/e/)ff|
+w: Son que-sti~i cre-spi cri-ni~e que - - - - sto~il
+w: Que-sti son~gli oc-chi che mi-ran - - - - do
+% 5 - 9
+[V: 1] cAB2     |cAAA |c3B|G2!fermata!Gz ::e4|
+w: que-sto~il vi-so ond' io ri-man-go~uc-ci-so. Deh,
+w: ran-do fi-so, tut-to re-stai con-qui-so.
+[V: 2] AAG2     |AFFF |A3F|=E2!fermata!Ez::c4|
+w: que-sto~il vi-so ond' io ri-man-go~uc-ci-so. Deh,
+w: ran-do fi-so tut-to re-stai con-qui-so.
+[V: 3] (ag/f/e2)|A_ddd|A3B|c2!fermata!cz ::A4|
+w: vi - - - so ond' io ti-man-go~uc-ci-so. Deh,
+w: fi - - - so tut-to re-stai con-qui-so.
+% 10 - 15
+[V: 1] f_dec |B2c2|zAGF  |\
+w: dim-me-lo ben mi-o, che que-sto\
+=EFG2          |1F2z2:|2F8|] % more notes
+w: sol de-si-o_. % more lyrics
+[V: 2] ABGA  |G2AA|GF=EF |(GF3/2=E//D//E)|1F2z2:|2F8|]
+w: dim-me-lo ben mi-o, che que-sto sol de-si - - - - o_.
+[V: 3] _dBc>d|e2AF|=EFc_d|c4             |1F2z2:|2F8|]
+w: dim-me-lo ben mi-o, che que-sto sol de-si-o_.
\ No newline at end of file
diff --git a/node_modules/ace/demo/kitchen-sink/docs/actionscript.as b/node_modules/ace/demo/kitchen-sink/docs/actionscript.as
new file mode 100644
index 00000000..ffe21fbf
--- /dev/null
+++ b/node_modules/ace/demo/kitchen-sink/docs/actionscript.as
@@ -0,0 +1,51 @@
+package code
+{
+    /*****************************************
+	 * based on textmate actionscript bundle
+	 ****************************************/
+	 
+	import fl.events.SliderEvent;
+	
+	public class Foo extends MovieClip
+	{
+		//*************************
+		// Properties:
+		
+		public var activeSwatch:MovieClip;
+		
+		// Color offsets
+		public var c1:Number = 0;	// R
+		
+		//*************************
+		// Constructor:
+		
+		public function Foo()
+		{
+			// Respond to mouse events
+			swatch1_btn.addEventListener(MouseEvent.CLICK,swatchHandler,false,0,false);
+			previewBox_btn.addEventListener(MouseEvent.MOUSE_DOWN,dragPressHandler);
+			
+			// Respond to drag events
+			red_slider.addEventListener(SliderEvent.THUMB_DRAG,sliderHandler);
+			
+			// Draw a frame later
+			addEventListener(Event.ENTER_FRAME,draw);
+		}
+        
+		protected function clickHandler(event:MouseEvent):void
+		{
+			car.transform.colorTransform = new ColorTransform(0,0,0,1,c1,c2,c3);
+		}
+		
+		protected function changeRGBHandler(event:Event):void
+		{
+			c1 = Number(c1_txt.text);
+            
+			if(!(c1>=0)){
+				c1 = 0;
+			}			
+			
+			updateSliders();
+		}
+	}
+}
\ No newline at end of file
diff --git a/node_modules/ace/demo/kitchen-sink/docs/ada.ada b/node_modules/ace/demo/kitchen-sink/docs/ada.ada
new file mode 100644
index 00000000..90e027f0
--- /dev/null
+++ b/node_modules/ace/demo/kitchen-sink/docs/ada.ada
@@ -0,0 +1,5 @@
+with Ada.Text_IO; use Ada.Text_IO;
+procedure Hello is
+begin
+  Put_Line("Hello, world!");
+end Hello;
\ No newline at end of file
diff --git a/node_modules/ace/demo/kitchen-sink/docs/asciidoc.asciidoc b/node_modules/ace/demo/kitchen-sink/docs/asciidoc.asciidoc
new file mode 100644
index 00000000..8cddab5d
--- /dev/null
+++ b/node_modules/ace/demo/kitchen-sink/docs/asciidoc.asciidoc
@@ -0,0 +1,6040 @@
+AsciiDoc User Guide
+===================
+Stuart Rackham 
+:Author Initials: SJR
+:toc:
+:icons:
+:numbered:
+:website: http://www.methods.co.nz/asciidoc/
+
+AsciiDoc is a text document format for writing notes, documentation,
+articles, books, ebooks, slideshows, web pages, blogs and UNIX man
+pages.  AsciiDoc files can be translated to many formats including
+HTML, PDF, EPUB, man page.  AsciiDoc is highly configurable: both the
+AsciiDoc source file syntax and the backend output markups (which can
+be almost any type of SGML/XML markup) can be customized and extended
+by the user.
+
+.This document
+**********************************************************************
+This is an overly large document, it probably needs to be refactored
+into a Tutorial, Quick Reference and Formal Reference.
+
+If you're new to AsciiDoc read this section and the <> section and take a look at the example AsciiDoc (`*.txt`)
+source files in the distribution `doc` directory.
+**********************************************************************
+
+
+Introduction
+------------
+AsciiDoc is a plain text human readable/writable document format that
+can be translated to DocBook or HTML using the asciidoc(1) command.
+You can then either use asciidoc(1) generated HTML directly or run
+asciidoc(1) DocBook output through your favorite DocBook toolchain or
+use the AsciiDoc a2x(1) toolchain wrapper to produce PDF, EPUB, DVI,
+LaTeX, PostScript, man page, HTML and text formats.
+
+The AsciiDoc format is a useful presentation format in its own right:
+AsciiDoc markup is simple, intuitive and as such is easily proofed and
+edited.
+
+AsciiDoc is light weight: it consists of a single Python script and a
+bunch of configuration files. Apart from asciidoc(1) and a Python
+interpreter, no other programs are required to convert AsciiDoc text
+files to DocBook or HTML. See <>
+below.
+
+Text markup conventions tend to be a matter of (often strong) personal
+preference: if the default syntax is not to your liking you can define
+your own by editing the text based asciidoc(1) configuration files.
+You can also create configuration files to translate AsciiDoc
+documents to almost any SGML/XML markup.
+
+asciidoc(1) comes with a set of configuration files to translate
+AsciiDoc articles, books and man pages to HTML or DocBook backend
+formats.
+
+.My AsciiDoc Itch
+**********************************************************************
+DocBook has emerged as the de facto standard Open Source documentation
+format. But DocBook is a complex language, the markup is difficult to
+read and even more difficult to write directly -- I found I was
+spending more time typing markup tags, consulting reference manuals
+and fixing syntax errors, than I was writing the documentation.
+**********************************************************************
+
+
+[[X6]]
+Getting Started
+---------------
+Installing AsciiDoc
+~~~~~~~~~~~~~~~~~~~
+See the `README` and `INSTALL` files for install prerequisites and
+procedures. Packagers take a look at <>.
+
+[[X11]]
+Example AsciiDoc Documents
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+The best way to quickly get a feel for AsciiDoc is to view the
+AsciiDoc web site and/or distributed examples:
+
+- Take a look at the linked examples on the AsciiDoc web site home
+  page {website}.  Press the 'Page Source' sidebar menu item to view
+  corresponding AsciiDoc source.
+- Read the `*.txt` source files in the distribution `./doc` directory
+  along with the corresponding HTML and DocBook XML files.
+
+
+AsciiDoc Document Types
+-----------------------
+There are three types of AsciiDoc documents: article, book and
+manpage. All document types share the same AsciiDoc format with some
+minor variations. If you are familiar with DocBook you will have
+noticed that AsciiDoc document types correspond to the same-named
+DocBook document types.
+
+Use the asciidoc(1) `-d` (`--doctype`) option to specify the AsciiDoc
+document type -- the default document type is 'article'.
+
+By convention the `.txt` file extension is used for AsciiDoc document
+source files.
+
+article
+~~~~~~~
+Used for short documents, articles and general documentation.  See the
+AsciiDoc distribution `./doc/article.txt` example.
+
+AsciiDoc defines standard DocBook article frontmatter and backmatter
+<> (appendix, abstract, bibliography,
+glossary, index).
+
+book
+~~~~
+Books share the same format as articles, with the following
+differences:
+
+- The part titles in multi-part books are <>
+  (same level as book title).
+- Some sections are book specific e.g. preface and colophon.
+
+Book documents will normally be used to produce DocBook output since
+DocBook processors can automatically generate footnotes, table of
+contents, list of tables, list of figures, list of examples and
+indexes.
+
+AsciiDoc defines standard DocBook book frontmatter and backmatter
+<> (appendix, dedication, preface,
+bibliography, glossary, index, colophon).
+
+.Example book documents
+Book::
+  The `./doc/book.txt` file in the AsciiDoc distribution.
+
+Multi-part book::
+  The `./doc/book-multi.txt` file in the AsciiDoc distribution.
+
+manpage
+~~~~~~~
+Used to generate roff format UNIX manual pages.  AsciiDoc manpage
+documents observe special header title and section naming conventions
+-- see the <> section for details.
+
+AsciiDoc defines the 'synopsis' <> to
+generate the DocBook `refsynopsisdiv` section.
+
+See also the asciidoc(1) man page source (`./doc/asciidoc.1.txt`) from
+the AsciiDoc distribution.
+
+
+[[X5]]
+AsciiDoc Backends
+-----------------
+The asciidoc(1) command translates an AsciiDoc formatted file to the
+backend format specified by the `-b` (`--backend`) command-line
+option. asciidoc(1) itself has little intrinsic knowledge of backend
+formats, all translation rules are contained in customizable cascading
+configuration files. Backend specific attributes are listed in the
+<> section.
+
+docbook45::
+  Outputs DocBook XML 4.5 markup.
+
+html4::
+  This backend generates plain HTML 4.01 Transitional markup.
+
+xhtml11::
+  This backend generates XHTML 1.1 markup styled with CSS2. Output
+  files have an `.html` extension.
+
+html5::
+  This backend generates HTML 5 markup, apart from the inclusion of
+  <> it is functionally identical to
+  the 'xhtml11' backend.
+
+slidy::
+  Use this backend to generate self-contained
+  http://www.w3.org/Talks/Tools/Slidy2/[Slidy] HTML slideshows for
+  your web browser from AsciiDoc documents. The Slidy backend is
+  documented in the distribution `doc/slidy.txt` file and
+  {website}slidy.html[online].
+
+wordpress::
+  A minor variant of the 'html4' backend to support
+  http://srackham.wordpress.com/blogpost1/[blogpost].
+
+latex::
+  Experimental LaTeX backend.
+
+Backend Aliases
+~~~~~~~~~~~~~~~
+Backend aliases are alternative names for AsciiDoc backends.  AsciiDoc
+comes with two backend aliases: 'html' (aliased to 'xhtml11') and
+'docbook' (aliased to 'docbook45').
+
+You can assign (or reassign) backend aliases by setting an AsciiDoc
+attribute named like `backend-alias-` to an AsciiDoc backend
+name. For example, the following backend alias attribute definitions
+appear in the `[attributes]` section of the global `asciidoc.conf`
+configuration file:
+
+  backend-alias-html=xhtml11
+  backend-alias-docbook=docbook45
+
+[[X100]]
+Backend Plugins
+~~~~~~~~~~~~~~~
+The asciidoc(1) `--backend` option is also used to install and manage
+backend <>.
+
+- A backend plugin is used just like the built-in backends.
+- Backend plugins <> over built-in backends with
+  the same name.
+- You can use the `{asciidoc-confdir}` <> to
+  refer to the built-in backend configuration file location from
+  backend plugin configuration files.
+- You can use the `{backend-confdir}` <> to
+  refer to the backend plugin configuration file location.
+- By default backends plugins are installed in
+  `$HOME/.asciidoc/backends/` where `` is the
+  backend name.
+
+
+DocBook
+-------
+AsciiDoc generates 'article', 'book' and 'refentry'
+http://www.docbook.org/[DocBook] documents (corresponding to the
+AsciiDoc 'article', 'book' and 'manpage' document types).
+
+Most Linux distributions come with conversion tools (collectively
+called a toolchain) for <> to
+presentation formats such as Postscript, HTML, PDF, EPUB, DVI,
+PostScript, LaTeX, roff (the native man page format), HTMLHelp,
+JavaHelp and text.  There are also programs that allow you to view
+DocBook files directly, for example http://live.gnome.org/Yelp[Yelp]
+(the GNOME help viewer).
+
+[[X12]]
+Converting DocBook to other file formats
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+DocBook files are validated, parsed and translated various
+presentation file formats using a combination of applications
+collectively called a DocBook 'tool chain'. The function of a tool
+chain is to read the DocBook markup (produced by AsciiDoc) and
+transform it to a presentation format (for example HTML, PDF, HTML
+Help, EPUB, DVI, PostScript, LaTeX).
+
+A wide range of user output format requirements coupled with a choice
+of available tools and stylesheets results in many valid tool chain
+combinations.
+
+[[X43]]
+a2x Toolchain Wrapper
+~~~~~~~~~~~~~~~~~~~~~
+One of the biggest hurdles for new users is installing, configuring
+and using a DocBook XML toolchain. `a2x(1)` can help -- it's a
+toolchain wrapper command that will generate XHTML (chunked and
+unchunked), PDF, EPUB, DVI, PS, LaTeX, man page, HTML Help and text
+file outputs from an AsciiDoc text file.  `a2x(1)` does all the grunt
+work associated with generating and sequencing the toolchain commands
+and managing intermediate and output files.  `a2x(1)` also optionally
+deploys admonition and navigation icons and a CSS stylesheet. See the
+`a2x(1)` man page for more details. In addition to `asciidoc(1)` you
+also need <>, <> and
+optionally: <> or <> (to generate PDF);
+`w3m(1)` or `lynx(1)` (to generate text).
+
+The following examples generate `doc/source-highlight-filter.pdf` from
+the AsciiDoc `doc/source-highlight-filter.txt` source file. The first
+example uses `dblatex(1)` (the default PDF generator) the second
+example forces FOP to be used:
+
+  $ a2x -f pdf doc/source-highlight-filter.txt
+  $ a2x -f pdf --fop doc/source-highlight-filter.txt
+
+See the `a2x(1)` man page for details.
+
+TIP: Use the `--verbose` command-line option to view executed
+toolchain commands.
+
+HTML generation
+~~~~~~~~~~~~~~~
+AsciiDoc produces nicely styled HTML directly without requiring a
+DocBook toolchain but there are also advantages in going the DocBook
+route:
+
+- HTML from DocBook can optionally include automatically generated
+  indexes, tables of contents, footnotes, lists of figures and tables.
+- DocBook toolchains can also (optionally) generate separate (chunked)
+  linked HTML pages for each document section.
+- Toolchain processing performs link and document validity checks.
+- If the DocBook 'lang' attribute is set then things like table of
+  contents, figure and table captions and admonition captions will be
+  output in the specified language (setting the AsciiDoc 'lang'
+  attribute sets the DocBook 'lang' attribute).
+
+On the other hand, HTML output directly from AsciiDoc is much faster,
+is easily customized and can be used in situations where there is no
+suitable DocBook toolchain (for example, see the {website}[AsciiDoc
+website]).
+
+PDF generation
+~~~~~~~~~~~~~~
+There are two commonly used tools to generate PDFs from DocBook,
+<> and <>.
+
+.dblatex or FOP?
+- 'dblatex' is easier to install, there's zero configuration
+  required and no Java VM to install -- it just works out of the box.
+- 'dblatex' source code highlighting and numbering is superb.
+- 'dblatex' is easier to use as it converts DocBook directly to PDF
+  whereas before using 'FOP' you have to convert DocBook to XML-FO
+  using <>.
+- 'FOP' is more feature complete (for example, callouts are processed
+  inside literal layouts) and arguably produces nicer looking output.
+
+HTML Help generation
+~~~~~~~~~~~~~~~~~~~~
+. Convert DocBook XML documents to HTML Help compiler source files
+  using <> and <>.
+. Convert the HTML Help source (`.hhp` and `.html`) files to HTML Help
+  (`.chm`) files using the <>.
+
+Toolchain components summary
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+AsciiDoc::
+    Converts AsciiDoc (`.txt`) files to DocBook XML (`.xml`) files.
+
+[[X13]]http://docbook.sourceforge.net/projects/xsl/[DocBook XSL Stylesheets]::
+  These are a set of XSL stylesheets containing rules for converting
+  DocBook XML documents to HTML, XSL-FO, manpage and HTML Help files.
+  The stylesheets are used in conjunction with an XML parser such as
+  <>.
+
+[[X40]]http://www.xmlsoft.org[xsltproc]::
+  An XML parser for applying XSLT stylesheets (in our case the
+  <>) to XML documents.
+
+[[X31]]http://dblatex.sourceforge.net/[dblatex]::
+  Generates PDF, DVI, PostScript and LaTeX formats directly from
+  DocBook source via the intermediate LaTeX typesetting language --
+  uses <>, <> and
+  `latex(1)`.
+
+[[X14]]http://xml.apache.org/fop/[FOP]::
+  The Apache Formatting Objects Processor converts XSL-FO (`.fo`)
+  files to PDF files.  The XSL-FO files are generated from DocBook
+  source files using <> and
+  <>.
+
+[[X67]]Microsoft Help Compiler::
+  The Microsoft HTML Help Compiler (`hhc.exe`) is a command-line tool
+  that converts HTML Help source files to a single HTML Help (`.chm`)
+  file. It runs on MS Windows platforms and can be downloaded from
+  http://www.microsoft.com.
+
+AsciiDoc dblatex configuration files
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The AsciiDoc distribution `./dblatex` directory contains
+`asciidoc-dblatex.xsl` (customized XSL parameter settings) and
+`asciidoc-dblatex.sty` (customized LaTeX settings). These are examples
+of optional <> output customization and are used by
+<>.
+
+AsciiDoc DocBook XSL Stylesheets drivers
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+You will have noticed that the distributed HTML and HTML Help
+documentation files (for example `./doc/asciidoc.html`) are not the
+plain outputs produced using the default 'DocBook XSL Stylesheets'
+configuration.  This is because they have been processed using
+customized DocBook XSL Stylesheets along with (in the case of HTML
+outputs) the custom `./stylesheets/docbook-xsl.css` CSS stylesheet.
+
+You'll find the customized DocBook XSL drivers along with additional
+documentation in the distribution `./docbook-xsl` directory. The
+examples that follow are executed from the distribution documentation
+(`./doc`) directory. These drivers are also used by <>.
+
+`common.xsl`::
+    Shared driver parameters.  This file is not used directly but is
+    included in all the following drivers.
+
+`chunked.xsl`::
+    Generate chunked XHTML (separate HTML pages for each document
+    section) in the `./doc/chunked` directory. For example:
+
+    $ python ../asciidoc.py -b docbook asciidoc.txt
+    $ xsltproc --nonet ../docbook-xsl/chunked.xsl asciidoc.xml
+
+`epub.xsl`::
+    Used by <> to generate EPUB formatted documents.
+
+`fo.xsl`::
+    Generate XSL Formatting Object (`.fo`) files for subsequent PDF
+    file generation using FOP. For example:
+
+    $ python ../asciidoc.py -b docbook article.txt
+    $ xsltproc --nonet ../docbook-xsl/fo.xsl article.xml > article.fo
+    $ fop article.fo article.pdf
+
+`htmlhelp.xsl`::
+    Generate Microsoft HTML Help source files for the MS HTML Help
+    Compiler in the `./doc/htmlhelp` directory. This example is run on
+    MS Windows from a Cygwin shell prompt:
+
+    $ python ../asciidoc.py -b docbook asciidoc.txt
+    $ xsltproc --nonet ../docbook-xsl/htmlhelp.xsl asciidoc.xml
+    $ c:/Program\ Files/HTML\ Help\ Workshop/hhc.exe htmlhelp.hhp
+
+`manpage.xsl`::
+    Generate a `roff(1)` format UNIX man page from a DocBook XML
+    'refentry' document. This example generates an `asciidoc.1` man
+    page file:
+
+    $ python ../asciidoc.py -d manpage -b docbook asciidoc.1.txt
+    $ xsltproc --nonet ../docbook-xsl/manpage.xsl asciidoc.1.xml
+
+`xhtml.xsl`::
+    Convert a DocBook XML file to a single XHTML file. For example:
+
+    $ python ../asciidoc.py -b docbook asciidoc.txt
+    $ xsltproc --nonet ../docbook-xsl/xhtml.xsl asciidoc.xml > asciidoc.html
+
+If you want to see how the complete documentation set is processed
+take a look at the A-A-P script `./doc/main.aap`.
+
+
+Generating Plain Text Files
+---------------------------
+AsciiDoc does not have a text backend (for most purposes AsciiDoc
+source text is fine), however you can convert AsciiDoc text files to
+formatted text using the AsciiDoc <> toolchain wrapper
+utility.
+
+
+[[X35]]
+HTML5 and XHTML 1.1
+-------------------
+The 'xhtml11' and 'html5' backends embed or link CSS and JavaScript
+files in their outputs, there is also a <> plugin
+framework.
+
+- If the AsciiDoc 'linkcss' attribute is defined then CSS and
+  JavaScript files are linked to the output document, otherwise they
+  are embedded (the default behavior).
+- The default locations for CSS and JavaScript files can be changed by
+  setting the AsciiDoc 'stylesdir' and 'scriptsdir' attributes
+  respectively.
+- The default locations for embedded and linked files differ and are
+  calculated at different times -- embedded files are loaded when
+  asciidoc(1) generates the output document, linked files are loaded
+  by the browser when the user views the output document.
+- Embedded files are automatically inserted in the output files but
+  you need to manually copy linked CSS and Javascript files from
+  AsciiDoc <> to the correct location
+  relative to the output document.
+
+.Stylesheet file locations
+[cols="3*",frame="topbot",options="header"]
+|====================================================================
+|'stylesdir' attribute
+|Linked location ('linkcss' attribute defined)
+|Embedded location ('linkcss' attribute undefined)
+
+|Undefined (default).
+|Same directory as the output document.
+|`stylesheets` subdirectory in the AsciiDoc configuration directory
+(the directory containing the backend conf file).
+
+|Absolute or relative directory name.
+|Absolute or relative to the output document.
+|Absolute or relative to the AsciiDoc configuration directory (the
+directory containing the backend conf file).
+
+|====================================================================
+
+.JavaScript file locations
+[cols="3*",frame="topbot",options="header"]
+|====================================================================
+|'scriptsdir' attribute
+|Linked location ('linkcss' attribute defined)
+|Embedded location ('linkcss' attribute undefined)
+
+|Undefined (default).
+|Same directory as the output document.
+|`javascripts` subdirectory in the AsciiDoc configuration directory
+(the directory containing the backend conf file).
+
+|Absolute or relative directory name.
+|Absolute or relative to the output document.
+|Absolute or relative to the AsciiDoc configuration directory (the
+directory containing the backend conf file).
+
+|====================================================================
+
+[[X99]]
+Themes
+~~~~~~
+The AsciiDoc 'theme' attribute is used to select an alternative CSS
+stylesheet and to optionally include additional JavaScript code.
+
+- Theme files reside in an AsciiDoc <>
+  named `themes//` (where `` is the the theme name set
+  by the 'theme' attribute). asciidoc(1) sets the 'themedir' attribute
+  to the theme directory path name.
+- The 'theme' attribute can also be set using the asciidoc(1)
+  `--theme` option, the `--theme` option can also be used to manage
+  theme <>.
+- AsciiDoc ships with two themes: 'flask' and 'volnitsky'.
+- The `.css` file replaces the default `asciidoc.css` CSS file.
+- The `.js` file is included in addition to the default
+  `asciidoc.js` JavaScript file.
+- If the <> attribute is defined then icons are loaded
+  from the theme `icons` sub-directory if it exists (i.e.  the
+  'iconsdir' attribute is set to theme `icons` sub-directory path).
+- Embedded theme files are automatically inserted in the output files
+  but you need to manually copy linked CSS and Javascript files to the
+  location of the output documents.
+- Linked CSS and JavaScript theme files are linked to the same linked
+  locations as <>.
+
+For example, the command-line option `--theme foo` (or `--attribute
+theme=foo`) will cause asciidoc(1) to search <<"X27","configuration
+file locations 1, 2 and 3">> for a sub-directory called `themes/foo`
+containing the stylesheet `foo.css` and optionally a JavaScript file
+name `foo.js`.
+
+
+Document Structure
+------------------
+An AsciiDoc document consists of a series of <>
+starting with an optional document Header, followed by an optional
+Preamble, followed by zero or more document Sections.
+
+Almost any combination of zero or more elements constitutes a valid
+AsciiDoc document: documents can range from a single sentence to a
+multi-part book.
+
+Block Elements
+~~~~~~~~~~~~~~
+Block elements consist of one or more lines of text and may contain
+other block elements.
+
+The AsciiDoc block structure can be informally summarized as follows
+footnote:[This is a rough structural guide, not a rigorous syntax
+definition]:
+
+  Document      ::= (Header?,Preamble?,Section*)
+  Header        ::= (Title,(AuthorInfo,RevisionInfo?)?)
+  AuthorInfo    ::= (FirstName,(MiddleName?,LastName)?,EmailAddress?)
+  RevisionInfo  ::= (RevisionNumber?,RevisionDate,RevisionRemark?)
+  Preamble      ::= (SectionBody)
+  Section       ::= (Title,SectionBody?,(Section)*)
+  SectionBody   ::= ((BlockTitle?,Block)|BlockMacro)+
+  Block         ::= (Paragraph|DelimitedBlock|List|Table)
+  List          ::= (BulletedList|NumberedList|LabeledList|CalloutList)
+  BulletedList  ::= (ListItem)+
+  NumberedList  ::= (ListItem)+
+  CalloutList   ::= (ListItem)+
+  LabeledList   ::= (ListEntry)+
+  ListEntry     ::= (ListLabel,ListItem)
+  ListLabel     ::= (ListTerm+)
+  ListItem      ::= (ItemText,(List|ListParagraph|ListContinuation)*)
+
+Where:
+
+- '?' implies zero or one occurrence, '+' implies one or more
+  occurrences, '*' implies zero or more occurrences.
+- All block elements are separated by line boundaries.
+- `BlockId`, `AttributeEntry` and `AttributeList` block elements (not
+  shown) can occur almost anywhere.
+- There are a number of document type and backend specific
+  restrictions imposed on the block syntax.
+- The following elements cannot contain blank lines: Header, Title,
+  Paragraph, ItemText.
+- A ListParagraph is a Paragraph with its 'listelement' option set.
+- A ListContinuation is a <>.
+
+[[X95]]
+Header
+~~~~~~
+The Header contains document meta-data, typically title plus optional
+authorship and revision information:
+
+- The Header is optional, but if it is used it must start with a
+  document <>.
+- Optional Author and Revision information immediately follows the
+  header title.
+- The document header must be separated from the remainder of the
+  document by one or more blank lines and cannot contain blank lines.
+- The header can include comments.
+- The header can include <>, typically
+  'doctype', 'lang', 'encoding', 'icons', 'data-uri', 'toc',
+  'numbered'.
+- Header attributes are overridden by command-line attributes.
+- If the header contains non-UTF-8 characters then the 'encoding' must
+  precede the header (either in the document or on the command-line).
+
+Here's an example AsciiDoc document header:
+
+  Writing Documentation using AsciiDoc
+  ====================================
+  Joe Bloggs 
+  v2.0, February 2003:
+  Rewritten for version 2 release.
+
+The author information line contains the author's name optionally
+followed by the author's email address. The author's name is formatted
+like:
+
+  firstname[ [middlename ]lastname][ ]]
+
+i.e. a first name followed by optional middle and last names followed
+by an email address in that order.  Multi-word first, middle and last
+names can be entered using the underscore as a word separator.  The
+email address comes last and must be enclosed in angle <> brackets.
+Here a some examples of author information lines:
+
+  Joe Bloggs 
+  Joe Bloggs
+  Vincent Willem van_Gogh
+
+If the author line does not match the above specification then the
+entire author line is treated as the first name.
+
+The optional revision information line follows the author information
+line. The revision information can be one of two formats:
+
+. An optional document revision number followed by an optional
+  revision date followed by an optional revision remark:
++
+--
+  * If the revision number is specified it must be followed by a
+    comma.
+  * The revision number must contain at least one numeric character.
+  * Any non-numeric characters preceding the first numeric character
+    will be dropped.
+  * If a revision remark is specified it must be preceded by a colon.
+    The revision remark extends from the colon up to the next blank
+    line, attribute entry or comment and is subject to normal text
+    substitutions.
+  * If a revision number or remark has been set but the revision date
+    has not been set then the revision date is set to the value of the
+    'docdate' attribute.
+
+Examples:
+
+  v2.0, February 2003
+  February 2003
+  v2.0,
+  v2.0, February 2003: Rewritten for version 2 release.
+  February 2003: Rewritten for version 2 release.
+  v2.0,: Rewritten for version 2 release.
+  :Rewritten for version 2 release.
+--
+
+. The revision information line can also be an RCS/CVS/SVN $Id$
+  marker:
++
+--
+  * AsciiDoc extracts the 'revnumber', 'revdate', and 'author'
+    attributes from the $Id$ revision marker and displays them in the
+    document header.
+  * If an $Id$ revision marker is used the header author line can be
+    omitted.
+
+Example:
+
+  $Id: mydoc.txt,v 1.5 2009/05/17 17:58:44 jbloggs Exp $
+--
+
+You can override or set header parameters by passing 'revnumber',
+'revremark', 'revdate', 'email', 'author', 'authorinitials',
+'firstname' and 'lastname' attributes using the asciidoc(1) `-a`
+(`--attribute`) command-line option. For example:
+
+  $ asciidoc -a revdate=2004/07/27 article.txt
+
+Attribute entries can also be added to the header for substitution in
+the header template with <> elements.
+
+The 'title' element in HTML outputs is set to the AsciiDoc document
+title, you can set it to a different value by including a 'title'
+attribute entry in the document header.
+
+[[X87]]
+Additional document header information
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+AsciiDoc has two mechanisms for optionally including additional
+meta-data in the header of the output document:
+
+'docinfo' configuration file sections::
+If a <> section named 'docinfo' has been loaded
+then it will be included in the document header. Typically the
+'docinfo' section name will be prefixed with a '+' character so that it
+is appended to (rather than replace) other 'docinfo' sections.
+
+'docinfo' files::
+Two docinfo files are recognized: one named `docinfo` and a second
+named like the AsciiDoc source file with a `-docinfo` suffix.  For
+example, if the source document is called `mydoc.txt` then the
+document information files would be `docinfo.xml` and
+`mydoc-docinfo.xml` (for DocBook outputs) and `docinfo.html` and
+`mydoc-docinfo.html` (for HTML outputs).  The <> attributes control which docinfo files are included in
+the output files.
+
+The contents docinfo templates and files is dependent on the type of
+output:
+
+HTML::
+  Valid 'head' child elements. Typically 'style' and 'script' elements
+  for CSS and JavaScript inclusion.
+
+DocBook::
+  Valid 'articleinfo' or 'bookinfo' child elements.  DocBook defines
+  numerous elements for document meta-data, for example: copyrights,
+  document history and authorship information.  See the DocBook
+  `./doc/article-docinfo.xml` example that comes with the AsciiDoc
+  distribution.  The rendering of meta-data elements (or not) is
+  DocBook processor dependent.
+
+
+[[X86]]
+Preamble
+~~~~~~~~
+The Preamble is an optional untitled section body between the document
+Header and the first Section title.
+
+Sections
+~~~~~~~~
+In addition to the document title (level 0), AsciiDoc supports four
+section levels: 1 (top) to 4 (bottom).  Section levels are delimited
+by section <>.  Sections are translated using
+configuration file <>. AsciiDoc
+generates the following <> specifically for
+use in section markup templates:
+
+level::
+The `level` attribute is the section level number, it is normally just
+the <> level number (1..4). However, if the `leveloffset`
+attribute is defined it will be added to the `level` attribute. The
+`leveloffset` attribute is useful for <>.
+
+sectnum::
+The `-n` (`--section-numbers`) command-line option generates the
+`sectnum` (section number) attribute.  The `sectnum` attribute is used
+for section numbers in HTML outputs (DocBook section numbering are
+handled automatically by the DocBook toolchain commands).
+
+[[X93]]
+Section markup templates
+^^^^^^^^^^^^^^^^^^^^^^^^
+Section markup templates specify output markup and are defined in
+AsciiDoc configuration files.  Section markup template names are
+derived as follows (in order of precedence):
+
+1. From the title's first positional attribute or 'template'
+   attribute. For example, the following three section titles are
+   functionally equivalent:
++
+.....................................................................
+[[terms]]
+[glossary]
+List of Terms
+-------------
+
+["glossary",id="terms"]
+List of Terms
+-------------
+
+[template="glossary",id="terms"]
+List of Terms
+-------------
+.....................................................................
+
+2. When the title text matches a configuration file
+   <> entry.
+3. If neither of the above the default `sect` template is used
+   (where `` is a number from 1 to 4).
+
+In addition to the normal section template names ('sect1', 'sect2',
+'sect3', 'sect4') AsciiDoc has the following templates for
+frontmatter, backmatter and other special sections: 'abstract',
+'preface', 'colophon', 'dedication', 'glossary', 'bibliography',
+'synopsis', 'appendix', 'index'.  These special section templates
+generate the corresponding Docbook elements; for HTML outputs they
+default to the 'sect1' section template.
+
+Section IDs
+^^^^^^^^^^^
+If no explicit section ID is specified an ID will be synthesised from
+the section title.  The primary purpose of this feature is to ensure
+persistence of table of contents links (permalinks): the missing
+section IDs are generated dynamically by the JavaScript TOC generator
+*after* the page is loaded. If you link to a dynamically generated TOC
+address the page will load but the browser will ignore the (as yet
+ungenerated) section ID.
+
+The IDs are generated by the following algorithm:
+
+- Replace all non-alphanumeric title characters with underscores.
+- Strip leading or trailing underscores.
+- Convert to lowercase.
+- Prepend the `idprefix` attribute (so there's no possibility of name
+  clashes with existing document IDs). Prepend an underscore if the
+  `idprefix` attribute is not defined.
+- A numbered suffix (`_2`, `_3` ...) is added if a same named
+  auto-generated section ID exists.
+- If the `ascii-ids` attribute is defined then non-ASCII characters
+  are replaced with ASCII equivalents. This attribute may be
+  deprecated in future releases and *should be avoided*, it's sole
+  purpose is to accommodate deficient downstream applications that
+  cannot process non-ASCII ID attributes.
+
+Example: the title 'Jim's House' would generate the ID `_jim_s_house`.
+
+Section ID synthesis can be disabled by undefining the `sectids`
+attribute.
+
+[[X16]]
+Special Section Titles
+^^^^^^^^^^^^^^^^^^^^^^
+AsciiDoc has a mechanism for mapping predefined section titles
+auto-magically to specific markup templates. For example a title
+'Appendix A: Code Reference' will automatically use the 'appendix'
+<>. The mappings from title to template
+name are specified in `[specialsections]` sections in the Asciidoc
+language configuration files (`lang-*.conf`).  Section entries are
+formatted like:
+
+  =<template>
+
+`<title>` is a Python regular expression and `<template>` is the name
+of a configuration file markup template section. If the `<title>`
+matches an AsciiDoc document section title then the backend output is
+marked up using the `<template>` markup template (instead of the
+default `sect<level>` section template). The `{title}` attribute value
+is set to the value of the matched regular expression group named
+'title', if there is no 'title' group `{title}` defaults to the whole
+of the AsciiDoc section title. If `<template>` is blank then any
+existing entry with the same `<title>` will be deleted.
+
+.Special section titles vs. explicit template names
+*********************************************************************
+AsciiDoc has two mechanisms for specifying non-default section markup
+templates: you can specify the template name explicitly (using the
+'template' attribute) or indirectly (using 'special section titles').
+Specifying a <<X93,section template>> attribute explicitly is
+preferred.  Auto-magical 'special section titles' have the following
+drawbacks:
+
+- They are non-obvious, you have to know the exact matching
+  title for each special section on a language by language basis.
+- Section titles are predefined and can only be customised with a
+  configuration change.
+- The implementation is complicated by multiple languages: every
+  special section title has to be defined for each language (in each
+  of the `lang-*.conf` files).
+
+Specifying special section template names explicitly does add more
+noise to the source document (the 'template' attribute declaration),
+but the intention is obvious and the syntax is consistent with other
+AsciiDoc elements c.f.  bibliographic, Q&A and glossary lists.
+
+Special section titles have been deprecated but are retained for
+backward compatibility.
+
+*********************************************************************
+
+Inline Elements
+~~~~~~~~~~~~~~~
+<<X34,Inline document elements>> are used to format text and to
+perform various types of text substitution. Inline elements and inline
+element syntax is defined in the asciidoc(1) configuration files.
+
+Here is a list of AsciiDoc inline elements in the (default) order in
+which they are processed:
+
+Special characters::
+        These character sequences escape special characters used by
+        the backend markup (typically `<`, `>`, and `&` characters).
+        See `[specialcharacters]` configuration file sections.
+
+Quotes::
+        Elements that markup words and phrases; usually for character
+        formatting. See `[quotes]` configuration file sections.
+
+Special Words::
+        Word or word phrase patterns singled out for markup without
+        the need for further annotation.  See `[specialwords]`
+        configuration file sections.
+
+Replacements::
+        Each replacement defines a word or word phrase pattern to
+        search for along with corresponding replacement text. See
+        `[replacements]` configuration file sections.
+
+Attribute references::
+        Document attribute names enclosed in braces are replaced by
+        the corresponding attribute value.
+
+Inline Macros::
+        Inline macros are replaced by the contents of parametrized
+        configuration file sections.
+
+
+Document Processing
+-------------------
+The AsciiDoc source document is read and processed as follows:
+
+1. The document 'Header' is parsed, header parameter values are
+   substituted into the configuration file `[header]` template section
+   which is then written to the output file.
+2. Each document 'Section' is processed and its constituent elements
+   translated to the output file.
+3. The configuration file `[footer]` template section is substituted
+   and written to the output file.
+
+When a block element is encountered asciidoc(1) determines the type of
+block by checking in the following order (first to last): (section)
+Titles, BlockMacros, Lists, DelimitedBlocks, Tables, AttributeEntrys,
+AttributeLists, BlockTitles, Paragraphs.
+
+The default paragraph definition `[paradef-default]` is last element
+to be checked.
+
+Knowing the parsing order will help you devise unambiguous macro, list
+and block syntax rules.
+
+Inline substitutions within block elements are performed in the
+following default order:
+
+1. Special characters
+2. Quotes
+3. Special words
+4. Replacements
+5. Attributes
+6. Inline Macros
+7. Replacements2
+
+The substitutions and substitution order performed on
+Title, Paragraph and DelimitedBlock elements is determined by
+configuration file parameters.
+
+
+Text Formatting
+---------------
+[[X51]]
+Quoted Text
+~~~~~~~~~~~
+Words and phrases can be formatted by enclosing inline text with
+quote characters:
+
+_Emphasized text_::
+        Word phrases \'enclosed in single quote characters' (acute
+        accents) or \_underline characters_ are emphasized.
+
+*Strong text*::
+        Word phrases \*enclosed in asterisk characters* are rendered
+        in a strong font (usually bold).
+
+[[X81]]+Monospaced text+::
+        Word phrases \+enclosed in plus characters+ are rendered in a
+        monospaced font. Word phrases \`enclosed in backtick
+        characters` (grave accents) are also rendered in a monospaced
+        font but in this case the enclosed text is rendered literally
+        and is not subject to further expansion (see <<X80,inline
+        literal passthrough>>).
+
+`Single quoted text'::
+        Phrases enclosed with a \`single grave accent to the left and
+        a single acute accent to the right' are rendered in single
+        quotation marks.
+
+``Double quoted text''::
+        Phrases enclosed with \\``two grave accents to the left and
+        two acute accents to the right'' are rendered in quotation
+        marks.
+
+#Unquoted text#::
+        Placing \#hashes around text# does nothing, it is a mechanism
+        to allow inline attributes to be applied to otherwise
+        unformatted text.
+
+New quote types can be defined by editing asciidoc(1) configuration
+files. See the <<X7,Configuration Files>> section for details.
+
+.Quoted text behavior
+- Quoting cannot be overlapped.
+- Different quoting types can be nested.
+- To suppress quoted text formatting place a backslash character
+  immediately in front of the leading quote character(s). In the case
+  of ambiguity between escaped and non-escaped text you will need to
+  escape both leading and trailing quotes, in the case of
+  multi-character quotes you may even need to escape individual
+  characters.
+
+[[X96]]
+Quoted text attributes
+^^^^^^^^^^^^^^^^^^^^^^
+Quoted text can be prefixed with an <<X21,attribute list>>.  The first
+positional attribute ('role' attribute) is translated by AsciiDoc to
+an HTML 'span' element 'class' attribute or a DocBook 'phrase' element
+'role' attribute.
+
+DocBook XSL Stylesheets translate DocBook 'phrase' elements with
+'role' attributes to corresponding HTML 'span' elements with the same
+'class' attributes; CSS can then be used
+http://www.sagehill.net/docbookxsl/UsingCSS.html[to style the
+generated HTML].  Thus CSS styling can be applied to both DocBook and
+AsciiDoc generated HTML outputs.  You can also specify multiple class
+names separated by spaces.
+
+CSS rules for text color, text background color, text size and text
+decorators are included in the distributed AsciiDoc CSS files and are
+used in conjunction with AsciiDoc 'xhtml11', 'html5' and 'docbook'
+outputs. The CSS class names are:
+
+- '<color>' (text foreground color).
+- '<color>-background' (text background color).
+- 'big' and 'small' (text size).
+- 'underline', 'overline' and 'line-through' (strike through) text
+  decorators.
+
+Where '<color>' can be any of the
+http://en.wikipedia.org/wiki/Web_colors#HTML_color_names[sixteen HTML
+color names].  Examples:
+
+  [red]#Obvious# and [big red yellow-background]*very obvious*.
+
+  [underline]#Underline text#, [overline]#overline text# and
+  [blue line-through]*bold blue and line-through*.
+
+is rendered as:
+
+[red]#Obvious# and [big red yellow-background]*very obvious*.
+
+[underline]#Underline text#, [overline]#overline text# and
+[bold blue line-through]*bold blue and line-through*.
+
+NOTE: Color and text decorator attributes are rendered for XHTML and
+HTML 5 outputs using CSS stylesheets.  The mechanism to implement
+color and text decorator attributes is provided for DocBook toolchains
+via the DocBook 'phrase' element 'role' attribute, but the actual
+rendering is toolchain specific and is not part of the AsciiDoc
+distribution.
+
+[[X52]]
+Constrained and Unconstrained Quotes
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+There are actually two types of quotes:
+
+Constrained quotes
+++++++++++++++++++
+Quoted must be bounded by white space or commonly adjoining
+punctuation characters. These are the most commonly used type of
+quote.
+
+Unconstrained quotes
+++++++++++++++++++++
+Unconstrained quotes have no boundary constraints and can be placed
+anywhere within inline text. For consistency and to make them easier
+to remember unconstrained quotes are double-ups of the `_`, `*`, `+`
+and `#` constrained quotes:
+
+  __unconstrained emphasized text__
+  **unconstrained strong text**
+  ++unconstrained monospaced text++
+  ##unconstrained unquoted text##
+
+The following example emboldens the letter F:
+
+  **F**ile Open...
+
+Superscripts and Subscripts
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Put \^carets on either^ side of the text to be superscripted, put
+\~tildes on either side~ of text to be subscripted.  For example, the
+following line:
+
+  e^πi^+1 = 0. H~2~O and x^10^. Some ^super text^
+  and ~some sub text~
+
+Is rendered like:
+
+e^πi^+1 = 0. H~2~O and x^10^. Some ^super text^
+and ~some sub text~
+
+Superscripts and subscripts are implemented as <<X52,unconstrained
+quotes>> and they can be escaped with a leading backslash and prefixed
+with with an attribute list.
+
+Line Breaks
+~~~~~~~~~~~
+A plus character preceded by at least one space character at the end
+of a non-blank line forces a line break. It generates a line break
+(`br`) tag for HTML outputs and a custom XML `asciidoc-br` processing
+instruction for DocBook outputs. The `asciidoc-br` processing
+instruction is handled by <<X43,a2x(1)>>.
+
+Page Breaks
+~~~~~~~~~~~
+A line of three or more less-than (`<<<`) characters will generate a
+hard page break in DocBook and printed HTML outputs.  It uses the CSS
+`page-break-after` property for HTML outputs and a custom XML
+`asciidoc-pagebreak` processing instruction for DocBook outputs. The
+`asciidoc-pagebreak` processing instruction is handled by
+<<X43,a2x(1)>>. Hard page breaks are sometimes handy but as a general
+rule you should let your page processor generate page breaks for you.
+
+Rulers
+~~~~~~
+A line of three or more apostrophe characters will generate a ruler
+line.  It generates a ruler (`hr`) tag for HTML outputs and a custom
+XML `asciidoc-hr` processing instruction for DocBook outputs. The
+`asciidoc-hr` processing instruction is handled by <<X43,a2x(1)>>.
+
+Tabs
+~~~~
+By default tab characters input files will translated to 8 spaces. Tab
+expansion is set with the 'tabsize' entry in the configuration file
+`[miscellaneous]` section and can be overridden in included files by
+setting a 'tabsize' attribute in the `include` macro's attribute list.
+For example:
+
+  include::addendum.txt[tabsize=2]
+
+The tab size can also be set using the attribute command-line option,
+for example `--attribute tabsize=4`
+
+Replacements
+~~~~~~~~~~~~
+The following replacements are defined in the default AsciiDoc
+configuration:
+
+  (C) copyright, (TM) trademark, (R) registered trademark,
+  -- em dash, ... ellipsis, -> right arrow, <- left arrow, => right
+  double arrow, <= left double arrow.
+
+Which are rendered as:
+
+(C) copyright, (TM) trademark, (R) registered trademark,
+-- em dash, ... ellipsis, -> right arrow, <- left arrow, => right
+double arrow, <= left double arrow.
+
+You can also include arbitrary entity references in the AsciiDoc
+source. Examples:
+
+  ➊ ¶
+
+renders:
+
+➊ ¶
+
+To render a replacement literally escape it with a leading back-slash.
+
+The <<X7,Configuration Files>> section explains how to configure your
+own replacements.
+
+Special Words
+~~~~~~~~~~~~~
+Words defined in `[specialwords]` configuration file sections are
+automatically marked up without having to be explicitly notated.
+
+The <<X7,Configuration Files>> section explains how to add and replace
+special words.
+
+
+[[X17]]
+Titles
+------
+Document and section titles can be in either of two formats:
+
+Two line titles
+~~~~~~~~~~~~~~~
+A two line title consists of a title line, starting hard against the
+left margin, and an underline. Section underlines consist a repeated
+character pairs spanning the width of the preceding title (give or
+take up to two characters):
+
+The default title underlines for each of the document levels are:
+
+
+  Level 0 (top level):     ======================
+  Level 1:                 ----------------------
+  Level 2:                 ~~~~~~~~~~~~~~~~~~~~~~
+  Level 3:                 ^^^^^^^^^^^^^^^^^^^^^^
+  Level 4 (bottom level):  ++++++++++++++++++++++
+
+Examples:
+
+  Level One Section Title
+  -----------------------
+
+  Level 2 Subsection Title
+  ~~~~~~~~~~~~~~~~~~~~~~~~
+
+[[X46]]
+One line titles
+~~~~~~~~~~~~~~~
+One line titles consist of a single line delimited on either side by
+one or more equals characters (the number of equals characters
+corresponds to the section level minus one).  Here are some examples:
+
+  = Document Title (level 0) =
+  == Section title (level 1) ==
+  === Section title (level 2) ===
+  ==== Section title (level 3) ====
+  ===== Section title (level 4) =====
+
+[NOTE]
+=====================================================================
+- One or more spaces must fall between the title and the delimiters.
+- The trailing title delimiter is optional.
+- The one-line title syntax can be changed by editing the
+  configuration file `[titles]` section `sect0`...`sect4` entries.
+=====================================================================
+
+Floating titles
+~~~~~~~~~~~~~~~
+Setting the title's first positional attribute or 'style' attribute to
+'float' generates a free-floating title. A free-floating title is
+rendered just like a normal section title but is not formally
+associated with a text body and is not part of the regular section
+hierarchy so the normal ordering rules do not apply. Floating titles
+can also be used in contexts where section titles are illegal: for
+example sidebar and admonition blocks.  Example:
+
+  [float]
+  The second day
+  ~~~~~~~~~~~~~~
+
+Floating titles do not appear in a document's table of contents.
+
+
+[[X42]]
+Block Titles
+------------
+A 'BlockTitle' element is a single line beginning with a period
+followed by the title text. A BlockTitle is applied to the immediately
+following Paragraph, DelimitedBlock, List, Table or BlockMacro. For
+example:
+
+........................
+.Notes
+- Note 1.
+- Note 2.
+........................
+
+is rendered as:
+
+.Notes
+- Note 1.
+- Note 2.
+
+
+[[X41]]
+BlockId Element
+---------------
+A 'BlockId' is a single line block element containing a unique
+identifier enclosed in double square brackets. It is used to assign an
+identifier to the ensuing block element. For example:
+
+  [[chapter-titles]]
+  Chapter titles can be ...
+
+The preceding example identifies the ensuing paragraph so it can be
+referenced from other locations, for example with
+`<<chapter-titles,chapter titles>>`.
+
+'BlockId' elements can be applied to Title, Paragraph, List,
+DelimitedBlock, Table and BlockMacro elements.  The BlockId element
+sets the `{id}` attribute for substitution in the subsequent block's
+markup template. If a second positional argument is supplied it sets
+the `{reftext}` attribute which is used to set the DocBook `xreflabel`
+attribute.
+
+The 'BlockId' element has the same syntax and serves the same function
+to the <<X30,anchor inline macro>>.
+
+[[X79]]
+AttributeList Element
+---------------------
+An 'AttributeList' block element is an <<X21,attribute list>> on a
+line by itself:
+
+- 'AttributeList' attributes are only applied to the immediately
+  following block element -- the attributes are made available to the
+  block's markup template.
+- Multiple contiguous 'AttributeList' elements are additively combined
+  in the order they appear..
+- The first positional attribute in the list is often used to specify
+  the ensuing element's <<X23,style>>.
+
+Attribute value substitution
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+By default, only substitutions that take place inside attribute list
+values are attribute references, this is because not all attributes
+are destined to be marked up and rendered as text (for example the
+table 'cols' attribute). To perform normal inline text substitutions
+(special characters, quotes, macros, replacements) on an attribute
+value you need to enclose it in single quotes. In the following quote
+block the second attribute value in the AttributeList is quoted to
+ensure the 'http' macro is expanded to a hyperlink.
+
+---------------------------------------------------------------------
+[quote,'http://en.wikipedia.org/wiki/Samuel_Johnson[Samuel Johnson]']
+_____________________________________________________________________
+Sir, a woman's preaching is like a dog's walking on his hind legs. It
+is not done well; but you are surprised to find it done at all.
+_____________________________________________________________________
+---------------------------------------------------------------------
+
+Common attributes
+~~~~~~~~~~~~~~~~~
+Most block elements support the following attributes:
+
+[cols="1e,1,5a",frame="topbot",options="header"]
+|====================================================================
+|Name |Backends |Description
+
+|id |html4, html5, xhtml11, docbook |
+Unique identifier typically serve as link targets.
+Can also be set by the 'BlockId' element.
+
+|role |html4, html5, xhtml11, docbook |
+Role contains a string used to classify or subclassify an element and
+can be applied to AsciiDoc block elements.  The AsciiDoc 'role'
+attribute is translated to the 'role' attribute in DocBook outputs and
+is included in the 'class' attribute in HTML outputs, in this respect
+it behaves like the <<X96,quoted text role attribute>>.
+
+DocBook XSL Stylesheets translate DocBook 'role' attributes to HTML
+'class' attributes; CSS can then be used
+http://www.sagehill.net/docbookxsl/UsingCSS.html[to style the
+generated HTML].
+
+|reftext |docbook |
+'reftext' is used to set the DocBook 'xreflabel' attribute.
+The 'reftext' attribute can an also be set by the 'BlockId' element.
+
+|====================================================================
+
+
+Paragraphs
+----------
+Paragraphs are blocks of text terminated by a blank line, the end of
+file, or the start of a delimited block or a list.  There are three
+paragraph syntaxes: normal, indented (literal) and admonition which
+are rendered, by default, with the corresponding paragraph style.
+
+Each syntax has a default style, but you can explicitly apply any
+paragraph style to any paragraph syntax. You can also apply
+<<X104,delimited block>> styles to single paragraphs.
+
+The built-in paragraph styles are: 'normal', 'literal', 'verse',
+'quote', 'listing', 'TIP', 'NOTE', 'IMPORTANT', 'WARNING', 'CAUTION',
+'abstract', 'partintro', 'comment', 'example', 'sidebar', 'source',
+'music', 'latex', 'graphviz'.
+
+normal paragraph syntax
+~~~~~~~~~~~~~~~~~~~~~~~
+Normal paragraph syntax consists of one or more non-blank lines of
+text. The first line must start hard against the left margin (no
+intervening white space). The default processing expectation is that
+of a normal paragraph of text.
+
+[[X85]]
+literal paragraph syntax
+~~~~~~~~~~~~~~~~~~~~~~~~
+Literal paragraphs are rendered verbatim in a monospaced font without
+any distinguishing background or border.  By default there is no text
+formatting or substitutions within Literal paragraphs apart from
+Special Characters and Callouts.
+
+The 'literal' style is applied implicitly to indented paragraphs i.e.
+where the first line of the paragraph is indented by one or more space
+or tab characters.  For example:
+
+---------------------------------------------------------------------
+  Consul *necessitatibus* per id,
+  consetetur, eu pro everti postulant
+  homero verear ea mea, qui.
+---------------------------------------------------------------------
+
+Renders:
+
+  Consul *necessitatibus* per id,
+  consetetur, eu pro everti postulant
+  homero verear ea mea, qui.
+
+NOTE: Because <<X64,lists>> can be indented it's possible for your
+indented paragraph to be misinterpreted as a list -- in situations
+like this apply the 'literal' style to a normal paragraph.
+
+Instead of using a paragraph indent you could apply the 'literal'
+style explicitly, for example:
+
+---------------------------------------------------------------------
+[literal]
+Consul *necessitatibus* per id,
+consetetur, eu pro everti postulant
+homero verear ea mea, qui.
+---------------------------------------------------------------------
+
+Renders:
+
+[literal]
+Consul *necessitatibus* per id,
+consetetur, eu pro everti postulant
+homero verear ea mea, qui.
+
+[[X94]]
+quote and verse paragraph styles
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The optional 'attribution' and 'citetitle' attributes (positional
+attributes 2 and 3) specify the author and source respectively.
+
+The 'verse' style retains the line breaks, for example:
+
+---------------------------------------------------------------------
+[verse, William Blake, from Auguries of Innocence]
+To see a world in a grain of sand,
+And a heaven in a wild flower,
+Hold infinity in the palm of your hand,
+And eternity in an hour.
+---------------------------------------------------------------------
+
+Which is rendered as:
+
+[verse, William Blake, from Auguries of Innocence]
+To see a world in a grain of sand,
+And a heaven in a wild flower,
+Hold infinity in the palm of your hand,
+And eternity in an hour.
+
+The 'quote' style flows the text at left and right margins, for
+example:
+
+---------------------------------------------------------------------
+[quote, Bertrand Russell, The World of Mathematics (1956)]
+A good notation has subtlety and suggestiveness which at times makes
+it almost seem like a live teacher.
+---------------------------------------------------------------------
+
+Which is rendered as:
+
+[quote, Bertrand Russell, The World of Mathematics (1956)]
+A good notation has subtlety and suggestiveness which at times makes
+it almost seem like a live teacher.
+
+[[X28]]
+Admonition Paragraphs
+~~~~~~~~~~~~~~~~~~~~~
+'TIP', 'NOTE', 'IMPORTANT', 'WARNING' and 'CAUTION' admonishment
+paragraph styles are generated by placing `NOTE:`, `TIP:`,
+`IMPORTANT:`, `WARNING:` or `CAUTION:` as the first word of the
+paragraph. For example:
+
+  NOTE: This is an example note.
+
+Alternatively, you can specify the paragraph admonition style
+explicitly using an <<X79,AttributeList element>>. For example:
+
+  [NOTE]
+  This is an example note.
+
+Renders:
+
+NOTE: This is an example note.
+
+TIP: If your admonition requires more than a single paragraph use an
+<<X22,admonition block>> instead.
+
+[[X47]]
+Admonition Icons and Captions
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+NOTE: Admonition customization with `icons`, `iconsdir`, `icon` and
+`caption` attributes does not apply when generating DocBook output. If
+you are going the DocBook route then the <<X43,a2x(1)>> `--no-icons`
+and `--icons-dir` options can be used to set the appropriate XSL
+Stylesheets parameters.
+
+By default the asciidoc(1) HTML backends generate text captions
+instead of admonition icon image links. To generate links to icon
+images define the <<X45,`icons`>> attribute, for example using the `-a
+icons` command-line option.
+
+The <<X44,`iconsdir`>> attribute sets the location of linked icon
+images.
+
+You can override the default icon image using the `icon` attribute to
+specify the path of the linked image. For example:
+
+  [icon="./images/icons/wink.png"]
+  NOTE: What lovely war.
+
+Use the `caption` attribute to customize the admonition captions (not
+applicable to `docbook` backend). The following example suppresses the
+icon image and customizes the caption of a 'NOTE' admonition
+(undefining the `icons` attribute with `icons=None` is only necessary
+if <<X45,admonition icons>> have been enabled):
+
+  [icons=None, caption="My Special Note"]
+  NOTE: This is my special note.
+
+This subsection also applies to <<X22,Admonition Blocks>>.
+
+
+[[X104]]
+Delimited Blocks
+----------------
+Delimited blocks are blocks of text enveloped by leading and trailing
+delimiter lines (normally a series of four or more repeated
+characters). The behavior of Delimited Blocks is specified by entries
+in configuration file `[blockdef-*]` sections.
+
+Predefined Delimited Blocks
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+AsciiDoc ships with a number of predefined DelimitedBlocks (see the
+`asciidoc.conf` configuration file in the asciidoc(1) program
+directory):
+
+Predefined delimited block underlines:
+
+  CommentBlock:     //////////////////////////
+  PassthroughBlock: ++++++++++++++++++++++++++
+  ListingBlock:     --------------------------
+  LiteralBlock:     ..........................
+  SidebarBlock:     **************************
+  QuoteBlock:       __________________________
+  ExampleBlock:     ==========================
+  OpenBlock:        --
+
+.Default DelimitedBlock substitutions
+[cols="2e,7*^",frame="topbot",options="header,autowidth"]
+|=====================================================
+| |Attributes |Callouts |Macros | Quotes |Replacements
+|Special chars |Special words
+
+|PassthroughBlock |Yes |No  |Yes |No  |No  |No  |No
+|ListingBlock     |No  |Yes |No  |No  |No  |Yes |No
+|LiteralBlock     |No  |Yes |No  |No  |No  |Yes |No
+|SidebarBlock     |Yes |No  |Yes |Yes |Yes |Yes |Yes
+|QuoteBlock       |Yes |No  |Yes |Yes |Yes |Yes |Yes
+|ExampleBlock     |Yes |No  |Yes |Yes |Yes |Yes |Yes
+|OpenBlock        |Yes |No  |Yes |Yes |Yes |Yes |Yes
+|=====================================================
+
+Listing Blocks
+~~~~~~~~~~~~~~
+'ListingBlocks' are rendered verbatim in a monospaced font, they
+retain line and whitespace formatting and are often distinguished by a
+background or border. There is no text formatting or substitutions
+within Listing blocks apart from Special Characters and Callouts.
+Listing blocks are often used for computer output and file listings.
+
+Here's an example:
+
+[listing]
+......................................
+--------------------------------------
+#include <stdio.h>
+
+int main() {
+   printf("Hello World!\n");
+   exit(0);
+}
+--------------------------------------
+......................................
+
+Which will be rendered like:
+
+--------------------------------------
+#include <stdio.h>
+
+int main() {
+    printf("Hello World!\n");
+    exit(0);
+}
+--------------------------------------
+
+By convention <<X59,filter blocks>> use the listing block syntax and
+are implemented as distinct listing block styles.
+
+[[X65]]
+Literal Blocks
+~~~~~~~~~~~~~~
+'LiteralBlocks' are rendered just like <<X85,literal paragraphs>>.
+Example:
+
+---------------------------------------------------------------------
+...................................
+Consul *necessitatibus* per id,
+consetetur, eu pro everti postulant
+homero verear ea mea, qui.
+...................................
+---------------------------------------------------------------------
+
+Renders:
+...................................
+Consul *necessitatibus* per id,
+consetetur, eu pro everti postulant
+homero verear ea mea, qui.
+...................................
+
+If the 'listing' style is applied to a LiteralBlock it will be
+rendered as a ListingBlock (this is handy if you have a listing
+containing a ListingBlock).
+
+Sidebar Blocks
+~~~~~~~~~~~~~~
+A sidebar is a short piece of text presented outside the narrative
+flow of the main text. The sidebar is normally presented inside a
+bordered box to set it apart from the main text.
+
+The sidebar body is treated like a normal section body.
+
+Here's an example:
+
+---------------------------------------------------------------------
+.An Example Sidebar
+************************************************
+Any AsciiDoc SectionBody element (apart from
+SidebarBlocks) can be placed inside a sidebar.
+************************************************
+---------------------------------------------------------------------
+
+Which will be rendered like:
+
+.An Example Sidebar
+************************************************
+Any AsciiDoc SectionBody element (apart from
+SidebarBlocks) can be placed inside a sidebar.
+************************************************
+
+[[X26]]
+Comment Blocks
+~~~~~~~~~~~~~~
+The contents of 'CommentBlocks' are not processed; they are useful for
+annotations and for excluding new or outdated content that you don't
+want displayed. CommentBlocks are never written to output files.
+Example:
+
+---------------------------------------------------------------------
+//////////////////////////////////////////
+CommentBlock contents are not processed by
+asciidoc(1).
+//////////////////////////////////////////
+---------------------------------------------------------------------
+
+See also <<X25,Comment Lines>>.
+
+NOTE: System macros are executed inside comment blocks.
+
+[[X76]]
+Passthrough Blocks
+~~~~~~~~~~~~~~~~~~
+By default the block contents is subject only to 'attributes' and
+'macros' substitutions (use an explicit 'subs' attribute to apply
+different substitutions).  PassthroughBlock content will often be
+backend specific. Here's an example:
+
+---------------------------------------------------------------------
+[subs="quotes"]
+++++++++++++++++++++++++++++++++++++++
+<table border="1"><tr>
+  <td>*Cell 1*</td>
+  <td>*Cell 2*</td>
+</tr></table>
+++++++++++++++++++++++++++++++++++++++
+---------------------------------------------------------------------
+
+The following styles can be applied to passthrough blocks:
+
+pass::
+  No substitutions are performed. This is equivalent to `subs="none"`.
+
+asciimath, latexmath::
+  By default no substitutions are performed, the contents are rendered
+  as <<X78,mathematical formulas>>.
+
+Quote Blocks
+~~~~~~~~~~~~
+'QuoteBlocks' are used for quoted passages of text. There are two
+styles: 'quote' and 'verse'. The style behavior is identical to
+<<X94,quote and verse paragraphs>> except that blocks can contain
+multiple paragraphs and, in the case of the 'quote' style, other
+section elements.  The first positional attribute sets the style, if
+no attributes are specified the 'quote' style is used.  The optional
+'attribution' and 'citetitle' attributes (positional attributes 2 and
+3) specify the quote's author and source. For example:
+
+---------------------------------------------------------------------
+[quote, Sir Arthur Conan Doyle, The Adventures of Sherlock Holmes]
+____________________________________________________________________
+As he spoke there was the sharp sound of horses' hoofs and
+grating wheels against the curb, followed by a sharp pull at the
+bell. Holmes whistled.
+
+"A pair, by the sound," said he. "Yes," he continued, glancing
+out of the window. "A nice little brougham and a pair of
+beauties. A hundred and fifty guineas apiece. There's money in
+this case, Watson, if there is nothing else."
+____________________________________________________________________
+---------------------------------------------------------------------
+
+Which is rendered as:
+
+[quote, Sir Arthur Conan Doyle, The Adventures of Sherlock Holmes]
+____________________________________________________________________
+As he spoke there was the sharp sound of horses' hoofs and
+grating wheels against the curb, followed by a sharp pull at the
+bell. Holmes whistled.
+
+"A pair, by the sound," said he. "Yes," he continued, glancing
+out of the window. "A nice little brougham and a pair of
+beauties. A hundred and fifty guineas apiece. There's money in
+this case, Watson, if there is nothing else."
+____________________________________________________________________
+
+[[X48]]
+Example Blocks
+~~~~~~~~~~~~~~
+'ExampleBlocks' encapsulate the DocBook Example element and are used
+for, well, examples.  Example blocks can be titled by preceding them
+with a 'BlockTitle'.  DocBook toolchains will normally automatically
+number examples and generate a 'List of Examples' backmatter section.
+
+Example blocks are delimited by lines of equals characters and can
+contain any block elements apart from Titles, BlockTitles and
+Sidebars) inside an example block. For example:
+
+---------------------------------------------------------------------
+.An example
+=====================================================================
+Qui in magna commodo, est labitur dolorum an. Est ne magna primis
+adolescens.
+=====================================================================
+---------------------------------------------------------------------
+
+Renders:
+
+.An example
+=====================================================================
+Qui in magna commodo, est labitur dolorum an. Est ne magna primis
+adolescens.
+=====================================================================
+
+A title prefix that can be inserted with the `caption` attribute
+(HTML backends). For example:
+
+---------------------------------------------------------------------
+[caption="Example 1: "]
+.An example with a custom caption
+=====================================================================
+Qui in magna commodo, est labitur dolorum an. Est ne magna primis
+adolescens.
+=====================================================================
+---------------------------------------------------------------------
+
+[[X22]]
+Admonition Blocks
+~~~~~~~~~~~~~~~~~
+The 'ExampleBlock' definition includes a set of admonition
+<<X23,styles>> ('NOTE', 'TIP', 'IMPORTANT', 'WARNING', 'CAUTION') for
+generating admonition blocks (admonitions containing more than a
+<<X28,single paragraph>>).  Just precede the 'ExampleBlock' with an
+attribute list specifying the admonition style name. For example:
+
+---------------------------------------------------------------------
+[NOTE]
+.A NOTE admonition block
+=====================================================================
+Qui in magna commodo, est labitur dolorum an. Est ne magna primis
+adolescens.
+
+. Fusce euismod commodo velit.
+. Vivamus fringilla mi eu lacus.
+  .. Fusce euismod commodo velit.
+  .. Vivamus fringilla mi eu lacus.
+. Donec eget arcu bibendum
+  nunc consequat lobortis.
+=====================================================================
+---------------------------------------------------------------------
+
+Renders:
+
+[NOTE]
+.A NOTE admonition block
+=====================================================================
+Qui in magna commodo, est labitur dolorum an. Est ne magna primis
+adolescens.
+
+. Fusce euismod commodo velit.
+. Vivamus fringilla mi eu lacus.
+  .. Fusce euismod commodo velit.
+  .. Vivamus fringilla mi eu lacus.
+. Donec eget arcu bibendum
+  nunc consequat lobortis.
+=====================================================================
+
+See also <<X47,Admonition Icons and Captions>>.
+
+[[X29]]
+Open Blocks
+~~~~~~~~~~~
+Open blocks are special:
+
+- The open block delimiter is line containing two hyphen characters
+  (instead of four or more repeated characters).
+
+- They can be used to group block elements for <<X15,List item
+  continuation>>.
+
+- Open blocks can be styled to behave like any other type of delimited
+  block.  The  following built-in styles can be applied to open
+  blocks: 'literal', 'verse', 'quote', 'listing', 'TIP', 'NOTE',
+  'IMPORTANT', 'WARNING', 'CAUTION', 'abstract', 'partintro',
+  'comment', 'example', 'sidebar', 'source', 'music', 'latex',
+  'graphviz'. For example, the following open block and listing block
+  are functionally identical:
+
+  [listing]
+  --
+  Lorum ipsum ...
+  --
+
+  ---------------
+  Lorum ipsum ...
+  ---------------
+
+- An unstyled open block groups section elements but otherwise does
+  nothing.
+
+Open blocks are used to generate document abstracts and book part
+introductions:
+
+- Apply the 'abstract' style to generate an abstract, for example:
+
+  [abstract]
+  --
+  In this paper we will ...
+  --
+
+. Apply the 'partintro' style to generate a book part introduction for
+  a multi-part book, for example:
+
+  [partintro]
+  .Optional part introduction title
+  --
+  Optional part introduction goes here.
+  --
+
+
+[[X64]]
+Lists
+-----
+.List types
+- Bulleted lists. Also known as itemized or unordered lists.
+- Numbered lists. Also called ordered lists.
+- Labeled lists. Sometimes called variable or definition lists.
+- Callout lists (a list of callout annotations).
+
+.List behavior
+- List item indentation is optional and does not determine nesting,
+  indentation does however make the source more readable.
+- Another list or a literal paragraph immediately following a list
+  item will be implicitly included in the list item; use <<X15, list
+  item continuation>> to explicitly append other block elements to a
+  list item.
+- A comment block or a comment line block macro element will terminate
+  a list -- use inline comment lines to put comments inside lists.
+- The `listindex` <<X60,intrinsic attribute>> is the current list item
+  index (1..). If this attribute is used outside a list then it's value
+  is the number of items in the most recently closed list. Useful for
+  displaying the number of items in a list.
+
+Bulleted Lists
+~~~~~~~~~~~~~~
+Bulleted list items start with a single dash or one to five asterisks
+followed by some white space then some text. Bulleted list syntaxes
+are:
+
+...................
+- List item.
+* List item.
+** List item.
+*** List item.
+**** List item.
+***** List item.
+...................
+
+Numbered Lists
+~~~~~~~~~~~~~~
+List item numbers are explicit or implicit.
+
+.Explicit numbering
+List items begin with a number followed by some white space then the
+item text. The numbers can be decimal (arabic), roman (upper or lower
+case) or alpha (upper or lower case). Decimal and alpha numbers are
+terminated with a period, roman numbers are terminated with a closing
+parenthesis. The different terminators are necessary to ensure 'i',
+'v' and 'x' roman numbers are are distinguishable from 'x', 'v' and
+'x' alpha numbers. Examples:
+
+.....................................................................
+1.   Arabic (decimal) numbered list item.
+a.   Lower case alpha (letter) numbered list item.
+F.   Upper case alpha (letter) numbered list item.
+iii) Lower case roman numbered list item.
+IX)  Upper case roman numbered list item.
+.....................................................................
+
+.Implicit numbering
+List items begin one to five period characters, followed by some white
+space then the item text. Examples:
+
+.....................................................................
+. Arabic (decimal) numbered list item.
+.. Lower case alpha (letter) numbered list item.
+... Lower case roman numbered list item.
+.... Upper case alpha (letter) numbered list item.
+..... Upper case roman numbered list item.
+.....................................................................
+
+You can use the 'style' attribute (also the first positional
+attribute) to specify an alternative numbering style.  The numbered
+list style can be one of the following values: 'arabic', 'loweralpha',
+'upperalpha', 'lowerroman', 'upperroman'.
+
+Here are some examples of bulleted and numbered lists:
+
+---------------------------------------------------------------------
+- Praesent eget purus quis magna eleifend eleifend.
+  1. Fusce euismod commodo velit.
+    a. Fusce euismod commodo velit.
+    b. Vivamus fringilla mi eu lacus.
+    c. Donec eget arcu bibendum nunc consequat lobortis.
+  2. Vivamus fringilla mi eu lacus.
+    i)  Fusce euismod commodo velit.
+    ii) Vivamus fringilla mi eu lacus.
+  3. Donec eget arcu bibendum nunc consequat lobortis.
+  4. Nam fermentum mattis ante.
+- Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
+  * Fusce euismod commodo velit.
+  ** Qui in magna commodo, est labitur dolorum an. Est ne magna primis
+     adolescens. Sit munere ponderum dignissim et. Minim luptatum et
+     vel.
+  ** Vivamus fringilla mi eu lacus.
+  * Donec eget arcu bibendum nunc consequat lobortis.
+- Nulla porttitor vulputate libero.
+  . Fusce euismod commodo velit.
+  . Vivamus fringilla mi eu lacus.
+[upperroman]
+    .. Fusce euismod commodo velit.
+    .. Vivamus fringilla mi eu lacus.
+  . Donec eget arcu bibendum nunc consequat lobortis.
+---------------------------------------------------------------------
+
+Which render as:
+
+- Praesent eget purus quis magna eleifend eleifend.
+  1. Fusce euismod commodo velit.
+    a. Fusce euismod commodo velit.
+    b. Vivamus fringilla mi eu lacus.
+    c. Donec eget arcu bibendum nunc consequat lobortis.
+  2. Vivamus fringilla mi eu lacus.
+    i)  Fusce euismod commodo velit.
+    ii) Vivamus fringilla mi eu lacus.
+  3. Donec eget arcu bibendum nunc consequat lobortis.
+  4. Nam fermentum mattis ante.
+- Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
+  * Fusce euismod commodo velit.
+  ** Qui in magna commodo, est labitur dolorum an. Est ne magna primis
+     adolescens. Sit munere ponderum dignissim et. Minim luptatum et
+     vel.
+  ** Vivamus fringilla mi eu lacus.
+  * Donec eget arcu bibendum nunc consequat lobortis.
+- Nulla porttitor vulputate libero.
+  . Fusce euismod commodo velit.
+  . Vivamus fringilla mi eu lacus.
+[upperroman]
+    .. Fusce euismod commodo velit.
+    .. Vivamus fringilla mi eu lacus.
+  . Donec eget arcu bibendum nunc consequat lobortis.
+
+A predefined 'compact' option is available to bulleted and numbered
+lists -- this translates to the DocBook 'spacing="compact"' lists
+attribute which may or may not be processed by the DocBook toolchain.
+Example:
+
+  [options="compact"]
+  - Compact list item.
+  - Another compact list item.
+
+TIP: To apply the 'compact' option globally define a document-wide
+'compact-option' attribute, e.g. using the `-a compact-option`
+command-line option.
+
+You can set the list start number using the 'start' attribute (works
+for HTML outputs and DocBook outputs processed by DocBook XSL
+Stylesheets). Example:
+
+  [start=7]
+  . List item 7.
+  . List item 8.
+
+Labeled Lists
+~~~~~~~~~~~~~
+Labeled list items consist of one or more text labels followed by the
+text of the list item.
+
+An item label begins a line with an alphanumeric character hard
+against the left margin and ends with two, three or four colons or two
+semi-colons. A list item can have multiple labels, one per line.
+
+The list item text consists of one or more lines of text starting
+after the last label (either on the same line or a new line) and can
+be followed by nested List or ListParagraph elements. Item text can be
+optionally indented.
+
+Here are some examples:
+
+---------------------------------------------------------------------
+In::
+Lorem::
+  Fusce euismod commodo velit.
+
+  Fusce euismod commodo velit.
+
+Ipsum:: Vivamus fringilla mi eu lacus.
+  * Vivamus fringilla mi eu lacus.
+  * Donec eget arcu bibendum nunc consequat lobortis.
+Dolor::
+  Donec eget arcu bibendum nunc consequat lobortis.
+  Suspendisse;;
+    A massa id sem aliquam auctor.
+  Morbi;;
+    Pretium nulla vel lorem.
+  In;;
+    Dictum mauris in urna.
+    Vivamus::: Fringilla mi eu lacus.
+    Donec:::   Eget arcu bibendum nunc consequat lobortis.
+---------------------------------------------------------------------
+
+Which render as:
+
+In::
+Lorem::
+  Fusce euismod commodo velit.
+
+  Fusce euismod commodo velit.
+
+Ipsum:: Vivamus fringilla mi eu lacus.
+  * Vivamus fringilla mi eu lacus.
+  * Donec eget arcu bibendum nunc consequat lobortis.
+Dolor::
+  Donec eget arcu bibendum nunc consequat lobortis.
+  Suspendisse;;
+    A massa id sem aliquam auctor.
+  Morbi;;
+    Pretium nulla vel lorem.
+  In;;
+    Dictum mauris in urna.
+    Vivamus::: Fringilla mi eu lacus.
+    Donec:::   Eget arcu bibendum nunc consequat lobortis.
+
+Horizontal labeled list style
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+The 'horizontal' labeled list style (also the first positional
+attribute) places the list text side-by-side with the label instead of
+under the label. Here is an example:
+
+---------------------------------------------------------------------
+[horizontal]
+*Lorem*:: Fusce euismod commodo velit.  Qui in magna commodo, est
+labitur dolorum an. Est ne magna primis adolescens.
+
+  Fusce euismod commodo velit.
+
+*Ipsum*:: Vivamus fringilla mi eu lacus.
+- Vivamus fringilla mi eu lacus.
+- Donec eget arcu bibendum nunc consequat lobortis.
+
+*Dolor*::
+  - Vivamus fringilla mi eu lacus.
+  - Donec eget arcu bibendum nunc consequat lobortis.
+
+---------------------------------------------------------------------
+
+Which render as:
+
+[horizontal]
+*Lorem*:: Fusce euismod commodo velit.  Qui in magna commodo, est
+labitur dolorum an. Est ne magna primis adolescens.
+
+  Fusce euismod commodo velit.
+
+*Ipsum*:: Vivamus fringilla mi eu lacus.
+- Vivamus fringilla mi eu lacus.
+- Donec eget arcu bibendum nunc consequat lobortis.
+
+*Dolor*::
+  - Vivamus fringilla mi eu lacus.
+  - Donec eget arcu bibendum nunc consequat lobortis.
+
+[NOTE]
+=====================================================================
+- Current PDF toolchains do not make a good job of determining
+  the relative column widths for horizontal labeled lists.
+- Nested horizontal labeled lists will generate DocBook validation
+  errors because the 'DocBook XML V4.2' DTD does not permit nested
+  informal tables (although <<X13,DocBook XSL Stylesheets>> and
+  <<X31,dblatex>> process them correctly).
+- The label width can be set as a percentage of the total width by
+  setting the 'width' attribute e.g. `width="10%"`
+=====================================================================
+
+Question and Answer Lists
+~~~~~~~~~~~~~~~~~~~~~~~~~
+AsciiDoc comes pre-configured with a 'qanda' style labeled list for generating
+DocBook question and answer (Q&A) lists. Example:
+
+---------------------------------------------------------------------
+[qanda]
+Question one::
+        Answer one.
+Question two::
+        Answer two.
+---------------------------------------------------------------------
+
+Renders:
+
+[qanda]
+Question one::
+        Answer one.
+Question two::
+        Answer two.
+
+Glossary Lists
+~~~~~~~~~~~~~~
+AsciiDoc comes pre-configured with a 'glossary' style labeled list for
+generating DocBook glossary lists. Example:
+
+---------------------------------------------------------------------
+[glossary]
+A glossary term::
+    The corresponding definition.
+A second glossary term::
+    The corresponding definition.
+---------------------------------------------------------------------
+
+For working examples see the `article.txt` and `book.txt` documents in
+the AsciiDoc `./doc` distribution directory.
+
+NOTE: To generate valid DocBook output glossary lists must be located
+in a section that uses the 'glossary' <<X93,section markup template>>.
+
+Bibliography Lists
+~~~~~~~~~~~~~~~~~~
+AsciiDoc comes with a predefined 'bibliography' bulleted list style
+generating DocBook bibliography entries. Example:
+
+---------------------------------------------------------------------
+[bibliography]
+.Optional list title
+- [[[taoup]]] Eric Steven Raymond. 'The Art of UNIX
+  Programming'. Addison-Wesley. ISBN 0-13-142901-9.
+- [[[walsh-muellner]]] Norman Walsh & Leonard Muellner.
+  'DocBook - The Definitive Guide'. O'Reilly & Associates.
+  1999. ISBN 1-56592-580-7.
+---------------------------------------------------------------------
+
+The `[[[<reference>]]]` syntax is a bibliography entry anchor, it
+generates an anchor named `<reference>` and additionally displays
+`[<reference>]` at the anchor position. For example `[[[taoup]]]`
+generates an anchor named `taoup` that displays `[taoup]` at the
+anchor position. Cite the reference from elsewhere your document using
+`<<taoup>>`, this displays a hyperlink (`[taoup]`) to the
+corresponding bibliography entry anchor.
+
+For working examples see the `article.txt` and `book.txt` documents in
+the AsciiDoc `./doc` distribution directory.
+
+NOTE: To generate valid DocBook output bibliography lists must be
+located in a <<X93,bibliography section>>.
+
+[[X15]]
+List Item Continuation
+~~~~~~~~~~~~~~~~~~~~~~
+Another list or a literal paragraph immediately following a list item
+is implicitly appended to the list item; to append other block
+elements to a list item you need to explicitly join them to the list
+item with a 'list continuation' (a separator line containing a single
+plus character). Multiple block elements can be appended to a list
+item using list continuations (provided they are legal list item
+children in the backend markup).
+
+Here are some examples of list item continuations: list item one
+contains multiple continuations; list item two is continued with an
+<<X29,OpenBlock>> containing multiple elements:
+
+---------------------------------------------------------------------
+1. List item one.
++
+List item one continued with a second paragraph followed by an
+Indented block.
++
+.................
+$ ls *.sh
+$ mv *.sh ~/tmp
+.................
++
+List item continued with a third paragraph.
+
+2. List item two continued with an open block.
++
+--
+This paragraph is part of the preceding list item.
+
+a. This list is nested and does not require explicit item continuation.
++
+This paragraph is part of the preceding list item.
+
+b. List item b.
+
+This paragraph belongs to item two of the outer list.
+--
+---------------------------------------------------------------------
+
+Renders:
+
+1. List item one.
++
+List item one continued with a second paragraph followed by an
+Indented block.
++
+.................
+$ ls *.sh
+$ mv *.sh ~/tmp
+.................
++
+List item continued with a third paragraph.
+
+2. List item two continued with an open block.
++
+--
+This paragraph is part of the preceding list item.
+
+a. This list is nested and does not require explicit item continuation.
++
+This paragraph is part of the preceding list item.
+
+b. List item b.
+
+This paragraph belongs to item two of the outer list.
+--
+
+
+[[X92]]
+Footnotes
+---------
+The shipped AsciiDoc configuration includes three footnote inline
+macros:
+
+`footnote:[<text>]`::
+  Generates a footnote with text `<text>`.
+
+`footnoteref:[<id>,<text>]`::
+  Generates a footnote with a reference ID `<id>` and text `<text>`.
+
+`footnoteref:[<id>]`::
+  Generates a reference to the footnote with ID `<id>`.
+
+The footnote text can span multiple lines.
+
+The 'xhtml11' and 'html5' backends render footnotes dynamically using
+JavaScript; 'html4' outputs do not use JavaScript and leave the
+footnotes inline; 'docbook' footnotes are processed by the downstream
+DocBook toolchain.
+
+Example footnotes:
+
+  A footnote footnote:[An example footnote.];
+  a second footnote with a reference ID footnoteref:[note2,Second footnote.];
+  finally a reference to the second footnote footnoteref:[note2].
+
+Renders:
+
+A footnote footnote:[An example footnote.];
+a second footnote with a reference ID footnoteref:[note2,Second footnote.];
+finally a reference to the second footnote footnoteref:[note2].
+
+
+Indexes
+-------
+The shipped AsciiDoc configuration includes the inline macros for
+generating DocBook index entries.
+
+`indexterm:[<primary>,<secondary>,<tertiary>]`::
+`(((<primary>,<secondary>,<tertiary>)))`::
+    This inline macro generates an index term (the `<secondary>` and
+    `<tertiary>` positional attributes are optional). Example:
+    `indexterm:[Tigers,Big cats]` (or, using the alternative syntax
+    `(((Tigers,Big cats)))`.  Index terms that have secondary and
+    tertiary entries also generate separate index terms for the
+    secondary and tertiary entries. The index terms appear in the
+    index, not the primary text flow.
+
+`indexterm2:[<primary>]`::
+`((<primary>))`::
+    This inline macro generates an index term that appears in both the
+    index and the primary text flow.  The `<primary>` should not be
+    padded to the left or right with white space characters.
+
+For working examples see the `article.txt` and `book.txt` documents in
+the AsciiDoc `./doc` distribution directory.
+
+NOTE: Index entries only really make sense if you are generating
+DocBook markup -- DocBook conversion programs automatically generate
+an index at the point an 'Index' section appears in source document.
+
+
+[[X105]]
+Callouts
+--------
+Callouts are a mechanism for annotating verbatim text (for example:
+source code, computer output and user input). Callout markers are
+placed inside the annotated text while the actual annotations are
+presented in a callout list after the annotated text. Here's an
+example:
+
+---------------------------------------------------------------------
+ .MS-DOS directory listing
+ -----------------------------------------------------
+ 10/17/97   9:04         <DIR>    bin
+ 10/16/97  14:11         <DIR>    DOS            \<1>
+ 10/16/97  14:40         <DIR>    Program Files
+ 10/16/97  14:46         <DIR>    TEMP
+ 10/17/97   9:04         <DIR>    tmp
+ 10/16/97  14:37         <DIR>    WINNT
+ 10/16/97  14:25             119  AUTOEXEC.BAT   \<2>
+  2/13/94   6:21          54,619  COMMAND.COM    \<2>
+ 10/16/97  14:25             115  CONFIG.SYS     \<2>
+ 11/16/97  17:17      61,865,984  pagefile.sys
+  2/13/94   6:21           9,349  WINA20.386     \<3>
+ -----------------------------------------------------
+
+ \<1> This directory holds MS-DOS.
+ \<2> System startup code for DOS.
+ \<3> Some sort of Windows 3.1 hack.
+---------------------------------------------------------------------
+
+Which renders:
+
+.MS-DOS directory listing
+-----------------------------------------------------
+10/17/97   9:04         <DIR>    bin
+10/16/97  14:11         <DIR>    DOS            <1>
+10/16/97  14:40         <DIR>    Program Files
+10/16/97  14:46         <DIR>    TEMP
+10/17/97   9:04         <DIR>    tmp
+10/16/97  14:37         <DIR>    WINNT
+10/16/97  14:25             119  AUTOEXEC.BAT   <2>
+ 2/13/94   6:21          54,619  COMMAND.COM    <2>
+10/16/97  14:25             115  CONFIG.SYS     <2>
+11/16/97  17:17      61,865,984  pagefile.sys
+ 2/13/94   6:21           9,349  WINA20.386     <3>
+-----------------------------------------------------
+
+<1> This directory holds MS-DOS.
+<2> System startup code for DOS.
+<3> Some sort of Windows 3.1 hack.
+
+.Explanation
+- The callout marks are whole numbers enclosed in angle brackets --
+  they refer to the correspondingly numbered item in the following
+  callout list.
+- By default callout marks are confined to 'LiteralParagraphs',
+  'LiteralBlocks' and 'ListingBlocks' (although this is a
+  configuration file option and can be changed).
+- Callout list item numbering is fairly relaxed -- list items can
+  start with `<n>`, `n>` or `>` where `n` is the optional list item
+  number (in the latter case list items starting with a single `>`
+  character are implicitly numbered starting at one).
+- Callout lists should not be nested.
+- Callout lists start list items hard against the left margin.
+- If you want to present a number inside angle brackets you'll need to
+  escape it with a backslash to prevent it being interpreted as a
+  callout mark.
+
+NOTE: Define the AsciiDoc 'icons' attribute (for example using the `-a
+icons` command-line option) to display callout icons.
+
+Implementation Notes
+~~~~~~~~~~~~~~~~~~~~
+Callout marks are generated by the 'callout' inline macro while
+callout lists are generated using the 'callout' list definition. The
+'callout' macro and 'callout' list are special in that they work
+together. The 'callout' inline macro is not enabled by the normal
+'macros' substitutions option, instead it has its own 'callouts'
+substitution option.
+
+The following attributes are available during inline callout macro
+substitution:
+
+`{index}`::
+    The callout list item index inside the angle brackets.
+`{coid}`::
+    An identifier formatted like `CO<listnumber>-<index>` that
+    uniquely identifies the callout mark. For example `CO2-4`
+    identifies the fourth callout mark in the second set of callout
+    marks.
+
+The `{coids}` attribute can be used during callout list item
+substitution -- it is a space delimited list of callout IDs that refer
+to the explanatory list item.
+
+Including callouts in included code
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+You can annotate working code examples with callouts -- just remember
+to put the callouts inside source code comments. This example displays
+the `test.py` source file (containing a single callout) using the
+'source' (code highlighter) filter:
+
+.AsciiDoc source
+---------------------------------------------------------------------
+ [source,python]
+ -------------------------------------------
+ \include::test.py[]
+ -------------------------------------------
+
+ \<1> Print statement.
+---------------------------------------------------------------------
+
+.Included `test.py` source
+---------------------------------------------------------------------
+print 'Hello World!'   # \<1>
+---------------------------------------------------------------------
+
+
+Macros
+------
+Macros are a mechanism for substituting parametrized text into output
+documents.
+
+Macros have a 'name', a single 'target' argument and an 'attribute
+list'.  The usual syntax is `<name>:<target>[<attrlist>]` (for
+inline macros) and `<name>::<target>[<attrlist>]` (for block
+macros).  Here are some examples:
+
+  http://www.docbook.org/[DocBook.org]
+  include::chapt1.txt[tabsize=2]
+  mailto:srackham@gmail.com[]
+
+.Macro behavior
+- `<name>` is the macro name. It can only contain letters, digits or
+  dash characters and cannot start with a dash.
+- The optional `<target>` cannot contain white space characters.
+- `<attrlist>` is a <<X21,list of attributes>> enclosed in square
+  brackets.
+- `]` characters inside attribute lists must be escaped with a
+  backslash.
+- Expansion of macro references can normally be escaped by prefixing a
+  backslash character (see the AsciiDoc 'FAQ' for examples of
+  exceptions to this rule).
+- Attribute references in block macros are expanded.
+- The substitutions performed prior to Inline macro macro expansion
+  are determined by the inline context.
+- Macros are processed in the order they appear in the configuration
+  file(s).
+- Calls to inline macros can be nested inside different inline macros
+  (an inline macro call cannot contain a nested call to itself).
+- In addition to `<name>`, `<target>` and `<attrlist>` the
+  `<passtext>` and `<subslist>` named groups are available to
+  <<X77,passthrough macros>>. A macro is a passthrough macro if the
+  definition includes a `<passtext>` named group.
+
+Inline Macros
+~~~~~~~~~~~~~
+Inline Macros occur in an inline element context. Predefined Inline
+macros include 'URLs', 'image' and 'link' macros.
+
+URLs
+^^^^
+'http', 'https', 'ftp', 'file', 'mailto' and 'callto' URLs are
+rendered using predefined inline macros.
+
+- If you don't need a custom link caption you can enter the 'http',
+  'https', 'ftp', 'file' URLs and email addresses without any special
+  macro syntax.
+- If the `<attrlist>` is empty the URL is displayed.
+
+Here are some examples:
+
+  http://www.docbook.org/[DocBook.org]
+  http://www.docbook.org/
+  mailto:joe.bloggs@foobar.com[email Joe Bloggs]
+  joe.bloggs@foobar.com
+
+Which are rendered:
+
+http://www.docbook.org/[DocBook.org]
+
+http://www.docbook.org/
+
+mailto:joe.bloggs@foobar.com[email Joe Bloggs]
+
+joe.bloggs@foobar.com
+
+If the `<target>` necessitates space characters use `%20`, for example
+`large%20image.png`.
+
+Internal Cross References
+^^^^^^^^^^^^^^^^^^^^^^^^^
+Two AsciiDoc inline macros are provided for creating hypertext links
+within an AsciiDoc document. You can use either the standard macro
+syntax or the (preferred) alternative.
+
+[[X30]]
+anchor
+++++++
+Used to specify hypertext link targets:
+
+  [[<id>,<xreflabel>]]
+  anchor:<id>[<xreflabel>]
+
+The `<id>` is a unique string that conforms to the output markup's
+anchor syntax. The optional `<xreflabel>` is the text to be displayed
+by captionless 'xref' macros that refer to this anchor. The optional
+`<xreflabel>` is only really useful when generating DocBook output.
+Example anchor:
+
+  [[X1]]
+
+You may have noticed that the syntax of this inline element is the
+same as that of the <<X41,BlockId block element>>, this is no
+coincidence since they are functionally equivalent.
+
+xref
+++++
+Creates a hypertext link to a document anchor.
+
+  <<<id>,<caption>>>
+  xref:<id>[<caption>]
+
+The `<id>` refers to an anchor ID. The optional `<caption>` is the
+link's displayed text. Example:
+
+  <<X21,attribute lists>>
+
+If `<caption>` is not specified then the displayed text is
+auto-generated:
+
+- The AsciiDoc 'xhtml11' and 'html5' backends display the `<id>`
+  enclosed in square brackets.
+- If DocBook is produced the DocBook toolchain is responsible for the
+  displayed text which will normally be the referenced figure, table
+  or section title number followed by the element's title text.
+
+Here is an example:
+
+---------------------------------------------------------------------
+[[tiger_image]]
+.Tyger tyger
+image::tiger.png[]
+
+This can be seen in <<tiger_image>>.
+---------------------------------------------------------------------
+
+Linking to Local Documents
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+Hypertext links to files on the local file system are specified using
+the 'link' inline macro.
+
+  link:<target>[<caption>]
+
+The 'link' macro generates relative URLs. The link macro `<target>` is
+the target file name (relative to the file system location of the
+referring document). The optional `<caption>` is the link's displayed
+text. If `<caption>` is not specified then `<target>` is displayed.
+Example:
+
+  link:downloads/foo.zip[download foo.zip]
+
+You can use the `<filename>#<id>` syntax to refer to an anchor within
+a target document but this usually only makes sense when targeting
+HTML documents.
+
+[[X9]]
+Images
+^^^^^^
+Inline images are inserted into the output document using the 'image'
+macro. The inline syntax is:
+
+  image:<target>[<attributes>]
+
+The contents of the image file `<target>` is displayed. To display the
+image its file format must be supported by the target backend
+application. HTML and DocBook applications normally support PNG or JPG
+files.
+
+`<target>` file name paths are relative to the location of the
+referring document.
+
+[[X55]]
+.Image macro attributes
+- The optional 'alt' attribute is also the first positional attribute,
+  it specifies alternative text which is displayed if the output
+  application is unable to display the image file (see also
+  http://htmlhelp.com/feature/art3.htm[Use of ALT texts in IMGs]). For
+  example:
+
+  image:images/logo.png[Company Logo]
+
+- The optional 'title' attribute provides a title for the image. The
+  <<X49,block image macro>> renders the title alongside the image.
+  The inline image macro displays the title as a popup ``tooltip'' in
+  visual browsers (AsciiDoc HTML outputs only).
+
+- The optional `width` and `height` attributes scale the image size
+  and can be used in any combination. The units are pixels.  The
+  following example scales the previous example to a height of 32
+  pixels:
+
+  image:images/logo.png["Company Logo",height=32]
+
+- The optional `link` attribute is used to link the image to an
+  external document. The following example links a screenshot
+  thumbnail to a full size version:
+
+  image:screen-thumbnail.png[height=32,link="screen.png"]
+
+- The optional `scaledwidth` attribute is only used in DocBook block
+  images (specifically for PDF documents). The following example
+  scales the images to 75% of the available print width:
+
+  image::images/logo.png[scaledwidth="75%",alt="Company Logo"]
+
+- The image `scale` attribute sets the DocBook `imagedata` element
+  `scale` attribute.
+
+- The optional `align` attribute is used for horizontal image
+  alignment.  Allowed values are `center`, `left` and `right`. For
+  example:
+
+  image::images/tiger.png["Tiger image",align="left"]
+
+- The optional `float` attribute floats the image `left` or `right` on
+  the page (works with HTML outputs only, has no effect on DocBook
+  outputs). `float` and `align` attributes are mutually exclusive.
+  Use the `unfloat::[]` block macro to stop floating.
+
+Comment Lines
+^^^^^^^^^^^^^
+See <<X25,comment block macro>>.
+
+Block Macros
+~~~~~~~~~~~~
+A Block macro reference must be contained in a single line separated
+either side by a blank line or a block delimiter.
+
+Block macros behave just like Inline macros, with the following
+differences:
+
+- They occur in a block context.
+- The default syntax is `<name>::<target>[<attrlist>]` (two
+  colons, not one).
+- Markup template section names end in `-blockmacro` instead of
+  `-inlinemacro`.
+
+Block Identifier
+^^^^^^^^^^^^^^^^
+The Block Identifier macro sets the `id` attribute and has the same
+syntax as the <<X30,anchor inline macro>> since it performs
+essentially the same function -- block templates use the `id`
+attribute as a block element ID. For example:
+
+  [[X30]]
+
+This is equivalent to the `[id="X30"]` <<X79,AttributeList element>>).
+
+[[X49]]
+Images
+^^^^^^
+The 'image' block macro is used to display images in a block context.
+The syntax is:
+
+  image::<target>[<attributes>]
+
+The block `image` macro has the same <<X55,macro attributes>> as it's
+<<X9,inline image macro>> counterpart.
+
+Block images can be titled by preceding the 'image' macro with a
+'BlockTitle'.  DocBook toolchains normally number titled block images
+and optionally list them in an automatically generated 'List of
+Figures' backmatter section.
+
+This example:
+
+  .Main circuit board
+  image::images/layout.png[J14P main circuit board]
+
+is equivalent to:
+
+  image::images/layout.png["J14P main circuit board",
+                            title="Main circuit board"]
+
+A title prefix that can be inserted with the `caption` attribute
+(HTML backends). For example:
+
+  .Main circuit board
+  [caption="Figure 2: "]
+  image::images/layout.png[J14P main circuit board]
+
+[[X66]]
+.Embedding images in XHTML documents
+*********************************************************************
+If you define the `data-uri` attribute then images will be embedded in
+XHTML outputs using the
+http://en.wikipedia.org/wiki/Data:_URI_scheme[data URI scheme].  You
+can use the 'data-uri' attribute with the 'xhtml11' and 'html5'
+backends to produce single-file XHTML documents with embedded images
+and CSS, for example:
+
+  $ asciidoc -a data-uri mydocument.txt
+
+[NOTE]
+======
+- All current popular browsers support data URIs, although versions
+  of Internet Explorer prior to version 8 do not.
+- Some browsers limit the size of data URIs.
+======
+*********************************************************************
+
+[[X25]]
+Comment Lines
+^^^^^^^^^^^^^
+Single lines starting with two forward slashes hard up against the
+left margin are treated as comments. Comment lines do not appear in
+the output unless the 'showcomments' attribute is defined.  Comment
+lines have been implemented as both block and inline macros so a
+comment line can appear as a stand-alone block or within block elements
+that support inline macro expansion. Example comment line:
+
+  // This is a comment.
+
+If the 'showcomments' attribute is defined comment lines are written
+to the output:
+
+- In DocBook the comment lines are enclosed by the 'remark' element
+  (which may or may not be rendered by your toolchain).
+- The 'showcomments' attribute does not expose <<X26,Comment Blocks>>.
+  Comment Blocks are never passed to the output.
+
+System Macros
+~~~~~~~~~~~~~
+System macros are block macros that perform a predefined task and are
+hardwired into the asciidoc(1) program.
+
+- You can escape system macros with a leading backslash character
+  (as you can with other macros).
+- The syntax and tasks performed by system macros is built into
+  asciidoc(1) so they don't appear in configuration files.  You can
+  however customize the syntax by adding entries to a configuration
+  file `[macros]` section.
+
+[[X63]]
+Include Macros
+^^^^^^^^^^^^^^
+The `include` and `include1`  system macros to include the contents of
+a named file into the source document.
+
+The `include` macro includes a file as if it were part of the parent
+document -- tabs are expanded and system macros processed. The
+contents of `include1` files are not subject to tab expansion or
+system macro processing nor are attribute or lower priority
+substitutions performed. The `include1` macro's intended use is to
+include verbatim embedded CSS or scripts into configuration file
+headers.  Example:
+
+------------------------------------
+\include::chapter1.txt[tabsize=4]
+------------------------------------
+
+.Include macro behavior
+- If the included file name is specified with a relative path then the
+  path is relative to the location of the referring document.
+- Include macros can appear inside configuration files.
+- Files included from within 'DelimitedBlocks' are read to completion
+  to avoid false end-of-block underline termination.
+- Attribute references are expanded inside the include 'target'; if an
+  attribute is undefined then the included file is silently skipped.
+- The 'tabsize' macro attribute sets the number of space characters to
+  be used for tab expansion in the included file (not applicable to
+  `include1` macro).
+- The 'depth' macro attribute sets the maximum permitted number of
+  subsequent nested includes (not applicable to `include1` macro which
+  does not process nested includes). Setting 'depth' to '1' disables
+  nesting inside the included file. By default, nesting is limited to
+  a depth of ten.
+- If the he 'warnings' attribute is set to 'False' (or any other
+  Python literal that evaluates to boolean false) then no warning
+  message is printed if the included file does not exist. By default
+  'warnings' are enabled.
+- Internally the `include1` macro is translated to the `include1`
+  system attribute which means it must be evaluated in a region where
+  attribute substitution is enabled. To inhibit nested substitution in
+  included files it is preferable to use the `include` macro and set
+  the attribute `depth=1`.
+
+Conditional Inclusion Macros
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Lines of text in the source document can be selectively included or
+excluded from processing based on the existence (or not) of a document
+attribute.
+
+Document text between the `ifdef` and `endif` macros is included if a
+document attribute is defined:
+
+  ifdef::<attribute>[]
+  :
+  endif::<attribute>[]
+
+Document text between the `ifndef` and `endif` macros is not included
+if a document attribute is defined:
+
+  ifndef::<attribute>[]
+  :
+  endif::<attribute>[]
+
+`<attribute>` is an attribute name which is optional in the trailing
+`endif` macro.
+
+If you only want to process a single line of text then the text can be
+put inside the square brackets and the `endif` macro omitted, for
+example:
+
+  ifdef::revnumber[Version number 42]
+
+Is equivalent to:
+
+  ifdef::revnumber[]
+  Version number 42
+  endif::revnumber[]
+
+'ifdef' and 'ifndef' macros also accept multiple attribute names:
+
+- Multiple ',' separated attribute names evaluate to defined if one
+  or more of the attributes is defined, otherwise it's value is
+  undefined.
+- Multiple '+' separated attribute names evaluate to defined if all
+  of the attributes is defined, otherwise it's value is undefined.
+
+Document text between the `ifeval` and `endif` macros is included if
+the Python expression inside the square brackets is true. Example:
+
+  ifeval::[{rs458}==2]
+  :
+  endif::[]
+
+- Document attribute references are expanded before the expression is
+  evaluated.
+- If an attribute reference is undefined then the expression is
+  considered false.
+
+Take a look at the `*.conf` configuration files in the AsciiDoc
+distribution for examples of conditional inclusion macro usage.
+
+Executable system macros
+^^^^^^^^^^^^^^^^^^^^^^^^
+The 'eval', 'sys' and 'sys2' block macros exhibit the same behavior as
+their same named <<X24, system attribute references>>. The difference
+is that system macros occur in a block macro context whereas system
+attributes are confined to inline contexts where attribute
+substitution is enabled.
+
+The following example displays a long directory listing inside a
+literal block:
+
+  ------------------
+  sys::[ls -l *.txt]
+  ------------------
+
+NOTE: There are no block macro versions of the 'eval3' and 'sys3'
+system attributes.
+
+Template System Macro
+^^^^^^^^^^^^^^^^^^^^^
+The `template` block macro allows the inclusion of one configuration
+file template section within another.  The following example includes
+the `[admonitionblock]` section in the `[admonitionparagraph]`
+section:
+
+  [admonitionparagraph]
+  template::[admonitionblock]
+
+.Template macro behavior
+- The `template::[]` macro is useful for factoring configuration file
+  markup.
+- `template::[]` macros cannot be nested.
+- `template::[]` macro expansion is applied after all configuration
+  files have been read.
+
+
+[[X77]]
+Passthrough macros
+~~~~~~~~~~~~~~~~~~
+Passthrough macros are analogous to <<X76,passthrough blocks>> and are
+used to pass text directly to the output. The substitution performed
+on the text is determined by the macro definition but can be overridden
+by the `<subslist>`.  The usual syntax is
+`<name>:<subslist>[<passtext>]` (for inline macros) and
+`<name>::<subslist>[<passtext>]` (for block macros). Passthroughs, by
+definition, take precedence over all other text substitutions.
+
+pass::
+  Inline and block. Passes text unmodified (apart from explicitly
+  specified substitutions). Examples:
+
+  pass:[<q>To be or not to be</q>]
+  pass:attributes,quotes[<u>the '{author}'</u>]
+
+asciimath, latexmath::
+  Inline and block. Passes text unmodified.  Used for
+  <<X78,mathematical formulas>>.
+
+\+++::
+  Inline and block. The triple-plus passthrough is functionally
+  identical to the 'pass' macro but you don't have to escape `]`
+  characters and you can prefix with quoted attributes in the inline
+  version. Example:
+
+  Red [red]+++`sum_(i=1)\^n i=(n(n+1))/2`$+++ AsciiMathML formula
+
+$$::
+  Inline and block. The double-dollar passthrough is functionally
+  identical to the triple-plus passthrough with one exception: special
+  characters are escaped. Example:
+
+  $$`[[a,b],[c,d]]((n),(k))`$$
+
+[[X80]]`::
+  Text quoted with single backtick characters constitutes an 'inline
+  literal' passthrough. The enclosed text is rendered in a monospaced
+  font and is only subject to special character substitution.  This
+  makes sense since monospace text is usually intended to be rendered
+  literally and often contains characters that would otherwise have to
+  be escaped. If you need monospaced text containing inline
+  substitutions use a <<X81,plus character instead of a backtick>>.
+
+Macro Definitions
+~~~~~~~~~~~~~~~~~
+Each entry in the configuration `[macros]` section is a macro
+definition which can take one of the following forms:
+
+`<pattern>=<name>[<subslist]`:: Inline macro definition.
+`<pattern>=#<name>[<subslist]`:: Block macro definition.
+`<pattern>=+<name>[<subslist]`:: System macro definition.
+`<pattern>`:: Delete the existing macro with this `<pattern>`.
+
+`<pattern>` is a Python regular expression and `<name>` is the name of
+a markup template. If `<name>` is omitted then it is the value of the
+regular expression match group named 'name'.  The optional
+`[<subslist]` is a comma-separated list of substitution names enclosed
+in `[]` brackets, it sets the default substitutions for passthrough
+text, if omitted then no passthrough substitutions are performed.
+
+.Pattern named groups
+The following named groups can be used in macro `<pattern>` regular
+expressions and are available as markup template attributes:
+
+name::
+  The macro name.
+
+target::
+  The macro target.
+
+attrlist::
+  The macro attribute list.
+
+passtext::
+  Contents of this group are passed unmodified to the output subject
+  only to 'subslist' substitutions.
+
+subslist::
+  Processed as a comma-separated list of substitution names for
+  'passtext' substitution, overrides the the macro definition
+  'subslist'.
+
+.Here's what happens during macro substitution
+- Each contextually relevant macro 'pattern' from the `[macros]`
+  section is matched against the input source line.
+- If a match is found the text to be substituted is loaded from a
+  configuration markup template section named like
+  `<name>-inlinemacro` or `<name>-blockmacro` (depending on the macro
+  type).
+- Global and macro attribute list attributes are substituted in the
+  macro's markup template.
+- The substituted template replaces the macro reference in the output
+  document.
+
+
+[[X98]]
+HTML 5 audio and video block macros
+-----------------------------------
+The 'html5' backend 'audio' and 'video' block macros generate the HTML
+5 'audio' and 'video' elements respectively.  They follow the usual
+AsciiDoc block macro syntax `<name>::<target>[<attrlist>]` where:
+
+[horizontal]
+`<name>`:: 'audio' or 'video'.
+`<target>`:: The URL or file name of the video or audio file.
+`<attrlist>`:: A list of named attributes (see below).
+
+.Audio macro attributes
+[options="header",cols="1,5",frame="topbot"]
+|====================================================================
+|Name | Value
+|options
+|A comma separated list of one or more of the following items:
+'autoplay', 'loop' which correspond to the same-named HTML 5 'audio'
+element boolean attributes.  By default the player 'controls' are
+enabled, include the 'nocontrols' option value to hide them.
+|====================================================================
+
+.Video macro attributes
+[options="header",cols="1,5",frame="topbot"]
+|====================================================================
+|Name   | Value
+|height | The height of the player in pixels.
+|width  | The width of the player in pixels.
+|poster | The URL or file name of an image representing the video.
+|options
+|A comma separated list of one or more of the following items:
+'autoplay', 'loop' and 'nocontrols'. The 'autoplay' and 'loop' options
+correspond to the same-named HTML 5 'video' element boolean
+attributes.  By default the player 'controls' are enabled, include the
+'nocontrols' option value to hide them.
+|====================================================================
+
+Examples:
+
+---------------------------------------------------------------------
+audio::images/example.ogg[]
+
+video::gizmo.ogv[width=200,options="nocontrols,autoplay"]
+
+.Example video
+video::gizmo.ogv[]
+
+video::http://www.808.dk/pics/video/gizmo.ogv[]
+---------------------------------------------------------------------
+
+If your needs are more complex put raw HTML 5 in a markup block, for
+example (from http://www.808.dk/?code-html-5-video):
+
+---------------------------------------------------------------------
+++++
+<video poster="pics/video/gizmo.jpg" id="video" style="cursor: pointer;" >
+  <source src="pics/video/gizmo.mp4" />
+  <source src="pics/video/gizmo.webm" type="video/webm" />
+  <source src="pics/video/gizmo.ogv" type="video/ogg" />
+  Video not playing? <a href="pics/video/gizmo.mp4">Download file</a> instead.
+</video>
+
+<script type="text/javascript">
+  var video = document.getElementById('video');
+  video.addEventListener('click',function(){
+    video.play();
+  },false);
+</script>
+++++
+---------------------------------------------------------------------
+
+
+Tables
+------
+The AsciiDoc table syntax looks and behaves like other delimited block
+types and supports standard <<X73,block configuration entries>>.
+Formatting is easy to read and, just as importantly, easy to enter.
+
+- Cells and columns can be formatted using built-in customizable styles.
+- Horizontal and vertical cell alignment can be set on columns and
+  cell.
+- Horizontal and vertical cell spanning is supported.
+
+.Use tables sparingly
+*********************************************************************
+When technical users first start creating documents, tables (complete
+with column spanning and table nesting) are often considered very
+important. The reality is that tables are seldom used, even in
+technical documentation.
+
+Try this exercise: thumb through your library of technical books,
+you'll be surprised just how seldom tables are actually used, even
+less seldom are tables containing block elements (such as paragraphs
+or lists) or spanned cells. This is no accident, like figures, tables
+are outside the normal document flow -- tables are for consulting not
+for reading.
+
+Tables are designed for, and should normally only be used for,
+displaying column oriented tabular data.
+*********************************************************************
+
+Example tables
+~~~~~~~~~~~~~~
+
+.Simple table
+[width="15%"]
+|=======
+|1 |2 |A
+|3 |4 |B
+|5 |6 |C
+|=======
+
+.AsciiDoc source
+---------------------------------------------------------------------
+[width="15%"]
+|=======
+|1 |2 |A
+|3 |4 |B
+|5 |6 |C
+|=======
+---------------------------------------------------------------------
+
+.Columns formatted with strong, monospaced and emphasis styles
+[width="50%",cols=">s,^m,e",frame="topbot",options="header,footer"]
+|==========================
+|      2+|Columns 2 and 3
+|1       |Item 1  |Item 1
+|2       |Item 2  |Item 2
+|3       |Item 3  |Item 3
+|4       |Item 4  |Item 4
+|footer 1|footer 2|footer 3
+|==========================
+
+.AsciiDoc source
+---------------------------------------------------------------------
+.An example table
+[width="50%",cols=">s,^m,e",frame="topbot",options="header,footer"]
+|==========================
+|      2+|Columns 2 and 3
+|1       |Item 1  |Item 1
+|2       |Item 2  |Item 2
+|3       |Item 3  |Item 3
+|4       |Item 4  |Item 4
+|footer 1|footer 2|footer 3
+|==========================
+---------------------------------------------------------------------
+
+.Horizontal and vertical source data
+[width="80%",cols="3,^2,^2,10",options="header"]
+|=========================================================
+|Date |Duration |Avg HR |Notes
+
+|22-Aug-08 |10:24 | 157 |
+Worked out MSHR (max sustainable heart rate) by going hard
+for this interval.
+
+|22-Aug-08 |23:03 | 152 |
+Back-to-back with previous interval.
+
+|24-Aug-08 |40:00 | 145 |
+Moderately hard interspersed with 3x 3min intervals (2min
+hard + 1min really hard taking the HR up to 160).
+
+|=========================================================
+
+Short cells can be entered horizontally, longer cells vertically.  The
+default behavior is to strip leading and trailing blank lines within a
+cell. These characteristics aid readability and data entry.
+
+.AsciiDoc source
+---------------------------------------------------------------------
+.Windtrainer workouts
+[width="80%",cols="3,^2,^2,10",options="header"]
+|=========================================================
+|Date |Duration |Avg HR |Notes
+
+|22-Aug-08 |10:24 | 157 |
+Worked out MSHR (max sustainable heart rate) by going hard
+for this interval.
+
+|22-Aug-08 |23:03 | 152 |
+Back-to-back with previous interval.
+
+|24-Aug-08 |40:00 | 145 |
+Moderately hard interspersed with 3x 3min intervals (2min
+hard + 1min really hard taking the HR up to 160).
+
+|=========================================================
+---------------------------------------------------------------------
+
+.A table with externally sourced CSV data
+[format="csv",cols="^1,4*2",options="header"]
+|===================================================
+ID,Customer Name,Contact Name,Customer Address,Phone
+include::customers.csv[]
+|===================================================
+
+.AsciiDoc source
+---------------------------------------------------------------------
+[format="csv",cols="^1,4*2",options="header"]
+|===================================================
+ID,Customer Name,Contact Name,Customer Address,Phone
+\include::customers.csv[]
+|===================================================
+---------------------------------------------------------------------
+
+
+.Cell spans, alignments and styles
+[cols="e,m,^,>s",width="25%"]
+|============================
+|1 >s|2 |3 |4
+^|5 2.2+^.^|6 .3+<.>m|7
+^|8
+|9 2+>|10
+|============================
+
+.AsciiDoc source
+---------------------------------------------------------------------
+[cols="e,m,^,>s",width="25%"]
+|============================
+|1 >s|2 |3 |4
+^|5 2.2+^.^|6 .3+<.>m|7
+^|8
+|9 2+>|10
+|============================
+---------------------------------------------------------------------
+
+[[X68]]
+Table input data formats
+~~~~~~~~~~~~~~~~~~~~~~~~
+AsciiDoc table data can be 'psv', 'dsv' or 'csv' formatted.  The
+default table format is 'psv'.
+
+AsciiDoc 'psv' ('Prefix Separated Values') and 'dsv' ('Delimiter
+Separated Values') formats are cell oriented -- the table is treated
+as a sequence of cells -- there are no explicit row separators.
+
+- 'psv' prefixes each cell with a separator whereas 'dsv' delimits
+  cells with a separator.
+- 'psv' and 'dsv' separators are Python regular expressions.
+- The default 'psv' separator contains <<X84, cell specifier>> related
+  named regular expression groups.
+- The default 'dsv' separator is `:|\n` (a colon or a new line
+  character).
+- 'psv' and 'dsv' cell separators can be escaped by preceding them
+  with a backslash character.
+
+Here are four 'psv' cells (the second item spans two columns; the
+last contains an escaped separator):
+
+  |One 2+|Two and three |A \| separator character
+
+'csv'  is the quasi-standard row oriented 'Comma Separated Values
+(CSV)' format commonly used to import and export spreadsheet and
+database data.
+
+[[X69]]
+Table attributes
+~~~~~~~~~~~~~~~~
+Tables can be customized by the following attributes:
+
+format::
+'psv' (default), 'dsv' or 'csv' (See <<X68, Table Data Formats>>).
+
+separator::
+The cell separator. A Python regular expression ('psv' and 'dsv'
+formats) or a single character ('csv' format).
+
+frame::
+Defines the table border and can take the following values: 'topbot'
+(top and bottom), 'all' (all sides), 'none' and 'sides' (left and
+right sides). The default value is 'all'.
+
+grid::
+Defines which ruler lines are drawn between table rows and columns.
+The 'grid' attribute value can be any of the following values: 'none',
+'cols', 'rows' and 'all'. The default value is 'all'.
+
+align::
+Use the 'align' attribute to horizontally align the table on the
+page (works with HTML outputs only, has no effect on DocBook outputs).
+The following values are valid: 'left', 'right', and 'center'.
+
+float::
+Use the 'float' attribute to float the table 'left' or 'right' on the
+page (works with HTML outputs only, has no effect on DocBook outputs).
+Floating only makes sense in conjunction with a table 'width'
+attribute value of less than 100% (otherwise the table will take up
+all the available space).  'float' and 'align' attributes are mutually
+exclusive.  Use the `unfloat::[]` block macro to stop floating.
+
+halign::
+Use the 'halign' attribute to horizontally align all cells in a table.
+The following values are valid: 'left', 'right', and 'center'
+(defaults to 'left'). Overridden by <<X70,Column specifiers>>  and
+<<X84,Cell specifiers>>.
+
+valign::
+Use the 'valign' attribute to vertically align all cells in a table.
+The following values are valid: 'top', 'bottom', and 'middle'
+(defaults to 'top'). Overridden by <<X70,Column specifiers>>  and
+<<X84,Cell specifiers>>.
+
+options::
+The 'options' attribute can contain comma separated values, for
+example: 'header', 'footer'. By default header and footer rows are
+omitted.  See <<X74,attribute options>> for a complete list of
+available table options.
+
+cols::
+The 'cols' attribute is a comma separated list of <<X70,column
+specifiers>>. For example `cols="2<p,2*,4p,>"`.
+
+- If 'cols' is present it must specify all columns.
+- If the 'cols' attribute is not specified the number of columns is
+  calculated as the number of data items in the *first line* of the
+  table.
+- The degenerate form for the 'cols' attribute is an integer
+  specifying the number of columns e.g. `cols=4`.
+
+width::
+The 'width' attribute is expressed as a percentage value
+('"1%"'...'"99%"'). The width specifies the table width relative to
+the available width. HTML backends use this value to set the table
+width attribute. It's a bit more complicated with DocBook, see the
+<<X89,DocBook table widths>> sidebar.
+
+filter::
+The 'filter' attribute defines an external shell command that is
+invoked for each cell. The built-in 'asciidoc' table style is
+implemented using a filter.
+
+[[X89]]
+.DocBook table widths
+**********************************************************************
+The AsciiDoc docbook backend generates CALS tables. CALS tables do not
+support a table width attribute -- table width can only be controlled
+by specifying absolute column widths.
+
+Specifying absolute column widths is not media independent because
+different presentation media have different physical dimensions. To
+get round this limitation both
+http://www.sagehill.net/docbookxsl/Tables.html#TableWidth[DocBook XSL
+Stylesheets] and
+http://dblatex.sourceforge.net/doc/manual/ch03s05.html#sec-table-width[dblatex]
+have implemented table width processing instructions for setting the
+table width as a percentage of the available width. AsciiDoc emits
+these processing instructions if the 'width' attribute is set along
+with proportional column widths (the AsciiDoc docbook backend
+'pageunits' attribute defaults to '*').
+
+To generate DocBook tables with absolute column widths set the
+'pageunits' attribute to a CALS absolute unit such as 'pt' and set the
+'pagewidth' attribute to match the width of the presentation media.
+**********************************************************************
+
+[[X70]]
+Column Specifiers
+~~~~~~~~~~~~~~~~~
+Column specifiers define how columns are rendered and appear in the
+table <<X69,cols attribute>>.  A column specifier consists of an
+optional column multiplier followed by optional alignment, width and
+style values and is formatted like:
+
+  [<multiplier>*][<align>][<width>][<style>]
+
+- All components are optional. The multiplier must be first and the
+  style last. The order of `<align>` or `<width>` is not important.
+- Column `<width>` can be either an integer proportional value (1...)
+  or a percentage (1%...100%). The default value is 1. To ensure
+  portability across different backends, there is no provision for
+  absolute column widths (not to be confused with output column width
+  <<X72,markup attributes>> which are available in both percentage and
+  absolute units).
+- The '<align>' column alignment specifier is formatted like:
+
+  [<horizontal>][.<vertical>]
++
+Where `<horizontal>` and `<vertical>` are one of the following
+characters: `<`, `^` or `>` which represent 'left', 'center' and
+'right' horizontal alignment or 'top', 'middle' and 'bottom' vertical
+alignment respectively.
+
+- A `<multiplier>` can be used to specify repeated columns e.g.
+  `cols="4*<"` specifies four left-justified columns. The default
+  multiplier value is 1.
+- The `<style>` name specifies a <<X71,table style>> to used to markup
+  column cells (you can use the full style names if you wish but the
+  first letter is normally sufficient).
+- Column specific styles are not applied to header rows.
+
+[[X84]]
+Cell Specifiers
+~~~~~~~~~~~~~~~
+Cell specifiers allow individual cells in 'psv' formatted tables to be
+spanned, multiplied, aligned and styled.  Cell specifiers prefix 'psv'
+`|` delimiters and are formatted like:
+
+  [<span>*|+][<align>][<style>]
+
+- '<span>' specifies horizontal and vertical cell spans ('+' operator) or
+  the number of times the cell is replicated ('*' operator). '<span>'
+  is formatted like:
+
+  [<colspan>][.<rowspan>]
++
+Where `<colspan>` and `<rowspan>` are integers specifying the number of
+columns and rows to span.
+
+- `<align>` specifies horizontal and vertical cell alignment an is the
+  same as in <<X70,column specifiers>>.
+- A `<style>` value is the first letter of <<X71,table style>> name.
+
+For example, the following 'psv' formatted cell will span two columns
+and the text will be centered and emphasized:
+
+  `2+^e| Cell text`
+
+[[X71]]
+Table styles
+~~~~~~~~~~~~
+Table styles can be applied to the entire table (by setting the
+'style' attribute in the table's attribute list) or on a per column
+basis (by specifying the style in the table's <<X69,cols attribute>>).
+Table data can be formatted using the following predefined styles:
+
+default::
+The default style: AsciiDoc inline text formatting; blank lines are
+treated as paragraph breaks.
+
+emphasis::
+Like default but all text is emphasised.
+
+monospaced::
+Like default but all text is in a monospaced font.
+
+strong::
+Like default but all text is bold.
+
+header::
+Apply the same style as the table header. Normally used to create a
+vertical header in the first column.
+
+asciidoc::
+With this style table cells can contain any of the AsciiDoc elements
+that are allowed inside document sections. This style runs asciidoc(1)
+as a filter to process cell contents. See also <<X83,Docbook table
+limitations>>.
+
+literal::
+No text formatting; monospaced font; all line breaks are retained
+(the same as the AsciiDoc <<X65,LiteralBlock>> element).
+
+verse::
+All line breaks are retained (just like the AsciiDoc <<X94,verse
+paragraph style>>).
+
+[[X72]]
+Markup attributes
+~~~~~~~~~~~~~~~~~
+AsciiDoc makes a number of attributes available to table markup
+templates and tags. Column specific attributes are available when
+substituting the 'colspec' cell data tags.
+
+pageunits::
+DocBook backend only. Specifies table column absolute width units.
+Defaults to '*'.
+
+pagewidth::
+DocBook backend only. The nominal output page width in 'pageunit'
+units. Used to calculate CALS tables absolute column and table
+widths. Defaults to '425'.
+
+tableabswidth::
+Integer value calculated from 'width' and 'pagewidth' attributes.
+In 'pageunit' units.
+
+tablepcwidth::
+Table width expressed as a percentage of the available width. Integer
+value (0..100).
+
+colabswidth::
+Integer value calculated from 'cols' column width, 'width' and
+'pagewidth' attributes.  In 'pageunit' units.
+
+colpcwidth::
+Column width expressed as a percentage of the table width. Integer
+value (0..100).
+
+colcount::
+Total number of table columns.
+
+rowcount::
+Total number of table rows.
+
+halign::
+Horizontal cell content alignment: 'left', 'right' or 'center'.
+
+valign::
+Vertical cell content alignment: 'top', 'bottom' or 'middle'.
+
+colnumber, colstart::
+The number of the leftmost column occupied by the cell (1...).
+
+colend::
+The number of the rightmost column occupied by the cell (1...).
+
+colspan::
+Number of columns the cell should span.
+
+rowspan::
+Number of rows the cell should span (1...).
+
+morerows::
+Number of additional rows the cell should span (0...).
+
+Nested tables
+~~~~~~~~~~~~~
+An alternative 'psv' separator character '!' can be used (instead of
+'|') in nested tables. This allows a single level of table nesting.
+Columns containing nested tables must use the 'asciidoc' style. An
+example can be found in `./examples/website/newtables.txt`.
+
+[[X83]]
+DocBook table limitations
+~~~~~~~~~~~~~~~~~~~~~~~~~
+Fully implementing tables is not trivial, some DocBook toolchains do
+better than others.  AsciiDoc HTML table outputs are rendered
+correctly in all the popular browsers -- if your DocBook generated
+tables don't look right compare them with the output generated by the
+AsciiDoc 'xhtml11' backend or try a different DocBook toolchain.  Here
+is a list of things to be aware of:
+
+- Although nested tables are not legal in DocBook 4 the FOP and
+  dblatex toolchains will process them correctly.  If you use `a2x(1)`
+  you will need to include the `--no-xmllint` option to suppress
+  DocBook validation errors.
++
+NOTE: In theory you can nest DocBook 4 tables one level using the
+'entrytbl' element, but not all toolchains process 'entrytbl'.
+
+- DocBook only allows a subset of block elements inside table cells so
+  not all AsciiDoc elements produce valid DocBook inside table cells.
+  If you get validation errors running `a2x(1)` try the `--no-xmllint`
+  option, toolchains will often process nested block elements such as
+  sidebar blocks and floating titles correctly even though, strictly
+  speaking, they are not legal.
+
+- Text formatting in cells using the 'monospaced' table style will
+  raise validation errors because the DocBook 'literal' element was
+  not designed to support formatted text (using the 'literal' element
+  is a kludge on the part of AsciiDoc as there is no easy way to set
+  the font style in DocBook.
+
+- Cell alignments are ignored for 'verse', 'literal' or 'asciidoc'
+  table styles.
+
+
+[[X1]]
+Manpage Documents
+-----------------
+Sooner or later, if you program in a UNIX environment, you're going
+to have to write a man page.
+
+By observing a couple of additional conventions (detailed below) you
+can write AsciiDoc files that will generate HTML and PDF man pages
+plus the native manpage roff format.  The easiest way to generate roff
+manpages from AsciiDoc source is to use the a2x(1) command. The
+following example generates a roff formatted manpage file called
+`asciidoc.1` (a2x(1) uses asciidoc(1) to convert `asciidoc.1.txt` to
+DocBook which it then converts to roff using DocBook XSL Stylesheets):
+
+  a2x --doctype manpage --format manpage asciidoc.1.txt
+
+.Viewing and printing manpage files
+**********************************************************************
+Use the `man(1)` command to view the manpage file:
+
+  $ man -l asciidoc.1
+
+To print a high quality man page to a postscript printer:
+
+  $ man -l -Tps asciidoc.1 | lpr
+
+You could also create a PDF version of the man page by converting
+PostScript to PDF using `ps2pdf(1)`:
+
+  $ man -l -Tps asciidoc.1 | ps2pdf - asciidoc.1.pdf
+
+The `ps2pdf(1)` command is included in the Ghostscript distribution.
+**********************************************************************
+
+To find out more about man pages view the `man(7)` manpage
+(`man 7 man` and `man man-pages` commands).
+
+
+Document Header
+~~~~~~~~~~~~~~~
+A manpage document Header is mandatory. The title line contains the
+man page name followed immediately by the manual section number in
+brackets, for example 'ASCIIDOC(1)'. The title name should not contain
+white space and the manual section number is a single digit optionally
+followed by a single character.
+
+The NAME Section
+~~~~~~~~~~~~~~~~
+The first manpage section is mandatory, must be titled 'NAME' and must
+contain a single paragraph (usually a single line) consisting of a
+list of one or more comma separated command name(s) separated from the
+command purpose by a dash character. The dash must have at least one
+white space character on either side. For example:
+
+  printf, fprintf, sprintf - print formatted output
+
+The SYNOPSIS Section
+~~~~~~~~~~~~~~~~~~~~
+The second manpage section is mandatory and must be titled 'SYNOPSIS'.
+
+refmiscinfo attributes
+~~~~~~~~~~~~~~~~~~~~~~
+In addition to the automatically created man page <<X60,intrinsic
+attributes>> you can assign DocBook
+http://www.docbook.org/tdg5/en/html/refmiscinfo.html[refmiscinfo]
+element 'source', 'version' and 'manual' values using AsciiDoc
+`{mansource}`, `{manversion}` and `{manmanual}` attributes
+respectively. This example is from the AsciiDoc header of a man page
+source file:
+
+  :man source:   AsciiDoc
+  :man version:  {revnumber}
+  :man manual:   AsciiDoc Manual
+
+
+[[X78]]
+Mathematical Formulas
+---------------------
+The 'asciimath' and 'latexmath' <<X77,passthrough macros>> along with
+'asciimath' and 'latexmath'  <<X76,passthrough blocks>> provide a
+(backend dependent) mechanism for rendering mathematical formulas. You
+can use the following math markups:
+
+NOTE: The 'latexmath' macro used to include 'LaTeX Math' in DocBook
+outputs is not the same as the 'latexmath' macro used to include
+'LaTeX MathML' in XHTML outputs.  'LaTeX Math' applies to DocBook
+outputs that are processed by <<X31,dblatex>> and is normally used to
+generate PDF files.  'LaTeXMathML' is very much a subset of 'LaTeX
+Math' and applies to XHTML documents.
+
+LaTeX Math
+~~~~~~~~~~
+ftp://ftp.ams.org/pub/tex/doc/amsmath/short-math-guide.pdf[LaTeX
+math] can be included in documents that are processed by
+<<X31,dblatex(1)>>.  Example inline formula:
+
+  latexmath:[$C = \alpha + \beta Y^{\gamma} + \epsilon$]
+
+For more examples see the {website}[AsciiDoc website] or the
+distributed `doc/latexmath.txt` file.
+
+ASCIIMathML
+~~~~~~~~~~~
+/////////////////////////////////////////////////////////////////////
+The older ASCIIMathML 1.47 version is used instead of version 2
+because:
+
+1. Version 2 doesn't work when embedded.
+2. Version 2 is much larger.
+/////////////////////////////////////////////////////////////////////
+
+http://www1.chapman.edu/~jipsen/mathml/asciimath.html[ASCIIMathML]
+formulas can be included in XHTML documents generated using the
+'xhtml11' and 'html5' backends. To enable ASCIIMathML support you must
+define the 'asciimath' attribute, for example using the `-a asciimath`
+command-line option.  Example inline formula:
+
+  asciimath:[`x/x={(1,if x!=0),(text{undefined},if x=0):}`]
+
+For more examples see the {website}[AsciiDoc website] or the
+distributed `doc/asciimathml.txt` file.
+
+LaTeXMathML
+~~~~~~~~~~~
+/////////////////////////////////////////////////////////////////////
+There is an http://math.etsu.edu/LaTeXMathML/[extended LaTeXMathML
+version] by Jeff Knisley, in addition to a JavaScript file it requires
+the inclusion of a CSS file.
+/////////////////////////////////////////////////////////////////////
+
+'LaTeXMathML' allows LaTeX Math style formulas to be included in XHTML
+documents generated using the AsciiDoc 'xhtml11' and 'html5' backends.
+AsciiDoc uses the
+http://www.maths.nottingham.ac.uk/personal/drw/lm.html[original
+LaTeXMathML] by Douglas Woodall.  'LaTeXMathML' is derived from
+ASCIIMathML and is for users who are more familiar with or prefer
+using LaTeX math formulas (it recognizes a subset of LaTeX Math, the
+differences are documented on the 'LaTeXMathML' web page).  To enable
+LaTeXMathML support you must define the 'latexmath' attribute, for
+example using the `-a latexmath` command-line option.  Example inline
+formula:
+
+  latexmath:[$\sum_{n=1}^\infty \frac{1}{2^n}$]
+
+For more examples see the {website}[AsciiDoc website] or the
+distributed `doc/latexmathml.txt` file.
+
+MathML
+~~~~~~
+http://www.w3.org/Math/[MathML] is a low level XML markup for
+mathematics. AsciiDoc has no macros for MathML but users familiar with
+this markup could use passthrough macros and passthrough blocks to
+include MathML in output documents.
+
+
+[[X7]]
+Configuration Files
+-------------------
+AsciiDoc source file syntax and output file markup is largely
+controlled by a set of cascading, text based, configuration files.  At
+runtime The AsciiDoc default configuration files are combined with
+optional user and document specific configuration files.
+
+Configuration File Format
+~~~~~~~~~~~~~~~~~~~~~~~~~
+Configuration files contain named sections. Each section begins with a
+section name in square brackets []. The section body consists of the
+lines of text between adjacent section headings.
+
+- Section names consist of one or more alphanumeric, underscore or
+  dash characters and cannot begin or end with a dash.
+- Lines starting with a '#' character are treated as comments and
+  ignored.
+- If the section name is prefixed with a '+' character then the
+  section contents is appended to the contents of an already existing
+  same-named section.
+- Otherwise same-named sections and section entries override
+  previously loaded sections and section entries (this is sometimes
+  referred to as 'cascading').  Consequently, downstream configuration
+  files need only contain those sections and section entries that need
+  to be overridden.
+
+TIP: When creating custom configuration files you only need to include
+the sections and entries that differ from the default configuration.
+
+TIP: The best way to learn about configuration files is to read the
+default configuration files in the AsciiDoc distribution in
+conjunction with asciidoc(1) output files. You can view configuration
+file load sequence by turning on the asciidoc(1) `-v` (`--verbose`)
+command-line option.
+
+AsciiDoc reserves the following section names for specific purposes:
+
+miscellaneous::
+        Configuration options that don't belong anywhere else.
+attributes::
+        Attribute name/value entries.
+specialcharacters::
+        Special characters reserved by the backend markup.
+tags::
+        Backend markup tags.
+quotes::
+        Definitions for quoted inline character formatting.
+specialwords::
+        Lists of words and phrases singled out for special markup.
+replacements, replacements2, replacements3::
+        Find and replace substitution definitions.
+specialsections::
+        Used to single out special section names for specific markup.
+macros::
+        Macro syntax definitions.
+titles::
+        Heading, section and block title definitions.
+paradef-*::
+        Paragraph element definitions.
+blockdef-*::
+        DelimitedBlock element definitions.
+listdef-*::
+        List element definitions.
+listtags-*::
+        List element tag definitions.
+tabledef-*::
+        Table element definitions.
+tabletags-*::
+        Table element tag definitions.
+
+Each line of text in these sections is a 'section entry'. Section
+entries share the following syntax:
+
+name=value::
+        The entry value is set to value.
+name=::
+        The entry value is set to a zero length string.
+name!::
+        The entry is undefined (deleted from the configuration). This
+        syntax only applies to 'attributes' and 'miscellaneous'
+        sections.
+
+.Section entry behavior
+- All equals characters inside the `name` must be escaped with a
+  backslash character.
+- `name` and `value` are stripped of leading and trailing white space.
+- Attribute names, tag entry names and markup template section names
+  consist of one or more alphanumeric, underscore or dash characters.
+  Names should not begin or end with a dash.
+- A blank configuration file section (one without any entries) deletes
+  any preceding section with the same name (applies to non-markup
+  template sections).
+
+
+Miscellaneous section
+~~~~~~~~~~~~~~~~~~~~~
+The optional `[miscellaneous]` section specifies the following
+`name=value` options:
+
+newline::
+        Output file line termination characters. Can include any
+        valid Python string escape sequences. The default value is
+        `\r\n` (carriage return, line feed). Should not be quoted or
+        contain explicit spaces (use `\x20` instead). For example:
+
+        $ asciidoc -a 'newline=\n' -b docbook mydoc.txt
+
+outfilesuffix::
+        The default extension for the output file, for example
+        `outfilesuffix=.html`. Defaults to backend name.
+tabsize::
+        The number of spaces to expand tab characters, for example
+        `tabsize=4`. Defaults to 8. A 'tabsize' of zero suppresses tab
+        expansion (useful when piping included files through block
+        filters). Included files can override this option using the
+        'tabsize' attribute.
+pagewidth, pageunits::
+        These global table related options are documented in the
+        <<X4,Table Configuration File Definitions>> sub-section.
+
+NOTE: `[miscellaneous]` configuration file entries can be set using
+the asciidoc(1) `-a` (`--attribute`) command-line option.
+
+Titles section
+~~~~~~~~~~~~~~
+sectiontitle::
+        Two line section title pattern. The entry value is a Python
+        regular expression containing the named group 'title'.
+
+underlines::
+        A comma separated list of document and section title underline
+        character pairs starting with the section level 0 and ending
+        with section level 4 underline. The default setting is:
+
+        underlines="==","--","~~","^^","++"
+
+sect0...sect4::
+        One line section title patterns. The entry value is a Python
+        regular expression containing the named group 'title'.
+
+blocktitle::
+        <<X42,BlockTitle element>> pattern.  The entry value is a
+        Python regular expression containing the named group 'title'.
+
+subs::
+        A comma separated list of substitutions that are performed on
+        the document header and section titles. Defaults to 'normal'
+        substitution.
+
+Tags section
+~~~~~~~~~~~~
+The `[tags]` section contains backend tag definitions (one per
+line). Tags are used to translate AsciiDoc elements to backend
+markup.
+
+An AsciiDoc tag definition is formatted like
+`<tagname>=<starttag>|<endtag>`. For example:
+
+  emphasis=<em>|</em>
+
+In this example asciidoc(1) replaces the | character with the
+emphasized text from the AsciiDoc input file and writes the result to
+the output file.
+
+Use the `{brvbar}` attribute reference if you need to include a | pipe
+character inside tag text.
+
+Attributes section
+~~~~~~~~~~~~~~~~~~
+The optional `[attributes]` section contains predefined attributes.
+
+If the attribute value requires leading or trailing spaces then the
+text text should be enclosed in quotation mark (") characters.
+
+To delete a attribute insert a `name!` entry in a downstream
+configuration file or use the asciidoc(1) `--attribute name!`
+command-line option (an attribute name suffixed with a `!` character
+deletes the attribute)
+
+Special Characters section
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+The `[specialcharacters]` section specifies how to escape characters
+reserved by the backend markup. Each translation is specified on a
+single line formatted like:
+
+  <special_character>=<translated_characters>
+
+Special characters are normally confined to those that resolve
+markup ambiguity (in the case of HTML and XML markups the ampersand,
+less than and greater than characters).  The following example causes
+all occurrences of the `<` character to be replaced by `<`.
+
+  <=<
+
+Quoted Text section
+~~~~~~~~~~~~~~~~~~~
+Quoting is used primarily for text formatting.  The `[quotes]` section
+defines AsciiDoc quoting characters and their corresponding backend
+markup tags.  Each section entry value is the name of a of a `[tags]`
+section entry. The entry name is the character (or characters) that
+quote the text.  The following examples are taken from AsciiDoc
+configuration files:
+
+  [quotes]
+  _=emphasis
+
+  [tags]
+  emphasis=<em>|</em>
+
+You can specify the left and right quote strings separately by
+separating them with a | character, for example:
+
+  ``|''=quoted
+
+Omitting the tag will disable quoting, for example, if you don't want
+superscripts or subscripts put the following in a custom configuration
+file or edit the global `asciidoc.conf` configuration file:
+
+  [quotes]
+  ^=
+  ~=
+
+<<X52,Unconstrained quotes>> are differentiated from constrained
+quotes by prefixing the tag name with a hash character, for example:
+
+  __=#emphasis
+
+.Quoted text behavior
+- Quote characters must be non-alphanumeric.
+- To minimize quoting ambiguity try not to use the same quote
+  characters in different quote types.
+
+Special Words section
+~~~~~~~~~~~~~~~~~~~~~
+The `[specialwords]` section is used to single out words and phrases
+that you want to consistently format in some way throughout your
+document without having to repeatedly specify the markup. The name of
+each entry corresponds to a markup template section and the entry
+value consists of a list of words and phrases to be marked up. For
+example:
+
+  [specialwords]
+  strongwords=NOTE IMPORTANT
+
+  [strongwords]
+  <strong>{words}</strong>
+
+The examples specifies that any occurrence of `NOTE` or `IMPORTANT`
+should appear in a bold font.
+
+Words and word phrases are treated as Python regular expressions: for
+example, the word `^NOTE` would only match `NOTE` if appeared at
+the start of a line.
+
+AsciiDoc comes with three built-in Special Word types:
+'emphasizedwords', 'monospacedwords' and 'strongwords', each has a
+corresponding (backend specific) markup template section. Edit the
+configuration files to customize existing Special Words and to add new
+ones.
+
+.Special word behavior
+- Word list entries must be separated by space characters.
+- Word list entries with embedded spaces should be enclosed in quotation (")
+  characters.
+- A `[specialwords]` section entry of the form
+  +name=word1{nbsp}[word2...]+ adds words to existing `name` entries.
+- A `[specialwords]` section entry of the form `name` undefines
+  (deletes) all existing `name` words.
+- Since word list entries are processed as Python regular expressions
+  you need to be careful to escape regular expression special
+  characters.
+- By default Special Words are substituted before Inline Macros, this
+  may lead to undesirable consequences. For example the special word
+  `foobar` would be expanded inside the macro call
+  `http://www.foobar.com[]`.  A possible solution is to emphasize
+  whole words only by defining the word using regular expression
+  characters, for example `\bfoobar\b`.
+- If the first matched character of a special word is a backslash then
+  the remaining characters are output without markup i.e. the
+  backslash can be used to escape special word markup.  For example
+  the special word `\\?\b[Tt]en\b` will mark up the words `Ten` and
+  `ten` only if they are not preceded by a backslash.
+
+[[X10]]
+Replacements section
+~~~~~~~~~~~~~~~~~~~~
+`[replacements]`, `[replacements2]` and `[replacements3]`
+configuration file entries specify find and replace text and are
+formatted like:
+
+  <find_pattern>=<replacement_text>
+
+The find text can be a Python regular expression; the replace text can
+contain Python regular expression group references.
+
+Use Replacement shortcuts for often used macro references, for
+example (the second replacement allows us to backslash escape the
+macro name):
+
+  NEW!=image:./images/smallnew.png[New!]
+  \\NEW!=NEW!
+
+The only difference between the three replacement types is how they
+are applied. By default 'replacements' and 'replacement2' are applied
+in <<X102,normal>> substitution contexts whereas 'replacements3' needs
+to be configured explicitly and should only be used in backend
+configuration files.
+
+.Replacement behavior
+- The built-in replacements can be escaped with a backslash.
+- If the find or replace text has leading or trailing spaces then the
+  text should be enclosed in quotation (") characters.
+- Since the find text is processed as a regular expression you need to
+  be careful to escape regular expression special characters.
+- Replacements are performed in the same order they appear in the
+  configuration file replacements section.
+
+Markup Template Sections
+~~~~~~~~~~~~~~~~~~~~~~~~
+Markup template sections supply backend markup for translating
+AsciiDoc elements.  Since the text is normally backend dependent
+you'll find these sections in the backend specific configuration
+files. Template sections differ from other sections in that they
+contain a single block of text instead of per line 'name=value'
+entries. A markup template section body can contain:
+
+- Attribute references
+- System macro calls.
+- A document content placeholder
+
+The document content placeholder is a single | character and is
+replaced by text from the source element.  Use the `{brvbar}`
+attribute reference if you need a literal | character in the template.
+
+[[X27]]
+Configuration file names, precedence and locations
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Configuration files have a `.conf` file name extension; they are
+loaded from the following locations:
+
+1. The directory containing the asciidoc executable.
+2. If there is no `asciidoc.conf` file in the directory containing the
+   asciidoc executable then load from the global configuration
+   directory (normally `/etc/asciidoc` or `/usr/local/etc/asciidoc`)
+   i.e. the global configuration files directory is skipped if
+   AsciiDoc configuration files are installed in the same directory as
+   the asciidoc executable. This allows both a system wide copy and
+   multiple local copies of AsciiDoc to coexist on the same host PC.
+3. The user's `$HOME/.asciidoc` directory (if it exists).
+4. The directory containing the AsciiDoc source file.
+5. Explicit configuration files specified using:
+   - The `conf-files` attribute (one or more file names separated by a
+     `|` character). These files are loaded in the order they are
+     specified and prior to files specified using the `--conf-file`
+     command-line option.
+   - The asciidoc(1) `--conf-file`) command-line option.  The
+     `--conf-file` option can be specified multiple times, in which
+     case configuration files will be processed in the same order they
+     appear on the command-line.
+6. <<X100,Backend plugin>> configuration files are loaded from
+   subdirectories named like `backends/<backend>` in locations 1, 2
+   and 3.
+7. <<X59,Filter>> configuration files are loaded from subdirectories
+   named like `filters/<filter>` in locations 1, 2 and 3.
+
+Configuration files from the above locations are loaded in the
+following order:
+
+- The `[attributes]` section only from:
+  * `asciidoc.conf` in location 3
+  * Files from location 5.
++
+This first pass makes locally set attributes available in the global
+`asciidoc.conf` file.
+
+- `asciidoc.conf` from locations 1, 2, 3.
+- 'attributes', 'titles' and 'specialcharacters' sections from the
+  `asciidoc.conf` in location 4.
+- The document header is parsed at this point and we can assume the
+  'backend' and 'doctype' have now been defined.
+- Backend plugin `<backend>.conf` and `<backend>-<doctype>.conf` files
+  from locations 6.  If a backend plugin is not found then try
+  locations 1, 2 and 3 for `<backend>.conf` and
+  `<backend>-<doctype>.conf` backend configuration files.
+- Filter conf files from locations 7.
+- `lang-<lang>.conf` from locations 1, 2, 3.
+- `asciidoc.conf` from location 4.
+- `<backend>.conf` and `<backend>-<doctype>.conf` from location 4.
+- Filter conf files from location 4.
+- `<docfile>.conf` and `<docfile>-<backend>.conf` from location 4.
+- Configuration files from location 5.
+
+Where:
+
+- `<backend>` and `<doctype>` are values specified by the asciidoc(1)
+  `-b` (`--backend`) and `-d` (`--doctype`) command-line options.
+- `<infile>` is the path name of the AsciiDoc input file without the
+  file name extension.
+- `<lang>` is a two letter country code set by the the AsciiDoc 'lang'
+  attribute.
+
+[NOTE]
+=====================================================================
+The backend and language global configuration files are loaded *after*
+the header has been parsed.  This means that you can set most
+attributes in the document header. Here's an example header:
+
+  Life's Mysteries
+  ================
+  :author: Hu Nose
+  :doctype: book
+  :toc:
+  :icons:
+  :data-uri:
+  :lang: en
+  :encoding: iso-8859-1
+
+Attributes set in the document header take precedence over
+configuration file attributes.
+
+=====================================================================
+
+TIP: Use the asciidoc(1) `-v` (`--verbose`) command-line option to see
+which configuration files are loaded and the order in which they are
+loaded.
+
+
+Document Attributes
+-------------------
+A document attribute is comprised of a 'name' and a textual 'value'
+and is used for textual substitution in AsciiDoc documents and
+configuration files. An attribute reference (an attribute name
+enclosed in braces) is replaced by the corresponding attribute
+value. Attribute names are case insensitive and can only contain
+alphanumeric, dash and underscore characters.
+
+There are four sources of document attributes (from highest to lowest
+precedence):
+
+- Command-line attributes.
+- AttributeEntry, AttributeList, Macro and BlockId elements.
+- Configuration file `[attributes]` sections.
+- Intrinsic attributes.
+
+Within each of these divisions the last processed entry takes
+precedence.
+
+NOTE: If an attribute is not defined then the line containing the
+attribute reference is dropped. This property is used extensively in
+AsciiDoc configuration files to facilitate conditional markup
+generation.
+
+
+[[X18]]
+Attribute Entries
+-----------------
+The `AttributeEntry` block element allows document attributes to be
+assigned within an AsciiDoc document. Attribute entries are added to
+the global document attributes dictionary. The attribute name/value
+syntax is a single line like:
+
+  :<name>: <value>
+
+For example:
+
+  :Author Initials: JB
+
+This will set an attribute reference `{authorinitials}` to the value
+'JB' in the current document.
+
+To delete (undefine) an attribute use the following syntax:
+
+  :<name>!:
+
+.AttributeEntry behavior
+- The attribute entry line begins with colon -- no white space allowed
+  in left margin.
+- AsciiDoc converts the `<name>` to a legal attribute name (lower
+  case, alphanumeric, dash and underscore characters only -- all other
+  characters deleted). This allows more human friendly text to be
+  used.
+- Leading and trailing white space is stripped from the `<value>`.
+- Lines ending in a space followed by a plus character are continued
+  to the next line, for example:
+
+  :description: AsciiDoc is a text document format for writing notes, +
+                documentation, articles, books, slideshows, web pages +
+                and man pages.
+
+- If the `<value>` is blank then the corresponding attribute value is
+  set to an empty string.
+- Attribute references contained in the entry `<value>` will be
+  expanded.
+- By default AttributeEntry values are substituted for
+  `specialcharacters` and `attributes` (see above), if you want to
+  change or disable AttributeEntry substitution use the <<X77,pass:[]
+  inline macro>> syntax.
+- Attribute entries in the document Header are available for header
+  markup template substitution.
+- Attribute elements override configuration file and intrinsic
+  attributes but do not override command-line attributes.
+
+Here are some more attribute entry examples:
+
+---------------------------------------------------------------------
+AsciiDoc User Manual
+====================
+:author:    Stuart Rackham
+:email:     srackham@gmail.com
+:revdate:   April 23, 2004
+:revnumber: 5.1.1
+---------------------------------------------------------------------
+
+Which creates these attributes:
+
+  {author}, {firstname}, {lastname}, {authorinitials}, {email},
+  {revdate}, {revnumber}
+
+The previous example is equivalent to this <<X95,document header>>:
+
+---------------------------------------------------------------------
+AsciiDoc User Manual
+====================
+Stuart Rackham <srackham@gmail.com>
+5.1.1, April 23, 2004
+---------------------------------------------------------------------
+
+Setting configuration entries
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+A variant of the Attribute Entry syntax allows configuration file
+section entries and markup template sections to be set from within an
+AsciiDoc document:
+
+  :<section_name>.[<entry_name>]: <entry_value>
+
+Where `<section_name>` is the configuration section name,
+`<entry_name>` is the name of the entry and `<entry_value>` is the
+optional entry value. This example sets the default labeled list
+style to 'horizontal':
+
+  :listdef-labeled.style: horizontal
+
+It is exactly equivalent to a configuration file containing:
+
+  [listdef-labeled]
+  style=horizontal
+
+- If the `<entry_name>` is omitted then the entire section is
+  substituted with the `<entry_value>`. This feature should only be
+  used to set markup template sections. The following example sets the
+  'xref2' inline macro markup template:
+
+  :xref2-inlinemacro.: <a href="#{1}">{2?{2}}</a>
+
+- No substitution is performed on configuration file attribute entries
+  and they cannot be undefined.
+- This feature can only be used in attribute entries -- configuration
+  attributes cannot be set using the asciidoc(1) command `--attribute`
+  option.
+
+[[X62]]
+.Attribute entries promote clarity and eliminate repetition
+*********************************************************************
+URLs and file names in AsciiDoc macros are often quite long -- they
+break paragraph flow and readability suffers.  The problem is
+compounded by redundancy if the same name is used repeatedly.
+Attribute entries can be used to make your documents easier to read
+and write, here are some examples:
+
+  :1:         http://freshmeat.net/projects/asciidoc/
+  :homepage:  http://methods.co.nz/asciidoc/[AsciiDoc home page]
+  :new:       image:./images/smallnew.png[]
+  :footnote1: footnote:[A meaningless latin term]
+
+  Using previously defined attributes: See the {1}[Freshmeat summary]
+  or the {homepage} for something new {new}. Lorem ispum {footnote1}.
+
+.Note
+- The attribute entry definition must precede it's usage.
+- You are not limited to URLs or file names, entire macro calls or
+  arbitrary lines of text can be abbreviated.
+- Shared attributes entries could be grouped into a separate file and
+  <<X63,included>> in multiple documents.
+*********************************************************************
+
+
+[[X21]]
+Attribute Lists
+---------------
+- An attribute list is a comma separated list of attribute values.
+- The entire list is enclosed in square brackets.
+- Attribute lists are used to pass parameters to macros, blocks (using
+  the <<X79,AttributeList element>>) and inline quotes.
+
+The list consists of zero or more positional attribute values followed
+by zero or more named attribute values.  Here are three examples: a
+single unquoted positional attribute; three unquoted positional
+attribute values; one positional attribute followed by two named
+attributes; the unquoted attribute value in the final example contains
+comma (`,`) and double-quote (`"`) character entities:
+
+  [Hello]
+  [quote, Bertrand Russell, The World of Mathematics (1956)]
+  ["22 times", backcolor="#0e0e0e", options="noborders,wide"]
+  [A footnote, "with an image" image:smallnew.png[]]
+
+.Attribute list behavior
+- If one or more attribute values contains a comma the all string
+  values must be quoted (enclosed in double quotation mark
+  characters).
+- If the list contains any named or quoted attributes then all string
+  attribute values must be quoted.
+- To include a double quotation mark (") character in a quoted
+  attribute value the the quotation mark must be escaped with a
+  backslash.
+- List attributes take precedence over existing attributes.
+- List attributes can only be referenced in configuration file markup
+  templates and tags, they are not available elsewhere in the
+  document.
+- Setting a named attribute to `None` undefines the attribute.
+- Positional attributes are referred to as `{1}`,`{2}`,`{3}`,...
+- Attribute `{0}` refers to the entire list (excluding the enclosing
+  square brackets).
+- Named attribute names cannot contain dash characters.
+
+[[X75]]
+Options attribute
+~~~~~~~~~~~~~~~~~
+If the attribute list contains an attribute named `options` it is
+processed as a comma separated list of option names:
+
+- Each name generates an attribute named like `<option>-option` (where
+  `<option>` is the option name) with an empty string value.  For
+  example `[options="opt1,opt2,opt3"]` is equivalent to setting the
+  following three attributes
+  `[opt1-option="",opt2-option="",opt2-option=""]`.
+- If you define a an option attribute globally (for example with an
+  <<X18,attribute entry>>) then it will apply to all elements in the
+  document.
+- AsciiDoc implements a number of predefined options which are listed
+  in the <<X74,Attribute Options appendix>>.
+
+Macro Attribute lists
+~~~~~~~~~~~~~~~~~~~~~
+Macros calls are suffixed with an attribute list. The list may be
+empty but it cannot be omitted. List entries are used to pass
+attribute values to macro markup templates.
+
+
+Attribute References
+--------------------
+An attribute reference is an attribute name (possibly followed by an
+additional parameters) enclosed in curly braces.  When an attribute
+reference is encountered it is evaluated and replaced by its
+corresponding text value.  If the attribute is undefined the line
+containing the attribute is dropped.
+
+There are three types of attribute reference: 'Simple', 'Conditional'
+and 'System'.
+
+.Attribute reference evaluation
+- You can suppress attribute reference expansion by placing a
+  backslash character immediately in front of the opening brace
+  character.
+- By default attribute references are not expanded in
+  'LiteralParagraphs', 'ListingBlocks' or 'LiteralBlocks'.
+- Attribute substitution proceeds line by line in reverse line order.
+- Attribute reference evaluation is performed in the following order:
+  'Simple' then 'Conditional' and finally 'System'.
+
+Simple Attributes References
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Simple attribute references take the form `{<name>}`. If the
+attribute name is defined its text value is substituted otherwise the
+line containing the reference is dropped from the output.
+
+Conditional Attribute References
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Additional parameters are used in conjunction with attribute names to
+calculate a substitution value. Conditional attribute references take
+the following forms:
+
+`{<names>=<value>}`::
+        `<value>` is substituted if the attribute `<names>` is
+        undefined otherwise its value is substituted. `<value>` can
+        contain simple attribute references.
+
+`{<names>?<value>}`::
+        `<value>` is substituted if the attribute `<names>` is defined
+        otherwise an empty string is substituted.  `<value>` can
+        contain simple attribute references.
+
+`{<names>!<value>}`::
+        `<value>` is substituted if the attribute `<names>` is
+        undefined otherwise an empty string is substituted.  `<value>`
+        can contain simple attribute references.
+
+`{<names>#<value>}`::
+        `<value>` is substituted if the attribute `<names>` is defined
+        otherwise the undefined attribute entry causes the containing
+        line to be dropped.  `<value>` can contain simple attribute
+        references.
+
+`{<names>%<value>}`::
+        `<value>` is substituted if the attribute `<names>` is not
+        defined otherwise the containing line is dropped.  `<value>`
+        can contain simple attribute references.
+
+`{<names>@<regexp>:<value1>[:<value2>]}`::
+        `<value1>` is substituted if the value of attribute `<names>`
+        matches the regular expression `<regexp>` otherwise `<value2>`
+        is substituted. If attribute `<names>` is not defined the
+        containing line is dropped. If `<value2>` is omitted an empty
+        string is assumed. The values and the regular expression can
+        contain simple attribute references.  To embed colons in the
+        values or the regular expression escape them with backslashes.
+
+`{<names>$<regexp>:<value1>[:<value2>]}`::
+        Same behavior as the previous ternary attribute except for
+        the following cases:
+
+        `{<names>$<regexp>:<value>}`;;
+                Substitutes `<value>` if `<names>` matches `<regexp>`
+                otherwise the result is undefined and the containing
+                line is dropped.
+
+        `{<names>$<regexp>::<value>}`;;
+                Substitutes `<value>` if `<names>` does not match
+                `<regexp>` otherwise the result is undefined and the
+                containing line is dropped.
+
+The attribute `<names>` parameter normally consists of a single
+attribute name but it can be any one of the following:
+
+- A single attribute name which evaluates to the attributes value.
+- Multiple ',' separated attribute names which evaluates to an empty
+  string if one or more of the attributes is defined, otherwise it's
+  value is undefined.
+- Multiple '+' separated attribute names which evaluates to an empty
+  string if all of the attributes are defined, otherwise it's value is
+  undefined.
+
+Conditional attributes with single attribute names are evaluated first
+so they can be used inside the multi-attribute conditional `<value>`.
+
+Conditional attribute examples
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Conditional attributes are mainly used in AsciiDoc configuration
+files -- see the distribution `.conf` files for examples.
+
+Attribute equality test::
+  If `{backend}` is 'docbook45' or 'xhtml11' the example evaluates to
+  ``DocBook 4.5 or XHTML 1.1 backend'' otherwise it evaluates to
+  ``some other backend'':
+
+  {backend@docbook45|xhtml11:DocBook 4.5 or XHTML 1.1 backend:some other backend}
+
+Attribute value map::
+  This example maps the `frame` attribute values [`topbot`, `all`,
+  `none`, `sides`] to [`hsides`, `border`, `void`, `vsides`]:
+
+  {frame@topbot:hsides}{frame@all:border}{frame@none:void}{frame@sides:vsides}
+
+
+[[X24]]
+System Attribute References
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+System attribute references generate the attribute text value by
+executing a predefined action that is parametrized by one or more
+arguments. The syntax is `{<action>:<arguments>}`.
+
+`{counter:<attrname>[:<seed>]}`::
+        Increments the document attribute (if the attribute is
+        undefined it is set to `1`). Returns the new attribute value.
+
+        - Counters generate global (document wide) attributes.
+        - The optional `<seed>` specifies the counter's initial value;
+          it can be a number or a single letter; defaults to '1'.
+        - `<seed>` can contain simple and conditional attribute
+          references.
+        - The 'counter' system attribute will not be executed if the
+          containing line is dropped by the prior evaluation of an
+          undefined attribute.
+
+`{counter2:<attrname>[:<seed>]}`::
+        Same as `counter` except the it always returns a blank string.
+
+`{eval:<expression>}`::
+        Substitutes the result of the Python `<expression>`.
+
+        - If `<expression>` evaluates to `None` or `False` the
+          reference is deemed undefined and the line containing the
+          reference is dropped from the output.
+        - If the expression evaluates to `True` the attribute
+          evaluates to an empty string.
+        - `<expression>` can contain simple and conditional attribute
+          references.
+        - The 'eval' system attribute can be nested inside other
+          system attributes.
+
+`{eval3:<command>}`::
+        Passthrough version of `{eval:<expression>}` -- the generated
+        output is written directly to the output without any further
+        substitutions.
+
+`{include:<filename>}`::
+        Substitutes contents of the file named `<filename>`.
+
+        - The included file is read at the time of attribute
+          substitution.
+        - If the file does not exist a warning is emitted and the line
+          containing the reference is dropped from the output file.
+        - Tabs are expanded based on the current 'tabsize' attribute
+          value.
+
+`{set:<attrname>[!][:<value>]}`::
+        Sets or unsets document attribute. Normally only used in
+        configuration file markup templates (use
+        <<X18,AttributeEntries>> in AsciiDoc documents).
+
+        - If the attribute name is followed by an exclamation mark
+          the attribute becomes undefined.
+        - If `<value>` is omitted the attribute is set to a blank
+          string.
+        - `<value>` can contain simple and conditional attribute
+          references.
+        - Returns a blank string unless the attribute is undefined in
+          which case the return value is undefined and the enclosing
+          line will be dropped.
+
+`{set2:<attrname>[!][:<value>]}`::
+        Same as `set` except that the attribute scope is local to the
+        template.
+
+`{sys:<command>}`::
+        Substitutes the stdout generated by the execution of the shell
+        `<command>`.
+
+`{sys2:<command>}`::
+        Substitutes the stdout and stderr generated by the execution
+        of the shell `<command>`.
+
+`{sys3:<command>}`::
+        Passthrough version of `{sys:<command>}` -- the generated
+        output is written directly to the output without any further
+        substitutions.
+
+`{template:<template>}`::
+        Substitutes the contents of the configuration file section
+        named `<template>`. Attribute references contained in the
+        template are substituted.
+
+.System reference behavior
+- System attribute arguments can contain non-system attribute
+  references.
+- Closing brace characters inside system attribute arguments must be
+  escaped with a backslash.
+
+[[X60]]
+Intrinsic Attributes
+--------------------
+Intrinsic attributes are simple attributes that are created
+automatically from: AsciiDoc document header parameters; asciidoc(1)
+command-line arguments; attributes defined in the default
+configuration files; the execution context.  Here's the list of
+predefined intrinsic attributes:
+
+  {amp}                 ampersand (&) character entity
+  {asciidoc-args}       used to pass inherited arguments to asciidoc filters
+  {asciidoc-confdir}    the asciidoc(1) global configuration directory
+  {asciidoc-dir}        the asciidoc(1) application directory
+  {asciidoc-file}       the full path name of the asciidoc(1) script
+  {asciidoc-version}    the version of asciidoc(1)
+  {author}              author's full name
+  {authored}            empty string '' if {author} or {email} defined,
+  {authorinitials}      author initials (from document header)
+  {backend-<backend>}   empty string ''
+  {<backend>-<doctype>} empty string ''
+  {backend}             document backend specified by `-b` option
+  {backend-confdir}     the directory containing the <backend>.conf file
+  {backslash}           backslash character
+  {basebackend-<base>}  empty string ''
+  {basebackend}         html or docbook
+  {blockname}           current block name (note 8).
+  {brvbar}              broken vertical bar (|) character
+  {docdate}             document last modified date
+  {docdir}              document input directory name  (note 5)
+  {docfile}             document file name  (note 5)
+  {docname}             document file name without extension (note 6)
+  {doctime}             document last modified time
+  {doctitle}            document title (from document header)
+  {doctype-<doctype>}   empty string ''
+  {doctype}             document type specified by `-d` option
+  {email}               author's email address (from document header)
+  {empty}               empty string ''
+  {encoding}            specifies input and output encoding
+  {filetype-<fileext>}  empty string ''
+  {filetype}            output file name file extension
+  {firstname}           author first name (from document header)
+  {gt}                  greater than (>) character entity
+  {id}                  running block id generated by BlockId elements
+  {indir}               input file directory name (note 2,5)
+  {infile}              input file name (note 2,5)
+  {lastname}            author last name (from document header)
+  {ldquo}               Left double quote character (note 7)
+  {level}               title level 1..4 (in section titles)
+  {listindex}           the list index (1..) of the most recent list item
+  {localdate}           the current date
+  {localtime}           the current time
+  {lsquo}               Left single quote character (note 7)
+  {lt}                  less than (<) character entity
+  {manname}             manpage name (defined in NAME section)
+  {manpurpose}          manpage (defined in NAME section)
+  {mantitle}            document title minus the manpage volume number
+  {manvolnum}           manpage volume number (1..8) (from document header)
+  {middlename}          author middle name (from document header)
+  {nbsp}                non-breaking space character entity
+  {notitle}             do not display the document title
+  {outdir}              document output directory name (note 2)
+  {outfile}             output file name (note 2)
+  {python}              the full path name of the Python interpreter executable
+  {rdquo}               Right double quote character (note 7)
+  {reftext}             running block xreflabel generated by BlockId elements
+  {revdate}             document revision date (from document header)
+  {revnumber}           document revision number (from document header)
+  {rsquo}               Right single quote character (note 7)
+  {sectnum}             formatted section number (in section titles)
+  {sp}                  space character
+  {showcomments}        send comment lines to the output
+  {title}               section title (in titled elements)
+  {two-colons}          Two colon characters
+  {two-semicolons}      Two semicolon characters
+  {user-dir}            the ~/.asciidoc directory (if it exists)
+  {verbose}             defined as '' if --verbose command option specified
+  {wj}                  Word-joiner
+  {zwsp}                Zero-width space character entity
+
+[NOTE]
+======
+1. Intrinsic attributes are global so avoid defining custom attributes
+   with the same names.
+2. `{outfile}`, `{outdir}`, `{infile}`, `{indir}` attributes are
+   effectively read-only (you can set them but it won't affect the
+   input or output file paths).
+3.  See also the <<X88,Backend Attributes>> section for attributes
+    that relate to AsciiDoc XHTML file generation.
+4. The entries that translate to blank strings are designed to be used
+   for conditional text inclusion. You can also use the `ifdef`,
+   `ifndef` and `endif` System macros for conditional inclusion.
+   footnote:[Conditional inclusion using `ifdef` and `ifndef` macros
+   differs from attribute conditional inclusion in that the former
+   occurs when the file is read while the latter occurs when the
+   contents are written.]
+5. `{docfile}` and `{docdir}` refer to root document specified on the
+   asciidoc(1) command-line; `{infile}` and `{indir}` refer to the
+   current input file which may be the root document or an included
+   file. When the input is being read from the standard input
+   (`stdin`) these attributes are undefined.
+6. If the input file is the standard input and the output file is not
+   the standard output then `{docname}` is the output file name sans
+   file extension.
+7. See
+   http://en.wikipedia.org/wiki/Non-English_usage_of_quotation_marks[non-English
+   usage of quotation marks].
+8. The `{blockname}` attribute identifies the style of the current
+   block. It applies to delimited blocks, lists and tables. Here is a
+   list of `{blockname}` values (does not include filters or custom
+   block and style names):
+
+   delimited blocks:: comment, sidebar, open, pass, literal, verse,
+   listing, quote, example, note, tip, important, caution, warning,
+   abstract, partintro
+
+   lists:: arabic, loweralpha, upperalpha, lowerroman, upperroman,
+   labeled, labeled3, labeled4, qanda, horizontal, bibliography,
+   glossary
+
+   tables:: table
+
+======
+
+
+[[X73]]
+Block Element Definitions
+-------------------------
+The syntax and behavior of Paragraph, DelimitedBlock, List and Table
+block elements is determined by block definitions contained in
+<<X7,AsciiDoc configuration file>> sections.
+
+Each definition consists of a section title followed by one or more
+section entries. Each entry defines a block parameter controlling some
+aspect of the block's behavior. Here's an example:
+
+---------------------------------------------------------------------
+[blockdef-listing]
+delimiter=^-{4,}$
+template=listingblock
+presubs=specialcharacters,callouts
+---------------------------------------------------------------------
+
+Configuration file block definition sections are processed
+incrementally after each configuration file is loaded. Block
+definition section entries are merged into the block definition, this
+allows block parameters to be overridden and extended by later
+<<X27,loading configuration files>>.
+
+AsciiDoc Paragraph, DelimitedBlock, List and Table block elements
+share a common subset of configuration file parameters:
+
+delimiter::
+  A Python regular expression that matches the first line of a block
+  element -- in the case of DelimitedBlocks and Tables it also matches
+  the last line.
+
+template::
+  The name of the configuration file markup template section that will
+  envelope the block contents. The pipe ('|') character is substituted
+  for the block contents. List elements use a set of (list specific)
+  tag parameters instead of a single template. The template name can
+  contain attribute references allowing dynamic template selection a
+  the time of template substitution.
+
+options::
+  A comma delimited list of element specific option names. In addition
+  to being used internally, options are available during markup tag
+  and template substitution as attributes with an empty string value
+  named like `<option>-option` (where `<option>` is the option name).
+  See <<X74,attribute options>> for a complete list of available
+  options.
+
+subs, presubs, postsubs::
+  * 'presubs' and 'postsubs' are lists of comma separated substitutions that are
+    performed on the block contents. 'presubs' is applied first,
+    'postsubs' (if specified) second.
+
+  * 'subs' is an alias for 'presubs'.
+
+  * If a 'filter' is allowed (Paragraphs, DelimitedBlocks and Tables)
+    and has been specified then 'presubs' and 'postsubs' substitutions
+    are performed before and after the filter is run respectively.
+
+  * Allowed values: 'specialcharacters', 'quotes', 'specialwords',
+    'replacements', 'macros', 'attributes', 'callouts'.
+
+  * [[X102]]The following composite values are also allowed:
+
+    'none';;
+        No substitutions.
+    'normal';;
+        The following substitutions in the following order:
+        'specialcharacters', 'quotes', 'attributes', 'specialwords',
+        'replacements', 'macros', 'replacements2'.
+    'verbatim';;
+        The following substitutions in the following order:
+        'specialcharacters' and 'callouts'.
+
+  * 'normal' and 'verbatim' substitutions can be redefined by with
+    `subsnormal` and `subsverbatim` entries in a configuration file
+    `[miscellaneous]` section.
+
+  * The substitutions are processed in the order in which they are
+    listed and can appear more than once.
+
+filter::
+  This optional entry specifies an executable shell command for
+  processing block content (Paragraphs, DelimitedBlocks and Tables).
+  The filter command can contain attribute references.
+
+posattrs::
+  Optional comma separated list of positional attribute names. This
+  list maps positional attributes (in the block's <<X21,attribute
+  list>>) to named block attributes. The following example, from the
+  QuoteBlock definition, maps the first and section positional
+  attributes:
+
+  posattrs=attribution,citetitle
+
+style::
+  This optional parameter specifies the default style name.
+
+
+<stylename>-style::
+  Optional style definition (see <<X23,Styles>> below).
+
+The following block parameters behave like document attributes and can
+be set in block attribute lists and style definitions: 'template',
+'options', 'subs', 'presubs', 'postsubs', 'filter'.
+
+[[X23]]
+Styles
+~~~~~~
+A style is a set of block parameter bundled as a single named
+parameter. The following example defines a style named 'verbatim':
+
+  verbatim-style=template="literalblock",subs="verbatim"
+
+If a block's <<X21,attribute list>> contains a 'style' attribute then
+the corresponding style parameters are be merged into the default
+block definition parameters.
+
+- All style parameter names must be suffixed with `-style` and the
+  style parameter value is in the form of a list of <<X21,named
+  attributes>>.
+- The 'template' style parameter is mandatory, other parameters can be
+  omitted in which case they inherit their values from the default
+  block definition parameters.
+- Multi-item style parameters ('subs','presubs','postsubs','posattrs')
+  must be specified using Python tuple syntax (rather than a simple
+  list of values as they in separate entries) e.g.
+  `postsubs=("callouts",)` not `postsubs="callouts"`.
+
+Paragraphs
+~~~~~~~~~~
+Paragraph translation is controlled by `[paradef-*]` configuration
+file section entries. Users can define new types of paragraphs and
+modify the behavior of existing types by editing AsciiDoc
+configuration files.
+
+Here is the shipped Default paragraph definition:
+
+--------------------------------------------------------------------
+[paradef-default]
+delimiter=(?P<text>\S.*)
+template=paragraph
+--------------------------------------------------------------------
+
+The normal paragraph definition has a couple of special properties:
+
+1. It must exist and be defined in a configuration file section named
+   `[paradef-default]`.
+2. Irrespective of its position in the configuration files default
+   paragraph document matches are attempted only after trying all
+   other paragraph types.
+
+Paragraph specific block parameter notes:
+
+delimiter::
+  This regular expression must contain the named group 'text' which
+  matches the text on the first line.  Paragraphs are terminated by a
+  blank line, the end of file, or the start of a DelimitedBlock.
+
+options::
+  The 'listelement' option specifies that paragraphs of this type will
+  automatically be considered part of immediately preceding list
+  items.  The 'skip' option causes the paragraph to be treated as a
+  comment (see <<X26,CommentBlocks>>).
+
+.Paragraph processing proceeds as follows:
+1. The paragraph text is aligned to the left margin.
+2. Optional 'presubs' inline substitutions are performed on the
+   paragraph text.
+3. If a filter command is specified it is executed and the paragraph
+   text piped to its standard input; the filter output replaces the
+   paragraph text.
+4. Optional 'postsubs' inline substitutions are performed on the
+   paragraph text.
+5. The paragraph text is enveloped by the paragraph's markup template
+   and written to the output file.
+
+Delimited Blocks
+~~~~~~~~~~~~~~~~
+DelimitedBlock 'options' values are:
+
+sectionbody::
+    The block contents are processed as a SectionBody.
+
+skip::
+    The block is treated as a comment (see <<X26,CommentBlocks>>).
+    Preceding <<X21,attribute lists>> and <<X42,block titles>> are not
+    consumed.
+
+'presubs', 'postsubs' and 'filter' entries are ignored when
+'sectionbody' or 'skip' options are set.
+
+DelimitedBlock processing proceeds as follows:
+
+1. Optional 'presubs' substitutions are performed on the block
+   contents.
+2. If a filter is specified it is executed and the block's contents
+   piped to its standard input. The filter output replaces the block
+   contents.
+3. Optional 'postsubs' substitutions are performed on the block
+   contents.
+4. The block contents is enveloped by the block's markup template and
+   written to the output file.
+
+TIP: Attribute expansion is performed on the block filter command
+before it is executed, this is useful for passing arguments to the
+filter.
+
+Lists
+~~~~~
+List behavior and syntax is determined by `[listdef-*]` configuration
+file sections. The user can change existing list behavior and add new
+list types by editing configuration files.
+
+List specific block definition notes:
+
+type::
+  This is either 'bulleted','numbered','labeled' or 'callout'.
+
+delimiter::
+  A Python regular expression that matches the first line of a
+  list element entry. This expression can contain the named groups
+  'text' (bulleted groups), 'index' and 'text' (numbered lists),
+  'label' and 'text' (labeled lists).
+
+tags::
+  The `<name>` of the `[listtags-<name>]` configuration file section
+  containing list markup tag definitions.  The tag entries ('list',
+  'entry', 'label', 'term', 'text') map the AsciiDoc list structure to
+  backend markup; see the 'listtags' sections in the AsciiDoc
+  distributed backend `.conf` configuration files for examples.
+
+Tables
+~~~~~~
+Table behavior and syntax is determined by `[tabledef-*]` and
+`[tabletags-*]` configuration file sections. The user can change
+existing table behavior and add new table types by editing
+configuration files.  The following `[tabledef-*]` section entries
+generate table output markup elements:
+
+colspec::
+  The table 'colspec' tag definition.
+
+headrow, footrow, bodyrow::
+  Table header, footer and body row tag definitions. 'headrow' and
+  'footrow' table definition entries default to 'bodyrow' if
+  they are undefined.
+
+headdata, footdata, bodydata::
+  Table header, footer and body data tag definitions. 'headdata' and
+  'footdata' table definition entries default to 'bodydata' if they
+  are undefined.
+
+paragraph::
+  If the 'paragraph' tag is specified then blank lines in the cell
+  data are treated as paragraph delimiters and marked up using this
+  tag.
+
+[[X4]]
+Table behavior is also influenced by the following `[miscellaneous]`
+configuration file entries:
+
+pagewidth::
+  This integer value is the printable width of the output media. See
+  <<X69,table attributes>>.
+
+pageunits::
+  The units of width in output markup width attribute values.
+
+.Table definition behavior
+- The output markup generation is specifically designed to work with
+  the HTML and CALS (DocBook) table models, but should be adaptable to
+  most XML table schema.
+- Table definitions can be ``mixed in'' from multiple cascading
+  configuration files.
+- New table definitions inherit the default table and table tags
+  definitions (`[tabledef-default]` and `[tabletags-default]`) so you
+  only need to override those conf file entries that require
+  modification.
+
+
+[[X59]]
+Filters
+-------
+AsciiDoc filters allow external commands to process AsciiDoc
+'Paragraphs', 'DelimitedBlocks' and 'Table' content. Filters are
+primarily an extension mechanism for generating specialized outputs.
+Filters are implemented using external commands which are specified in
+configuration file definitions.
+
+There's nothing special about the filters, they're just standard UNIX
+filters: they read text from the standard input, process it, and write
+to the standard output.
+
+The asciidoc(1) command `--filter` option can be used to install and
+remove filters. The same option is used to unconditionally load a
+filter.
+
+Attribute substitution is performed on the filter command prior to
+execution -- attributes can be used to pass parameters from the
+AsciiDoc source document to the filter.
+
+WARNING: Filters sometimes included executable code. Before installing
+a filter you should verify that it is from a trusted source.
+
+Filter Search Paths
+~~~~~~~~~~~~~~~~~~~
+If the filter command does not specify a directory path then
+asciidoc(1) recursively searches for the executable filter command:
+
+- First it looks in the user's `$HOME/.asciidoc/filters` directory.
+- Next the global filters directory (usually `/etc/asciidoc/filters`
+  or `/usr/local/etc/asciidoc`) directory is searched.
+- Then it looks in the asciidoc(1) `./filters` directory.
+- Finally it relies on the executing shell to search the environment
+  search path (`$PATH`).
+
+Standard practice is to install each filter in it's own sub-directory
+with the same name as the filter's style definition. For example the
+music filter's style name is 'music' so it's configuration and filter
+files are stored in the `filters/music` directory.
+
+Filter Configuration Files
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+Filters are normally accompanied by a configuration file containing a
+Paragraph or DelimitedBlock definition along with corresponding markup
+templates.
+
+While it is possible to create new 'Paragraph' or 'DelimitedBlock'
+definitions the preferred way to implement a filter is to add a
+<<X23,style>> to the existing Paragraph and ListingBlock definitions
+(all filters shipped with AsciiDoc use this technique). The filter is
+applied to the paragraph or delimited block by preceding it with an
+attribute list: the first positional attribute is the style name,
+remaining attributes are normally filter specific parameters.
+
+asciidoc(1) auto-loads all `.conf` files found in the filter search
+paths unless the container directory also contains a file named
+`__noautoload__` (see previous section). The `__noautoload__` feature
+is used for filters that will be loaded manually using the `--filter`
+option.
+
+[[X56]]
+Example Filter
+~~~~~~~~~~~~~~
+AsciiDoc comes with a toy filter for highlighting source code keywords
+and comments.  See also the `./filters/code/code-filter-readme.txt`
+file.
+
+NOTE: The purpose of this toy filter is to demonstrate how to write a
+filter -- it's much to simplistic to be passed off as a code syntax
+highlighter.  If you want a full featured multi-language highlighter
+use the {website}source-highlight-filter.html[source code highlighter
+filter].
+
+Built-in filters
+~~~~~~~~~~~~~~~~
+The AsciiDoc distribution includes 'source', 'music', 'latex' and
+'graphviz' filters, details are on the
+{website}index.html#_filters[AsciiDoc website].
+
+[cols="1e,5",frame="topbot",options="header"]
+.Built-in filters list
+|====================================================================
+|Filter name |Description
+
+|music
+|A {website}music-filter.html[music filter] is included in the
+distribution `./filters/` directory. It translates music in
+http://lilypond.org/[LilyPond] or http://abcnotation.org.uk/[ABC]
+notation to standard classical notation.
+
+|source
+|A {website}source-highlight-filter.html[source code highlight filter]
+is included in the distribution `./filters/` directory.
+
+|latex
+|The {website}latex-filter.html[AsciiDoc LaTeX filter] translates
+LaTeX source to a PNG image that is automatically inserted into the
+AsciiDoc output documents.
+
+|graphviz
+|Gouichi Iisaka has written a http://www.graphviz.org/[Graphviz]
+filter for AsciiDoc.  Graphviz generates diagrams from a textual
+specification. Gouichi Iisaka's Graphviz filter is included in the
+AsciiDoc distribution. Here are some
+{website}asciidoc-graphviz-sample.html[AsciiDoc Graphviz examples].
+
+|====================================================================
+
+[[X58]]
+Filter plugins
+~~~~~~~~~~~~~~
+Filter <<X101,plugins>> are a mechanism for distributing AsciiDoc
+filters.  A filter plugin is a Zip file containing the files that
+constitute a filter.  The asciidoc(1) `--filter` option is used to
+load and manage filer <<X101,plugins>>.
+
+- Filter plugins <<X27,take precedence>> over built-in filters with
+  the same name.
+- By default filter plugins are installed in
+  `$HOME/.asciidoc/filters/<filter>` where `<filter>` is the filter
+  name.
+
+
+[[X101]]
+Plugins
+-------
+The AsciiDoc plugin architecture is an extension mechanism that allows
+additional <<X100,backends>>, <<X58,filters>> and <<X99,themes>> to be
+added to AsciiDoc.
+
+- A plugin is a Zip file containing an AsciiDoc backend, filter or
+  theme (configuration files, stylesheets, scripts, images).
+- The asciidoc(1) `--backend`, `--filter` and `--theme` command-line
+  options are used to load and manage plugins. Each of these options
+  responds to the plugin management 'install', 'list', 'remove' and
+  'build' commands.
+- The plugin management command names are reserved and cannot be used
+  for filter, backend or theme names.
+- The plugin Zip file name always begins with the backend, filter or
+  theme name.
+
+Plugin commands and conventions are documented in the asciidoc(1) man
+page.  You can find lists of plugins on the
+{website}plugins.html[AsciiDoc website].
+
+
+[[X36]]
+Help Commands
+-------------
+The asciidoc(1) command has a `--help` option which prints help topics
+to stdout. The default topic summarizes asciidoc(1) usage:
+
+  $ asciidoc --help
+
+To print a help topic specify the topic name as a command argument.
+Help topic names can be shortened so long as they are not ambiguous.
+Examples:
+
+  $ asciidoc --help manpage
+  $ asciidoc -h m              # Short version of previous example.
+  $ asciidoc --help syntax
+  $ asciidoc -h s              # Short version of previous example.
+
+Customizing Help
+~~~~~~~~~~~~~~~~
+To change, delete or add your own help topics edit a help
+configuration file.  The help file name `help-<lang>.conf` is based on
+the setting of the `lang` attribute, it defaults to `help.conf`
+(English).  The <<X27,help file location>> will depend on whether you
+want the topics to apply to all users or just the current user.
+
+The help topic files have the same named section format as other
+<<X7,configuration files>>. The `help.conf` files are stored in the
+same locations and loaded in the same order as other configuration
+files.
+
+When the `--help` command-line option is specified AsciiDoc loads the
+appropriate help files and then prints the contents of the section
+whose name matches the help topic name.  If a topic name is not
+specified `default` is used. You don't need to specify the whole help
+topic name on the command-line, just enough letters to ensure it's not
+ambiguous. If a matching help file section is not found a list of
+available topics is printed.
+
+
+Tips and Tricks
+---------------
+
+Know Your Editor
+~~~~~~~~~~~~~~~~
+Writing AsciiDoc documents will be a whole lot more pleasant if you
+know your favorite text editor. Learn how to indent and reformat text
+blocks, paragraphs, lists and sentences. <<X20,Tips for 'vim' users>>
+follow.
+
+[[X20]]
+Vim Commands for Formatting AsciiDoc
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Text Wrap Paragraphs
+^^^^^^^^^^^^^^^^^^^^
+Use the vim `:gq` command to reformat paragraphs. Setting the
+'textwidth' sets the right text wrap margin; for example:
+
+  :set textwidth=70
+
+To reformat a paragraph:
+
+1. Position the cursor at the start of the paragraph.
+2. Type `gq}`.
+
+Execute `:help gq` command to read about the vim gq command.
+
+[TIP]
+=====================================================================
+- Assign the `gq}` command to the Q key with the `nnoremap Q gq}`
+  command or put it in your `~/.vimrc` file to so it's always
+  available (see the <<X61, Example `~/.vimrc` file>>).
+- Put `set` commands in your `~/.vimrc` file so you don't have to
+  enter them manually.
+- The Vim website (http://www.vim.org) has a wealth of resources,
+  including scripts for automated spell checking and ASCII Art
+  drawing.
+=====================================================================
+
+Format Lists
+^^^^^^^^^^^^
+The `gq` command can also be used to format bulleted, numbered and
+callout lists. First you need to set the `comments`, `formatoptions`
+and `formatlistpat` (see the <<X61, Example `~/.vimrc` file>>).
+
+Now you can format simple lists that use dash, asterisk, period and
+plus bullets along with numbered ordered lists:
+
+1. Position the cursor at the start of the list.
+2. Type `gq}`.
+
+Indent Paragraphs
+^^^^^^^^^^^^^^^^^
+Indent whole paragraphs by indenting the fist line with the desired
+indent and then executing the `gq}` command.
+
+[[X61]]
+Example `~/.vimrc` File
+^^^^^^^^^^^^^^^^^^^^^^^
+---------------------------------------------------------------------
+" Use bold bright fonts.
+set background=dark
+
+" Show tabs and trailing characters.
+set listchars=tab:»·,trail:·
+set list
+
+" Don't highlight searched text.
+highlight clear Search
+
+" Don't move to matched text while search pattern is being entered.
+set noincsearch
+
+" Reformat paragraphs and list.
+nnoremap R gq}
+
+" Delete trailing white space and Dos-returns and to expand tabs to spaces.
+nnoremap S :set et<CR>:retab!<CR>:%s/[\r \t]\+$//<CR>
+
+autocmd BufRead,BufNewFile *.txt,README,TODO,CHANGELOG,NOTES
+        \ setlocal autoindent expandtab tabstop=8 softtabstop=2 shiftwidth=2 filetype=asciidoc
+        \ textwidth=70 wrap formatoptions=tcqn
+        \ formatlistpat=^\\s*\\d\\+\\.\\s\\+\\\\|^\\s*<\\d\\+>\\s\\+\\\\|^\\s*[a-zA-Z.]\\.\\s\\+\\\\|^\\s*[ivxIVX]\\+\\.\\s\\+
+        \ comments=s1:/*,ex:*/,://,b:#,:%,:XCOMM,fb:-,fb:*,fb:+,fb:.,fb:>
+---------------------------------------------------------------------
+
+Troubleshooting
+~~~~~~~~~~~~~~~
+AsciiDoc diagnostic features are detailed in the <<X82,Diagnostics
+appendix>>.
+
+Gotchas
+~~~~~~~
+Incorrect character encoding::
+    If you get an error message like `'UTF-8' codec can't decode ...`
+    then you source file contains invalid UTF-8 characters -- set the
+    AsciiDoc <<X54,encoding attribute>> for the correct character set
+    (typically ISO-8859-1 (Latin-1) for European languages).
+
+Invalid output::
+    AsciiDoc attempts to validate the input AsciiDoc source but makes
+    no attempt to validate the output markup, it leaves that to
+    external tools such as `xmllint(1)` (integrated into `a2x(1)`).
+    Backend validation cannot be hardcoded into AsciiDoc because
+    backends are dynamically configured. The following example
+    generates valid HTML but invalid DocBook (the DocBook `literal`
+    element cannot contain an `emphasis` element):
+
+    +monospaced text with an _emphasized_ word+
+
+Misinterpreted text formatting::
+    You can suppress markup expansion by placing a backslash character
+    immediately in front of the element. The following example
+    suppresses inline monospaced formatting:
+
+    \+1 for C++.
+
+Overlapping text formatting::
+    Overlapping text formatting will generate illegal overlapping
+    markup tags which will result in downstream XML parsing errors.
+    Here's an example:
+
+    Some *strong markup _that overlaps* emphasized markup_.
+
+Ambiguous underlines::
+    A DelimitedBlock can immediately follow a paragraph without an
+    intervening blank line, but be careful, a single line paragraph
+    underline may be misinterpreted as a section title underline
+    resulting in a ``closing block delimiter expected'' error.
+
+Ambiguous ordered list items::
+    Lines beginning with numbers at the end of sentences will be
+    interpreted as ordered list items.  The following example
+    (incorrectly) begins a new list with item number 1999:
+
+    He was last sighted in
+    1999. Since then things have moved on.
++
+The 'list item out of sequence' warning makes it unlikely that this
+problem will go unnoticed.
+
+Special characters in attribute values::
+    Special character substitution precedes attribute substitution so
+    if attribute values contain special characters you may, depending
+    on the substitution context, need to escape the special characters
+    yourself. For example:
+
+    $ asciidoc -a 'orgname=Bill & Ben Inc.' mydoc.txt
+
+Attribute lists::
+    If any named attribute entries are present then all string
+    attribute values must be quoted.  For example:
+
+    ["Desktop screenshot",width=32]
+
+[[X90]]
+Combining separate documents
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+You have a number of stand-alone AsciiDoc documents that you want to
+process as a single document. Simply processing them with a series of
+`include` macros won't work because the documents contain (level 0)
+document titles.  The solution is to create a top level wrapper
+document and use the `leveloffset` attribute to push them all down one
+level. For example:
+
+[listing]
+.....................................................................
+Combined Document Title
+=======================
+
+// Push titles down one level.
+:leveloffset: 1
+
+\include::document1.txt[]
+
+// Return to normal title levels.
+:leveloffset: 0
+
+A Top Level Section
+-------------------
+Lorum ipsum.
+
+// Push titles down one level.
+:leveloffset: 1
+
+\include::document2.txt[]
+
+\include::document3.txt[]
+.....................................................................
+
+The document titles in the included documents will now be processed as
+level 1 section titles, level 1 sections as level 2 sections and so
+on.
+
+- Put a blank line between the `include` macro lines to ensure the
+  title of the included document is not seen as part of the last
+  paragraph of the previous document.
+- You won't want non-title document header lines (for example, Author
+  and Revision lines) in the included files -- conditionally exclude
+  them if they are necessary for stand-alone processing.
+
+Processing document sections separately
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+You have divided your AsciiDoc document into separate files (one per
+top level section) which are combined and processed with the following
+top level document:
+
+---------------------------------------------------------------------
+Combined Document Title
+=======================
+Joe Bloggs
+v1.0, 12-Aug-03
+
+\include::section1.txt[]
+
+\include::section2.txt[]
+
+\include::section3.txt[]
+---------------------------------------------------------------------
+
+You also want to process the section files as separate documents.
+This is easy because asciidoc(1) will quite happily process
+`section1.txt`, `section2.txt` and `section3.txt` separately -- the
+resulting output documents contain the section but have no document
+title.
+
+Processing document snippets
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Use the `-s` (`--no-header-footer`) command-line option to suppress
+header and footer output, this is useful if the processed output is to
+be included in another file. For example:
+
+  $ asciidoc -sb docbook section1.txt
+
+asciidoc(1) can be used as a filter, so you can pipe chunks of text
+through it. For example:
+
+  $ echo 'Hello *World!*' | asciidoc -s -
+  <div class="paragraph"><p>Hello <strong>World!</strong></p></div>
+
+Badges in HTML page footers
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+See the `[footer]` section in the AsciiDoc distribution `xhtml11.conf`
+configuration file.
+
+Pretty printing AsciiDoc output
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+If the indentation and layout of the asciidoc(1) output is not to your
+liking you can:
+
+1. Change the indentation and layout of configuration file markup
+   template sections. The `{empty}` attribute is useful for outputting
+   trailing blank lines in markup templates.
+
+2. Use Dave Raggett's http://tidy.sourceforge.net/[HTML Tidy] program
+   to tidy asciidoc(1) output. Example:
+
+   $ asciidoc -b docbook -o - mydoc.txt | tidy -indent -xml >mydoc.xml
+
+3. Use the `xmllint(1)` format option. Example:
+
+   $ xmllint --format mydoc.xml
+
+Supporting minor DocBook DTD variations
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The conditional inclusion of DocBook SGML markup at the end of the
+distribution `docbook45.conf` file illustrates how to support minor
+DTD variations. The included sections override corresponding entries
+from preceding sections.
+
+Creating stand-alone HTML documents
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+If you've ever tried to send someone an HTML document that includes
+stylesheets and images you'll know that it's not as straight-forward
+as exchanging a single file.  AsciiDoc has options to create
+stand-alone documents containing embedded images, stylesheets and
+scripts.  The following AsciiDoc command creates a single file
+containing <<X66,embedded images>>, CSS stylesheets, and JavaScript
+(for table of contents and footnotes):
+
+  $ asciidoc -a data-uri -a icons -a toc -a max-width=55em article.txt
+
+You can view the HTML file here: {website}article-standalone.html[]
+
+Shipping stand-alone AsciiDoc source
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Reproducing presentation documents from someone else's source has one
+major problem: unless your configuration files are the same as the
+creator's you won't get the same output.
+
+The solution is to create a single backend specific configuration file
+using the asciidoc(1) `-c` (`--dump-conf`) command-line option. You
+then ship this file along with the AsciiDoc source document plus the
+`asciidoc.py` script. The only end user requirement is that they have
+Python installed (and that they consider you a trusted source). This
+example creates a composite HTML configuration file for `mydoc.txt`:
+
+  $ asciidoc -cb xhtml11 mydoc.txt > mydoc-xhtml11.conf
+
+Ship `mydoc.txt`, `mydoc-html.conf`, and `asciidoc.py`. With
+these three files (and a Python interpreter) the recipient can
+regenerate the HMTL output:
+
+  $ ./asciidoc.py -eb xhtml11 mydoc.txt
+
+The `-e` (`--no-conf`) option excludes the use of implicit
+configuration files, ensuring that only entries from the
+`mydoc-html.conf` configuration are used.
+
+Inserting blank space
+~~~~~~~~~~~~~~~~~~~~~
+Adjust your style sheets to add the correct separation between block
+elements. Inserting blank paragraphs containing a single non-breaking
+space character `{nbsp}` works but is an ad hoc solution compared
+to using style sheets.
+
+Closing open sections
+~~~~~~~~~~~~~~~~~~~~~
+You can close off section tags up to level `N` by calling the
+`eval::[Section.setlevel(N)]` system macro. This is useful if you
+want to include a section composed of raw markup. The following
+example includes a DocBook glossary division at the top section level
+(level 0):
+
+---------------------------------------------------------------------
+\ifdef::basebackend-docbook[]
+
+\eval::[Section.setlevel(0)]
+
++++++++++++++++++++++++++++++++
+<glossary>
+  <title>Glossary
+  
+  ...
+  
+
++++++++++++++++++++++++++++++++
+\endif::basebackend-docbook[]
+---------------------------------------------------------------------
+
+Validating output files
+~~~~~~~~~~~~~~~~~~~~~~~
+Use `xmllint(1)` to check the AsciiDoc generated markup is both well
+formed and valid. Here are some examples:
+
+  $ xmllint --nonet --noout --valid docbook-file.xml
+  $ xmllint --nonet --noout --valid xhtml11-file.html
+  $ xmllint --nonet --noout --valid --html html4-file.html
+
+The `--valid` option checks the file is valid against the document
+type's DTD, if the DTD is not installed in your system's catalog then
+it will be fetched from its Internet location. If you omit the
+`--valid` option the document will only be checked that it is well
+formed.
+
+The online http://validator.w3.org/#validate_by_uri+with_options[W3C
+Markup Validation Service] is the defacto standard when it comes to
+validating HTML (it validates all HTML standards including HTML5).
+
+
+:numbered!:
+
+[glossary]
+Glossary
+--------
+[glossary]
+[[X8]] Block element::
+    An AsciiDoc block element is a document entity composed of one or
+    more whole lines of text.
+
+[[X34]] Inline element::
+    AsciiDoc inline elements occur within block element textual
+    content, they perform formatting and substitution tasks.
+
+Formal element::
+    An AsciiDoc block element that has a BlockTitle. Formal elements
+    are normally listed in front or back matter, for example lists of
+    tables, examples and figures.
+
+Verbatim element::
+    The word verbatim indicates that white space and line breaks in
+    the source document are to be preserved in the output document.
+
+
+[appendix]
+Migration Notes
+---------------
+[[X53]]
+Version 7 to version 8
+~~~~~~~~~~~~~~~~~~~~~~
+- A new set of quotes has been introduced which may match inline text
+  in existing documents -- if they do you'll need to escape the
+  matched text with backslashes.
+- The index entry inline macro syntax has changed -- if your documents
+  include indexes you may need to edit them.
+- Replaced a2x(1) `--no-icons` and `--no-copy` options with their
+  negated equivalents: `--icons` and `--copy` respectively. The
+  default behavior has also changed -- the use of icons and copying of
+  icon and CSS files must be specified explicitly with the `--icons`
+  and `--copy` options.
+
+The rationale for the changes can be found in the AsciiDoc
+`CHANGELOG`.
+
+NOTE: If you want to disable unconstrained quotes, the new alternative
+constrained quotes syntax and the new index entry syntax then you can
+define the attribute `asciidoc7compatible` (for example by using the
+`-a asciidoc7compatible` command-line option).
+
+[[X38]]
+[appendix]
+Packager Notes
+--------------
+Read the `README` and `INSTALL` files (in the distribution root
+directory) for install prerequisites and procedures.  The distribution
+`Makefile.in` (used by `configure` to generate the `Makefile`) is the
+canonical installation procedure.
+
+
+[[X39]]
+[appendix]
+AsciiDoc Safe Mode
+-------------------
+AsciiDoc 'safe mode' skips potentially dangerous scripted sections in
+AsciiDoc source files by inhibiting the execution of arbitrary code or
+the inclusion of arbitrary files.
+
+The safe mode is disabled by default, it can be enabled with the
+asciidoc(1) `--safe` command-line option.
+
+.Safe mode constraints
+- `eval`, `sys` and `sys2` executable attributes and block macros are
+  not executed.
+- `include::[]` and `include1::[]` block macro
+  files must reside inside the parent file's directory.
+- `{include:}` executable attribute files must reside
+  inside the source document directory.
+- Passthrough Blocks are dropped.
+
+[WARNING]
+=====================================================================
+The safe mode is not designed to protect against unsafe AsciiDoc
+configuration files. Be especially careful when:
+
+1. Implementing filters.
+2. Implementing elements that don't escape special characters.
+3. Accepting configuration files from untrusted sources.
+=====================================================================
+
+
+[appendix]
+Using AsciiDoc with non-English Languages
+-----------------------------------------
+AsciiDoc can process UTF-8 character sets but there are some things
+you need to be aware of:
+
+- If you are generating output documents using a DocBook toolchain
+  then you should set the AsciiDoc `lang` attribute to the appropriate
+  language (it defaults to `en` (English)). This will ensure things
+  like table of contents, figure and table captions and admonition
+  captions are output in the specified language.  For example:
+
+  $ a2x -a lang=es doc/article.txt
+
+- If you are outputting HTML directly from asciidoc(1) you'll
+  need to set the various `*_caption` attributes to match your target
+  language (see the list of captions and titles in the `[attributes]`
+  section of the distribution `lang-*.conf` files). The easiest way is
+  to create a language `.conf` file (see the AsciiDoc's `lang-en.conf`
+  file).
++
+NOTE: You still use the 'NOTE', 'CAUTION', 'TIP', 'WARNING',
+'IMPORTANT' captions in the AsciiDoc source, they get translated in
+the HTML output file.
+
+- asciidoc(1) automatically loads configuration files named like
+  `lang-.conf` where `` is a two letter language code that
+  matches the current AsciiDoc `lang` attribute. See also
+  <>.
+
+
+[appendix]
+Vim Syntax Highlighter
+----------------------
+Syntax highlighting is incredibly useful, in addition to making
+reading AsciiDoc documents much easier syntax highlighting also helps
+you catch AsciiDoc syntax errors as you write your documents.
+
+The AsciiDoc `./vim/` distribution directory contains Vim syntax
+highlighter and filetype detection scripts for AsciiDoc.  Syntax
+highlighting makes it much easier to spot AsciiDoc syntax errors.
+
+If Vim is installed on your system the AsciiDoc installer
+(`install.sh`) will automatically install the vim scripts in the Vim
+global configuration directory (`/etc/vim`).
+
+You can also turn on syntax highlighting by adding the following line
+to the end of you AsciiDoc source files:
+
+  // vim: set syntax=asciidoc:
+
+TIP: Bold fonts are often easier to read, use the Vim `:set
+background=dark` command to set bold bright fonts.
+
+NOTE: There are a number of alternative syntax highlighters for
+various editors listed on the {website}[AsciiDoc website].
+
+Limitations
+~~~~~~~~~~~
+The current implementation does a reasonable job but on occasions gets
+things wrong:
+
+- Nested quoted text formatting is highlighted according to the outer
+  format.
+- If a closing Example Block delimiter is sometimes mistaken for a
+  title underline. A workaround is to insert a blank line before the
+  closing delimiter.
+- Lines within a paragraph starting with equals characters may be
+  highlighted as single-line titles.
+- Lines within a paragraph beginning with a period may be highlighted
+  as block titles.
+
+
+[[X74]]
+[appendix]
+Attribute Options
+-----------------
+Here is the list of predefined <>:
+
+
+[cols="2e,2,2,5",frame="topbot",options="header"]
+|====================================================================
+|Option|Backends|AsciiDoc Elements|Description
+
+|autowidth |xhtml11, html5, html4 |table|
+The column widths are determined by the browser, not the AsciiDoc
+'cols' attribute. If there is no 'width' attribute the table width is
+also left up to the browser.
+
+|unbreakable |xhtml11, html5 |block elements|
+'unbreakable' attempts to keep the block element together on a single
+printed page c.f. the 'breakable' and 'unbreakable' docbook (XSL/FO)
+options below.
+
+|breakable, unbreakable |docbook (XSL/FO) |table, example, block image|
+The 'breakable' options allows block elements to break across page
+boundaries; 'unbreakable' attempts to keep the block element together
+on a single page. If neither option is specified the default XSL
+stylesheet behavior prevails.
+
+|compact |docbook, xhtml11, html5 |bulleted list, numbered list|
+Minimizes vertical space in the list
+
+|footer |docbook, xhtml11, html5, html4 |table|
+The last row of the table is rendered as a footer.
+
+|header |docbook, xhtml11, html5, html4 |table|
+The first row of the table is rendered as a header.
+
+|pgwide |docbook (XSL/FO) |table, block image, horizontal labeled list|
+Specifies that the element should be rendered across the full text
+width of the page irrespective of the current indentation.
+
+|strong |xhtml11, html5, html4 |labeled lists|
+Emboldens label text.
+|====================================================================
+
+
+[[X82]]
+[appendix]
+Diagnostics
+-----------
+The `asciidoc(1)` `--verbose` command-line option prints additional
+information to stderr: files processed, filters processed, warnings,
+system attribute evaluation.
+
+A special attribute named 'trace' enables the output of
+element-by-element diagnostic messages detailing output markup
+generation to stderr.  The 'trace' attribute can be set on the
+command-line or from within the document using <> (the latter allows tracing to be confined to specific
+portions of the document).
+
+- Trace messages print the source file name and line number and the
+  trace name followed by related markup.
+- 'trace names' are normally the names of AsciiDoc elements (see the
+  list below).
+- The trace message is only printed if the 'trace' attribute value
+  matches the start of a 'trace name'. The 'trace' attribute value can
+  be any Python regular expression.  If a trace value is not specified
+  all trace messages will be printed (this can result in large amounts
+  of output if applied to the whole document).
+
+- In the case of inline substitutions:
+  * The text before and after the substitution is printed; the before
+    text is preceded by a line containing `<<<` and the after text by
+    a line containing `>>>`.
+  * The 'subs' trace value is an alias for all inline substitutions.
+
+.Trace names
+.....................................................................
+ block close
+ block open
+
+dropped line (a line containing an undefined attribute reference).
+floating title
+footer
+header
+list close
+list entry close
+list entry open
+list item close
+list item open
+list label close
+list label open
+list open
+macro block (a block macro)
+name (man page NAME section)
+paragraph
+preamble close
+preamble open
+push blockname
+pop blockname
+section close
+section open: level 
+subs (all inline substitutions)
+table
+.....................................................................
+
+Where:
+
+- `` is section level number '0...4'.
+- `` is a delimited block name: 'comment', 'sidebar',
+  'open', 'pass', 'listing', 'literal', 'quote', 'example'.
+- `` is an inline substitution type:
+  'specialcharacters','quotes','specialwords', 'replacements',
+  'attributes','macros','callouts', 'replacements2', 'replacements3'.
+
+Command-line examples:
+
+. Trace the entire document.
+
+  $ asciidoc -a trace mydoc.txt
+
+. Trace messages whose names start with `quotes` or `macros`:
+
+  $ asciidoc -a 'trace=quotes|macros'  mydoc.txt
+
+. Print the first line of each trace message:
+
+  $ asciidoc -a trace mydoc.txt 2>&1 | grep ^TRACE:
+
+Attribute Entry examples:
+
+. Begin printing all trace messages:
+
+  :trace:
+
+. Print only matched trace messages:
+
+  :trace: quotes|macros
+
+. Turn trace messages off:
+
+  :trace!:
+
+
+[[X88]]
+[appendix]
+Backend Attributes
+------------------
+This table contains a list of optional attributes that influence the
+generated outputs.
+
+[cols="1e,1,5a",frame="topbot",options="header"]
+|====================================================================
+|Name |Backends |Description
+
+|badges |xhtml11, html5 |
+Link badges ('XHTML 1.1' and 'CSS') in document footers. By default
+badges are omitted ('badges' is undefined).
+
+NOTE: The path names of images, icons and scripts are relative path
+names to the output document not the source document.
+
+|data-uri |xhtml11, html5 |
+Embed images using the <>.
+
+|css-signature |html5, xhtml11 |
+Set a 'CSS signature' for the document (sets the 'id' attribute of the
+HTML 'body' element). CSS signatures provide a mechanism that allows
+users to personalize the document appearance. The term 'CSS signature'
+was http://archivist.incutio.com/viewlist/css-discuss/13291[coined by
+Eric Meyer].
+
+
+|disable-javascript |xhtml11, html5 |
+If the `disable-javascript` attribute is defined the `asciidoc.js`
+JavaScript is not embedded or linked to the output document.  By
+default AsciiDoc automatically embeds or links the `asciidoc.js`
+JavaScript to the output document. The script dynamically generates
+<> and <>.
+
+|[[X97]] docinfo, docinfo1, docinfo2 |All backends |
+These three attributes control which <> will be included in the the header of the output file:
+
+docinfo:: Include `-docinfo.`
+docinfo1:: Include `docinfo.`
+docinfo2:: Include `docinfo.` and `-docinfo.`
+
+Where `` is the file name (sans extension) of the AsciiDoc
+input file and `` is `.html` for HTML outputs or `.xml` for
+DocBook outputs. If the input file is the standard input then the
+output file name is used. The following example will include the
+`mydoc-docinfo.xml` docinfo file in the DocBook `mydoc.xml` output
+file:
+
+  $ asciidoc -a docinfo -b docbook mydoc.txt
+
+This next example will include `docinfo.html` and `mydoc-docinfo.html`
+docinfo files in the HTML output file:
+
+  $ asciidoc -a docinfo2 -b html4 mydoc.txt
+
+
+|[[X54]]encoding |html4, html5, xhtml11, docbook |
+Set the input and output document character set encoding. For example
+the `--attribute encoding=ISO-8859-1` command-line option will set the
+character set encoding to `ISO-8859-1`.
+
+- The default encoding is UTF-8.
+- This attribute specifies the character set in the output document.
+- The encoding name must correspond to a Python codec name or alias.
+- The 'encoding' attribute can be set using an AttributeEntry inside
+  the document header. For example:
+
+  :encoding: ISO-8859-1
+
+|[[X45]]icons |xhtml11, html5 |
+Link admonition paragraph and admonition block icon images and badge
+images. By default 'icons' is undefined and text is used in place of
+icon images.
+
+|[[X44]]iconsdir |html4, html5, xhtml11, docbook |
+The name of the directory containing linked admonition icons,
+navigation icons and the `callouts` sub-directory (the `callouts`
+sub-directory contains <> number images). 'iconsdir'
+defaults to `./images/icons`.
+
+|imagesdir |html4, html5, xhtml11, docbook |
+If this attribute is defined it is prepended to the target image file
+name paths in inline and block image macros.
+
+|keywords, description, title |html4, html5, xhtml11 |
+The 'keywords' and 'description' attributes set the correspondingly
+named HTML meta tag contents; the 'title' attribute sets the HTML
+title tag contents.  Their principle use is for SEO (Search Engine
+Optimisation).  All three are optional, but if they are used they must
+appear in the document header (or on the command-line). If 'title' is
+not specified the AsciiDoc document title is used.
+
+|linkcss |html5, xhtml11 |
+Link CSS stylesheets and JavaScripts. By default 'linkcss' is
+undefined in which case stylesheets and scripts are automatically
+embedded in the output document.
+
+|[[X103]]max-width |html5, xhtml11 |
+Set the document maximum display width (sets the 'body' element CSS
+'max-width' property).
+
+|numbered |html4, html5, xhtml11, docbook (XSL Stylesheets) |
+Adds section numbers to section titles. The 'docbook' backend ignores
+'numbered' attribute entries after the document header.
+
+|plaintext | All backends |
+If this global attribute is defined all inline substitutions are
+suppressed and block indents are retained.  This option is useful when
+dealing with large amounts of imported plain text.
+
+|quirks |xhtml11 |
+Include the `xhtml11-quirks.conf` configuration file and
+`xhtml11-quirks.css` <> to work around IE6 browser
+incompatibilities. This feature is deprecated and its use is
+discouraged -- documents are still viewable in IE6 without it.
+
+|revremark |docbook |
+A short summary of changes in this document revision. Must be defined
+prior to the first document section. The document also needs to be
+dated to output this attribute.
+
+|scriptsdir |html5, xhtml11 |
+The name of the directory containing linked JavaScripts.
+See <>.
+
+|sgml |docbook45 |
+The `--backend=docbook45` command-line option produces DocBook 4.5
+XML.  You can produce the older DocBook SGML format using the
+`--attribute sgml` command-line option.
+
+|stylesdir |html5, xhtml11 |
+The name of the directory containing linked or embedded
+<>.
+See <>.
+
+|stylesheet |html5, xhtml11 |
+The file name of an optional additional CSS <>.
+
+|theme |html5, xhtml11 |
+Use alternative stylesheet (see <>).
+
+|[[X91]]toc |html5, xhtml11, docbook (XSL Stylesheets) |
+Adds a table of contents to the start of an article or book document.
+The `toc` attribute can be specified using the `--attribute toc`
+command-line option or a `:toc:` attribute entry in the document
+header. The 'toc' attribute is defined by default when the 'docbook'
+backend is used. To disable table of contents generation undefine the
+'toc' attribute by putting a `:toc!:` attribute entry in the document
+header or from the command-line with an `--attribute toc!` option.
+
+*xhtml11 and html5 backends*
+
+- JavaScript needs to be enabled in your browser.
+- The following example generates a numbered table of contents using a
+  JavaScript embedded in the `mydoc.html` output document:
+
+  $ asciidoc -a toc -a numbered mydoc.txt
+
+|toc2 |html5, xhtml11 |
+Adds a scrollable table of contents in the left hand margin of an
+article or book document. Use the 'max-width' attribute to change the
+content width. In all other respects behaves the same as the 'toc'
+attribute.
+
+|toc-placement |html5, xhtml11 |
+When set to 'auto' (the default value) asciidoc(1) will place the
+table of contents in the document header. When 'toc-placement' is set
+to 'manual' the TOC can be positioned anywhere in the document by
+placing the `toc::[]` block macro at the point you want the TOC to
+appear.
+
+NOTE: If you use 'toc-placement' then you also have to define the
+<> attribute.
+
+|toc-title |html5, xhtml11 |
+Sets the table of contents title (defaults to 'Table of Contents').
+
+|toclevels |html5, xhtml11 |
+Sets the number of title levels (1..4) reported in the table of
+contents (see the 'toc' attribute above). Defaults to 2 and must be
+used with the 'toc' attribute. Example usage:
+
+  $ asciidoc -a toc -a toclevels=3 doc/asciidoc.txt
+
+|====================================================================
+
+
+[appendix]
+License
+-------
+AsciiDoc is free software; you can redistribute it and/or modify it
+under the terms of the 'GNU General Public License version 2' (GPLv2)
+as published by the Free Software Foundation.
+
+AsciiDoc is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License version 2 for more details.
+
+AsciiDoc Highlighter sponsored by O'Reilly Media
+
+Copyright (C) 2002-2011 Stuart Rackham.
diff --git a/node_modules/ace/demo/kitchen-sink/docs/assembly_x86.asm b/node_modules/ace/demo/kitchen-sink/docs/assembly_x86.asm
new file mode 100644
index 00000000..01e8305c
--- /dev/null
+++ b/node_modules/ace/demo/kitchen-sink/docs/assembly_x86.asm
@@ -0,0 +1,18 @@
+section	.text
+    global main         ;must be declared for using gcc
+
+main:	                ;tell linker entry point
+
+	mov	edx, len	    ;message length
+	mov	ecx, msg	    ;message to write
+	mov	ebx, 1	        ;file descriptor (stdout)
+	mov	eax, 4	        ;system call number (sys_write)
+	int	0x80	        ;call kernel
+
+	mov	eax, 1	        ;system call number (sys_exit)
+	int	0x80	        ;call kernel
+
+section	.data
+
+msg	db	'Hello, world!',0xa	;our dear string
+len	equ	$ - msg			;length of our dear string
diff --git a/node_modules/ace/demo/kitchen-sink/docs/autohotkey.ahk b/node_modules/ace/demo/kitchen-sink/docs/autohotkey.ahk
new file mode 100644
index 00000000..73687e67
--- /dev/null
+++ b/node_modules/ace/demo/kitchen-sink/docs/autohotkey.ahk
@@ -0,0 +1,35 @@
+#NoEnv
+SetBatchLines -1
+
+CoordMode Mouse, Screen
+OnExit GuiClose
+
+zoom := 9
+
+computeSize(){
+	global as_x
+	as_x := Round(ws_x/zoom/2 - 0.5)
+	if (zoom>1) {
+		pix := Round(zoom)
+	} ele {
+		pix := 1
+	}
+    ToolTip Message %as_x% %zoom% %ws_x% %hws_x% 
+}
+
+hdc_frame := DllCall("GetDC", UInt, MagnifierID)
+
+; comment
+DrawCross(byRef x="", rX,rY,z, dc){
+        ;specify the style, thickness and color of the cross lines
+    h_pen := DllCall( "gdi32.dll\CreatePen", Int, 0, Int, 1, UInt, 0x0000FF)
+}
+
+;Ctrl ^; Shift +; Win #; Alt !
+^NumPadAdd::
+^WheelUp::   
+^;::   ;comment
+    If(zoom < ws_x and ( A_ThisHotKey = "^WheelUp" or A_ThisHotKey ="^NumPadAdd") )
+		zoom *= 1.189207115         ; sqrt(sqrt(2))
+	Gosub,setZoom
+return
diff --git a/node_modules/ace/demo/kitchen-sink/docs/batchfile.bat b/node_modules/ace/demo/kitchen-sink/docs/batchfile.bat
new file mode 100644
index 00000000..c066a9e9
--- /dev/null
+++ b/node_modules/ace/demo/kitchen-sink/docs/batchfile.bat
@@ -0,0 +1,15 @@
+:: batch file highlighting in Ace!
+@echo off
+
+CALL set var1=%cd%
+echo unhide everything in %var1%!
+
+:: FOR loop in bat is super strange!
+FOR /f "tokens=*" %%G IN ('dir /A:D /b') DO (
+echo %var1%%%G
+attrib -r -a -h -s "%var1%%%G" /D /S
+)
+
+pause
+
+REM that's all
diff --git a/node_modules/ace/demo/kitchen-sink/docs/c9search.c9search_results b/node_modules/ace/demo/kitchen-sink/docs/c9search.c9search_results
new file mode 100644
index 00000000..0ad9ccd4
--- /dev/null
+++ b/node_modules/ace/demo/kitchen-sink/docs/c9search.c9search_results
@@ -0,0 +1,25 @@
+Searching for var in/.c9/metadata/workspace/pluginsregexp, case sensitive, whole word
+
+configs/default.js:
+    1: var fs = require("fs");
+	2: var argv = require('optimist').argv;
+	3: var path = require("path");
+	5: var clientExtensions = {};
+	6: var clientDirs = fs.readdirSync(__dirname + "/../plugins-client");
+	7: for (var i = 0; i < clientDirs.length; i++) {
+	8:     var dir = clientDirs[i];
+	12:     var name = dir.split(".")[1];
+	16: var projectDir = (argv.w && path.resolve(process.cwd(), argv.w)) || process.cwd();
+	17: var fsUrl = "/workspace";
+	19: var port = argv.p || process.env.PORT || 3131;
+	20: var host = argv.l || "localhost";
+	22: var config = {
+
+configs/local.js:
+	2: var config = require("./default");
+
+configs/packed.js:
+	1: var config = require("./default");
+
+
+Found 15 matches in 3 files
\ No newline at end of file
diff --git a/node_modules/ace/demo/kitchen-sink/docs/c_cpp.cpp b/node_modules/ace/demo/kitchen-sink/docs/c_cpp.cpp
new file mode 100644
index 00000000..a2ebdaa2
--- /dev/null
+++ b/node_modules/ace/demo/kitchen-sink/docs/c_cpp.cpp
@@ -0,0 +1,44 @@
+// compound assignment operators
+
+#include 
+
+#include \
+   
+
+#include \
+   \
+   
+
+#include \
+   \
+   "iostream"
+
+#include 
+#include "boost/asio/io_service.hpp"
+
+#include \
+   \
+   "iostream" \
+   "string" \
+   
+   
+using namespace std;
+
+int main ()
+{
+    int a, b=3; /* foobar */
+    a = b;
+    a+=2; // equivalent to a=a+2
+    cout << a;
+    #if VERBOSE >= 2
+        prints("trace message");
+    #endif
+    return 0;
+}
+
+/* Print an error message and get out */
+#define ABORT                             \
+    do {                                  \
+        print( "Abort\n" );                \
+        exit(8);                          \
+} while (0)                      /* Note: No semicolon */
\ No newline at end of file
diff --git a/node_modules/ace/demo/kitchen-sink/docs/cirru.cirru b/node_modules/ace/demo/kitchen-sink/docs/cirru.cirru
new file mode 100644
index 00000000..244833df
--- /dev/null
+++ b/node_modules/ace/demo/kitchen-sink/docs/cirru.cirru
@@ -0,0 +1,42 @@
+-- https://github.com/Cirru/cirru-gopher/blob/master/code/scope.cr,
+
+set a (int 2)
+
+print (self)
+
+set c (child)
+
+under c
+  under parent
+    print a
+
+print $ get c a
+
+set c x (int 3)
+print $ get c x
+
+set just-print $ code
+  print a
+
+print just-print
+
+eval (self) just-print
+eval just-print
+
+print (string "string with space")
+print (string "escapes \n \"\\")
+
+brackets ((((()))))
+
+"eval" $ string "eval"
+
+print (add $ (int 1) (int 2))
+
+print $ unwrap $
+  map (a $ int 1) (b $ int 2)
+
+print a
+  int 1
+  , b c
+  int 2
+  , d
\ No newline at end of file
diff --git a/node_modules/ace/demo/kitchen-sink/docs/clojure.clj b/node_modules/ace/demo/kitchen-sink/docs/clojure.clj
new file mode 100644
index 00000000..42acfcc7
--- /dev/null
+++ b/node_modules/ace/demo/kitchen-sink/docs/clojure.clj
@@ -0,0 +1,19 @@
+(defn parting
+  "returns a String parting in a given language"
+  ([] (parting "World"))
+  ([name] (parting name "en"))
+  ([name language]
+    ; condp is similar to a case statement in other languages.
+    ; It is described in more detail later.
+    ; It is used here to take different actions based on whether the
+    ; parameter "language" is set to "en", "es" or something else.
+    (condp = language
+      "en" (str "Goodbye, " name)
+      "es" (str "Adios, " name)
+      (throw (IllegalArgumentException.
+        (str "unsupported language " language))))))
+
+(println (parting)) ; -> Goodbye, World
+(println (parting "Mark")) ; -> Goodbye, Mark
+(println (parting "Mark" "es")) ; -> Adios, Mark
+(println (parting "Mark", "xy")) ; -> java.lang.IllegalArgumentException: unsupported language xy
\ No newline at end of file
diff --git a/node_modules/ace/demo/kitchen-sink/docs/cobol.CBL b/node_modules/ace/demo/kitchen-sink/docs/cobol.CBL
new file mode 100644
index 00000000..30404ce4
--- /dev/null
+++ b/node_modules/ace/demo/kitchen-sink/docs/cobol.CBL
@@ -0,0 +1 @@
+TODO
\ No newline at end of file
diff --git a/node_modules/ace/demo/kitchen-sink/docs/coffee.coffee b/node_modules/ace/demo/kitchen-sink/docs/coffee.coffee
new file mode 100644
index 00000000..a7e50d08
--- /dev/null
+++ b/node_modules/ace/demo/kitchen-sink/docs/coffee.coffee
@@ -0,0 +1,22 @@
+#!/usr/bin/env coffee
+
+try
+    throw URIError decodeURI(0xC0ffee * 123456.7e-8 / .9)
+catch e
+    console.log 'qstring' + "qqstring" + '''
+        qdoc
+    ''' + """
+        qqdoc
+    """
+
+do ->
+    ###
+    herecomment
+    ###
+    re = /regex/imgy.test ///
+        heregex  # comment
+    ///imgy
+    this isnt: `just JavaScript`
+    undefined
+    
+sentence = "#{ 22 / 7 } is a decent approximation of π"
\ No newline at end of file
diff --git a/node_modules/ace/demo/kitchen-sink/docs/coldfusion.cfm b/node_modules/ace/demo/kitchen-sink/docs/coldfusion.cfm
new file mode 100644
index 00000000..750a389f
--- /dev/null
+++ b/node_modules/ace/demo/kitchen-sink/docs/coldfusion.cfm
@@ -0,0 +1,5 @@
+
+
+
+
+#welcome#
\ No newline at end of file
diff --git a/node_modules/ace/demo/kitchen-sink/docs/csharp.cs b/node_modules/ace/demo/kitchen-sink/docs/csharp.cs
new file mode 100644
index 00000000..9478be87
--- /dev/null
+++ b/node_modules/ace/demo/kitchen-sink/docs/csharp.cs
@@ -0,0 +1,4 @@
+public void HelloWorld() {
+    //Say Hello!
+    Console.WriteLine("Hello World");
+}
\ No newline at end of file
diff --git a/node_modules/ace/demo/kitchen-sink/docs/css.css b/node_modules/ace/demo/kitchen-sink/docs/css.css
new file mode 100644
index 00000000..6d2d71f5
--- /dev/null
+++ b/node_modules/ace/demo/kitchen-sink/docs/css.css
@@ -0,0 +1,18 @@
+.text-layer {
+    font: 12px Monaco, "Courier New", monospace;
+    cursor: text;
+}
+
+.blinker {
+    animation: blink 1s linear infinite alternate;
+}
+
+@keyframes blink {
+    0%, 40% {
+        opacity: 0;
+    }
+
+    40.5%, 100% {
+        opacity: 1
+    }
+}
\ No newline at end of file
diff --git a/node_modules/ace/demo/kitchen-sink/docs/curly.curly b/node_modules/ace/demo/kitchen-sink/docs/curly.curly
new file mode 100644
index 00000000..c42d6790
--- /dev/null
+++ b/node_modules/ace/demo/kitchen-sink/docs/curly.curly
@@ -0,0 +1,16 @@
+
+    
+
+    
+
+    
+    
+        

{{author_name}}

+ + diff --git a/node_modules/ace/demo/kitchen-sink/docs/d.d b/node_modules/ace/demo/kitchen-sink/docs/d.d new file mode 100644 index 00000000..57069067 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/d.d @@ -0,0 +1,14 @@ +#!/usr/bin/env rdmd +// Computes average line length for standard input. +import std.stdio; + +void main() { + ulong lines = 0; + double sumLength = 0; + foreach (line; stdin.byLine()) { + ++lines; + sumLength += line.length; + } + writeln("Average line length: ", + lines ? sumLength / lines : 0); +} \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/dart.dart b/node_modules/ace/demo/kitchen-sink/docs/dart.dart new file mode 100644 index 00000000..735a20b3 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/dart.dart @@ -0,0 +1,19 @@ +// Go ahead and modify this example. + +import "dart:html"; + +// Computes the nth Fibonacci number. +int fibonacci(int n) { + if (n < 2) return n; + return fibonacci(n - 1) + fibonacci(n - 2); +} + +// Displays a Fibonacci number. +void main() { + int i = 20; + String message = "fibonacci($i) = ${fibonacci(i)}"; + + // This example uses HTML to display the result and it will appear + // in a nested HTML frame (an iframe). + document.body.append(new HeadingElement.h1()..appendText(message)); +} diff --git a/node_modules/ace/demo/kitchen-sink/docs/diff.diff b/node_modules/ace/demo/kitchen-sink/docs/diff.diff new file mode 100644 index 00000000..16c89890 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/diff.diff @@ -0,0 +1,69 @@ +diff --git a/lib/ace/edit_session.js b/lib/ace/edit_session.js +index 23fc3fc..ed3b273 100644 +--- a/lib/ace/edit_session.js ++++ b/lib/ace/edit_session.js +@@ -51,6 +51,7 @@ var TextMode = require("./mode/text").Mode; + var Range = require("./range").Range; + var Document = require("./document").Document; + var BackgroundTokenizer = require("./background_tokenizer").BackgroundTokenizer; ++var SearchHighlight = require("./search_highlight").SearchHighlight; + + /** + * class EditSession +@@ -307,6 +308,13 @@ var EditSession = function(text, mode) { + return token; + }; + ++ this.highlight = function(re) { ++ if (!this.$searchHighlight) { ++ var highlight = new SearchHighlight(null, "ace_selected-word", "text"); ++ this.$searchHighlight = this.addDynamicMarker(highlight); ++ } ++ this.$searchHighlight.setRegexp(re); ++ } + /** + * EditSession.setUndoManager(undoManager) + * - undoManager (UndoManager): The new undo manager +@@ -556,7 +564,8 @@ var EditSession = function(text, mode) { + type : type || "line", + renderer: typeof type == "function" ? type : null, + clazz : clazz, +- inFront: !!inFront ++ inFront: !!inFront, ++ id: id + } + + if (inFront) { +diff --git a/lib/ace/editor.js b/lib/ace/editor.js +index 834e603..b27ec73 100644 +--- a/lib/ace/editor.js ++++ b/lib/ace/editor.js +@@ -494,7 +494,7 @@ var Editor = function(renderer, session) { + * Emitted when a selection has changed. + **/ + this.onSelectionChange = function(e) { +- var session = this.getSession(); ++ var session = this.session; + + if (session.$selectionMarker) { + session.removeMarker(session.$selectionMarker); +@@ -509,12 +509,40 @@ var Editor = function(renderer, session) { + this.$updateHighlightActiveLine(); + } + +- var self = this; +- if (this.$highlightSelectedWord && !this.$wordHighlightTimer) +- this.$wordHighlightTimer = setTimeout(function() { +- self.session.$mode.highlightSelection(self); +- self.$wordHighlightTimer = null; +- }, 30, this); ++ var re = this.$highlightSelectedWord && this.$getSelectionHighLightRegexp() + }; +diff --git a/lib/ace/search_highlight.js b/lib/ace/search_highlight.js +new file mode 100644 +index 0000000..b2df779 +--- /dev/null ++++ b/lib/ace/search_highlight.js +@@ -0,0 +1,3 @@ ++new ++empty file \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/dot.dot b/node_modules/ace/demo/kitchen-sink/docs/dot.dot new file mode 100644 index 00000000..1e13be7e --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/dot.dot @@ -0,0 +1,110 @@ +// Original source: http://www.graphviz.org/content/lion_share +##"A few people in the field of genetics are using dot to draw "marriage node diagram" pedigree drawings. Here is one I have done of a test pedigree from the FTREE pedigree drawing package (Lion Share was a racehorse)." Contributed by David Duffy. + +##Command to get the layout: "dot -Tpng thisfile > thisfile.png" + +digraph Ped_Lion_Share { +# page = "8.2677165,11.692913" ; +ratio = "auto" ; +mincross = 2.0 ; +label = "Pedigree Lion_Share" ; + +"001" [shape=box , regular=1,style=filled,fillcolor=white ] ; +"002" [shape=box , regular=1,style=filled,fillcolor=white ] ; +"003" [shape=circle , regular=1,style=filled,fillcolor=white ] ; +"004" [shape=box , regular=1,style=filled,fillcolor=white ] ; +"005" [shape=box , regular=1,style=filled,fillcolor=white ] ; +"006" [shape=circle , regular=1,style=filled,fillcolor=white ] ; +"007" [shape=circle , regular=1,style=filled,fillcolor=white ] ; +"009" [shape=circle , regular=1,style=filled,fillcolor=white ] ; +"014" [shape=circle , regular=1,style=filled,fillcolor=white ] ; +"015" [shape=circle , regular=1,style=filled,fillcolor=white ] ; +"016" [shape=circle , regular=1,style=filled,fillcolor=white ] ; +"ZZ01" [shape=circle , regular=1,style=filled,fillcolor=white ] ; +"ZZ02" [shape=circle , regular=1,style=filled,fillcolor=white ] ; +"017" [shape=circle , regular=1,style=filled,fillcolor=white ] ; +"012" [shape=circle , regular=1,style=filled,fillcolor=white ] ; +"008" [shape=box , regular=1,style=filled,fillcolor=white ] ; +"011" [shape=box , regular=1,style=filled,fillcolor=white ] ; +"013" [shape=box , regular=1,style=filled,fillcolor=white ] ; +"010" [shape=box , regular=1,style=filled,fillcolor=white ] ; +"023" [shape=circle , regular=1,style=filled,fillcolor=white ] ; +"020" [shape=circle , regular=1,style=filled,fillcolor=white ] ; +"021" [shape=circle , regular=1,style=filled,fillcolor=white ] ; +"018" [shape=circle , regular=1,style=filled,fillcolor=white ] ; +"025" [shape=circle , regular=1,style=filled,fillcolor=white ] ; +"019" [shape=box , regular=1,style=filled,fillcolor=white ] ; +"022" [shape=box , regular=1,style=filled,fillcolor=white ] ; +"024" [shape=box , regular=1,style=filled,fillcolor=white ] ; +"027" [shape=circle , regular=1,style=filled,fillcolor=white ] ; +"026" [shape=box , regular=1,style=filled,fillcolor=white ] ; +"028" [shape=box , regular=1,style=filled,fillcolor=grey ] ; +"marr0001" [shape=diamond,style=filled,label="",height=.1,width=.1] ; +"001" -> "marr0001" [dir=none,weight=1] ; +"007" -> "marr0001" [dir=none,weight=1] ; +"marr0001" -> "017" [dir=none, weight=2] ; +"marr0002" [shape=diamond,style=filled,label="",height=.1,width=.1] ; +"001" -> "marr0002" [dir=none,weight=1] ; +"ZZ02" -> "marr0002" [dir=none,weight=1] ; +"marr0002" -> "012" [dir=none, weight=2] ; +"marr0003" [shape=diamond,style=filled,label="",height=.1,width=.1] ; +"002" -> "marr0003" [dir=none,weight=1] ; +"003" -> "marr0003" [dir=none,weight=1] ; +"marr0003" -> "008" [dir=none, weight=2] ; +"marr0004" [shape=diamond,style=filled,label="",height=.1,width=.1] ; +"002" -> "marr0004" [dir=none,weight=1] ; +"006" -> "marr0004" [dir=none,weight=1] ; +"marr0004" -> "011" [dir=none, weight=2] ; +"marr0005" [shape=diamond,style=filled,label="",height=.1,width=.1] ; +"002" -> "marr0005" [dir=none,weight=1] ; +"ZZ01" -> "marr0005" [dir=none,weight=1] ; +"marr0005" -> "013" [dir=none, weight=2] ; +"marr0006" [shape=diamond,style=filled,label="",height=.1,width=.1] ; +"004" -> "marr0006" [dir=none,weight=1] ; +"009" -> "marr0006" [dir=none,weight=1] ; +"marr0006" -> "010" [dir=none, weight=2] ; +"marr0007" [shape=diamond,style=filled,label="",height=.1,width=.1] ; +"005" -> "marr0007" [dir=none,weight=1] ; +"015" -> "marr0007" [dir=none,weight=1] ; +"marr0007" -> "023" [dir=none, weight=2] ; +"marr0008" [shape=diamond,style=filled,label="",height=.1,width=.1] ; +"005" -> "marr0008" [dir=none,weight=1] ; +"016" -> "marr0008" [dir=none,weight=1] ; +"marr0008" -> "020" [dir=none, weight=2] ; +"marr0009" [shape=diamond,style=filled,label="",height=.1,width=.1] ; +"005" -> "marr0009" [dir=none,weight=1] ; +"012" -> "marr0009" [dir=none,weight=1] ; +"marr0009" -> "021" [dir=none, weight=2] ; +"marr0010" [shape=diamond,style=filled,label="",height=.1,width=.1] ; +"008" -> "marr0010" [dir=none,weight=1] ; +"017" -> "marr0010" [dir=none,weight=1] ; +"marr0010" -> "018" [dir=none, weight=2] ; +"marr0011" [shape=diamond,style=filled,label="",height=.1,width=.1] ; +"011" -> "marr0011" [dir=none,weight=1] ; +"023" -> "marr0011" [dir=none,weight=1] ; +"marr0011" -> "025" [dir=none, weight=2] ; +"marr0012" [shape=diamond,style=filled,label="",height=.1,width=.1] ; +"013" -> "marr0012" [dir=none,weight=1] ; +"014" -> "marr0012" [dir=none,weight=1] ; +"marr0012" -> "019" [dir=none, weight=2] ; +"marr0013" [shape=diamond,style=filled,label="",height=.1,width=.1] ; +"010" -> "marr0013" [dir=none,weight=1] ; +"021" -> "marr0013" [dir=none,weight=1] ; +"marr0013" -> "022" [dir=none, weight=2] ; +"marr0014" [shape=diamond,style=filled,label="",height=.1,width=.1] ; +"019" -> "marr0014" [dir=none,weight=1] ; +"020" -> "marr0014" [dir=none,weight=1] ; +"marr0014" -> "024" [dir=none, weight=2] ; +"marr0015" [shape=diamond,style=filled,label="",height=.1,width=.1] ; +"022" -> "marr0015" [dir=none,weight=1] ; +"025" -> "marr0015" [dir=none,weight=1] ; +"marr0015" -> "027" [dir=none, weight=2] ; +"marr0016" [shape=diamond,style=filled,label="",height=.1,width=.1] ; +"024" -> "marr0016" [dir=none,weight=1] ; +"018" -> "marr0016" [dir=none,weight=1] ; +"marr0016" -> "026" [dir=none, weight=2] ; +"marr0017" [shape=diamond,style=filled,label="",height=.1,width=.1] ; +"026" -> "marr0017" [dir=none,weight=1] ; +"027" -> "marr0017" [dir=none,weight=1] ; +"marr0017" -> "028" [dir=none, weight=2] ; +} diff --git a/node_modules/ace/demo/kitchen-sink/docs/eiffel.e b/node_modules/ace/demo/kitchen-sink/docs/eiffel.e new file mode 100644 index 00000000..943cdb35 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/eiffel.e @@ -0,0 +1,30 @@ +note + description: "Represents a person." + +class + PERSON + +create + make, make_unknown + +feature {NONE} -- Creation + + make (a_name: like name) + -- Create a person with `a_name' as `name'. + do + name := a_name + ensure + name = a_name + end + + make_unknown + do ensure + name = Void + end + +feature -- Access + + name: detachable STRING + -- Full name or Void if unknown. + +end \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/ejs.ejs b/node_modules/ace/demo/kitchen-sink/docs/ejs.ejs new file mode 100644 index 00000000..aaf497a9 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/ejs.ejs @@ -0,0 +1,31 @@ + + + + Cloud9 Rocks! + + + + + + + + + <% if (!isRoot) { %> + + + + + <% } %> + <% entries.forEach(function(entry) { %> + + + + + <% }) %> +
NameSize
..
+ + <%= entry.name %> + <%= entry.size %>
+ + + \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/elixir.ex b/node_modules/ace/demo/kitchen-sink/docs/elixir.ex new file mode 100644 index 00000000..bb6a45f1 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/elixir.ex @@ -0,0 +1,42 @@ +defmodule HelloModule do + @moduledoc """ + This is supposed to be `markdown`. + __Yes__ this is [mark](http://down.format) + + # Truly + + ## marked + + * with lists + * more + * and more + + Even.with(code) + blocks |> with |> samples + + _Docs are first class citizens in Elixir_ (Jose Valim) + """ + + # A "Hello world" function + def some_fun do + IO.puts "Juhu Kinners!" + end + # A private function + defp priv do + is_regex ~r""" + This is a regex + spanning several + lines. + """ + x = elem({ :a, :b, :c }, 0) #=> :a + end +end + +test_fun = fn(x) -> + cond do + x > 10 -> + :greater_than_ten + true -> + :maybe_ten + end +end \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/elm.elm b/node_modules/ace/demo/kitchen-sink/docs/elm.elm new file mode 100644 index 00000000..eef70b2a --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/elm.elm @@ -0,0 +1,12 @@ +{- Ace {- 4 -} Elm -} +main = lift clock (every second) + +clock t = collage 400 400 [ filled lightGrey (ngon 12 110) + , outlined (solid grey) (ngon 12 110) + , hand orange 100 t + , hand charcoal 100 (t/60) + , hand charcoal 60 (t/720) ] + +hand clr len time = + let angle = degrees (90 - 6 * inSeconds time) + in traced (solid clr) <| segment (0,0) (len * cos angle, len * sin angle) \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/erlang.erl b/node_modules/ace/demo/kitchen-sink/docs/erlang.erl new file mode 100644 index 00000000..705642b3 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/erlang.erl @@ -0,0 +1,20 @@ + %% A process whose only job is to keep a counter. + %% First version + -module(counter). + -export([start/0, codeswitch/1]). + + start() -> loop(0). + + loop(Sum) -> + receive + {increment, Count} -> + loop(Sum+Count); + {counter, Pid} -> + Pid ! {counter, Sum}, + loop(Sum); + code_switch -> + ?MODULE:codeswitch(Sum) + % Force the use of 'codeswitch/1' from the latest MODULE version + end. + + codeswitch(Sum) -> loop(Sum). \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/forth.frt b/node_modules/ace/demo/kitchen-sink/docs/forth.frt new file mode 100644 index 00000000..dc85cd7b --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/forth.frt @@ -0,0 +1,41 @@ +: HELLO ( -- ) CR ." Hello, world!" ; + +HELLO +Hello, world! + +: [CHAR] CHAR POSTPONE LITERAL ; IMMEDIATE + +0 value ii 0 value jj +0 value KeyAddr 0 value KeyLen +create SArray 256 allot \ state array of 256 bytes +: KeyArray KeyLen mod KeyAddr ; + +: get_byte + c@ ; +: set_byte + c! ; +: as_byte 255 and ; +: reset_ij 0 TO ii 0 TO jj ; +: i_update 1 + as_byte TO ii ; +: j_update ii SArray get_byte + as_byte TO jj ; +: swap_s_ij + jj SArray get_byte + ii SArray get_byte jj SArray set_byte + ii SArray set_byte +; + +: rc4_init ( KeyAddr KeyLen -- ) + 256 min TO KeyLen TO KeyAddr + 256 0 DO i i SArray set_byte LOOP + reset_ij + BEGIN + ii KeyArray get_byte jj + j_update + swap_s_ij + ii 255 < WHILE + ii i_update + REPEAT + reset_ij +; +: rc4_byte + ii i_update jj j_update + swap_s_ij + ii SArray get_byte jj SArray get_byte + as_byte SArray get_byte xor +; \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/ftl.ftl b/node_modules/ace/demo/kitchen-sink/docs/ftl.ftl new file mode 100644 index 00000000..faa573f5 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/ftl.ftl @@ -0,0 +1,46 @@ +<#ftl encoding="utf-8" /> +<#setting locale="en_US" /> +<#import "library" as lib /> +<#-- + FreeMarker comment + ${abc} <#assign a=12 /> +--> + + + + + + + ${title!"FreeMarker"}<title> + </head> + + <body> + + <h1>Hello ${name!""}</h1> + + <p>Today is: ${.now?date}</p> + + <#assign x = 13> + <#if x > 12 && x lt 14>x equals 13: ${x}</#if> + + <ul> + <#list items as item> + <li>${item_index}: ${item.name!?split("\n")[0]}</li> + </#list> + </ul> + + User directive: <@lib.function attr1=true attr2='value' attr3=-42.12>Test</@lib.function> + <@anotherOne /> + + <#if variable?exists> + Deprecated + <#elseif variable??> + Better + <#else> + Default + </#if> + + <img src="images/${user.id}.png" /> + + </body> +</html> diff --git a/node_modules/ace/demo/kitchen-sink/docs/gcode.gcode b/node_modules/ace/demo/kitchen-sink/docs/gcode.gcode new file mode 100644 index 00000000..5f47bca3 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/gcode.gcode @@ -0,0 +1,31 @@ +O003 (DIAMOND SQUARE) +N2 G54 G90 G49 G80 +N3 M6 T1 (1.ENDMILL) +N4 M3 S1800 +N5 G0 X-.6 Y2.050 +N6 G43 H1 Z.1 +N7 G1 Z-.3 F50. +N8 G41 D1 Y1.45 +N9 G1 X0 F20. +N10 G2 J-1.45 +(CUTTER COMP CANCEL) +N11 G1 Z-.2 F50. +N12 Y-.990 +N13 G40 +N14 G0 X-.6 Y1.590 +N15 G0 Z.1 +N16 M5 G49 G28 G91 Z0 +N17 CALL O9456 +N18 #500=0.004 +N19 #503=[#500+#501] +N20 VC45=0.0006 +VS4=0.0007 +N21 G90 G10 L20 P3 X5.Y4. Z6.567 +N22 G0 X5000 +N23 IF [#1 LT 0.370] GOTO 49 +N24 X-0.678 Y+.990 +N25 G84.3 X-0.1 +N26 #4=#5*COS[45] +N27 #4=#5*SIN[45] +N28 VZOFZ=652.9658 +% \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/gherkin.feature b/node_modules/ace/demo/kitchen-sink/docs/gherkin.feature new file mode 100644 index 00000000..52cd811e --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/gherkin.feature @@ -0,0 +1,28 @@ +@these @are @tags +Feature: Serve coffee + Coffee should not be served until paid for + Coffee should not be served until the button has been pressed + If there is no coffee left then money should be refunded + + Scenario Outline: Eating + Given there are <start> cucumbers + When I eat <eat> cucumbers + Then I should have <left> cucumbers + + Examples: + | start | eat | left | + | 12 | 5 | 7 | + | 20 | 5 | 15 | + + Scenario: Buy last coffee + Given there are 1 coffees left in the machine + And I have deposited 1$ + When I press the coffee button + Then I should be served a "coffee" + + # this a comment + + """ + this is a + pystring + """ \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/glsl.glsl b/node_modules/ace/demo/kitchen-sink/docs/glsl.glsl new file mode 100644 index 00000000..e32bf07d --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/glsl.glsl @@ -0,0 +1,20 @@ +uniform float amplitude; +attribute float displacement; +varying vec3 vNormal; + +void main() { + + vNormal = normal; + + // multiply our displacement by the + // amplitude. The amp will get animated + // so we'll have animated displacement + vec3 newPosition = position + + normal * + vec3(displacement * + amplitude); + + gl_Position = projectionMatrix * + modelViewMatrix * + vec4(newPosition,1.0); +} \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/golang.go b/node_modules/ace/demo/kitchen-sink/docs/golang.go new file mode 100644 index 00000000..6b1298f0 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/golang.go @@ -0,0 +1,34 @@ +// Concurrent computation of pi. +// See http://goo.gl/ZuTZM. +// +// This demonstrates Go's ability to handle +// large numbers of concurrent processes. +// It is an unreasonable way to calculate pi. +package main + +import ( + "fmt" + "math" +) + +func main() { + fmt.Println(pi(5000)) +} + +// pi launches n goroutines to compute an +// approximation of pi. +func pi(n int) float64 { + ch := make(chan float64) + for k := 0; k <= n; k++ { + go term(ch, float64(k)) + } + f := 0.0 + for k := 0; k <= n; k++ { + f += <-ch + } + return f +} + +func term(ch chan float64, k float64) { + ch <- 4 * math.Pow(-1, k) / (2*k + 1) +} diff --git a/node_modules/ace/demo/kitchen-sink/docs/groovy.groovy b/node_modules/ace/demo/kitchen-sink/docs/groovy.groovy new file mode 100644 index 00000000..8097a702 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/groovy.groovy @@ -0,0 +1,41 @@ +//http://groovy.codehaus.org/Martin+Fowler%27s+closure+examples+in+Groovy + +class Employee { + def name, salary + boolean manager + String toString() { return name } +} + +def emps = [new Employee(name:'Guillaume', manager:true, salary:200), + new Employee(name:'Graeme', manager:true, salary:200), + new Employee(name:'Dierk', manager:false, salary:151), + new Employee(name:'Bernd', manager:false, salary:50)] + +def managers(emps) { + emps.findAll { e -> e.isManager() } +} + +assert emps[0..1] == managers(emps) // [Guillaume, Graeme] + +def highPaid(emps) { + threshold = 150 + emps.findAll { e -> e.salary > threshold } +} + +assert emps[0..2] == highPaid(emps) // [Guillaume, Graeme, Dierk] + +def paidMore(amount) { + { e -> e.salary > amount} +} +def highPaid = paidMore(150) + +assert highPaid(emps[0]) // true +assert emps[0..2] == emps.findAll(highPaid) + +def filename = 'test.txt' +new File(filename).withReader{ reader -> doSomethingWith(reader) } + +def readersText +def doSomethingWith(reader) { readersText = reader.text } + +assert new File(filename).text == readersText \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/haml.haml b/node_modules/ace/demo/kitchen-sink/docs/haml.haml new file mode 100644 index 00000000..d07ed4a2 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/haml.haml @@ -0,0 +1,36 @@ +!!!5 + +# <!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7" lang="en"> <![endif]--> +# <!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8" lang="en"> <![endif]--> +# <!--[if IE 8]> <html class="no-js lt-ie9" lang="en"> <![endif]--> +# <!--[if gt IE 8]><!--> <html class="no-js" lang="en"> <!--<![endif]--> + + +/adasdasdad +%div{:id => "#{@item.type}_#{@item.number}", :class => '#{@item.type} #{@item.urgency}', :phoney => `asdasdasd`} +/ file: app/views/movies/index.html.haml +\d +%ads:{:bleh => 33} +%p==ddd== + Date/Time: + - now = DateTime.now + %strong= now + = if now DateTime.parse("December 31, 2006") + = "Happy new " + "year!" +%sfd.dfdfg +#content + .title + %h1= @title + = link_to 'Home', home_url + + #contents +%div#content + %div.articles + %div.article.title Blah + %div.article.date 2006-11-05 + %div.article.entry + Neil Patrick Harris + +%div[@user, :greeting] + %bar[290]/ + ==Hello!== diff --git a/node_modules/ace/demo/kitchen-sink/docs/handlebars.hbs b/node_modules/ace/demo/kitchen-sink/docs/handlebars.hbs new file mode 100644 index 00000000..bb096a1a --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/handlebars.hbs @@ -0,0 +1,8 @@ +{{!-- Ace + :-}} --}} + +<div id="comments"> + {{#each comments}} + <h2><a href="/posts/{{../permalink}}#{{id}}">{{title}}</a></h2> + <div>{{{body}}}</div> + {{/each}} +</div> diff --git a/node_modules/ace/demo/kitchen-sink/docs/haskell.hs b/node_modules/ace/demo/kitchen-sink/docs/haskell.hs new file mode 100644 index 00000000..5c0defc2 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/haskell.hs @@ -0,0 +1,20 @@ +-- Type annotation (optional) +fib :: Int -> Integer + +-- With self-referencing data +fib n = fibs !! n + where fibs = 0 : scanl (+) 1 fibs + -- 0,1,1,2,3,5,... + +-- Same, coded directly +fib n = fibs !! n + where fibs = 0 : 1 : next fibs + next (a : t@(b:_)) = (a+b) : next t + +-- Similar idea, using zipWith +fib n = fibs !! n + where fibs = 0 : 1 : zipWith (+) fibs (tail fibs) + +-- Using a generator function +fib n = fibs (0,1) !! n + where fibs (a,b) = a : fibs (b,a+b) \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/htaccess b/node_modules/ace/demo/kitchen-sink/docs/htaccess new file mode 100644 index 00000000..a9f5a27c --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/htaccess @@ -0,0 +1,10 @@ +Redirect /linux http://www.linux.org +Redirect 301 /kernel http://www.linux.org + +# comment +RewriteEngine on + +RewriteCond %{HTTP_USER_AGENT} ^Mozilla.* +RewriteRule ^/$ /homepage.max.html [L] + +RewriteRule ^/$ /homepage.std.html [L] diff --git a/node_modules/ace/demo/kitchen-sink/docs/html.html b/node_modules/ace/demo/kitchen-sink/docs/html.html new file mode 100644 index 00000000..81398bef --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/html.html @@ -0,0 +1,17 @@ +<!DOCTYPE html> +<html> + <head> + + <style type="text/css"> + .text-layer { + font-family: Monaco, "Courier New", monospace; + font-size: 12px; + cursor: text; + } + </style> + + </head> + <body> + <h1 style="color:red">Juhu Kinners</h1> + </body> +</html> \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/html_ruby.erb b/node_modules/ace/demo/kitchen-sink/docs/html_ruby.erb new file mode 100644 index 00000000..f75835ca --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/html_ruby.erb @@ -0,0 +1,26 @@ +<h1>Listing Books</h1> + +<table> + <tr> + <th>Title</th> + <th>Summary</th> + <th></th> + <th></th> + <th></th> + </tr> + +<% @books.each do |book| %> + <tr> + <%# comment %> + <td><%= book.title %></td> + <td><%= book.content %></td> + <td><%= link_to 'Show', book %></td> + <td><%= link_to 'Edit', edit_book_path(book) %></td> + <td><%= link_to 'Remove', book, :confirm => 'Are you sure?', :method => :delete %></td> + </tr> +<% end %> +</table> + +<br /> + +<%= link_to 'New book', new_book_path %> \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/ini.ini b/node_modules/ace/demo/kitchen-sink/docs/ini.ini new file mode 100644 index 00000000..45f83c9a --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/ini.ini @@ -0,0 +1,4 @@ +[.ShellClassInfo] +IconResource=..\logo.png +[ViewState] +FolderType=Generic diff --git a/node_modules/ace/demo/kitchen-sink/docs/io.io b/node_modules/ace/demo/kitchen-sink/docs/io.io new file mode 100644 index 00000000..4b80b6c2 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/io.io @@ -0,0 +1,6 @@ +// computes factorial of a number +factorial := method(n, + if(n == 0, return 1) + res := 1 + Range 1 to(n) foreach(i, res = res * i) +) \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/jade.jade b/node_modules/ace/demo/kitchen-sink/docs/jade.jade new file mode 100644 index 00000000..d9fb7e30 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/jade.jade @@ -0,0 +1,45 @@ +!!!doctype +!!!5 +!!! + +include something + + include another_thing + + // let's talk about it + +// + here it is. a block comment! + and another row! +but not here. + + // + a far spaced + should be lack of block + + // also not a comment + div.attemptAtBlock + + span#myName + + #{implicit} + !{more_explicit} + + #idDiv + + .idDiv + + test(id="tag") + header(id="tag", blah="foo", meh="aads") +mixin article(obj, parents) + + mixin bleh() + + mixin clever-name + + -var x = "0"; + - y each z + + - var items = ["one", "two", "three"] + each item in items + li= item \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/java.java b/node_modules/ace/demo/kitchen-sink/docs/java.java new file mode 100644 index 00000000..f3b542b7 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/java.java @@ -0,0 +1,15 @@ +public class InfiniteLoop { + + /* + * This will cause the program to hang... + * + * Taken from: + * http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/ + */ + public static void main(String[] args) { + double d = Double.parseDouble("2.2250738585072012e-308"); + + // unreachable code + System.out.println("Value: " + d); + } +} \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/javascript.js b/node_modules/ace/demo/kitchen-sink/docs/javascript.js new file mode 100644 index 00000000..5b367b5f --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/javascript.js @@ -0,0 +1,5 @@ +function foo(items, nada) { + for (var i=0; i<items.length; i++) { + alert(items[i] + "juhu\n"); + } // Real Tab. +} \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/json.json b/node_modules/ace/demo/kitchen-sink/docs/json.json new file mode 100644 index 00000000..6028d5ed --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/json.json @@ -0,0 +1,66 @@ +{ + "query": { + "count": 10, + "created": "2011-06-21T08:10:46Z", + "lang": "en-US", + "results": { + "photo": [ + { + "farm": "6", + "id": "5855620975", + "isfamily": "0", + "isfriend": "0", + "ispublic": "1", + "owner": "32021554@N04", + "secret": "f1f5e8515d", + "server": "5110", + "title": "7087 bandit cat" + }, + { + "farm": "4", + "id": "5856170534", + "isfamily": "0", + "isfriend": "0", + "ispublic": "1", + "owner": "32021554@N04", + "secret": "ff1efb2a6f", + "server": "3217", + "title": "6975 rusty cat" + }, + { + "farm": "6", + "id": "5856172972", + "isfamily": "0", + "isfriend": "0", + "ispublic": "1", + "owner": "51249875@N03", + "secret": "6c6887347c", + "server": "5192", + "title": "watermarked-cats" + }, + { + "farm": "6", + "id": "5856168328", + "isfamily": "0", + "isfriend": "0", + "ispublic": "1", + "owner": "32021554@N04", + "secret": "0c1cfdf64c", + "server": "5078", + "title": "7020 mandy cat" + }, + { + "farm": "3", + "id": "5856171774", + "isfamily": "0", + "isfriend": "0", + "ispublic": "1", + "owner": "32021554@N04", + "secret": "7f5a3180ab", + "server": "2696", + "title": "7448 bobby cat" + } + ] + } + } +} \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/jsoniq.jq b/node_modules/ace/demo/kitchen-sink/docs/jsoniq.jq new file mode 100644 index 00000000..30404ce4 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/jsoniq.jq @@ -0,0 +1 @@ +TODO \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/jsp.jsp b/node_modules/ace/demo/kitchen-sink/docs/jsp.jsp new file mode 100644 index 00000000..43fbb835 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/jsp.jsp @@ -0,0 +1,46 @@ +<html> +<body> + <script> + var x = "abc"; + function y { + } + </script> + <style> + .class { + background: #124356; + } + </style> + + <p> + Today's date: <%= (new java.util.Date()).toLocaleString()%> + </p> + <%! int i = 0; %> + <jsp:declaration> + int j = 10; + </jsp:declaration> + + <%-- This is JSP comment --%> + <%@ directive attribute="value" %> + + <h2>Select Languages:</h2> + + <form ACTION="jspCheckBox.jsp"> + <input type="checkbox" name="id" value="Java"> Java<BR> + <input type="checkbox" name="id" value=".NET"> .NET<BR> + <input type="checkbox" name="id" value="PHP"> PHP<BR> + <input type="checkbox" name="id" value="C/C++"> C/C++<BR> + <input type="checkbox" name="id" value="PERL"> PERL <BR> + <input type="submit" value="Submit"> + </form> + + <% + String select[] = request.getParameterValues("id"); + if (select != null && select.length != 0) { + out.println("You have selected: "); + for (int i = 0; i < select.length; i++) { + out.println(select[i]); + } + } + %> +</body> +</html> \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/jsx.jsx b/node_modules/ace/demo/kitchen-sink/docs/jsx.jsx new file mode 100644 index 00000000..fbbeb662 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/jsx.jsx @@ -0,0 +1,9 @@ +/*EXPECTED +hello world! +*/ +class Test { + static function run() : void { + // console.log("hello world!"); + log "hello world!"; + } +} \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/julia.jl b/node_modules/ace/demo/kitchen-sink/docs/julia.jl new file mode 100644 index 00000000..f558ae22 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/julia.jl @@ -0,0 +1,15 @@ +for op = (:+, :*, :&, :|, :$) + @eval ($op)(a,b,c) = ($op)(($op)(a,b),c) +end + +v = α'; +function g(x,y) + return x * y + x + y +end + +cd("data") do + open("outfile", "w") do f + write(f, data) + end +end diff --git a/node_modules/ace/demo/kitchen-sink/docs/latex.tex b/node_modules/ace/demo/kitchen-sink/docs/latex.tex new file mode 100644 index 00000000..1427168a --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/latex.tex @@ -0,0 +1,22 @@ +\usepackage{amsmath} +\title{\LaTeX} +\date{} +\begin{document} + \maketitle + \LaTeX{} is a document preparation system for the \TeX{} + typesetting program. It offers programmable desktop publishing + features and extensive facilities for automating most aspects of + typesetting and desktop publishing, including numbering and + cross-referencing, tables and figures, page layout, bibliographies, + and much more. \LaTeX{} was originally written in 1984 by Leslie + Lamport and has become the dominant method for using \TeX; few + people write in plain \TeX{} anymore. The current version is + \LaTeXe. + + % This is a comment; it will not be shown in the final output. + % The following shows a little of the typesetting power of LaTeX: + \begin{align} + E &= mc^2 \\ + m &= \frac{m_0}{\sqrt{1-\frac{v^2}{c^2}}} + \end{align} +\end{document} \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/less.less b/node_modules/ace/demo/kitchen-sink/docs/less.less new file mode 100644 index 00000000..b3fdaadd --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/less.less @@ -0,0 +1,28 @@ +/* styles.less */ + +@base: #f938ab; + +.box-shadow(@style, @c) when (iscolor(@c)) { + box-shadow: @style @c; + -webkit-box-shadow: @style @c; + -moz-box-shadow: @style @c; +} +.box-shadow(@style, @alpha: 50%) when (isnumber(@alpha)) { + .box-shadow(@style, rgba(0, 0, 0, @alpha)); +} + +// Box styles +.box { + color: saturate(@base, 5%); + border-color: lighten(@base, 30%); + + div { .box-shadow(0 0 5px, 30%) } + + a { + color: @base; + + &:hover { + color: lighten(@base, 50%); + } + } +} diff --git a/node_modules/ace/demo/kitchen-sink/docs/liquid.liquid b/node_modules/ace/demo/kitchen-sink/docs/liquid.liquid new file mode 100644 index 00000000..29c0b016 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/liquid.liquid @@ -0,0 +1,76 @@ +The following examples can be found in full at http://liquidmarkup.org/ + +Liquid is an extraction from the e-commerce system Shopify. +Shopify powers many thousands of e-commerce stores which all call for unique designs. +For this we developed Liquid which allows our customers complete design freedom while +maintaining the integrity of our servers. + +Liquid has been in production use since June 2006 and is now used by many other +hosted web applications. + +It was developed for usage in Ruby on Rails web applications and integrates seamlessly +as a plugin but it also works excellently as a stand alone library. + +Here's what it looks like: + + <ul id="products"> + {% for product in products %} + <li> + <h2>{{ product.title }}</h2> + Only {{ product.price | format_as_money }} + + <p>{{ product.description | prettyprint | truncate: 200 }}</p> + + </li> + {% endfor %} + </ul> + + +Some more features include: + +<h2>Filters</h2> +<p> The word "tobi" in uppercase: {{ 'tobi' | upcase }} </p> +<p>The word "tobi" has {{ 'tobi' | size }} letters! </p> +<p>Change "Hello world" to "Hi world": {{ 'Hello world' | replace: 'Hello', 'Hi' }} </p> +<p>The date today is {{ 'now' | date: "%Y %b %d" }} </p> + + +<h2>If</h2> +<p> + {% if user.name == 'tobi' or user.name == 'marc' %} + hi marc or tobi + {% endif %} +</p> + + +<h2>Case</h2> +<p> + {% case template %} + {% when 'index' %} + Welcome + {% when 'product' %} + {{ product.vendor | link_to_vendor }} / {{ product.title }} + {% else %} + {{ page_title }} + {% endcase %} +</p> + + +<h2>For Loops</h2> +<p> + {% for item in array %} + {{ item }} + {% endfor %} +</p> + + +<h2>Tables</h2> +<p> + {% tablerow item in items cols: 3 %} + {% if tablerowloop.col_first %} + First column: {{ item.variable }} + {% else %} + Different column: {{ item.variable }} + {% endif %} + {% endtablerow %} +</p> diff --git a/node_modules/ace/demo/kitchen-sink/docs/lisp.lisp b/node_modules/ace/demo/kitchen-sink/docs/lisp.lisp new file mode 100644 index 00000000..e8d25558 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/lisp.lisp @@ -0,0 +1,22 @@ +(defun prompt-for-cd () + "Prompts + for CD" + (prompt-read "Title" 1.53 1 2/4 1.7 1.7e0 2.9E-4 +42 -7 #b001 #b001/100 #o777 #O777 #xabc55 #c(0 -5.6)) + (prompt-read "Artist" &rest) + (or (parse-integer (prompt-read "Rating") :junk-allowed t) 0) + (if x (format t "yes") (format t "no" nil) ;and here comment + ) 0xFFLL -23ull + ;; second line comment + '(+ 1 2) + (defvar *lines*) ; list of all lines + (position-if-not #'sys::whitespacep line :start beg)) + (quote (privet 1 2 3)) + '(hello world) + (* 5 7) + (1 2 34 5) + (:use "aaaa") + (let ((x 10) (y 20)) + (print (+ x y)) + ) LAmbDa + + "asdad\0eqweqe" \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/livescript.ls b/node_modules/ace/demo/kitchen-sink/docs/livescript.ls new file mode 100644 index 00000000..ce082b4c --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/livescript.ls @@ -0,0 +1,245 @@ +# Defines an editing mode for [Ace](http://ace.ajax.org). +# +# Open [test/ace.html](../test/ace.html) to test. + +require, exports, module <-! define \ace/mode/ls + +identifier = /(?![\d\s])[$\w\xAA-\uFFDC](?:(?!\s)[$\w\xAA-\uFFDC]|-[A-Za-z])*/$ + +exports.Mode = class LiveScriptMode extends require(\ace/mode/text)Mode + -> + @$tokenizer = + new (require \ace/tokenizer)Tokenizer LiveScriptMode.Rules + if require \ace/mode/matching_brace_outdent + @$outdent = new that.MatchingBraceOutdent + + indenter = // (? + : [({[=:] + | [-~]> + | \b (?: e(?:lse|xport) | d(?:o|efault) | t(?:ry|hen) | finally | + import (?:\s* all)? | const | var | + let | new | catch (?:\s* #identifier)? ) + ) \s* $ // + + getNextLineIndent: (state, line, tab) -> + indent = @$getIndent line + {tokens} = @$tokenizer.getLineTokens line, state + unless tokens.length and tokens[*-1]type is \comment + indent += tab if state is \start and indenter.test line + indent + + toggleCommentLines: (state, doc, startRow, endRow) -> + comment = /^(\s*)#/; range = new (require \ace/range)Range 0 0 0 0 + for i from startRow to endRow + if out = comment.test line = doc.getLine i + then line.=replace comment, \$1 + else line.=replace /^\s*/ \$&# + range.end.row = range.start.row = i + range.end.column = line.length + 1 + doc.replace range, line + 1 - out * 2 + + checkOutdent: (state, line, input) -> @$outdent?checkOutdent line, input + + autoOutdent: (state, doc, row) -> @$outdent?autoOutdent doc, row + +### Highlight Rules + +keywordend = /(?![$\w]|-[A-Za-z]|\s*:(?![:=]))/$ +stringfill = token: \string, regex: '.+' + +LiveScriptMode.Rules = + start: + * token: \keyword + regex: //(? + :t(?:h(?:is|row|en)|ry|ypeof!?) + |c(?:on(?:tinue|st)|a(?:se|tch)|lass) + |i(?:n(?:stanceof)?|mp(?:ort(?:\s+all)?|lements)|[fs]) + |d(?:e(?:fault|lete|bugger)|o) + |f(?:or(?:\s+own)?|inally|unction) + |s(?:uper|witch) + |e(?:lse|x(?:tends|port)|val) + |a(?:nd|rguments) + |n(?:ew|ot) + |un(?:less|til) + |w(?:hile|ith) + |o[fr]|return|break|let|var|loop + )//$ + keywordend + + * token: \constant.language + regex: '(?:true|false|yes|no|on|off|null|void|undefined)' + keywordend + + * token: \invalid.illegal + regex: '(? + :p(?:ackage|r(?:ivate|otected)|ublic) + |i(?:mplements|nterface) + |enum|static|yield + )' + keywordend + + * token: \language.support.class + regex: '(? + :R(?:e(?:gExp|ferenceError)|angeError) + |S(?:tring|yntaxError) + |E(?:rror|valError) + |Array|Boolean|Date|Function|Number|Object|TypeError|URIError + )' + keywordend + + * token: \language.support.function + regex: '(? + :is(?:NaN|Finite) + |parse(?:Int|Float) + |Math|JSON + |(?:en|de)codeURI(?:Component)? + )' + keywordend + + * token: \variable.language + regex: '(?:t(?:hat|il|o)|f(?:rom|allthrough)|it|by|e)' + keywordend + + * token: \identifier + regex: identifier + /\s*:(?![:=])/$ + + * token: \variable + regex: identifier + + * token: \keyword.operator + regex: /(?:\.{3}|\s+\?)/$ + + * token: \keyword.variable + regex: /(?:@+|::|\.\.)/$ + next : \key + + * token: \keyword.operator + regex: /\.\s*/$ + next : \key + + * token: \string + regex: /\\\S[^\s,;)}\]]*/$ + + * token: \string.doc + regex: \''' + next : \qdoc + + * token: \string.doc + regex: \""" + next : \qqdoc + + * token: \string + regex: \' + next : \qstring + + * token: \string + regex: \" + next : \qqstring + + * token: \string + regex: \` + next : \js + + * token: \string + regex: '<\\[' + next : \words + + * token: \string.regex + regex: \// + next : \heregex + + * token: \comment.doc + regex: '/\\*' + next : \comment + + * token: \comment + regex: '#.*' + + * token: \string.regex + regex: // + /(?: [^ [ / \n \\ ]* + (?: (?: \\. + | \[ [^\]\n\\]* (?:\\.[^\]\n\\]*)* \] + ) [^ [ / \n \\ ]* + )* + )/ [gimy$]{0,4} + //$ + next : \key + + * token: \constant.numeric + regex: '(?:0x[\\da-fA-F][\\da-fA-F_]* + |(?:[2-9]|[12]\\d|3[0-6])r[\\da-zA-Z][\\da-zA-Z_]* + |(?:\\d[\\d_]*(?:\\.\\d[\\d_]*)?|\\.\\d[\\d_]*) + (?:e[+-]?\\d[\\d_]*)?[\\w$]*)' + + * token: \lparen + regex: '[({[]' + + * token: \rparen + regex: '[)}\\]]' + next : \key + + * token: \keyword.operator + regex: \\\S+ + + * token: \text + regex: \\\s+ + + heregex: + * token: \string.regex + regex: '.*?//[gimy$?]{0,4}' + next : \start + * token: \string.regex + regex: '\\s*#{' + * token: \comment.regex + regex: '\\s+(?:#.*)?' + * token: \string.regex + regex: '\\S+' + + key: + * token: \keyword.operator + regex: '[.?@!]+' + * token: \identifier + regex: identifier + next : \start + * token: \text + regex: '.' + next : \start + + comment: + * token: \comment.doc + regex: '.*?\\*/' + next : \start + * token: \comment.doc + regex: '.+' + + qdoc: + token: \string + regex: ".*?'''" + next : \key + stringfill + + qqdoc: + token: \string + regex: '.*?"""' + next : \key + stringfill + + qstring: + token: \string + regex: /[^\\']*(?:\\.[^\\']*)*'/$ + next : \key + stringfill + + qqstring: + token: \string + regex: /[^\\"]*(?:\\.[^\\"]*)*"/$ + next : \key + stringfill + + js: + token: \string + regex: /[^\\`]*(?:\\.[^\\`]*)*`/$ + next : \key + stringfill + + words: + token: \string + regex: '.*?\\]>' + next : \key + stringfill diff --git a/node_modules/ace/demo/kitchen-sink/docs/logiql.logic b/node_modules/ace/demo/kitchen-sink/docs/logiql.logic new file mode 100644 index 00000000..910862d7 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/logiql.logic @@ -0,0 +1,16 @@ +// ancestors +parentof("douglas", "john"). +parentof("john", "bob"). +parentof("bob", "ebbon"). + +parentof("douglas", "jane"). +parentof("jane", "jan"). + +ancestorof(A, B) <- parentof(A, B). +ancestorof(A, C) <- ancestorof(A, B), parentof(B,C). + +grandparentof(A, B) <- parentof(A, C), parentof(C, B). + +cousins(A,B) <- grandparentof(C,A), grandparentof(C,B). + +parentof[`arg](A, B) -> int[32](A), !string(B). \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/lsl.lsl b/node_modules/ace/demo/kitchen-sink/docs/lsl.lsl new file mode 100644 index 00000000..baf06f08 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/lsl.lsl @@ -0,0 +1,75 @@ +/* + Testing syntax highlighting + of Ace Editor + for the Linden Scripting Language +*/ + +integer someIntNormal = 3672; +integer someIntHex = 0x00000000; +integer someIntMath = PI_BY_TWO; + +integer event = 5673; // invalid.illegal + +key someKeyTexture = TEXTURE_DEFAULT; +string someStringSpecial = EOF; + +some_user_defined_function_without_return_type(string inputAsString) +{ + llSay(PUBLIC_CHANNEL, inputAsString); +} + +string user_defined_function_returning_a_string(key inputAsKey) +{ + return (string)inputAsKey; +} + +default +{ + state_entry() + { + key someKey = NULL_KEY; + someKey = llGetOwner(); + + string someString = user_defined_function_returning_a_string(someKey); + + some_user_defined_function_without_return_type(someString); + } + + touch_start(integer num_detected) + { + list agentsInRegion = llGetAgentList(AGENT_LIST_REGION, []); + integer numOfAgents = llGetListLength(agentsInRegion); + + integer index; // defaults to 0 + for (; index <= numOfAgents - 1; index++) // for each agent in region + { + llRegionSayTo(llList2Key(agentsInRegion, index), PUBLIC_CHANNEL, "Hello, Avatar!"); + } + } + + touch_end(integer num_detected) + { + someIntNormal = 3672; + someIntHex = 0x00000000; + someIntMath = PI_BY_TWO; + + event = 5673; // invalid.illegal + + someKeyTexture = TEXTURE_DEFAULT; + someStringSpecial = EOF; + + llSetInventoryPermMask("some item", MASK_NEXT, PERM_ALL); // reserved.godmode + + llWhisper(PUBLIC_CHANNEL, "Leaving \"default\" now..."); + state other; + } +} + +state other +{ + state_entry() + { + llWhisper(PUBLIC_CHANNEL, "Entered \"state other\", returning to \"default\" again..."); + state default; + } +} diff --git a/node_modules/ace/demo/kitchen-sink/docs/lua.lua b/node_modules/ace/demo/kitchen-sink/docs/lua.lua new file mode 100644 index 00000000..6c927197 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/lua.lua @@ -0,0 +1,38 @@ +--[[-- +num_args takes in 5.1 byte code and extracts the number of arguments +from its function header. +--]]-- + +function int(t) + return t:byte(1)+t:byte(2)*0x100+t:byte(3)*0x10000+t:byte(4)*0x1000000 +end + +function num_args(func) + local dump = string.dump(func) + local offset, cursor = int(dump:sub(13)), offset + 26 + --Get the params and var flag (whether there's a ... in the param) + return dump:sub(cursor):byte(), dump:sub(cursor+1):byte() +end + +-- Usage: +num_args(function(a,b,c,d, ...) end) -- return 4, 7 + +-- Python styled string format operator +local gm = debug.getmetatable("") + +gm.__mod=function(self, other) + if type(other) ~= "table" then other = {other} end + for i,v in ipairs(other) do other[i] = tostring(v) end + return self:format(unpack(other)) +end + +print([===[ + blah blah %s, (%d %d) +]===]%{"blah", num_args(int)}) + +--[=[-- +table.maxn is deprecated, use # instead. +--]=]-- +print(table.maxn{1,2,[4]=4,[8]=8) -- outputs 8 instead of 2 + +print(5 --[[ blah ]]) \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/luapage.lp b/node_modules/ace/demo/kitchen-sink/docs/luapage.lp new file mode 100644 index 00000000..f70c992b --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/luapage.lp @@ -0,0 +1,71 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html> +<% --[[-- + index.lp from the Kepler Project's LuaDoc HTML doclet. + http://keplerproject.github.com/luadoc/ +--]] %> +<head> + <title>Reference + " type="text/css" /> + + + + +
+ +
+ +
+
+
+ +
+ + + +
+ + +<%if not options.nomodules and #doc.modules > 0 then%> +

Modules

+ + +<%for _, modulename in ipairs(doc.modules) do%> + + + + +<%end%> +
<%=modulename%><%=doc.modules[modulename].summary%>
+<%end%> + + + +<%if not options.nofiles and #doc.files > 0 then%> +

Files

+ + +<%for _, filepath in ipairs(doc.files) do%> + + + + +<%end%> +
<%=filepath%>
+<%end%> + +
+ +
+ +
+

Valid XHTML 1.0!

+
+ +
+ + diff --git a/node_modules/ace/demo/kitchen-sink/docs/lucene.lucene b/node_modules/ace/demo/kitchen-sink/docs/lucene.lucene new file mode 100644 index 00000000..7ac4b90b --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/lucene.lucene @@ -0,0 +1 @@ +(title:"foo bar" AND body:"quick fox") OR title:fox \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/markdown.md b/node_modules/ace/demo/kitchen-sink/docs/markdown.md new file mode 100644 index 00000000..63e96eab --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/markdown.md @@ -0,0 +1,186 @@ +Ace (Ajax.org Cloud9 Editor) +============================ + +Ace is a standalone code editor written in JavaScript. Our goal is to create a browser based editor that matches and extends the features, usability and performance of existing native editors such as TextMate, Vim or Eclipse. It can be easily embedded in any web page or JavaScript application. Ace is developed as the primary editor for [Cloud9 IDE](http://www.cloud9ide.com/) and the successor of the Mozilla Skywriter (Bespin) Project. + +Features +-------- + +* Syntax highlighting +* Automatic indent and outdent +* An optional command line +* Handles huge documents (100,000 lines and more are no problem) +* Fully customizable key bindings including VI and Emacs modes +* Themes (TextMate themes can be imported) +* Search and replace with regular expressions +* Highlight matching parentheses +* Toggle between soft tabs and real tabs +* Displays hidden characters +* Drag and drop text using the mouse +* Line wrapping +* Unstructured / user code folding +* Live syntax checker (currently JavaScript/CoffeeScript) + +Take Ace for a spin! +-------------------- + +Check out the Ace live [demo](http://ajaxorg.github.com/ace/) or get a [Cloud9 IDE account](http://run.cloud9ide.com) to experience Ace while editing one of your own GitHub projects. + +If you want, you can use Ace as a textarea replacement thanks to the [Ace Bookmarklet](http://ajaxorg.github.com/ace/build/textarea/editor.html). + +History +------- + +Previously known as “Bespin†and “Skywriter†it’s now known as Ace (Ajax.org Cloud9 Editor)! Bespin and Ace started as two independent projects, both aiming to build a no-compromise code editor component for the web. Bespin started as part of Mozilla Labs and was based on the canvas tag, while Ace is the Editor component of the Cloud9 IDE and is using the DOM for rendering. After the release of Ace at JSConf.eu 2010 in Berlin the Skywriter team decided to merge Ace with a simplified version of Skywriter's plugin system and some of Skywriter's extensibility points. All these changes have been merged back to Ace. Both Ajax.org and Mozilla are actively developing and maintaining Ace. + +Getting the code +---------------- + +Ace is a community project. We actively encourage and support contributions. The Ace source code is hosted on GitHub. It is released under the BSD License. This license is very simple, and is friendly to all kinds of projects, whether open source or not. Take charge of your editor and add your favorite language highlighting and keybindings! + +```bash + git clone git://github.com/ajaxorg/ace.git + cd ace + git submodule update --init --recursive +``` + +Embedding Ace +------------- + +Ace can be easily embedded into any existing web page. The Ace git repository ships with a pre-packaged version of Ace inside of the `build` directory. The same packaged files are also available as a separate [download](https://github.com/ajaxorg/ace/downloads). Simply copy the contents of the `src` subdirectory somewhere into your project and take a look at the included demos of how to use Ace. + +The easiest version is simply: + +```html +
some text
+ + +``` + +With "editor" being the id of the DOM element, which should be converted to an editor. Note that this element must be explicitly sized and positioned `absolute` or `relative` for Ace to work. e.g. + +```css + #editor { + position: absolute; + width: 500px; + height: 400px; + } +``` + +To change the theme simply include the Theme's JavaScript file + +```html + +``` + +and configure the editor to use the theme: + +```javascript + editor.setTheme("ace/theme/twilight"); +``` + +By default the editor only supports plain text mode; many other languages are available as separate modules. After including the mode's JavaScript file: + +```html + +``` + +Then the mode can be used like this: + +```javascript + var JavaScriptMode = require("ace/mode/javascript").Mode; + editor.getSession().setMode(new JavaScriptMode()); +``` + +Documentation +------------- + +You find a lot more sample code in the [demo app](https://github.com/ajaxorg/ace/blob/master/demo/demo.js). + +There is also some documentation on the [wiki page](https://github.com/ajaxorg/ace/wiki). + +If you still need help, feel free to drop a mail on the [ace mailing list](http://groups.google.com/group/ace-discuss). + +Running Ace +----------- + +After the checkout Ace works out of the box. No build step is required. Open 'editor.html' in any browser except Google Chrome. Google Chrome doesn't allow XMLHTTPRequests from files loaded from disc (i.e. with a file:/// URL). To open Ace in Chrome simply start the bundled mini HTTP server: + +```bash + ./static.py +``` + +Or using Node.JS + +```bash + ./static.js +``` + +The editor can then be opened at http://localhost:8888/index.html. + +Package Ace +----------- + +To package Ace we use the dryice build tool developed by the Mozilla Skywriter team. Before you can build you need to make sure that the submodules are up to date. + +```bash + git submodule update --init --recursive +``` + +Afterwards Ace can be built by calling + +```bash + ./Makefile.dryice.js normal +``` + +The packaged Ace will be put in the 'build' folder. + +To build the bookmarklet version execute + +```bash + ./Makefile.dryice.js bm +``` + +Running the Unit Tests +---------------------- + +The Ace unit tests run on node.js. Before the first run a couple of node modules have to be installed. The easiest way to do this is by using the node package manager (npm). In the Ace base directory simply call + +```bash + npm link . +``` + +To run the tests call: + +```bash + node lib/ace/test/all.js +``` + +You can also run the tests in your browser by serving: + + http://localhost:8888/lib/ace/test/tests.html + +This makes debugging failing tests way more easier. + +Contributing +------------ + +Ace wouldn't be what it is without contributions! Feel free to fork and improve/enhance Ace any way you want. If you feel that the editor or the Ace community will benefit from your changes, please open a pull request. To protect the interests of the Ace contributors and users we require contributors to sign a Contributors License Agreement (CLA) before we pull the changes into the main repository. Our CLA is the simplest of agreements, requiring that the contributions you make to an ajax.org project are only those you're allowed to make. This helps us significantly reduce future legal risk for everyone involved. It is easy, helps everyone, takes ten minutes, and only needs to be completed once. There are two versions of the agreement: + +1. [The Individual CLA](https://github.com/ajaxorg/ace/raw/master/doc/Contributor_License_Agreement-v2.pdf): use this version if you're working on an ajax.org in your spare time, or can clearly claim ownership of copyright in what you'll be submitting. +2. [The Corporate CLA](https://github.com/ajaxorg/ace/raw/master/doc/Corporate_Contributor_License_Agreement-v2.pdf): have your corporate lawyer review and submit this if your company is going to be contributing to ajax.org projects + +If you want to contribute to an ajax.org project please print the CLA and fill it out and sign it. Then either send it by snail mail or fax to us or send it back scanned (or as a photo) by email. + +Email: fabian.jakobs@web.de + +Fax: +31 (0) 206388953 + +Address: Ajax.org B.V. + Keizersgracht 241 + 1016 EA, Amsterdam + the Netherlands \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/mask.mask b/node_modules/ace/demo/kitchen-sink/docs/mask.mask new file mode 100644 index 00000000..85a9e6c2 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/mask.mask @@ -0,0 +1,52 @@ +/* Mask Syntax Demo */ + +div > ' Test ~[name]'; + +define :userProfile { + header { + h4 > @title; + button.close; + } +} + +:userProfile { + @title > ' Hello ~[: username.toUpperCase()]' +} + +style { + html, body { + background: url('name.png') 0 0 no-repeat; + } +} + +button { + event click (e) { + this.textContent = `name ${e.clientX} !`; + } +} + +md > """ + +- div +- span + +Hello + +[one](http://google.com) + +"""; + + +header .foo > 'Heading' + +button .baz x-signal='click: test' disabled > " + Hello, + world + \"Buddy\" +" + +var a = { + name: `name ${window.innerWidth}` +}; + +span .foo > "~[bind: a.name]" \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/matlab.matlab b/node_modules/ace/demo/kitchen-sink/docs/matlab.matlab new file mode 100644 index 00000000..b2ca44d5 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/matlab.matlab @@ -0,0 +1,17 @@ +%{ + %{ + Ace Matlab demo + %} +%} + +classdef hello + methods + function greet(this) + disp('Hello!') % say hi + end + end +end + +% transpose +a = [ 'x''y', "x\n\ + y", 1' ]' + 2' \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/mel.mel b/node_modules/ace/demo/kitchen-sink/docs/mel.mel new file mode 100644 index 00000000..63dc14d6 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/mel.mel @@ -0,0 +1,33 @@ +// animated duplicates, instances script +proc animatedDuplication (int $rangeStart, int $rangeEnd, int $numOfDuplicates, int $duplicateOrInstance) +{ + int $range_start = $rangeStart; + int $range_end = $rangeEnd; + int $num_of_duplicates = $numOfDuplicates; + int $step_size = ($range_end - $range_start) / $num_of_duplicates; + int $i = 0; + int $temp; + + currentTime $range_start; // set to range start + + string $selectedObjects[]; // to store selected objects + $selectedObjects = `ls -sl`; // store selected objects + select $selectedObjects; + + while ($i <= $num_of_duplicates) + { + $temp = $range_start + ($step_size * $i); + currentTime ($temp); + // seleced the objects to duplicate or instance + select $selectedObjects; + if($duplicateOrInstance == 0) + { + duplicate; + } + else + { + instance; + } + $i++; + } +} \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/mushcode.mc b/node_modules/ace/demo/kitchen-sink/docs/mushcode.mc new file mode 100644 index 00000000..6861f955 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/mushcode.mc @@ -0,0 +1,8 @@ +@create phone +&pickup phone=$pick up:@ifelse [u(is,u(mode),ICC)]={@pemit %#=You pick up the [fullname(me)].[set(me,PHONER:%#)][set(me,MODE:CIP)][set([u(INCOMING)],CONNECTED:[num(me)])][set(me,CONNECTED:[u(INCOMING)])]%r[showpicture(PICPICKUP)]%rUse '[color(green,black,psay )]' (or '[color(green,black,p )]') to talk into the phone.;@oemit %#=%N picks up the [fullname(me)].},{@pemit %#=You pick up the phone but no one is there. You hear a dialtone and then hang up. [play(u(DIALTONE))];@oemit %#=%N picks up the phone, but no one is on the other end.} +&ringfun phone=[ifelse(eq(comp([u(%0/ringtone)],off),0),[color(black,cyan,INCOMING CALL FROM %1)],[play([switch([u(%0/ringtone)],1,[u(%0/ringtone1)],2,[u(%0/ringtone2)],3,[u(%0/ringtone3)],4,[u(%0/ringtone4)],5,[u(%0/ringtone5)],6,[u(%0/ringtone6)],7,[u(%0/ringtone7)],8,[u(%0/ringtone8)],9,[u(%0/ringtone9)],custom,[u(%0/customtone)],vibrate,[u(%0/vibrate)])])] +&ringloop phone=@switch [u(ringstate)]=1,{@emit [setq(q,[u(connecting)])][set(%qq,rangs:0)][set(%qq,mode:WFC)][set(%qq,INCOMING:)];@ifelse [u(%qq/HASVMB)]={@tr me/ROUTEVMB=[u(connecting)];},{@pemit %#=[u(MSGCNC)];}},2,{@pemit %#=The call is connected.[setq(q,[u(CONNECTING)])][set(me,CONNECTED:%qq)][set(%qq,CONNECTED:[num(me)])][set(%qq,MODE:CIP)];@tr me/ciploop;@tr %qq/ciploop;},3,{@emit On [fullname(me)]'s earpiece you hear a ringing sound.[play(u(LINETONE))];@tr me/ringhere;@increment [u(connecting)]/RANGS;@wait 5={@tr me/ringloop};},4,{} +&ringstate phone=[setq(q,u(connecting))][setq(1,[gt(u(%qq/rangs),sub(u(%qq/rings),1))])][setq(2,[and(u(is,u(%qq/MODE),CIP),u(is,u(%qq/INCOMING),[num(me)]))][setq(3,[u(is,u(%qq/MODE),ICC)])][ifelse(%q1,1,ifelse(%q2,2,ifelse(%q3,3,4)))] +;comment +@@(comment) +say [time()] diff --git a/node_modules/ace/demo/kitchen-sink/docs/mysql.mysql b/node_modules/ace/demo/kitchen-sink/docs/mysql.mysql new file mode 100644 index 00000000..30404ce4 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/mysql.mysql @@ -0,0 +1 @@ +TODO \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/objectivec.m b/node_modules/ace/demo/kitchen-sink/docs/objectivec.m new file mode 100644 index 00000000..1728dfe5 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/objectivec.m @@ -0,0 +1,104 @@ +@protocol Printing: someParent +-(void) print; +@end + +@interface Fraction: NSObject { + int numerator; + int denominator; +} +@end + +@"blah\8" @"a\222sd\d" @"\faw\"\? \' \4 n\\" @"\56" +@"\xSF42" + +-(NSDecimalNumber*)addCount:(id)addObject{ + +return [count decimalNumberByAdding:addObject.count]; + +} + + NS_DURING NS_HANDLER NS_ENDHANDLER + +@try { + if (argc > 1) { + @throw [NSException exceptionWithName:@"Throwing a test exception" reason:@"Testing the @throw directive." userInfo:nil]; + } +} +@catch (id theException) { + NSLog(@"%@", theException); + result = 1 ; +} +@finally { + NSLog(@"This always happens."); + result += 2 ; +} + + @synchronized(lock) { + NSLog(@"Hello World"); + } + +struct { @defs( NSObject) } + +char *enc1 = @encode(int); + + IBOutlet|IBAction|BOOL|SEL|id|unichar|IMP|Class + + + @class @protocol + +@public + // instance variables +@package + // instance variables +@protected + // instance variables +@private + // instance variables + + YES NO Nil nil +NSApp() +NSRectToCGRect (Protocol ProtocolFromString:"NSTableViewDelegate")) + +[SPPoint pointFromCGPoint:self.position] + +NSRoundDownToMultipleOfPageSize + +#import + +int main( int argc, const char *argv[] ) { + printf( "hello world\n" ); + return 0; +} + +NSChangeSpelling + +@"0 != SUBQUERY(image, $x, 0 != SUBQUERY($x.bookmarkItems, $y, $y.@count == 0).@count).@count" + +@selector(lowercaseString) @selector(uppercaseString:) + +NSFetchRequest *localRequest = [[NSFetchRequest alloc] init]; +localRequest.entity = [NSEntityDescription entityForName:@"VNSource" inManagedObjectContext:context]; +localRequest.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"resolution" ascending:YES]]; +NSPredicate *predicate = [NSPredicate predicateWithFormat:@"0 != SUBQUERY(image, $x, 0 != SUBQUERY($x.bookmarkItems, $y, $y.@count == 0).@count).@count"]; +[NSPredicate predicateWithFormat:] +NSString *predicateString = [NSString stringWithFormat:@"SELF beginsWith[cd] %@", searchString]; +NSPredicate *pred = [NSPredicate predicateWithFormat:predicateString]; +NSArray *filteredKeys = [[myMutableDictionary allKeys] filteredArrayUsingPredicate:pred]; + +localRequest.predicate = [NSPredicate predicateWithFormat:@"whichChart = %@" argumentArray: listChartToDownload]; +localRequest.fetchBatchSize = 100; +arrayRequest = [context executeFetchRequest:localRequest error:&error1]; + +[localRequest release]; + +#ifndef Nil +#define Nil __DARWIN_NULL /* id of Nil class */ +#endif + +@implementation MyObject +- (unsigned int)areaOfWidth:(unsigned int)width + height:(unsigned int)height +{ + return width*height; +} +@end diff --git a/node_modules/ace/demo/kitchen-sink/docs/ocaml.ml b/node_modules/ace/demo/kitchen-sink/docs/ocaml.ml new file mode 100644 index 00000000..85e6eba7 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/ocaml.ml @@ -0,0 +1,18 @@ +(* + * Example of early return implementation taken from + * http://ocaml.janestreet.com/?q=node/91 + *) + +let with_return (type t) (f : _ -> t) = + let module M = + struct exception Return of t end + in + let return = { return = (fun x -> raise (M.Return x)); } in + try f return with M.Return x -> x + + +(* Function that uses the 'early return' functionality provided by `with_return` *) +let sum_until_first_negative list = + with_return (fun r -> + List.fold list ~init:0 ~f:(fun acc x -> + if x >= 0 then acc + x else r.return acc)) \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/pascal.pas b/node_modules/ace/demo/kitchen-sink/docs/pascal.pas new file mode 100644 index 00000000..7a4a7fc6 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/pascal.pas @@ -0,0 +1,48 @@ +(***************************************************************************** + * A simple bubble sort program. Reads integers, one per line, and prints * + * them out in sorted order. Blows up if there are more than 49. * + *****************************************************************************) +PROGRAM Sort(input, output); + CONST + (* Max array size. *) + MaxElts = 50; + TYPE + (* Type of the element array. *) + IntArrType = ARRAY [1..MaxElts] OF Integer; + + VAR + (* Indexes, exchange temp, array size. *) + i, j, tmp, size: integer; + + (* Array of ints *) + arr: IntArrType; + + (* Read in the integers. *) + PROCEDURE ReadArr(VAR size: Integer; VAR a: IntArrType); + BEGIN + size := 1; + WHILE NOT eof DO BEGIN + readln(a[size]); + IF NOT eof THEN + size := size + 1 + END + END; + + BEGIN + (* Read *) + ReadArr(size, arr); + + (* Sort using bubble sort. *) + FOR i := size - 1 DOWNTO 1 DO + FOR j := 1 TO i DO + IF arr[j] > arr[j + 1] THEN BEGIN + tmp := arr[j]; + arr[j] := arr[j + 1]; + arr[j + 1] := tmp; + END; + + (* Print. *) + FOR i := 1 TO size DO + writeln(arr[i]) + END. + \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/perl.pl b/node_modules/ace/demo/kitchen-sink/docs/perl.pl new file mode 100644 index 00000000..d6a332e2 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/perl.pl @@ -0,0 +1,37 @@ +#!/usr/bin/perl +=begin + perl example code for Ace +=cut + +use strict; +use warnings; +my $num_primes = 0; +my @primes; + +# Put 2 as the first prime so we won't have an empty array +$primes[$num_primes] = 2; +$num_primes++; + +MAIN_LOOP: +for my $number_to_check (3 .. 200) +{ + for my $p (0 .. ($num_primes-1)) + { + if ($number_to_check % $primes[$p] == 0) + { + next MAIN_LOOP; + } + } + + # If we reached this point it means $number_to_check is not + # divisable by any prime number that came before it. + $primes[$num_primes] = $number_to_check; + $num_primes++; +} + +for my $p (0 .. ($num_primes-1)) +{ + print $primes[$p], ", "; +} +print "\n"; + diff --git a/node_modules/ace/demo/kitchen-sink/docs/pgsql.pgsql b/node_modules/ace/demo/kitchen-sink/docs/pgsql.pgsql new file mode 100644 index 00000000..ef265cdc --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/pgsql.pgsql @@ -0,0 +1,118 @@ + +BEGIN; + +/** +* Samples from PostgreSQL src/tutorial/basics.source +*/ +CREATE TABLE weather ( + city varchar(80), + temp_lo int, -- low temperature + temp_hi int, -- high temperature + prcp real, -- precipitation + "date" date +); + +CREATE TABLE cities ( + name varchar(80), + location point +); + + +INSERT INTO weather + VALUES ('San Francisco', 46, 50, 0.25, '1994-11-27'); + +INSERT INTO cities + VALUES ('San Francisco', '(-194.0, 53.0)'); + +INSERT INTO weather (city, temp_lo, temp_hi, prcp, "date") + VALUES ('San Francisco', 43, 57, 0.0, '1994-11-29'); + +INSERT INTO weather (date, city, temp_hi, temp_lo) + VALUES ('1994-11-29', 'Hayward', 54, 37); + + +SELECT city, (temp_hi+temp_lo)/2 AS temp_avg, "date" FROM weather; + +SELECT city, temp_lo, temp_hi, prcp, "date", location + FROM weather, cities + WHERE city = name; + + + +/** +* Dollar quotes starting at the end of the line are colored as SQL unless +* a special language tag is used. Dollar quote syntax coloring is implemented +* for Perl, Python, JavaScript, and Json. +*/ +create or replace function blob_content_chunked( + in p_data bytea, + in p_chunk integer) +returns setof bytea as $$ +-- Still SQL comments +declare + v_size integer = octet_length(p_data); +begin + for i in 1..v_size by p_chunk loop + return next substring(p_data from i for p_chunk); + end loop; +end; +$$ language plpgsql stable; + + +-- pl/perl +CREATE FUNCTION perl_max (integer, integer) RETURNS integer AS $perl$ + # perl comment... + my ($x,$y) = @_; + if (! defined $x) { + if (! defined $y) { return undef; } + return $y; + } + if (! defined $y) { return $x; } + if ($x > $y) { return $x; } + return $y; +$perl$ LANGUAGE plperl; + +-- pl/python +CREATE FUNCTION usesavedplan() RETURNS trigger AS $python$ + # python comment... + if SD.has_key("plan"): + plan = SD["plan"] + else: + plan = plpy.prepare("SELECT 1") + SD["plan"] = plan +$python$ LANGUAGE plpythonu; + +-- pl/v8 (javascript) +CREATE FUNCTION plv8_test(keys text[], vals text[]) RETURNS text AS $javascript$ +var o = {}; +for(var i=0; i \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/plaintext.txt b/node_modules/ace/demo/kitchen-sink/docs/plaintext.txt new file mode 100644 index 00000000..37bb4cca --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/plaintext.txt @@ -0,0 +1,11 @@ +Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. + +Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. + +Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. + +Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. + +Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis. + +At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores duo eirmod eos erat, et nonumy sed tempor et et invidunt justo labore Stet clita ea et gubergren, kasd magna no rebum. sanctus sea sed takimata ut vero voluptua. est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/powershell.ps1 b/node_modules/ace/demo/kitchen-sink/docs/powershell.ps1 new file mode 100644 index 00000000..f3a70bc1 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/powershell.ps1 @@ -0,0 +1,24 @@ +# This is a simple comment +function Hello($name) { + Write-host "Hello $name" +} + +function add($left, $right=4) { + if ($right -ne 4) { + return $left + } elseif ($left -eq $null -and $right -eq 2) { + return 3 + } else { + return 2 + } +} + +$number = 1 + 2; +$number += 3 + +Write-Host Hello -name "World" + +$an_array = @(1, 2, 3) +$a_hash = @{"something" = "something else"} + +& notepad .\readme.md diff --git a/node_modules/ace/demo/kitchen-sink/docs/praat.praat b/node_modules/ace/demo/kitchen-sink/docs/praat.praat new file mode 100644 index 00000000..3700ae6f --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/praat.praat @@ -0,0 +1,148 @@ +form Highlighter test + sentence My_sentence This should all be a string + text My_text This should also all be a string + word My_word Only the first word is a string, the rest is invalid + boolean Binary 1 + boolean Text no + boolean Quoted "yes" + comment This should be a string + real left_Range -123.6 + positive right_Range_max 3.3 + integer Int 4 + natural Nat 4 +endform + +# External scripts +include /path/to/file +runScript: "/path/to/file" +execute /path/to/file + +stopwatch + +# old-style procedure call +call oldStyle "quoted" 2 unquoted string +assert oldStyle.local = 1 + +# New-style procedure call with parens +@newStyle("quoted", 2, "quoted string") +if praatVersion >= 5364 + # New-style procedure call with colon + @newStyle: "quoted", 2, "quoted string" +endif + +# if-block with built-in variables +if windows + # We are on Windows +elsif unix = 1 or !macintosh + exitScript: "We are on Linux" +else macintosh == 1 + exit We are on Mac +endif + +# inline if with inline comment +var = if macintosh = 1 then 0 else 1 fi ; This is an inline comment + +# for-loop with explicit from using local variable +# and paren-style function calls and variable interpolation +n = numberOfSelected("Sound") +for i from newStyle.local to n + sound'i' = selected("Sound", i) + sound[i] = sound'i' +endfor + +for i from 1 to n + # Different styles of object selection + select sound'i' + sound = selected() + sound$ = selected$("Sound") + select Sound 'sound$' + selectObject(sound[i]) + selectObject: sound + + # Pause commands + beginPause("Viewing " + sound$) + if i > 1 + button = endPause("Stop", "Previous", + ...if i = total_sounds then "Finish" else "Next" fi, + ...3, 1) + else + button = endPause("Stop", + ...if i = total_sounds then "Finish" else "Next" fi, + ...2, 1) + endif + editor_name$ = if total_textgrids then "TextGrid " else "Sound " fi + name$ + nocheck editor 'editor_name$' + nocheck Close + nocheck endeditor + + # New-style standalone command call + Rename: "SomeName" + + # Command call with assignment + duration = Get total duration + + # Multi-line command with modifier + pitch = noprogress To Pitch (ac): 0, 75, 15, "no", + ...0.03, 0.45, 0.01, 0.35, 0.14, 600 + + # do-style command with assignment + minimum = do("Get minimum...", 0, 0, "Hertz", "Parabolic") + + # New-style multi-line command call with broken strings + table = Create Table with column names: "table", 0, + ..."file subject speaker + ...f0 f1 f2 f3 " + + ..."duration response" + + removeObject: pitch, table + + # Picture window commands + selectObject: sound + # do-style command + do("Select inner viewport...", 1, 6, 0.5, 1.5) + Black + Draw... 0 0 0 0 "no" Curve + Draw inner box + Text bottom: "yes", sound$ + Erase all + + # Demo window commands + demo Erase all + demo Select inner viewport... 0 100 0 100 + demo Axes... 0 100 0 100 + demo Paint rectangle... white 0 100 0 100 + demo Text... 50 centre 50 half Click to finish + demoWaitForInput ( ) + demo Erase all + demo Text: 50, "centre", 50, "half", "Finished" +endfor + +# An old-style sendpraat block +sendpraat Praat + ...'newline$' Create Sound as pure tone... "tone" 1 0 0.4 44100 440 0.2 0.01 0.01 + ...'newline$' Play + ...'newline$' Remove + +# A new-style sendpraat block +beginSendPraat: "Praat" + Create Sound as pure tone: "tone", 1, 0, 0.4, 44100, 440, 0.2, 0.01, 0.01 + duration = Get total duration + Remove +endSendPraat: "duration" +appendInfoLine: "The generated sound lasted for ", duration, "seconds" + +time = stopwatch +clearinfo +echo This script took +print 'time' seconds to +printline execute. + +# Old-style procedure declaration +procedure oldStyle .str1$ .num .str2$ + .local = 1 +endproc + +# New-style procedure declaration +procedure newStyle (.str1$, .num, .str2$) + .local = 1 +endproc diff --git a/node_modules/ace/demo/kitchen-sink/docs/prolog.plg b/node_modules/ace/demo/kitchen-sink/docs/prolog.plg new file mode 100644 index 00000000..2c867157 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/prolog.plg @@ -0,0 +1,18 @@ +partition([], _, [], []). +partition([X|Xs], Pivot, Smalls, Bigs) :- + ( X @< Pivot -> + Smalls = [X|Rest], + partition(Xs, Pivot, Rest, Bigs) + ; Bigs = [X|Rest], + partition(Xs, Pivot, Smalls, Rest) + ). + +quicksort([]) --> []. +quicksort([X|Xs]) --> + { partition(Xs, X, Smaller, Bigger) }, + quicksort(Smaller), [X], quicksort(Bigger). + +perfect(N) :- + between(1, inf, N), U is N // 2, + findall(D, (between(1,U,D), N mod D =:= 0), Ds), + sumlist(Ds, N). \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/properties.properties b/node_modules/ace/demo/kitchen-sink/docs/properties.properties new file mode 100644 index 00000000..446b340d --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/properties.properties @@ -0,0 +1,15 @@ +# You are reading the ".properties" entry. +! The exclamation mark can also mark text as comments. +# The key and element characters #, !, =, and : are written with a preceding backslash to ensure that they are properly loaded. +website = http\://en.wikipedia.org/ +language = English +# The backslash below tells the application to continue reading +# the value onto the next line. +message = Welcome to \ + Wikipedia! +# Add spaces to the key +key\ with\ spaces = This is the value that could be looked up with the key "key with spaces". +# Unicode +tab : \u0009 +empty-key= +last.line=value diff --git a/node_modules/ace/demo/kitchen-sink/docs/protobuf.proto b/node_modules/ace/demo/kitchen-sink/docs/protobuf.proto new file mode 100644 index 00000000..4da95a75 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/protobuf.proto @@ -0,0 +1,16 @@ +message Point { + required int32 x = 1; + required int32 y = 2; + optional string label = 3; +} + +message Line { + required Point start = 1; + required Point end = 2; + optional string label = 3; +} + +message Polyline { + repeated Point point = 1; + optional string label = 2; +} \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/python.py b/node_modules/ace/demo/kitchen-sink/docs/python.py new file mode 100644 index 00000000..90afdc30 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/python.py @@ -0,0 +1,19 @@ +#!/usr/local/bin/python + +import string, sys + +# If no arguments were given, print a helpful message +if len(sys.argv)==1: + print '''Usage: +celsius temp1 temp2 ...''' + sys.exit(0) + +# Loop over the arguments +for i in sys.argv[1:]: + try: + fahrenheit=float(string.atoi(i)) + except string.atoi_error: + print repr(i), "not a numeric value" + else: + celsius=(fahrenheit-32)*5.0/9.0 + print '%i\260F = %i\260C' % (int(fahrenheit), int(celsius+.5)) \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/r.r b/node_modules/ace/demo/kitchen-sink/docs/r.r new file mode 100644 index 00000000..e4d4c579 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/r.r @@ -0,0 +1,20 @@ +Call: +lm(formula = y ~ x) + +Residuals: +1 2 3 4 5 6 +3.3333 -0.6667 -2.6667 -2.6667 -0.6667 3.3333 + +Coefficients: + Estimate Std. Error t value Pr(>|t|) +(Intercept) -9.3333 2.8441 -3.282 0.030453 * +x 7.0000 0.7303 9.585 0.000662 *** +--- +Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1 + +Residual standard error: 3.055 on 4 degrees of freedom +Multiple R-squared: 0.9583, Adjusted R-squared: 0.9478 +F-statistic: 91.88 on 1 and 4 DF, p-value: 0.000662 + +> par(mfrow=c(2, 2)) # Request 2x2 plot layout +> plot(lm_1) # Diagnostic plot of regression model \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/rdoc.Rd b/node_modules/ace/demo/kitchen-sink/docs/rdoc.Rd new file mode 100644 index 00000000..16664795 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/rdoc.Rd @@ -0,0 +1,64 @@ +\name{picker} +\alias{picker} +\title{Create a picker control} +\description{ + Create a picker control to enable manipulation of plot variables based on a set of fixed choices. +} + +\usage{ +picker(..., initial = NULL, label = NULL) +} + + +\arguments{ + \item{\dots}{ + Arguments containing objects to be presented as choices for the picker (or a list containing the choices). If an element is named then the name is used to display it within the picker. If an element is not named then it is displayed within the picker using \code{\link{as.character}}. +} + \item{initial}{ + Initial value for picker. Value must be present in the list of choices specified. If not specified defaults to the first choice. +} + \item{label}{ + Display label for picker. Defaults to the variable name if not specified. +} +} + +\value{ + An object of class "manipulator.picker" which can be passed to the \code{\link{manipulate}} function. +} + +\seealso{ +\code{\link{manipulate}}, \code{\link{slider}}, \code{\link{checkbox}}, \code{\link{button}} +} + + +\examples{ +\dontrun{ + +## Filtering data with a picker +manipulate( + barplot(as.matrix(longley[,factor]), + beside = TRUE, main = factor), + factor = picker("GNP", "Unemployed", "Employed")) + +## Create a picker with labels +manipulate( + plot(pressure, type = type), + type = picker("points" = "p", "line" = "l", "step" = "s")) + +## Picker with groups +manipulate( + barplot(as.matrix(mtcars[group,"mpg"]), beside=TRUE), + group = picker("Group 1" = 1:11, + "Group 2" = 12:22, + "Group 3" = 23:32)) + +## Histogram w/ picker to select type +require(lattice) +require(stats) +manipulate( + histogram(~ height | voice.part, + data = singer, type = type), + type = picker("percent", "count", "density")) + +} +} \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/rhtml.Rhtml b/node_modules/ace/demo/kitchen-sink/docs/rhtml.Rhtml new file mode 100644 index 00000000..5eb6189d --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/rhtml.Rhtml @@ -0,0 +1,22 @@ + + + +Title + + + + +

This is an R HTML document. When you click the Knit HTML button a web page will be generated that includes both content as well as the output of any embedded R code chunks within the document. You can embed an R code chunk like this:

+ + + +

You can also embed plots, for example:

+ + + + + diff --git a/node_modules/ace/demo/kitchen-sink/docs/ruby.rb b/node_modules/ace/demo/kitchen-sink/docs/ruby.rb new file mode 100644 index 00000000..386fbb86 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/ruby.rb @@ -0,0 +1,35 @@ +#!/usr/bin/ruby + +# Program to find the factorial of a number +def fact(n) + if n == 0 + 1 + else + n * fact(n-1) + end +end + +puts fact(ARGV[0].to_i) + +class Range + def to_json(*a) + { + 'json_class' => self.class.name, # = 'Range' + 'data' => [ first, last, exclude_end? ] + }.to_json(*a) + end +end + +{:id => ?", :key => "value"} + + + herDocs = [<<'FOO', <(vector: &[T], function: &fn(v: &T) -> U) -> ~[U] { + let mut accumulator = ~[]; + for vec::each(vector) |element| { + accumulator.push(function(element)); + } + return accumulator; +} diff --git a/node_modules/ace/demo/kitchen-sink/docs/sass.sass b/node_modules/ace/demo/kitchen-sink/docs/sass.sass new file mode 100644 index 00000000..6caaaff8 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/sass.sass @@ -0,0 +1,39 @@ +// sass ace mode; + +@import url(http://fonts.googleapis.com/css?family=Ace:700) + +html, body + :background-color #ace + text-align: center + height: 100% + /*;*********; + ;comment ; + ;*********; + +.toggle + $size: 14px + + :background url(http://subtlepatterns.com/patterns/dark_stripes.png) + border-radius: 8px + height: $size + + &:before + $radius: $size * 0.845 + $glow: $size * 0.125 + + box-shadow: 0 0 $glow $glow / 2 #fff + border-radius: $radius + + &:active + ~ .button + box-shadow: 0 15px 25px -4px rgba(0,0,0,0.4) + ~ .label + font-size: 40px + color: rgba(0,0,0,0.45) + + &:checked + ~ .button + box-shadow: 0 15px 25px -4px #ace + ~ .label + font-size: 40px + color: #c9c9c9 diff --git a/node_modules/ace/demo/kitchen-sink/docs/scad.scad b/node_modules/ace/demo/kitchen-sink/docs/scad.scad new file mode 100644 index 00000000..a45c1aec --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/scad.scad @@ -0,0 +1,21 @@ +// ace can highlight scad! +module Element(xpos, ypos, zpos){ + translate([xpos,ypos,zpos]){ + union(){ + cube([10,10,4],true); + cylinder(10,15,5); + translate([0,0,10])sphere(5); + } + } +} + +union(){ + for(i=[0:30]){ + # Element(0,0,0); + Element(15*i,0,0); + } +} + +for (i = [3, 5, 7, 11]){ + rotate([i*10,0,0])scale([1,1,i])cube(10); +} \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/scala.scala b/node_modules/ace/demo/kitchen-sink/docs/scala.scala new file mode 100644 index 00000000..f8280677 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/scala.scala @@ -0,0 +1,69 @@ +// http://www.scala-lang.org/node/54 + +package examples.actors + +import scala.actors.Actor +import scala.actors.Actor._ + +abstract class PingMessage +case object Start extends PingMessage +case object SendPing extends PingMessage +case object Pong extends PingMessage + +abstract class PongMessage +case object Ping extends PongMessage +case object Stop extends PongMessage + +object pingpong extends Application { + val pong = new Pong + val ping = new Ping(100000, pong) + ping.start + pong.start + ping ! Start +} + +class Ping(count: Int, pong: Actor) extends Actor { + def act() { + println("Ping: Initializing with count "+count+": "+pong) + var pingsLeft = count + loop { + react { + case Start => + println("Ping: starting.") + pong ! Ping + pingsLeft = pingsLeft - 1 + case SendPing => + pong ! Ping + pingsLeft = pingsLeft - 1 + case Pong => + if (pingsLeft % 1000 == 0) + println("Ping: pong from: "+sender) + if (pingsLeft > 0) + self ! SendPing + else { + println("Ping: Stop.") + pong ! Stop + exit('stop) + } + } + } + } +} + +class Pong extends Actor { + def act() { + var pongCount = 0 + loop { + react { + case Ping => + if (pongCount % 1000 == 0) + println("Pong: ping "+pongCount+" from "+sender) + sender ! Pong + pongCount = pongCount + 1 + case Stop => + println("Pong: Stop.") + exit('stop) + } + } + } +} \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/scheme.scm b/node_modules/ace/demo/kitchen-sink/docs/scheme.scm new file mode 100644 index 00000000..8c78359c --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/scheme.scm @@ -0,0 +1,21 @@ +(define (prompt-for-cd) + "Prompts + for CD" + (prompt-read "Title" 1.53 1 2/4 1.7 1.7e0 2.9E-4 +42 -7 #b001 #b001/100 #o777 #O777 #xabc55 #c(0 -5.6)) + (prompt-read "Artist") + (or (parse-integer (prompt-read "Rating") #:junk-allowed #t) 0) + (if x (format #t "yes") (format #f "no") ;and here comment + ) + ;; second line comment + '(+ 1 2) + (position-if-not char-set:whitespace line #:start beg)) + (quote (privet 1 2 3)) + '(hello world) + (* 5 7) + (1 2 34 5) + (#:use "aaaa") + (let ((x 10) (y 20)) + (display (+ x y)) + ) + + "asdad\0eqweqe" diff --git a/node_modules/ace/demo/kitchen-sink/docs/scss.scss b/node_modules/ace/demo/kitchen-sink/docs/scss.scss new file mode 100644 index 00000000..e1558168 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/scss.scss @@ -0,0 +1,20 @@ +/* style.scss */ + +#navbar { + $navbar-width: 800px; + $items: 5; + $navbar-color: #ce4dd6; + + width: $navbar-width; + border-bottom: 2px solid $navbar-color; + + li { + float: left; + width: $navbar-width/$items - 10px; + + background-color: lighten($navbar-color, 20%); + &:hover { + background-color: lighten($navbar-color, 10%); + } + } +} \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/sh.sh b/node_modules/ace/demo/kitchen-sink/docs/sh.sh new file mode 100755 index 00000000..4c5e6968 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/sh.sh @@ -0,0 +1,40 @@ +#!/bin/sh + +# Script to open a browser to current branch +# Repo formats: +# ssh git@github.com:richo/gh_pr.git +# http https://richoH@github.com/richo/gh_pr.git +# git git://github.com/richo/gh_pr.git + +username=`git config --get github.user` + +get_repo() { + git remote -v | grep ${@:-$username} | while read remote; do + if repo=`echo $remote | grep -E -o "git@github.com:[^ ]*"`; then + echo $repo | sed -e "s/^git@github\.com://" -e "s/\.git$//" + exit 1 + fi + if repo=`echo $remote | grep -E -o "https?://([^@]*@)?github.com/[^ ]*\.git"`; then + echo $repo | sed -e "s|^https?://||" -e "s/^.*github\.com\///" -e "s/\.git$//" + exit 1 + fi + if repo=`echo $remote | grep -E -o "git://github.com/[^ ]*\.git"`; then + echo $repo | sed -e "s|^git://github.com/||" -e "s/\.git$//" + exit 1 + fi + done + + if [ $? -eq 0 ]; then + echo "Couldn't find a valid remote" >&2 + exit 1 + fi +} + +echo ${#x[@]} + +if repo=`get_repo $@`; then + branch=`git symbolic-ref HEAD 2>/dev/null` + echo "http://github.com/$repo/pull/new/${branch##refs/heads/}" +else + exit 1 +fi diff --git a/node_modules/ace/demo/kitchen-sink/docs/sjs.sjs b/node_modules/ace/demo/kitchen-sink/docs/sjs.sjs new file mode 100644 index 00000000..18ce0e49 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/sjs.sjs @@ -0,0 +1,28 @@ +var { each, map } = require('sjs:sequence'); +var { get } = require('sjs:http'); + +function foo(items, nada) { + var component = { name: "Ace", role: "Editor" }; + console.log(" + Welcome, #{component.name} + ".trim()); + + logging.debug(`Component added: $String(component) (${component})`); + + console.log(` + Welcome, {${function() { + return { x: 1, y: "why?}"}; + }()} + `.trim()); + + waitfor { + items .. each.par { |item| + get(item); + } + } and { + var lengths = items .. map(i -> i.length); + } or { + hold(1500); + throw new Error("timed out"); + } +} // Real Tab. diff --git a/node_modules/ace/demo/kitchen-sink/docs/smarty.smarty b/node_modules/ace/demo/kitchen-sink/docs/smarty.smarty new file mode 100644 index 00000000..77206724 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/smarty.smarty @@ -0,0 +1,7 @@ +{foreach $foo as $bar} + {$bar.zag} + {$bar.zag2} + {$bar.zag3} +{foreachelse} + There were no rows found. +{/foreach} \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/snippets.snippets b/node_modules/ace/demo/kitchen-sink/docs/snippets.snippets new file mode 100644 index 00000000..be99f51e --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/snippets.snippets @@ -0,0 +1,26 @@ +# Function +snippet fun + function ${1?:function_name}(${2:argument}) { + ${3:// body...} + } +# Anonymous Function +regex /((=)\s*|(:)\s*|(\()|\b)/f/(\))?/ +name f + function${M1?: ${1:functionName}}($2) { + ${0:$TM_SELECTED_TEXT} + }${M2?;}${M3?,}${M4?)} +# Immediate function +trigger \(?f\( +endTrigger \)? +snippet f( + (function(${1}) { + ${0:${TM_SELECTED_TEXT:/* code */}} + }(${1})); +# if +snippet if + if (${1:true}) { + ${0} + } + + + \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/soy_template.soy b/node_modules/ace/demo/kitchen-sink/docs/soy_template.soy new file mode 100644 index 00000000..3a9e3436 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/soy_template.soy @@ -0,0 +1,46 @@ +/** + * Greets a person using "Hello" by default. + * @param name The name of the person. + * @param? greetingWord Optional greeting word to use instead of "Hello". + */ +{template .helloName #eee} + {if not $greetingWord} + Hello {$name}! + {else} + {$greetingWord} {$name}! + {/if} +{/template} + +/** + * Greets a person and optionally a list of other people. + * @param name The name of the person. + * @param additionalNames The additional names to greet. May be an empty list. + */ +{template .helloNames} + // Greet the person. + {call .helloName data="all" /}
+ // Greet the additional people. + {foreach $additionalName in $additionalNames} + {call .helloName} + {param name: $additionalName /} + {/call} + {if not isLast($additionalName)} +
// break after every line except the last + {/if} + {ifempty} + No additional people to greet. + {/foreach} +{/template} + + +{/foreach} +{if length($items) > 5} +{msg desc="Says hello to the user."} + + +{namespace ns autoescape="contextual"} + +/** Example. */ +{template .example} + foo is {$ij.foo} +{/template} \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/space.space b/node_modules/ace/demo/kitchen-sink/docs/space.space new file mode 100644 index 00000000..7bd8ab19 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/space.space @@ -0,0 +1,56 @@ +query + count 10 + created 2011-06-21T08:10:46Z + lang en-US + results + photo + 0 + farm 6 + id 5855620975 + isfamily 0 + isfriend 0 + ispublic 1 + owner 32021554@N04 + secret f1f5e8515d + server 5110 + title 7087 bandit cat + 1 + farm 4 + id 5856170534 + isfamily 0 + isfriend 0 + ispublic 1 + owner 32021554@N04 + secret ff1efb2a6f + server 3217 + title 6975 rusty cat + 2 + farm 6 + id 5856172972 + isfamily 0 + isfriend 0 + ispublic 1 + owner 51249875@N03 + secret 6c6887347c + server 5192 + title watermarked-cats + 3 + farm 6 + id 5856168328 + isfamily 0 + isfriend 0 + ispublic 1 + owner 32021554@N04 + secret 0c1cfdf64c + server 5078 + title 7020 mandy cat + 4 + farm 3 + id 5856171774 + isfamily 0 + isfriend 0 + ispublic 1 + owner 32021554@N04 + secret 7f5a3180ab + server 2696 + title 7448 bobby cat diff --git a/node_modules/ace/demo/kitchen-sink/docs/sql.sql b/node_modules/ace/demo/kitchen-sink/docs/sql.sql new file mode 100644 index 00000000..d674f8a6 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/sql.sql @@ -0,0 +1,6 @@ +SELECT city, COUNT(id) AS users_count +FROM users +WHERE group_name = 'salesman' +AND created > '2011-05-21' +GROUP BY 1 +ORDER BY 2 DESC \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/stylus.styl b/node_modules/ace/demo/kitchen-sink/docs/stylus.styl new file mode 100644 index 00000000..614981a4 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/stylus.styl @@ -0,0 +1,55 @@ +// I'm a comment! + +/* + * Adds the given numbers together. + */ + + +/*! + * Adds the given numbers together. + */ + + +asdasdasdad(df, ad=23) + +add(a, b = a) + a + b +green(#0c0) + add(10, 5) + // => 15 + + add(10) + add(a, b) + + &asdasd + + (arguments) + + @sdfsdf +.signatures + background-color #e0e8e0 + border 1px solid grayLighter + box-shadow 0 0 3px grayLightest + border-radius 3px + padding 3px 5px + "adsads" + margin-left 0 + list-style none +.signature + list-style none + display: inline + margin-left 0 + > li + display inline +is not +.signature-values + list-style none + display inline + margin-left 0 + &:before + content '→' + margin 0 5px + > li + !important + + unless \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/svg.svg b/node_modules/ace/demo/kitchen-sink/docs/svg.svg new file mode 100644 index 00000000..4bb28e22 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/svg.svg @@ -0,0 +1,83 @@ + + + Test Tube Progress Bar + Created for the Web Directions SVG competition + + + + + + + Hickory, + + dickory, + + dock! + \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/tcl.tcl b/node_modules/ace/demo/kitchen-sink/docs/tcl.tcl new file mode 100644 index 00000000..5c53b971 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/tcl.tcl @@ -0,0 +1,40 @@ + +proc dijkstra {graph origin} { + # Initialize + dict for {vertex distmap} $graph { + dict set dist $vertex Inf + dict set path $vertex {} + } + dict set dist $origin 0 + dict set path $origin [list $origin] + + while {[dict size $graph]} { + # Find unhandled node with least weight + set d Inf + dict for {uu -} $graph { + if {$d > [set dd [dict get $dist $uu]]} { + set u $uu + set d $dd + } + } + + # No such node; graph must be disconnected + if {$d == Inf} break + + # Update the weights for nodes\ + lead to by the node we've picked + dict for {v dd} [dict get $graph $u] { + if {[dict exists $graph $v]} { + set alt [expr {$d + $dd}] + if {$alt < [dict get $dist $v]} { + dict set dist $v $alt + dict set path $v [list {*}[dict get $path $u] $v] + } + } + } + + # Remove chosen node from graph still to be handled + dict unset graph $u + } + return [list $dist $path] +} \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/tex.tex b/node_modules/ace/demo/kitchen-sink/docs/tex.tex new file mode 100644 index 00000000..9f1df621 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/tex.tex @@ -0,0 +1,20 @@ +The quadratic formula is $$-b \pm \sqrt{b^2 - 4ac} \over 2a$$ +\bye + +\makeatletter + \newcommand{\be}{% + \begingroup + % \setlength{\arraycolsep}{2pt} + \eqnarray% + \@ifstar{\nonumber}{}% + } + \newcommand{\ee}{\endeqnarray\endgroup} + \makeatother + + \begin{equation} + x=\left\{ \begin{array}{cl} + 0 & \textrm{if }A=\ldots\\ + 1 & \textrm{if }B=\ldots\\ + x & \textrm{this runs with as much text as you like, but without an raggeright text +.}\end{array}\right. + \end{equation} \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/textile.textile b/node_modules/ace/demo/kitchen-sink/docs/textile.textile new file mode 100644 index 00000000..8c67ec16 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/textile.textile @@ -0,0 +1,29 @@ +h1. Textile document + +h2. Heading Two + +h3. A two-line + header + +h2. Another two-line +header + +Paragraph: +one, two, +thee lines! + +p(classone two three). This is a paragraph with classes + +p(#id). (one with an id) + +p(one two three#my_id). ..classes + id + +* Unordered list +** sublist +* back again! +** sublist again.. + +# ordered + +bg. Blockquote! + This is a two-list blockquote..! \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/toml.toml b/node_modules/ace/demo/kitchen-sink/docs/toml.toml new file mode 100644 index 00000000..46e5b9d1 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/toml.toml @@ -0,0 +1,29 @@ +# This is a TOML document. Boom. + +title = "TOML Example" + +[owner] +name = "Tom Preston-Werner" +organization = "GitHub" +bio = "GitHub Cofounder & CEO\nLikes tater tots and beer." +dob = 1979-05-27T07:32:00Z # First class dates? Why not? + +[database] +server = "192.168.1.1" +ports = [ 8001, 8001, 8002 ] +connection_max = 5000 +enabled = true + +[servers] + + # You can indent as you please. Tabs or spaces. TOML don't care. + [servers.alpha] + ip = "10.0.0.1" + dc = "eqdc10" + + [servers.beta] + ip = "10.0.0.2" + dc = "eqdc10" + +[clients] +data = [ ["gamma", "delta"], [1, 2] ] # just an update to make sure parsers support it \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/twig.twig b/node_modules/ace/demo/kitchen-sink/docs/twig.twig new file mode 100644 index 00000000..02214f09 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/twig.twig @@ -0,0 +1,30 @@ + + + + My Webpage + + + + + {% if 1 not in [1, 2, 3] %} + + {# is equivalent to #} + {% if not (1 in [1, 2, 3]) %} + + {% autoescape true %} + {{ var }} + {{ var|raw }} {# var won't be escaped #} + {{ var|escape }} {# var won't be doubled-escaped #} + {% endautoescape %} + + {{ include('twig.html', sandboxed = true) }} + + {{"string #{with} \" escapes" 'another#one' }} +

My Webpage

+ {{ a_variable }} + + \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/typescript.ts b/node_modules/ace/demo/kitchen-sink/docs/typescript.ts new file mode 100644 index 00000000..2f880d03 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/typescript.ts @@ -0,0 +1,72 @@ +class Greeter { + greeting: string; + constructor (message: string) { + this.greeting = message; + } + greet() { + return "Hello, " + this.greeting; + } +} + +var greeter = new Greeter("world"); + +var button = document.createElement('button') +button.innerText = "Say Hello" +button.onclick = function() { + alert(greeter.greet()) +} + +document.body.appendChild(button) + +class Snake extends Animal { + move() { + alert("Slithering..."); + super(5); + } +} + +class Horse extends Animal { + move() { + alert("Galloping..."); + super.move(45); + } +} + +module Sayings { + export class Greeter { + greeting: string; + constructor (message: string) { + this.greeting = message; + } + greet() { + return "Hello, " + this.greeting; + } + } +} +module Mankala { + export class Features { + public turnContinues = false; + public seedStoredCount = 0; + public capturedCount = 0; + public spaceCaptured = NoSpace; + + public clear() { + this.turnContinues = false; + this.seedStoredCount = 0; + this.capturedCount = 0; + this.spaceCaptured = NoSpace; + } + + public toString() { + var stringBuilder = ""; + if (this.turnContinues) { + stringBuilder += " turn continues,"; + } + stringBuilder += " stores " + this.seedStoredCount; + if (this.capturedCount > 0) { + stringBuilder += " captures " + this.capturedCount + " from space " + this.spaceCaptured; + } + return stringBuilder; + } + } +} \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/vala.vala b/node_modules/ace/demo/kitchen-sink/docs/vala.vala new file mode 100644 index 00000000..f9600286 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/vala.vala @@ -0,0 +1,21 @@ +using Gtk; + +int main (string[] args) { + Gtk.init (ref args); + var foo = new MyFoo>(); + + var window = new Window(); + window.title = "Hello, World!"; + window.border_width = 10; + window.window_position = WindowPosition.CENTER; + window.set_default_size(350, 70); + window.destroy.connect(Gtk.main_quit); + + var label = new Label("Hello, World!"); + + window.add(label); + window.show_all(); + + Gtk.main(); + return 0; +} \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/vbscript.vbs b/node_modules/ace/demo/kitchen-sink/docs/vbscript.vbs new file mode 100644 index 00000000..ace5c9f9 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/vbscript.vbs @@ -0,0 +1,23 @@ +myfilename = "C:\Wikipedia - VBScript - Example - Hello World.txt" +MakeHelloWorldFile myfilename + +Sub MakeHelloWorldFile (FileName) +'Create a new file in C: drive or overwrite existing file + Set FSO = CreateObject("Scripting.FileSystemObject") + If FSO.FileExists(FileName) Then + Answer = MsgBox ("File " & FileName & " exists ... OK to overwrite?", vbOKCancel) + 'If button selected is not OK, then quit now + 'vbOK is a language constant + If Answer <> vbOK Then Exit Sub + Else + 'Confirm OK to create + Answer = MsgBox ("File " & FileName & " ... OK to create?", vbOKCancel) + If Answer <> vbOK Then Exit Sub + End If + 'Create new file (or replace an existing file) + Set FileObject = FSO.CreateTextFile (FileName) + FileObject.WriteLine "Time ... " & Now() + FileObject.WriteLine "Hello World" + FileObject.Close() + MsgBox "File " & FileName & " ... updated." +End Sub \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/velocity.vm b/node_modules/ace/demo/kitchen-sink/docs/velocity.vm new file mode 100644 index 00000000..9156020b --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/velocity.vm @@ -0,0 +1,44 @@ +#* + This is a sample comment block that + spans multiple lines. +*# + +#macro ( outputItem $item ) +
  • ${item}
  • +#end + +## Define the items to iterate +#set ( $items = [1, 2, 3, 4] ) + +
      + ## Iterate over the items and output the evens. + #foreach ( $item in $items ) + #if ( $_MathTool.mod($item, 2) == 0 ) + #outputItem ($item) + #end + #end +
    + + + + \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/verilog.v b/node_modules/ace/demo/kitchen-sink/docs/verilog.v new file mode 100644 index 00000000..b1f79265 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/verilog.v @@ -0,0 +1,12 @@ +always @(negedge reset or posedge clk) begin + if (reset == 0) begin + d_out <= 16'h0000; + d_out_mem[resetcount] <= d_out; + laststoredvalue <= d_out; + end else begin + d_out <= d_out + 1'b1; + end +end + +always @(bufreadaddr) + bufreadval = d_out_mem[bufreadaddr]; \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/vhdl.vhd b/node_modules/ace/demo/kitchen-sink/docs/vhdl.vhd new file mode 100644 index 00000000..662375e8 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/vhdl.vhd @@ -0,0 +1,34 @@ +library IEEE +user IEEE.std_logic_1164.all; +use IEEE.numeric_std.all; + +entity COUNT16 is + + port ( + cOut :out std_logic_vector(15 downto 0); -- counter output + clkEn :in std_logic; -- count enable + clk :in std_logic; -- clock input + rst :in std_logic -- reset input + ); + +end entity; + +architecture count_rtl of COUNT16 is + signal count :std_logic_vector (15 downto 0); + +begin + process (clk, rst) begin + + if(rst = '1') then + count <= (others=>'0'); + elsif(rising_edge(clk)) then + if(clkEn = '1') then + count <= count + 1; + end if; + end if; + + end process; + cOut <= count; + +end architecture; + \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/xml.xml b/node_modules/ace/demo/kitchen-sink/docs/xml.xml new file mode 100644 index 00000000..5b12c0a2 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/xml.xml @@ -0,0 +1,55 @@ + + + + true + + 26 + 25 + 21978 + + + + 24865670 + Continent + Africa + + + 24865675 + Continent + Europe + + + 24865673 + Continent + South America + + + 28289421 + Continent + Antarctic + + + 24865671 + Continent + Asia + + + 24865672 + Continent + North America + + + 55949070 + Continent + Australia + + + \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/docs/xquery.xq b/node_modules/ace/demo/kitchen-sink/docs/xquery.xq new file mode 100644 index 00000000..1b0ac753 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/xquery.xq @@ -0,0 +1,6 @@ +xquery version "1.0"; + +let $message := "Hello World!" +return + {$message} + diff --git a/node_modules/ace/demo/kitchen-sink/docs/yaml.yaml b/node_modules/ace/demo/kitchen-sink/docs/yaml.yaml new file mode 100644 index 00000000..52ee320e --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/docs/yaml.yaml @@ -0,0 +1,35 @@ +# This sample document was taken from wikipedia: +# http://en.wikipedia.org/wiki/YAML#Sample_document +--- +receipt: Oz-Ware Purchase Invoice +date: 2007-08-06 +customer: + given: Dorothy + family: Gale + +items: + - part_no: 'A4786' + descrip: Water Bucket (Filled) + price: 1.47 + quantity: 4 + + - part_no: 'E1628' + descrip: High Heeled "Ruby" Slippers + size: 8 + price: 100.27 + quantity: 1 + +bill-to: &id001 + street: | + 123 Tornado Alley + Suite 16 + city: East Centerville + state: KS + +ship-to: *id001 + +specialDelivery: > + Follow the Yellow Brick + Road to the Emerald City. + Pay no attention to the + man behind the curtain. diff --git a/node_modules/ace/demo/kitchen-sink/file_drop.js b/node_modules/ace/demo/kitchen-sink/file_drop.js new file mode 100644 index 00000000..8b89d5f1 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/file_drop.js @@ -0,0 +1,73 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + +var config = require("ace/config"); +var event = require("ace/lib/event"); +var modelist = require("ace/ext/modelist"); + +module.exports = function(editor) { + event.addListener(editor.container, "dragover", function(e) { + var types = e.dataTransfer.types; + if (types && Array.prototype.indexOf.call(types, 'Files') !== -1) + return event.preventDefault(e); + }); + + event.addListener(editor.container, "drop", function(e) { + var file; + try { + file = e.dataTransfer.files[0]; + if (window.FileReader) { + var reader = new FileReader(); + reader.onload = function() { + var mode = modelist.getModeForPath(file.name); + editor.session.doc.setValue(reader.result); + editor.session.setMode(mode.mode); + editor.session.modeName = mode.name; + }; + reader.readAsText(file); + } + return event.preventDefault(e); + } catch(err) { + return event.stopEvent(e); + } + }); +}; + +var Editor = require("ace/editor").Editor; +config.defineOptions(Editor.prototype, "editor", { + loadDroppedFile: { + set: function() { module.exports(this); }, + value: true + } +}); + +}); \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/icons/Readme.txt b/node_modules/ace/demo/kitchen-sink/icons/Readme.txt new file mode 100644 index 00000000..87a71c8d --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/icons/Readme.txt @@ -0,0 +1 @@ +The icons in this folder are from the Eclipse project and licensed under the Eclipse public license version 1.0 (EPL). \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/icons/epl.html b/node_modules/ace/demo/kitchen-sink/icons/epl.html new file mode 100644 index 00000000..f57b834b --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/icons/epl.html @@ -0,0 +1,260 @@ + + + + +Eclipse Public License - Version 1.0 + + + + + + +

    Eclipse Public License - v 1.0

    + +

    THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE +PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR +DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS +AGREEMENT.

    + +

    1. DEFINITIONS

    + +

    "Contribution" means:

    + +

    a) in the case of the initial Contributor, the initial +code and documentation distributed under this Agreement, and

    +

    b) in the case of each subsequent Contributor:

    +

    i) changes to the Program, and

    +

    ii) additions to the Program;

    +

    where such changes and/or additions to the Program +originate from and are distributed by that particular Contributor. A +Contribution 'originates' from a Contributor if it was added to the +Program by such Contributor itself or anyone acting on such +Contributor's behalf. Contributions do not include additions to the +Program which: (i) are separate modules of software distributed in +conjunction with the Program under their own license agreement, and (ii) +are not derivative works of the Program.

    + +

    "Contributor" means any person or entity that distributes +the Program.

    + +

    "Licensed Patents" mean patent claims licensable by a +Contributor which are necessarily infringed by the use or sale of its +Contribution alone or when combined with the Program.

    + +

    "Program" means the Contributions distributed in accordance +with this Agreement.

    + +

    "Recipient" means anyone who receives the Program under +this Agreement, including all Contributors.

    + +

    2. GRANT OF RIGHTS

    + +

    a) Subject to the terms of this Agreement, each +Contributor hereby grants Recipient a non-exclusive, worldwide, +royalty-free copyright license to reproduce, prepare derivative works +of, publicly display, publicly perform, distribute and sublicense the +Contribution of such Contributor, if any, and such derivative works, in +source code and object code form.

    + +

    b) Subject to the terms of this Agreement, each +Contributor hereby grants Recipient a non-exclusive, worldwide, +royalty-free patent license under Licensed Patents to make, use, sell, +offer to sell, import and otherwise transfer the Contribution of such +Contributor, if any, in source code and object code form. This patent +license shall apply to the combination of the Contribution and the +Program if, at the time the Contribution is added by the Contributor, +such addition of the Contribution causes such combination to be covered +by the Licensed Patents. The patent license shall not apply to any other +combinations which include the Contribution. No hardware per se is +licensed hereunder.

    + +

    c) Recipient understands that although each Contributor +grants the licenses to its Contributions set forth herein, no assurances +are provided by any Contributor that the Program does not infringe the +patent or other intellectual property rights of any other entity. Each +Contributor disclaims any liability to Recipient for claims brought by +any other entity based on infringement of intellectual property rights +or otherwise. As a condition to exercising the rights and licenses +granted hereunder, each Recipient hereby assumes sole responsibility to +secure any other intellectual property rights needed, if any. For +example, if a third party patent license is required to allow Recipient +to distribute the Program, it is Recipient's responsibility to acquire +that license before distributing the Program.

    + +

    d) Each Contributor represents that to its knowledge it +has sufficient copyright rights in its Contribution, if any, to grant +the copyright license set forth in this Agreement.

    + +

    3. REQUIREMENTS

    + +

    A Contributor may choose to distribute the Program in object code +form under its own license agreement, provided that:

    + +

    a) it complies with the terms and conditions of this +Agreement; and

    + +

    b) its license agreement:

    + +

    i) effectively disclaims on behalf of all Contributors +all warranties and conditions, express and implied, including warranties +or conditions of title and non-infringement, and implied warranties or +conditions of merchantability and fitness for a particular purpose;

    + +

    ii) effectively excludes on behalf of all Contributors +all liability for damages, including direct, indirect, special, +incidental and consequential damages, such as lost profits;

    + +

    iii) states that any provisions which differ from this +Agreement are offered by that Contributor alone and not by any other +party; and

    + +

    iv) states that source code for the Program is available +from such Contributor, and informs licensees how to obtain it in a +reasonable manner on or through a medium customarily used for software +exchange.

    + +

    When the Program is made available in source code form:

    + +

    a) it must be made available under this Agreement; and

    + +

    b) a copy of this Agreement must be included with each +copy of the Program.

    + +

    Contributors may not remove or alter any copyright notices contained +within the Program.

    + +

    Each Contributor must identify itself as the originator of its +Contribution, if any, in a manner that reasonably allows subsequent +Recipients to identify the originator of the Contribution.

    + +

    4. COMMERCIAL DISTRIBUTION

    + +

    Commercial distributors of software may accept certain +responsibilities with respect to end users, business partners and the +like. While this license is intended to facilitate the commercial use of +the Program, the Contributor who includes the Program in a commercial +product offering should do so in a manner which does not create +potential liability for other Contributors. Therefore, if a Contributor +includes the Program in a commercial product offering, such Contributor +("Commercial Contributor") hereby agrees to defend and +indemnify every other Contributor ("Indemnified Contributor") +against any losses, damages and costs (collectively "Losses") +arising from claims, lawsuits and other legal actions brought by a third +party against the Indemnified Contributor to the extent caused by the +acts or omissions of such Commercial Contributor in connection with its +distribution of the Program in a commercial product offering. The +obligations in this section do not apply to any claims or Losses +relating to any actual or alleged intellectual property infringement. In +order to qualify, an Indemnified Contributor must: a) promptly notify +the Commercial Contributor in writing of such claim, and b) allow the +Commercial Contributor to control, and cooperate with the Commercial +Contributor in, the defense and any related settlement negotiations. The +Indemnified Contributor may participate in any such claim at its own +expense.

    + +

    For example, a Contributor might include the Program in a commercial +product offering, Product X. That Contributor is then a Commercial +Contributor. If that Commercial Contributor then makes performance +claims, or offers warranties related to Product X, those performance +claims and warranties are such Commercial Contributor's responsibility +alone. Under this section, the Commercial Contributor would have to +defend claims against the other Contributors related to those +performance claims and warranties, and if a court requires any other +Contributor to pay any damages as a result, the Commercial Contributor +must pay those damages.

    + +

    5. NO WARRANTY

    + +

    EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS +PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS +OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, +ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY +OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely +responsible for determining the appropriateness of using and +distributing the Program and assumes all risks associated with its +exercise of rights under this Agreement , including but not limited to +the risks and costs of program errors, compliance with applicable laws, +damage to or loss of data, programs or equipment, and unavailability or +interruption of operations.

    + +

    6. DISCLAIMER OF LIABILITY

    + +

    EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT +NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING +WITHOUT LIMITATION LOST PROFITS), 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 OR +DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED +HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

    + +

    7. GENERAL

    + +

    If any provision of this Agreement is invalid or unenforceable under +applicable law, it shall not affect the validity or enforceability of +the remainder of the terms of this Agreement, and without further action +by the parties hereto, such provision shall be reformed to the minimum +extent necessary to make such provision valid and enforceable.

    + +

    If Recipient institutes patent litigation against any entity +(including a cross-claim or counterclaim in a lawsuit) alleging that the +Program itself (excluding combinations of the Program with other +software or hardware) infringes such Recipient's patent(s), then such +Recipient's rights granted under Section 2(b) shall terminate as of the +date such litigation is filed.

    + +

    All Recipient's rights under this Agreement shall terminate if it +fails to comply with any of the material terms or conditions of this +Agreement and does not cure such failure in a reasonable period of time +after becoming aware of such noncompliance. If all Recipient's rights +under this Agreement terminate, Recipient agrees to cease use and +distribution of the Program as soon as reasonably practicable. However, +Recipient's obligations under this Agreement and any licenses granted by +Recipient relating to the Program shall continue and survive.

    + +

    Everyone is permitted to copy and distribute copies of this +Agreement, but in order to avoid inconsistency the Agreement is +copyrighted and may only be modified in the following manner. The +Agreement Steward reserves the right to publish new versions (including +revisions) of this Agreement from time to time. No one other than the +Agreement Steward has the right to modify this Agreement. The Eclipse +Foundation is the initial Agreement Steward. The Eclipse Foundation may +assign the responsibility to serve as the Agreement Steward to a +suitable separate entity. Each new version of the Agreement will be +given a distinguishing version number. The Program (including +Contributions) may always be distributed subject to the version of the +Agreement under which it was received. In addition, after a new version +of the Agreement is published, Contributor may elect to distribute the +Program (including its Contributions) under the new version. Except as +expressly stated in Sections 2(a) and 2(b) above, Recipient receives no +rights or licenses to the intellectual property of any Contributor under +this Agreement, whether expressly, by implication, estoppel or +otherwise. All rights in the Program not expressly granted under this +Agreement are reserved.

    + +

    This Agreement is governed by the laws of the State of New York and +the intellectual property laws of the United States of America. No party +to this Agreement will bring a legal action under this Agreement more +than one year after the cause of action arose. Each party waives its +rights to a jury trial in any resulting litigation.

    + + + + + \ No newline at end of file diff --git a/node_modules/ace/demo/kitchen-sink/icons/error_obj.gif b/node_modules/ace/demo/kitchen-sink/icons/error_obj.gif new file mode 100644 index 0000000000000000000000000000000000000000..0bc60689c6dcbfb71770789a3c2e98f51f6eecd7 GIT binary patch literal 339 zcmZ?wbhEHb6krfwxXQrrHNWU4 z&?^&f5)>{J;LlXy?-r(U7vw8pD9sGYH>i^m7 z{}+n?Uupb*wdw!W=Kpu5|Gzi)|MMOH&*W4G3O9s`Hie5dhKhAYOSDHz^u$R`Ns&F; ztb4Lu|5%IOu~xma-9{(d4NrF&pY1liGsFJ=Y^MivoF6U?J>712zT5O-ui5SC4)jB<~Eh3Ck(|MR1tY+CYw%7@BZ0uHG65^MT;^$&kcave^ j77&vV;AWL^lhtKopEXNY&Ru%J!UdsAmM(L0WUvMR>~MP$ literal 0 HcmV?d00001 diff --git a/node_modules/ace/demo/kitchen-sink/inline_editor.js b/node_modules/ace/demo/kitchen-sink/inline_editor.js new file mode 100644 index 00000000..6b56887d --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/inline_editor.js @@ -0,0 +1,102 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + + +define(function(require, exports, module) { +"use strict"; + +var LineWidgets = require("ace/line_widgets").LineWidgets; +var Editor = require("ace/editor").Editor; +var Renderer = require("ace/virtual_renderer").VirtualRenderer; +var dom = require("ace/lib/dom"); + + +require("ace/commands/default_commands").commands.push({ + name: "openInlineEditor", + bindKey: "F3", + exec: function(editor) { + var split = window.env.split; + var s = editor.session; + var inlineEditor = new Editor(new Renderer()); + var splitSession = split.$cloneSession(s); + + var row = editor.getCursorPosition().row; + if (editor.session.lineWidgets && editor.session.lineWidgets[row]) { + editor.session.lineWidgets[row].destroy(); + return; + } + + var rowCount = 10; + var w = { + row: row, + // rowCount: rowCount, + fixedWidth: true, + el: dom.createElement("div"), + editor: inlineEditor + }; + var el = w.el; + el.appendChild(inlineEditor.container); + + if (!editor.session.widgetManager) { + editor.session.widgetManager = new LineWidgets(editor.session); + editor.session.widgetManager.attach(editor); + } + + var h = rowCount*editor.renderer.layerConfig.lineHeight; + inlineEditor.container.style.height = h + "px"; + + el.style.position = "absolute"; + el.style.zIndex = "4"; + el.style.borderTop = "solid blue 2px"; + el.style.borderBottom = "solid blue 2px"; + + inlineEditor.setSession(splitSession); + editor.session.widgetManager.addLineWidget(w); + + var kb = { + handleKeyboard:function(_,hashId, keyString) { + if (hashId === 0 && keyString === "esc") { + w.destroy(); + return true; + } + } + }; + + w.destroy = function() { + editor.keyBinding.removeKeyboardHandler(kb); + s.widgetManager.removeLineWidget(w); + }; + + editor.keyBinding.addKeyboardHandler(kb); + inlineEditor.keyBinding.addKeyboardHandler(kb); + inlineEditor.setTheme("ace/theme/solarized_light"); + } +}); +}); diff --git a/node_modules/ace/demo/kitchen-sink/layout.js b/node_modules/ace/demo/kitchen-sink/layout.js new file mode 100644 index 00000000..1332eef3 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/layout.js @@ -0,0 +1,132 @@ + +define(function(require, exports, module) { +"use strict"; + +var dom = require("ace/lib/dom"); +var event = require("ace/lib/event"); + +var EditSession = require("ace/edit_session").EditSession; +var UndoManager = require("ace/undomanager").UndoManager; +var Renderer = require("ace/virtual_renderer").VirtualRenderer; +var Editor = require("ace/editor").Editor; +var MultiSelect = require("ace/multi_select").MultiSelect; + +dom.importCssString("\ +splitter {\ + border: 1px solid #C6C6D2;\ + width: 0px;\ + cursor: ew-resize;\ + z-index:10}\ +splitter:hover {\ + margin-left: -2px;\ + width:3px;\ + border-color: #B5B4E0;\ +}\ +", "splitEditor"); + +exports.edit = function(el) { + if (typeof(el) == "string") + el = document.getElementById(el); + + var editor = new Editor(new Renderer(el, require("ace/theme/textmate"))); + + editor.resize(); + event.addListener(window, "resize", function() { + editor.resize(); + }); + return editor; +}; + + +var SplitRoot = function(el, theme, position, getSize) { + el.style.position = position || "relative"; + this.container = el; + this.getSize = getSize || this.getSize; + this.resize = this.$resize.bind(this); + + event.addListener(el.ownerDocument.defaultView, "resize", this.resize); + this.editor = this.createEditor(); +}; + +(function(){ + this.createEditor = function() { + var el = document.createElement("div"); + el.className = this.$editorCSS; + el.style.cssText = "position: absolute; top:0px; bottom:0px"; + this.$container.appendChild(el); + var session = new EditSession(""); + var editor = new Editor(new Renderer(el, this.$theme)); + + /*editor.on("focus", function() { + this._emit("focus", editor); + }.bind(this));*/ + + this.$editors.push(editor); + editor.setFontSize(this.$fontSize); + return editor; + }; + this.$resize = function() { + var size = this.getSize(this.container); + this.rect = { + x: size.left, + y: size.top, + w: size.width, + h: size.height + }; + this.item.resize(this.rect); + }; + this.getSize = function(el) { + return el.getBoundingClientRect(); + }; + this.destroy = function() { + var win = this.container.ownerDocument.defaultView; + event.removeListener(win, "resize", this.resize); + }; + + +}).call(SplitRoot.prototype); + + + +var Split = function(){ + +}; +(function(){ + this.execute = function(options) { + this.$u.execute(options); + }; + +}).call(Split.prototype); + + + +exports.singleLineEditor = function(el) { + var renderer = new Renderer(el); + el.style.overflow = "hidden"; + + renderer.screenToTextCoordinates = function(x, y) { + var pos = this.pixelToScreenCoordinates(x, y); + return this.session.screenToDocumentPosition( + Math.min(this.session.getScreenLength() - 1, Math.max(pos.row, 0)), + Math.max(pos.column, 0) + ); + }; + + renderer.$maxLines = 4; + + renderer.setStyle("ace_one-line"); + var editor = new Editor(renderer); + editor.session.setUndoManager(new UndoManager()); + + editor.setShowPrintMargin(false); + editor.renderer.setShowGutter(false); + editor.renderer.setHighlightGutterLine(false); + editor.$mouseHandler.$focusWaitTimout = 0; + + return editor; +}; + + + +}); + diff --git a/node_modules/ace/demo/kitchen-sink/logo.png b/node_modules/ace/demo/kitchen-sink/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..a722472f14258f4d6e6942879e8fc03017222161 GIT binary patch literal 49263 zcmd?QRa9JC6F=BUf+WEMK^qzk4#7RpxVr@iL4&(nf;0qzyK8U=PNTuyEkOe`ZlTde zr*rT9{_`*|^Ehh_FPwGOK3%oTcGYiJMX0IBzQ88K1^@sr(bCP+)Wrhu*4*)f1+~1rsg;F>g{ir>^N@uI0Pq7}9{g6zYw<7( zBZy8r>oKreNLh6?>(>gYrR#e%Q|E|yVs!}=X@QWJ^j}=|SJqcbUtP2KWLotGp>XDX z#?B`|M@J{p3o+{M?%w`!d^q0!YY5u9)>+nC)>78eU5@jHvIAIhbez6lw*Tcsv-8R~ z#(5kI$=lz*el)C%f1dyV6qJ9TBqaX#1{L++r=Xz!y+KF+@9FhG8jdM$!`1{3QXsk>vtBlwR@Vb6}I-lqjK zkpLEwOpJ*-J&FJOBj;30kx)94_3tVyWcP!RSP7Z`e$RrQ((d!4*ea;opLHU}EnH5X zPZE_BY2ttNsa4_joq!ns*lg8!2F_X(vcp6Yi~lb*iJ@>=K6tDnei{?jy4dy(FWVI! zE&~%CR7RGX7Wvyq!w;%WiasSsl*Gau(WF^X7E4v7!T%b49T6n~{*U-3J5|85M+8+$ zWh#+^7@VFaU`q-t0?wxm08xg2K`#0$F9jW;eoZCp*HnnaSUc%Z;lWQSZm{?_pG%Mo zqJCCJuG(avLd4@FL%hvd~*mx~L{SvWl4apk$!_|L;J0l6-Y-!eBBF#v!n5`{F1 zURvO^IwsAKj)F^C@{XxN_ExiG;AQLhHkQ+yr+|Ol8uN=R`&6`Dky%?P-OyFXRr}CL zw5W%ItEQ%_vc0{gM0{CyoLs@pjs)i`J13@hG5uyW59m8mW@cu=JyKGl_xJZJt-?Y= zIRX2n_iKo8&!=!|5aR9~rr@XW|8~_cE%H}9@q{f$mrEHbIRQ5t@(GL+5n#|8$vibf zYCHiY;;2#$YEJzJ$;vi$8<>32XFI2H$d<6WDv0VN=|uk4tmY?`zSbf{R;JP2)7?H0 zk)+!guvF;jQLPei&~)6_ zR2Ya64`~U1^+QdiFE7I<85db-J{UGy%FD|;5cau?Hn{8eI|O7NvB>_*e#~z8m%dVI z%H)7K*Dun@zIj~S7wxrH6WM{r-gDaJCI;<36@YwoOs>D;`Ild&R4=dgiTx9+99I<> zqxi!q>6qp>*6J_d=oAaHns7VLrW!lHj33-dy--)^yWQwMgqjG|nurkJrHiiaLS56E z$I>SMnxAV9uJ_=@$zNWBf{?za9xmHa7~GE7&R|r@;o9`Cb;<-i8vr3>wId#1eRF_J zFL{d0Xox5t!~NMAo(7egCy^?1UJ}ZP#nc z;>RNv6NJKj1Mq&=mywq*8yF2%i4BygE3r$=x4tGOj7)U8ioif>EdA4`PXj>TyHj7W z<`2>k)ziVI#J~Q4hlk|Q3&u+IYdB17EX#9M@W`L!os+b(`vtV?{U0WTY{;^1rn25# z>4y}86k#LDAs{IQ#od8zb^GP*n`Dl)Ll8x1a(o3CodEUUt$vJvq*%i=MN${)6%v|L z{C=aQEX>Y#s3u1j!Ak%kX3HTV1DmJzQc_Z?Z4WmGogzoGn*7*L3J$1<(CJ$-**5|0U^=NbD3K}x~GBPp`HLe5ECu|1wyMmECMBLmUW`akv0T3PMbpNO1|t_f*P z411dQ$_oknPYe-+xWb4(nk&qVr$1}V20|+O*!K-XZ{W++1T;0%_R;W zQi7>UC**s36L6EJ8hCRn{)m{sIAa2ZhyCkbYN+tIYU0Xw1MY5ae$C#)iI30GQO~$Z z!fbS2GJ_!I_|SWk>el1it5x5V?_d4?u)=y{!l}vrGc1(89z`*iN(YPEfZNNXoyLX+ ze_p)j;}9>c=I|1}540d(AzaE9i}iKLV?}GLa9lyq|M?VuP_`qVs(a&f(Y8A4yY=Zt z1~N=w;o(w)KnffOl$4bG6WP26s_fJ23>1jNNxc8rG75}#sRXilD@*0?HZD9aut~ly z2Qz|OVQrw?eUW1&_O(CzrfebrAEedA{vy|rPlHsKggUh;ApkJ^P7F*ic=UAW`T;(| zQGI-LaC<3em2>}@6=-Ft&EZ}B7gK4di7ulV$A^hM@0;^TC(Sw&#}bt6vGTx?=M?lO#a!G<;d9p-b7t8>4t zsI8G4u3<=x!V7>P#iqwxEsnU~dbjum?(@6zFmi_y#-073(YKjdWgob@&ITsDk)8xK z!Z?jZ1E^WT*U$GaS7%$2SgFPN_{t;EUDcQl3FeY4eLWkS0)37%1#uI+cnYbtYw@s9 z07R%@2>_sv9XKk(=c3Fx@hX|kkob7-=)ONrmI@KBEf)J82is%Wb|B^SM^fRuex2nC zFQ>ru$m4D2V}{a)DZFaTh=h7!|M>|;uoM8`-Fdmb{uGcqxYe`g%09NA-rxSG`%oUhqgF9ttINaN26e4wuzTx7zq`~Y6hJHq9x@Iqm3R@U zi7ltk%?-Fy37sQ0W5gev%l$Y9F;Y`qyUAXp3At{Mnp|F7-0v=*jhE*if~W?c{ig^C z1XXtr$4OhAySdwWO@DtsIV>q6wHIxRm2-;V1MzzuBh9nCzYa7Zc6L}N8~eDg=dkna zuPz=I1i@M;0D2J6m|!DS&w;YZ|Mv3Cax@bm<;}}LY877ll8KMI%-mVbtEBF%T(elE zJ&U{C%wndzW!Lw>C+`mcFi7@~Jeh&ULv=?1H+qo!rJoh}}j`!EW zaxVuAP-<4U?3b-Q4er`h3JZ22V#2SOiuDrdaJ|@{1Bz|I5=a+{c>6#!G`E;S!f8!|x=Sh;VWqiZ}uhL*i?J zkI#|$Uy5AY37#A#fckNP1FVb!Af%=afc5CwiYYu&0b34h#h-lc>g!L-w?iLJifW4m ze^^uG=xp04BvgGTb?Hs>>pb7#FL5Iv5$ivPwFF{B*2T+VYq(%ba=~9I{#&6{2(xak z2DmpdQ|!C{QezCe-uK_?Z&Ch}4PX!gMCi489DR&TVTBqRyJd;dD!zOPV3wCO@4q}* zd+eJ}PR@~({5KPT_2l?9V-L<(8cyVh`d(7Py9;i>n7#lxIk=gp=T%b%gX%+iZjd=G z&ELEMc`m65!fR}=j&YkB>z6?sBIpRf4;{&prlu>|1Tu2Rkbm_97?j0<*El{t1ll?{ zbjSw)gZu!$*=f+w&^pVi%Wo5NgCvmjpP-HXK?Nvih#{l+O+72nBow*I%Q&9vS=qO5 z+ru3X4>^21JaV6R(pI3aU5q1*f&cQ%lhn{SpaFzD16FBORfm_S z>_9a!s~+BGBp(ciiy?zdfLs7-H+mthA>ulU6_^9@15ii1l=JHhl97?!jF?td>Rw)6 zGQeVngZA|RLC$FScz_?^VGKlE3>pUR0|^W*$ZmX2iw-Pom_N0Pp!B`GtLW%32D!%U zsqEyeprN&%Wr_5o0RSMRg|!Vsvh=*#u`kYQ9M?Kx_*K(f>J0Qg`vGE~%p1>OJbfCV zYodE4uOQ7D6&Gt~H~>GSMOR0P_3yWmBaj)MZunG(?Se(E-yJTJ@Vg14vr>Ic&9knm zT`a!JN@iN$rn$6s2n8339%!PI3}*f@Bw5rAAZf_Qe^dgR$0 zc$Unz3dZuYO+gkdqP!x8JdAPI=&f@an0ocih)lTmZI@F}dpK z?@U2ghd`u((>|f=-D@NEW2!=S1 z1H1wz)&}X2$@Okhc0v!T>Z+hO`#7~Hgmfv%HIw51rf`Ghe&%dci<4_>j|tZ97ez>t z3@VZzYJRrhzVka32KxQ!T0f1&L%R51Y7q+5a@<^MOH)DDBZhi;u-;%>zRUiSbk$J2zbbhs}rJ{{ry z=oL|x%kfKKP`()rdqKXce5|hAgn{FL%lNPD4=RWa7R0U#u^P4ToFmJ{lPmZJ*);r9 zEf#>#^Ee}8CyPJuA?DfR^ijLxk%IgnUdnYHIt$7^}Yp=!S_mFz~$Hw>(-wETMVeTWzkY;P!r@SPmyQ)Z#ft_p*DBI@Pn zs&7YY$(6HBQ&q@^dSN|8FW0FgyWfoD>^Z;I|A>k4QO7LNQnj?`NgcyfMY0bC3nBG) zk^7F52V`Dw9?8++1&Q?Yl9o_=`3z}D7+3vD)^a-i=@X70T-!fz^~1Oa9pZT2qWCYkj*!UO9GZS)RAPq%tmf z)Lubn9d(n1rl6ppn##Kuf5&d6#XagTwZBDZRGpt*Uylk{$s0({XD49Wh0MEEC}Y}U zDxQUak8XWF9wi6YJE(F{zM`5bAS?axWCRa;JUo+}<4rOuW!XEfK)7iM)GS@N385jw z6GHyzKtv!VsPoX-AfzPQ$T!Iq`Hi7~_PrlnVQcGct8xP4BQ9bD8N@qKoJipZ&j%fypY!4K41yQ$m$HY+YpzB@cIhl`SZ~IdZ0S0)b_QK!(PYIY<;f5Gy zl4D2AJ&pED?Ag4&mq!LQr115z<9q+}yT$hN#Rp?DMWr~ zb$-P!Y;CnBCsf_j3{8{fV{Mgk6iVSz+>5q2v=~ndddEp~@01v$R6UrAp(@Z6-&Y|> z-5(w|a*pzFIK@8Ea)@xI zg-MhPG}q>3)~SWWM^zG`9cv#>ulvnX*o5!D@~^(4)#^h9{6+J`wtAE$YRh~swvj@y zo!aQ@)O~o0_>PZ@AiION_@BdC+Gn$rm~}&gK2AOFVX*Yju9|KghWco4pD*js9pa$i zs#7nJ3Py3mf}BXQxEkXvh92drRV|G%H@D%H5B00mpy9vK)c2)nFi@Kn z{Ptglw8SzCgPBIkbXQhZ_!s6D0x968mIJHCKD&Kc^}bHMlWtXo4i@rkhlYeBY2Ixu z!cj@_quQlWzR~)_F3EeZ1bs?oL_Z75CH-_;uJro&M*KiPagH^?>y zCi_T~l7Ks%_2NiW8^@zqK2f(Mh)?y_H$k~7qM=UGjN^a-DJD^#Q@PG>Ao|je#QgJ< zU*2rb%nr>p>tV*q72cbkZI1yB>aC|tj9|2;aX55^Xn*6ZgoI1APto&WDXA-IP@Lzk zN!jmRh)b3c^jmQDa$8PV!?s()U>G}fKZD!M=BRf0^ZS6GV7BIRnd@>FdS+lp#^!~n zYHNju!$Xy34$b1vkfI9PK_kvDkeV+#;m$&?<3vJ_^-v;gg=Xt!sxW;+W~nNSaH0o-)#yJ6SsEU0jxB+2p>^V zC}V}HbEirRuvQvb&}C%6MMqo5#JXvW{fBKoXM!j?=%no=Z};^@qzsfcmF8**wzqu~ zigrWtTzh6Yc?t4aQYH$#XULIgSyy80>dO7mw{PDbX-{qRc4;X8$(Fj&>3|VCE#aeC z!u<87Jz*qhUBB(_6<;z@4>w$trg%)PH34%4`00|!X{q*o9X@Ui3&KtPtJxzh9@xl{ z@K^g6IPv-)#y5>Kiwo znO+!XI6K`wCofr{?f5&nI)i;DF6UT>N+m8NoKbw!(h?Kj8REt>^6a1D3k5aa_Pj^$ ziDJv|`;(Z5(~jHuUD0ga_Zx^swk)^DbPuv<*UFuQdcRk2v1u&WcF0-OzP1tz|C^cB zQ`bFWn-2@$IMXs>!~LP})f1wa4U$ihNZg+BPr}6lKPl}BaLb;tHzv0V35D~kEcb4u zcWQQ=bcF*s{>RX|alMW^UJQg>tSkC|seKSO5uW%Iu94*5`c1>kZ1duVgoWuQkEo5x z&q26yb*WMz)SQ+od0|#1&yBEk-e_YkMK&3vCh>YufmmdLacONh%Wwo#`>||+0!5y& zh;dpYKU%z{G`T8Z0)$LCo4@PzYA;pM78Fcq$rh04o6|0YxFN#{6WU}w1|Sx<+%NWP zca)3gSY2F}LAjVt|50!Jg4wmm^?3&3)&Mt>=x4y1yvbp*JtGE{VliI z1;4@x1{-jor5bkMLx1Edkxkd`XmW5^T)lQhc6374+t=rpHHBLxC*ZeOUftnSHUS~? zSYRZ0g$rORvVB5Dfpn(42g)HhEH4VK=r1O3L)I@(!MABJ|3Uadw$jfyH^ zF^nNNi18~N^H&uAi>9>zUt1&lBl@r>I=vo7P3;K*m!p>Zk@WHTU9%;!`|X8dTnpe3 zdT~aRG-igf5>gBeTD&N|Z8Oun;)ha~jIB?BEex-q=u+t48gfvY9;@6lXKsEfS&?%& zUuRr9D&Ny=g)H*%k4h;#E1-Hg1)|=+h6TLf^k2j27rg(or+j|S((07QmHn`fg9(uw z=s;eYSS9#}pdl+r<_n=ukf#8x!XOygJtuw6)%oSa_r^w#(1$*3yjYUeWkuZTHK`#P zgEX=WYRj_mo+vh>B1OySN?qvX`)sbtM_bP-{D|%yyPvXx-~vwLzzx*<2q&qNy=^*o zMKIWrh9wD@50)NJ6Axt<@uy-JNW_2Q&1<0TPHZ6~1}A><79Blk8Wjl&Fsq6Uz7-pk z0S{WX$!l~x-k+#eR+d6@<6)aMB%YHdM2N}kSXC#MV&nbSF|%r=V(vMM}h1_1L(nsg$yUDNn+DY5+hIDXcFZgcvmV(E-cIB>ihcLjwt^U2(-TOgkj+TkcT zgw!w;G?82t{)=PALC~X8$$4q*_qpN9!qRP1ycAEb<-L7^%ru*cg%ab(TLTSOFzSr} zdua}u%`<)YjxO%yj6H630XQ@Tf@Brxo6BX|<*UbMpCG%uqkE>$0J(bAxL)r85`rWE zZ1VeE5x3nDB&hUQ6m-S*_`Gi4S{+pPnz{v8siXa8F z9=vt2Bgy(EMI`#}e*Q3dr;XKNe{gcvCYj(#%^tl`Ovo-;v4!Tr?&1||)vjDP7dE$u z$X!!WbYx%ho zjN5dOGAKm?kl->V|MMLXtmDTq@~7Fe}P%XGfiq1KxQYq$V=@`M{DbAemKb!=MjvdpJRW+*4E4MP^5*{5^t`cVVURvoS#jBSh46r8#uQvDT_~> zyRcmMM`$NT29JeTN6r?6UhymaP&SzdQN4@wp}WPAmlm(rWxxfBdb3luzE_YoPKZ*E z9UmXBR?ZT-AeJOT{}-Qr())U$M^TclbpkCo_=@=gs%i4Uf&?HqDGK(yGkf!uDMi+- zS8D9^cYm4ge!`#Uh)LhZ?<}xwoyylNL)52bvQSo8FH*6LpJNu@h)VW;Hto9ReOfF< z+0bD(=LWK55S=sjP~hF6prZA5eakRmEX-0KDkT#4Q_y?5aP#K&b`xhK&IuovXXu#( zX%Mp>Kr7qtXTaAsVKhY?@w=%QgK|*Z%z2yz1F)xntHpMUk8C?J&gqa2h{VMESb>>K z4S+sH88N$z^OtwZhzV`3Lo>GSB3?fvhrV3TwnZ+Kwg zlS02?wBh;tu{HjgYg>C0?`~xzm1T4jrW@qsKvlAD6P+W;%lB@ssN|F8jT4IGR~hFRyc?_` za@wq*ztYeTLIQq#q23%{>{rlXJ@#$ZEsk)1f2p3%S2`sXm-ltH!q(-iK&8E{cdDTI z-kw;msxAN6ZP4hsLY4g3Hrsyl6y?nb?dJZgft~M4ty{lTi<7Tdht`(Yy&LSAl-~<} z+p=hV7&X<$S$ZQ{H|uzA;0dzCiY2`Xoys`Xj(J(MsUYv0WG!_?z0&F8`^4CACM8== zdkzkK*p;0bY?uF&nGSpMw|HeDonlJKkzHjQ-~^t@b(kP85QNb_Nsz~R>Glbb@I2{Rs-=z`zT^EWH7t3Dvfq6qCVrt~7ek)7 zyU5NTg+B&CnDiy+Q%q_of%(7nR}-_!-eWZd%psxN3?!7>s%gTW13R12%M7^dmDwkY zJb2PuXdYWA-o+=X(UhE&y4E4$r*sIu5NA`}*$IAn|68yvp z|04Q=;@hY4bK(jY_}!bs%>uk(Xl^s1vYOfgdRz-;X52okRBKdN5LN0cWLTL1%gJEm zvPz(%Cl)!uX!6&!Iddj+n3`3hdg0=7zgrK{fY%b*+B_}qfa)?6WI#V>t8acK__*J; z0Ei5?Xy3c!Uf zTp2L@R=}kl7`=Jr5^7ar{EIHfO38DCt;tVqb#}@{IDoI-bA~+Y-ewv~{73!vRxUv0 z%4wWCo+8yan*W3@TQGX*g!G-?I8TU%d>zae!l{J@&r64R|+hyla zfbUYZ@L6`w5AMtzN8{UB54G~W*J~PO7WB$sWxW(w=fK>PvdZg@`f5n@ieGFpn{^d6 zmgxtH|)B60c9jLoNm(H@+8sc-)X67q9(s>Fla!6i=eZ?zah` z)HN1Pp9>hfHgRh@?kR~{Dg{0(%(qd9*;6_ay>H?;Dk=Hq z{dH&;c?q~PmMQoqwhxV<7=snzC-D!^B_})Hyu!s zRQ9GM{PNMd92s=*_NWYSzC!j!pet6)u^zA3Bwu*i4n!<+Co_PQj$|3=>6An}h_K>H zOvIj^czYOz8qLf}Vwx%Aik?rB@)5)-atr;%pMNyV%kmMd%L1@zuo2O*cu-mK@U|RI z%c#yh7859Vl}3BZ&ClHpXEOc1JxorvC2?rB4W~**Bz1lO@<6v@&@j+(!QyP1TLI^6 zHhWXMIx@<4LbI@p{pd~M5r>`a-U}94jQ1}$xe?Kluj3oZ5Zl(Gi8IkXI>@v4y=C6R zuI|i0LXfwjRjS7DPj~;o@lhFW=Cp+QfmgJso3E+zXSRjD?rpCvFW+^zv^23?oIciC zHl=TxS~FGF`Wgfc>H+cVY1!U>yd33A!e2>mTcB^RBIIG zd~2@a=!kdOX=EO7xp`R8{Qw?W&dELlNm(ToQVNI3r3buwJ)ke~HM&rYWuV{j5t_wZ zG{#`YTY=2C>e%MKhxdY@bRepduqVh;I>=7}lGACWsXV0msZ$LUf7BMS>?#qm4YAq>4g|Q`` z|CI{W-4RFhGdiEUO8n>56!t}#oF3pw2yn&&w zCJb>88drK!dy|Tcz{)aKqp7aF=hlN#2SV0vtm>~lQSMhNe$`FXdFx41fx1I1asKio z2g&scSAZ;dO?7+LC=7b-B%4R&a9a%j+HzBU+zGp%C0C5qp$t1`=G15@i%Moaq{Xz* zZ67Wd`f4`d&)4|FRgZy$hv3xWT2nB!{e^~gphmfhoF%4-dyXkV?ov*qJ`uKotg z?6moJ$u1R7&e1QZ5I_Cy=8Rsth|8I1+SuBxz8&|rHO5U|?m$Cw6r@0c8z=9Yh?Bh4 z{0^fOy#3n1ND)|8Ru;V=n|xjAuf@K6?`l;{b}A<;TF*HB4d>}s-usI(J=h91fuQ&= zk}vPV=`s?oxusL2y78ag64%tq^Id%*`o$4h8v~2=LLW9Mw_s=c{BZ!MsDR4gnO>pn zTMg~+sf$?K2}?NBYDGLFdo zRoV*?oD*$A6&GS7;6nD;SqEzkN93KuLVyl>VDOR0j>pJw8@fxoQ1V;J**3hbSN?Z% zD=#;Id-ip1d()o31|fqzum9eYNQl6Rj|O#wTwda+Ltm*1{%Ngft5`sG_e`*)+}`Pl zye;?e+#A|no<6T?7!S}HtFG0WDGv}PAyRf~GW@mzZ_Z%B;vvkOBF!=T%;%ZHIu&vu z!Vnkf_L<2bc=U*0z`=83t^53rc3PNeHd>nZwNb$Bd9(@{Riy6cPrJgod3oz@a0dac_hJKQw2B(>PMZOrELjtG-c?rcg{Rx7f?MmgBss|642>Eb_57FymQzp z=LZ(%p%=kLpSNozEH1O_9$d+NYq4b2A8e%hb*%a`ZA9?Hqo}1To;iDhaAIfL4^R7K z(>K%Jq?es*dx@U!vIqFqGp+32I`C($ynWq9c{KlZ$?n-z-RzZzZgdTL(;ab9Pa3#P z*A3zLE-ofyT2Uw^W)A)Sr~yalv6GObJk`t~BP0Erba{DkNYDDW_ndkhkFO~( z(QRgrh~ns8m$k(VY%0W_0aI{R=@ z9oR0eN&uUqtL9@T6@?zR9FR%nO-h!hC4v;v%(QQ5?jv|;hqSg7Ca5{@)Q;7jj};jt zEO<7XdF$GJn6gpK-0>vMKA7mcRB!BLY_jk27e&F-Pu}EHz+EN$f9z)s`XfCFN9FVYktFVd2>B7BRBQoDe@{_ZrnE$k}KCs zyJY=z{`;DS#s=*|+fuNQvaS$gE+P0~DV!zw(AAfWd7%56@Un?4#E(0A9hEm`n_(gW5bU1PM8h8zh<& zLI)KINB}Q+D8B}r90{$preJvdosPBoTV0+CCh4jeWbG_R_42EXJTb_|*0und)p9XJ z4s{@Vq5R$4+zt{ZW3jjXXfHbF>zVwN!$I7d_{DVm zC+0Se; z)XlHBok&-Xp#Tr}DpSbi7HM}5{Pj$Z88Z=EYj$=PdC8M`r`=O4quAWzSDXCRF95iK zio8FEU46(X_kwM<@6;nZf#1$~cHXYM$tYG5q^H2)c=0qi5|+c)x6nAasg>VH0eSs7 zp044w6cdqX@=`e zvUz}OXc;EO;wGFVW)zTMWb-v=zU%NRYm7TB#&z5|2O5dPZ_ip8i0@sPNZtPup#}n$ z?&}U&dT+h<7#=u2mI|KbgSL!1vX_2kGKq<4KA%>!J%;XN2e?#)ZMieK;J$sm@B12t zt_Aic7!YK_KOL0eId@(#3G_d*5<5$CC1X?;((LHU$_4YofG^J=Tr>#Ub zL-y4SP~8$0l^aFq^nq%tztC??2IRc5aK##TC(rxw6shx#b?2$^A{%Yv{z{Y1hs3>^ zViUa5G9hK+=$@63V14nL>2f!7Mn+>RPh_|I8y`UlFDQWeW9Tm`Ab=Pf|b-=37m9(MlTt1i^|BgWlq zTKRP&k5Z8jZtA->na;^4*J9i^#^lb5ffy`uBsg{inzI1|LSt;-s0`xdM})uYPwopI zAe2Wb{gBz=KgC6ao$NS*=og6%&dOTL;d9@AGzjT�dvtrNxf$7NR3d*+CVtJHD(8 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 literal 0 HcmV?d00001 diff --git a/node_modules/ace/demo/kitchen-sink/require.js b/node_modules/ace/demo/kitchen-sink/require.js new file mode 100644 index 00000000..203843c1 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/require.js @@ -0,0 +1,2074 @@ +/** vim: et:ts=4:sw=4:sts=4 + * @license RequireJS 2.1.11+ Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ +//Not using strict: uneven strict support in browsers, #392, and causes +//problems with requirejs.exec()/transpiler plugins that may not be strict. +/*jslint regexp: true, nomen: true, sloppy: true */ +/*global window, navigator, document, importScripts, setTimeout, opera */ + +var requirejs, require, define; +(function (global) { + var req, s, head, baseElement, dataMain, src, + interactiveScript, currentlyAddingScript, mainScript, subPath, + version = '2.1.11+', + commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, + cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, + jsSuffixRegExp = /\.js$/, + currDirRegExp = /^\.\//, + op = Object.prototype, + ostring = op.toString, + hasOwn = op.hasOwnProperty, + ap = Array.prototype, + apsp = ap.splice, + isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document), + isWebWorker = !isBrowser && typeof importScripts !== 'undefined', + //PS3 indicates loaded and complete, but need to wait for complete + //specifically. Sequence is 'loading', 'loaded', execution, + // then 'complete'. The UA check is unfortunate, but not sure how + //to feature test w/o causing perf issues. + readyRegExp = isBrowser && navigator.platform === 'PLAYSTATION 3' ? + /^complete$/ : /^(complete|loaded)$/, + defContextName = '_', + //Oh the tragedy, detecting opera. See the usage of isOpera for reason. + isOpera = typeof opera !== 'undefined' && opera.toString() === '[object Opera]', + contexts = {}, + cfg = {}, + globalDefQueue = [], + useInteractive = false; + + function isFunction(it) { + return ostring.call(it) === '[object Function]'; + } + + function isArray(it) { + return ostring.call(it) === '[object Array]'; + } + + /** + * Helper function for iterating over an array. If the func returns + * a true value, it will break out of the loop. + */ + function each(ary, func) { + if (ary) { + var i; + for (i = 0; i < ary.length; i += 1) { + if (ary[i] && func(ary[i], i, ary)) { + break; + } + } + } + } + + /** + * Helper function for iterating over an array backwards. If the func + * returns a true value, it will break out of the loop. + */ + function eachReverse(ary, func) { + if (ary) { + var i; + for (i = ary.length - 1; i > -1; i -= 1) { + if (ary[i] && func(ary[i], i, ary)) { + break; + } + } + } + } + + function hasProp(obj, prop) { + return hasOwn.call(obj, prop); + } + + function getOwn(obj, prop) { + return hasProp(obj, prop) && obj[prop]; + } + + /** + * Cycles over properties in an object and calls a function for each + * property value. If the function returns a truthy value, then the + * iteration is stopped. + */ + function eachProp(obj, func) { + var prop; + for (prop in obj) { + if (hasProp(obj, prop)) { + if (func(obj[prop], prop)) { + break; + } + } + } + } + + /** + * Simple function to mix in properties from source into target, + * but only if target does not already have a property of the same name. + */ + function mixin(target, source, force, deepStringMixin) { + if (source) { + eachProp(source, function (value, prop) { + if (force || !hasProp(target, prop)) { + if (deepStringMixin && typeof value === 'object' && value && + !isArray(value) && !isFunction(value) && + !(value instanceof RegExp)) { + + if (!target[prop]) { + target[prop] = {}; + } + mixin(target[prop], value, force, deepStringMixin); + } else { + target[prop] = value; + } + } + }); + } + return target; + } + + //Similar to Function.prototype.bind, but the 'this' object is specified + //first, since it is easier to read/figure out what 'this' will be. + function bind(obj, fn) { + return function () { + return fn.apply(obj, arguments); + }; + } + + function scripts() { + return document.getElementsByTagName('script'); + } + + function defaultOnError(err) { + throw err; + } + + //Allow getting a global that is expressed in + //dot notation, like 'a.b.c'. + function getGlobal(value) { + if (!value) { + return value; + } + var g = global; + each(value.split('.'), function (part) { + g = g[part]; + }); + return g; + } + + /** + * Constructs an error with a pointer to an URL with more information. + * @param {String} id the error ID that maps to an ID on a web page. + * @param {String} message human readable error. + * @param {Error} [err] the original error, if there is one. + * + * @returns {Error} + */ + function makeError(id, msg, err, requireModules) { + var e = new Error(msg + '\nhttp://requirejs.org/docs/errors.html#' + id); + e.requireType = id; + e.requireModules = requireModules; + if (err) { + e.originalError = err; + } + return e; + } + + if (typeof define !== 'undefined') { + //If a define is already in play via another AMD loader, + //do not overwrite. + return; + } + + if (typeof requirejs !== 'undefined') { + if (isFunction(requirejs)) { + //Do not overwrite an existing requirejs instance. + return; + } + cfg = requirejs; + requirejs = undefined; + } + + //Allow for a require config object + if (typeof require !== 'undefined' && !isFunction(require)) { + //assume it is a config object. + cfg = require; + require = undefined; + } + + function newContext(contextName) { + var inCheckLoaded, Module, context, handlers, + checkLoadedTimeoutId, + config = { + //Defaults. Do not set a default for map + //config to speed up normalize(), which + //will run faster if there is no default. + waitSeconds: 7, + baseUrl: './', + paths: {}, + bundles: {}, + pkgs: {}, + shim: {}, + config: {} + }, + registry = {}, + //registry of just enabled modules, to speed + //cycle breaking code when lots of modules + //are registered, but not activated. + enabledRegistry = {}, + undefEvents = {}, + defQueue = [], + defined = {}, + urlFetched = {}, + bundlesMap = {}, + requireCounter = 1, + unnormalizedCounter = 1; + + /** + * Trims the . and .. from an array of path segments. + * It will keep a leading path segment if a .. will become + * the first path segment, to help with module name lookups, + * which act like paths, but can be remapped. But the end result, + * all paths that use this function should look normalized. + * NOTE: this method MODIFIES the input array. + * @param {Array} ary the array of path segments. + */ + function trimDots(ary) { + var i, part, length = ary.length; + for (i = 0; i < length; i++) { + part = ary[i]; + if (part === '.') { + ary.splice(i, 1); + i -= 1; + } else if (part === '..') { + if (i === 1 && (ary[2] === '..' || ary[0] === '..')) { + //End of the line. Keep at least one non-dot + //path segment at the front so it can be mapped + //correctly to disk. Otherwise, there is likely + //no path mapping for a path starting with '..'. + //This can still fail, but catches the most reasonable + //uses of .. + break; + } else if (i > 0) { + ary.splice(i - 1, 2); + i -= 2; + } + } + } + } + + /** + * Given a relative module name, like ./something, normalize it to + * a real name that can be mapped to a path. + * @param {String} name the relative name + * @param {String} baseName a real name that the name arg is relative + * to. + * @param {Boolean} applyMap apply the map config to the value. Should + * only be done if this normalization is for a dependency ID. + * @returns {String} normalized name + */ + function normalize(name, baseName, applyMap) { + var pkgMain, mapValue, nameParts, i, j, nameSegment, lastIndex, + foundMap, foundI, foundStarMap, starI, + baseParts = baseName && baseName.split('/'), + normalizedBaseParts = baseParts, + map = config.map, + starMap = map && map['*']; + + //Adjust any relative paths. + if (name && name.charAt(0) === '.') { + //If have a base name, try to normalize against it, + //otherwise, assume it is a top-level require that will + //be relative to baseUrl in the end. + if (baseName) { + //Convert baseName to array, and lop off the last part, + //so that . matches that 'directory' and not name of the baseName's + //module. For instance, baseName of 'one/two/three', maps to + //'one/two/three.js', but we want the directory, 'one/two' for + //this normalization. + normalizedBaseParts = baseParts.slice(0, baseParts.length - 1); + name = name.split('/'); + lastIndex = name.length - 1; + + // If wanting node ID compatibility, strip .js from end + // of IDs. Have to do this here, and not in nameToUrl + // because node allows either .js or non .js to map + // to same file. + if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) { + name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, ''); + } + + name = normalizedBaseParts.concat(name); + trimDots(name); + name = name.join('/'); + } else if (name.indexOf('./') === 0) { + // No baseName, so this is ID is resolved relative + // to baseUrl, pull off the leading dot. + name = name.substring(2); + } + } + + //Apply map config if available. + if (applyMap && map && (baseParts || starMap)) { + nameParts = name.split('/'); + + outerLoop: for (i = nameParts.length; i > 0; i -= 1) { + nameSegment = nameParts.slice(0, i).join('/'); + + if (baseParts) { + //Find the longest baseName segment match in the config. + //So, do joins on the biggest to smallest lengths of baseParts. + for (j = baseParts.length; j > 0; j -= 1) { + mapValue = getOwn(map, baseParts.slice(0, j).join('/')); + + //baseName segment has config, find if it has one for + //this name. + if (mapValue) { + mapValue = getOwn(mapValue, nameSegment); + if (mapValue) { + //Match, update name to the new value. + foundMap = mapValue; + foundI = i; + break outerLoop; + } + } + } + } + + //Check for a star map match, but just hold on to it, + //if there is a shorter segment match later in a matching + //config, then favor over this star map. + if (!foundStarMap && starMap && getOwn(starMap, nameSegment)) { + foundStarMap = getOwn(starMap, nameSegment); + starI = i; + } + } + + if (!foundMap && foundStarMap) { + foundMap = foundStarMap; + foundI = starI; + } + + if (foundMap) { + nameParts.splice(0, foundI, foundMap); + name = nameParts.join('/'); + } + } + + // If the name points to a package's name, use + // the package main instead. + pkgMain = getOwn(config.pkgs, name); + + return pkgMain ? pkgMain : name; + } + + function removeScript(name) { + if (isBrowser) { + each(scripts(), function (scriptNode) { + if (scriptNode.getAttribute('data-requiremodule') === name && + scriptNode.getAttribute('data-requirecontext') === context.contextName) { + scriptNode.parentNode.removeChild(scriptNode); + return true; + } + }); + } + } + + function hasPathFallback(id) { + var pathConfig = getOwn(config.paths, id); + if (pathConfig && isArray(pathConfig) && pathConfig.length > 1) { + //Pop off the first array value, since it failed, and + //retry + pathConfig.shift(); + context.require.undef(id); + + //Custom require that does not do map translation, since + //ID is "absolute", already mapped/resolved. + context.makeRequire(null, { + skipMap: true + })([id]); + + return true; + } + } + + //Turns a plugin!resource to [plugin, resource] + //with the plugin being undefined if the name + //did not have a plugin prefix. + function splitPrefix(name) { + var prefix, + index = name ? name.indexOf('!') : -1; + if (index > -1) { + prefix = name.substring(0, index); + name = name.substring(index + 1, name.length); + } + return [prefix, name]; + } + + /** + * Creates a module mapping that includes plugin prefix, module + * name, and path. If parentModuleMap is provided it will + * also normalize the name via require.normalize() + * + * @param {String} name the module name + * @param {String} [parentModuleMap] parent module map + * for the module name, used to resolve relative names. + * @param {Boolean} isNormalized: is the ID already normalized. + * This is true if this call is done for a define() module ID. + * @param {Boolean} applyMap: apply the map config to the ID. + * Should only be true if this map is for a dependency. + * + * @returns {Object} + */ + function makeModuleMap(name, parentModuleMap, isNormalized, applyMap) { + var url, pluginModule, suffix, nameParts, + prefix = null, + parentName = parentModuleMap ? parentModuleMap.name : null, + originalName = name, + isDefine = true, + normalizedName = ''; + + //If no name, then it means it is a require call, generate an + //internal name. + if (!name) { + isDefine = false; + name = '_@r' + (requireCounter += 1); + } + + nameParts = splitPrefix(name); + prefix = nameParts[0]; + name = nameParts[1]; + + if (prefix) { + prefix = normalize(prefix, parentName, applyMap); + pluginModule = getOwn(defined, prefix); + } + + //Account for relative paths if there is a base name. + if (name) { + if (prefix) { + if (pluginModule && pluginModule.normalize) { + //Plugin is loaded, use its normalize method. + normalizedName = pluginModule.normalize(name, function (name) { + return normalize(name, parentName, applyMap); + }); + } else { + normalizedName = normalize(name, parentName, applyMap); + } + } else { + //A regular module. + normalizedName = normalize(name, parentName, applyMap); + + //Normalized name may be a plugin ID due to map config + //application in normalize. The map config values must + //already be normalized, so do not need to redo that part. + nameParts = splitPrefix(normalizedName); + prefix = nameParts[0]; + normalizedName = nameParts[1]; + isNormalized = true; + + url = context.nameToUrl(normalizedName); + } + } + + //If the id is a plugin id that cannot be determined if it needs + //normalization, stamp it with a unique ID so two matching relative + //ids that may conflict can be separate. + suffix = prefix && !pluginModule && !isNormalized ? + '_unnormalized' + (unnormalizedCounter += 1) : + ''; + + return { + prefix: prefix, + name: normalizedName, + parentMap: parentModuleMap, + unnormalized: !!suffix, + url: url, + originalName: originalName, + isDefine: isDefine, + id: (prefix ? + prefix + '!' + normalizedName : + normalizedName) + suffix + }; + } + + function getModule(depMap) { + var id = depMap.id, + mod = getOwn(registry, id); + + if (!mod) { + mod = registry[id] = new context.Module(depMap); + } + + return mod; + } + + function on(depMap, name, fn) { + var id = depMap.id, + mod = getOwn(registry, id); + + if (hasProp(defined, id) && + (!mod || mod.defineEmitComplete)) { + if (name === 'defined') { + fn(defined[id]); + } + } else { + mod = getModule(depMap); + if (mod.error && name === 'error') { + fn(mod.error); + } else { + mod.on(name, fn); + } + } + } + + function onError(err, errback) { + var ids = err.requireModules, + notified = false; + + if (errback) { + errback(err); + } else { + each(ids, function (id) { + var mod = getOwn(registry, id); + if (mod) { + //Set error on module, so it skips timeout checks. + mod.error = err; + if (mod.events.error) { + notified = true; + mod.emit('error', err); + } + } + }); + + if (!notified) { + req.onError(err); + } + } + } + + /** + * Internal method to transfer globalQueue items to this context's + * defQueue. + */ + function takeGlobalQueue() { + //Push all the globalDefQueue items into the context's defQueue + if (globalDefQueue.length) { + //Array splice in the values since the context code has a + //local var ref to defQueue, so cannot just reassign the one + //on context. + apsp.apply(defQueue, + [defQueue.length, 0].concat(globalDefQueue)); + globalDefQueue = []; + } + } + + handlers = { + 'require': function (mod) { + if (mod.require) { + return mod.require; + } else { + return (mod.require = context.makeRequire(mod.map)); + } + }, + 'exports': function (mod) { + mod.usingExports = true; + if (mod.map.isDefine) { + if (mod.exports) { + return (defined[mod.map.id] = mod.exports); + } else { + return (mod.exports = defined[mod.map.id] = {}); + } + } + }, + 'module': function (mod) { + if (mod.module) { + return mod.module; + } else { + return (mod.module = { + id: mod.map.id, + uri: mod.map.url, + config: function () { + return getOwn(config.config, mod.map.id) || {}; + }, + exports: mod.exports || (mod.exports = {}) + }); + } + } + }; + + function cleanRegistry(id) { + //Clean up machinery used for waiting modules. + delete registry[id]; + delete enabledRegistry[id]; + } + + function breakCycle(mod, traced, processed) { + var id = mod.map.id; + + if (mod.error) { + mod.emit('error', mod.error); + } else { + traced[id] = true; + each(mod.depMaps, function (depMap, i) { + var depId = depMap.id, + dep = getOwn(registry, depId); + + //Only force things that have not completed + //being defined, so still in the registry, + //and only if it has not been matched up + //in the module already. + if (dep && !mod.depMatched[i] && !processed[depId]) { + if (getOwn(traced, depId)) { + mod.defineDep(i, defined[depId]); + mod.check(); //pass false? + } else { + breakCycle(dep, traced, processed); + } + } + }); + processed[id] = true; + } + } + + function checkLoaded() { + var err, usingPathFallback, + waitInterval = config.waitSeconds * 1000, + //It is possible to disable the wait interval by using waitSeconds of 0. + expired = waitInterval && (context.startTime + waitInterval) < new Date().getTime(), + noLoads = [], + reqCalls = [], + stillLoading = false, + needCycleCheck = true; + + //Do not bother if this call was a result of a cycle break. + if (inCheckLoaded) { + return; + } + + inCheckLoaded = true; + + //Figure out the state of all the modules. + eachProp(enabledRegistry, function (mod) { + var map = mod.map, + modId = map.id; + + //Skip things that are not enabled or in error state. + if (!mod.enabled) { + return; + } + + if (!map.isDefine) { + reqCalls.push(mod); + } + + if (!mod.error) { + //If the module should be executed, and it has not + //been inited and time is up, remember it. + if (!mod.inited && expired) { + if (hasPathFallback(modId)) { + usingPathFallback = true; + stillLoading = true; + } else { + noLoads.push(modId); + removeScript(modId); + } + } else if (!mod.inited && mod.fetched && map.isDefine) { + stillLoading = true; + if (!map.prefix) { + //No reason to keep looking for unfinished + //loading. If the only stillLoading is a + //plugin resource though, keep going, + //because it may be that a plugin resource + //is waiting on a non-plugin cycle. + return (needCycleCheck = false); + } + } + } + }); + + if (expired && noLoads.length) { + //If wait time expired, throw error of unloaded modules. + err = makeError('timeout', 'Load timeout for modules: ' + noLoads, null, noLoads); + err.contextName = context.contextName; + return onError(err); + } + + //Not expired, check for a cycle. + if (needCycleCheck) { + each(reqCalls, function (mod) { + breakCycle(mod, {}, {}); + }); + } + + //If still waiting on loads, and the waiting load is something + //other than a plugin resource, or there are still outstanding + //scripts, then just try back later. + if ((!expired || usingPathFallback) && stillLoading) { + //Something is still waiting to load. Wait for it, but only + //if a timeout is not already in effect. + if ((isBrowser || isWebWorker) && !checkLoadedTimeoutId) { + checkLoadedTimeoutId = setTimeout(function () { + checkLoadedTimeoutId = 0; + checkLoaded(); + }, 50); + } + } + + inCheckLoaded = false; + } + + Module = function (map) { + this.events = getOwn(undefEvents, map.id) || {}; + this.map = map; + this.shim = getOwn(config.shim, map.id); + this.depExports = []; + this.depMaps = []; + this.depMatched = []; + this.pluginMaps = {}; + this.depCount = 0; + + /* this.exports this.factory + this.depMaps = [], + this.enabled, this.fetched + */ + }; + + Module.prototype = { + init: function (depMaps, factory, errback, options) { + options = options || {}; + + //Do not do more inits if already done. Can happen if there + //are multiple define calls for the same module. That is not + //a normal, common case, but it is also not unexpected. + if (this.inited) { + return; + } + + this.factory = factory; + + if (errback) { + //Register for errors on this module. + this.on('error', errback); + } else if (this.events.error) { + //If no errback already, but there are error listeners + //on this module, set up an errback to pass to the deps. + errback = bind(this, function (err) { + this.emit('error', err); + }); + } + + //Do a copy of the dependency array, so that + //source inputs are not modified. For example + //"shim" deps are passed in here directly, and + //doing a direct modification of the depMaps array + //would affect that config. + this.depMaps = depMaps && depMaps.slice(0); + + this.errback = errback; + + //Indicate this module has be initialized + this.inited = true; + + this.ignore = options.ignore; + + //Could have option to init this module in enabled mode, + //or could have been previously marked as enabled. However, + //the dependencies are not known until init is called. So + //if enabled previously, now trigger dependencies as enabled. + if (options.enabled || this.enabled) { + //Enable this module and dependencies. + //Will call this.check() + this.enable(); + } else { + this.check(); + } + }, + + defineDep: function (i, depExports) { + //Because of cycles, defined callback for a given + //export can be called more than once. + if (!this.depMatched[i]) { + this.depMatched[i] = true; + this.depCount -= 1; + this.depExports[i] = depExports; + } + }, + + fetch: function () { + if (this.fetched) { + return; + } + this.fetched = true; + + context.startTime = (new Date()).getTime(); + + var map = this.map; + + //If the manager is for a plugin managed resource, + //ask the plugin to load it now. + if (this.shim) { + context.makeRequire(this.map, { + enableBuildCallback: true + })(this.shim.deps || [], bind(this, function () { + return map.prefix ? this.callPlugin() : this.load(); + })); + } else { + //Regular dependency. + return map.prefix ? this.callPlugin() : this.load(); + } + }, + + load: function () { + var url = this.map.url; + + //Regular dependency. + if (!urlFetched[url]) { + urlFetched[url] = true; + context.load(this.map.id, url); + } + }, + + /** + * Checks if the module is ready to define itself, and if so, + * define it. + */ + check: function () { + if (!this.enabled || this.enabling) { + return; + } + + var err, cjsModule, + id = this.map.id, + depExports = this.depExports, + exports = this.exports, + factory = this.factory; + + if (!this.inited) { + this.fetch(); + } else if (this.error) { + this.emit('error', this.error); + } else if (!this.defining) { + //The factory could trigger another require call + //that would result in checking this module to + //define itself again. If already in the process + //of doing that, skip this work. + this.defining = true; + + if (this.depCount < 1 && !this.defined) { + if (isFunction(factory)) { + //If there is an error listener, favor passing + //to that instead of throwing an error. However, + //only do it for define()'d modules. require + //errbacks should not be called for failures in + //their callbacks (#699). However if a global + //onError is set, use that. + if ((this.events.error && this.map.isDefine) || + req.onError !== defaultOnError) { + try { + exports = context.execCb(id, factory, depExports, exports); + } catch (e) { + err = e; + } + } else { + exports = context.execCb(id, factory, depExports, exports); + } + + // Favor return value over exports. If node/cjs in play, + // then will not have a return value anyway. Favor + // module.exports assignment over exports object. + if (this.map.isDefine && exports === undefined) { + cjsModule = this.module; + if (cjsModule) { + exports = cjsModule.exports; + } else if (this.usingExports) { + //exports already set the defined value. + exports = this.exports; + } + } + + if (err) { + err.requireMap = this.map; + err.requireModules = this.map.isDefine ? [this.map.id] : null; + err.requireType = this.map.isDefine ? 'define' : 'require'; + return onError((this.error = err)); + } + + } else { + //Just a literal value + exports = factory; + } + + this.exports = exports; + + if (this.map.isDefine && !this.ignore) { + defined[id] = exports; + + if (req.onResourceLoad) { + req.onResourceLoad(context, this.map, this.depMaps); + } + } + + //Clean up + cleanRegistry(id); + + this.defined = true; + } + + //Finished the define stage. Allow calling check again + //to allow define notifications below in the case of a + //cycle. + this.defining = false; + + if (this.defined && !this.defineEmitted) { + this.defineEmitted = true; + this.emit('defined', this.exports); + this.defineEmitComplete = true; + } + + } + }, + + callPlugin: function () { + var map = this.map, + id = map.id, + //Map already normalized the prefix. + pluginMap = makeModuleMap(map.prefix); + + //Mark this as a dependency for this plugin, so it + //can be traced for cycles. + this.depMaps.push(pluginMap); + + on(pluginMap, 'defined', bind(this, function (plugin) { + var load, normalizedMap, normalizedMod, + bundleId = getOwn(bundlesMap, this.map.id), + name = this.map.name, + parentName = this.map.parentMap ? this.map.parentMap.name : null, + localRequire = context.makeRequire(map.parentMap, { + enableBuildCallback: true + }); + + //If current map is not normalized, wait for that + //normalized name to load instead of continuing. + if (this.map.unnormalized) { + //Normalize the ID if the plugin allows it. + if (plugin.normalize) { + name = plugin.normalize(name, function (name) { + return normalize(name, parentName, true); + }) || ''; + } + + //prefix and name should already be normalized, no need + //for applying map config again either. + normalizedMap = makeModuleMap(map.prefix + '!' + name, + this.map.parentMap); + on(normalizedMap, + 'defined', bind(this, function (value) { + this.init([], function () { return value; }, null, { + enabled: true, + ignore: true + }); + })); + + normalizedMod = getOwn(registry, normalizedMap.id); + if (normalizedMod) { + //Mark this as a dependency for this plugin, so it + //can be traced for cycles. + this.depMaps.push(normalizedMap); + + if (this.events.error) { + normalizedMod.on('error', bind(this, function (err) { + this.emit('error', err); + })); + } + normalizedMod.enable(); + } + + return; + } + + //If a paths config, then just load that file instead to + //resolve the plugin, as it is built into that paths layer. + if (bundleId) { + this.map.url = context.nameToUrl(bundleId); + this.load(); + return; + } + + load = bind(this, function (value) { + this.init([], function () { return value; }, null, { + enabled: true + }); + }); + + load.error = bind(this, function (err) { + this.inited = true; + this.error = err; + err.requireModules = [id]; + + //Remove temp unnormalized modules for this module, + //since they will never be resolved otherwise now. + eachProp(registry, function (mod) { + if (mod.map.id.indexOf(id + '_unnormalized') === 0) { + cleanRegistry(mod.map.id); + } + }); + + onError(err); + }); + + //Allow plugins to load other code without having to know the + //context or how to 'complete' the load. + load.fromText = bind(this, function (text, textAlt) { + /*jslint evil: true */ + var moduleName = map.name, + moduleMap = makeModuleMap(moduleName), + hasInteractive = useInteractive; + + //As of 2.1.0, support just passing the text, to reinforce + //fromText only being called once per resource. Still + //support old style of passing moduleName but discard + //that moduleName in favor of the internal ref. + if (textAlt) { + text = textAlt; + } + + //Turn off interactive script matching for IE for any define + //calls in the text, then turn it back on at the end. + if (hasInteractive) { + useInteractive = false; + } + + //Prime the system by creating a module instance for + //it. + getModule(moduleMap); + + //Transfer any config to this other module. + if (hasProp(config.config, id)) { + config.config[moduleName] = config.config[id]; + } + + try { + req.exec(text); + } catch (e) { + return onError(makeError('fromtexteval', + 'fromText eval for ' + id + + ' failed: ' + e, + e, + [id])); + } + + if (hasInteractive) { + useInteractive = true; + } + + //Mark this as a dependency for the plugin + //resource + this.depMaps.push(moduleMap); + + //Support anonymous modules. + context.completeLoad(moduleName); + + //Bind the value of that module to the value for this + //resource ID. + localRequire([moduleName], load); + }); + + //Use parentName here since the plugin's name is not reliable, + //could be some weird string with no path that actually wants to + //reference the parentName's path. + plugin.load(map.name, localRequire, load, config); + })); + + context.enable(pluginMap, this); + this.pluginMaps[pluginMap.id] = pluginMap; + }, + + enable: function () { + enabledRegistry[this.map.id] = this; + this.enabled = true; + + //Set flag mentioning that the module is enabling, + //so that immediate calls to the defined callbacks + //for dependencies do not trigger inadvertent load + //with the depCount still being zero. + this.enabling = true; + + //Enable each dependency + each(this.depMaps, bind(this, function (depMap, i) { + var id, mod, handler; + + if (typeof depMap === 'string') { + //Dependency needs to be converted to a depMap + //and wired up to this module. + depMap = makeModuleMap(depMap, + (this.map.isDefine ? this.map : this.map.parentMap), + false, + !this.skipMap); + this.depMaps[i] = depMap; + + handler = getOwn(handlers, depMap.id); + + if (handler) { + this.depExports[i] = handler(this); + return; + } + + this.depCount += 1; + + on(depMap, 'defined', bind(this, function (depExports) { + this.defineDep(i, depExports); + this.check(); + })); + + if (this.errback) { + on(depMap, 'error', bind(this, this.errback)); + } + } + + id = depMap.id; + mod = registry[id]; + + //Skip special modules like 'require', 'exports', 'module' + //Also, don't call enable if it is already enabled, + //important in circular dependency cases. + if (!hasProp(handlers, id) && mod && !mod.enabled) { + context.enable(depMap, this); + } + })); + + //Enable each plugin that is used in + //a dependency + eachProp(this.pluginMaps, bind(this, function (pluginMap) { + var mod = getOwn(registry, pluginMap.id); + if (mod && !mod.enabled) { + context.enable(pluginMap, this); + } + })); + + this.enabling = false; + + this.check(); + }, + + on: function (name, cb) { + var cbs = this.events[name]; + if (!cbs) { + cbs = this.events[name] = []; + } + cbs.push(cb); + }, + + emit: function (name, evt) { + each(this.events[name], function (cb) { + cb(evt); + }); + if (name === 'error') { + //Now that the error handler was triggered, remove + //the listeners, since this broken Module instance + //can stay around for a while in the registry. + delete this.events[name]; + } + } + }; + + function callGetModule(args) { + //Skip modules already defined. + if (!hasProp(defined, args[0])) { + getModule(makeModuleMap(args[0], null, true)).init(args[1], args[2]); + } + } + + function removeListener(node, func, name, ieName) { + //Favor detachEvent because of IE9 + //issue, see attachEvent/addEventListener comment elsewhere + //in this file. + if (node.detachEvent && !isOpera) { + //Probably IE. If not it will throw an error, which will be + //useful to know. + if (ieName) { + node.detachEvent(ieName, func); + } + } else { + node.removeEventListener(name, func, false); + } + } + + /** + * Given an event from a script node, get the requirejs info from it, + * and then removes the event listeners on the node. + * @param {Event} evt + * @returns {Object} + */ + function getScriptData(evt) { + //Using currentTarget instead of target for Firefox 2.0's sake. Not + //all old browsers will be supported, but this one was easy enough + //to support and still makes sense. + var node = evt.currentTarget || evt.srcElement; + + //Remove the listeners once here. + removeListener(node, context.onScriptLoad, 'load', 'onreadystatechange'); + removeListener(node, context.onScriptError, 'error'); + + return { + node: node, + id: node && node.getAttribute('data-requiremodule') + }; + } + + function intakeDefines() { + var args; + + //Any defined modules in the global queue, intake them now. + takeGlobalQueue(); + + //Make sure any remaining defQueue items get properly processed. + while (defQueue.length) { + args = defQueue.shift(); + if (args[0] === null) { + return onError(makeError('mismatch', 'Mismatched anonymous define() module: ' + args[args.length - 1])); + } else { + //args are id, deps, factory. Should be normalized by the + //define() function. + callGetModule(args); + } + } + } + + context = { + config: config, + contextName: contextName, + registry: registry, + defined: defined, + urlFetched: urlFetched, + defQueue: defQueue, + Module: Module, + makeModuleMap: makeModuleMap, + nextTick: req.nextTick, + onError: onError, + + /** + * Set a configuration for the context. + * @param {Object} cfg config object to integrate. + */ + configure: function (cfg) { + //Make sure the baseUrl ends in a slash. + if (cfg.baseUrl) { + if (cfg.baseUrl.charAt(cfg.baseUrl.length - 1) !== '/') { + cfg.baseUrl += '/'; + } + } + + //Save off the paths since they require special processing, + //they are additive. + var shim = config.shim, + objs = { + paths: true, + bundles: true, + config: true, + map: true + }; + + eachProp(cfg, function (value, prop) { + if (objs[prop]) { + if (!config[prop]) { + config[prop] = {}; + } + mixin(config[prop], value, true, true); + } else { + config[prop] = value; + } + }); + + //Reverse map the bundles + if (cfg.bundles) { + eachProp(cfg.bundles, function (value, prop) { + each(value, function (v) { + if (v !== prop) { + bundlesMap[v] = prop; + } + }); + }); + } + + //Merge shim + if (cfg.shim) { + eachProp(cfg.shim, function (value, id) { + //Normalize the structure + if (isArray(value)) { + value = { + deps: value + }; + } + if ((value.exports || value.init) && !value.exportsFn) { + value.exportsFn = context.makeShimExports(value); + } + shim[id] = value; + }); + config.shim = shim; + } + + //Adjust packages if necessary. + if (cfg.packages) { + each(cfg.packages, function (pkgObj) { + var location, name; + + pkgObj = typeof pkgObj === 'string' ? { name: pkgObj } : pkgObj; + + name = pkgObj.name; + location = pkgObj.location; + if (location) { + config.paths[name] = pkgObj.location; + } + + //Save pointer to main module ID for pkg name. + //Remove leading dot in main, so main paths are normalized, + //and remove any trailing .js, since different package + //envs have different conventions: some use a module name, + //some use a file name. + config.pkgs[name] = pkgObj.name + '/' + (pkgObj.main || 'main') + .replace(currDirRegExp, '') + .replace(jsSuffixRegExp, ''); + }); + } + + //If there are any "waiting to execute" modules in the registry, + //update the maps for them, since their info, like URLs to load, + //may have changed. + eachProp(registry, function (mod, id) { + //If module already has init called, since it is too + //late to modify them, and ignore unnormalized ones + //since they are transient. + if (!mod.inited && !mod.map.unnormalized) { + mod.map = makeModuleMap(id); + } + }); + + //If a deps array or a config callback is specified, then call + //require with those args. This is useful when require is defined as a + //config object before require.js is loaded. + if (cfg.deps || cfg.callback) { + context.require(cfg.deps || [], cfg.callback); + } + }, + + makeShimExports: function (value) { + function fn() { + var ret; + if (value.init) { + ret = value.init.apply(global, arguments); + } + return ret || (value.exports && getGlobal(value.exports)); + } + return fn; + }, + + makeRequire: function (relMap, options) { + options = options || {}; + + function localRequire(deps, callback, errback) { + var id, map, requireMod; + + if (options.enableBuildCallback && callback && isFunction(callback)) { + callback.__requireJsBuild = true; + } + + if (typeof deps === 'string') { + if (isFunction(callback)) { + //Invalid call + return onError(makeError('requireargs', 'Invalid require call'), errback); + } + + //If require|exports|module are requested, get the + //value for them from the special handlers. Caveat: + //this only works while module is being defined. + if (relMap && hasProp(handlers, deps)) { + return handlers[deps](registry[relMap.id]); + } + + //Synchronous access to one module. If require.get is + //available (as in the Node adapter), prefer that. + if (req.get) { + return req.get(context, deps, relMap, localRequire); + } + + //Normalize module name, if it contains . or .. + map = makeModuleMap(deps, relMap, false, true); + id = map.id; + + if (!hasProp(defined, id)) { + return onError(makeError('notloaded', 'Module name "' + + id + + '" has not been loaded yet for context: ' + + contextName + + (relMap ? '' : '. Use require([])'))); + } + return defined[id]; + } + + //Grab defines waiting in the global queue. + intakeDefines(); + + //Mark all the dependencies as needing to be loaded. + context.nextTick(function () { + //Some defines could have been added since the + //require call, collect them. + intakeDefines(); + + requireMod = getModule(makeModuleMap(null, relMap)); + + //Store if map config should be applied to this require + //call for dependencies. + requireMod.skipMap = options.skipMap; + + requireMod.init(deps, callback, errback, { + enabled: true + }); + + checkLoaded(); + }); + + return localRequire; + } + + mixin(localRequire, { + isBrowser: isBrowser, + + /** + * Converts a module name + .extension into an URL path. + * *Requires* the use of a module name. It does not support using + * plain URLs like nameToUrl. + */ + toUrl: function (moduleNamePlusExt) { + var ext, + index = moduleNamePlusExt.lastIndexOf('.'), + segment = moduleNamePlusExt.split('/')[0], + isRelative = segment === '.' || segment === '..'; + + //Have a file extension alias, and it is not the + //dots from a relative path. + if (index !== -1 && (!isRelative || index > 1)) { + ext = moduleNamePlusExt.substring(index, moduleNamePlusExt.length); + moduleNamePlusExt = moduleNamePlusExt.substring(0, index); + } + + return context.nameToUrl(normalize(moduleNamePlusExt, + relMap && relMap.id, true), ext, true); + }, + + defined: function (id) { + return hasProp(defined, makeModuleMap(id, relMap, false, true).id); + }, + + specified: function (id) { + id = makeModuleMap(id, relMap, false, true).id; + return hasProp(defined, id) || hasProp(registry, id); + } + }); + + //Only allow undef on top level require calls + if (!relMap) { + localRequire.undef = function (id) { + //Bind any waiting define() calls to this context, + //fix for #408 + takeGlobalQueue(); + + var map = makeModuleMap(id, relMap, true), + mod = getOwn(registry, id); + + removeScript(id); + + delete defined[id]; + delete urlFetched[map.url]; + delete undefEvents[id]; + + //Clean queued defines too. Go backwards + //in array so that the splices do not + //mess up the iteration. + eachReverse(defQueue, function(args, i) { + if(args[0] === id) { + defQueue.splice(i, 1); + } + }); + + if (mod) { + //Hold on to listeners in case the + //module will be attempted to be reloaded + //using a different config. + if (mod.events.defined) { + undefEvents[id] = mod.events; + } + + cleanRegistry(id); + } + }; + } + + return localRequire; + }, + + /** + * Called to enable a module if it is still in the registry + * awaiting enablement. A second arg, parent, the parent module, + * is passed in for context, when this method is overridden by + * the optimizer. Not shown here to keep code compact. + */ + enable: function (depMap) { + var mod = getOwn(registry, depMap.id); + if (mod) { + getModule(depMap).enable(); + } + }, + + /** + * Internal method used by environment adapters to complete a load event. + * A load event could be a script load or just a load pass from a synchronous + * load call. + * @param {String} moduleName the name of the module to potentially complete. + */ + completeLoad: function (moduleName) { + var found, args, mod, + shim = getOwn(config.shim, moduleName) || {}, + shExports = shim.exports; + + takeGlobalQueue(); + + while (defQueue.length) { + args = defQueue.shift(); + if (args[0] === null) { + args[0] = moduleName; + //If already found an anonymous module and bound it + //to this name, then this is some other anon module + //waiting for its completeLoad to fire. + if (found) { + break; + } + found = true; + } else if (args[0] === moduleName) { + //Found matching define call for this script! + found = true; + } + + callGetModule(args); + } + + //Do this after the cycle of callGetModule in case the result + //of those calls/init calls changes the registry. + mod = getOwn(registry, moduleName); + + if (!found && !hasProp(defined, moduleName) && mod && !mod.inited) { + if (config.enforceDefine && (!shExports || !getGlobal(shExports))) { + if (hasPathFallback(moduleName)) { + return; + } else { + return onError(makeError('nodefine', + 'No define call for ' + moduleName, + null, + [moduleName])); + } + } else { + //A script that does not call define(), so just simulate + //the call for it. + callGetModule([moduleName, (shim.deps || []), shim.exportsFn]); + } + } + + checkLoaded(); + }, + + /** + * Converts a module name to a file path. Supports cases where + * moduleName may actually be just an URL. + * Note that it **does not** call normalize on the moduleName, + * it is assumed to have already been normalized. This is an + * internal API, not a public one. Use toUrl for the public API. + */ + nameToUrl: function (moduleName, ext, skipExt) { + var paths, syms, i, parentModule, url, + parentPath, bundleId, + pkgMain = getOwn(config.pkgs, moduleName); + + if (pkgMain) { + moduleName = pkgMain; + } + + bundleId = getOwn(bundlesMap, moduleName); + + if (bundleId) { + return context.nameToUrl(bundleId, ext, skipExt); + } + + //If a colon is in the URL, it indicates a protocol is used and it is just + //an URL to a file, or if it starts with a slash, contains a query arg (i.e. ?) + //or ends with .js, then assume the user meant to use an url and not a module id. + //The slash is important for protocol-less URLs as well as full paths. + if (req.jsExtRegExp.test(moduleName)) { + //Just a plain path, not module name lookup, so just return it. + //Add extension if it is included. This is a bit wonky, only non-.js things pass + //an extension, this method probably needs to be reworked. + url = moduleName + (ext || ''); + } else { + //A module that needs to be converted to a path. + paths = config.paths; + + syms = moduleName.split('/'); + //For each module name segment, see if there is a path + //registered for it. Start with most specific name + //and work up from it. + for (i = syms.length; i > 0; i -= 1) { + parentModule = syms.slice(0, i).join('/'); + + parentPath = getOwn(paths, parentModule); + if (parentPath) { + //If an array, it means there are a few choices, + //Choose the one that is desired + if (isArray(parentPath)) { + parentPath = parentPath[0]; + } + syms.splice(0, i, parentPath); + break; + } + } + + //Join the path parts together, then figure out if baseUrl is needed. + url = syms.join('/'); + url += (ext || (/^data\:|\?/.test(url) || skipExt ? '' : '.js')); + url = (url.charAt(0) === '/' || url.match(/^[\w\+\.\-]+:/) ? '' : config.baseUrl) + url; + } + + return config.urlArgs ? url + + ((url.indexOf('?') === -1 ? '?' : '&') + + config.urlArgs) : url; + }, + + //Delegates to req.load. Broken out as a separate function to + //allow overriding in the optimizer. + load: function (id, url) { + req.load(context, id, url); + }, + + /** + * Executes a module callback function. Broken out as a separate function + * solely to allow the build system to sequence the files in the built + * layer in the right sequence. + * + * @private + */ + execCb: function (name, callback, args, exports) { + return callback.apply(exports, args); + }, + + /** + * callback for script loads, used to check status of loading. + * + * @param {Event} evt the event from the browser for the script + * that was loaded. + */ + onScriptLoad: function (evt) { + //Using currentTarget instead of target for Firefox 2.0's sake. Not + //all old browsers will be supported, but this one was easy enough + //to support and still makes sense. + if (evt.type === 'load' || + (readyRegExp.test((evt.currentTarget || evt.srcElement).readyState))) { + //Reset interactive script so a script node is not held onto for + //to long. + interactiveScript = null; + + //Pull out the name of the module and the context. + var data = getScriptData(evt); + context.completeLoad(data.id); + } + }, + + /** + * Callback for script errors. + */ + onScriptError: function (evt) { + var data = getScriptData(evt); + if (!hasPathFallback(data.id)) { + return onError(makeError('scripterror', 'Script error for: ' + data.id, evt, [data.id])); + } + } + }; + + context.require = context.makeRequire(); + return context; + } + + /** + * Main entry point. + * + * If the only argument to require is a string, then the module that + * is represented by that string is fetched for the appropriate context. + * + * If the first argument is an array, then it will be treated as an array + * of dependency string names to fetch. An optional function callback can + * be specified to execute when all of those dependencies are available. + * + * Make a local req variable to help Caja compliance (it assumes things + * on a require that are not standardized), and to give a short + * name for minification/local scope use. + */ + req = requirejs = function (deps, callback, errback, optional) { + + //Find the right context, use default + var context, config, + contextName = defContextName; + + // Determine if have config object in the call. + if (!isArray(deps) && typeof deps !== 'string') { + // deps is a config object + config = deps; + if (isArray(callback)) { + // Adjust args if there are dependencies + deps = callback; + callback = errback; + errback = optional; + } else { + deps = []; + } + } + + if (config && config.context) { + contextName = config.context; + } + + context = getOwn(contexts, contextName); + if (!context) { + context = contexts[contextName] = req.s.newContext(contextName); + } + + if (config) { + context.configure(config); + } + + return context.require(deps, callback, errback); + }; + + /** + * Support require.config() to make it easier to cooperate with other + * AMD loaders on globally agreed names. + */ + req.config = function (config) { + return req(config); + }; + + /** + * Execute something after the current tick + * of the event loop. Override for other envs + * that have a better solution than setTimeout. + * @param {Function} fn function to execute later. + */ + req.nextTick = typeof setTimeout !== 'undefined' ? function (fn) { + setTimeout(fn, 4); + } : function (fn) { fn(); }; + + /** + * Export require as a global, but only if it does not already exist. + */ + if (!require) { + require = req; + } + + req.version = version; + + //Used to filter out dependencies that are already paths. + req.jsExtRegExp = /^\/|:|\?|\.js$/; + req.isBrowser = isBrowser; + s = req.s = { + contexts: contexts, + newContext: newContext + }; + + //Create default context. + req({}); + + //Exports some context-sensitive methods on global require. + each([ + 'toUrl', + 'undef', + 'defined', + 'specified' + ], function (prop) { + //Reference from contexts instead of early binding to default context, + //so that during builds, the latest instance of the default context + //with its config gets used. + req[prop] = function () { + var ctx = contexts[defContextName]; + return ctx.require[prop].apply(ctx, arguments); + }; + }); + + if (isBrowser) { + head = s.head = document.getElementsByTagName('head')[0]; + //If BASE tag is in play, using appendChild is a problem for IE6. + //When that browser dies, this can be removed. Details in this jQuery bug: + //http://dev.jquery.com/ticket/2709 + baseElement = document.getElementsByTagName('base')[0]; + if (baseElement) { + head = s.head = baseElement.parentNode; + } + } + + /** + * Any errors that require explicitly generates will be passed to this + * function. Intercept/override it if you want custom error handling. + * @param {Error} err the error object. + */ + req.onError = defaultOnError; + + /** + * Creates the node for the load command. Only used in browser envs. + */ + req.createNode = function (config, moduleName, url) { + var node = config.xhtml ? + document.createElementNS('http://www.w3.org/1999/xhtml', 'html:script') : + document.createElement('script'); + node.type = config.scriptType || 'text/javascript'; + node.charset = 'utf-8'; + node.async = true; + return node; + }; + + /** + * Does the request to load a module for the browser case. + * Make this a separate function to allow other environments + * to override it. + * + * @param {Object} context the require context to find state. + * @param {String} moduleName the name of the module. + * @param {Object} url the URL to the module. + */ + req.load = function (context, moduleName, url) { + var config = (context && context.config) || {}, + node; + if (isBrowser) { + //In the browser so use a script tag + node = req.createNode(config, moduleName, url); + + node.setAttribute('data-requirecontext', context.contextName); + node.setAttribute('data-requiremodule', moduleName); + + //Set up load listener. Test attachEvent first because IE9 has + //a subtle issue in its addEventListener and script onload firings + //that do not match the behavior of all other browsers with + //addEventListener support, which fire the onload event for a + //script right after the script execution. See: + //https://connect.microsoft.com/IE/feedback/details/648057/script-onload-event-is-not-fired-immediately-after-script-execution + //UNFORTUNATELY Opera implements attachEvent but does not follow the script + //script execution mode. + if (node.attachEvent && + //Check if node.attachEvent is artificially added by custom script or + //natively supported by browser + //read https://github.com/jrburke/requirejs/issues/187 + //if we can NOT find [native code] then it must NOT natively supported. + //in IE8, node.attachEvent does not have toString() + //Note the test for "[native code" with no closing brace, see: + //https://github.com/jrburke/requirejs/issues/273 + !(node.attachEvent.toString && node.attachEvent.toString().indexOf('[native code') < 0) && + !isOpera) { + //Probably IE. IE (at least 6-8) do not fire + //script onload right after executing the script, so + //we cannot tie the anonymous define call to a name. + //However, IE reports the script as being in 'interactive' + //readyState at the time of the define call. + useInteractive = true; + + node.attachEvent('onreadystatechange', context.onScriptLoad); + //It would be great to add an error handler here to catch + //404s in IE9+. However, onreadystatechange will fire before + //the error handler, so that does not help. If addEventListener + //is used, then IE will fire error before load, but we cannot + //use that pathway given the connect.microsoft.com issue + //mentioned above about not doing the 'script execute, + //then fire the script load event listener before execute + //next script' that other browsers do. + //Best hope: IE10 fixes the issues, + //and then destroys all installs of IE 6-9. + //node.attachEvent('onerror', context.onScriptError); + } else { + node.addEventListener('load', context.onScriptLoad, false); + node.addEventListener('error', context.onScriptError, false); + } + node.src = url; + + //For some cache cases in IE 6-8, the script executes before the end + //of the appendChild execution, so to tie an anonymous define + //call to the module name (which is stored on the node), hold on + //to a reference to this node, but clear after the DOM insertion. + currentlyAddingScript = node; + if (baseElement) { + head.insertBefore(node, baseElement); + } else { + head.appendChild(node); + } + currentlyAddingScript = null; + + return node; + } else if (isWebWorker) { + try { + //In a web worker, use importScripts. This is not a very + //efficient use of importScripts, importScripts will block until + //its script is downloaded and evaluated. However, if web workers + //are in play, the expectation that a build has been done so that + //only one script needs to be loaded anyway. This may need to be + //reevaluated if other use cases become common. + importScripts(url); + + //Account for anonymous modules + context.completeLoad(moduleName); + } catch (e) { + context.onError(makeError('importscripts', + 'importScripts failed for ' + + moduleName + ' at ' + url, + e, + [moduleName])); + } + } + }; + + function getInteractiveScript() { + if (interactiveScript && interactiveScript.readyState === 'interactive') { + return interactiveScript; + } + + eachReverse(scripts(), function (script) { + if (script.readyState === 'interactive') { + return (interactiveScript = script); + } + }); + return interactiveScript; + } + + //Look for a data-main script attribute, which could also adjust the baseUrl. + if (isBrowser && !cfg.skipDataMain) { + //Figure out baseUrl. Get it from the script tag with require.js in it. + eachReverse(scripts(), function (script) { + //Set the 'head' where we can append children by + //using the script's parent. + if (!head) { + head = script.parentNode; + } + + //Look for a data-main attribute to set main script for the page + //to load. If it is there, the path to data main becomes the + //baseUrl, if it is not already set. + dataMain = script.getAttribute('data-main'); + if (dataMain) { + //Preserve dataMain in case it is a path (i.e. contains '?') + mainScript = dataMain; + + //Set final baseUrl if there is not already an explicit one. + if (!cfg.baseUrl) { + //Pull off the directory of data-main for use as the + //baseUrl. + src = mainScript.split('/'); + mainScript = src.pop(); + subPath = src.length ? src.join('/') + '/' : './'; + + cfg.baseUrl = subPath; + } + + //Strip off any trailing .js since mainScript is now + //like a module name. + mainScript = mainScript.replace(jsSuffixRegExp, ''); + + //If mainScript is still a path, fall back to dataMain + if (req.jsExtRegExp.test(mainScript)) { + mainScript = dataMain; + } + + //Put the data-main script in the files to load. + cfg.deps = cfg.deps ? cfg.deps.concat(mainScript) : [mainScript]; + + return true; + } + }); + } + + /** + * The function that handles definitions of modules. Differs from + * require() in that a string for the module should be the first argument, + * and the function to execute after dependencies are loaded should + * return a value to define the module corresponding to the first argument's + * name. + */ + define = function (name, deps, callback) { + var node, context; + + //Allow for anonymous modules + if (typeof name !== 'string') { + //Adjust args appropriately + callback = deps; + deps = name; + name = null; + } + + //This module may not have dependencies + if (!isArray(deps)) { + callback = deps; + deps = null; + } + + //If no name, and callback is a function, then figure out if it a + //CommonJS thing with dependencies. + if (!deps && isFunction(callback)) { + deps = []; + //Remove comments from the callback string, + //look for require calls, and pull them into the dependencies, + //but only if there are function args. + if (callback.length) { + callback + .toString() + .replace(commentRegExp, '') + .replace(cjsRequireRegExp, function (match, dep) { + deps.push(dep); + }); + + //May be a CommonJS thing even without require calls, but still + //could use exports, and module. Avoid doing exports and module + //work though if it just needs require. + //REQUIRES the function to expect the CommonJS variables in the + //order listed below. + deps = (callback.length === 1 ? ['require'] : ['require', 'exports', 'module']).concat(deps); + } + } + + //If in IE 6-8 and hit an anonymous define() call, do the interactive + //work. + if (useInteractive) { + node = currentlyAddingScript || getInteractiveScript(); + if (node) { + if (!name) { + name = node.getAttribute('data-requiremodule'); + } + context = contexts[node.getAttribute('data-requirecontext')]; + } + } + + //Always save off evaluating the def call until the script onload handler. + //This allows multiple modules to be in a file without prematurely + //tracing dependencies, and allows for anonymous module support, + //where the module name is not known until the script onload event + //occurs. If no context, use the global queue, and get it processed + //in the onscript load callback. + (context ? context.defQueue : globalDefQueue).push([name, deps, callback]); + }; + + define.amd = { + jQuery: true + }; + + + /** + * Executes the text. Normally just uses eval, but can be modified + * to use a better, environment-specific call. Only used for transpiling + * loader plugins, not for plain JS modules. + * @param {String} text the text to execute/evaluate. + */ + req.exec = function (text) { + /*jslint evil: true */ + return eval(text); + }; + + //Set up with config info. + req(cfg); +}(this)); diff --git a/node_modules/ace/demo/kitchen-sink/styles.css b/node_modules/ace/demo/kitchen-sink/styles.css new file mode 100644 index 00000000..3f46f701 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/styles.css @@ -0,0 +1,55 @@ +html { + height: 100%; + width: 100%; + overflow: hidden; +} + +body { + overflow: hidden; + margin: 0; + padding: 0; + height: 100%; + width: 100%; + font-family: Arial, Helvetica, sans-serif, Tahoma, Verdana, sans-serif; + font-size: 12px; + background: rgb(14, 98, 165); + color: white; +} + +#c9-logo, #ace-logo { + padding: 0; + border: none; +} + +#editor-container { + position: absolute; + top: 0px; + left: 280px; + bottom: 0px; + right: 0px; + background: white; +} + +#controls { + padding: 5px; +} + +#controls td { + text-align: right; +} + +#controls td + td { + text-align: left; +} +.ace_status-indicator { + color: gray; + position: absolute; + right: 0; + border-left: 1px solid; +} + +/* .ace_text-input { + z-index: 10!important; + opacity: 1!important; + background: rgb(84, 0, 255)!important; +}*/ diff --git a/node_modules/ace/demo/kitchen-sink/token_tooltip.js b/node_modules/ace/demo/kitchen-sink/token_tooltip.js new file mode 100644 index 00000000..9e607f69 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/token_tooltip.js @@ -0,0 +1,156 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var dom = require("ace/lib/dom"); +var oop = require("ace/lib/oop"); +var event = require("ace/lib/event"); +var Range = require("ace/range").Range; +var Tooltip = require("ace/tooltip").Tooltip; + +function TokenTooltip (editor) { + if (editor.tokenTooltip) + return; + Tooltip.call(this, editor.container); + editor.tokenTooltip = this; + this.editor = editor; + + this.update = this.update.bind(this); + this.onMouseMove = this.onMouseMove.bind(this); + this.onMouseOut = this.onMouseOut.bind(this); + event.addListener(editor.renderer.scroller, "mousemove", this.onMouseMove); + event.addListener(editor.renderer.content, "mouseout", this.onMouseOut); +} + +oop.inherits(TokenTooltip, Tooltip); + +(function(){ + this.token = {}; + this.range = new Range(); + + this.update = function() { + this.$timer = null; + + var r = this.editor.renderer; + if (this.lastT - (r.timeStamp || 0) > 1000) { + r.rect = null; + r.timeStamp = this.lastT; + this.maxHeight = window.innerHeight; + this.maxWidth = window.innerWidth; + } + + var canvasPos = r.rect || (r.rect = r.scroller.getBoundingClientRect()); + var offset = (this.x + r.scrollLeft - canvasPos.left - r.$padding) / r.characterWidth; + var row = Math.floor((this.y + r.scrollTop - canvasPos.top) / r.lineHeight); + var col = Math.round(offset); + + var screenPos = {row: row, column: col, side: offset - col > 0 ? 1 : -1}; + var session = this.editor.session; + var docPos = session.screenToDocumentPosition(screenPos.row, screenPos.column); + var token = session.getTokenAt(docPos.row, docPos.column); + + if (!token && !session.getLine(docPos.row)) { + token = { + type: "", + value: "", + state: session.bgTokenizer.getState(0) + }; + } + if (!token) { + session.removeMarker(this.marker); + this.hide(); + return; + } + + var tokenText = token.type; + if (token.state) + tokenText += "|" + token.state; + if (token.merge) + tokenText += "\n merge"; + if (token.stateTransitions) + tokenText += "\n " + token.stateTransitions.join("\n "); + + if (this.tokenText != tokenText) { + this.setText(tokenText); + this.width = this.getWidth(); + this.height = this.getHeight(); + this.tokenText = tokenText; + } + + this.show(null, this.x, this.y); + + this.token = token; + session.removeMarker(this.marker); + this.range = new Range(docPos.row, token.start, docPos.row, token.start + token.value.length); + this.marker = session.addMarker(this.range, "ace_bracket", "text"); + }; + + this.onMouseMove = function(e) { + this.x = e.clientX; + this.y = e.clientY; + if (this.isOpen) { + this.lastT = e.timeStamp; + this.setPosition(this.x, this.y); + } + if (!this.$timer) + this.$timer = setTimeout(this.update, 100); + }; + + this.onMouseOut = function(e) { + if (e && e.currentTarget.contains(e.relatedTarget)) + return; + this.hide(); + this.editor.session.removeMarker(this.marker); + this.$timer = clearTimeout(this.$timer); + }; + + this.setPosition = function(x, y) { + if (x + 10 + this.width > this.maxWidth) + x = window.innerWidth - this.width - 10; + if (y > window.innerHeight * 0.75 || y + 20 + this.height > this.maxHeight) + y = y - this.height - 30; + + Tooltip.prototype.setPosition.call(this, x + 10, y + 20); + }; + + this.destroy = function() { + this.onMouseOut(); + event.removeListener(this.editor.renderer.scroller, "mousemove", this.onMouseMove); + event.removeListener(this.editor.renderer.content, "mouseout", this.onMouseOut); + delete this.editor.tokenTooltip; + }; + +}).call(TokenTooltip.prototype); + +exports.TokenTooltip = TokenTooltip; + +}); diff --git a/node_modules/ace/demo/kitchen-sink/util.js b/node_modules/ace/demo/kitchen-sink/util.js new file mode 100644 index 00000000..c4b74f38 --- /dev/null +++ b/node_modules/ace/demo/kitchen-sink/util.js @@ -0,0 +1,235 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var dom = require("ace/lib/dom"); +var event = require("ace/lib/event"); + +var EditSession = require("ace/edit_session").EditSession; +var UndoManager = require("ace/undomanager").UndoManager; +var Renderer = require("ace/virtual_renderer").VirtualRenderer; +var Editor = require("ace/editor").Editor; +var MultiSelect = require("ace/multi_select").MultiSelect; + +exports.createEditor = function(el) { + return new Editor(new Renderer(el)); +}; + +exports.createSplitEditor = function(el) { + if (typeof(el) == "string") + el = document.getElementById(el); + + var e0 = document.createElement("div"); + var s = document.createElement("splitter"); + var e1 = document.createElement("div"); + el.appendChild(e0); + el.appendChild(e1); + el.appendChild(s); + e0.style.position = e1.style.position = s.style.position = "absolute"; + el.style.position = "relative"; + var split = {$container: el}; + + split.editor0 = split[0] = new Editor(new Renderer(e0)); + split.editor1 = split[1] = new Editor(new Renderer(e1)); + split.splitter = s; + + s.ratio = 0.5; + + split.resize = function resize(){ + var height = el.parentNode.clientHeight - el.offsetTop; + var total = el.clientWidth; + var w1 = total * s.ratio; + var w2 = total * (1- s.ratio); + s.style.left = w1 - 1 + "px"; + s.style.height = el.style.height = height + "px"; + + var st0 = split[0].container.style; + var st1 = split[1].container.style; + st0.width = w1 + "px"; + st1.width = w2 + "px"; + st0.left = 0 + "px"; + st1.left = w1 + "px"; + + st0.top = st1.top = "0px"; + st0.height = st1.height = height + "px"; + + split[0].resize(); + split[1].resize(); + }; + + split.onMouseDown = function(e) { + var rect = el.getBoundingClientRect(); + var x = e.clientX; + var y = e.clientY; + + var button = e.button; + if (button !== 0) { + return; + } + + var onMouseMove = function(e) { + x = e.clientX; + y = e.clientY; + }; + var onResizeEnd = function(e) { + clearInterval(timerId); + }; + + var onResizeInterval = function() { + s.ratio = (x - rect.left) / rect.width; + split.resize(); + }; + + event.capture(s, onMouseMove, onResizeEnd); + var timerId = setInterval(onResizeInterval, 40); + + return e.preventDefault(); + }; + + + + event.addListener(s, "mousedown", split.onMouseDown); + event.addListener(window, "resize", split.resize); + split.resize(); + return split; +}; + +/***************************/ +exports.stripLeadingComments = function(str) { + if(str.slice(0,2)=='/*') { + var j = str.indexOf('*/')+2; + str = str.substr(j); + } + return str.trim() + "\n"; +}; + +/***************************/ +exports.saveOption = function(el, val) { + if (!el.onchange && !el.onclick) + return; + + if ("checked" in el) { + if (val !== undefined) + el.checked = val; + + localStorage && localStorage.setItem(el.id, el.checked ? 1 : 0); + } + else { + if (val !== undefined) + el.value = val; + + localStorage && localStorage.setItem(el.id, el.value); + } +}; + +exports.bindCheckbox = function(id, callback, noInit) { + if (typeof id == "string") + var el = document.getElementById(id); + else { + var el = id; + id = el.id; + } + var el = document.getElementById(id); + if (localStorage && localStorage.getItem(id)) + el.checked = localStorage.getItem(id) == "1"; + + var onCheck = function() { + callback(!!el.checked); + exports.saveOption(el); + }; + el.onclick = onCheck; + noInit || onCheck(); + return el; +}; + +exports.bindDropdown = function(id, callback, noInit) { + if (typeof id == "string") + var el = document.getElementById(id); + else { + var el = id; + id = el.id; + } + if (localStorage && localStorage.getItem(id)) + el.value = localStorage.getItem(id); + + var onChange = function() { + callback(el.value); + exports.saveOption(el); + }; + + el.onchange = onChange; + noInit || onChange(); +}; + +exports.fillDropdown = function(el, values) { + if (typeof el == "string") + el = document.getElementById(el); + + dropdown(values).forEach(function(e) { + el.appendChild(e); + }); +}; + +function elt(tag, attributes, content) { + var el = dom.createElement(tag); + if (typeof content == "string") { + el.appendChild(document.createTextNode(content)); + } else if (content) { + content.forEach(function(ch) { + el.appendChild(ch); + }); + } + + for (var i in attributes) + el.setAttribute(i, attributes[i]); + return el; +} + +function optgroup(values) { + return values.map(function(item) { + if (typeof item == "string") + item = {name: item, caption: item}; + return elt("option", {value: item.value || item.name}, item.caption || item.desc); + }); +} + +function dropdown(values) { + if (Array.isArray(values)) + return optgroup(values); + + return Object.keys(values).map(function(i) { + return elt("optgroup", {"label": i}, optgroup(values[i])); + }); +} + + +}); diff --git a/node_modules/ace/demo/modelist.html b/node_modules/ace/demo/modelist.html new file mode 100644 index 00000000..9b4b6039 --- /dev/null +++ b/node_modules/ace/demo/modelist.html @@ -0,0 +1,51 @@ + + + + + + ACE Editor Modelist Demo + + + + +
    
    +    
    +
    +
    +
    +
    +
    +
    diff --git a/node_modules/ace/demo/r.js/build.js b/node_modules/ace/demo/r.js/build.js
    new file mode 100644
    index 00000000..028d2234
    --- /dev/null
    +++ b/node_modules/ace/demo/r.js/build.js
    @@ -0,0 +1,20 @@
    +({
    +    optimize: "none",
    +    preserveLicenseComments: false,
    +    name: "node_modules/almond/almond",
    +    baseUrl: "../../",
    +    paths: {
    +        ace : "lib/ace",
    +        demo: "demo/kitchen-sink"        
    +    },
    +    packages: [
    +    ],
    +    include: [
    +        "ace/ace"
    +    ],
    +    exclude: [
    +    ],
    +    out: "./packed.js",
    +    useStrict: true,
    +    wrap: false
    +})
    \ No newline at end of file
    diff --git a/node_modules/ace/demo/r.js/editor.html b/node_modules/ace/demo/r.js/editor.html
    new file mode 100644
    index 00000000..9f7a47bf
    --- /dev/null
    +++ b/node_modules/ace/demo/r.js/editor.html
    @@ -0,0 +1,36 @@
    +
    +
    +
    +
    +    Editor
    +        
    +
    +
    +    
    +
    +        
    + demo showing Ace usage with r.js: + + install r.js and almond + and run `r.js -o demo/r.js/build.js` + + note that you also need ace/build/src to lazy load modes and themes + require("ace/config").set("basePath", "../../build/src"); + require("ace/config").set("packaged", true); +
    +
    + + + + + diff --git a/node_modules/ace/demo/requirejs+build.html b/node_modules/ace/demo/requirejs+build.html new file mode 100644 index 00000000..72d50dbc --- /dev/null +++ b/node_modules/ace/demo/requirejs+build.html @@ -0,0 +1,49 @@ + + + + + + Editor + + + + +
    function foo(items) {
    +    var i;
    +    for (i = 0; i < items.length; i++) {
    +        alert("Ace Rocks " + items[i]);
    +    }
    +}
    + + + + + + diff --git a/node_modules/ace/demo/scrollable-page.html b/node_modules/ace/demo/scrollable-page.html new file mode 100644 index 00000000..ef725c4a --- /dev/null +++ b/node_modules/ace/demo/scrollable-page.html @@ -0,0 +1,155 @@ + + + + + + Editor + + + +
    + + scroll down ⇓ + +
    +
    function foo(items) {
    +    var i;
    +    for (i = 0; i < items.length; i++) {
    +        alert("Ace Rocks " + items[i]);
    +    }
    +
    +}
    +
    +
    + press F11 to switch to fullscreen mode +
    + + + + + +
    + + + + + + diff --git a/node_modules/ace/demo/settings_menu.html b/node_modules/ace/demo/settings_menu.html new file mode 100644 index 00000000..9fb82a43 --- /dev/null +++ b/node_modules/ace/demo/settings_menu.html @@ -0,0 +1,49 @@ + + + + + + Editor + + + + +
    
    +    
    +
    +
    +
    +
    +
    +
    diff --git a/node_modules/ace/demo/show_own_source.js b/node_modules/ace/demo/show_own_source.js
    new file mode 100644
    index 00000000..a9e0ec69
    --- /dev/null
    +++ b/node_modules/ace/demo/show_own_source.js
    @@ -0,0 +1,16 @@
    +if (typeof ace == "undefined" && typeof require == "undefined") {
    +    document.body.innerHTML = "

    couldn't find ace.js file,
    " + + "to build it run node Makefile.dryice.js full" +} else if (typeof ace == "undefined" && typeof require != "undefined") { + require(["ace/ace"], setValue) +} else { + require = ace.require; + setValue() +} + +function setValue() { + require("ace/lib/net").get(document.baseURI, function(t){ + var el = document.getElementById("editor"); + el.env.editor.setValue(t, 1); + }) +} \ No newline at end of file diff --git a/node_modules/ace/demo/static-highlighter.html b/node_modules/ace/demo/static-highlighter.html new file mode 100644 index 00000000..39546541 --- /dev/null +++ b/node_modules/ace/demo/static-highlighter.html @@ -0,0 +1,64 @@ + + + + + Static Code highlighter using Ace + + + + + +

    Client Side Syntax Highlighting

    + +

    Syntax highlighting using Ace language modes and themes.

    + +
    +.code { + width: 50%; + + position: relative; + white-space: pre-wrap; +} + +
    + +
    +function wobble (flam) {
    +    return flam.wobbled = true;
    +}
    +
    +
    + + + + + + diff --git a/node_modules/ace/demo/static-highlighter/client.html b/node_modules/ace/demo/static-highlighter/client.html new file mode 100644 index 00000000..93d20909 --- /dev/null +++ b/node_modules/ace/demo/static-highlighter/client.html @@ -0,0 +1,47 @@ + + + + + + Static Code highlighter using Ace + + + + +

    Client Side Syntax Highlighting

    + +

    Syntax highlighting using Ace language modes and themes.

    + +
    + + + + + + diff --git a/node_modules/ace/demo/static-highlighter/server.js b/node_modules/ace/demo/static-highlighter/server.js new file mode 100644 index 00000000..d1d6adbb --- /dev/null +++ b/node_modules/ace/demo/static-highlighter/server.js @@ -0,0 +1,37 @@ +/** + * Simple node.js server, which generates the synax highlighted version of itself + * using the Ace modes and themes on the server and serving a static web page. + */ +// $' +// include ace search path and modules +require("amd-loader"); + +// load jsdom, which is required by Ace +require("../../lib/ace/test/mockdom"); + +var http = require("http"); +var fs = require("fs"); + +// load the highlighter and the desired mode and theme +var highlighter = require("../../lib/ace/ext/static_highlight"); +var JavaScriptMode = require("../../lib/ace/mode/javascript").Mode; +var theme = require("../../lib/ace/theme/twilight"); + +var port = process.env.PORT || 2222; + +http.createServer(function(req, res) { + res.writeHead(200, {"Content-Type": "text/html; charset=utf-8"}); + fs.readFile(__filename, "utf8", function(err, data) { + var highlighted = highlighter.render(data, new JavaScriptMode(), theme); + res.end( + '\n' + + '\n' + + highlighted.html + + '' + ); + }); +}).listen(port); + +console.log("Listening on port " + port); \ No newline at end of file diff --git a/node_modules/ace/demo/statusbar.html b/node_modules/ace/demo/statusbar.html new file mode 100644 index 00000000..d38bfcb9 --- /dev/null +++ b/node_modules/ace/demo/statusbar.html @@ -0,0 +1,61 @@ + + + + + + ACE Editor StatusBar Demo + + + + +
    
    +
    ace rocks!
    + + + + + + + diff --git a/node_modules/ace/doc/Contributor_License_Agreement-v2.pdf b/node_modules/ace/doc/Contributor_License_Agreement-v2.pdf new file mode 100644 index 0000000000000000000000000000000000000000..1c4baa870a07e67cffbbc63ac897c57a0d1ca44b GIT binary patch literal 89761 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

    M;`=Vk&NS|}T3~YZ}xH5?<?dH?gt0B?qUk6# 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


    1wW7;3||sc1?0IL%t=DIFzp@>c@>ItW*nzoru6P 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 WIsu2*UmGv%=43&lq!g7GL;8Q((E}&| literal 0 HcmV?d00001 diff --git a/node_modules/ace/doc/Corporate_Contributor_License_Agreement-v2.pdf b/node_modules/ace/doc/Corporate_Contributor_License_Agreement-v2.pdf new file mode 100644 index 0000000000000000000000000000000000000000..dbeaf37cc5dea9f57f673a748c97486ec62fd870 GIT binary patch literal 376398 zcmafZV|1p=()Pr*Z5vN)+qP}nwr$(CCeB1ptci`uB$;sX&E9A4bKZa7pS$nXy}IkF zu3ptubv1>Om;?h0BO5Hm*zx`GW#!MJg|Ts1c4B5?M-v-ZK0ab5Idca~H!EVmpDq<* zCJAdhH*=Rit(~!(xtO`BqnSCefB>wkn~S-zJ**cB%>eBHU4h^4xtYenm)pV5!(V|6 z2EVf{KssqSLik5oUthNlrX=??zW%&D|N2_}w5r(7PG&i`x}9-1P}xp5GHMI1=c9?XwuIK;y}7Gf2aD;qir?J` z4Yn!T-cB)%=iL6CL{fXMOD8XWk5C5E@!aI#LT_io4G+ z?v*^>dYj*S`~K>g38_a$_bl%4d4BvEwTVFyf(37;e4jiD7peo37(nKI^sX71HnuCl zSL=GP(GhvC1fYVSYih=gnb^9Gt=InCU%=e*@2+KeVi-4_f8HiitQ*|9nrXOYwX>_3 zFsG;T^?X21}5U2d~k(>;#0*8lt)lKKwu*dJF@H6 z(;qDyAXUZ31mSjIT@}Kwr%R10uEfT;e8l*WjP?ehj^F+k%4FL=Z4#f`s=;O(^qEr{ zoXBeOAn!KW7D}0%B&4og8s@8p{YgeL* zcj5`Z<_Y5L1*;#j}}qJdUQ$GA7w2E4vb`R;lbR--y zS6a}ON{IJ=1l{2tD=l|%C(?)xcS|t1+ppCYpkl=1mB?J$OA#8yMnokb!AFHQSJ%#C zA1L8;?sB`7BW3L^a(D70)#CN7*ka>da=Ac?bWWfaIiAcgNTCTbf6( zh)ObbPGyvm4MVR8OA%7sA9U+A=9O)su-H`Xf_b_TwiRt8StHvXxb5qgB97Z47_pRt>?&1DP$`lh`kE;)STzmZ3@`js3L6L&N~cig z#cQ9>Hzxu+qhD$cVJ9AbJvjJZ;+*TFFAJ)D0_#{ZkG5@0Q z01W*?7;yIm)B2)-HsZB|WrA9!UNx6l!d00ks?^3rKq?F4I9Ts+)3g!TY!dER45GQd7%3G%ZZ}XsP zn#D3=Xt7REB~MJx`uc@(2L_c8&6l7r?&{xKW4sDc7+?{886VUggUdE`bbMh}7*-7L z2($|=(p#Qn`JIH^j|kgHIMLb*UN{aiK_H?B2JeJ22xIXK(!*rWEIRz91({hr)8BW+J9iJ27fMb&rWGS z#b0InBWROVvjQ?mjXWk?jpCL&w#WcIP&DbRT+sYRs<8WwS%MF7xvK>n4l@NsXkwvn z2Rb4t63cDXy&V$+BzXdU^j z_Mup)#}Uk3B9N`{b}_s2$IWU4?f#(oX(q=-Qtl$tu~sG3wzCHNsQ_FLSD*g*C!za@k21mSK1}TjVSX0C}1Pb^g7LGZx74S~BL3 z{tCgfU-k;~a0J;}m+BCUxvA>z_*iXc=CMn%8AJNS-=##1TFiK}^S zXaOMS%_qD{S|~+cLnXN?~9 zCC<6%LxpoaiNxE_)51>$JgBL>Y8xp6jaL~Eu;-!gIyOwdBXxJRt2}1OF(tWS;%R`% zt?6hF@#VL~27bXlO5$6(b#m`H1V}S6TONCM6weY^Ztj;bXuV>Pz6ty*oXDmQWgBan zCYHi``gF*ez;<%s-c z&REb{h7mUwlDd(eNC`2NJiK88Q}Noi>fmw^{Hfe>2tMr!__jRiyDsS+3B9&%L^p^0N%p+;F#g z%HfP$w%LAMT)#!if;Dxfr(^cST)4&o9#x@eTkA2nzvu1w&H2r+35>-+m|LWIYyLzp zcxUOO!jx(G4Sr=-=~jCf^pSz9*I)*NDwwk5K3Q|F0)UH|8ZLhx42H;SIm#Qzreox{ zftbO-87bS5BtYv-3kict1J57G8tJ;W-B_lN_!&?PNaP1cw{&{!`I{Az@j4 z%VrIIE~yVE9)t7KXLpx&tbNOL0E_I+4N|+4Cf7lA5VXTwv&wS?Dg z1!WEOo7BSlSyQ$RG)vR0g&m3|#$Xc$u;q&2WYLBvMCQ~>& zj|DC}<^cptY*i{pa=n$E4!d#RT`Y#kzUK$D7WLWN!}+qRdBKnJfcJY%9na^BW$zcF z>6n#H;Ah(YF}Ys!Da3)}69p9i&*`7$7Qe!|Q?e69n(V9%FrX0O2-f{;`$suTqk0%3 zD-S3=Xj=I0CqLGg(4`XnwpCFGKj-j+^q5jkX>a7-7@Vz9v&=W2VYt7=6|(Cho}wmQ zfcQ6J-P!QnoMnA=aiZjV?`2mtu+@u`r-TT)=gBkR$O8L{Z)(5MJfTJIV#X2he#W|? zTVZ+F_!zg4s%FZP*PY}Dk?mYwuf9!z4jEja3F$;ljV@x=I#iH$vBfsl<)8C0HZX^x zW%n58Oq}qOR4GLNI$JYgyl~FpBuk>BpDG7(?0xiE1e>t7T1dzlcghwEj#N?nDyN_>C$m78mZF4?JkI2S^iUPb@)Bq0^V_c?%X!28dyYz#&6cL1SN6 zNmsOWB?2{$yS850W)uZ?RfJB0*AF@Ese-nEkfh>f#O2H5iyG!{!qq=VOnnc3aI)vH z`gyofq_IMudd>ad(27=SN=r_JusK7Ltt~ZZ&L4xvRyD%x&GhB7F6+jbvd@BXRAJ~y z_&A5yoa&>$krOq()_$hKxiCdOp1gA3%Yi&wfadEIT0HrMlgyFi4)J|B1%Zd$^aswz z95Gz+&+$-*Q%w}#hhG-p^FBb2uAUE{RxL#Tb+e4B&=0i4w(3}djcVl>rxm|;^*3I~6 z!4!jVZl~HAR}S+i^c>=?y{!kX-|dq!_v#e(WT8EY9y~X6xtC$>vcORIdVbe+80+#x z=dOwDnQ*DxQGCDXM9@e7%J)?gWy1*Gkq@5i$Hg;tK&z>QR_O>?P6h?f{QgZ9!jDza%=LrSKskjMzq_Hst57jj_9E1(j~09`nJoWvgEuV7S?gm5K%(r z(+LUPlN!XihO>|;n!P-n1qF6|4lJkyLlj+9=v1VBq0IjNYD{)kf&D%^rDdoGR1oK( zP9jRCtv|W{odZ7)uk?txRDr&WUC-t!{#FSd5uLz9C=-X<;`2 zlaG)AOPyJu(Kq3}+!H1=D5J|74zVAWaYij5zeGibFrB$&z$*4t#~dGmZLSJ*I>jp_ z>$rQnBxx}n3R3yr2yhIp+o16Vtj(#iYs)KzWp%}81F_wlKzU}L0=3RF9LlGGcM%&x zZl6S!W|`8&CXVDOjHg<>;W5O4nP~zsel>brOnF$OO*>PDm%)!euFNtUk+Q@~{9eR8 zgR)4x2Tr^S{F*E?aqBRaWTtAVBz<=kOTq_8cwHzcdL>ZI4S{h;=`NZ&smAecsU4EK zM1CHVP(ckL@3>I4`AAsu?TPdB}-`9hGsM#qsU#n-&=H(f1=goMeoE6gg%-SIn*v%J?Q_ zGF_uD0t7EGlMhRA`RGL?6;N^FID{oHrCogm2*I$E=&`3Rw)KLdntT7IL>F zllmx8lEQIK;ATb~?J=lm7j`MD9QlxsSKzrfDTl4mWXpiIVeGc-nsZI0VHZ@DN!6pC zVvrZ5MCD8^UoSk}(qZ)r*`eV)o*x-@tf#3;3PDg{3%_!t?}LC`7UHl*VQ`h#_F##? z{R7l$v>Bk+hRtQp%O)Nk3&X&REjlvnPvqddm-;TO#u6`>ynT<-WiMJ(>ibfiTz?kw zf(Yw$XthBASIxY!5S7xK@W>)|eS`&wQq_~F&7-bfl?M35T(lLY-Pkg8|7O=p5Ydpi zxn0!M=h)5YqE_aZeOvu|JJYM8TiiOq^d|iLcZtIcv9b;xEzl^jk`KfmjkZ2;s`23E zIX`%@tm~20k|U&mWJ^FLDO7nDdZhHRyOenPGC?4o7G`+^Skn=}I?;xwk$baDMpQ5X zmZ*fI5+Q?x7{ZSuT0aFdiy)I-dJ7fs3uQ~2tj#@sY}okw_!Ibd?{8j_9d*ADh&b*> z`=>YBG6cQjzDIS^?atpzWk<>o!N)6QM4E_6&I)kpIxX3x0D|dbb(L{C*{3H=zXucX z2D?7mlDIerO{UL%kgmihE~gOdCv|O;g^((QD0kq$mPk&P=IzhUFszOU4ldIuu1tW8 zKoi=)(A@5!h+8Vs`3F%c|NGwbi-xwjboL)NG8J$SE{ccONg#6r&f*EDZF1! z_1aY--Pk6~FX_KSE>h9gmzA2NK_JZcz-Bs?9?O&zr-2xWg`y${bNb7kR=QVdRCPH(Saam(*GlQCBX%#p{Kv z{#L1L1sd;wq*QYPmkF`v!XqcD3k?>0WF>t4`LG^se{E77mz|;MCEriGh#Q@ZVzmCo zmK1-Bbf$c4g1W`o7f6jpw7B_iT34mRafR0@?wQjtk@TsINj%t=pmoLbMo#T*%v<*xRKd%D`rfC$*;+<>- z;-*M^C$T9(X?PMTI&5FllyitWy11sUM>A4cBch!M z?Sv+<{hDx;q@NUm_G~MrVeM&Ei7zQ#*)d{HekdvS8QH4OTmmg`r6?=gMU|hF)vPVf zaZf3gw`n&lj{K+#6reTJC5~4)^i}as7{ zO$~I{+0GsG^292x{{tczK~YTq*~I2oyy5{luuQy2~r`w*OKoT@Hr_&}== zGGwQuA>MP8aD~HIr)0!3vIv?K)c1kHgmGi8smo->AU65UijxeE1XO1m^;39-J9tCo zYuXU_t?^F2p)kmI==~bb;8W7R$+BA3l}KdB3mmf8HDv|BRU_Ggr3ItXSaJsqP9e3Y zcU|2&9)3Wbsk5`6__S}^yWLZ0wa)DV+!plM^AwVpEE=4HbbK=idu)`2n-;~|zAL5HVv*Dm5={woE5%1ANgP1QB z(H+Q1C3NLrk$o>nL_(>|Yf7PVzM;JnM=$B>d5H3ilN8**IrAEH89=EfQwhi5PUP9jvFgm*oplCXcUFc2H=n!dKkQ4vO1)*cj;|{3 z1&OJmVYDX^)KSrFUdMeudzU;+865|*!%zCzJm6^7SGI%?)z`dZpR+XnY!G7@l=14M zZk)=j9`MOE!Nzyw(CPWO2i4p<5hVmltv;<1NnTLrVf~v|Zg4zlEQ!7xp%#QJ5+p9$ zMZadRC7x0a5v{?ed8w6`kKA_&7Oj{uCK;Hs-icEQ(=Q9d|3$KHud4r zZSWYmVTcX$dN6_-BA3n-8m>`guta)hYFXk_GbLB!q`H6rbMcylXb5{Tt*R`aXA*duMO01?w#>f-k;~@SwE=c zQ`wEC-`pqe}q|vg&*nWmHV%6>=b5jx z5`?252;8@g{_KIiAgMcb0k^!1X6b_ORyU!Z6Tn2ICb_Lh!SNEu>`-o>%SZ_=ISgZ7 zM*vT4NBljf?D0=6(U-w5^@e$4t78a3)zDRmck`PLKZQBJr7KOjVhSE zaCwF~i*wLE$eX|mAUa*pYf^J^;gfbj7LJyep7B5}VjQ?BJFAN$8K#jsq|b)Y`z|Hw zpmjpfFp|W66Ddn9NSo4@q)&LP0tHgwhA}fEv7)pOqjU77kG>~o(4ECE{qky0V6ri| z>B|!j*dRFA3ha{JXy*c_ohZ9F2UJurPw#;hqEnD~rlV(P2D~yp#K|y!iWKy7O4D`G zCQi0_u+wII{vO|z;@8w=W5II#5`mQB@3NfbjMIq+O^8ISvDUPF26xv@27Ecr(TDVy zy0G3StnWxyE8)~6G)O)->O@^>%m!ETV;4Ss)12)ME!4cf^Ahd(5Pws{EcFgyAfeet zo=BUTD`u8!_5rsl519RKMMb#!q1Gww?K7peV+ z!In2Svo;oS^di<}{?oz1!b;4^&8iRkhs6Fz&R_HXCBKzi98Fct-H3Jn2osYaW>Pcv zawBGvw*Mnoh}yppIBvl#ke6ly?PsH z?C;PjVu3!+Qz8#_L4-zDMx8Fr8>K$w%fY`CSOKs_nI-o9 z5SUn787x=vRCIS=S>AaB>a^FyAP@BOfW!Ng1Y1Q%ATyBgh`^5-74_PPsD)8OC@&~g zlKNmQPDe>7w8;oNSz!Vev&3c9C>KekXCOSOXd#qkqa}phWJ)AE*vEpdgdUJXhl`fa zA9QHNOo@5=@90X-5yTP&uc{H)wT(M>DsWAGkjNUKtzq);{ zk$qtdU4`LK)s8MK5lNyCLutr{*H&vCn3kJ`Hg>a+=0iIWnJx=K*(ymg7{Xr7OL=kN z5)EVx8gfsoPUhT1EuxZKV2O3;$Zi!CGZiVlkN@x5ftcV!{>;uZ5NMq`3mFg^>L{TL zH1*0b{o}MX$hpvWFf^gB;D>F9AIr4VU25pGq?)MNAyUU`W~?PCm+UU};U#Kk=sct= zXwez)R?>qJupSX@?5QsN%2o(63_djwc>P0X(Ac4>j1{XcM|uhmDkYl8U}DU>cnEiK z%b)Z}k*BHu#gcY76f`PgWn!b08**kYR!NMDqdba<;M!T_MTWlJg&g|httsQ7S}HTH zOH{fdnc$K`Bz;@wz2stOUyE50LyWaEZ=N zZDZs{HeC&_6~A5klK3+JL45}gYGhMEoC{Q00Lbkr$&xq?X%tIhgEd5~l$lCtu9ABz ztz3Fn4w1B%(p7JX&Xa$T~NPfF-DZmuWKAV*_G zZsM*p~{UZrE?zYWb_y4?Gxd zDw|tyP< zQ*At{)^24mZ~Hc&H=J8>TG+bX9Yxj#o(W^iFNOTxf}dAI)pC$1qmaI?5k)r&;2L`K z^&C}FFP>AMU4{StRYMBbOBl7{tzV`gd~pQsw?nyxR1>8FmC1$ut!jq20)&zFuRRv!jUzEO^HH6TdSw0fQ;JzSomt! zJUSObro2JrxI!dt&6P#ITd34YHQ?YWva>rj&OgP_o1)`M*?B8<6Qo7qDcrFmw%*EH z?C9869x~aRMgDXpbG4bi-pt$V?`ZOKU~F78`arZfJ+f2=NfPrDUEPbLVT`4F`a?tg zE_CxQZ`^m~qkQKAlN%?9LQjzyTd!D!b_KRx1L1(fQw0w5_u#|wN%-mCZWBLP5C=4F z^lZ!^WCDXrK{Ntj7L`;JU@x)kBvr8fqvA|!>=0~UJJLjaBBcg#VwEVyK>&HVPq4>2 zQ10?~R|nV+g13WWF3;=u+u$I3&xv269uyC^a#vf~;5U$=y3_<3(jOYqp(5*!>D!%T z)s~VjSesvZ(R6>2vtK1P?h$GF68HE7ioFCkwTzNLP>HzCi=TS$(hodTQ4Ulw)Jm%e z%Dq06NlHTkAU6Z!x!1wh+^shCihrl}7xMM~b9jPKfUvWqBGx$yq&CENjA%$HQ0=1M z7B@Orx&t85YV^4lH;MsbPy#v2xDw`k$0S#E6`d5doG3KIL!j> zn9{QZCU@5d_?>rpQFS~h0b10n(hM5W{aa{I9aK-s(ia$ITeQ`#wth2+N$x6J!MXO4 z4jn`a4!mg#ZsY^M$$8pKV->?r36Q3E(2}oxEBPAAsA|Qv>B#C~mnuo_I7inRQ+Mz* zzy_TEdy6QBe?eC;zIUuD3@x&ziDo$aO~H5SWwpB>l|t4Gh(yChq~y4c#=4EG-oerC z73_h)_vh-#hj|*_d@J3=G0z>j31yMnM4I5hkFIZ3LL3KNMLX_gFWBcxL4ez*JlVt4 z^P+AFt**khi* zTrRemI(0IClf!nBf2;dcON_M4_{UHGzJNBGW@a>H14av50jw9!6?`yA-czV4(X_iAo0+BD&xS0C%cz|GMR%w}yke8vM2y?m z25xM1Z}yriH@D)``g?5U)++NR-HKssMy}cO<{oIvi@{gA`I-5@V}svv&_#P1)tX2( z>IAg<&W#5W9y`sp=e`Zc`8~_+FFtb_cPIJG=2WtXJNN=g%uP%cwwhuy4PhPm(G06F zb8;SIoZ1tdLLQXtA|4a5g{dd`KjwN58DM{n0YdGO#$sqr$D@lU$pGZG`Rh@+Ib{eA z7QQJwPgL%NQa7NLw=wq32@actJ7yTmb_8oZOvR5W)bn(I+{&N3=Mw;0L{2%b5|Wt>J@G&_4GaUqOQDHj+(e&Smar*K zWD-O-w#QU$VeDDwFW6$NnPM#Wv-S9Dx=rj(CiJs3@o`>DSvAFAIbw~`78^^Nl)9@d zCyZGL<2p-GNXv!a9QG+Q{hlMRS|GmkcaHZ3-yl$|E^G(!7>lkRbM3n>FVrsmBX{C|KS`7)>qU^D-cMwln$mBHk|FFRFr2!C#&=1ckr9 zoQslUiQ>zHDtPc8M+1^DG#L8@T5^4zeBEwEYFdU1X@Uh1!DNi7;1k!)#WLJcT$t1s zfJ$rQE=Tj5yWv?&WMw$aM~S?hFBDuj@P~cx;U;zPxC&x;O)p)?pZBo+?sEKIXdP$v z&hojYxgF!3_VQMH8SBmY9*muA%?hCL9M>_n$XuPyiXv#>r47V(fo4%$MmF$Qn>oN< zhGt7$leMQYj@mHH+Aawvc2pb^d9}oZP-b55t#4dM%hcZ;s5gB}Y!W9{3E}9tocS4^ z9jpT)d-P?gq>6v0(?CTtQ_9z_)B=N~zS~a&DHp&AEu%<|@cuU3Um>Xh2`Ht7aTyuC z2?aeDL{5cjpivQfzP757O+CCXLs(ckLSEeLh9}^|$!%)*IVYcGWy|!U>M%pO>KeC) zfy>8GZ|CN0lb^-i*JSMb4gZg(uug5Nj$5fArMiY|82wz+O^!c?=@2=Ux7vc3PO$z` z$+m$*M@Vz>bKUrK_|3LdXKljMUg2UV1=!9|yhA(SK0o&@w6hmS{x-qf58=rXHLK?< zu=*pc4oCGi(UAvT)e~F5qS*V%8Dgy^hc#zqPKyPctq0x{h2Xj=qL)|Wlmizx2tuDr z&T1nXaRuG1c(Wts#0k;Y_Tu!yN zfihHW7I(KDQ8o`Wrl4q)ylCIo?9uav2Z}mGT^&nP^T^$A`ZxTae=iiIIn-)xcS7JJ z1fLABw8dQ9-u=Q9>0k<*Q)+4R?iz)X-I;w3N_DwqxsH|BBG~fmr9xl<09kQ}t=Yp|?qcY` zVT%`{)=o6CS+DXOYuEYO=@@Ij1B>QKer%{U@@rz{I=YSzS>1!Y=gP|MeE%-wgJi>( zvGTSnse}7&alGgOA=o z1(!9g0jLwbw3mQC&ZkGcmsBt{ZS^1h<;*7KAUv-8g!Yzul`nAlQ5=E0L`#{9Y|MR#8}_dS5dB7vOvx5 zbG85~DM*mO^?ErV+;{YE>@7($#PymDJeOu5C>8UTE-sJN*Jyv_H5l}#uZVM}c8tK_ z>DYLs%*U}4b(^VJ@0e?5AeK}jzuM<5xy&-gXYXh1@%LA|>^P&0E8oOZZ@-lJ<}nC- zWLy-?>uz!>T!zwB@b5Yv!}7J`$a~l{C-PeTjHutk;Qg#6`zr7q7ZHUA+`uwK6mL(~ z(x0($%lEbSx>CbI;K#W_Pr z#B}6&SuuFqLBzsuq|ooq#>m&m$UL z`zp>gJ3TWu`OWvCi@3Il5zxCycC@>h3Nqv2>*vZieWA0TP-P>rn$~DKyoo#wv=WCF zVUu>HV+Kt6n5w}|;zlmCpFdwxU%+`%R~!TxhJ37yg-w({?xYxZL&7 zM7kRSw{7Sf@mU9gGrM0zHH#aZT^DVg^IQF}I%m!PZ-4UY-)eqekxm=@e8>DZB1S(q z-7ki?nL5AU+5YfEyE)yRrtZn4nVy?toRnsooui)i)ypf?CY=sR!!&Enw;VB1ZlLBB zyjK2J|JKckx`fDMV9>F1GJ}SN7>V_fw%ztBaubmx1K+qyxYtEl_CB;zAddq4ybhN` zXt4lo!35gd;0qc5GUytd=Y2OYw-grDEEH2P4l$@l^SOb@Aq2s-v{|pgk&{SMG5S5Qd$;=H$}cp)`>?}Y}%%g+Jo63e!B1!VrOfA z(#mLkrO{vGs}8VU(51gLBX>AIug;0QPkl!E|GZ2;@1}q_emr)sPd|9lah8>JHT6}s zmu&57EgxttFRoSJ-dP3itlp(GRhL(2=&5V!E^BEl7vyMOVg>}JUZ*D_zS_b0xlwn# zPR?np@3T1Bxw;YP&2WeTNlinPE;(ClR;#szXU*b&K4Yxu=+CYnW@6uWQFabg)*9A? z%HnKt=m3_hajYs%5bh4?eEM26Q>n)Oadn`ea-NW1mF#h26-*OZ0q}i33vD4*>ReZA zDK;?8Fur|nG9Bt_*W+0ymS(DQY^e;3@oH9sPNS<4yPtA=$OfQ+w+M^!c%`{oT`WByZzoQ! zYN5&{U)`v5;6=vHPWo9^-bBS~?HYA>^?S0?p1R69`Xux;sT{0rZZ0n}5aDalb&!cq zFq2Ca^^mhOgpPU)(J<@{s)loQx?P-vc&L{jYNV`d*(oLaUduiuGPB$bI@h2qv?SH8 z)?%K*F|Y0udNo%K_BQ#~w?y3(vv8e2*iC;% zEU_mn+|G0Uquh7sK3eds^jr^#P`9R6$SlY!NrXP1*)r}ZZFZI#pCO@}SPVfP38I8r zFxAk_Avbz(tWVfq`%9}(AvkD$=5ob=;(UUhiP7F6(RgQPhMAt+VuC;u|@k& zdc6F_;JUoXRitgpo&z%bn7`FA4tNpL8_kH?lvjRawj$fce@VlhmyFp^ z+XddppW@W+`ce3%e(n(2H4^?zMC{Mh-PqP)6Lr<(eVov!Z3j~^Pn;#T!C!YkYZ?|X3q8H&H^$f+`HDBHyC&Y|5M{TEOi}S- z8PdW>HsU>oQsyk$g&o?l$|Gsmr>eEMu)DJ<($A_GOf1vyD z;?YGQJFM`umzP9ZV)d(3s$V3d!=Hu7z;SlH5_Vgj>7SnE-P)5rMQGS{EBDfr*sIEM zx`Zd2Uy>zH`IsS%Op~GqW5(y3ksQ>)I1ag0lM-eCIXpQy(dc#RD-^!RRR?1i zmCDH{AIW{x?8+4&{u3B8gU`ZNFP6fWiDu_qY{Hfhf~q1RAw6D1%S&xO!Exg?WD3p! z;~H@`7M;jdL+hN!Y1_<74KH}sr06m)SvJzS)8h&FKWw_=tkT5h#2{J$*O%rZy|ow; zfgC3*PqxJpNTTdB%;RY!lz>9pbXxgDv3%8?bdARMwR77@vRY2V#ut_{XM44YoJmY$ zcrJU{xT8x;=$wzRtXeW$j&OBT*fh3Gm6#eGo*bPhd`w>&9q4(McIF0oD_Usn1Cama zY#^W^8<^+NX$)r(#BxqagqPeQ&uXGJ@qSTBY@CEzJJbe5Dy<}ah^F~}+(g{XGBTAR z`S&jU;_yqp1I@x-r&kjZ;K%m+Jx{e91zrdg02i$5oGrs4&o~}xM#R_}J|kl2VHP)D zX=|BROJglv8PK*OU}9?oiTS8SwEWxO?DAsrgoq4}#Fi{T7unt&-KUe~m-TCP(NSK> z_)UfbDTwM!kuctOoKLk=0de_-2E$?3ed)jGkH2HNFVI1ULept==kHX^yCLP(HgI#e zkj@voE|tRjF)blre?QIYb%GKCNC>OFL=9@@^kz8Ko1 zr+%21ewX~^3`l&rXiu3VVG>uJ4Wd`Ol5`{N|M7*}PXL1FF`|~Dmh>`EXwS{+ zu_8$Z&fMSXI43Fxz!}4luefuG!Q9Pi^O-vzE(*Y+Z&$}3(|8`Or*8tAP@xOB$ z6GS1$pb6g&U;WEVybj@8#G|jg)=o|nE*ykhKQ}a6RD`2*S6-5#uG-%23RAJ%ha6Hn zOK8!#G8>>5{ZcF5$mRkh0YhuZ zmh)`~LUr$314e8wM(AC8X@G4PSq^K_IhBJ~TkmJN)lZ^-&SDT5vko}DG)T8hS9h4>YN_35$HNKs;bvGVF(qN zKFCUh5}SE-pQMIJOq74y?^%&}s4K!{C)RI}=FzI$=t7};zsT^a2adbe5vZ-O90gNh za9q%}#pEzJ@z_g&;EmxfldjOHu{aDQTd~p5$VpsW&ig@Y6N_nuOG0p7x0w1(Sl^zB z`vRkPUU22r<>ch@MbLmr0!3)G)`49cwV_+N_1GtQ<=BmGFAU6Jzw^GPHm3(F@`x70 z+{UgeS!lT~Gq3t*DHEt{?EjJ@FT`L&W1DH=yNso&HXaDRX`_z_NgS)2NWAupnO9p1 zJU>;B7crs-Sdh7ujwg8OGMz3{#aV*b*|BZs)1HgZS$@TA2S$BGl88=>b-qYFY_L8GkEBuhj z*2$8016NheiKuET>(^Zc)^B(|z5j~T8~8nSN|*b6eqQhWNbIgsP@A^!1O4IpT(&j< z@%f}^RCsL&_}(&pvzt(0@F(=#!juDl&X$w9Z^naJhW_W1lh7l~!Z^L+kfYUsdkQta1!y?(IrmSN9#f8H@Vq31`0nc-#v zVvkYrifNT&{qsvQAqiMpX5J+b9r0gsVTew|s7($b=l5@&$Idl|bfQK~`v>XmLky2~ zFgbmLwM~+A=u1oGiV9gn7UR!A$82mvm7IuN+^}-W)Edawa;==&x(fcro(~7@!|Ul2 zC;)?WV#^JmRHu>(p#?v^O_$-e7u6tXWle{vSCt{jInLEry)*XHF19w$Fd$?CywEbF z_F_OGG9Je0-u-el%V)Pdt`^QK7rXvF;^CRSK*p2}w zqOU9M2=#FURrv!A_~P>TD5v6PxLD$b18`i6Q&hrTQC!RWUzI9z7knSW-je(1+q-BqW~-u2Zk4G?ZaWf@Q_R;pTYR! z4)D zLpo}(?aRb5A4s)*Q;s+_ZN+UUw@_8e zxMlBhD!fzN!ZgQbtRY0;CnTWn1xMZcn1wXyN5k&*Vrf_u<;0u_0D5_0P+_*$XPQA< zafnNv-SZIWzM}P~zVv2qo;!#lIf7dU_K_j+Ca2w?74(tery1n^p9!w|Jph1>#y<>_#jNs&F*TVpfiGdse=!cIJ_P77^|l*Uqn zzOVC0g`zJh^ov=6U+gOUP9gtJXv#}AN68Wjv>?PPASH7GSa~Sq51^L@NfO!_)~1aw z;7*i4uW?)({vbgi@ze>EVF8)VR}mvl0nt7Gw+u*t0q?S8suV`?Op*aT_ug*@3z>`z z>RJq2`gCB*+8q+<8LM1(qqHVgCCXVIc|svhLf9?!zG%DyyxQUjxLtY`i^>?Sx>A=I zYZ^c?%LUi5Sg*R=%(}qXFpBu-(6$ka-QRI6O^Vm>yUZnK*>e6z|K}(K1^h1t ze1=!F`ai5AR)G$!_vd1`@q-Td0@Z5RX{IK(K&Hv$+om_HqLpXBKQUfz_74{kR? zg_$0ZTCRgHmogskcpfTDtoCOorr3t%Er6oAF~TVQe`2RhJ^mo}U*HeRDxv;a>So{G zkvduv)M0pD6*QMsI0PK;F871J)RtB?an!ehu-}oG^LhP7$YW;82|En;&D*9)Ox-2x zv3XBJ|82tH2damH9UpRLXjLaOmwZf6BFem<3`R}UrP>F>`#D4sjRFS-Sc2islzT{X zyng|VxRd@$b6^Zi8sECNtliNI|kMU0ZZI>sJz0(7P4ugL}|LQ2gp=Q6QdXqlp~UeH<02l?VE zZci;zlEJoBscnwtwQYX9Xe~t5E^=d8Vd>lI;Oo?{-|bk{pr@4$$46&*@xG|?^NVte zsstwkntFzSK|IqLnf$PXPXAxbeA#he6Q+@Jx`LH3%KoSC$4Sx{sq<_`egtpBEbO<_ zF4|*rF2MrUC6-X+)>89B7!`emTthN{7f_u}93NBv#!SD}r|DN~`Ka=})_XYq9+$}9 zl@EgNe)N5kE;_c;^!FA_lyVU*CO#!82t?G8W9m9}=4o=UUdQVH8V1z=8OFAHdM1y2 zpf6Kkgx0q$`yn8aKHcZf)_$jF8io5D;|Y$V1PHq&y8|`moEHp`GFiMlD|_o7X7=`! z9Tss*TomYqYXmYDVIJ3?bnd;}#Tze9JMMnmdC*ujt!j6h3#%(w<5>C?zMn>;!$PD8 zc=|`aSEUshbp?TL3>`}ROs{^*NBsBJAx;Wb z?U^C>&Zk^+@7201oN>Swn{IGwpY!2R0_|Hs+;3)Pg^?p3qcF|<0~A2~0Ee2nR8P-j zo}xdCB~XxZBzByy=T~fWl5+dVkmBRec0Ld-M#~t{4LA0_NNL-pf4CAdR7U!RS=~!v zh|t917q%lnH|0*%k*>$p-QDf{4tN&$j}rNyhxE$=G`Sq2c_a&!n#pwWwfcA}6o=lL z{`&Aw0A#%5cs0%*SIwOKm3l;(6Zzeh8xobd)H>*Q{-=AQ<9-j!3g?%m00PYmQ|tD? z_FH_A7;Vs^5!Tz&6cp=2%-gx)J&Xk3*}Iy z>|YQ7{)aYlkp9GfmKYYP0jzR^q88qUh~SM+Enn+>VeeP{f&c8Z&)NM@UbJUb#*5w5 zRpL&aKPD{_l?-y$e$?@NiZt#&!lDuAo@=~y+KY;AB7#o#*{0Mw%@*(8vHXgo23x*50o z?4vz^Z%Jk+IhZL-gH-JyQt1AN%%*#9_-ppIw*W&Zln4fs;StM_s0yXr8YYzyk?Qql z?X~nH@L{t>PU2uN`9TFaNq|2PN5{T*z0m0t(GK5S_F_l=G5s@lxUXjCKgaZ}-(#Wx z>aAPam>QjQf7hL!*BKw<7Xdh8a0jS709ic~5oo2^iXV6pYa3CvX+$+H9bI#rcS(N> z9;c2N?=ge~t{Fe5%3}UF{Tlsq_cf|n0*6P`-v*;FLd8UoDTSRxuV%iNp8k{19mHoA zimVgczAT|i%rael%r4P!4PlSCm;)SMeq@3^d;b|y#eY>Ky(=#W8AL?%%#wrpImRQw zL7;p_ci&1dv{OTwKzWgIlQrq;NibGm2$Jz$qyNK85iF70W)Lhb3W(nVT#FYz2b>G^MGTa~>64^TSX&M=#u zLaYzL3|x7D6S@DtJj(3i$Kt&$y71Y{Qr zcuIrQrs@M=gbLMP27aMWS zH+l?& zlL?%Qq;6-Ocrn~X%r|<1q=jD*-d2Mkcw_-bxf1cK?Rqi4gS$5x!PfPN3FTLg6x6cm zMmj$X`F+XR7lbo3=mNZ<`!ZY>lU4q1c^xXz7vvdvp83_1M6P5%)Z-#(*|TjA%>56yJZ7 zK`0v^qKyIN;svfN-Uwv67IIh~s=xyQFk#13M<_CgbZ}pZGt)|DsQvJtIr>*&Qt32aF~psn%d6d zz>#Q(ihOJTZT$lZvU*_iPP9wRLq8GI}SL5LLEBv>CPshNPfMq46&fl{E6h zB6IY22?rJeiiY!`hT6yfV!_j-U;@vwC2E#HgVQFt9U>k9(X`9gBWbKxO`37v`h4YJ zKotRFQG`{Q++?~I3^}lfNpKukawlwtLy{#z2H4Y>>4Z(korKLnorLA`HkMIK%GH^& z)jYtz11Rr0wR8}9n)lHnxLtX6n>tUc(;-v_I@x-DVC6CD@2dw&r$Vb#ey7sg$!P0; zUbM>V2(LC1O}pQ$xvV<>g9t#>$`Ptao^9eQ>k2?R67RM^0&vhrC}`|^nIsJWe|duP zuZ{oHoTa0Hxoh+Tji@#Eu$zH9eXrdI(Nk#}48&v8He}7Mp>c75$!EMaV>9bLq#>!m zd1^8w!)|%{oSBZsy!GBWyg)$S>TtD7&u5+e6iZLP*d~-Szu29x6y}RM15&vbSLRz` z5xkEy)=P5#pX)^b(eO=AXJ6@tLD45ygy_48NsJ5M4wG1#7wetJ#PpWozGLK@|@OVh<^VZ zYINoq44Vrzvc_(tob507wkV|5l7_-#jeP8>nU{n9^OD|d)`y7U3HSeL?ux%NL4RAB z{Q#!jE7LBNzZl*YiX5YMcpF$rX=9EnT}{YOhl-SL?)*SFYiTX?H~0aOpg#pP8|QQi zi*;fnv!FMGmlq`1buXJ!g=ptNyy?_!KX|*4KSxXB*$OUw1fLG#-Xw46lr|U163_?v z{W|gPhPvZ-5>N3@M$cJoHOW=))2Ru1-VFVFPQF=Ss@F!;QR;i>f@b2&bFV04C*oP! zDIpogZeUfsNW5?s8ro8pg>zu?*7p-B)6B@kN{c5yo$vo6|6jVjSNaE-;#-Lv{~rMJ zrAMGUEZr#P7>u5#!Rcf*i99pAYLtF~GW0Sgm5Dg4wz@)Pl4wZ6=OB+va% z9iUTJ*^%_xjD6>&?`c*S-(Qz@=}Ux~dTPCc`7YX{7gYv?G7Xn*i$wJ);b|L%s?ZDx zwh}2u5OwyIGTT~*MYH@0{?=`qz`HXn#Nkhuse;{>CYl*fbvNS z&&H1jhCnng{pX+Pk@(U+M#57pG*atIp4Dgx`F9549A5bhnVw zB6|fu!4c*wXQ5m1sA!5c0xNK(HHGL0TPQGpi5MDU^$%aRMf7L!r~AKx zU7Q)3Wo|L#x%4?#TFf%#pXsg&+BTmJtiH!Ar|xGD3hhJXw*5%P4ZF7#NKy8&qId<8 zWFIKAPj~D?Os`|u#m|`A61;6&3B_wjc&V&jZX%_i%6#1)E=tj4o73?ujx&iQaY!;xlIkE-?NdiE>xD zxmPOvEuGG3V%NmY)DmG!{BY_P)p0cru<2gf#HvfCT5+6dDpQWo*vMjs`g<&z6^cPp z!IuQM=@^~uo?n7^F^C!(nW8u3cft!x>&``c@=#1mgmK+c{6lEH$G7S zs6tN6uOL8Ih2ot<*`+LseWm6n?bn22x5(&h!tSF)#I1ABBk5A_R5=hGOrG3rb@s9!$k1J4f^CgP3EC4$4bYal5<_&l|rX-?;D-? zf=9l)O?NqMBmXn$_}4YYqTv)*^To%;@zK9Z*gCQO0g3rS0|;{TJ3*XWs%4>fPm!$b zpP2tsqz=A+Z3i}oXfdVYf)C*F1+y#<;ez^W`%VKBK$pX$tuF^q_bGVBQ6p%nWjlSL zV&)!YPWJcI57?=*os{^sj5v3octU3a2XeQuFhj(!D^| zE;ymZpqL-*nGg8?RzXaV;)B4e9O;}ZJ+Apehp^J( z`jLy9Ic4=PSLpg`{E*5R(iRCv8I4}1(>&{cMLNYX=5 zCa=$UX*-6DYhb(XcYhBAxU8ehhM9v|)bNl4j{I;D7BV;<>sKbbXawmU_;7}=iwJ#q z_^)4lBt70Khui-#CDO>gG>LH>OH8Srjk9^Kb|1oH&tTdm;4=|=irPqlVKq#^f6T&t39*<7T1*Naa#b{P%ptUsn)rgIMyc^An1|CsMU9&Zp1D$`GODu~azJieV=w*5Y$b{sEmZ-%jL zk#R+lb)?STRbyG`a;cZNF_~U>w@or%8>-^M0?jV~fq#ZpL3WWYU?N`}K5kNh0W@oR z*NOvuGQ8=*|CFb=rsUw`E+$;?LtI6&XN=66eRT zB}IQ7bv^{`TuFzf)Vx7E z6ax-XZfpA}vq|ZDsCJvGE4{7=L~wG6;rk*^DTHYY%O=q07b^o(ljXWgVW5X#*)0Yl z10ULR;BcY4{J&|3(O*}0E}xl^xd+5jRL!h9ca*#)a?Vqk7dgm5Vc+?(;y=y+3XS}L zFSUt+vmb3O^y0ieN3xu6*&b=eb2#NposMja%XXo}HCyG-DbWYXIE#K2w9@T)uwetFSD-{&KR0 z<4-gw=o4(ltY_A}bjK@C`R2nx$2EZJ%R}P#Um(>R2l$hl_=J9-71BRS2O=6teC9lo zvGV&Y@z0+dVi(^y{_Xxr4H<$|+?k0jG0KI7%mXzv{XjLxVHz|~)HMB#*6XPzMrQIF zQG<5-^No07uBPl(DvrbG|9PJfS*ujIXp2IZkiQ2CM#TeUMi( zWm1;lc9XC`^~Ypwt;|op>I4)mIOl4%=A>TR2kl8{OTgGnPVxDkkP=;&LW z5gjT`3m2h(>U2K+l`l->CS#EYo=42w;Qp$R*G)_%m{i#MIgtS7;?P>+U_w99^!i|i z&4BoLTwlvj;hH)+Hj3Z0R$k1e@-#qf3_9X2r+nIXet2!&d!EESTYdri zF=*6o1-^6Mysbpe$(wD3-?>>CDIBy$|WBBxCX3$0bK@qarJ2y7f*#XUZqfkCb>s($h1B z-OjQ>`HTGwN`omD`K|BdCXq=aSKEkEQ0uWlzoGGAd3aM)X8AikHvA9!!_hFeb91Pq z{R!t(H@g>Jx^T!56(1aj9&%mnfH1)%A4Y!3-+U%LFhpdE#!IGdLbh=>>b~i|xz0Ne z{JUJ8(f>3HZ9o} zZ^$%{JJ#k@lI|^~CY>|>{1z{6eILWz*rk<}TTW}6{9L%ARywk%MQ?gk@2!3HyalF( zY3zKFdVYsfk44946%7$S7vSf$HC&e*%{8w~xPw2V%-#7m$rVY6rN`-9u~L zd+{@;iH$4iQbX8iOkMZjA^W&DY4nZhv?_$Ri*kYQA-^q2>!xU-Wt8ZA~^$~q7 zCnXJ$-BF?}{32SHh4W!yg@?DZo^aW|Ech(@5%>SH()7i)pX249#{SavmJG8=I8-q4 z!4Ty`&){hog6%2MKZH$O1!42Y8W z9Yp=z1p%cPxhOh;=7VRjR!*Cqa*Hcuip$+Q%6iknf`Le;>q%o->-D$_w1n#XkG(4R z9YRS9 zkNb*XDW-0d`^xK3#syQ>i7NYCgJq@7BinkDEA5`sKQ70G)M;n5?DJ#M?qo&#bKTX} zP~pb5cD5X9D}E((zl9y*GNiBW>=su%%a} z^)qDJ+=*PYePp8xsWpRTwwIW9sj=jwuHrDEJaQr>}e zO3{Oru~J073B6h6ia`ocQXXDI=3$&LldN2Ou*VrhMPj@GxHWl_*QBs2_|G|~V@s66shZM7xXn`$cVPuA@t#z(pH zNpHH0f0n9WX615U^?sb|aLg846aR@Mfx1)>f9wZM0%IQIrhb%=ZFsDwq;CE#OCAP=4ShnMRU{ek|6 zVnSe@O)?ZR@#4Zp#nGKQIQg*$4)(o5zII@{fZN2I5kW#5j4+SvdPxMV314ekhOD>y zS}5>AVJCn-!%ws$!-XeStw!-=fmlF=7szOVUa)x9RQAt;U;Jd@rv|Jh^6Xr>NSTdh z3N2T;<&WJN9ULPf$6TMQ-%-uq6pERM2#a9HX=pGt$N>ez$pqxgRESbBj0G|m9=@5f zyFZW4VddJ;vTx~=aX=^VesG2|1X)Wes|**|N@VIPlgy?PBN-0F%a4C~X7mxEo3vtW zIPaz8pC#mUTy0kKr5z~o&UCKZjc>B_*zI3|T{}u|nbIG4dY(1j`)~8b$GT}_j@1i$ zy3xbjeA!MMM!O8Jo@;T_&t4tg9z&s(-P{r)TiovcP6m@2=F+V3EOL$`zOM$iF}h1g z?PBESi}-hN{&!iy_5|&q)r@3Le!|ZU)-%`X^&W5Z?j0@m#X7T8+2X-4 z;lgu**BEXF%Le&SxlJop|AD^bg4h!mZ;expN1>mX|5n5Z5YdJa3)s#*cSf@d?kIo|e^eSIL_FLK3` zf|!Pcep_m8&XtlvGcWHVooAE$f&TH;|8c})Qslnf`d}@tY2JpWbS1gRQ2j$bzMS*i ziGr($@j)ibnayJH5N(U7PI6+RD=S4$OLcB-tC&L}p%{9u2Is^#mPb!v_^+}u9(&Fe z6gx+*Ur*}2#mP9Uj5-P4;A^28&QGnmXpHVgm!fph=+pu|iAdCH1*L+N?*hp8?}J?l zcq)Jt3*}NjhW@>)&OKHhO#{F)Bu1qOW9Dk@4rGAZc3ZP2H z^rMRiJB&e{?E_JfM*Y)swaNsm?XMv3wEun_9~4uc(9epRi*yMFkKR2@!Y9#1yo@5C z#KKNJm!L!r zNc%$(Sxibu!Oo(TPdsBao>HVFRGt_V)Hq_nAJ3y5ugH~L>FB?%F#=H~IK%T-CN`$d z@0T%RjC__8sfwSnIhB7+nR|Fa=)m(J=j8% z(@;U(uM?p9!5t?ZJzdRLgHp%^WT(K&?|2oq7S#cGa0RMTP^HxAKFsynH5WvwSe%c! z-RVr8lK>nT1{p3)_CsJ*q+HwacfXCpo1Z)} zUO(JOc0e4i4$HcAKgX?g`L~*PU8;dnl^^zSm_Fh`U=T~JxnK9G*ej^;}q(mzm%j6`xP&x4Kzro)P6vJtuz=q+2mimF)=(!U_ zXbPvoSYIAUpObMH&0NV(qn#@8S>hBY@Y3%-WU)#jceO}Ho`xt5p1+BGF@&5G{Lo?m zmXF_T(8WuJ@Fe_E{@r70>8a%x3-Lx8#F7U0)7@W$u%RgxGf9zmE0e!#jfdojBg`aW zXUgXJ6ov>0eJ4ajbBnlB36qS@ZlwMVqs2(WQuGBCWkF;f3{}=&nVML5ZhFeZ_3C4M z^I?V~XisfCcIWteT9`slo)~IoqwFicv)Tk1U}=m2$RSl7Su@ zhUs^1zf9djkJoi(q-V@Awhox+I6Vz(f6opPh5EAg_O2Ft>}GzIrDWV=Y;vB|tdU~4 zW31##D70cJ=pO1SCl4@8gJPu>TIJ|WFL_-#uXp9Mo|?K0FFKo3#!*)M`Ar^I?-Kbw zLEWp*_>G(!yJvsiYX2)$^Fc9LLm7r`;beAkr3Jnsj`gNB~^z|~UM*j-&Y&Zxs?9eW{T9naa^G36wgahwS1nJS8X zsP=u-=`#thKe0A_t_=|IF0-q%-ECt?JM*5oq7{Nkx^Gv+6EPXio38I)%^ z(V*TOw=#lrcf5U)nqN28ek9b5G2YQ$-Kz?DZo!!N9eTa$9}(HMCxl9BN~mu7=g2!o zObt1mPC`KA*h1t_<03-1%nQx}02x|8wB}}0F^O9BN{+93T`kNEFuj;b99_$E`rJ8R zf7;#_2Zb6hzLr#S=e3Vree}Ft&C4%;#+_97KY8{R%0tYlLkooYI5L}uUIkxOANpft z-$crvuFeFh9woVd-6Ma9zRT6mCRLgbpQ)%KC+Mo>Om~XH6D0Fr9`Fin5dGsX0iPHU>gm#wlDJ&6N{U)N z{|LEiH@#qoaaxqVMOt_FkHEXl7~9L&_Cd9GxJ zD`*j>8izGb!pDPWT>#MdcWs8REO7)wD~5Myb<(AbeL*dx+l+}F8i1RzTGm8T<3Yr< z1FfnKIFf2XSNmOfqKD{jZS~_XJtAEtUFa+#UYUL|SRMxgj#^$D&!z4MswmNItb`&ZAjHN_WpjBnkM=$n zR^n`vh+Xrz^j}==x^l3dYSTuW`q^ch_S8IZK^{nsCSM{Wfcm&-HhoYE@qTH#`4#e2 zg~^_F$f+JJt=$Ok{yOb4={dmduOh=g#C+$U7ena3{^_Fd+s{qT-Zi*hL{YE!8WCes z_hG)swe-{afzkfFhi|;+$-b1Zclo5gXBI`HEk%2( zow@40##{W3ikMm;Z)SatM8kyw0f)a=c%i z_aa@#tMfVw(~pV%G?-b64*txGTZ7!YuIF^BA&vw7jv@?>M7KyW?wr%8=FQ7ZhN{Z= zvYj&MXt+#Q`It)o^~WG_;!7aYZ{c|wO5ZN`S-UG_IdM9!q|O-<+tap2%Q$Y<4N>Ln zySn>Pm$c3s5DxaMnWv{Y_tx_wci)v=Q`f-HL56dSBFpSewCglH1L7v`vHJDlb~!B#UqQa?0lQb)JAw*4Z;eLR@+$ zm3@=mywdv;`_X44OOD%^U-Yw99`EeWL-YH9e{L85B$@Ne$u(nqhyT;S;Q%OCQ#Cf$ zci`cI-xswl3KRv8H-0zbpz{2QEN<3R*CuC{Y$fo9Y-Zxp;zbe8WwO+8Hyuuu_FU8! zQ`kYSCo->_+vBh=zii&(EwE~zYnbsiX^|>n02?i!&xk=)6*4N%$3CkzBYo zxJ9-mL^)QCkw^^zxu6-6Ai}iqOoxs#{ac~AMvclzI5gk@$BNUJ_vY(WgwaMR)xE!l z4~$DkIWpN+S^QHBM+D(~@TTP#@1YVwoXdLk(8@=t?2S!`h#&?2I9y!-tfNASaPT*^ z05u$HyOeM3LZOBR3gs&03oe+9^s6Ke(LtwM>zpc^%=fi^2Bq%6^9#^#x4zMY13mX6 z?~M!-EY2&N+qJCecV+?kcl{Uv#7s<#{ssnI2Iue$+d_r5eLSQYc7N^6O z_sd3*OZm~%YU&LoMDTe|haj%3M)xU!A&1%}f4Shy&uZJ$P)6ivjztEDnstrRY)-ji zxn}u1>nxtD<)(D4gRU`9Np82HWS-C_ms|9#j}xqLzLv7~E{Vb(_RXoWoe zC%F^o=6IzUnKF0$>4*`>K6~7Mt@zFLb+>0_zsFGjK2-N`yX_lQ>Jd;JsL$4<3G>W5XHqj`&$rI=LtWO{uZm%-n3$& z<0gQhx6fAI`CL|XKWJGW`*=-b<06c2n#M_qaYyO0&3ly}E@)Y&`8ZMH7?NZg0QD6p zCn8A>LfO_=3wf%WcL>G01#R2PsVW*vP?nQf%>OVhhAbp&n%)Z`JW~opvVw&jvuXlK z$H5dP*CgJvcb%+V%4E#t~yCu|6LOzfnKDX4(b1+w(8~($tKxEg)3oU7Y9biG1<1!$tZmWo0y>H4k!2obk)tZh9y<>u(`9W}HSdizRywefGc!4HD4x4;= zJBDn$(-Rr2tVf*YhZ8cwm+v=i^H|y?EVwdM@LFC!Jx23K>&TUj;Yx?lcQUYP!L-^9 zoJW%fVJI^1C^K&fV_Nv}tusm_Gd@3u<8wSh zltIniueuDM1T)&4Vr6M*Ndm44_W2A+fnd;`8GVZLi*jW&@4Ne(Bq}w;LQCd|`a$A5 zR79tj7@IH>z^*CWu2ulQEt0iqh&;JNA`Oy`JEqDhfW+L#W;5g|`=({z=#D7|PDe+M zGFq_z5pFi z5BpnzRi?1_seyArFd2qH7<=0ZVGxN>V|Yy1hHZO6m0s+*Xrh$ z8?;d)VV&{Y`xY5koq8Y|! zs{MyT{3>xck{w>ZZksJ41X{O4B7l`ec}3OfUVt)C_Dfe`JYZ^-aH$3iW?oKJ6Ji>+ z9I5!c0z3t^pQi46D1Ej%2~zxZfO?0BLyXjS@wA9q{U7(*RE#;+!Y&NFNZl3BIxQ=y z&XpyAhQizR(F%SWy(q+F}<^Z@<)JliD`SheShT6GIp=;m*`uD`=h9uW}Y$UlV z!rbv@UWNZDyj}rIblHGOP|4?iJ;8lxFrd~`SaHYFeCA|B>D_Wo%c@_1{izp^erTl( z-v5(LTH)7|ey2wr005|~y9v5wL%#hH9!?a=s2FS?h!MH*D=UOa^>B-tp)7ekSrRjz zN9D&rsJ~AD6Zh%1>`J)E*JF9g{p2?JI_L_iU+HI~V~+g}O5MyzgCvYf+ld(8APfs9 z617^HC2;!XZ`I3x-Rc|hKnC9ym9U%+$(Tmam8^pOM5bns9}{N(u?j7HBo`Vz%kUoR z=Nt-a@-JaSY3s2fU7l!;@{3#($#RQkxYKts@DU#LPzHGzzdS8xZ$Is{C$!?fc>I>J zoB89^69UKS46v8EY2+H;YrhbLecj&MpCdbBP*Kb2Sq82TL-I*66$fGGYr+?$o(2o+ zp}(XCsYirdC8*`Js1_n@r&@{wkf)e>9$4P1{;;?I>XRRB=_cR)=5n4#Djo zrI+nW%}DD zE$LbMyC2*+b|q2$+DvkyeUq^jzw+2)NK`#7&|cbjYG6wVe}lzqx@TTW4dd?e1?vY~ zE#!dCmD3KpvbaF%HJgt?&$DU9{;bxc?Y7MYyR4LPxfKAw<*C`Xybadf?H|ou_*Qj- zw{vUp8Sb*N3@1Qa)-#zRiR8i&EGg7ZCj8g9oHvhOR>Ik5=1f4eIh-ko4D2SIzP zRj_z>KK?IbzSDT6pX@OYPx2tMH6(mqZO_Yzo8XNYnd9Rsn=KUf{+1D)x_~IO2Fx+d zWd2Ich%uvry`qf|*1gg#j*D!Q-?^QgbRH{)HR&vnehNOGwQT__7~9)wtMYEO%%)C3 z3&Y90AF+jm%*7Uq$aIr=Z1x-RnB8}hW;nF@h_YDiJQ=eXh&WwD?cMzn2o@MeUL}uJ%m2K#|8!X<^c{)6N3x1`0rnEj=tI->H`{PRVU3C>{QUa;}=IxcViKZ6? zIO1INV!-s11edt`WG@08wI-4x>Cf^vliv<1&iHopNI3Gch!Kf?aKd^f{L2vh3gb01 z1L`6a@uH{^k}@hNE`1yff_Mlf9LODjjKAP}!E|@I%zy=~a?3IYM8V7=rYN4bQGX23I7uC~p9Y!t? z@ab*!RT9qq-2M7R4kCslnV*pd_hsfwWuxe^vDEow!sR%9neQyy@D;c@@)2q&s5wY| zhdW<~qc^p?sSB@Lf1c zyk&Zz;EN@;=-LG-4qz`{%(ph`>dx2uQgiP%d}Fgo#x_qYu(-VnDr)vDO5fG%@F;PV zhKJB$2GQf9M~O;|V;}Nos(NBKo^8&<2%t*i)pdWUtJE_1YEJm)b_2)BHN*Iai41ex z0j|Q0?#(j-IVDL@i9K%h4z$*c>b#8hN#2oAN ze`vOUsQq7pvhBO-xnJHlLSc~dxcoayDlqqo#6d3w4f-eLd|s7+eCJ8IHO@~i|MU3I zm+*+b6-0Ep zBuLohtt7*ty!b7e)+YrtP#gH}h*s#FF^_GwM}mv?Jqh9UQa@XOfdi}KF`yV`C1fhG z77fb}B$!C6zm@B}y&h_Ih|RtJ9#zX*`pv)Tw{O>;;%;<~`ZSws+LD`1Exvx1{=>zR zULNRlZGM2$Fm$loYkOBIj~u3Jj~2TCp{G+6$>%*;-lfkNHbaojr=GO1v7o)A{liDZ zIJUO4^Cc9v_!t9w78VWGYt(_LfK)*aw4A5c{@{3VNX^`aw#6ebrod&XYTH{smq6YO zh<3h=p3cO~<0Ri4(h~VCOs&d9GS#0oZaOrG0X_WKQOE4rcQ_Gw2<#Qh8V>ind>nh# zn`ZPqtt#R_piFYUi&Ik*vURqGj}|bpQ`Lz2(^ku;!Uv~>oObH($`?6{8j~;(0RFou zAXp*6v#3>E;BMr)Zo;Y}#Ji(V*04WcOlaxJDq*k;7Z)*nHZ((Wa4y_E5 zO9PAZ5Z>OD7%KV36t14; zIno4RRGWUh360Hv?03)kUECH=b#E3DfCDJcK+uSIh2*%xZ)EvdepnqBZRyj$PK{M%@qdgtk+`X@ z7d>nGsS2A-%BPvf=q5y%+%fOV>Sqf2?v(m#bf3Y%3;M9WtBjJrw#gY9Q<%a2D6evL zo5-tv&^bM>w&}@qZdPqDo6c*xvZLinO7(tnSQ%|NfLSY_j+ABdB|tbffU@2=m#(sC z61<<&Mm|fT$eb53qH75OlGIT6-yOu((SlO&1>D*%Cqg$VRLY}`rf|7@0C7N$zugTfPt7wXDGE`=iK9o39jrWa*xuXByhL|9tD5~=lK=)Ryg_QEny|NL zi9wuQ$Db?&unG4)Tf=|H?j9ey4Ff_ybAhL+&_BM+FWMGlwoFg31sgKCf-@kdgjLRQ zrhZ3*38a}RElLd}0@21sgVf2>W73#t9UZYh_^rbpG1jr>466RI1uI{DbNf!~@#^O8 zmd?J;URsH0%wH)|lX!cFDD0&UF`o-78m`!FXIgA^S6+I3>*KGzF?H5QkHw}if$Xl& z^GrD8_xj0z=u)*)^miFE#s8wq;8!?M8fY%}jV_TZ} z{qgFWHsyA3wxV4xBlAw2kV3!cpGJl@2veQXr6o&vi-!mheEOD~d|ZD8vZ7mc5$yzvCn2 zGkAokmk5goU{d8gQW_D>GxY4YBRWgJ#0#0MOoTT-fd#fRc(JJIN^Wl8+<(j(Iuy z`GkiMBJ-6bl6u5XhzutX@>E6*AVyW^DLIH4%vHp z?H8J^)?Bmye}+|$#%~RdP4x=jc5CBv6sYMMR@hPcT_0m~+O)SV_%uae;Td4gWMl=JyP#Kb-y9)`HIMndfW= z&bKnn+uerTp~+&HgjnglghtGstadxrs@E=aToUIqyl*|NO*=b&-sN@UZ!f3e!e{A&75iupt#V6@yC_!*7mk8`;k`rk3&D48v6PDODs?e0mF1t zOsNmeUGd!Vtv>Zm_DwM6a^o{=@%{!T3A688 zo-@&uG%@`1A0_ND??01Q$4MRb_KO&ywcA_H+j|i`6bD^c{?1i@DRdq+soIA~GL~S)gNM?P+Sz8>&#n|$y zkg&{V&{}xo_*0R?45E<3!s`0`HTyBU{o7%md^0-rK3ats(FwE_F18>rhE`$qi?ezy zwt1tSnK_EBV2a*0(MY(>H(oRkJp4%@KM{dw1X2WSmMD&QywyFy>Y0!i5SKMEIvESD z@6TVmKBuAl?3MG4R~gcOZaEq((T5>cnjyW6~L&TuCqTu*q9R6UFg-#(IeFp@DOTIA&ykpCK z6AFA{v!*Pw1x9TD{*ts8*A#@U&bC$dR9(D=FzC3%OcBt0mF<)?67f(I%1B%GWx5ZQ zOEqC6-pl?qPA9m^?gPx2?5%VPyM05A{kzL8K@mxhyjdD(%=OggF!kY~%ZB+vO^(hR z7o9^N!2{2EkB`opV9sJDhxsum$3D>CB=8#So?^^=)VMp~nV4_BV0_|Fue|x$wlrJO zvD4>j>+9M(JFp^?@>UVcDmvfs>X2Nx&9`hJ5*=vgXjlm0n?C&@aUJrc+#cesCL-fV z;NY!>5AXm7pb~4Kkf9bvVV$t}l8+ibv`0-rZTuuYAUnrDRqz6FfG3$aIr2Gg`6p?j zgbqQ!V}g!;iPS13H>G?)>Bx&Q1278fB--L}Ow-XX>%}nyzx+`BR#t(GBmHWEYPABj zFkh0VQcI1%IGuc=5_jM)jXP!M!+11(2nIuC0J=Si2G9mGSuniM6yCGGg z*l^xcOv(4neCzq;8=p75zukK5NL}}t7W;u_`|JCve;SiMB|ObzQI?+x!=VEK(bhmi z+PJt3m#E#rOLHeK&Yl>x<9`d}|)C-PG!EU^}!QR)5T^x(()jfSRz4q#c zjtlh{FJ7o^ZK|a!bYAX2(n(5trVT;PG-Lyy{JC&o}`g%}En>xChE;ctb)?RFGY;6&%OGqub-;JuE_aZ(V z-~6cv6jDL`Zv!Bz?Dmh#+8$c8{sBYASWOm6v7CFMB?!j=FAj{hxh)ZGfPvpMy=}S< zXtoB#0^h>n;ZFkji3mia!HCsupdp5Dt?o-uRC9b6XN`+Vf6$Qf@SODvR~Ba+xpK1h zN;_jZ&YZ@CK+J;oKT_IU|LczYPkCVjPH3{2c8JknS0DT6Yc6(Y9;p7=thkUr>mP{P z%ES?K^-hNTv9Y$`m>h;!{xKA=Knz+i-!cKySrf(VF}oLY7~jGo@7M!gaizYox!&fK z;Kdf#(4CV_ng6}a@-yT1*LNSUsP1d0J%iL7?|GHo1kCg+8_1!B60;LZS%6R{J(N?o z`K#kfZwu!O(Z~7Y$YuNgt~lTxnd+k#E7WYF_ts@%P7o9;`tpsA?mQ0t+9*_PWe{Ef zOas>F*OSb-(=@yMpIyo+c5fu+tlYda*OGJQX@5s5;7%n1VLWPT zAe2P`P7BVzaQw3_#@KbQ$5}0Pp05^u_n3|(nHBdOAY(A3 zmLHNVNKLJ&D6jJE&Uz5SQUYIUzlN%HuGjweH+SD3wk|}!Gax3L2{C^RcTL5?#=;;| zet?iRI06fK2Sn!wnytzdnI+hqi<5o=`AJ5jQ!{}^IN$olTD(xH;;e|Q5R+wcRN8k9 zY2TZ-{x=I&q#kTMSaqScsUEvAF6$Byz_h3*9I)7=} z#JTt>=0_N6}zKT{q^J=T=sACuu_ObLq4oE(!mEpq1%jXUCZ9m9D0!X+$sxqS#DH*P6H%wBE9 zEEY-HgXrbpnGRv!d!+-*Gi2P2NX@a~AT`s-Vn{G-`l%G}g}VnJbr*TSVHK&BJ#Ea; z_i~DJFH)i#sYPd(J%|>fI_gC>7&SymrK=aU+-^VKYyaDO$qz?v!C>BBo5k>n%RXp7 zqP0X9Dow)b6Ki#2i#JAAChKIKa3RKgnwdwuaCrDrh7*Bk9`RNtOoBz*v--qYJmYb> zK5@CQ_koz~2N!Moap;B()}}+}`&v7%^|Xtv0m??h{$4^626VlDy8AGA0v8pezMd9W zJ)^P0((-f71@%`${;)9k#kcM=rGSH6yaN0MM(6sQExu-}w>cl@XR@Nqf_>vnnK(Rj z5LkrioforJae2Px)N#xnMD7D38IVkU?c-;b?%GyVbH3Hy*51>@kPnEFC__zLA2?7u z&>$y0gkKnkVj$Gf)^Ulzx?cOy7Q10vMeu^no|<%a8DMR8ZbJjiZ^3rGH)}|e-Ovt5fWLCpfnSWD{8cp@wn1cEf9t6IeR3|mi0UhnO`F3ZK z8kmM2Sw@QBNb_*~Lm)K;ROJjU1F(~@sOCbZWHB_~B-7v?kBl#=a!iD98G*>MAdZyF z^ksYo365+B_Xk62nU_o%q;_ocUr{S(W{i%+Ed#*ij+56Oo4dO@_nXw?xuz^Ok;kN6c+D+T3!W34z65n>@S<-1F*4=woYdvo4jyfHiXaOJ7W z^T-{=j#n`|;nb_{tDGAQOuv&`_n2;TKzQPmH?gP93wgcFJt~c*;Xq9)rfz-)i>J|w zvL6_iA7n_I8n*dc3qO8&dE#do$B#DKE1K-N7wtcd*)cV8>v&`GEg?1F_*lf}?7;d{ z%=(QL&AX4a#U~a$y(IDeSs&i7W6xJXaQp$UmZL`lw;&w3r;`ewpR)5i`0>cL*i3d zmI7(4{&}6|f9ijQMPKM*A}xhQ7n)i*SU|rnmyiOdu4kAsljLu zqi|j(o4=WbdjZxV=6KZn}jK*bgm}%&wc6+R5gawJ)ppEst@G6tSH(~jc5lo=La_Q)+3pxq4aDOZ zKETg7jRG=8f*8q9YGE*>mPC>u9^$B&NTT zLZb7>nk3mEhOlrPn{H>FWFnvv6nNSc;w%Zf-oqQzh^KqJeUglh{We2{Y%NwE3 zL;sq#ywpE3ImDD3V950`S$tv(ebKMYc@y>fAJK06*6a`d62Ez!rEXBbu}rY+p~i}>Ateq-;l?CP+M1wYfTePsTMXqnk&8d$rToaj}~ zrfY;SWB`T`YQiZ)2nU!Glf6omfp127m^oE;+ZU|d_t?T!_v?2B>Qb;9^o%L;h$+S* zQOtFiF(&i6!auuOVB;Za@Um={-K^hlFq#0%N(=0Z1P5oeb%fKeEd!{`n- z)+G8D5#SZJm%hxLoAZ2)xy<=9D>8P`_6H+3e=l@JLSla5xr^tUJH*+!R2)a*iRzP8 zBdbk$i;#X3YpRt&)Q<9+Uu!=6!}6quHJh1lX9t#-CeuAaET-e&q!qO0Ah(D4rz4s;`c>?Z9u+JGOBPCaR7k=jLmahE*`B{B#vr~sg4FO0%mS(; z<&Z5)HyHhcg%5_*Dv=aIYSW}3fsePEon(j%xoH+q$Rl~Ba!>tShRZnMDbGz4A&{6D zz|$D;FgTGy0}r1NBEOOxkhu&%YMRp^wQ+}n=~kQ}b6K2r^2CC-r)akM>(YF*wm?%! zprJ6(i1}`&Z!{L*+1}u_vC!X8=x@wpD9)StUSE@#&GR-FdYKD(D=r_skBKrF&Cis} zhd4fAWIom)-oA|CSwCH3bu;Y`Ht&4c`1wOKVs}+sIC`d~@jQE=x-PfWa%w0dkxK+V z$v*R)xgQ12TpJXfJ;r1k8CNvU^=c9&Thr{JrA+tXI z*1Y#tThHw(Ji&q{#~uh}76lLmx?lA7>(t6s!~!=JU=(?Fw&) zM?ahasVB``X;{5Wu2X-3)Cg3$POZ#-_vfgre2T2UctpJG4kA^*^awgxq%Nty`iqE< zzGK)lS-;Culk6UCaf>O$Q7PV{J>=1rg7xA})#Jnrup!^yP~>YYVZ;8ISmE&SCvA+M zh(I*=*j$g8TrZ(!Qe}KX3lyIK8LoP!ZEaJGNslc2=#4$a`G?M3Y3b;#IgfmCRO^N* z+`cI8m-+guO9G>)AGBK3Tge$a6V26K_N2p&e=vP=?~h)&KXm=L@ErmAbOv?IEx4PC zT}>tK6f?GzzC$CVHHrpl5(T6y(Tp)RLye`d{bLgBGYuINwMi3az5mqfiCfF6PhaY5 z$993U+F^Mk2>TKK`vEZc!2MJ0t*Rp&5rxYT`_GXjNe zgYtYCBmYIeOOdN)#-CIfEd=qa3SQ|44u+Wh=2sp^IWIq#K!4*~jVV7=fm;n9;E{=w zCd5d3BqD%xj{4e72Oetaq(=oo(KwZ72!w(RnGpmyT9kpF{0Z5TClU>1%mI`S{pVmv ztwI~r%8cNlB*u{mgg_W%44sRN=E!R4=dFH7vg)G-svlB7N(v3~6DAXADonWyhSV~e z%*By!1M1?A{Yme>EbL|zk2X)9|Grz;PXDC`$7oCajE4er#esSdFwHAE)iXN7)12$8 zFD4KLmcz>Y07ql4kI}|do~Nk*Wr6)Tc=!{&kEviHh-k(fKE&Y()aL~2#G6wr++uRw zUoRNFIL$q7*TmRukA{A*Y-j1gv%PiITr=Hc@8Tq9w)NRhT)46#`AF~|4flm^^w;bg zt<7*>R^j#b3Fm~ed$c*A0OmSD`Yga25$9&gcQWTYM;CaBgUU0fa7y{2E#EWl`C(l0 z{EW6Ae^?e|NcJ(LKnau&(;+iM!uJ0By|Q1tSN!w$tkWYlOw(?e9KCx&LM8@s?u$#@ z6ApSUIqVZx;cF-e)MSs<=5fC>40O|#1SK3E#|EXy;|Mp#qJmW zqMadmRUPg6epsop@m7>^uFXn1bm{wxKK!O}`*_nnY@%GE^PFP~#>5o3MbknA!8Ds7 zorM;~#E581l)}Kiwn8ssG3Vioi7vd~^MYxV3Dq!!uQqaZcapwt(O*UAoe zM&5n+#W^swefF|$`|}^?d^>(0RpX)AE5^(*wsDIwL@yMIyg~3*jJgMFRQi6T_AnNC z>kEQ)S>xwznD|%oe?2pIdrHQkio&C1c^4Zh+t}W4SsV{2h*6%~W$;(~orG!Ru#~X~ zYG6^q5FuZR)KWh4l`8WUT)oK)3D2VfoXlZML568Xyl?+ zoJ>v4g2?Jnfk4Pcj0~Yu%j{(0|01OBvDaO^7MFY|B=WOSx>WbqPu?9-?x8;tpeyZ1 z>X>Br7?9fHt1ndoEfRvIY>`L}MoV`csRcC4XztO-TLIib`kZmv9NtKzF|n5ajLRDJ zdfv$ReLm)`-!yIfWAysmBi+?Cm;1WAluHb+c647uSv$hpfj z8&N5sz`goB-=zn}L}dl&GXZPTM4@($DRzo00j%8^Bxut)VJu|Pj`0fC4W``!vtQ-q27tOv|FlcM%Mu`G9@Vb?grF3+ePp5|1S=$sMJ){)VLD1)wsLXRkP zM(fmsgRa_AcjIACeVJ!e&RA{Q6y5I0^F9v#i}6SE7N?!Qn0@$MLu>b?<`!Xu#I768 zWmAw)Su)0$L98Jo?r=i(D(lo8y>^iLfmdE%JhIvLtcf~mLHN_Q!)CBSq5r{_Pag7D6vuJFAdP}gTFi2DCqd(wg zIxsS(WJGkHi+I)r2g=UEw>Yqc4xZ(Wjh|~%`QdI(} z#XTBaPsvgO+X)*xtjFtrIYayS-%S%rxaelZ?bFOsAZtM#HOab@2|89QITDA5KtADH{3NcH zT7D=g(pg?8uOfD^Zs**>bvdR3MzjzXKBc@#*o?X1#32YYm=NbDPEibwe08^T|PvTCey;M=KN7H zMF?=-E}XexwEF9F*vS>FO=ZiBzaib*l7nuyr)p{&y4c#vQe&@j@^ zw3QvGtFB^~)=h1{Z9+`fNGE?4Ln%~#Qy#W|zEPR%uyC2Z zBPcX!{H!(JznUMrAvrnEdbB*hDL%EY*S*Nl%*Yo)Te92K3R+jFj zZ@wZNVqn)DlrS1;tovM~nWd@wQl9W9U=hX+aMZOHf4=YbKBge3GdWqX)K z?l+ZGHw`3Nn80AbU!N@!F=mnoFpWYD3^_-O$#xfGzPrxmrM3EM@_e-U&Jo3Kn&L;^ zILrd~lo@YN_`}@a%rmV{O3o{*C_Bup1!tQZn|j%rg-`=eR8SOpnNX(xVV(LPk($dC zK(U+BIauKBAvJV4Ahn`F3nb!j?>_Wv3Dcb5*>(A9(`B)ZdTDyqcOyQV7Pc`ca*r6B zMcbUrHkbpxs7MVZ)CJB*Z*|jT(j@%i3thD76PJ{FE=-|CKj={<$o7GpYZA0y}3nYrPU|P`x;N#JL~M+RMXeZWP)rt zL$mJxuU`QRngNI@1^!KCuN1s0Qm7!sCwz#ICj}bSaEhP;rHm|ut#Sz$NvU`w(&0-bv)phnpy=iM@a?|6hg#mH91O!mqgSu4yQ(B9JLuZ=B}2J>|~B)gh$qtq~yl8 zj0tUb7O9~VB2}2?Pl`!5XMXJG`VIF*ZT8XbWAWE@*@;o+BTl+9FI}OJF4x<@?%*^J zV-`A&x3&=H%d8#4Z%roX?61q_6be$n4jnyzI&`Lo#|+_X=R2jhp*g?7T%z? zzcxEiD->=1bTV7+iLrjooa?--;GU>mlVZ~!(CmD8_PS4s+wxA-)wgws-AaA-OU*2Q zbufB8f1x?&(6Jx48HP912l$?!?6lHSE&5hBhrGkFPs{i$ftb z7G>zv5~+tvxl%^hej7UV&5>GAD0(r(LOy5FFt9k&VK2LC|FL=7LlK)p!V|s2cLygF zF}dMnu)3IRoQf&9ZOHaAWGQdKdDfuaH92C6CeGp(l^mc=cAxQi(A>n}If()D636OO z{mj`e`gD+*mgcF;gW=Q~&B;%j>#wme7V^*+jxiRGFc-NblsYqf((aqC*~;alYiy0{ z(~q7!FS;0gM|MmImYzHJMuQe38RRvL!ih&#pU|m6YT%N2Hx{}2>e}tL+P+uc-{tm; zx!=}tKK3^Ms1yveoFa2v8Q>XgEN6HaC4XR%;1bQ1d1l(JhrvbzW*j)iREQhRlsKn) zYLdszUib97X&Vo=Cm(J;*>t6@t%u77&@Y${x!S|+v0}D{OU<~6RkNjH`rNfai?)r6 zv3NumjxrTFvCv=;GhjD5SnU|-ZLs1PUrjXSOw}b%T(B|Vxi`MM@WUU^TD-I9M6$KG zvhr+eLzTUwQMs$Vlko}S1-ATqKF|hUfDS4K-6(iv2r3&MDTEQ=`1$HKTG3!20&-DV zkb#7k`n8&!Bw)asXgo3wND3M{qTY?%R`XRol$}fmB&+^O;@}bGrLcGy*^-4UK5>-H z|KTM;jR+J0#H1{ILi%KP(+6q+9Ugv_)Z!-#Nr0L(f08By$Pkr0NduY6>329lc8;mt z$bn&oKp4c6DLIlp4<4B>f%0)A<3>MmBza#2Qd4VcK_KyXt#EGT%FEfE|c>|(NvGTH7iTHF#!{xfusxN^&o?D_W(=WQ;xR<&@_ zW-BvH;&PtlH_;6s94Y0;u9mxhd zpv{5TIHBqqkm`bFeu510#YuV`h0>S!m03aMb5gK?J~%w6x4;mGF?wpVy|nB|#aX>H zxl`hcI0k&&OYcv9O8b8c<5zCnQC?nt_DDrrU1e8e-Q~6xPRSM+jkE`@S%0AY3il;Q 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 T|87W#00000NkvXXu0mjfQ&#ZR literal 0 HcmV?d00001 diff --git a/node_modules/ace/doc/site/images/ace-tab.png b/node_modules/ace/doc/site/images/ace-tab.png new file mode 100644 index 0000000000000000000000000000000000000000..50298c102fd882a2fc6718fa917255c91079633c GIT binary patch literal 2655 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 XM~`vmQcs7_00000NkvXXu0mjfem-^= literal 0 HcmV?d00001 diff --git a/node_modules/ace/doc/site/images/body_background.png b/node_modules/ace/doc/site/images/body_background.png new file mode 100644 index 0000000000000000000000000000000000000000..2101cdfabf781b0d3d9a0e16e52101b66ec3f27c GIT binary patch literal 3013 zcmV;$3p(_PP)KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z0002+Nkli&?^kD9FYbRCTp5NifC{vXJ&3{ev`mXT~HEW$;jD z{^%*4b*g9W%4cHaQMY)x;tP}YmeM%ST70s5H>@3!fl=c=YF;>Z-9mZCmR^r{H(d9k zbRr00000NkvXX Hu0mjfNY$oD literal 0 HcmV?d00001 diff --git a/node_modules/ace/doc/site/images/bottombar.png b/node_modules/ace/doc/site/images/bottombar.png new file mode 100644 index 0000000000000000000000000000000000000000..2e76bf841f8b46372584a02cb8b7c130bee177a0 GIT binary patch literal 1186 zcmeAS@N?(olHy`uVBq!ia0vp^Y(T8R!2~3OIAkJ$lw^r(L`iUdT1k0gQ7VIDN`6wR zf@f}GdTLN=VoGJ<$y6H#24v4 zq}24xJX@vryZ0+8WTx0Eg`4^s_!c;)W@LI)6{QAO`Gq7`WhYyvDB0U7*i={n4aiL` zNmQuF&B-gas<2f8n`;GRgM{^!6u?SKvTcwn`Gtf;oFf&jvGt@IQ zHZeCh*HJJsFf`CNFw!?P(ls=ndS0-B(gnVDi`>EdW6;=wxDOXy|HSY3gY1Vq#)$v4~Pj*wm=R%;iu*SQ+p9GS$};Vbew^KQOwiDF{I*F z&!zKO%?<)=A0qFDMQ0~{ka7{=Rr}}K`QrC}7n@%KRa+kWNFJK^OZLwF?G_rRSMAYY zROnii8Yz(w88$6dtd-IC@}B?}Egt8Z|7E-P#_6}2SvmP${&G+7+pcy0C1j2l&P#vu zgPo`P_O|bR7k=-1e5jenl&9Hnh2HdTLk>p)oB8J(4l%@>6KS-X>vwE@)Y14Co<^W7h$Xk{4j;}!LGd6>w2w>ZuZ+MR<815=zBaR^<{uW zfXGpGR|a{JH%u3z?B)1<6B{n}>&`CPf1fp>q{eC9^E*KLNa52D1wT(2D)cqV+pi;xr)z4*}Q$iB}ub-C~ literal 0 HcmV?d00001 diff --git a/node_modules/ace/doc/site/images/cloud9-logo.png b/node_modules/ace/doc/site/images/cloud9-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..5466cf7eed7480aa0f99797c19ee972053c3dd8f GIT binary patch literal 10601 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 literal 0 HcmV?d00001 diff --git a/node_modules/ace/doc/site/images/codecademy-logo.png b/node_modules/ace/doc/site/images/codecademy-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..e27947ae1cb2efadf8c719a42924d210248bc117 GIT binary patch literal 4643 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 literal 0 HcmV?d00001 diff --git a/node_modules/ace/doc/site/images/codiad.png b/node_modules/ace/doc/site/images/codiad.png new file mode 100644 index 0000000000000000000000000000000000000000..c77a446c29f15bc86f378a524648bb4c382b2508 GIT binary patch literal 10708 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 Xn!@ev1FZ#Rki+itGlO{*(aGy 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 literal 0 HcmV?d00001 diff --git a/node_modules/ace/doc/site/images/favicon.ico b/node_modules/ace/doc/site/images/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..e97c70f6b4f365efc03f9a1cf58ed4709b0b9b6c GIT binary patch literal 1150 zcmdr~S!)wf7`;IQ))11A(3cAO=#K~#8fc=~n>L_XsAy2AOJ9-(p(ZY^HZ^9dc0o(b zgAd|{G%A>aBtcS5Lyge7ytttcB`674lq_@nW?-Z$&Pb zmo*yA{N{Tg@1w<03tq+gQJM9iaq}RW3qxpTPN2CsjAr^MnzsU|Ui0Bi+>LD1hK`Qy zc_Blm)5Y!tP2hQ6MERl@>vLYTS}pwi`WoLC#?j(i_;%eduID3GWKP*|mpodnHm*{s zllQ`Aale$olULARradBmp7V)Z{j`c_=lW2(eF^u;)77;jrPu3|4lH zH|q5|>Wv28r#VzVyu?au0L$DU8dMY3GG|;!kJ@1{7-pr{@;oSpO{Ph3d&QMxjS zjg22D%?I&(VgTjTh*(?V{3u*KjNGILk0TB^91fk+>0}m*C7zA#=Zn(;6lVg+jrZf} zX*+7Qny7_&Zp?)TCoT2xzV3HsvpGS&ZGu+-<%mqWlg=}?JmrUogbyz`ABuz$)p`tu zS;^DRLWY!MG@352-8hc56oGg(c?=fHukNj?8!A;)I3ai%?c6GoGXqcg>&eo_x9 lYx95fFKU1>2_LsG7L~Pq1D z2pP#7a&PWD)LeDuJ+J=0wbnjoSLI$!7;K(>^V_LYr_QkV`mgW%{@=KTfAe*CCjW#G zfNc+c_dJQuexrbw-#iY-6ZCfruxtp6e!_xHub1>Y_<3Q&vIKt${pzac1pO}6@BBCY z9{LdVe#>_FrA64*4*J}Kwq;*PPs~}up0jLgijJyq>?jBjh;$7ds^tgv^KcTluxQ;+7B^nh6&3+8f z<4Vy+xgfCEjL;2Z`1Eu_*Ah7n>iu%<=l%7u!clC0d@1KM3ntzfP^ddT5L{PnmV0jL~wA(GXu2(C;s~1rit)MhoLaA1S zSMg9PxNr)N0)y5Lg;anLnjW1QK~yPT)(%rNyCFKXxcx8&Z3Ijx<-dL~8g%?H*^hU)j&sl@^HHjMsLjow zx_=fEbJN(nV+#AH#;~3w^QA7?r-ny* zo{lZ00_N%oPW1!KO_#A{YZ>?a-TlSpvGv#Xdg*IVN72Ki{eIuI@h9}Q&c8-5inKC6 zN{0G9j>C39qEr#6ZQDkYunV=FW7xNA3I_>{iE5EeIRaYHeyDf<4v%)bw(qD|YV*_9 z9Rji0^6>vMFfz&E_asac=tCw78W`7(aH8g6+spQ&d}1Ao51xj9wslFTj}MWdeYb6k z-zmEGf2Z#V|FwYeYPy(TCY5xhORTF{N>Lu0M1A)Gl($Y`Vzz?IF4=|cWONw>vbV6z z3Xj-&@%s!6J$9vDe12Ulhd_v&6lC^80bpK`n%@%xNNOGzJQtU3--0^Xnd)eS{)Gqd z#jh>m&;uvox1)>Z*P}md_Tsk}UGaYUsL%iZ77V)HZS=qYKos_E4ymI;QKC??QJLO{ z`i^}l)Lm>PBYnk{^n0~{zMs&}m&9gyu?6VQ*y>s+TYB+%F=MmPLj9KkAqW4*;QtyP zqOt^tP*11yKLv&qFs21#mc$x;@K~{i<44cpLgzGYe)9|-zJ3gUcH5J<^Wjx2cdToQ zuJxIsBY%&+=ik%Yn%}84v%Zx#d-i$%^nJ9lUnMtS07S7|MSbg)bR2+JurWhGTzdI# zQWX~Zq`#vmLX{S0id0hFPO+W%y+aEaNqvz2K!@4Y^n1+Dsh_;d_2WeS4a#3g%eS&oEHisOZ0y&4J60xM2 zt56=@LW`fGRx4oNMcXtB@(BoHIWkFL$pmArz&2t+wgLi!1=dHZK;Q+H=4WbvO6hOu zVA16U0J6vA_!%IEU{2A-Xp}rOX2)>N4VS{7z5qAsp1qEvxv|s~1n) zT9_1NubzG_?!-vQr-{j{cSc6wO*lHRKoXzy=sP1#Le2}uFT8HMx#;sBw9{WtSN?y) zcG^;ikGRAkzi`;Yhwdn=PzZg)bLdNMBe1SyARJOX3`U_eg39;>WVA=&5qq&*Hk5R6 za}%`75(R>U27^y>oWO9%sL}^OGUBeK!z)I~OEEOksoY3kH3&n1GP{tDfk8_zK0s%^o6dcV&iYSenl^voAIo@j z-s1&+34Oz@bZoO!_==>07Sk(~NiFRnTTv%qTv}vL#iK^2$+I3Usf$-qA@q_)wuhyN z40dN3Bi%(fPdy0t(XYTha|G$wR!Fa)R#r-5taHHRk2J@mv>MaTv$~2hBc2*5VKqrk zNdj%umpTDLG7Pq5BTQ{N_Y&@Z+{Zn49>FWGN>M5=(b{%#&E*Ze@?e7d5BuBxVr6!8 zfBPt%>(a%}xb>1^CA}@`B<*hsjQ78C3+>YM{D+i3EfeuhNu*zfk!MBGv4#2YYd`(j z5d@Zd1Fi30(>II>p@WGI13|mHRNFED!Xhhf+x*ieLs_9+=4t~k{<%Lw>GK~!;j4dzn1BcmUI)qID07maq(D3k44IRJp>${vqJi<((!oG2 z^&^~I_tEiVbcxYL3=X}ZM=B?kq&7)P9zH5?-(B-~_4BKwYEKh_E120<$D6J#j3DCp z%2qeI^Fxo0%?8r_6n*$8e*rsF7VRj{PvC>dL*tSC!hg1~pd{zM*Q0EDOQ46a(g2+s--*^ceuvZ+@q#27&{iojRVAJ#71`qJ z=j1@8F#ycUGKt946suH@(k{0HZP*Enh&;+(J46t0#I=A*wT!PHO7V?{7Vz5ZYOvE2 z1jxFg=ihtnIQc;qe&eZK*m3p=ROT1AG`4#Og;icD%oba)W%rqa;fOdnU(6gbir<`u z>2BGli=vZENzaq#HRbj2mvt*Bw8A18gQ4Pfl;JMGDO5<*=|a?2ruU@8mLwkz0s^%Y zSSZFmUi{_X!hwfxftU8lyDOoGGQE#%jn&15!n;^-W1vyR1zq&$MWe; zpBzevmYhr~YktmEn zxFuRGkIsSA5qk@qv!K5@j)R1Dc};e3(|x~$OCR|-63azeE~n z0a0d&h}G(ffitHiLv5DqcXKd%k~ya?HHMmj;P6SpaSi&OqicP|^dw6&Nk*F_qs@R2 z@G-qGpx>M80UAjYui76WAz&8Q=@V(Aefho)IioFHeg&ORyG`1nN1xHh^Dmu6X{3Vx zbl)iUoqP~`cUq-|ue)2Td+ZxaGv41s&7_q^Vvu_|*J1y=%geOL(K(KAEb-%Cll{1o zJ*VsjElx;m;Uc+;Ig-M^UuYmoi)7qv>>9Ii(KHm>Y>PQ%z8DNklCNUAu8w>eyhp#xw|y+M zeA-Y_vA&T?0jCz)N+reg_n3Z0K0T%*pzChWui>c&4&mC_CO-aK&xc!{!WZv4hWGyF zmk_s3;wvBWQMO5P*cMbOa7HH}s=M&M-(JR%Km9y@rg|6)XDwX%?%mk&eOvxV^R}=2 zP_)#dwK=!1ZU4ljMcUbNHCm(=3{v_E9R~bppz`8}U5hKJ}N--X< zT#P#}|4HmVumz5557WKsz~HCQi~*U%oA6W4=_3&6NjBC#Jw8q~KMz1T;X{T^z3K+X;1hw52Wl8(%A=-4YeY)7N-9yyt(uws6 zK%XRv4gw=3G4|J*SbXdR{J!3O971pk1Vqh7foz3KQg+MqTVY@MVvLWMjGfRcEer_K zTf&wxeqW;ODiapFl;HX+>-fNzikLWk1Y&U& zjSFTl`O>-TU`2msH)>6Lj9A&`|9upZ#15KQmrbrHR#DS6u1xDCMXTAl$LyN)}DhbqrMF!eJp+X*SQR1{a zgU`(U2xc$ZNxIw_NW~x|XQFb-Mu=QUL}+^u^N~?jWKX@~(+4=%^F0@p()P-P^!;13)0A#F?04?)NHvL#2VEh#6mReK z(+gTH+9Bi@Y`=bl(5)izEdf+c= zxFuVG;g&4Apac&lbGU!s8?bHHIBZf;B9n|95W`~_qsnp=aqcni_QCV?eaiRoY?APV zNP>q7?eunsRBxRJ3B*LP_H zt{)a7xKR+3S9a&VGI~ zpR(V+)loYoe=xHRLivtnGuh1v=lwS}P@k=k8WQL)^hp}%0=fzPjI>+DR#WI)s8R!o zRH{HPr$ZNPX@;u2ZZe((u2&==NID!^B#V9qPn^W@i7OxuUWSsBWr?(k8h8_#?Z~78 z!wgwdLy+u zbpAx*9iqj@J4oA2yzDwsN$nP`Ao&`#5~EXjT z`1(Dl&AL|Fi>nB`w_sBk)c*dOgwIAfcl61qbvo(yrJlIpl2-%Cucz-6`qK-T2OYE1Bpb9SWVdshO6yB>&Pm`&wc}^FS`-e z)~)1$rvvA62*S|M$mnglDJYmlWwnSKz_fr$N)^hQi^ z0}iK<8l|1@jMUIwSYaoaE;+*e53J#PuW`^AiIi;=ZV&bdF~xKnqNSsBz1pbTv;m4l z*T-hdxaF_b@zU!n7(G})+7r8_-}#ti(aMAI8jrn9x#8%M>z)YlipyRxa{1U!l87dG z&1Xp>XeUWRJqZ#e32EjQ^GDH@rm@a5#*{*`O3>=R3q4dw9hSHOS_gA{N43Cu%!|xM?9? zUsTe@nt-YK-Z|io!$f?_3HH9IinNn@$-?@vnhCk_N-|VN?j4519%TwosU{B&n)FX|$SQ zLHvHM)+>6LI{9_%_>ZqeaNu%?@kzQEGNKOIwbCd(PO)x};_>n4!EX@#-M$mvwp}VQ zrEN$Si_$7;==>Q6FdYU8W0N`Lg=a$_$J(GPFFazV1fokyrZFpHio zz9B17qSca;h)9RSIDFn)ZejKDL&RdqYxZ2!4jh0}t&y>IQK(jM>z7Eq1a*!oA>pVm zt8u@H;w%~au@R#DWMgVO>HUEcwFBFTFsRK*Ut(KRGI95$O(q0=bvTBT4vb~EwESKn zl5t5F6E-ztVtG~ulX*0YY>}ma^fftzl0;A?iOfQqyqylM8flPbwJl+?K9&K19!taH zwX~|eKd{wo9uhGuzcHoKilXkBtYUoo6y)SSEG%*WGcthc&m4x)4UNymuViNDEMrqr zp(G+UYKcK<9zBWGCk`VZ#$+EmhSKaT3R||Iw0|FM&}CFcD!A{^A`Tz*v7gSxZ>}I| za(uKvs;r6Xexk;oUm(?0qlGRJ;pxzoxhl^um8aQ-RjOPlqvqYx(%}&&T3OF)sj;-* zdn>CHHrgS1+=BFRYIZX_gTm#wkgW}rsb`SsFea1_;0<+)eykv6oY?FrQ1pA5RehCcJXwF|tZ@4_=C`ul`}|_~;T6t3rl18u}il@IV^Xlp5bkRf*7N zaZ*b?Z)}EEt-`2Tp;Z&@fYymKr1y2%c+~D7eC#pQJdbw#IJ}uzIIAmI@IBo5U=#aa zQ>Kl&1WA&SlJCS7`J{k|i4oA<9=xe>#K%|QITame;q!~yr1q+Fsb5z49tB3Yu$+?& zyw$A~CX%&SId!a#R91pdIHnV}HN{LB43=@eh%{3<=?1zv*v`t#NWGY9WyHYwR42tk zPTnayfoY3qBB=+|paplz473mGW<{ewtuqJdyTotlt{GTO=u*ZC{Hwx~_Um&4;K$(E?2v}ZRQ0wN}L zBgiV-oWZ2?yyNR_{P3#_S`BlMaXnPV-g3zc-{qpWw2s>LI=Uxm!*J^aubWcaP7y(1nvvaQW2$?ba`T z?iAkr(KYmoq?gHXbBxKdv}(eJ$ZeK>l{)@3I4mO>sbWn!Gy-L)`L&&eC3I;M@Mow# z5(b&`;>#=OKKTUsT0NzX3Z)VrJ-SMaQ?p7YJZP~Ir)w*bWQ@{!uag86X5daaT0LjX zlk}k!@kB;wq{{RS!@1Ylj(sqh_eoD%$}sbXt1KU1praivrJ|zLfHSlS+Px6N5{_JH z%~0Ft>R^?j&|vWUCk|{!<3&G;%8psM(+#?SvZBA<_BlHCle@f(lXpFi-~U1%fAV!& zI8t5PcTb?$7|{!vqyyWefJiZ*xzf;F_NI9uf@T*!Es{Gv2CGt45);R?cJ+8Tm|Gs<6RJ^Gjq0??O9Tc0=Q@=q=cEUx&Nw1oN`4zVO{owO44#l_J+U2BOP zM?xnERMoa7I3!^u%dzSFeZNTOD{|$Xu6PpyC<7gnu1HX7sjyK>P;-Rx+6)L zx~E}+2e}mJAkVPDffkzTDk^AcD@~tOZn$s@bRoR}>CvZ1BFK(ZiYQIg(K|7Zk9=+w zfABy7$H=Lwmu-w~oj_yHPPnv~ktsXZp&4U0Oa*jetT;zi*Pc9%h?ybTn3xtutggc) z%F1FXN*a`eZ6uwWJvl`{k0DxLL(*v(Kh~6w5@?)K=CY!-C5s3|7c*O+Q_~8J2oA?| zL;|l!-$VA$A|{x$o3LvhI7h_3k!_LtDT-t%NiEp)d2EpBb1S5`Zj`HZqU4b$>#=qS zvMW*TV>(T#3Ka%^#E_}TT&8^xPs$t`ktML901%F)Dn<0cHo_rQMvmo)J0M370{tdE zXTz;}`1BV__|2~t@U^8f$`uzg+iIwiL2T^YhVsM&*?FOL@X%v58zifv(o8QRni+Ka zw8?^DOsmyKe|ePvh*8+K1J3jo+S##^4hA*xeVq!(lIv{zX%P#qjUIXA{8SiQIJ*$y ziY@7Y(np+Xs7TlameznSJywz~*OzI1Ev2gXvq(+FtM`nK+0*fLqT0LFf$E9FRaSx> zSqz7nk_vZ3u@Xt>(gMB6=|&02t1E$FP17(3VQC>!Eq@Gxr2*hzoTH_Kf456y1bZiG zmw2d+ZbOF_`Io;~#?6ma$>%6zX6GoXWYlY0r%)ang;y@A9UO*oQ}jT8e`?5qu8Cls z@1V4OJNip2@Ryfp2gizpsIpK~j|K%U7pkl$lasU^DjTf!a+3O;lh(Cf;QVyuV0x>g zbek<+h8Bk%=%iZOabo~jMJX>Ena?29$xE}-6~cpx-F!xF7~r!^*h4Kk?Wm0hflx5O z&}-~s2?cK%M_beQw_ljXT}vfQPK}_kYZmow#PLT*Nc;;5R27LeoH{dr*$$D0NTgw? z)Gl#nwcw&$L2*Y}Wgx@(1s%&`P&h4n;y64~VfNG(go|gbkIz$d_Z&-;Uhc=0m zRcFpDlO&wR2j4e?&wr*!2An>N)RtWyCGs(W_Wh5kfM!~jDw_!r>b0@ydwmx&?2_7| zzmr4l_w4K3HP_p@+q!@a_%vDU3#B7M@)?d=))RRDPj17RFCC&qj$zM`i2obR!BbKmYwx%!kt8AT*r~1ojON{CQ_NzDH(&VijjG- zQ^kgak%YldBRN7DXiF`=aJ4_d#+q4(Rpg6xmC6BA<$g#zctiyjFW4$D7H=hhYD(WH zX*2)_c}Wi4DZz>6F?Xn;^Pcfq(Wa;(k|$V@%m9Z!`uuWuu$w1p7=8=oozw77uhaL2C@A$1>*!-d*Jp=H-LO4= zV6lQ1L?n&0L8QHFE6FTLl}wxD$k{5&%E7=W)e8^pZ7VNZ3}a5LR+MITEaNj65R6nP z%F2>Z;KjF9#*DsCbvpIiF%}bM+(XMu4!W?Ou=Ay@$*KV9glMs=EEQzMJ zTx<}Med+hsIlxAAb%mV7Ddp4&T6Ed%z^nKuZX;)O=`8IE7g_XC#-#qNzWSbkRM?}- zHC#+^hI-`CrQ#_V-r)WT%%$>1*)XN9!dp2R>qoxek9J_ zPK2fTE*9qlwAUk5q0TAIpsj2C$brS(J70*EJ^Rt>Tlk(!dwAoe>-ejO$I&Gw<5h|S z=aN6)5*umrhB^f~>~zh}J#MWdSY1`1DOH>5dg0XM;s-F-b`Au9KU{z$`8N~ zIAq_`U=TABew!A*LJRIIhcfLoQQcXj4dsx{u({enNrpTKBuI}6Y3-H1_P*0t?*e92y0KB~V`->uW*1bJ$2RG2<56=8mFuBc53erzIC<2^ z>Qbaa)BN6mE`$wlk(fk~qcwc|;VSKDx`=9*uA!#=93u&- zu^9^ZOIdvz>tQ!X1>LsWD>)Sn_@7wG1Qh(RgT`od{M1tjN?Zbh*)hVW=-tGb4eu| zL9VjkYV*4qSEDjJi!z;HOp?If?!5~IRlzZ`FH)XyDlH7_)WiluE<`TJEAn37FkWVj zPm}#AlLL1G@fxWV@?~6lE?hXR7}c?(geXGd%@*(l59-c z@9XDz&FFIv!H7MbDBm=t8rxTk~s2x|}9Nl^FtoTpZe zJt%MCED~gES*M|6oq~3XwoZuAM&qJ!evX&0*O&PE39^TgjcwOWV*D}({rlDy9b!H8 zsOMWrpSzMgElO7IJcJlfJzZE}WMvZ&P~I`nT#Z#_9*sv>r==sx2 zz@w)ND2xld>Zck+F;5{`^N*8ch(f~sYmppMCd*QxWEp36L-TW8s$ud*Mnz#z5l$*9 zh~al*weu}AE3DvY$J14;D^=aGj9q2K!5h7Y@tKtuAg&fnDUTSaA%S5vVMb#ILCJh9 zN^A&*AeFf~z5Hk#gO-Xpvm?lLSbU8}#^hl9MQVyCjJlG;(6sVVxR->ayy6f;>Ty(; zYir3SmK%t;Rg8m=Ay<>I!yBszL*kpl4SKKVO5Asty!6#7KKS#8aq-@hhz@gzULI$& z>m;2}Cz2uzP9&rccIiSL*D^T*p)wjOnV;3nZ6JyAJ|oBz4tIR=A(DSDF5m%!-zs;kLn&zd$_nz$;)#XG{S*~+hAl|_tIM{1#) zac=v11@HN>75wCDmk=N8!CwrzBoId&vic)QU*%CHy-8$jPc?whhj5?7hP^k~tzsAt z8WbOBF|>5YEf-#^Lyg2Ewc|MquBi;?$SXngvy->MU#;P&vl=0!HS zb+ufMqOhD1(=&;*r09BEwmlIUC&!BM>l1&Dz3oN(LGN{Fi!v%!IP@zr$;h<;{hb6L_dKh54jGs?vf>3z7P?lRN8(xni9B4wY*e z_$Jv;Gbq4Fib(bET=3Q?v$Gap>vV)Fsi|niSD_;zxG!Q=hj&QbJ5|yPfgYcs%8??S z!e*f_lA5|Eb3#-gQ4#{|8*{9l{4XH{p)pBBb2L zOj5#}+%mwhBT9a}vhCAY#v8o*@%s9`xTwC2YR!RHC)!%A5i6`BD%EhNTf*Nw*1&&# zWG@!2DU?L2K(NT~;3%yK`dSKy?XlWEZcteojD9D@+pp{3!BP|3YV;Yhr)!T@F$8(z zs!f^8KcNDsNiXxqIQXd3tm-p~5;s>PT`Uvp5D!V$mstRvutS0u$}iH(Ud1fPE)R8X z$Sqcpj?89M+{%?|s#m5WLq^q=dY;}1N=A7Atj;%|Fb;lXeYYqE-f04NYJHPOcb`xLG(J&czYAHmMz8d9!2EL7nW zbqQpdG(m|D9{gFrww+b{KbPBh-H|8pQ-9vXo$GU`jn3%nhy%oDkC2L3XPGu?DIX>o zRyr#0x!cF(J9{|TSVO=*MaM_f(rU=EwK3&(q1T>C;$#mZ(sxC@yA#t|<(OhK6^^$}0RsC6n<@|70ypFf z)y>3~#^ppjGYzJ=1P1qZaokK9YR(}?I!mX(WQUQQAl_B4s6339mmb1mT*v8T3@uvV zn&o5KUdNQ(L{UTpkcTcO>;vu@qiyI15ac`9y`J(bMA0M3_Q|s^ z#r>`AD9{d8RVjSLY@_Urp^tpric5Of+a`6mbG(C#_qDLb%|c70W=L8%vd!nreuOIM z=2~}O4z5WtDUM%RIuxJs2Jh?du?j2|@*!gIk1NK#{>1uGMCmel)knyoxsE%LiWOI} zA+D?o$U(6@&2-f6Ne!>h)y^s}+2S5O8>PC7fcQ827TkKp`3##x)OB^ol1C-LLYIf1wR{Wx6m3)1cylJ=VFS(ic2Wc0GYVLAvPa!@f0eAG)l z?44T2){zinUr7mhEs_EZWnu4h^J|!b9 zgHGI!m-xczTpr|;;W0gO+|z~4B!Ye?p#^qy<%1N1rkAYhLgYvYJA#F}2SK}D1fdFu zxx^|s(Z%e>E?OoVOKOV%I)1!|vFRd4MjbtgGqn_D7N)$1m0he%tZgi}G_ff|T#bi5 z4A)pnYPn-IT%d(+-UV;8On_{Ge4>b@$42QzSLm80Qm^*db|kGuT||%--(@z#%&=0r zz8B!a16}NBw3QHYE+XnAYS%jiEQdrm?VzF%rtpt72nStRC1uSD?1MyY`YuQ6m{vsl zE5awUP=}N8Y&wB^)LtXB!!CUZ?O3LAeotQD?!nQ*7T;L}T1Vk$nwv#$?8tEwQN`UkszCGMh4` zlV0qsv!B!N>Yd5pKeFDyeNRpCq$I>-&_33_lB73L9x>;;)1;5MrM>VpO$Sn;9c~?$ z;sg}igX=Hp(PBlUU8Q11VJB8}-L2Bg`mqMU(eFzlofS;_CSWLZe2u%lR7aDEFp#u= z4Y7D|(4V1@*N-2j3p-0cxAfN{lqQQhu}>f9_q25Ij!^jvq3eSEcVu8I zU?MWsP7klXf|yq)Q9GK6PE3!T8mYq)FR}?}npsLpQcTmPDr<$VCtwr6>WqV@3Zz7Q zWH5MxJ<{b|Ma?_9Pc*FCPEoFDwbiE`p&BC@ZO(&B{lTd)w3pYM zor$_G&qNq1`lwQ+3_{jjM9x=zEXCZ87>_&=sfAoyiU3CZ`bT z2r5(MYB9w^T*QZ0FTbNdg7CfWSF_Vm#Jtesi zJP&E%>XCrdRTvxXE>%fA%vcHTI=%903wM0US9xLHD5@Erz9;mB>fK-##{P|EWfh|- zN(551#B^BTAJ%4ZbMp$Eb#}n5*GV#UF#{QgTu5CGdKI#wXb!7NhYOOsX0z}hlNw30 znKD3Xc4VxBH$A_jTImwgvBit()o3G>xnf@@&{W@IswXS3r0D*atj;Vm_)-)@-D;fi^upJ>4*vT7!l~W&0vh z{VaI=bhtKKM6m4zbg@S_NygJAuz!qDetnUAhUQubhj=s_-!AQj4xw8qX>WC9J|Mkb z*1TQ~0=9H}vF;Aj`rSO{32kYC3!Z7mFpW&oK@SZ}4sW=LX$voSNe!RAN8r$!jj2+E zqQhhAEHxgfXBV(Y9`=c-hC{(9j>HZ0#RyQWs);u2FDSJWC0RVz)VIlD>8UC+u{90P z7yzHh2!YAY51;+|2?D03z-d$#@DndtM}Ni8*vT1k=!jL7d+-i!9*$CpKel14m)<6{@rFtd6YKv9P4Q=t>G3go-wt&NC51v zD1FXe==e;Ga^2Vt%QALAlNUZQE2GU>fRR2lN1|N8tK z?mbmOy%;01T!bnf<>*2#?hWT%TsA+Qg7&1D&7>JmvP|)FqAMoUlooEDuR*p?0&9oW zWH`l38+++9s%FJVtyQMA#H_61J+FQe`)W93V&(c5dGO2lv- zRGUPt)l7)(xL90?u)07Lxa#Ns?&E{Rn>idB?E2$f;Ec@1i-L z>qe%8>>m+^sIQZK!q%ifMO3%|#7_neYGxM`?u{gTKJeJZcwvd`aN0-ZhHKZ|@w&;w zn|V`j9TDdmM@m~q{0JHEQb1o2M7o!onOBdv^4LTHZIT$j$J3h~VmvuV%}nCYchHK> z$)T*mgAKj1%9hC%vd3+q>`J_T&l;_Hg0C-+Ac`tlDpYTejbT&ZFoq;}8q4ydx^j|*T+?hjq(Vk$eXiqrS-vlkcG}2zlefubHayR~)zYOd z^@cMn!>?)SnDW=u4-}&qg-Mu z8zjSvzi>D0o~B+QUU(K;+uVpF_Vx4G$&y5kReJd753S?9&!5Lf?-JNqTfu+*-urQ& z)&i%#j~~O< zcojR|^~P@Fiv9mS_5D^>7{`YrQ+d8A{~tt{ysKDn#yL6DXXzkS<BOh++By>8&wnhzb$e1Q zomjyi-?)NCJypZ%R~K!RcaX8&GD2#m#|Z+&&A!UssftMe_H={_u`V8QXPK!sQkB5lYE!b~m9=rIB4+4VKPQVsHdDkh z)%{uY)QDA(SnA-KtAcJS#XYABczm7IWUx%{D?_RRY7Pn4l<%M{tFVTOH|r}`K*f0O z4g!|E;hW#q!wYswte%O;)krbIGufMhn45*__6j+5C6!uDV_St&;^memWTtdT)r%E9 zHEE8`Puw@9p{Yu z%-VWTq%ds+!WtGeh^Ni?61jd^B2i>VI4||ca#2aim(Psg@H)}nH7+tHirPP^hH{y^ zZs_7O0(-WWkWo(X0~e<_x@uwnju5Xqm=Jx}rA6&EEiG=@Ms>=AJ6ceLf!n2}qf3}N zht8PW+v!RXZ)!pT5|b@q>dLGsE70bw;xF9&9DKC(I=n$Xi1)qlUOeX)Uk}G}&!&O6 zgjD{@(?$vZGhpxn+++)JYe*NjM!rUm7M@G^17A-vQ$ep(8|a;LMNCh-W?rmz+IY|x z5BOr%p=`FRbLA=zZV&6OG8>~sUv3N#irnlqLx+nb(+;`&KG}}Nu8ot#@=g&3^IfRt zRM)7>AV_R)NbGE+n5ya7>uYokGu4qO^ZEf)gi5nz{(qhm(bBUW!j0ox!{Ac>}JVbMd>c{cBwPgWG7MG`Mr= zXGO948#u=uw!|kV|M^>J&|-a@^zsk%h#52ksct~Tfb_bNZUL}#5RoT7@84I(NW;}$ zxKTeW9X!`idDNE9d$1>+6~S3qLENC}M&_pQY@BGDqbjCzO{#FYYwL0#-5!!%sOik5 zjSvs&gX#5r9}cpCJdLzRMwfd=isUaj<{TC6<}@jHUGda5l8*N2wn+lg`^zqBm+VpP z2L6##h)9J;eZAQ{JH?4s5pVw7^Kso(E`Hv^2QkyHZM%~I|u{HKQyXbb#3C1l` z_A{9by@f9FUfS_nI|Rr&i8T-7;+16yQSl>-^BxI`MGF^PP$3&)tEI5atS)vO2N%mK z%oQ6;M1>eM-YDnY7Q=$)ykz7-8MKhep~tHSYz%(4vcFlnelMMl`g@1H~q#`o5LaO<@pX}_y*5?%PmRGIo zg1}`Jb%^7z_|i1>zJ&AKcTRkK@)?1_7jlzli%)X+X`Q5_#Wg{WrKi%wy1t4RF(g3B zbb$x3|6a4%C%31misOo{gQ)8ZPCALstpPLEb|R zg$#8%S)G$3Ob}9+qU!U}zpK4QPORS!(QifSa|+WH)GnS>^-&Rzj$Le{^W>^B>U{o% zF*5uYlu=2v@y@XFx4lPR!>&GSI`)642qzQ z=Zj$qHk*;C0 zHMBp`j8$~D^Z25gWm}$cP}%9BJWF(+2hwoSK~KlVRI7v|K1jRrr+9klKXs2L@mr(M z{I*N1b;m7n>x^f;rbQRMLcBUia}zSTIGzAur;q{RF!!E4B~)wHz(ddG5)O{dcEcJn zt%37sA-ls(u2(}s<|Ra$ft7Mo6OGUdqVDfYswL`j1l3p78d_ov)63K;+cKLy=?Gyb zq}}eJwzsCFf~h!9E>)5MA6D2zfegOO*T=2Kkl#r>23=}gx zA#cP7EK3f68T9@eVB{t{k_C1K>d%&g`^xFOHCOeB!NdlAF4B+?Q-%s|+zAxxs%|OM zZZAU=9hLLf(|Cje(iLmUrl?BCL>Fqnv|=-buMtK5%HjBTzVJl+o~%Li+YN@|jF-7$ z?*FY>pRTyh-W3H%JZSL>W1TH475G*^mP!<{7e2ei!_>4lP*1|xhirMV-dNtMU9UM1|Lkn78%X|SI3gPv^;9xkGO+JfPPEl@HC{Gm0 z@zarLPOzo1p)YDowT-0JBEOf>_TES9XJ|%+1Ijj%V?;^m(9Tn^YIAGKc4dDaC;t z_TXWV$R&8h|+F@meJ2h!u1CTVMp403()ppIzJ3`g7N{M{ahGI@U2)|Sz$8dyi z7s11TZFS=-1wxRuN0=rPGYKf-$Bk7lakIra-1;IgKPy<+8FOBT0imfiv7JIo$LzH-gXd^inUa(L)};^OpLdj zsUN9q#2D#jj%$@F*?hQU;6G@`Ya<=DGCHd0u-xQZ4DT;vnM#sDca<16T&nu0+$`Ne z>A;5YzCKaDaa_dBk=*p@=vppjW|qr=OAmi{Sbp~Z`%-xG6N~9#vspRq)G}c7q3@WS zZk~zut*WUE3|3Q~5ko#o9ND=$mS0K+t{x__(oLG)b$6i2r7 zFcwx_t@T)iC)nT@h`FcB7v?+3ve~4m zk&4KG5FxuSeg{y7^xd)J<{EVLyJ4%E>582PvJj3eEOpg ztTi7o*Pq=bf&mErCBWDWh-)5aM`q3%4><|@W!q!xz#6$X_fzdT-Oz`(L;1#;LBnE{p!#usU>w=&I1fy`Q$ zb>X(2fllfu43OBQUK&V&d1ySPMh8jz1b~gjSlA^Sc z>gq|A+Ts`&1HcQ^YjbrW-$E!fcP0>urLh{*HpCj_(*?3*Uhal*gFZJi?#U#6RFO2_ zIfhF_iTlQaR8b*Txv5f})FplQ{f|}f2ajEakMzC=OP#HFQS0ltwtN)352W~_zw*G( zes%E=N#OfA5Hi)|8(R^W=j1a5Lwpm|*51UZc(Q#dcVy3x@Z-9Lt#7GY*T1G_9drnd z7U}Fj&5$yqS2NaW7?Ez|w^WU-YUmfH4_j5Vr|Jg2E-{8e(bDCgOrzb*-pWCgR+?do zgCX^~!NNNA%hi2S^+^o8aQfSkl`8)G@yl^8pVuWKD9$`&miGH{*d@nT;?DUp4HioCBkp14RA(;-c99!=u(! zmzTtJ$ocJ9-&7>cCf-07G&3Sr*8k_|!e>@%j)`MQnblmeB&AAHoGf!_8_~5f$j3{Q zchCOLi6hO9Q(g{pdx+s>4c<5NV{Oh0X|HExhrC&7w z^vvS-HvOJG7d#tU`_10xUF40nS^Ua5erAAV2bpAy+*q?NeAAe92^siWkHn*&sQBri zG6kkvNcX@=6~N>4u5QlMt!f!Cta~ge&HXu2?HF2S8iVl#)RZRUr|@$e7FRxkt0t;w zAUyLs9VIta2_mNDmT>UonWXd4yMlZF_`&$jR*bV|kvrzd1CjxeS5fIRm5Of`jJ&$a z04e1_sN|%hngb?#?2${+c-^RV;Y|(ezzz>pET!I=DCb(RxT0I_YLhAC zoUtR`yi}VCblYE|JP^ie~G%Si(eybtv6Z2`=t2;hS)& z>?7a#IFj+3@9E?O?TDPo-#v$l^37{wY$VU$aWFPhT{j0x zCMD-mU)kf50nbw&yoLG;>(<;W$E*Wa)Wqy4S^8!o<*}Y@jyouiIiyIq9+yi)O(BD2 zn)59lro~w{+Sz3zm!KbGB`Kalqm0wWFmO$*=4J)gG?(WaoF{APFex8q-4ZDpWj zUV32@^)2OqD&=0|{hshpn=4r(+X`sxDvOaxPt?Z? zqR8azw#D@DranM{X={%gvsKUAEzlIHEw5nQtlR=YTlZjV?DkYT1$Z zo;N?vhd92iAbcmlI3FlhZgDe@y|5|1m6r@}(`%ia#MwCjtWC9t`9gYujrUVL7Z~9= z0Ld?Uxal?dJC>&Bn!@+p2*$ZU5jneJZ<3lkQ0}JZoZRcJ92gd!ezR9>Qcd}v8N=Bu z8F>kbHZ6RVTl{3x=gIHnf_pOhq$xs=YQ3|&Bhq#Sa9)A zNW!MZj&n~`-L$~zrl0a0?~(tj7vsC(pLmv!pF!Q-(;mxz=5^l{7ysS-@7r~r^1JyW c|EB;00B>yFu&6@@W&i*H07*qoM6N<$f*H>p4*&oF literal 0 HcmV?d00001 diff --git a/node_modules/ace/doc/site/images/fork_on_github.png b/node_modules/ace/doc/site/images/fork_on_github.png new file mode 100644 index 0000000000000000000000000000000000000000..e8ddb66e340432ef8dac0489c80cc5899f978468 GIT binary patch literal 18528 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 literal 0 HcmV?d00001 diff --git a/node_modules/ace/doc/site/images/habitat-logo.svg b/node_modules/ace/doc/site/images/habitat-logo.svg new file mode 100644 index 00000000..986c3687 --- /dev/null +++ b/node_modules/ace/doc/site/images/habitat-logo.svg @@ -0,0 +1 @@ +Slice 1 \ No newline at end of file diff --git a/node_modules/ace/doc/site/images/header-bg.png b/node_modules/ace/doc/site/images/header-bg.png new file mode 100644 index 0000000000000000000000000000000000000000..aaab9e3e0af757b7921d30672e5ff8a6ad1025bf GIT binary patch literal 154 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 Am;e9( literal 0 HcmV?d00001 diff --git a/node_modules/ace/doc/site/images/logo.png b/node_modules/ace/doc/site/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..6af129d92ddbdb1690f2f875e9768d771bf56479 GIT binary patch literal 52537 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%0AY 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 literal 0 HcmV?d00001 diff --git a/node_modules/ace/doc/README.md b/node_modules/ace/doc/README.md new file mode 100644 index 00000000..455a1c05 --- /dev/null +++ b/node_modules/ace/doc/README.md @@ -0,0 +1,17 @@ +# Introduction + +The API doc build takes a look a source Javascript files in the _lib_ directory, and turns it into HTML output in the _api_ directory. It uses [Panino](https://github.com/gjtorikian/panino-docs) to perform the conversion. + +For any questions on the build system, please see that repo. + +# Building + +In the root directory, just run: + + make doc + +In this directory, just run: + + npm install + node build.js + diff --git a/node_modules/ace/doc/additionalObjs.json b/node_modules/ace/doc/additionalObjs.json new file mode 100644 index 00000000..dd734f78 --- /dev/null +++ b/node_modules/ace/doc/additionalObjs.json @@ -0,0 +1,27 @@ +{ + "Array" : "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array", + "Boolean" : "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Boolean", + "Date" : "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date", + "Error" : "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Error", + "EvalError" : "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/EvalError", + "RangeError" : "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/RangeError", + "ReferenceError" : "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/ReferenceError", + "SyntaxError" : "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/SyntaxError", + "TypeError" : "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/TypeError", + "URIError" : "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/URIError", + "Function" : "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function", + "Infinity" : "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Infinity", + "JSON" : "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/JSON", + "Math" : "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math", + "NaN" : "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/NaN", + "Number" : "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Number", + "Object" : "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object", + "RegExp" : "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/RegExp", + "String" : "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String", + + "DOMElement": "https://developer.mozilla.org/en/DOM/element", + "Event": "https://github.com/ajaxorg/ace/blob/master/lib/ace/lib/event.js", + "TextMode": "https://github.com/ajaxorg/ace/blob/master/lib/ace/mode/text.js", + "KeyBinding": "https://github.com/ajaxorg/ace/blob/master/lib/ace/keyboard/keybinding.js", + "Cursor": "https://github.com/ajaxorg/ace/blob/master/lib/ace/layer/cursor.js" +} \ No newline at end of file diff --git a/node_modules/ace/doc/build.js b/node_modules/ace/doc/build.js new file mode 100644 index 00000000..2b1b469c --- /dev/null +++ b/node_modules/ace/doc/build.js @@ -0,0 +1,67 @@ +var fs = require("fs"); +var path = require("path"); +var panino = require("panino"); +var srcPath = __dirname + "/../lib/ace"; +var buildType = process.argv.splice(2)[0]; + +var options = { + title : "Ace API", + parseType : "jsd", + linkFormat : function(linkHtml) { + var href = linkHtml.href; + var o = href.match(/(.+)\.html(#.+)/); + var c = href.match(/#(.+)/); + + if ( o !== null ) { + href = href.replace(href, '#nav=api&api=' + o[1]);// + '§ion=' + o[2]); + } + + linkHtml.href = href; + + return linkHtml; + }, + output : "../api/", + outputAssets : "../api/resources", + skin : "./template/jade/layout.jade", + assets : "./template/resources", + additionalObjs : "./additionalObjs.json", + exclude : ["**/*_test.js", "**/mode/**", "default_commands.js", "multi_select_commands.js", "**/test/**", "**/theme/**", "**/worker/**"], + index : "./index.md" +}; + +files = [srcPath]; + +panino.parse(files, options, function (err, ast) { + if (err) { + console.error(err); + process.exit(1); + } + + panino.render(buildType || 'html', ast, options, function (err) { + if (err) { + console.error(err); + process.exit(1); + } + + /*fs.readdir(options.output, function (err, files) { + files.forEach(function(file) { + if (file.match(/\.html$/)) { + var outFile = options.output + "/" + file; + fs.readFile(outFile, "utf8", function(err, data) { + var otherPageRegExp = new RegExp('=2.2.0", + "asset-smasher": "0.2.0" + } +} \ No newline at end of file diff --git a/node_modules/ace/doc/site/images/ac-logo.png b/node_modules/ace/doc/site/images/ac-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..6ca069a37c6a87d6169e44e37244efd024f1eebf GIT binary patch literal 2662 zcmV-s3YqnZP)(_`g8%^e{{R4h=l}px2mk>USO5SzmjD14Z`WEM zkN^M)>`6pHRCwClntN~+)g8w_XLs+tNk|B=gq|s6yr51Sv2*f~=d$W5_|JdJ! zb=lo}ZxXH3@66`joOA9uXV3Td-c?p2K>!v5mB2Id|2Ke}fxW;qpb3}*^aWM{&jS5{ zdw?GTHlSq8GGGhP2bd2u13vmz%tmi+@@CzDM6UQeda?aBTzFD z^KLn?wZKXl(+IpGH&FoG2Bd+{$y|OiX2=yI7`uSEvKKGL2!T!hADm9AAp^>rN7gr~ z+FggO>E%WmLxEv{p+G5xVS!46QlQWnhJs*1YJkUs$oQIkb`@#g1?(0Hd_xWm-~`Ye zSPC=%3DKOSXRZUlVL61}KtI6o^pBIz(SQYP0A7-|?eck0<^Z@z_5qN&D+_oJxLl-v zzwdq~0Y4=g`+-vd?ZahnEBzf#nkLI&*0p_7ciCyi?x~5b=w9le(11cKEkZAU6`(bi zQl71Y2-yvQHhgOo0(Stv6jgml+WP}1f$<`l329p)#1uR! z>zpT2_lOYnP5Di4xiTo13lWA*aswNsZGdRpT%es#`V}yn>}VI!SDN`!Qfd;9DblXA z*C%a7%I4|eeN)AKyETtJTxZgdR3vSXK2nY%ghs1R|XXO1brAAq-oe7tsA@LeGh zk)S8#knfSUExiaJJ)X;00e=Ce$m zFO7EI2<|D zOhMtfN0%WaX|rT#pHxBbGW#os>kJx_il!8mcAC+OU?PIZm<>EHA!0u0FX7*`h%rA9 ziM=d``Mxhv*{~Lxzu$TjM%fP9(Fz?xhu2Kal1#QWcuds(319nHB?`&~%Yjaw9K?^Kz;XHB zMXn&+4=l=Iy_a(cZ!;(T0;FkdNMo8RVpzt9sKtXnlX|dYQF>I|gu=KcZb8h{D5cL) z5yKO9&djov8VNy@|B>Fb(P1Y zMFlfWz)~k=PwUX7fWgi{C~NzzRsv3&#jM@U~#27D0se8gczfE49|MYt)tN-Eh1eES5jaCeP#9b7sg!2J2C0nR;mHS- zEF9)js&kmPgV^@FB7Dv#id0hLIJ%`;u}REnDvFGtDB?t(3oVq(k697sCR+(+1MUN< zY&a~>F#3OrYh;_V5s`^Fg0k@Q+h`MEN}VmEUKT-wBM$yq34t$?YQd)!TXG>HqZ#!9 zA>er;orhYv5#55{43e^jAE(4@y%3ODe z|3{KEJfwX*@bi!oM%*4V5A!xsvgENZ+)O`2FKX=YY2Nai2ki zVN^g{17{zGwFVA=GGeS+R?E)qrzz`ZWh3RSd^EyK#^MOOz8?4OjjMBTx^0D^+boJ0 ze@lp2`xov@6s?8(JR@#Ue=^B)&(zYPvxN?4W2*>pGT(&^-16}9h%r-fUw_#rS!=G> z<1N{crwHgp7u+JGKO&nVWsM-L&c{SVU;<#GUF}%0)VJ7BZ7=4kOE!^ zVaiiY7||9c(Vy_`mB{3FQS)Rg=I)H=og*KLv;4Li_uZ?Fd91gAv#;`;Ne%K?|0HlL zZYe*iGLS(}(c-+Lrfg=)kLTp-F1G&?NvxW4oVQRCo?5xN)4qdPo5LJcVuQbcTc#g~ z`VE_OC07*qoM6N<$f*oYr9{>OV literal 0 HcmV?d00001 diff --git a/node_modules/ace/doc/site/images/ace-logo.png b/node_modules/ace/doc/site/images/ace-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..886a8df3119423f1b37d8675855421f53b525bd5 GIT binary patch literal 60546 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

    1. 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 literal 0 HcmV?d00001 diff --git a/node_modules/ace/doc/site/images/modx-logo-4.png b/node_modules/ace/doc/site/images/modx-logo-4.png new file mode 100644 index 0000000000000000000000000000000000000000..a640ef23e45bbe9f8301acc4e5580a719a5b533c GIT binary patch literal 4550 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 literal 0 HcmV?d00001 diff --git a/node_modules/ace/doc/site/images/pixie-logo.png b/node_modules/ace/doc/site/images/pixie-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..99968c46c23e1f03ff42ee96e28b6d21749cde65 GIT binary patch literal 5632 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 + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/node_modules/ace/doc/site/images/repl.it-logo.png b/node_modules/ace/doc/site/images/repl.it-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..bf383a623eedc37e16148baed0b988619968d100 GIT binary patch literal 4291 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 literal 0 HcmV?d00001 diff --git a/node_modules/ace/doc/site/images/rstudio_logo_64.png b/node_modules/ace/doc/site/images/rstudio_logo_64.png new file mode 100644 index 0000000000000000000000000000000000000000..3d402a21a7254fa4f83abd7385f4af405b5a2105 GIT binary patch literal 5631 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 LNkvXXu0mjfeCpyU literal 0 HcmV?d00001 diff --git a/node_modules/ace/doc/site/images/shiftedit-logo.png b/node_modules/ace/doc/site/images/shiftedit-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..b505f9df86d8030c81a36219865cd62a11b6d195 GIT binary patch literal 12956 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 literal 0 HcmV?d00001 diff --git a/node_modules/ace/doc/site/images/spandexio-logo.png b/node_modules/ace/doc/site/images/spandexio-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..e2fdb79d56aea5a419deb8ae1a3b8cf36f5d43dc GIT binary patch literal 10621 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 literal 0 HcmV?d00001 diff --git a/node_modules/ace/doc/site/images/textimage.png b/node_modules/ace/doc/site/images/textimage.png new file mode 100644 index 0000000000000000000000000000000000000000..6f7d3130c443acf83c8c499db330ccf8d449da49 GIT binary patch literal 11444 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 B5oG`X literal 0 HcmV?d00001 diff --git a/node_modules/ace/doc/site/images/weecod-logo.png b/node_modules/ace/doc/site/images/weecod-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..c4970727a8bead06d81e2a04d1a8367330317382 GIT binary patch literal 2935 zcmV--3yAcIP)Qz;Dy~kL2OA<0;iAE3r zg#@`vd;kAvptT!8Z0I^-Q;rjxc3M*8W@4=dX<)ht zfW_6Is2Gydz9YvY~D^DZ36i5s3~8mzmJ6-u|}c9!sZc+ zK0qv1(~ILz5{uePtm|}QO?nWsa+C5|*Cf_smVSu7BLzTXbujrj2ln>uTi*MQrk>*G zOIEL^Us%`{eGl8(#71l->m`?{`Nm9YyzUxRUy=Sk8~`1-f>?_I#0D(W4{&N4u{!=` zu8n^Cr9;^S_*Xku%FD~+z;^CGMD2U_(TCmhbc04s=<4F+#s0jJ4aBh z4x#k9OC74`7feHEETTPUu2T5kEc$fLIdvvfdrY*cRi@ghf}3aA1Q^tRh+;k?qNmW6 z%q)KVRl-v0&}*P_%`2b_{ll@A(ZAaGuUFFZS9uh&>xOX<1EK^#HNu!Dr*07=mEKp` zy&>JYdyk)A&d4OkCavi8>pa@N?*Jbojj3bG+ysqzCi35QT|L0)Lz?A>tpHe*PD!On|DC6R?K(J;_8vZ}oCo$BY;-+`Qch5=<_Dm6Y%EL-x(I+p>FJNp zIFwbJw$hI84)WvZnR6)f<}H4F?|k|d`UneiBkQT}*GU>@Gajl3*d<;7 zG^F2IIw)YKF8Er385TKK`F`4h#k6|M4&^*%)_jxd!kSWEYuYcntPbF?^#Y(FRjKWz zfZ4Wpzj8cye5`WZO9N8|i`1%XFO%!T_{mN3uAAxr#+}fNgEj(SVXEE6UjZYp{gBpd z-KiW$O`k>DscBHC$@Ojdb|1e-{E7SO&8UsL09cqB1%xPIE?&t{j+0KDRF1VLGf1IB zMwndRfnzEB9@{gYs0V22CIA*DEY#(6_kOl=eCg^n<#@&V%{l;MXD=|Ru1_p%=;7nX z(vKx4S3STlodrNc6N?|8J?D-3A~#oobpJt)axA}MlGDBHZ2DDYJEQA@>6KIR-Dm0n zR(22o4e7+0bM$V)f?ZCJo;-Q)I^I+mQ^&^@ZRpgw3rhJd8IRS$i$5hMF-2+F+Kpsv zLT_!*LEZbi-+WPxuQ9dL!m~N*07h;S%ZQ@XtW!5KCBgLKIVyUWp?^A6PY>_8=axEv z9Yza)rkYW;DdYMLzVOF{==WBR94MA2Sn%WV+ZA_1!KK)7ICEa;O<UZRS)b-`?G#9er@>ZB?axcK_5+5`Mk6D!ZP#B^MeA&RmF*1CU2y~ix26+i#)x+ z-r}M6y=OEw=^nWxrmLH2LfEnG-N!82!F&PA^6(`Vv6d_nF7gRU>rI)|c5@bauD(it zpL^c8ErU}}5eu77%+Awn{(tiaC=1)-oAr{+UTm^@XxNqAf0@+d%+R&$!vUz{HfBrA zu^}!kI98JHC~5n=SE$r;ottq}Y|j7dhY9d!BmqzW6cPZ11V8~$NB|TP0EGlV z0Z>Q)6cPZ1ROvG(_dJsU&RMpSjvPNpf3&Wy_c~m_j-5;^)OQ^L3UGbkxQYBcpwA$R zpTCIKZQsS6SJKX3q?2dQ(}tbj(u5ha$*Ew{af(lU zZql-cQSzzNddtsVn#ixaHE&OSM~zp4`oRDFyQE|u9|l4og3}i+@y)sLP=W_9$|GWv zylEG{^N6K}{JRbu;sFuPT~6oMvu@rl2u0#Qt{`yF`2CWfgRDtM3SKjXq=>sIk zd6A<{Sa~+lx&G@a_S`QIU~miw0D$Ad>O&7jLT>~RIRqCX8WvV2JZciphfikjDK*^i zjl`^L=r3bmPXjVZdbw+%xo@LxQW^9#M1Cr-CuSP*AU{BB1H`A^Kzk0v0>(>uS`R5b zfY74q15*U(4jd-MXpt<|c7-cXSp`wr&c_ZvNdD%EPB+RHZg1qhwJ zlup?>KPaY5jxq>ecbv;HKV{!Ni<$ z_vte-ipNYt8XjXfYSKR)-TBOvFJ;`@N(~!4xrkmjQ<`1EY|6bB@C(b2Ny(HHX<4Ec zAeJ4-(_?n&1B4PcZ00k`^*eU+hIMG%Qtu2>j`e~Fgxc4!?!yEnVbvOLf)Tg}rWHcZ z?ml!BZQ8w8@r8%E#tav}^7EFj;wG|1NEpu#?_R7KvAn@pi{u;DUz)PRY~hy=NNpk{ zcQIM52Irg1w1VDLy{Qz~2Q$+?2~v;r=}XL8qn6>)MyWBo^F4RR>Hfc1QXlnu3KE?(B_lP$6U)DyJ;=FP8=e=7e7H#)@_ENK zz;yL#rJfez zsHfzdWwOMxQ1g}mC;$oxfI*@-b$?*G!lZz<%jN&5f*002ovPDHLkV1irYo9X}n literal 0 HcmV?d00001 diff --git a/node_modules/ace/doc/site/images/wolf_3d_logo_trans.png b/node_modules/ace/doc/site/images/wolf_3d_logo_trans.png new file mode 100644 index 0000000000000000000000000000000000000000..fe61b9b487a529f99ee434cb13edb76f8f19196c GIT binary patch literal 46064 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 I6wKcL4}#~W;s5{u literal 0 HcmV?d00001 diff --git a/node_modules/ace/doc/site/images/zorba-logo.png b/node_modules/ace/doc/site/images/zorba-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..ad2c22f6a8abd84a8ce3032c751ca604a3452038 GIT binary patch literal 8197 zcmZ{J1ymf{(k|}q&M>&U1RLBfgA-tI4Q_)wL4s=_xCVD8zyv2~2<|Q+3<;VLc${<3 zfB*aLdau{&-ql}!Ro||vy?V98>1ZkAVo_lsARyqXswjY;N2lkV4+HJ_crSGEJfJW+ z%FFAh%F6?EJl*UZU)v%eh!IBXZ@I1Mkx0k6fy>B103+o$@xu-Jy05yZsp>}1RMX4P z)yT?EmN}UA#YN*jP@}J%v{!2fhKr&-Aj+&D6WkDTz zq2@%3J9To3h-Z-WcKU3GHXdX0JoWpd)(vBSK*IW598i0}m6SG^@($b&`Jc z-*=83XzM>|;9o>gkZO>!gWnTD=SEqjv=~5`NwXYhq;(j*Xp+6lcDx;y5M+w6^c{Uy z>TaN2YD-<3rRU5JZ?Z=R{}Vn>p3l`cvq+=g@5{TaJMrT-IdAkn#(|dFu4v%ujgW>e zRm)J+yX0Tw2qDr{={)1xv_&s2e)F)_;&)t6Htr zUsK7CF}aQEoL7w6v;0D@&WQo ~9^U{^h&Y*92k`rh>chlz|ot?cOJbor_B)E)< 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 literal 0 HcmV?d00001 diff --git a/node_modules/ace/doc/site/iphone.css b/node_modules/ace/doc/site/iphone.css new file mode 100644 index 00000000..dd90db03 --- /dev/null +++ b/node_modules/ace/doc/site/iphone.css @@ -0,0 +1,25 @@ +#wrapper { + position:relative; + overflow:hidden; +} + +#wrapper .content .column1 { + margin:0 16px 0 15px; +} + +#header .content .signature { + font-size:18px; + bottom:0; +} + +UL.menu-list LI { + font-size:22px; +} + +UL.menu-footer LI { + font-size:22px; +} + +PRE{ + font-size:22px; +} \ No newline at end of file diff --git a/node_modules/ace/doc/site/js/ga.js b/node_modules/ace/doc/site/js/ga.js new file mode 100644 index 00000000..e381972d --- /dev/null +++ b/node_modules/ace/doc/site/js/ga.js @@ -0,0 +1,9 @@ + var _gaq = _gaq || []; + _gaq.push(['_setAccount', 'UA-31998201-1']); + _gaq.push(['_trackPageview']); + + (function() { + var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; + ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; + var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); + })(); \ No newline at end of file diff --git a/node_modules/ace/doc/site/js/main.js b/node_modules/ace/doc/site/js/main.js new file mode 100644 index 00000000..92ce6e08 --- /dev/null +++ b/node_modules/ace/doc/site/js/main.js @@ -0,0 +1,187 @@ +var editor; +var embedded_editor; +$(function() { + if (typeof ace !== "undefined") { + ace.config.set("workerPath", "build/src-min"); + editor = ace.edit("ace_editor_demo"); + editor.container.style.opacity = ""; + embedded_editor = ace.edit("embedded_ace_code"); + embedded_editor.container.style.opacity = ""; + embedded_editor.session.setMode("ace/mode/html"); + embedded_editor.setAutoScrollEditorIntoView(true); + embedded_editor.setOption("maxLines", 40); + + editor.setOptions({ + maxLines: 30, + mode: "ace/mode/javascript", + autoScrollEditorIntoView: true + }); + + ace.config.loadModule("ace/ext/emmet", function() { + ace.require("ace/lib/net").loadScript("http://nightwing.github.io/emmet-core/emmet.js", function() { + embedded_editor.setOption("enableEmmet", true); + editor.setOption("enableEmmet", true); + }); + }); + + ace.config.loadModule("ace/ext/language_tools", function() { + embedded_editor.setOptions({ + enableSnippets: true, + enableBasicAutocompletion: true + }); + editor.setOptions({ + enableSnippets: true, + enableBasicAutocompletion: true + }); + }); + } else { + document.body.insertAdjacentHTML("afterbegin", '
      \ +
      \ + \ + Oh No! Couldn\'t load build/src/ace.js.
      \ + You can build it by running node Makefile.dryice.js
      \ + Or download older version by running git submodule update --init --recursive
      \ +
      \ +
      '); + } + $("ul.menu-list").mousedown(function(e) { + if (e.button === 1) { + e.preventDefault(); + } + }); + + $("ul.menu-list li").click(function(e) { + if (e.target.tagName !== "A") { + var href = $(this).find("a").attr("href"); + if (e.button == 1) + window.open(href, "_blank"); + else + window.location = href; + } + }); + + // used when page is access directly + function magicClickInterceptor(e) { + e.preventDefault(); + + var state = {}; + state.api = $(this).attr("href").substring(6, $(this).attr("href").length - 5); + $.bbq.pushState(state); + + var _self = $(this); + $("#apiHolder").load($(this).attr("href") + " #documentation", function(){ + $("#apiHolder").removeClass("apiIntro").removeClass("span9"); + $("#documentation").removeClass("span9").addClass("span7"); + ux(); + setupClicker(); + + // handles dropping in from new link + var section = $.bbq.getState("section"); + if (section) { + $("li#dropdown_" + section.replace(/\./g, '\\.') + " a").triggerHandler('click'); + } + + //setupDisqus(_self.attr("href")); + }); + } + + $('.menu-item a').click(magicClickInterceptor); + $('a.argument').click(magicClickInterceptor); + + $('a.external').click(function(e) { + e.preventDefault(); + }); + + var tabs = $("#tabnav"), + tab_a_selector = "a"; + + var firstLoad = true; + + tabs.find(tab_a_selector).click(function(e) { + e.preventDefault(); + if ($(this).attr("href") === "/") { + window.location = "http://ace.ajax.org"; + return; + } + if ($(this).attr("href").indexOf("#api") === 0) { + $("#top_container").addClass("collapse"); + scrollIntoPosition(null, 0); + } + else if ($(this).is(":visible")) { + if (firstLoad) { + firstLoad = false; + setTimeout(function() { + $("#top_container").removeClass("collapse"); + scrollIntoPosition(e.target); + }, 700); + } + else { + $("#top_container").removeClass("collapse"); + scrollIntoPosition(e.target); + } + } + + function scrollIntoPosition(el, overridePosition) { + if (typeof overridePosition !== "undefined") { + $("body").stop().animate({ + scrollTop: overridePosition + }, 400); + } + else if ($("body").scrollTop() > 345) { + $("body").stop().animate({ + scrollTop: ($(el).offset().top - 10) + }, 400); + } + } + + $(this).tab("show"); + + var state = {}; + state.nav = $(this).attr("href").substr(1); + $.bbq.pushState(state); + }); + + $('#tabnav a[data-toggle="tab"]').on('shown', function (e) { + $(".tab-content .tab-pane.active .ace_editor").each(function(i, el){ + el.env.onResize(); + }); + }); + + $(window).on("hashchange", function(e) { + _gaq.push(['_trackPageview',location.pathname + location.search + location.hash]); + tabs.each(function() { + var idx = $.bbq.getState("nav") || "about"; + var section = e.fragment.split("&")[1] || ""; + $(this).find(tab_a_selector + "[href='#" + idx + "']").triggerHandler('click'); + + // handles dropping in from new link + var api = $.bbq.getState("api"); + if (api) { + $(tab_a_selector + "[href='./api/" + api + ".html']").triggerHandler('click'); + } + }); + }).trigger("hashchange"); + + highlight(); +}); + + + +function highlight() { + var highlighter = ace.require("ace/ext/static_highlight") + var dom = ace.require("ace/lib/dom") + function qsa(sel) { + var els = document.querySelectorAll(sel); + var result = []; + for (var i = 0, l = els.length; i < l; i++) + result[i] = els[i]; + return result; + } + + qsa("code[class]").forEach(function(el) { + var m = el.className.match(/language-(\w+)|(javascript)/); + if (!m) return + var mode = "ace/mode/" + (m[1] || m[2]); + highlighter.highlight(el, {mode: mode, theme: "ace/theme/xcode"}) + }); +} \ No newline at end of file diff --git a/node_modules/ace/doc/site/style.css b/node_modules/ace/doc/site/style.css new file mode 100644 index 00000000..1167340a --- /dev/null +++ b/node_modules/ace/doc/site/style.css @@ -0,0 +1,509 @@ +body { + margin:0; + padding:0; + background-color:#e6f5fc; + font-family: Helvetica, Arial; +} + + + +#ace_editor_demo, #embedded_ace_code { + height: 275px; + border: 1px solid #DDD; + border-radius: 4px; + border-bottom-right-radius: 0px; + margin-top: 5px; +} + +#embedded_ace_code { + height: 525px; +} + +h1, h2, h3, h4, h5, h6 { + font-family: Helvetica; + font-weight: 100; + margin:0; + padding:0; +} + +h2, h3, h4, h5, h6 { + padding-top: 30px; + border-bottom: 1px solid #bedaea; +} + +H2 { + font-size:28px; + color:#263842; + padding-bottom:6px; +} + +H3 { + font-size:22px; + color:#253741; + margin-bottom:8px; +} + +H4 { + font-size:21px; + color:#222222; + margin-bottom:8px; +} + +P { + padding:13px 0; + margin:0; + line-height:21px; + font-size: 15px; +} + +UL{ + font-size: 15px; +} + +#header { + height: 93px; + position: relative; + background: url(images/background.png) repeat-x 0 0; + border-bottom: 1px solid #C9E8FA; + margin-top: 40px; +} + +#header .content .signature { + font-family:Trebuchet MS; + font-size:11px; + color:#ebe4d6; + position:absolute; + bottom:5px; + right:42px; + letter-spacing : 1px; +} + +.content { + width:970px; + position:relative; + margin:0 auto; +} + +#header .content { + height: 100%; + z-index: 90000; +} + +#header .content .logo { + width: 141px; + height: 92px; + background: url(images/logo_half.png) no-repeat 0 0; + position: absolute; + top: -14px; + left: 0; +} + +#header .content .title { + width: 605px; + height: 58px; + background: url(images/ace.png) no-repeat 0 0; + position: absolute; + top: 22px; + left: 329px; +} + +#wrapper { + background:url(images/body_background.png) repeat-x 0 -15px; + min-height:250px; +} + +#wrapper .content { + font-family:Arial; + font-size:14px; + color:#222222; + width: 960px; +} + +#wrapper .content .column1 { + position:relative; + overflow:hidden; + float:left; + width:315px; + margin-right:31px; +} + +#wrapper .content .column2 { + position:relative; + overflow:hidden; + float:left; + /*width:600px;*/ +} + +#top_container h1 { + font-size: 68px; + line-height: 60px; + width: 515px; + float: left; + font-weight: 100; + font-family: Helvetica; + padding: 65px 0 0 14px; + color: #333; +} + +#top_container { + background: url(images/header-bg.png) 0 0; + overflow: hidden; + padding: 11px 36px 19px 40px; + height: 267px; + -webkit-transition: height 0.4s ease-out, opacity 0.4s ease-out, padding 0.4s ease-out, margin 0.4s ease-out; + -moz-transition: height 0.4s ease-out, opacity 0.4s ease-out, padding 0.4s ease-out, margin 0.4s ease-out; + opacity: 1; + margin-top: 25px; +} + +#top_container.collapse { + padding: 0px; + height: 0px; + opacity: 0; + margin: 0; +} + +#page_logo { + padding: 35px 0 15px 0; + width: 350px; + float: right; + text-align: center; + height: 220px; +} + +.fork_on_github { + width:310px; + height:80px; + background:url(images/fork_on_github.png) no-repeat 0 0; + position:relative; + overflow:hidden; + margin-top:49px; + cursor:pointer; +} + +.fork_on_github:hover { + background-position:0 -80px; +} + +.divider { + height: 1px; + background-color:#bedaea; + margin-bottom:3px; +} + +.menu, .site-menu { + padding: 25px 0 0 35px; +} + +UL.content-list { + padding: 15px 0 15px 20px; + margin:0; +} + +UL.content-list li { + padding-left: 10px; + padding-bottom: 3px; +} + +ul.menu-list { + padding: 15px 0; + margin: 0 0 20px 0; + list-style-type: none; + line-height: 16px; + overflow: auto; +} + +ul.menu-list li { + color: #2557B4; + font-family: Helvetica, Trebuchet MS; + font-size: 12px; + padding: 5px; + cursor: pointer; + display: block; + float: left; + margin-right: 15px; + margin-bottom: 20px; + width: 100px; + height: 90px; + border-radius: 5px; + position: relative; + background: rgba(255, 255, 255, 0.7); + margin-left: 22px; + margin-top: 20px; + box-shadow: 0 0 4px rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 0 4px rgba(0, 0, 0, 0.1); + -webkit-transition: box-shadow 0.4s; + -moz-transition: box-shadow 0.4s; + border: 1px solid #999; + background-image: -webkit-repeating-linear-gradient(left, hsla(0,0%,100%,0) 0%, hsla(0,0%,100%,0) 6%, hsla(0,0%,100%, .1) 7.5%), + -webkit-repeating-linear-gradient(left, hsla(0,0%, 0%,0) 0%, hsla(0,0%, 0%,0) 4%, hsla(0,0%, 0%,.03) 4.5%), + -webkit-repeating-linear-gradient(left, hsla(0,0%,100%,0) 0%, hsla(0,0%,100%,0) 1.2%, hsla(0,0%,100%,.15) 2.2%), + + -webkit-linear-gradient(-90deg, hsl(0,0%,78%) 0%, + hsl(0,0%,90%) 47%, + hsl(0,0%,78%) 53%, + hsl(0,0%,70%)100%); + background-image: -moz-repeating-linear-gradient(left, hsla(0,0%,100%,0) 0%, hsla(0,0%,100%,0) 6%, hsla(0,0%,100%, .1) 7.5%), + -moz-repeating-linear-gradient(left, hsla(0,0%, 0%,0) 0%, hsla(0,0%, 0%,0) 4%, hsla(0,0%, 0%,.03) 4.5%), + -moz-repeating-linear-gradient(left, hsla(0,0%,100%,0) 0%, hsla(0,0%,100%,0) 1.2%, hsla(0,0%,100%,.15) 2.2%), + + -moz-linear-gradient(-90deg, hsl(0,0%,78%) 0%, + hsl(0,0%,90%) 47%, + hsl(0,0%,78%) 53%, + hsl(0,0%,70%)100%); +} + +ul.menu-list li:hover { + box-shadow: 0 0 4px rgba(0, 0, 0, 0.5); + -moz-box-shadow: 0 0 4px rgba(0, 0, 0, 0.5); +} + +ul.menu-list li a { + position: absolute; + bottom: 0px; + left: 0px; + color: white; + text-align: center; + font-weight: bold; + text-shadow: 0px 0px 4px rgba(0, 0, 0, 0.8); + width: 100%; + display: block; + background: rgba(0, 0, 0, 0.6); + line-height: 12px; + padding: 4px 0; +} + +UL.menu-list LI a:hover { + text-decoration: none; +} + +li#add_your_site p { + font-size: 32px; + border: 3px solid #34A034; + color: #34A034; + border-radius: 34px; + padding: 3px 4px 4px 5px; + width: 20px; + height: 22px; + line-height: 18px; + position: relative; + left: 33px; + top: 22px; + background: #fff; +} + +ul.menu-list li#add_your_site a { + color: #A3EEA3; +} + +/* This is the animation code. */ +@-webkit-keyframes example { + 0% { -webkit-transform: rotate(0deg); } + 25% { -webkit-transform: rotate(3deg); } + 50% { -webkit-transform: rotate(0deg); } + 75% { -webkit-transform: rotate(-3deg); } +} + +/* This is the element that we apply the animation to. */ +li#add_your_site { + -webkit-animation-name: example; + -webkit-animation-duration: 0.4s; + -webkit-animation-timing-function: ease; /* ease is the default */ + -webkit-animation-delay: 0s; /* 0 is the default */ + -webkit-animation-iteration-count: infinite; /* 1 is the default */ + -webkit-animation-direction: alternate; /* normal is the default */ +} + +A { + color:#2557b4; + text-decoration:none; +} + +A:hover { + text-decoration:underline; +} + +#footer { + height:40px; + position:relative; + overflow:hidden; + background:url(images/bottombar.png) repeat-x 0 0; + position:relative; + margin-top:40px; +} + +UL.menu-footer { + padding:0; + margin:8px 11px 0 0; + list-style-type:none; + float:right; +} + +UL.menu-footer LI { + color:white; + font-family:Arial; + font-size:12px; + display:inline-block; + margin:0 1px; +} + +UL.menu-footer LI A { + color:#8dd0ff; + text-decoration:none; +} + +UL.menu-footer LI A:hover { + text-decoration:underline; +} + +.nav-pills.nav { + margin: 10px 0 25px 0; + padding: 0; + border-radius: 5px; + border: 1px solid #d7d7d7; + background: #eeeeee; + background: -moz-linear-gradient(top, #eeeeee 0%, #cccccc 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#eeeeee), color-stop(100%,#cccccc)); + background: -webkit-linear-gradient(top, #eeeeee 0%,#cccccc 100%); + background: -o-linear-gradient(top, #eeeeee 0%,#cccccc 100%); + background: -ms-linear-gradient(top, #eeeeee 0%,#cccccc 100%); + background: linear-gradient(to bottom, #eeeeee 0%,#cccccc 100%); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#eeeeee', endColorstr='#cccccc',GradientType=0 ); + overflow: hidden; +} + +.nav-pills > .active > a, .nav-pills > .active > a:hover { + color: white; + background-color: #555; + box-shadow: inset 0 0 8px rgba(0, 0, 0, 0.8); + text-shadow: 0px 0px 3px #000; +} + +.nav-tabs > li > a, .nav-pills > li > a { + padding-right: 17px; + padding-left: 17px; + border-right: 1px solid #bbb; + border-radius: 0; + margin: 0; + line-height: 25px; + font-size: 14px; + color: #333; + text-shadow: 1px 1px 0 rgba(255, 255, 255, 0.3); + box-shadow: 0 0 1px rgba(255, 255, 255, 1); + -moz-box-shadow: 0 0 1px rgba(255, 255, 255, 1); + -webkit-transition: background 0.2s; + -moz-transition: background 0.2s; +} + +.nav.nav-pills li:first-child > a { + padding-left: 28px; + padding-right: 28px; +} + +.nav.nav-pills li:first-child > a > img { + width: 34px; +} + +.nav.nav-pills li:last-child > a { + border-right: none; + box-shadow: none; + -moz-box-shadow: none; +} + +.tab-content { + margin-bottom: 50px; +} + +.tab-content > .active, .pill-content > .active { + padding: 25px 30px; +} + +#top_container, .tab-content > .active, .pill-content > .active { + border: 1px solid #DDD; + border-radius: 5px; + -moz-border-radius: 5px; +} + +.tab-content > .active, .pill-content > .active { + background: rgba(255, 255, 255, 0.7); +} + +pre .xml .javascript, pre .xml .css { + opacity: 1; +} + +#embed_link { + text-align: right; + padding-top: 0; +} +#embed_link a { + color: #059C05; + font-weight: 100; + font-family: helvetica; + font-size: 13px; + display: inline-block; + padding: 2px 10px; + background: #f4f4f4; + border: 1px solid #ddd; + border-top: none; + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + text-shadow: 0px 1px 0px rgba(255, 255, 255, 1); + text-decoration: none; +} + +p.highlight_note { + padding: 8px 35px 8px 14px; + margin-top: 10px; + color: #A0762E; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + background-color: #FCF8E3; + border: 1px solid #CA9C44; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +p.highlight_note a { + color: #537CC7; +} + +.prod_no_image { + position: relative; left: -10px; top: -12px; +} + + +#api { + padding: 0; +} + +/*https://github.com/twitter/bootstrap/issues/5262*/ +img { + max-width: none; +} + +.text-logo{ + color: black; + font-size: 24px; + font-weight: lighter; + margin-top: 23px; + text-align: center; + text-shadow: 1px 17px 2px gray, 1px 1px 2px gray; +} + +.menu-list>li>img { + position: relative; +} + +.rotating-logo { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + -webkit-transition: all 0.5s ease-out; + transition: all 0.5s ease-out; +} +.rotating-logo:hover { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + -webkit-transition: all 0.5s ease-in-out; + transition: all 0.5s ease-in-out; +} \ No newline at end of file diff --git a/node_modules/ace/doc/template/jade/common_layout.jade b/node_modules/ace/doc/template/jade/common_layout.jade new file mode 100644 index 00000000..bb665600 --- /dev/null +++ b/node_modules/ace/doc/template/jade/common_layout.jade @@ -0,0 +1,55 @@ +-var dirPrefix = "./"; +-var sitePrefix = "../doc/site/"; +-var landingPage = 'false' +-var versions = [] + +mixin doctype + !!! 5 + + + + + + +mixin head + meta(http-equiv='Content-Type', content='text/html; charset=UTF-8') + + -if (isIndex) + title #{title} + -else + title #{classId} - #{title} + + meta(name="generator", content="panino-doc-build") + meta(name="description", content="Ace API documentation for the online code editor") + meta(name="author", content="Garen J. Torikian") + + script(src='#{sitePrefix}/js/main.js') + link(rel='stylesheet', media='all and (max-device-width: 480px)', href='doc/site/iphone.css') + link(rel='stylesheet', media='all and (min-device-width: 481px) and (max-device-width: 1024px)', href='doc/site/iphone.css') + link(href='#{dirPrefix}resources/ace/skeleton/images/favicon.ico', rel='icon', type='image/x-icon') + + link(href='#{sitePrefix}/style.css', rel='stylesheet', type='text/css') + link(rel="stylesheet", href="#{dirPrefix}resources/csses/ace_api.css") + link(rel="stylesheet", href="#{dirPrefix}resources/csses/font-awesome.css") + + link(href="#{dirPrefix}resources/images/favicon.ico", rel="icon", type="image/x-icon") + + script(src='#{dirPrefix}resources/javascripts/bbq.js') + script(src="#{dirPrefix}resources/javascripts/jquery.collapse.js") + script(src="#{dirPrefix}resources/javascripts/jquery.cookie.js") + script(src="#{dirPrefix}resources/javascripts/bootstrap.js") + + +mixin endingScripts + script(defer, src="#{dirPrefix}resources/javascripts/ux.js") + script(src="#{dirPrefix}resources/javascripts/clicker.js") + script(src="#{dirPrefix}resources/javascripts/jquery-scrollspy.js") + script(defer, src="#{dirPrefix}resources/javascripts/disqus-ext.js") + script(defer, src="#{dirPrefix}resources/javascripts/ga.js") + +mixin identifyBuild(tree, type) + landingPage = 'true' + -dirPrefix = './' + +mixin markdown(text, inline) + != markdown(text, inline) \ No newline at end of file diff --git a/node_modules/ace/doc/template/jade/layout.jade b/node_modules/ace/doc/template/jade/layout.jade new file mode 100644 index 00000000..c2911c69 --- /dev/null +++ b/node_modules/ace/doc/template/jade/layout.jade @@ -0,0 +1,12 @@ +include common_layout +include lib + +#documentation.span9 + -if (isIndex) + != indexContent + -else + mixin api() + + mixin endingScripts + + div(id="disqus_thread") \ No newline at end of file diff --git a/node_modules/ace/doc/template/jade/lib.jade b/node_modules/ace/doc/template/jade/lib.jade new file mode 100644 index 00000000..62ee92d2 --- /dev/null +++ b/node_modules/ace/doc/template/jade/lib.jade @@ -0,0 +1,217 @@ +- var methodSection, constructorSection, propertySection, eventSection; + +-function renameMemberTitle(title, count) + if title.indexOf("ethods") >= 0 + span Functions (#{count}) + else if title.indexOf("ropert") >= 0 + span Properties (#{count}) + else + span #{title} (#{count}) + +mixin article(obj, parents) + if typeof obj === 'string' + obj = list[obj] + + if (obj.private !== true && obj.name.charAt(0) !== "$") + title = obj.path + (obj.type ? ' (' + obj.type + ')' : '') + article.article(id=obj.path, data-title=title) + if obj.type === 'section' || obj.type === 'namespace' || obj.type === 'class' || obj.type === 'mixin' + + if obj.stability + mixin markdown(">" + obj.stability) + + if obj.description + .section.description + .memberContent + mixin markdown(obj.description) + + else + .section.method + .memberContent + if obj.signatures + div.title + i(id='#{obj.path}', class='methodToggle methodClicker inactive icon-caret-right') + ul.signatures + -var loops = 0; + for sig in obj.signatures + li.signature + ul + li.signature-call!= signature(obj, sig, ["methodClicker"]) + if sig.returns + li.signature-returns + ul.argument-types + for ret in sig.returns + li.argument-type!= returnLink(obj, ret, []) + -if (loops == 0) + -loops = 1 // ensure that we only print ONE meta info UL per signature (some methods have multiple signatures) + ul.metaInfo + if obj.undocumented + li + span.label.undocumented Undocumented + if obj.experimental + li + span.label.experimental Experimental + if obj.readonly + li + span.label.read-only Read-Only + if obj.chainable + li + span.label.chainable Chainable + if obj.internal + li + span.label.internal Internal + if obj.deprecated + li + span.label.deprecated + | Deprecated + if obj.deprecated.from + |   (since #{obj.deprecated.from}) + if obj.deprecated.off + |  and will be removed on #{obj.deprecated.off} + if obj.alias_of + li + span.label.alias.single + | Aliased as: + != link(obj.alias_of) + else if obj.aliases.length + li + span.label.alias.multiple + | Aliased as: + ul.alias + for alias in obj.aliases + li + mixin link(alias) + + if obj.related_to + li + span.label.related-to + | Related to + mixin link(obj.related_to, ["relatedToLink"]) + + div.sideToggler + + div(id='ellipsis_#{obj.path}', class='ellipsis_description') + mixin markdown(obj.short_description) + + + div.description + + mixin markdown(obj.description) + + if obj.bound && ~obj.bound.indexOf('#') + p.note.methodized + | This method can be called either as an + != link(obj.bound, ['link-short'], 'instance method') + | or as a generic method. If calling as generic, pass the instance in as the first argument. + else if obj.bound && !~obj.bound.indexOf('#') + p.note.functionalized + | This method can be called either as an instance method or as a + != link(obj.bound, ['link-short'], 'generic method') + |. If calling as generic, pass the instance in as the first argument. + + if obj.arguments && obj.arguments.length + h4 Arguments + != argumentTable(obj.arguments, ["argument-list", "table", "table-striped", "table-bordered"]) + + if obj.returns && obj.returns.length + h4 Returns + != returnTable(obj.returns, ["return-list", "table", "table-striped", "table-bordered"]) + + //- children + for child in obj.children.filter(function(x){return x.type === 'section'}) + mixin article(child, parents.concat(obj)) + for child in obj.children.filter(function(x){return x.type === 'utility'}) + mixin article(child, parents.concat(obj)) + + for child in obj.children.filter(function(x){return x.type === 'constructor'}) + - if (!constructorSection) + - constructorSection = true + h3.sectionHeader Constructors + mixin article(child, parents.concat(obj)) + + for child in obj.children.filter(function(x){return x.type === 'event'}) + - if (!eventSection) + - eventSection = true + h3.sectionHeader Events + mixin article(child, parents.concat(obj), 'event') + + for child in obj.children.filter(function(x){return x.type === 'class method'}) + - if (!methodSection) + - methodSection = true + h3.sectionHeader Methods + mixin article(child, parents.concat(obj)) + + for child in obj.children.filter(function(x){return x.type === 'class property'}) + - if (!propertySection) + - propertySection = true + h3.sectionHeader Properties + mixin article(child, parents.concat(obj)) + + for child in obj.children.filter(function(x){return x.type === 'instance method'}) + mixin article(child, parents.concat(obj)) + for child in obj.children.filter(function(x){return x.type === 'instance property'}) + mixin article(child, parents.concat(obj)) + for child in obj.children.filter(function(x){return x.type === 'constant'}) + mixin article(child, parents.concat(obj)) + + + +mixin api() + -pos = 0 + for obj in tree.children + -if (obj.subclasses.length == 0) + mixin render_starting_tabs(obj, pos) + -else + mixin render_starting_tabs(obj, pos) + for child in obj.children.filter(function(x){return x.type === 'namespace' || x.type === 'class' || x.type === 'mixin'}) + -pos++ + mixin render_starting_tabs(child, pos) + + +mixin render_starting_tabs(obj, pos) + .classContent + .membersBackground + + div(class=' members pos#{pos}') + div(class=' membersContent pos#{pos}') + h1.memberHeader + -var heading = obj.path + span.name #{heading} + + -if (true || obj.filename.indexOf("index") < 0) + ul(class='nav tabs pos#{pos}', data-tabs='tabs') + for selector, title in {'Events': ['event', 'events'], 'Constructors': ['constructor', 'constructors'], 'Class methods': ['class method', 'class_methods'], 'Class properties': ['class property', 'class_properties'], 'Instance methods': ['instance method', 'instance_methods'], 'Instance properties': ['instance property', 'instance_properties'], 'Constants': ['constant', 'constants']} + members = obj.children.filter(function(x){return x.type === selector[0]}) + li(class="dropdown", data-dropdown="dropdown") + if members.length + a(href="\#", class="dropdown-toggle", data-toggle="dropdown") + != renameMemberTitle(title, members.length) + b.caret + ul.dropdown-menu + for m in members + if (m.private !== true && m.name.charAt(0) !== "$") + li(id='dropdown_#{m.path}', data-id='#{m.path}', class='memberLink') + mixin link(m, [], true) + -methodSection = constructorSection = propertySection = eventSection = false; + mixin article(obj, []) + +mixin short_description_list(collection) + ul.method-details-list + for obj in collection + if typeof obj === 'string' + obj = list[obj] + li.method-description + h4 + mixin link(obj) + if obj.short_description + mixin markdown(obj.short_description) + +mixin link(obj, classes, short) + l = link(obj, classes, short) + != l + +mixin links(collection) + ul.method-list + for obj in collection + li + mixin link(obj) \ No newline at end of file diff --git a/node_modules/ace/doc/template/resources/csses/ace_api.css b/node_modules/ace/doc/template/resources/csses/ace_api.css new file mode 100644 index 00000000..7a90b4c3 --- /dev/null +++ b/node_modules/ace/doc/template/resources/csses/ace_api.css @@ -0,0 +1,912 @@ +/* + Generic "affects everything" stuff +*/ + +#wrapper .content .column2 { + float: none; +} + +#documentation ul { + font-size: 13px; +} + +#documentation li { + color: black; +} + +pre { + background-color: #FFFFFF; +} + +code { + font-size: 12px; + line-height: 16px; + font-family: 'Ubuntu Mono',Monaco,Consolas,monospace !important; + background-color: #F9F9F9; + border-radius: 3px 3px 3px 3px; + display: inline-block; + padding: 0 4px; + margin: 2px 1px; + color: inherit; +} + +#documentation pre { + margin-top: 10px; + border-radius: none; + box-shadow: none; + background : white; + /*background : #f5f5f5; + border: 0;*/ + + -webkit-border-radius: 6px 6px 0 0; + -moz-border-radius: 6px 6px 0 0; + border-radius: 6px 6px 0 0; + + padding: 5px; +} + +.method pre, .event pre, .property pre { + background : white; +} + +#documentation pre code { + background-color: transparent; + border-radius: none; + box-shadow: none; +} + +#documentation a code { + color: #00438a; +} + +#documentation h2 { + font-size: 26px; +} +#documentation p { + font-size: 13px; +} +#documentation li p:last-child { + margin-bottom : 5px; +} + +#documentation blockquote p{ + font-size: 14px; + font-weight: 500; + line-height: 23px; + font-style: italic; +} + +.alert-message{ + margin-bottom : 13px; +} +/* + Header and shoulders +*/ + +.navbar .nav > li { + float:none; + display:inline-block; + *display:inline; /* ie7 fix */ + zoom:1; /* hasLayout ie7 trigger */ +} + +.navbar .nav > li > a { + padding: 10px 15px 11px; +} + +.navbar { + text-align:center; +} + +#topSection { + width: 1000px; +} +.small_win #topSection { + width: 100%; +} +.small_win #topSection .dropdown { + margin-right: 40%; +} +.navbar .brand { + margin-left: 0px; +} +.brand { + background: transparent url(../images/ace_logo_menu.png) no-repeat 33px 5px; + width: 80px; + outline: none; + height: 40px; + padding: 0 10px !important; + border: none; +} +.brand.dropdown-toggle:after { + content: none; + display: block; + height: 40px; + border: none; +} + +.ace_logo { + position: absolute; + top: 45px; + z-index: 20000; + left: 210px; +} + +.headerTitle { + position: relative; + top: 100px; + left: 250px; +} + +/* + Menu venue +*/ + + +h3.api_title { + padding-top: 10px; +} + +ul.menu { + margin-left: 2px; +} + +.menu li { + list-style-image: url(../images/menu_disc.png); + margin-bottom: 4px; + font-weight: 700; + padding-left: 10px; + margin-left: 0; +} + +.menu li .menu-item a.menuLink, .menu li .menu-item span.menuLink { + color: #3E7096; + font-weight: 100; +} +.menuTwo { + margin-bottom: 5px; + margin-top: 2px; +} +.menuTwo li .menu-item a.menuLink { + color: #3E7096; + font-weight: 100; +} + +/* need specificity to "beat" the above colors */ +.menu li .menu-item a.currentItem, .menuTwo li .menu-item { + color: #0072bc; +} + +/* + Members and the tabs that represent them +*/ + +.srolled .members { + width: 100%; +/* -webkit-box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.35); + -moz-box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.35); + box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.35); */ + padding-bottom: 15px; +/* height: 31px;*/ + position: fixed; +} +.shadow.members{ + background: #edf8fd; + box-shadow: 0 0.1em 1em rgba(0,0,0, 0.3); + -moz-box-shadow: 0 0.1em 1em rgba(0,0,0, 0.3); + -o-box-shadow: 0 0.1em 1em rgba(0,0,0, 0.3); + -webkit-box-shadow: 0 0.1em 1em rgba(0,0,0, 0.3); +} + +.membersContent { + +/* border-bottom: 0.1em solid #FFF;*/ + height: 3em; + padding-top: 4px; +/* line-height: 4;*/ +/* margin-top: -0.1em;*/ + position: relative; +/* transition-property: border-color, line-height; + transition-duration: 125ms, 250ms; + transition-timing-function: ease-out, ease-out; + -moz-transition-property: border-color, line-height; + -moz-transition-duration: 125ms, 250ms; + -moz-transition-timing-function: ease-out, ease-out; + -o-transition-property: border-color, line-height; + -o-transition-duration: 125ms, 250ms; + -o-transition-timing-function: ease-out, ease-out; + -webkit-transition-property: border-color, line-height; + -webkit-transition-duration: 125ms, 250ms; + -webkit-transition-timing-function: ease-out, ease-out;*/ + + /*transition-duration: 125ms; + transition-property: top; + transition-timing-function: ease-out; + + top : 11px;*/ + z-index: 103; + padding-right: 10px; + margin-right: -5px; + /*width: 700px;*/ +} +.srolledHeader .membersContent { + line-height: 3; +} +.srolled .membersContent { + /*top : 0;*/ + width: 625px; + padding-left: 327px; + margin : 0 auto 0 auto; +} + +.srolled ul.nav { + padding-right: 10px; +} + +.membersBackground { +/* background-color: white; + position: fixed; + z-index: 2; + top: 40px; + left: 0px; + right: 0px; + width: 100%; + height: 55px; + opacity: 0; + display: none; + box-shadow: rgba(0, 0, 0, 0.398438) 1px 4px 6px;*/ + + background-color: transparent; + height: 47px; + /*width: 700px;*/ + position: absolute; +} +.srolled .membersBackground { + position: relative; +} +.srolledHeader .membersBackground { +/* display: block;*/ +} +.memberHeader { + float: left; + padding-right: 10px; + margin-bottom: 5px; + position: absolute; + padding-top: 4px; + +} + +ul.tabs li:first-child ul{ + left: -63px; +} + +.tabs a.menu:after, .tabs .dropdown-toggle:after { + margin-top: 22px; +} + +.nav .dropdown-toggle .caret { + margin-top: 12px; + border-top-color: #6D8CA0; + border-bottom-color: #6D8CA0; +} + +li.dropdown { + color: #2D2D2D; + font-weight: bold; +} + +.editInC9 { + font-size: 11px; + color: #657383; +} + +.editInC9 a { + color: #657383; + font-weight: normal; + position : relative; + top : -2px; +} + +.tabs { + padding-top: 14px; + /*border-bottom: 1px solid #848484;*/ + min-height : 27px; + padding-bottom : 5px; +} +.tabsSansBorder { + border: 0; +} +.tabs, .pills { + margin-bottom: 0; +} +.srolledHeader .members .tabs { + background-color: white; +} + +li.dropdown { + color: #2D2D2D; + font-weight: bold; +} + +.members .tabs .dropdown a, +.members .tabs a.menu:after, +.members .tabs .dropdown-toggle:after { + margin-right: 0; + margin-left: 6px; +} + +.memberLink a { + margin-left: 0 !important; +} +.menu-dropdown { + min-width : 105px; + max-height: 350px; + overflow: auto; + border-color : rgba(0, 0, 0, 0.1); +} +.topbar div > ul .menu-dropdown li a:hover, +.nav .menu-dropdown li a:hover, +.topbar div > ul .dropdown-menu li a:hover, +.nav .dropdown-menu li a:hover { + background-color: #ffffff; + color: #000000; +} + +.tabs a.menu:after, .tabs .dropdown-toggle:after { + margin-top: 13px; + line-height: 28px; +} +.open .menu, .dropdown.open .menu, .open .dropdown-toggle, .dropdown.open .dropdown-toggle { + background: transparent; + color: black; +/* font-weight: bold;*/ +} +#topSection .open .menu, #topSection .dropdown.open .menu, #topSection .open .dropdown-toggle, +#topSection .dropdown.open .dropdown-toggle { + color: #bfbfbf; +} + +.tabs > li { + font-weight: bold; +} + +.tabs > li > a { + border: none; + outline: none; + line-height: 28px; + font-size: 11px; + padding: 0 5px; +} +.tabs > li > a:hover { + color: #000000; + text-decoration: none; + background-color: transparent; + border: none; +} +.tabs > li, .pills > li { + float: right; +} +.topbar .dropdown-menu a, .dropdown-menu a { + font-size: 11px; +/* padding: 2px 12px;*/ + line-height: 14px; +} +.tabs .active > a, .tabs .active > a:hover { + color: #000000; + border: none; + cursor: default; +} +.tabs .menu-dropdown, .tabs .dropdown-menu { + border-radius: 0 0 6px 6px; + left: 10px; + width: 160px; +} +.srolled .tabs .menu-dropdown, .srolled .tabs .dropdown-menu { + top: 32px; +} +.dropdown-toggle { + color: #6D8CA0; +} + +ul.tabs .double ul, ul.tabs .triple ul, ul.tabs .quad ul{ + width:760px; + margin-bottom:20px; + overflow:hidden; + border-top:1px solid #ccc; +} +/*ul.tabs .double li, ul.tabs .triple li, ul.tabs .quad li{ + line-height:1.5em; + border-bottom:1px solid #ccc; + float:left; + display:inline; +}*/ + +/* + Center content (the "real stuff") +*/ + +#nonFooter { + padding-top: 40px; +} +#wrapper { + height: 100%; +} + +.content { + height: 100%; +} + +header.filler { + position: relative; + height: 40px; + width: 100%; +} + +/* +.container-fluid .row-fluid { + width: 1000px; + margin-left: auto; + margin-right: auto; +}*/ + +.divider { + height: 3px; + background-color: #BEDAEA; + margin-bottom: 3px; +} + +#sidebar h3 a, +#sidebar h3 a:hover { + color: #404040; +} + +#sidebarContainer { + padding-top: 20px; +} + +#mainContent { + margin-left: 30px; +} + +#documentation { + padding-top: 35px; + padding-bottom: 10px; +} + +#documentation article.article { + border-top: 1px solid #e9e9e9; + padding: 16px 10px 2px; + -webkit-transition: padding 0.2s; + -moz-transition: padding 0.2s; + -o-transition: padding 0.2s; +} + +#documentation h3.sectionHeader + article.article { + border-top: none; +} + +div#documentation article:last-child { + border-bottom: 1px solid #e9e9e9; + padding-bottom: 40px; +} +#documentation article.article.methodToggleOpen { + background: rgba(255, 255, 255, 0.5); + font-size: 13px; + line-height: 24px; + margin: 0 0 10px 0; +} + +#documentation article:first-child { + border:none; +} + +.site_logo { + display: block; + margin-left: auto; + margin-right: auto; +} +/* + Edit in Cloud9, sucka +*/ + +.snippet pre { + margin-bottom: 0; +} + +.snippet .toolbar { + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; + + text-align: right; + padding: 3px 10px; + margin-top : -1px; +} + +.snippet .filename, .snippet .toolbar { + font-family: Ubuntu, sans-serif; + font-size: 12px; + color: #EEE; +} + +.snippet .filename { + padding: 0 5px 2px 5px; + font-size: 10px; + background: rgba(230,230,230,0.5); + padding: 0 5px 2px 5px; + border-radius: 0 6px 0 6px; + margin : 1px; + position : absolute; + right : 0; + top : 0; +} + +.snippet .filename span{ + color : #666; +} + +.snippet .toolbar { + background-color: rgba(30,30,30,0.5); +} + +div.snippet { + margin-bottom: 18px; + position : relative; +} + +div.snippet a, div.toolbar a { + color: #FFF; +} + +/* + All about signatures +*/ + +.signatures { +/* width: 800px;*/ + margin-left: 20px; + margin-bottom: 5px; +} +.sideToggler { + padding-left: 20px; +} +ul.signatures ul { + list-style: none; + display: inline; +} + +li.signature { + list-style: none; +} + +.signature ul { + padding: 0; + margin: 0; +} + +.signature li { + display: inline; +} + +.signature ul.argument-types::before { + content: '→'; + margin: 0 5px; +} + +.signature li.argument-type::after { + content: '|'; + padding: 0 5px 0 5px; +} + +.signature li.argument-type:last-child:after { + content: ''; + padding: 0 5px 0 5px; +} + +.member-name { + color: #4397cd; + font-weight: bold; + text-decoration: none; + cursor: pointer; + padding-right: 3px; +} + +.signature-call { + cursor: pointer; +} + +#documentation .signature-call a { + color: #8e487e; +} + +.sigClassName { + display: none; +} + +.eventObjName { + font-style: italic; +} +.eventListenerStart, .eventListenerClose, .eventFunctionOpen, .eventFunctionClose { + color: #999999; +} +.eventMember { + padding-right: 0px; +} + +.metaInfo { + float: right; + z-index: 1; + position: relative; +} + +.chainable { + background-color: #0072bc; + color: #ffffff; +} + +.deprecated { + background-color: #f7941d; + color: #ffffff; +} + +.alias { + background-color: #6c951e; + color: #ffffff; +} + +.related-to { + background-color: #89289a; + color: #ffffff; + font-size: 10px; + padding: 2px 5px 3px; + text-transform: capitalize; +} + +.undocumented { + background-color: #B94A48; + color: #ffffff; +} + +#documentation .alias a, #documentation .related-to a { + color: #ffffff; + /* text-decoration: underline; */ +} +#documentation .alias a:hover, #documentation .related-to a:hover { + text-decoration: none; +} +.#documentation alias:hover, #documentation .related-to:hover { + opacity: 0.8; + cursor: pointer; +} +.memberContent .title { + +} +.memberContent .description { + position:relative; + /*top: -13px;*/ + display: none; +} +.snip-container .actions .toggle-plaintext label { + margin-top: 1px; + padding-top: 0; + text-align: left; +} +.snip-container .actions .toggle-plaintext input { + margin-top: 4px !important; +} +.snip-container label { + color: #ffffff; +} +.description h4 { + padding-top: 10px; + font-size: 18px; + line-height : 18px; +} + +.table-striped tbody tr:nth-child(odd) td, .table-striped tbody tr:nth-child(odd) th { + background-color: #F9F9F9; +} +.table-striped tbody tr:nth-child(even) td, .table-striped tbody tr:nth-child(even) th { + background-color: #fbfbfb; +} + +.argument-list { + margin-bottom : 13px; +} +.argName { + font-style: italic; +} + + +/* + Everyday I'm togglin' +*/ + +#documentation i.methodToggle { + cursor: pointer; + color: #9f9f9f; + padding-top: 2px; + float: left; +} +#documentation i.methodToggle.methodToggleHover { + text-shadow: 0 0 10px #4699d5; + color: #4699d5; +} +#documentation i.methodToggle.active { + text-shadow: 0 0 10px #4699d5; + color: #4699d5; + /* Safari */ + -webkit-transform: rotate(45deg); + + /* Firefox */ + -moz-transform: rotate(45deg); + + /* IE */ + -ms-transform: rotate(45deg); + + /* Opera */ + -o-transform: rotate(45deg); + padding-top: 9px; +} + +#documentation h3.sectionHeader { + line-height : 24px; +} + +div.method { + position: relative; +} + +.methodToggle a { + color: #fff; + border-bottom: 0px; + text-decoration: none; +} + +h3.methodToggle { + height : 13px; + width : 8px; + background-position : 0px 0px; + position: absolute; + top: -20px; + background-image : url(../images/member-sprites.png); + background-color : transparent; + background-repeat : no-repeat; + overflow: hidden; + left: 0px; +} + +h3.methodToggleHover { + /* background-position : 0px -28px; */ +} + +h3.methodToggle.inactive { + top: 4px; +} + +h3.methodToggle.active { + top: 6px; + height : 13px; + width : 8px; + background-position : 0px -59px; +} + +.hidden { + display: none; + visibility: hidden; +} + +.hiddenSpan { + display: none; +} + +.ellipsis_description, .short_description { +/* width: 800px;*/ +} +.methodToggleOpen .ellipsis_description { + display: none; +} +.sideToggler .short_description, +.sideToggler .description{ + display: none; +} +.methodToggleOpen .short_description, +.methodToggleOpen .description { + display: block; +} +.description td p { + margin: 0; +} +/* + Footer? I hardly know her +*/ + +#footer { + width:100%; + background: #101010 url(../images/dashed_back.png) repeat 0 0; + font-size: 12px; + color: white; + height: 40px; +} +#footer .footerInner { + padding-left: 300px; + margin-left: auto; + margin-right: auto; + min-height: 40px; +} +#footer .footer-text { + display: block; + font-size: 12px; + float: right; +} +#footer div.footerInner div.footer-text p { + font-size: 12px; + font-family: Arial; + line-height: 18px; + margin: 10px 15px 0px 1px; +} + +#footer a, #footer a:hover { + color: #8DD0FF; +} + +.logoText, .logoImg { + /*position: absolute;*/ + margin-bottom: 5px; +} + +.logoImg { + top: 40px; +} +.topbar div > ul .menu-dropdown li a:hover, +.nav .menu-dropdown li a:hover, +.topbar div > ul .dropdown-menu li a:hover, +.nav .dropdown-menu li a:hover { + background-color: #191919; + background-repeat: repeat-x; + background-image: -khtml-gradient(linear, left top, left bottom, from(#292929), to(#191919)); + background-image: -moz-linear-gradient(top, #292929, #191919); + background-image: -ms-linear-gradient(top, #292929, #191919); + background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #292929), color-stop(100%, #191919)); + background-image: -webkit-linear-gradient(top, #292929, #191919); + background-image: -o-linear-gradient(top, #292929, #191919); + background-image: linear-gradient(top, #292929, #191919); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#292929', endColorstr='#191919', GradientType=0); + color: #ffffff; +} + +.alert-message.block-message { + background: #fefaca; + border-color : #fefaca; + padding : 8px 14px 8px 14px; +} + +body .dsq-reply{ + margin-top : 10px; +} + +#disqus_thread{ + border-top : 1px solid #ddd; + margin-top : 30px; +} + +#disqus_thread h3, body #dsq-content h3 { + font-size : 12px; + margin : 0 0 20px 0; + line-height : 12px; +} +body #dsq-reply h3{ + font-size : 18px; + line-height : 18px; + margin : 15px 0 20px 0; +} + +#disqus_thread select{ + font-size : 11px; + height : 20px; + color : #444; +} + +#dsq-global-toolbar, #dsq-pagination, .dsq-trackback-url{ + display : none; +} diff --git a/node_modules/ace/doc/template/resources/font/fontawesome-webfont.eot b/node_modules/ace/doc/template/resources/font/fontawesome-webfont.eot new file mode 100644 index 0000000000000000000000000000000000000000..89070c1e63c2703b2334023922ecc1664f759b55 GIT binary patch literal 38708 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/node_modules/ace/doc/template/resources/font/fontawesome-webfont.ttf b/node_modules/ace/doc/template/resources/font/fontawesome-webfont.ttf new file mode 100644 index 0000000000000000000000000000000000000000..c17e9f8d100d01a002029b5b93cc081062618bf3 GIT binary patch literal 68476 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 literal 0 HcmV?d00001 diff --git a/node_modules/ace/doc/template/resources/images/Ace_ERD.png b/node_modules/ace/doc/template/resources/images/Ace_ERD.png new file mode 100644 index 0000000000000000000000000000000000000000..78fb8dab6a25315303e12b6653b480886ad85578 GIT binary patch literal 59424 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 E1vXzqcmMzZ literal 0 HcmV?d00001 diff --git a/node_modules/ace/doc/template/resources/images/ace_logo.png b/node_modules/ace/doc/template/resources/images/ace_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..4dab4f66ebffb0816dc8968ea52f64773970bedb GIT binary patch literal 42538 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 PelKaN>Z(*J*+l#o=FgAV literal 0 HcmV?d00001 diff --git a/node_modules/ace/doc/template/resources/images/c9-sponsor.png b/node_modules/ace/doc/template/resources/images/c9-sponsor.png new file mode 100644 index 0000000000000000000000000000000000000000..599d3b49b07be4610d0ce3c808b47c7218eb2257 GIT binary patch literal 12244 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

      C+U-;RWd&sWGV{Ott_dLlyBKs{1ktj;JxN^%*2 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 literal 0 HcmV?d00001 diff --git a/node_modules/ace/doc/template/resources/images/cloud9-logo.png b/node_modules/ace/doc/template/resources/images/cloud9-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..912524a9ee1d12e58f34ec5622fd4d0b99cfd9ea GIT binary patch literal 14564 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 P00000NkvXXu0mjfThRhE literal 0 HcmV?d00001 diff --git a/node_modules/ace/doc/template/resources/images/dashed_back.png b/node_modules/ace/doc/template/resources/images/dashed_back.png new file mode 100644 index 0000000000000000000000000000000000000000..c6ee9313f2d636546a778425ff998e839f05624f GIT binary patch literal 3445 zcmV-*4T|!KP)KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z0007@Nklv)PPhvl%6OdwT=`&N;wZOV`)eWUVDJjw2o) zA0dQ5a&T}!0N}lcl2XDshx_|`2=6@}9v+Y+36j&(Qv!f-93euuySsx30l zdGE1WtzzcAU$fO}_3s!F!8!NNy`7w#?9%oTwt4CC@$oKgJF=srqt9YQw0@`2t3NzE z+~o_|$dvaUx3{;)xw)YYb`C8OS0B7v(`?Ty88AFU%q_B%gb-5=jUhqdV1m`7-I+k z=JPpVjG?Nk$QVNi!5BlI#Ih`7R@XJNx~@rUO2udkRlu`r$P1C$#&bcXT+m>0F#!N~{0MKdU2>LSs XM~`vmQcs7_00000NkvXXu0mjfem-^= literal 0 HcmV?d00001 diff --git a/node_modules/ace/doc/template/resources/images/footer-bg.png b/node_modules/ace/doc/template/resources/images/footer-bg.png new file mode 100644 index 0000000000000000000000000000000000000000..0d572c2809916d5279032187efd1863651024884 GIT binary patch literal 1090 zcmaJ=TSyd97@jWLwjphyK|Y-w!3y1-%eK4j;HJAfySm}Xwk~J|(KvI|VVybC%+Xz? z2NMm2C_xAVDJY{Ls;5Hmq0C-{dgv+WAt<7!KmjMD460vS8Y3=P&HI3J};rh23dNFWP> zpr7?AY={LR&d&vohr{7Uz_T37usp-@J}xW-c!6cX#z&KAmf9y|#neVDGKc<=Kf^^L5l4gPeFWjNM+__%eTH3ERuG}BSel77WB^A|?nOg5N)xB06m)Y_ z*048@i5wVHlud^7vrbB7pd|ets_UC*8)xBPzgr61xe*gGS!kmnOCcB6SLcK>g@grV zjI10&gXL4q3?Pi`0c3(iR}e_Dq8ZM79WO~j+OV-~C@?KXX`72r75|+ml9Xq!b>TSrqs4vhL~ZTi~Z-K%S)tsoZ)8KlF4S_LxWViMasHj z?D9SGB%Y?lSg!c)%iHCu72v6O(>T`<&z$^$s^%*%eoKvZy}0^WX6txV@afk38T;4$hTRjMopINt$BmO? zp4p1YRNr$=+jDfnGuK#JXHS#Oi80SLp|nX5*W;~ItK)Ik^3v>+ q@52?yb#p3mr0&MV70#7@>3dG)&xIEj=RPhtuR5LV6d%RUkN*LJOIQW~ literal 0 HcmV?d00001 diff --git a/node_modules/ace/doc/template/resources/images/main_bg.png b/node_modules/ace/doc/template/resources/images/main_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..f26aefc2af41d6a77b1c5caa18f50cbe26e5990a GIT binary patch literal 9630 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 U(??5`rT_o{07*qoM6N<$f-EzwH~;_u literal 0 HcmV?d00001 diff --git a/node_modules/ace/doc/template/resources/images/member-sprites.png b/node_modules/ace/doc/template/resources/images/member-sprites.png new file mode 100644 index 0000000000000000000000000000000000000000..96b0520fd70a6299d27e188d1090606c78b3c72a GIT binary patch literal 3505 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 literal 0 HcmV?d00001 diff --git a/node_modules/ace/doc/template/resources/images/menu_disc.png b/node_modules/ace/doc/template/resources/images/menu_disc.png new file mode 100644 index 0000000000000000000000000000000000000000..1d3925b3f103cb7d1d2ccb34251cb2543f936f2e GIT binary patch literal 556 zcmV+{0@MA8P)KLZ*U+R`sCEkzKl)gj5&q@hY_5?)@_euSf22N!q0z{yc?Q2YY_Kym8e z5Fvwu2%hQO!{u_psMvL#(bD64NQRTZj^-}DnS22ry9f-;mW=gZvQj}U-ZdMsK&I8^7~DvX`q=inIVXE>RF&gA_=FG; u5mXfsK}5K&3+cUYfYusjMvM_v&>- literal 0 HcmV?d00001 diff --git a/node_modules/ace/doc/template/resources/images/method_bg.png b/node_modules/ace/doc/template/resources/images/method_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..b018955737a730de52f23bc8fd39786ffe7cd9d0 GIT binary patch literal 8001 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 N002ovPDHLkV1g96i!uNJ literal 0 HcmV?d00001 diff --git a/node_modules/ace/doc/template/resources/images/sidebar-top-bg.png b/node_modules/ace/doc/template/resources/images/sidebar-top-bg.png new file mode 100644 index 0000000000000000000000000000000000000000..c0a800e1f8ac0b7cba486dba48441f5cfaaca8be GIT binary patch literal 2693 zcmaJ@c{r47AD)mURCE%9&KQL(vogjsgjpXhEv2IGNHi%+mV_*sV>#)JPIbONzP|Um-uHQa&voDTZ+))o&G7Yh(_RBz z1A#!aJ>1FuiuG5;yG~t6@wGp&z)&m(AcY3*=0<=bIv;?zgmc3HmK!4gu{0@!H6*gg#a4>>981fG)F*)afE-;B`EeQ$4EHr z69kNMg#R5B&C3@?;_?BQ9Rg*;K;cj@92$Yf+S=ROTf;CYGzy8rAki2bv^@cfA)rvO z&ktPTjUOIC@F!D0`%+kr@JJBk5s*lcNQ4k!5nTR3B-+8jVMPOju~8sw1hE{D9%I81 zn0`?p0|Ex0$pe{O4s1n{9>x`dj&Mb!f2Y9aeU;@1K9@;RFk}p!heRV#D=B>edU^eS zD4YEiEdc$2f8zb0!h(QU9)R=*1Y9AXp=ex$>53~Jfy4*sAeSG&^vH=eGg&Y147xPW-$|$gT3eRMK&pZT#Q~6vr>{H4F<~L)p zqkdEGGdKL(v7o-mMJj?pt~B<)8vW%+F+D5WuVbq)z79UXQA|5uG1fCf3)&Ef>VgN^ zB_QT`=jk4nk;i&U@V@AeACYTRT-WKU8wAN7?)iRUUN@*$eV92`()##;SUg81%MS^K z)ofW!+{;(5u(LBWGar^j5kG{4UO1I8>z2nHAp$~QNdNZwY z`D|~#3bD$+lX5d$_Xd!2?AGc+l4Vxoolu{N(e->oR#C%sJyaX-1(C#fG_lmLfi-az zZ(FVzy8n~jIfLYbc4}t#jL{c0@wU>LE@ixJmJoT^nDT~Y%q5pr=GrH76&K&aeI%7Y zZq}V!TQ1Hm1T4NIq7wV0l^6E>Zc?=Bg%~EkpJB3@F({b0i)qKFxq22y+0+?tCN5+5 zE~}qU<&$6X$^;{zH$BiI{TjaBTNxPEX-d}}3)P?qA)pbdxY*QM7IgA4?7q47y~Vm? zTa!E;?Qh*|$XKtuOlpzI_IDYmJh$6t3Kn=8o*}04DQ5FO3yG@8loL)#eu9B1PAoem zI*oL5xpTI{#xlJoC0cN*l+<*8T3^`}yhv=Pu*$0mR*2;711$Y)m$alKi6%!Ymm(9C zux8Ma?HE5zm+O~1J@3qkE3=rZBu;$a@Wy?*nYDNIpD0akg|6lA+A{8ovUOwGekj|m z%eu%eZ8De6Og62$6zQIyJe!`V(XTD9&}+yZzoF#QE~;{9A$lck@DP-q@bmNW@iEo7 zy55SV8(nH7uIo3^e7=iTo1a)z{w&i!V#NFGc{8{50V(zilh?T6o$?lQUlsG*yzWFj z6cN@kJ$1Pe`oMi=cBK9G+><0%m7{_3v3Kju-QK3nkG$U#Jsk(xa-|b#S zvUp6%Cse&`EXdWXSz1~;-nL2hXl05xu1TV(;x-?*TE|uHcfUxGh9d{d*36 zODY?)*_u8s+3jxnA!w@cHGZfYdmv?kWYVW*R!M|RNS2Y z`y)S7tG9DI+OKcP>6dV%QmJ7^=~>c={UivA@Xtq4hd6P@VnrUXe%=w~ZEOYaW$K)P{|X)@I)m)yMVWrJXt{vTGr?>jYTZ#y#`K z+9k!cnNE8<-p@fFGROTaB2hgRCPt4Q6MCo<&f|tRIJTbb)9$QDncpG$v*FyD zW|T$LmUF>ZplOrK*r$%kD25qMqk#5ou*);6Ry**}&OoLLx+@uv_pGk!YBj&3pE`J4 zR-Bf#{f2G_Ce(kmd`OR4`J!?QbQ7+~y&8px#u58$k4#F`&8Gw}{ND{6lpNOCVK-I> zT?`2}l(S`lSGAi@ZFqKcBKG1n?ckn-uAPeH8?8~;_v@j^FWM>ROt% zM`#8ii=Cmhmz{dAWYQBk>1EDJKWkF${Wq5wS%AbG1Ew+U<4-YH?ikHq+YnW!uM!;E q{jpaa61jM9fI=A43m{H~Fe-X!2h!YK=+& literal 0 HcmV?d00001 diff --git a/node_modules/ace/doc/template/resources/images/sidebar_border.png b/node_modules/ace/doc/template/resources/images/sidebar_border.png new file mode 100644 index 0000000000000000000000000000000000000000..ea6cd700be849c020b74c06ca2c4ed521b744cd6 GIT binary patch literal 2967 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 LQ|<2BoVog6l3=FD literal 0 HcmV?d00001 diff --git a/node_modules/ace/doc/template/resources/images/swirl_divider.png b/node_modules/ace/doc/template/resources/images/swirl_divider.png new file mode 100644 index 0000000000000000000000000000000000000000..f3e9f6c6af3c18fc84c25594f3434d1a1031d209 GIT binary patch literal 1043 zcmV+u1nm2XP)R?59o%`Dv8?v^mBYql_}fD5H#NI5wfv&DMR<8C9Dp z{b^e^v-L~bZ0nk)O`A)u`Tjk3d*_zexpnOpD_QReFPGfsbI(Jc>&NrlJ%{E(Q9;-b z9q7jm45JSYQ`~`G3_->K4qMvj#%0L3g428Sc?1%?7=+vCM~sE=8@jGH&GvshVPEvm zuSH*c-P)d9kEdq7Y^sZ#)A0eP(1UxQBkI!)H9fhqwH=%fMT?wM(2p*R2i9YcR+Yqy zZ_&iU!kUt)xA76(mi`I!|$Xw#$v$P9b~8475=|Z&~7<%s`id#Onq0IY);j=j?VSUp1~rWIO$` z*6tqvAf2&P?h}RfjNQjb__xKg9WE0$qyxqa*~Z4;Z$bjPjm6<_f)BEdc_AGzZn#X^ zjoAQPCT>Uvj2E(vjlti91pfF_TT(MC{F788@5l4asGiOje~ITyWjzp%89BT((sRYK zLDPQbD5v*FmAX^+HF5=7yccVKFx2r7#*fEcGAMZ(64*XE2`5HQG=)9{XK?JWIX9BLR=y z$4C&*JcZW05!;wiE;E~4F})49I*D1{jz1*dXL^HPfV4vaO|a#tk>i8Yl5=rgO_>X5 z&klXM>2H$UHoK3JAd08Zx;LYT<@*K&Z;RhS$nZkODlcsUxnk)(dHwbL>&aX}XU3|T z_HkZ=gyF?-Y=-uV>=|to&=9Ub!Vo5yeNNSu{_OFr@H>kUNOeB8PL0yffZfMN5XDny z{TtHFp39J$&Tp>8k{@cD*4ZrohCP=NVt({k3oef`!?hwxp2DX2cOfPDh&SX9iA~}x zX1QLECbKGq^fhfhF-K@?BnKU%_L z05>3G2*-EHcff<2kTHlpOU_ALhK#H5z-eit4').hide().insertAfter("body")[0].contentWindow;q=function(){return a(n.document[c][l])};o=function(u,s){if(u!==s){var t=n.document;t.open().close();t[c].hash="#"+u}};o(a())}}m.start=function(){if(r){return}var t=a();o||p();(function s(){var v=a(),u=q(t);if(v!==t){o(t=v,u);$(i).trigger(d)}else{if(u!==t){i[c][l]=i[c][l].replace(/#.*/,"")+"#"+u}}r=setTimeout(s,$[d+"Delay"])})()};m.stop=function(){if(!n){r&&clearTimeout(r);r=0}};return m})()})(jQuery,this); \ No newline at end of file diff --git a/node_modules/ace/doc/template/resources/javascripts/bootstrap.js b/node_modules/ace/doc/template/resources/javascripts/bootstrap.js new file mode 100644 index 00000000..79241e74 --- /dev/null +++ b/node_modules/ace/doc/template/resources/javascripts/bootstrap.js @@ -0,0 +1,389 @@ +/* ============================================================ + * bootstrap-dropdown.js v2.1.1 + * http://twitter.github.com/bootstrap/javascript.html#dropdowns + * ============================================================ + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* DROPDOWN CLASS DEFINITION + * ========================= */ + + var toggle = '[data-toggle=dropdown]' + , Dropdown = function (element) { + var $el = $(element).on('click.dropdown.data-api', this.toggle) + $('html').on('click.dropdown.data-api', function () { + $el.parent().removeClass('open') + }) + } + + Dropdown.prototype = { + + constructor: Dropdown + + , toggle: function (e) { + var $this = $(this) + , $parent + , isActive + + if ($this.is('.disabled, :disabled')) return + + $parent = getParent($this) + + isActive = $parent.hasClass('open') + + clearMenus() + + if (!isActive) { + $parent.toggleClass('open') + $this.focus() + } + + return false + } + + , keydown: function (e) { + var $this + , $items + , $active + , $parent + , isActive + , index + + if (!/(38|40|27)/.test(e.keyCode)) return + + $this = $(this) + + e.preventDefault() + e.stopPropagation() + + if ($this.is('.disabled, :disabled')) return + + $parent = getParent($this) + + isActive = $parent.hasClass('open') + + if (!isActive || (isActive && e.keyCode == 27)) return $this.click() + + $items = $('[role=menu] li:not(.divider) a', $parent) + + if (!$items.length) return + + index = $items.index($items.filter(':focus')) + + if (e.keyCode == 38 && index > 0) index-- // up + if (e.keyCode == 40 && index < $items.length - 1) index++ // down + if (!~index) index = 0 + + $items + .eq(index) + .focus() + } + + } + + function clearMenus() { + getParent($(toggle)) + .removeClass('open') + } + + function getParent($this) { + var selector = $this.attr('data-target') + , $parent + + if (!selector) { + selector = $this.attr('href') + selector = selector && /#/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + $parent.length || ($parent = $this.parent()) + + return $parent + } + + + /* DROPDOWN PLUGIN DEFINITION + * ========================== */ + + $.fn.dropdown = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('dropdown') + if (!data) $this.data('dropdown', (data = new Dropdown(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.dropdown.Constructor = Dropdown + + + /* APPLY TO STANDARD DROPDOWN ELEMENTS + * =================================== */ + + $(function () { + $('html') + .on('click.dropdown.data-api touchstart.dropdown.data-api', clearMenus) + $('body') + .on('click.dropdown touchstart.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() }) + .on('click.dropdown.data-api touchstart.dropdown.data-api' , toggle, Dropdown.prototype.toggle) + .on('keydown.dropdown.data-api touchstart.dropdown.data-api', toggle + ', [role=menu]' , Dropdown.prototype.keydown) + }) + +}(window.jQuery); +/* ======================================================== + * bootstrap-tab.js v2.1.1 + * http://twitter.github.com/bootstrap/javascript.html#tabs + * ======================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================== */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* TAB CLASS DEFINITION + * ==================== */ + + var Tab = function (element) { + this.element = $(element) + } + + Tab.prototype = { + + constructor: Tab + + , show: function () { + var $this = this.element + , $ul = $this.closest('ul:not(.dropdown-menu)') + , selector = $this.attr('data-target') + , previous + , $target + , e + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + if ( $this.parent('li').hasClass('active') ) return + + previous = $ul.find('.active a').last()[0] + + e = $.Event('show', { + relatedTarget: previous + }) + + $this.trigger(e) + + if (e.isDefaultPrevented()) return + + $target = $(selector) + + this.activate($this.parent('li'), $ul) + this.activate($target, $target.parent(), function () { + $this.trigger({ + type: 'shown' + , relatedTarget: previous + }) + }) + } + + , activate: function ( element, container, callback) { + var $active = container.find('> .active') + , transition = callback + && $.support.transition + && $active.hasClass('fade') + + function next() { + $active + .removeClass('active') + .find('> .dropdown-menu > .active') + .removeClass('active') + + element.addClass('active') + + if (transition) { + element[0].offsetWidth // reflow for transition + element.addClass('in') + } else { + element.removeClass('fade') + } + + if ( element.parent('.dropdown-menu') ) { + element.closest('li.dropdown').addClass('active') + } + + callback && callback() + } + + transition ? + $active.one($.support.transition.end, next) : + next() + + $active.removeClass('in') + } + } + + + /* TAB PLUGIN DEFINITION + * ===================== */ + + $.fn.tab = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('tab') + if (!data) $this.data('tab', (data = new Tab(this))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.tab.Constructor = Tab + + + /* TAB DATA-API + * ============ */ + + $(function () { + $('body').on('click.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) { + e.preventDefault() + $(this).tab('show') + }) + }) + +}(window.jQuery); +/* ========================================================== + * bootstrap-affix.js v2.1.1 + * http://twitter.github.com/bootstrap/javascript.html#affix + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* AFFIX CLASS DEFINITION + * ====================== */ + + var Affix = function (element, options) { + this.options = $.extend({}, $.fn.affix.defaults, options) + this.$window = $(window).on('scroll.affix.data-api', $.proxy(this.checkPosition, this)) + this.$element = $(element) + this.checkPosition() + } + + Affix.prototype.checkPosition = function () { + if (!this.$element.is(':visible')) return + + var scrollHeight = $(document).height() + , scrollTop = this.$window.scrollTop() + , position = this.$element.offset() + , offset = this.options.offset + , offsetBottom = offset.bottom + , offsetTop = offset.top + , reset = 'affix affix-top affix-bottom' + , affix + + if (typeof offset != 'object') offsetBottom = offsetTop = offset + if (typeof offsetTop == 'function') offsetTop = offset.top() + if (typeof offsetBottom == 'function') offsetBottom = offset.bottom() + + affix = this.unpin != null && (scrollTop + this.unpin <= position.top) ? + false : offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ? + 'bottom' : offsetTop != null && scrollTop <= offsetTop ? + 'top' : false + + if (this.affixed === affix) return + + this.affixed = affix + this.unpin = affix == 'bottom' ? position.top - scrollTop : null + + this.$element.removeClass(reset).addClass('affix' + (affix ? '-' + affix : '')) + } + + + /* AFFIX PLUGIN DEFINITION + * ======================= */ + + $.fn.affix = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('affix') + , options = typeof option == 'object' && option + if (!data) $this.data('affix', (data = new Affix(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.affix.Constructor = Affix + + $.fn.affix.defaults = { + offset: 0 + } + + + /* AFFIX DATA-API + * ============== */ + + $(window).on('load', function () { + $('[data-spy="affix"]').each(function () { + var $spy = $(this) + , data = $spy.data() + + data.offset = data.offset || {} + + data.offsetBottom && (data.offset.bottom = data.offsetBottom) + data.offsetTop && (data.offset.top = data.offsetTop) + + $spy.affix(data) + }) + }) + + +}(window.jQuery); \ No newline at end of file diff --git a/node_modules/ace/doc/template/resources/javascripts/clicker.js b/node_modules/ace/doc/template/resources/javascripts/clicker.js new file mode 100644 index 00000000..90e7e12c --- /dev/null +++ b/node_modules/ace/doc/template/resources/javascripts/clicker.js @@ -0,0 +1,69 @@ +function setupClicker() { + // when hovering over arrow, add highlight (only if inactive) + $("i.methodToggle").hover(function () { + if (!$("i.methodToggle").hasClass('active')) + $(this).addClass("methodToggleHover"); + }, + function () { + $(this).removeClass("methodToggleHover"); + } + ); + + function handleClick(e, linkHref) { + //if (linkHref.indexOf("nav=api&api=") >= 0) + // return; + if (linkHref == "api") + return; + + e.preventDefault(); + + var dstElem; + if (linkHref) { + dstElem = $("article[id='" + linkHref + "']"); + } + + var $article = (dstElem || $(this)).closest('.article'), + $arrow = $('i.methodClicker', $article); + + if (!$article.hasClass('methodToggleOpen') || this.force) { + $article.addClass('methodToggleOpen'); + $arrow.removeClass('inactive').addClass('active'); + + if (!$arrow[0]) + return; + + var data = $arrow[0].id.replace(/^js_/, ""); + //var state = {}; + //state.section = data; + //$.bbq.pushState(state); + + scrollTo(null, data); + } + else { + $article.removeClass('methodToggleOpen'); + $arrow.removeClass('active').addClass('inactive'); + } + } + + function transformHash(e) { + // some bs to figure out link hash + var hashId = (e.srcElement ? e.srcElement.href : (e.hash || e.target.href)) || e.currentTarget.hash; + + handleClick(e, hashId.substring(hashId.indexOf("#") + 1)); + } + + // for the arrow + $("i.methodToggle").click(handleClick); + + // for the signature + $('.member-name').click(handleClick); + + // for the top dropdown + $('li.memberLink a').click(transformHash); + + //$('a[href^="#"]').click(transformHash); + + $('.related-to', '.metaInfo').click(function(){ + location.hash = $(this).find('a').attr('href').split('#')[1]; + }); +} \ No newline at end of file diff --git a/node_modules/ace/doc/template/resources/javascripts/disqus-ext.js b/node_modules/ace/doc/template/resources/javascripts/disqus-ext.js new file mode 100644 index 00000000..6bb7ff4e --- /dev/null +++ b/node_modules/ace/doc/template/resources/javascripts/disqus-ext.js @@ -0,0 +1,17 @@ +function setupDisqus(href) { + var disqus_shortname = 'aceapi'; + + //var paths = window.location.pathname.split("/"); + //var fileName = paths[paths.length - 2] + "/" + paths[paths.length - 1]; + + //var disqus_identifier = fileName; + var disqus_identifier = href.substring(2); + + (function() { + if (document.getElementById("disqusScript") === null) { + var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; + dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; + (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); + } + })(); +} \ No newline at end of file diff --git a/node_modules/ace/doc/template/resources/javascripts/jquery-scrollspy.js b/node_modules/ace/doc/template/resources/javascripts/jquery-scrollspy.js new file mode 100644 index 00000000..71b4a363 --- /dev/null +++ b/node_modules/ace/doc/template/resources/javascripts/jquery-scrollspy.js @@ -0,0 +1,98 @@ +/*! + * jQuery Scrollspy Plugin + * Author: @sxalexander + * Licensed under the MIT license + */ + + +;(function ( $, window, document, undefined ) { + + $.fn.extend({ + scrollspy: function ( options ) { + + var defaults = { + min: 0, + max: 0, + mode: 'vertical', + buffer: 0, + container: window, + onEnter: options.onEnter ? options.onEnter : [], + onLeave: options.onLeave ? options.onLeave : [], + onTick: options.onTick ? options.onTick : [] + } + + var options = $.extend( {}, defaults, options ); + + return this.each(function (i) { + + var element = this; + var o = options; + var $container = $(o.container); + var mode = o.mode; + var buffer = o.buffer; + var enters = leaves = 0; + var inside = false; + + /* add listener to container */ + $container.bind('scroll', function(e){ + var position = {top: $(this).scrollTop(), left: $(this).scrollLeft()}; + var xy = (mode == 'vertical') ? position.top + buffer : position.left + buffer; + var max = o.max; + var min = o.min; + + /* fix max */ + if($.isFunction(o.max)){ + max = o.max(); + } + + /* fix max */ + if($.isFunction(o.min)){ + min = o.min(); + } + + if(max == 0){ + max = (mode == 'vertical') ? $container.height() : $container.outerWidth() + $(element).outerWidth(); + } + + /* if we have reached the minimum bound but are below the max ... */ + if(xy >= o.min && xy <= max){ + /* trigger enter event */ + if(!inside){ + inside = true; + enters++; + + /* fire enter event */ + $(element).trigger('scrollEnter', {position: position}) + if($.isFunction(o.onEnter)){ + o.onEnter(element, position); + } + + } + + /* triger tick event */ + $(element).trigger('scrollTick', {position: position, inside: inside, enters: enters, leaves: leaves}) + if($.isFunction(o.onTick)){ + o.onTick(element, position, inside, enters, leaves); + } + }else{ + + if(inside){ + inside = false; + leaves++; + /* trigger leave event */ + $(element).trigger('scrollLeave', {position: position, leaves:leaves}) + + if($.isFunction(o.onLeave)){ + o.onLeave(element, position); + } + } + } + }); + + }); + } + + }) + + +})( jQuery, window ); diff --git a/node_modules/ace/doc/template/resources/javascripts/jquery.collapse.js b/node_modules/ace/doc/template/resources/javascripts/jquery.collapse.js new file mode 100644 index 00000000..427ee5fa --- /dev/null +++ b/node_modules/ace/doc/template/resources/javascripts/jquery.collapse.js @@ -0,0 +1,151 @@ +/*! + * Collapse plugin for jQuery + * http://github.com/danielstocks/jQuery-Collapse/ + * + * @author Daniel Stocks (http://webcloud.se) + * @version 0.9.1 + * @updated 17-AUG-2010 + * + * Copyright 2010, Daniel Stocks + * Released under the MIT, BSD, and GPL Licenses. + */ + +(function($) { + + // Use a cookie counter to allow multiple instances of the plugin + var cookieCounter = 0; + + $.fn.extend({ + collapse: function(options) { + + var defaults = { + head : "h3", + group : "div, ul", + cookieName : "collapse", + // Default function for showing content + show: function() { + this.show(); + }, + // Default function for hiding content + hide: function() { + this.hide(); + } + }; + var op = $.extend(defaults, options); + + // Default CSS classes + var active = "active", + inactive = "inactive"; + + return this.each(function() { + + // Increment coookie counter to ensure cookie name integrity + cookieCounter++; + var obj = $(this), + // Find all headers and wrap them in for accessibility. + sections = obj.find(op.head).wrapInner(''), + l = sections.length, + cookie = op.cookieName + "_" + cookieCounter; + // Locate all panels directly following a header + var panel = obj.find(op.head).map(function() { + var head = $(this) + if(!head.hasClass(active)) { + return head.next(op.group).hide()[0]; + } + return head.next(op.group)[0]; + }); + + // Bind event for showing content + obj.bind("show", function(e, bypass) { + var obj = $(e.target); + // ARIA attribute + obj.attr('aria-hidden', false) + .prev() + .removeClass(inactive) + .addClass(active); + // Bypass method for instant display + if(bypass) { + obj.show(); + } else { + op.show.call(obj); + } + }); + + // Bind event for hiding content + obj.bind("hide", function(e, bypass) { + var obj = $(e.target); + obj.attr('aria-hidden', true) + .prev() + .removeClass(active) + .addClass(inactive); + if(bypass) { + obj.hide(); + } else { + op.hide.call(obj); + } + }); + + // Look for existing cookies + if(cookieSupport) { + for (var c=0;c<=l;c++) { + var val = $.cookie(cookie + c); + // Show content if associating cookie is found + if ( val == c + "open" ) { + panel.eq(c).trigger('show', [true]); + // Hide content + } else if ( val == c + "closed") { + panel.eq(c).trigger('hide', [true]); + } + } + } + + // Delegate click event to show/hide content. + obj.bind("click", function(e) { + var t = $(e.target); + // Check if header was clicked + if(!t.is(op.head)) { + // What about link inside header. + if ( t.parent().is(op.head) ) { + t = t.parent(); + } else { + return; + } + e.preventDefault(); + } + // Figure out what position the clicked header has. + var num = sections.index(t), + cookieName = cookie + num, + cookieVal = num, + content = t.next(op.group); + // If content is already active, hide it. + if(t.hasClass(active)) { + content.trigger('hide'); + cookieVal += 'closed'; + if(cookieSupport) { + $.cookie(cookieName, cookieVal, { path: '/', expires: 10 }); + } + return; + } + // Otherwise show it. + content.trigger('show'); + cookieVal += 'open'; + if(cookieSupport) { + $.cookie(cookieName, cookieVal, { path: '/', expires: 10 }); + } + }); + }); + } + }); + + // Make sure can we eat cookies without getting into trouble. + var cookieSupport = (function() { + try { + $.cookie('x', 'x', { path: '/', expires: 10 }); + $.cookie('x', null); + } + catch(e) { + return false; + } + return true; + })(); +})(jQuery); \ No newline at end of file diff --git a/node_modules/ace/doc/template/resources/javascripts/jquery.cookie.js b/node_modules/ace/doc/template/resources/javascripts/jquery.cookie.js new file mode 100644 index 00000000..6df1faca --- /dev/null +++ b/node_modules/ace/doc/template/resources/javascripts/jquery.cookie.js @@ -0,0 +1,96 @@ +/** + * Cookie plugin + * + * Copyright (c) 2006 Klaus Hartl (stilbuero.de) + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + * + */ + +/** + * Create a cookie with the given name and value and other optional parameters. + * + * @example $.cookie('the_cookie', 'the_value'); + * @desc Set the value of a cookie. + * @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true }); + * @desc Create a cookie with all available options. + * @example $.cookie('the_cookie', 'the_value'); + * @desc Create a session cookie. + * @example $.cookie('the_cookie', null); + * @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain + * used when the cookie was set. + * + * @param String name The name of the cookie. + * @param String value The value of the cookie. + * @param Object options An object literal containing key/value pairs to provide optional cookie attributes. + * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object. + * If a negative value is specified (e.g. a date in the past), the cookie will be deleted. + * If set to null or omitted, the cookie will be a session cookie and will not be retained + * when the the browser exits. + * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie). + * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie). + * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will + * require a secure protocol (like HTTPS). + * @type undefined + * + * @name $.cookie + * @cat Plugins/Cookie + * @author Klaus Hartl/klaus.hartl@stilbuero.de + */ + +/** + * Get the value of a cookie with the given name. + * + * @example $.cookie('the_cookie'); + * @desc Get the value of a cookie. + * + * @param String name The name of the cookie. + * @return The value of the cookie. + * @type String + * + * @name $.cookie + * @cat Plugins/Cookie + * @author Klaus Hartl/klaus.hartl@stilbuero.de + */ +jQuery.cookie = function(name, value, options) { + if (typeof value != 'undefined') { // name and value given, set cookie + options = options || {}; + if (value === null) { + value = ''; + options.expires = -1; + } + var expires = ''; + if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) { + var date; + if (typeof options.expires == 'number') { + date = new Date(); + date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000)); + } else { + date = options.expires; + } + expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE + } + // CAUTION: Needed to parenthesize options.path and options.domain + // in the following expressions, otherwise they evaluate to undefined + // in the packed version for some reason... + var path = options.path ? '; path=' + (options.path) : ''; + var domain = options.domain ? '; domain=' + (options.domain) : ''; + var secure = options.secure ? '; secure' : ''; + document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join(''); + } else { // only name given, get cookie + var cookieValue = null; + if (document.cookie && document.cookie != '') { + var cookies = document.cookie.split(';'); + for (var i = 0; i < cookies.length; i++) { + var cookie = jQuery.trim(cookies[i]); + // Does this cookie string begin with the name we want? + if (cookie.substring(0, name.length + 1) == (name + '=')) { + cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); + break; + } + } + } + return cookieValue; + } +}; \ No newline at end of file diff --git a/node_modules/ace/doc/template/resources/javascripts/plugins.js b/node_modules/ace/doc/template/resources/javascripts/plugins.js new file mode 100644 index 00000000..efda459c --- /dev/null +++ b/node_modules/ace/doc/template/resources/javascripts/plugins.js @@ -0,0 +1,13 @@ +window.log=function(){log.history=log.history||[];log.history.push(arguments);if(this.console){arguments.callee=arguments.callee.caller;var a=[].slice.call(arguments);(typeof console.log==="object"?log.apply.call(console.log,console,a):console.log.apply(console,a))}}; +(function(b){function c(){}for(var d="assert,count,debug,dir,dirxml,error,exception,group,groupCollapsed,groupEnd,info,log,timeStamp,profile,profileEnd,time,timeEnd,trace,warn".split(","),a;a=d.pop();){b[a]=b[a]||c}})((function(){try +{console.log();return window.console;}catch(err){return window.console={};}})()); + +/* + * jQuery throttle / debounce - v1.1 - 3/7/2010 + * http://benalman.com/projects/jquery-throttle-debounce-plugin/ + * + * Copyright (c) 2010 "Cowboy" Ben Alman + * Dual licensed under the MIT and GPL licenses. + * http://benalman.com/about/license/ + */ +(function(b,c){var $=b.jQuery||b.Cowboy||(b.Cowboy={}),a;$.throttle=a=function(e,f,j,i){var h,d=0;if(typeof f!=="boolean"){i=j;j=f;f=c}function g(){var o=this,m=+new Date()-d,n=arguments;function l(){d=+new Date();j.apply(o,n)}function k(){h=c}if(i&&!h){l()}h&&clearTimeout(h);if(i===c&&m>e){l()}else{if(f!==true){h=setTimeout(i?k:l,i===c?e-m:e)}}}if($.guid){g.guid=j.guid=j.guid||$.guid++}return g};$.debounce=function(d,e,f){return f===c?a(d,e,false):a(d,f,e!==false)}})(this); diff --git a/node_modules/ace/doc/template/resources/javascripts/prettify-extension.js b/node_modules/ace/doc/template/resources/javascripts/prettify-extension.js new file mode 100644 index 00000000..ca8458dc --- /dev/null +++ b/node_modules/ace/doc/template/resources/javascripts/prettify-extension.js @@ -0,0 +1,24 @@ +// Stolen from StackOverflow. Find all

       
      +// elements on the page and add the "prettyprint" style. If at least one 
      +// prettyprint element was found, call the Google Prettify prettyPrint() API.
      +//http://sstatic.net/so/js/master.js?v=6523
      +function styleCode() 
      +{
      +    if (typeof disableStyleCode != "undefined") 
      +    {
      +        return;
      +    }
      +
      +    var a = false;
      +
      +    $("pre code").parent().each(function() 
      +    {
      +        if (!$(this).hasClass("prettyprint")) 
      +        {
      +            $(this).addClass("prettyprint");
      +            a = true
      +        }
      +    });
      +    
      +    if (a) { prettyPrint() } 
      +}
      \ No newline at end of file
      diff --git a/node_modules/ace/doc/template/resources/javascripts/prettify.js b/node_modules/ace/doc/template/resources/javascripts/prettify.js
      new file mode 100644
      index 00000000..eef5ad7e
      --- /dev/null
      +++ b/node_modules/ace/doc/template/resources/javascripts/prettify.js
      @@ -0,0 +1,28 @@
      +var q=null;window.PR_SHOULD_USE_CONTINUATION=!0;
      +(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a=
      +[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;ci[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m),
      +l=[],p={},d=0,g=e.length;d=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/,
      +q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/,
      +q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g,
      +"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a),
      +a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e}
      +for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],
      +"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"],
      +H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],
      +J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+
      +I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),
      +["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css",
      +/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}),
      +["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes",
      +hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p=0){var k=k.match(g),f,b;if(b=
      +!k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p 1010) sx = 1010 - document.documentElement.offsetWidth;
      +    }
      +    else sx = 0;
      +
      +    $('span.methodClicker, article.article, i.methodClicker').each(function () {
      +        var a = $(this);
      +        var constructorPos = a.attr("id").indexOf("new ");
      +
      +        var objName = a.attr("id");
      +        if (constructorPos >= 0) {
      +            objName = objName.substring(constructorPos + 4);
      +            objName += ".new";
      +        }
      +
      +        a.attr("id", objName);
      +    });
      +    
      +    function showMethodContent() {
      +        var locationHash = location.hash.replace(/^#/, '').replace(/\./g, '\\.');
      +        var equalsPos = location.hash.indexOf("=");
      +        
      +        if (equalsPos >=0) {
      +            locationHash = locationHash.substring(0, location.hash.indexOf("="));
      +        }
      +        
      +        var $clickerEl = $('span#' + locationHash);
      +        if ($clickerEl.length > 0 && $clickerEl.hasClass('methodClicker')) {
      +            var p = $clickerEl.parent();
      +            p[0].force = true;
      +            p.trigger('click');
      +            p[0].force = false;
      +        }
      +    }
      +
      +    if (location.hash.indexOf("section") >= 1) {
      +        showMethodContent();
      +        var data = location.hash;
      +        scrollTo(null, data.substr(1));
      +    }
      +
      +    window.onhashchange = function () {
      +        showMethodContent();
      +    }
      +};
      +
      +function scrollTo(el, data) {
      +    if (!data) {
      +        data = el.getAttribute("data-id");
      +        //location.hash = data;
      +    }
      +    var el = $("span#" + data.replace(/\./g, "\\."))[0];
      +    if (!el) return;
      +
      +    var article = $(el).closest('.article')[0];
      +
      +    var top = article.offsetTop - 100;
      +
      +    if (document.body.scrollTop > top || document.body.scrollTop != top && document.body.scrollTop + (window.innerHeight || document.documentElement.offsetHeight) < top + article.offsetHeight) {
      +        $('body').animate({
      +            scrollTop: top
      +        }, {
      +            duration: 200,
      +            easing: "swing"
      +        });
      +    }
      +}
      \ No newline at end of file
      diff --git a/node_modules/ace/experiments/animate_folding.html b/node_modules/ace/experiments/animate_folding.html
      new file mode 100644
      index 00000000..ea3f08ec
      --- /dev/null
      +++ b/node_modules/ace/experiments/animate_folding.html
      @@ -0,0 +1,249 @@
      +
      +
      +
      +
      +
      +
      +  
      +  
      +  Editor
      +  
      +
      +
      +
      +
      +
      +
      + + + + + + + diff --git a/node_modules/ace/experiments/basic_animation.html b/node_modules/ace/experiments/basic_animation.html new file mode 100644 index 00000000..85df5ab1 --- /dev/null +++ b/node_modules/ace/experiments/basic_animation.html @@ -0,0 +1,191 @@ + + + + + + + + + +
      +
      Lorem ipsum dolor sit amet, consectetuer adipiscing elit, + sed diam nonummy nibh euismod tincidunt ut laoreet dolore + magna aliquam erat volutpat. Ut wisi enim ad minim veniam, + quis nostrud exerci tation ullamcorper suscipit lobortis nisl + ut aliquip ex ea commodo consequat. Duis autem vel eum iriure + dolor in hendrerit in vulputate velit esse molestie consequat, + vel illum dolore eu feugiat nulla facilisis at vero eros et + accumsan et iusto odio dignissim qui blandit praesent luptatum + zzril delenit augue duis dolore te feugait nulla facilisi. + Nam liber tempor cum soluta nobis eleifend option congue + nihil imperdiet doming id quod mazim placerat facer possim + assum. Typi non habent claritatem insitam; est usus legentis + in iis qui facit eorum claritatem. Investigationes + demonstraverunt lectores legere me lius quod ii legunt saepius. + Claritas est etiam processus dynamicus, qui sequitur mutationem + consuetudium lectorum. Mirum est notare quam littera gothica, + quam nunc putamus parum claram, anteposuerit litterarum formas + humanitatis per seacula quarta decima et quinta decima. Eodem + modo typi, qui nunc nobis videntur parum clari, fiant sollemnes + in futurum.
      +
      +
      Lorem ipsum dolor sit amet, consectetuer adipiscing elit, + sed diam nonummy nibh euismod tincidunt ut laoreet dolore + magna aliquam erat volutpat. Ut wisi enim ad minim veniam, + quis nostrud exerci tation ullamcorper suscipit lobortis nisl + ut aliquip ex ea commodo consequat. Duis autem vel eum iriure + dolor in hendrerit in vulputate velit esse molestie consequat, + vel illum dolore eu feugiat nulla facilisis at vero eros et + accumsan et iusto odio dignissim qui blandit praesent luptatum + zzril delenit augue duis dolore te feugait nulla facilisi. + Nam liber tempor cum soluta nobis eleifend option congue + nihil imperdiet doming id quod mazim placerat facer possim + assum. Typi non habent claritatem insitam; est usus legentis + in iis qui facit eorum claritatem. Investigationes + demonstraverunt lectores legere me lius quod ii legunt saepius. + Claritas est etiam processus dynamicus, qui sequitur mutationem + consuetudium lectorum. Mirum est notare quam littera gothica, + quam nunc putamus parum claram, anteposuerit litterarum formas + humanitatis per seacula quarta decima et quinta decima. Eodem + modo typi, qui nunc nobis videntur parum clari, fiant sollemnes + in futurum.
      +
      Lorem ipsum dolor sit amet, consectetuer adipiscing elit, + sed diam nonummy nibh euismod tincidunt ut laoreet dolore + magna aliquam erat volutpat. Ut wisi enim ad minim veniam, + quis nostrud exerci tation ullamcorper suscipit lobortis nisl + ut aliquip ex ea commodo consequat. Duis autem vel eum iriure + dolor in hendrerit in vulputate velit esse molestie consequat, + vel illum dolore eu feugiat nulla facilisis at vero eros et + accumsan et iusto odio dignissim qui blandit praesent luptatum + zzril delenit augue duis dolore te feugait nulla facilisi. + Nam liber tempor cum soluta nobis eleifend option congue + nihil imperdiet doming id quod mazim placerat facer possim + assum. Typi non habent claritatem insitam; est usus legentis + in iis qui facit eorum claritatem. Investigationes + demonstraverunt lectores legere me lius quod ii legunt saepius. + Claritas est etiam processus dynamicus, qui sequitur mutationem + consuetudium lectorum. Mirum est notare quam littera gothica, + quam nunc putamus parum claram, anteposuerit litterarum formas + humanitatis per seacula quarta decima et quinta decima. Eodem + modo typi, qui nunc nobis videntur parum clari, fiant sollemnes + in futurum.
      +
      +
      Lorem ipsum dolor sit amet, consectetuer adipiscing elit, + sed diam nonummy nibh euismod tincidunt ut laoreet dolore + magna aliquam erat volutpat. Ut wisi enim ad minim veniam, + quis nostrud exerci tation ullamcorper suscipit lobortis nisl + ut aliquip ex ea commodo consequat. Duis autem vel eum iriure + dolor in hendrerit in vulputate velit esse molestie consequat, + vel illum dolore eu feugiat nulla facilisis at vero eros et + accumsan et iusto odio dignissim qui blandit praesent luptatum + zzril delenit augue duis dolore te feugait nulla facilisi. + Nam liber tempor cum soluta nobis eleifend option congue + nihil imperdiet doming id quod mazim placerat facer possim + assum. Typi non habent claritatem insitam; est usus legentis + in iis qui facit eorum claritatem. Investigationes + demonstraverunt lectores legere me lius quod ii legunt saepius. + Claritas est etiam processus dynamicus, qui sequitur mutationem + consuetudium lectorum. Mirum est notare quam littera gothica, + quam nunc putamus parum claram, anteposuerit litterarum formas + humanitatis per seacula quarta decima et quinta decima. Eodem + modo typi, qui nunc nobis videntur parum clari, fiant sollemnes + in futurum.
      +
      + + + + + diff --git a/node_modules/ace/experiments/capture.html b/node_modules/ace/experiments/capture.html new file mode 100644 index 00000000..9df5e3cd --- /dev/null +++ b/node_modules/ace/experiments/capture.html @@ -0,0 +1,45 @@ + + + + + + + + + + + + +
      + +
      + + + + + diff --git a/node_modules/ace/experiments/cut_copy.html b/node_modules/ace/experiments/cut_copy.html new file mode 100644 index 00000000..3299f3ad --- /dev/null +++ b/node_modules/ace/experiments/cut_copy.html @@ -0,0 +1,105 @@ + + + + + + Text Events + + + + + + + +
      + +
      +
      + + +
      + +
      + + + + + diff --git a/node_modules/ace/experiments/triple_click.html b/node_modules/ace/experiments/triple_click.html new file mode 100644 index 00000000..da953a94 --- /dev/null +++ b/node_modules/ace/experiments/triple_click.html @@ -0,0 +1,34 @@ + + + + + + triple_click + + + + + +
      + Juhu Kinners +
      + + + + + + + diff --git a/node_modules/ace/experiments/worker.html b/node_modules/ace/experiments/worker.html new file mode 100644 index 00000000..f3c75bde --- /dev/null +++ b/node_modules/ace/experiments/worker.html @@ -0,0 +1,33 @@ + + + + + + worker + + + + + + + + + + diff --git a/node_modules/ace/experiments/worker.js b/node_modules/ace/experiments/worker.js new file mode 100644 index 00000000..1335f55e --- /dev/null +++ b/node_modules/ace/experiments/worker.js @@ -0,0 +1,3 @@ +onmessage = function(e) { + onmessage = new Function("e", e.data); +}; \ No newline at end of file diff --git a/node_modules/ace/experiments/zenbg.png b/node_modules/ace/experiments/zenbg.png new file mode 100644 index 0000000000000000000000000000000000000000..734ea91202372efe38c634415d1f44cb11d49801 GIT binary patch literal 50753 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 literal 0 HcmV?d00001 diff --git a/node_modules/ace/index.html b/node_modules/ace/index.html new file mode 100644 index 00000000..9e05ed68 --- /dev/null +++ b/node_modules/ace/index.html @@ -0,0 +1,1352 @@ + + + + + Ace - The High Performance Code Editor for the Web + + + + + + + + + + + + + Fork me on GitHub + +
      +
      +
      +
      +

      The high performance code editor for the web.

      + +
      +
      + +
      +
      +

      Built for Code

      +

      Ace is an embeddable code editor written in JavaScript. + It matches the features and performance of native + editors such as Sublime, Vim and TextMate. It can be easily embedded + in any web page and JavaScript application. Ace is maintained as the + primary editor for Cloud9 IDE + and is the successor of the Mozilla Skywriter (Bespin) project. +

      + +
      /**
      + * In fact, you're looking at ACE right now. Go ahead and play with it!
      + *
      + * We are currently showing off the JavaScript mode. ACE has support for 45
      + * language modes and 24 color themes!
      + */
      +
      +function add(x, y) {
      +    var resultString = "Hello, ACE! The result of your math is: ";
      +    var result = x + y;
      +    return resultString + result;
      +}
      +
      +var addResult = add(3, 2);
      +console.log(addResult);
      +
      + +

      Looking for a more full-featured demo? Check out the + kitchen sink. +

      +

      Features

      +
        +
      • Syntax highlighting for over 110 languages (TextMate/Sublime Text.tmlanguage files can be imported)
      • +
      • Over 20 themes (TextMate/Sublime Text .tmtheme files can be imported)
      • +
      • Automatic indent and outdent
      • +
      • An optional command line
      • +
      • Handles huge documents (four million lines seems to be the limit!)
      • +
      • Fully customizable key bindings including vim and Emacs modes
      • +
      • Search and replace with regular expressions
      • +
      • Highlight matching parentheses
      • +
      • Toggle between soft tabs and real tabs
      • +
      • Displays hidden characters
      • +
      • Drag and drop text using the mouse
      • +
      • Line wrapping
      • +
      • Code folding
      • +
      • Multiple cursors and selections
      • +
      • Live syntax checker (currently JavaScript/CoffeeScript/CSS/XQuery)
      • +
      • Cut, copy, and paste functionality
      • +
      +

      Get the Open-Source Code

      +

      Ace is a community project. We actively encourage and support + contributions! The Ace source code is hosted on GitHub + and released under the BSD license ‐ + very simple and friendly to all kinds of projects, whether open-source + or not. Take charge of your editor and add your favorite language + highlighting and keybindings! +

      +
      git clone git://github.com/ajaxorg/ace.git
      +

      History

      +

      Skywriter/Bespin and Ace started + as two independent projects both aiming to build a no compromise + code editor component for the web. Bespin started as part of + Mozilla Labs and was based on the <canvas> tag, while Ace is + the editor component of Cloud9 IDE + and uses the DOM for rendering. After the release of Ace at + JSConf.eu 2010 + in Berlin the Skywriter team decided to merge Ace with a simplified + version of Skywriter's plugin system and some of Skywriter's + extensibility points. All these changes have been merged back to Ace + now, which supersedes Skywriter. Both Cloud9 IDE + and Mozilla are actively developing and + maintaining Ace. +

      +

      Related Projects

      + +
      +
      +

      Embedding Ace in Your Site

      +

      Ace can be easily embedded into a web page. Get prebuilt version of ace from + ace-builds repository and use the code below:

      +
      <!DOCTYPE html>
      +<html lang="en">
      +<head>
      +<title>ACE in Action</title>
      +<style type="text/css" media="screen">
      +    #editor { 
      +        position: absolute;
      +        top: 0;
      +        right: 0;
      +        bottom: 0;
      +        left: 0;
      +    }
      +</style>
      +</head>
      +<body>
      +
      +<div id="editor">function foo(items) {
      +    var x = "All this is syntax highlighted";
      +    return x;
      +}</div>
      +    
      +<script src="/ace-builds/src-noconflict/ace.js" type="text/javascript" charset="utf-8"></script>
      +<script>
      +    var editor = ace.edit("editor");
      +    editor.setTheme("ace/theme/monokai");
      +    editor.getSession().setMode("ace/mode/javascript");
      +</script>
      +</body>
      +</html>
      +

      Now check out the How-To Guide for instructions on + common operations, such as setting a different language mode or + getting the contents from the editor. +

      +

      Loading Ace from a Local URL

      +

      If you want to clone and host Ace locally you can + use one of the pre-packaged versions. Just copy + one of src* subdirectories somewhere into your project, or use RequireJS to load the + contents of lib/ace folder as ace: +

      +

      The packaged version can also be loaded from CDN's such as jsDelivr or cdnjs. +

      +
      +
      +

      Working with Ace

      +

      In all of these examples Ace has been invoked + as shown in the embedding guide. +

      +

      Setting Themes

      +

      Themes are loaded on demand; all you have to do is pass the string name:

      +
      editor.setTheme("ace/theme/twilight");
      +

      > See all themes

      +

      Setting the Programming Language Mode

      +

      By default, the editor supports plain text mode. All other language modes are available as separate modules, loaded on demand like this:

      +
      editor.getSession().setMode("ace/mode/javascript");
      + +

      Common Operations

      +

      Set and get content:

      +
      editor.setValue("the new text here"); // or session.setValue
      +editor.getValue(); // or session.getValue
      +

      Get selected text:

      +
      editor.session.getTextRange(editor.getSelectionRange());
      +

      Insert at cursor:

      +
      editor.insert("Something cool");
      +

      Get the current cursor line and column:

      +
      editor.selection.getCursor();
      +

      Go to a line:

      +
      editor.gotoLine(lineNumber);
      +

      Get total number of lines:

      +
      editor.session.getLength();
      +

      Set the default tab size:

      +
      editor.getSession().setTabSize(4);
      +

      Use soft tabs:

      +
      editor.getSession().setUseSoftTabs(true);
      +

      Set the font size:

      +
      document.getElementById('editor').style.fontSize='12px';
      +

      Toggle word wrapping:

      +
      editor.getSession().setUseWrapMode(true);
      +

      Set line highlighting:

      +
      editor.setHighlightActiveLine(false);
      +

      Set the print margin visibility:

      +
      editor.setShowPrintMargin(false);
      +

      Set the editor to read-only:

      +
      editor.setReadOnly(true);  // false to make it editable
      +

      Triggering Resizes

      +

      Ace only resizes itself on window events. If you resize the editor div in another manner, and need Ace to resize, use the following:

      +
      editor.resize()
      +

      Searching

      +
      editor.find('needle',{
      +    backwards: false,
      +    wrap: false,
      +    caseSensitive: false,
      +    wholeWord: false,
      +    regExp: false
      +});
      +editor.findNext();
      +editor.findPrevious();
      +

      The following options are available to you for your search parameters:

      +
        +
      • + needle: The string or regular expression you're looking for +
      • +
      • + backwards: Whether to search backwards from where cursor currently is. Defaults to false. +
      • +
      • + wrap: Whether to wrap the search back to the beginning when it hits the end. Defaults to false. +
      • +
      • + caseSensitive: Whether the search ought to be case-sensitive. Defaults to false. +
      • +
      • + wholeWord: Whether the search matches only on whole words. Defaults to false. +
      • +
      • + range: The Range to search within. Set this to null for the whole document +
      • +
      • + regExp: Whether the search is a regular expression or not. Defaults to false. +
      • +
      • + start: The starting Range or cursor position to begin the search +
      • +
      • + skipCurrent: Whether or not to include the current line in the search. Default to false. +
      • +
      +

      Here's how you can perform a replace:

      +
      editor.find('foo');
      +editor.replace('bar');
      +

      And here's a replace all:

      +
      editor.replaceAll('bar');
      +

      (editor.replaceAll uses the needle set earlier by editor.find('needle', ...)

      +

      Listening to Events

      +

      To listen for an onchange:

      +
      editor.getSession().on('change', function(e) {
      +    // e.type, etc
      +});
      +

      To listen for an selection change:

      +
      editor.getSession().selection.on('changeSelection', function(e) {
      +});
      +

      To listen for a cursor change:

      +
      editor.getSession().selection.on('changeCursor', function(e) {
      +});
      +

      Adding New Commands and Keybindings

      +

      To assign key bindings to a custom function:

      +
      editor.commands.addCommand({
      +    name: 'myCommand',
      +    bindKey: {win: 'Ctrl-M',  mac: 'Command-M'},
      +    exec: function(editor) {
      +        //...
      +    },
      +    readOnly: true // false if this command should not apply in readOnly mode
      +});
      +
      +
      +

      Creating a Syntax Highlighter for Ace

      +

      Creating a new syntax highlighter for Ace is extremly simple. You'll need to define two pieces of code: a new mode, and a new set of highlighting rules.

      +

      Where to Start

      +

      We recommend using the the Ace Mode Creator when defining your highlighter. This allows you to inspect your code's tokens, as well as providing a live preview of the syntax highlighter in action.

      +

      Defining a Mode

      +

      Every language needs a mode. A mode contains the paths to a language's syntax highlighting rules, indentation rules, and code folding rules. Without defining a mode, Ace won't know anything about the finer aspects of your language.

      +

      Here is the starter template we'll use to create a new mode:

      +
      define(function(require, exports, module) {
      +"use strict";
      +
      +var oop = require("../lib/oop");
      +// defines the parent mode
      +var TextMode = require("./text").Mode;
      +var Tokenizer = require("../tokenizer").Tokenizer;
      +var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent;
      +
      +// defines the language specific highlighters and folding rules
      +var MyNewHighlightRules = require("./mynew_highlight_rules").MyNewHighlightRules;
      +var MyNewFoldMode = require("./folding/mynew").MyNewFoldMode;
      +
      +var Mode = function() {
      +    // set everything up
      +    this.HighlightRules = MyNewHighlightRules;
      +    this.$outdent = new MatchingBraceOutdent();
      +    this.foldingRules = new MyNewFoldMode();
      +};
      +oop.inherits(Mode, TextMode);
      +
      +(function() {
      +    // configure comment start/end characters
      +    this.lineCommentStart = "//";
      +    this.blockComment = {start: "/*", end: "*/"};
      +    
      +    // special logic for indent/outdent. 
      +    // By default ace keeps indentation of previous line
      +    this.getNextLineIndent = function(state, line, tab) {
      +        var indent = this.$getIndent(line);
      +        return indent;
      +    };
      +
      +    this.checkOutdent = function(state, line, input) {
      +        return this.$outdent.checkOutdent(line, input);
      +    };
      +
      +    this.autoOutdent = function(state, doc, row) {
      +        this.$outdent.autoOutdent(doc, row);
      +    };
      +    
      +    // create worker for live syntax checking
      +    this.createWorker = function(session) {
      +        var worker = new WorkerClient(["ace"], "ace/mode/mynew_worker", "NewWorker");
      +        worker.attachToDocument(session.getDocument());
      +        worker.on("errors", function(e) {
      +            session.setAnnotations(e.data);
      +        });
      +        return worker;
      +    };
      +    
      +}).call(Mode.prototype);
      +
      +exports.Mode = Mode;
      +});
      +

      What's going on here? First, you're defining the path to TextMode (more on this later). Then you're pointing the mode to your definitions for the highlighting rules, as well as your rules for code folding. Finally, you're setting everything up to find those rules, and exporting the Mode so that it can be consumed. That's it!

      +

      Regarding TextMode, you'll notice that it's only being used once: oop.inherits(Mode, TextMode);. If your new language depends on the rules of another language, you can choose to inherit the same rules, while expanding on it with your language's own requirements. For example, PHP inherits from HTML, since it can be embedded directly inside .html pages. You can either inherit from TextMode, or any other existing mode, if it already relates to your language.

      +

      All Ace modes can be found in the lib/ace/mode folder.

      +

      Defining Syntax Highlighting Rules

      +

      The Ace highlighter can be considered to be a state machine. Regular expressions define the tokens for the current state, as well as the transitions into another state. Let's define mynew_highlight_rules.js, which our mode above uses.

      +

      All syntax highlighters start off looking something like this:

      +
      define(function(require, exports, module) {
      +"use strict";
      +
      +var oop = require("../lib/oop");
      +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules;
      +
      +var MyNewHighlightRules = function() {
      +
      +    // regexp must not have capturing parentheses. Use (?:) instead.
      +    // regexps are ordered -> the first match is used
      +   this.$rules = {
      +        "start" : [
      +            {
      +                token: <token>, // String, Array, or Function: the CSS token to apply
      +                regex: <regex>, // String or RegExp: the regexp to match
      +                next:  <next>   // [Optional] String: next state to enter
      +            }
      +        ]
      +    };
      +};
      +
      +oop.inherits(MyNewHighlightRules, TextHighlightRules);
      +
      +exports.MyNewHighlightRules = MyNewHighlightRules;
      +
      +});
      +

      The token state machine operates on whatever is defined in this.$rules. The highlighter always begins at the start state, and progresses down the list, looking for a matching regex. When one is found, the resulting text is wrapped within a <span class="ace_<token>"> tag, where <token> is defined as the token property. Note that all tokens are preceded by the ace_ prefix when they're rendered on the page.

      +

      Once again, we're inheriting from TextHighlightRules here. We could choose to make this any other language set we want, if our new language requires previously defined syntaxes. For more information on extending languages, see "extending Highlighters" below.

      +

      Defining Tokens

      +

      The Ace highlighting system is heavily inspired by the TextMate language grammar. Most tokens will follow the conventions of TextMate when naming grammars. A thorough (albeit incomplete) list of tokens can be found on the Ace Wiki.

      +

      For the complete list of tokens, see tool/tmtheme.js. It is possible to add new token names, but the scope of that knowledge is outside of this document.

      +

      Multiple tokens can be applied to the same text by adding dots in the token, e.g. token: support.function wraps the text in a <span class="ace_support ace_function"> tag.

      +

      Defining Regular Expressions

      +

      Regular expressions can either be a RegExp or String definition

      +

      If you're using a regular expression, remember to start and end the line with the / character, like this:

      +
      {
      +    token : "constant.language.escape",
      +    regex : /\$[\w\d]+/
      +}
      +

      A caveat of using stringed regular expressions is that any \ character must be escaped. That means that even an innocuous regular expression like this:

      +
      regex: "function\s*\(\w+\)"
      +

      Must actually be written like this:

      +
      regex: "function\\s*\(\\w+\)"
      +

      Groupings

      +

      You can also include flat regexps--(var)--or have matching groups--((a+)(b+)). There is a strict requirement whereby matching groups must cover the entire matched string; thus, (hel)lo is invalid. If you want to create a non-matching group, simply start the group with the ?: predicate; thus, (hel)(?:lo) is okay. You can, of course, create longer non-matching groups. For example:

      +
      {
      +    token : "constant.language.boolean",
      +    regex : /(?:true|false)\b/
      +},
      +

      For flat regular expression matches, token can be a String, or a Function that takes a single argument (the match) and returns a string token. For example, using a function might look like this:

      +
      var colors = lang.arrayToMap(
      +    ("aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|orange|" +
      +    "purple|red|silver|teal|white|yellow").split("|")
      +);
      +
      +var fonts = lang.arrayToMap(
      +    ("arial|century|comic|courier|garamond|georgia|helvetica|impact|lucida|" +
      +    "symbol|system|tahoma|times|trebuchet|utopia|verdana|webdings|sans-serif|" +
      +    "serif|monospace").split("|")
      +);
      +
      +...
      +
      +{
      +    token: function(value) {
      +        if (colors.hasOwnProperty(value.toLowerCase())) {
      +            return "support.constant.color";
      +        }
      +        else if (fonts.hasOwnProperty(value.toLowerCase())) {
      +            return "support.constant.fonts";
      +        }
      +        else {
      +            return "text";
      +        }
      +    },
      +    regex: "\\-?[a-zA-Z_][a-zA-Z0-9_\\-]*"
      +}
      +

      If token is a function,it should take the same number of arguments as there are groups, and return an array of tokens.

      +

      For grouped regular expressions, token can be a String, in which case all matched groups are given that same token, like this:

      +
      {
      +    token: "identifier",
      +    regex: "(\\w+\\s*:)(\\w*)"
      +}
      +

      More commonly, though, token is an Array (of the same length as the number of groups), whereby matches are given the token of the same alignment as in the match. For a complicated regular expression, like defining a function, that might look something like this:

      +
      {
      +    token : ["storage.type", "text", "entity.name.function"],
      +    regex : "(function)(\\s+)([a-zA-Z_][a-zA-Z0-9_]*\\b)"
      +}
      +

      Defining States

      +

      The syntax highlighting state machine stays in the start state, until you define a next state for it to advance to. At that point, the tokenizer stays in that new state, until it advances to another state. Afterwards, you should return to the original start state.

      +

      Here's an example:

      +
      this.$rules = {
      +    "start" : [ {
      +        token : "text",
      +        merge : true,
      +        regex : "<\\!\\[CDATA\\[",
      +        next : "cdata"
      +    },
      +
      +    "cdata" : [ {
      +        token : "text",
      +        regex : "\\]\\]>",
      +        next : "start"
      +    }, {
      +        token : "text",
      +        merge : true,
      +        regex : "\\s+"
      +    }, {
      +        token : "text",
      +        merge : true,
      +        regex : ".+"
      +    } ]
      +};
      +

      In this extremly short sample, we're defining some highlighting rules for when Ace detectes a <![CDATA tag. When one is encountered, the tokenizer moves from start into the cdata state. It remains there, applying the text token to any string it encounters. Finally, when it hits a closing ]> symbol, it returns to the start state and continues to tokenize anything else.

      +

      Using the TMLanguage Tool

      +

      There is a tool that + will take an existing tmlanguage file and do its best to convert it into Javascript for Ace to consume. Here's what you need to get started: +

      +
        +
      1. In the Ace repository, navigate to the tools folder.
      2. +
      3. Run npm install to install required dependencies.
      4. +
      5. Run node tmlanguage.js <path_to_tmlanguage_file>; for example, node <path_to_tmlanguage_file> /Users/Elrond/elven.tmLanguage
      6. +
      +

      Two files are created and placed in lib/ace/mode: one for the language mode, and one for the set of highlight rules. You will still need to add the code into ace/ext/modelist.js, and add a sample file for testing.

      +

      A Note on Accuracy

      +

      Your .tmlanguage file will then be converted to the best of the converter’s ability. It is an understatement to say that the tool is imperfect. Probably, language mode creation will never be able to be fully autogenerated. There's a list of non-determinable items; for example:

      +
        +
      • The use of regular expression lookbehinds
        This is a concept that JavaScript simply does not have and needs to be faked
      • +
      • Deciding which state to transition to
        While the tool does create new states correctly, it labels them with generic terms like state_2, state_10, e.t.c.
      • +
      • Extending modes
        Many modes say something like include source.c, to mean, “add all the rules in C highlighting.†That syntax does not make sense to Ace or this tool (though of course you can extending existing highlighters).
      • +
      • Rule preference order
      • +
      • Gathering keywords
        Most likely, you’ll need to take keywords from your language file and run them through createKeywordMapper()
      • +
      +

      However, the tool is an excellent way to get a quick start, if you already possess a tmlanguage file for you language.

      +

      Extending Highlighters

      +

      Suppose you're working on a LuaPage, PHP embedded in HTML, or a Django template. You'll need to create a syntax highlighter that takes all the rules from the original language (Lua, PHP, or Python) and extends it with some additional identifiers (<?lua, <?php, {%, for example). Ace allows you to easily extend a highlighter using a few helper functions.

      +

      Getting Existing Rules

      +

      To get the existing syntax highlighting rules for a particular language, use the getRules() function. For example:

      +
      var HtmlHighlightRules = require("./html_highlight_rules").HtmlHighlightRules;
      +
      +this.$rules = new HtmlHighlightRules().getRules();
      +
      +/*
      +    this.$rules == Same this.$rules as HTML highlighting
      +*/
      +

      Extending a Highlighter

      +

      The addRules method does one thing, and it does one thing well: it adds new rules to an existing rule set, and prefixes any state with a given tag. For example, let's say you've got two sets of rules, defined like this:

      +
      this.$rules = {
      +    "start": [ /* ... */ ]
      +};
      +
      +var newRules = {
      +    "start": [ /* ... */ ]
      +}
      +

      If you want to incorporate newRules into this.$rules, you'd do something like this:

      +
      this.addRules(newRules, "new-");
      +
      +/*
      +    this.$rules = {
      +        "start": [ ... ],
      +        "new-start": [ ... ]
      +    };
      +*/
      +

      Extending Two Highlighters

      +

      The last function available to you combines both of these concepts, and it's called embedRules. It takes three parameters:

      +
        +
      1. An existing rule set to embed with
      2. +
      3. A prefix to apply for each state in the existing rule set
      4. +
      5. A set of new states to add
      6. +
      +

      Like addRules, embedRules adds on to the existing this.$rules object.

      +

      To explain this visually, let's take a look at the syntax highlighter for Lua pages, which combines all of these concepts:

      +
      var HtmlHighlightRules = require("./html_highlight_rules").HtmlHighlightRules;
      +var LuaHighlightRules = require("./lua_highlight_rules").LuaHighlightRules;
      +
      +var LuaPageHighlightRules = function() {
      +    this.$rules = new HtmlHighlightRules().getRules();
      +
      +    for (var i in this.$rules) {
      +        this.$rules[i].unshift({
      +            token: "keyword",
      +            regex: "<\\%\\=?",
      +            next: "lua-start"
      +        }, {
      +            token: "keyword",
      +            regex: "<\\?lua\\=?",
      +            next: "lua-start"
      +        });
      +    }
      +    this.embedRules(LuaHighlightRules, "lua-", [
      +        {
      +            token: "keyword",
      +            regex: "\\%>",
      +            next: "start"
      +        },
      +        {
      +            token: "keyword",
      +            regex: "\\?>",
      +            next: "start"
      +        }
      +    ]);
      +};
      +

      Here, this.$rules starts off as a set of HTML highlighting rules. To this set, we add two new checks for <%= and <?lua=. We also delegate that if one of these rules are matched, we should move onto the lua-start state. Next, embedRules takes the already existing set of LuaHighlightRules and applies the lua- prefix to each state there. Finally, it adds two new checks for %> and ?>, allowing the state machine to return to start.

      +

      Code Folding

      +

      Adding new folding rules to your mode can be a little tricky. First, insert the following lines of code into your mode definition:

      +
      var MyFoldMode = require("./folding/newrules").FoldMode;
      +
      +...
      +var MyMode = function() {
      +
      +    ...
      +
      +    this.foldingRules = new MyFoldMode();
      +};
      +

      You'll be defining your code folding rules into the lib/ace/mode/folding folder. Here's a template that you can use to get started:

      +
      define(function(require, exports, module) {
      +"use strict";
      +
      +var oop = require("../../lib/oop");
      +var Range = require("../../range").Range;
      +var BaseFoldMode = require("./fold_mode").FoldMode;
      +
      +var FoldMode = exports.FoldMode = function() {};
      +oop.inherits(FoldMode, BaseFoldMode);
      +
      +(function() {
      +
      +    // regular expressions that identify starting and stopping points
      +    this.foldingStartMarker; 
      +    this.foldingStopMarker;
      +
      +    this.getFoldWidgetRange = function(session, foldStyle, row) {
      +        var line = session.getLine(row);
      +
      +        // test each line, and return a range of segments to collapse
      +    };
      +
      +}).call(FoldMode.prototype);
      +
      +});
      +

      Just like with TextMode for syntax highlighting, BaseFoldMode contains the starting point for code folding logic. foldingStartMarker defines your opening folding point, while foldingStopMarker defines the stopping point. For example, for a C-style folding system, these values might look like this:

      +
      this.foldingStartMarker = /(\{|\[)[^\}\]]*$|^\s*(\/\*)/;
      +this.foldingStopMarker = /^[^\[\{]*(\}|\])|^[\s\*]*(\*\/)/;
      +

      These regular expressions identify various symbols--{, [, //--to pay attention to. getFoldWidgetRange matches on these regular expressions, and when found, returns the range of relevant folding points. For more information on the Range object, see the Ace API documentation.

      +

      Again, for a C-style folding mechanism, a range to return for the starting fold might look like this:

      +
      var line = session.getLine(row);
      +var match = line.match(this.foldingStartMarker);
      +if (match) {
      +    var i = match.index;
      +
      +    if (match[1])
      +        return this.openingBracketBlock(session, match[1], row, i);
      +
      +    var range = session.getCommentFoldRange(row, i + match[0].length);
      +    range.end.column -= 2;
      +    return range;
      +}
      +

      Let's say we stumble across the code block hello_world() {. Our range object here becomes:

      +
      {
      +  startRow: 0,
      +  endRow: 0,
      +  startColumn: 0,
      +  endColumn: 13
      +}
      +

      Testing Your Highlighter

      +

      The best way to test your tokenizer is to see it live, right? To do that, you'll want to modify the live Ace demo to preview your changes. You can find this file in the root Ace directory with the name kitchen-sink.html.

      +
        +
      1. + add an entry to supportedModes in ace/ext/modelist.js +
      2. +
      3. +

        add a sample file to demo/kitchen-sink/docs/ with same name as the mode file +

      4. +
      +

      Once you set this up, you should be able to witness a live demonstration of your new highlighter.

      +

      Adding Automated Tests

      +

      Adding automated tests for a highlighter is trivial so you are not required to do it, but it can help during development.

      +

      In lib/ace/mode/_test create a file named

      text_<modeName>.txt
      with some example code. (You can skip this if the document you have added in demo/docs both looks good and covers various edge cases in your language syntax). +

      +

      Run node highlight_rules_test.js -gen to preserve current output of your tokenizer in tokens_<modeName>.json +

      +

      After this running highlight_rules_test.js optionalLanguageName will compare output of your tokenizer with the correct output you've created. +

      +

      Any files ending with the _test.js suffix are automatically run by Ace's Travis CI server.

      +
      +
      +
      +
      + +
      +
      +
      +

      Ace API Reference

      +

      Welcome to the Ace API Reference!

      +

      On the left, you'll find a list of all of our currently documented classes. + These is not a complete set of classes, but rather, the "core" set. For more + information on how to work with Ace, check out the embedding guide. +

      +

      Below is an ERD diagram describing some fundamentals about how the internals of Ace works:

      + +
      +
      +
      +
      +
      +

      Projects Using Ace

      +

      Ace is used all over the web in all kinds of production applications. Here is + just a small sampling:

      + +
      +
      +

      Support and User Resources

      +

      Aside from our GitHub page, here's a list of places you can find help for Ace:

      + +
      +
      +
      +
      +
      + + + + + + + + + diff --git a/node_modules/ace/kitchen-sink.html b/node_modules/ace/kitchen-sink.html new file mode 100644 index 00000000..32e87089 --- /dev/null +++ b/node_modules/ace/kitchen-sink.html @@ -0,0 +1,294 @@ + + + + + + Ace Kitchen Sink + + + + + + + + +
      + + + +
      +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + +
      + + + +
      + + + +
      + + + +
      + + + +
      + + + +
      + + + +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + +
      + + + +
      + + + +
      + + + + + +
      + + + +
      + + + +
      + + + +
      + + + +
      + + + +
      + + + +
      + + + +
      + + + +
      + + + +
      + + + +
      + + + +
      + + + +
      + +
      +
      + + + + + +
      +
      +
      +
      + + + + + + + + + + + diff --git a/node_modules/ace/lib/ace/ace.js b/node_modules/ace/lib/ace/ace.js new file mode 100644 index 00000000..6c8a6126 --- /dev/null +++ b/node_modules/ace/lib/ace/ace.js @@ -0,0 +1,129 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +/** + * The main class required to set up an Ace instance in the browser. + * + * @class Ace + **/ + +define(function(require, exports, module) { +"use strict"; + +require("./lib/fixoldbrowsers"); + +var dom = require("./lib/dom"); +var event = require("./lib/event"); + +var Editor = require("./editor").Editor; +var EditSession = require("./edit_session").EditSession; +var UndoManager = require("./undomanager").UndoManager; +var Renderer = require("./virtual_renderer").VirtualRenderer; + +// The following require()s are for inclusion in the built ace file +require("./worker/worker_client"); +require("./keyboard/hash_handler"); +require("./placeholder"); +require("./multi_select"); +require("./mode/folding/fold_mode"); +require("./theme/textmate"); +require("./ext/error_marker"); + +exports.config = require("./config"); + +/** + * Provides access to require in packed noconflict mode + * @param {String} moduleName + * @returns {Object} + * + **/ +exports.require = require; + +/** + * Embeds the Ace editor into the DOM, at the element provided by `el`. + * @param {String | DOMElement} el Either the id of an element, or the element itself + * + **/ +exports.edit = function(el) { + if (typeof(el) == "string") { + var _id = el; + el = document.getElementById(_id); + if (!el) + throw new Error("ace.edit can't find div #" + _id); + } + + if (el && el.env && el.env.editor instanceof Editor) + return el.env.editor; + + var value = ""; + if (el && /input|textarea/i.test(el.tagName)) { + var oldNode = el; + value = oldNode.value; + el = dom.createElement("pre"); + oldNode.parentNode.replaceChild(el, oldNode); + } else { + value = dom.getInnerText(el); + el.innerHTML = ''; + } + + var doc = exports.createEditSession(value); + + var editor = new Editor(new Renderer(el)); + editor.setSession(doc); + + var env = { + document: doc, + editor: editor, + onResize: editor.resize.bind(editor, null) + }; + if (oldNode) env.textarea = oldNode; + event.addListener(window, "resize", env.onResize); + editor.on("destroy", function() { + event.removeListener(window, "resize", env.onResize); + env.editor.container.env = null; // prevent memory leak on old ie + }); + editor.container.env = editor.env = env; + return editor; +}; + +/** + * Creates a new [[EditSession]], and returns the associated [[Document]]. + * @param {Document | String} text {:textParam} + * @param {TextMode} mode {:modeParam} + * + **/ +exports.createEditSession = function(text, mode) { + var doc = new EditSession(text, mode); + doc.setUndoManager(new UndoManager()); + return doc; +} +exports.EditSession = EditSession; +exports.UndoManager = UndoManager; +}); diff --git a/node_modules/ace/lib/ace/anchor.js b/node_modules/ace/lib/ace/anchor.js new file mode 100644 index 00000000..39b78e0f --- /dev/null +++ b/node_modules/ace/lib/ace/anchor.js @@ -0,0 +1,227 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("./lib/oop"); +var EventEmitter = require("./lib/event_emitter").EventEmitter; + +/** + * + * Defines a floating pointer in the document. Whenever text is inserted or deleted before the cursor, the position of the anchor is updated. + * + * @class Anchor + **/ + +/** + * Creates a new `Anchor` and associates it with a document. + * + * @param {Document} doc The document to associate with the anchor + * @param {Number} row The starting row position + * @param {Number} column The starting column position + * + * @constructor + **/ + +var Anchor = exports.Anchor = function(doc, row, column) { + this.$onChange = this.onChange.bind(this); + this.attach(doc); + + if (typeof column == "undefined") + this.setPosition(row.row, row.column); + else + this.setPosition(row, column); +}; + +(function() { + + oop.implement(this, EventEmitter); + + /** + * Returns an object identifying the `row` and `column` position of the current anchor. + * @returns {Object} + **/ + this.getPosition = function() { + return this.$clipPositionToDocument(this.row, this.column); + }; + + /** + * + * Returns the current document. + * @returns {Document} + **/ + this.getDocument = function() { + return this.document; + }; + + /** + * experimental: allows anchor to stick to the next on the left + */ + this.$insertRight = false; + /** + * Fires whenever the anchor position changes. + * + * Both of these objects have a `row` and `column` property corresponding to the position. + * + * Events that can trigger this function include [[Anchor.setPosition `setPosition()`]]. + * + * @event change + * @param {Object} e An object containing information about the anchor position. It has two properties: + * - `old`: An object describing the old Anchor position + * - `value`: An object describing the new Anchor position + * + **/ + this.onChange = function(delta) { + if (delta.start.row == delta.end.row && delta.start.row != this.row) + return; + + if (delta.start.row > this.row) + return; + + var point = $getTransformedPoint(delta, {row: this.row, column: this.column}, this.$insertRight); + this.setPosition(point.row, point.column, true); + }; + + function $pointsInOrder(point1, point2, equalPointsInOrder) { + var bColIsAfter = equalPointsInOrder ? point1.column <= point2.column : point1.column < point2.column; + return (point1.row < point2.row) || (point1.row == point2.row && bColIsAfter); + } + + function $getTransformedPoint(delta, point, moveIfEqual) { + // Get delta info. + var deltaIsInsert = delta.action == "insert"; + var deltaRowShift = (deltaIsInsert ? 1 : -1) * (delta.end.row - delta.start.row); + var deltaColShift = (deltaIsInsert ? 1 : -1) * (delta.end.column - delta.start.column); + var deltaStart = delta.start; + var deltaEnd = deltaIsInsert ? deltaStart : delta.end; // Collapse insert range. + + // DELTA AFTER POINT: No change needed. + if ($pointsInOrder(point, deltaStart, moveIfEqual)) { + return { + row: point.row, + column: point.column + }; + } + + // DELTA BEFORE POINT: Move point by delta shift. + if ($pointsInOrder(deltaEnd, point, !moveIfEqual)) { + return { + row: point.row + deltaRowShift, + column: point.column + (point.row == deltaEnd.row ? deltaColShift : 0) + }; + } + + // DELTA ENVELOPS POINT (delete only): Move point to delta start. + // TODO warn if delta.action != "remove" ? + + return { + row: deltaStart.row, + column: deltaStart.column + }; + } + + /** + * Sets the anchor position to the specified row and column. If `noClip` is `true`, the position is not clipped. + * @param {Number} row The row index to move the anchor to + * @param {Number} column The column index to move the anchor to + * @param {Boolean} noClip Identifies if you want the position to be clipped + * + **/ + this.setPosition = function(row, column, noClip) { + var pos; + if (noClip) { + pos = { + row: row, + column: column + }; + } else { + pos = this.$clipPositionToDocument(row, column); + } + + if (this.row == pos.row && this.column == pos.column) + return; + + var old = { + row: this.row, + column: this.column + }; + + this.row = pos.row; + this.column = pos.column; + this._signal("change", { + old: old, + value: pos + }); + }; + + /** + * When called, the `"change"` event listener is removed. + * + **/ + this.detach = function() { + this.document.removeEventListener("change", this.$onChange); + }; + this.attach = function(doc) { + this.document = doc || this.document; + this.document.on("change", this.$onChange); + }; + + /** + * Clips the anchor position to the specified row and column. + * @param {Number} row The row index to clip the anchor to + * @param {Number} column The column index to clip the anchor to + * + **/ + this.$clipPositionToDocument = function(row, column) { + var pos = {}; + + if (row >= this.document.getLength()) { + pos.row = Math.max(0, this.document.getLength() - 1); + pos.column = this.document.getLine(pos.row).length; + } + else if (row < 0) { + pos.row = 0; + pos.column = 0; + } + else { + pos.row = row; + pos.column = Math.min(this.document.getLine(pos.row).length, Math.max(0, column)); + } + + if (column < 0) + pos.column = 0; + + return pos; + }; + +}).call(Anchor.prototype); + +}); diff --git a/node_modules/ace/lib/ace/anchor_test.js b/node_modules/ace/lib/ace/anchor_test.js new file mode 100644 index 00000000..c0b97273 --- /dev/null +++ b/node_modules/ace/lib/ace/anchor_test.js @@ -0,0 +1,223 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +if (typeof process !== "undefined") { + require("amd-loader"); +} + +define(function(require, exports, module) { +"use strict"; + +var Document = require("./document").Document; +var Anchor = require("./anchor").Anchor; +var Range = require("./range").Range; +var assert = require("./test/assertions"); + +module.exports = { + + "test create anchor" : function() { + var doc = new Document("juhu"); + var anchor = new Anchor(doc, 0, 0); + + assert.position(anchor.getPosition(), 0, 0); + assert.equal(anchor.getDocument(), doc); + }, + + "test insert text in same row before cursor should move anchor column": function() { + var doc = new Document("juhu\nkinners"); + var anchor = new Anchor(doc, 1, 4); + + doc.insert({row: 1, column: 1}, "123"); + assert.position(anchor.getPosition(), 1, 7); + }, + + "test insert text at anchor should not move anchor when insertRight is true": function() { + var doc = new Document("juhu\nkinners"); + var anchor = new Anchor(doc, 1, 4); + anchor.$insertRight = true; + + doc.insert({row: 1, column: 4}, "123"); + assert.position(anchor.getPosition(), 1, 4); + }, + + "test insert lines before cursor should move anchor row": function() { + var doc = new Document("juhu\nkinners"); + var anchor = new Anchor(doc, 1, 4); + + doc.insertFullLines(1, ["123", "456"]); + assert.position(anchor.getPosition(), 3, 4); + }, + + "test insert lines at anchor position should move anchor down": function() { + var doc = new Document("juhu\nkinners"); + var anchor = new Anchor(doc, 1, 0); + + doc.insertLines(1, ["line"]); + assert.position(anchor.getPosition(), 2, 0); + }, + + "test insert lines at anchor position should not move anchor down when insertRight is true and column is 0": function() { + var doc = new Document("juhu\nkinners"); + var anchor = new Anchor(doc, 1, 0); + anchor.$insertRight = true; + + doc.insertLines(1, ["line"]); + assert.position(anchor.getPosition(), 1, 0); + }, + + "test insert lines at anchor row should move anchor down when column > 0": function() { + var doc = new Document("juhu\nkinners"); + var anchor = new Anchor(doc, 1, 2); + anchor.$insertRight = true; + + doc.insertLines(1, ["line"]); + assert.position(anchor.getPosition(), 2, 2); + }, + + "test insert new line before cursor should move anchor column": function() { + var doc = new Document("juhu\nkinners"); + var anchor = new Anchor(doc, 1, 4); + + doc.insertMergedLines({row: 0, column: 0}, ['', '']); + assert.position(anchor.getPosition(), 2, 4); + }, + + "test insert new line in anchor line before anchor should move anchor column and row": function() { + var doc = new Document("juhu\nkinners"); + var anchor = new Anchor(doc, 1, 4); + + doc.insertMergedLines({row: 1, column: 2}, ['', '']); + assert.position(anchor.getPosition(), 2, 2); + }, + + "test delete text in anchor line before anchor should move anchor column": function() { + var doc = new Document("juhu\nkinners"); + var anchor = new Anchor(doc, 1, 4); + + doc.remove(new Range(1, 1, 1, 3)); + assert.position(anchor.getPosition(), 1, 2); + }, + + "test remove range which contains the anchor should move the anchor to the start of the range": function() { + var doc = new Document("juhu\nkinners"); + var anchor = new Anchor(doc, 0, 3); + + doc.remove(new Range(0, 1, 1, 3)); + assert.position(anchor.getPosition(), 0, 1); + }, + + "test delete character before the anchor should have no effect": function() { + var doc = new Document("juhu\nkinners"); + var anchor = new Anchor(doc, 1, 4); + + doc.remove(new Range(1, 4, 1, 5)); + assert.position(anchor.getPosition(), 1, 4); + }, + + "test delete lines in anchor line before anchor should move anchor row": function() { + var doc = new Document("juhu\n1\n2\nkinners"); + var anchor = new Anchor(doc, 3, 4); + + doc.removeFullLines(1, 2); + assert.position(anchor.getPosition(), 1, 4); + }, + + "test remove new line before the cursor": function() { + var doc = new Document("juhu\nkinners"); + var anchor = new Anchor(doc, 1, 4); + + doc.removeNewLine(0); + assert.position(anchor.getPosition(), 0, 8); + }, + + "test delete range which contains the anchor should move anchor to the end of the range": function() { + var doc = new Document("juhu\nkinners"); + var anchor = new Anchor(doc, 1, 4); + + doc.remove(new Range(0, 2, 1, 2)); + assert.position(anchor.getPosition(), 0, 4); + }, + + "test delete line which contains the anchor should move anchor to the end of the range": function() { + var doc = new Document("juhu\nkinners\n123"); + var anchor = new Anchor(doc, 1, 5); + + doc.removeFullLines(1, 1); + assert.position(anchor.getPosition(), 1, 0); + }, + + "test remove after the anchor should have no effect": function() { + var doc = new Document("juhu\nkinners\n123"); + var anchor = new Anchor(doc, 1, 2); + + doc.remove(new Range(1, 4, 2, 2)); + assert.position(anchor.getPosition(), 1, 2); + }, + + "test anchor changes triggered by document changes should emit change event": function(next) { + var doc = new Document("juhu\nkinners\n123"); + var anchor = new Anchor(doc, 1, 5); + + anchor.on("change", function(e) { + assert.position(anchor.getPosition(), 0, 0); + next(); + }); + + doc.remove(new Range(0, 0, 2, 1)); + }, + + "test only fire change event if position changes": function() { + var doc = new Document("juhu\nkinners\n123"); + var anchor = new Anchor(doc, 1, 5); + + anchor.on("change", function(e) { + assert.fail(); + }); + + doc.remove(new Range(2, 0, 2, 1)); + }, + + "test insert/remove lines at the end of the document": function() { + var doc = new Document("juhu\nkinners\n123"); + var anchor = new Anchor(doc, 2, 4); + + doc.removeFullLines(0, 3); + assert.position(anchor.getPosition(), 0, 0); + doc.insertFullLines(0, ["a", "b", "c"]); + assert.position(anchor.getPosition(), 3, 0); + assert.equal(doc.getValue(), "a\nb\nc\n"); + } +}; + +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec() +} diff --git a/node_modules/ace/lib/ace/apply_delta.js b/node_modules/ace/lib/ace/apply_delta.js new file mode 100644 index 00000000..98bfe148 --- /dev/null +++ b/node_modules/ace/lib/ace/apply_delta.js @@ -0,0 +1,108 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +function throwDeltaError(delta, errorText){ + console.log("Invalid Delta:", delta); + throw "Invalid Delta: " + errorText; +} + +function positionInDocument(docLines, position) { + return position.row >= 0 && position.row < docLines.length && + position.column >= 0 && position.column <= docLines[position.row].length; +} + +function validateDelta(docLines, delta) { + // Validate action string. + if (delta.action != "insert" && delta.action != "remove") + throwDeltaError(delta, "delta.action must be 'insert' or 'remove'"); + + // Validate lines type. + if (!(delta.lines instanceof Array)) + throwDeltaError(delta, "delta.lines must be an Array"); + + // Validate range type. + if (!delta.start || !delta.end) + throwDeltaError(delta, "delta.start/end must be an present"); + + // Validate that the start point is contained in the document. + var start = delta.start; + if (!positionInDocument(docLines, delta.start)) + throwDeltaError(delta, "delta.start must be contained in document"); + + // Validate that the end point is contained in the document (remove deltas only). + var end = delta.end; + if (delta.action == "remove" && !positionInDocument(docLines, end)) + throwDeltaError(delta, "delta.end must contained in document for 'remove' actions"); + + // Validate that the .range size matches the .lines size. + var numRangeRows = end.row - start.row; + var numRangeLastLineChars = (end.column - (numRangeRows == 0 ? start.column : 0)); + if (numRangeRows != delta.lines.length - 1 || delta.lines[numRangeRows].length != numRangeLastLineChars) + throwDeltaError(delta, "delta.range must match delta lines"); +} + +exports.applyDelta = function(docLines, delta, doNotValidate) { + // disabled validation since it breaks autocompletion popup + // if (!doNotValidate) + // validateDelta(docLines, delta); + + var row = delta.start.row; + var startColumn = delta.start.column; + var line = docLines[row] || ""; + switch (delta.action) { + case "insert": + var lines = delta.lines; + if (lines.length === 1) { + docLines[row] = line.substring(0, startColumn) + delta.lines[0] + line.substring(startColumn); + } else { + var args = [row, 1].concat(delta.lines); + docLines.splice.apply(docLines, args); + docLines[row] = line.substring(0, startColumn) + docLines[row]; + docLines[row + delta.lines.length - 1] += line.substring(startColumn); + } + break; + case "remove": + var endColumn = delta.end.column; + var endRow = delta.end.row; + if (row === endRow) { + docLines[row] = line.substring(0, startColumn) + line.substring(endColumn); + } else { + docLines.splice( + row, endRow - row + 1, + line.substring(0, startColumn) + docLines[endRow].substring(endColumn) + ); + } + break; + } +} +}); diff --git a/node_modules/ace/lib/ace/autocomplete.js b/node_modules/ace/lib/ace/autocomplete.js new file mode 100644 index 00000000..460a62e6 --- /dev/null +++ b/node_modules/ace/lib/ace/autocomplete.js @@ -0,0 +1,497 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var HashHandler = require("./keyboard/hash_handler").HashHandler; +var AcePopup = require("./autocomplete/popup").AcePopup; +var util = require("./autocomplete/util"); +var event = require("./lib/event"); +var lang = require("./lib/lang"); +var dom = require("./lib/dom"); +var snippetManager = require("./snippets").snippetManager; + +var Autocomplete = function() { + this.autoInsert = false; + this.autoSelect = true; + this.exactMatch = false; + this.gatherCompletionsId = 0; + this.keyboardHandler = new HashHandler(); + this.keyboardHandler.bindKeys(this.commands); + + this.blurListener = this.blurListener.bind(this); + this.changeListener = this.changeListener.bind(this); + this.mousedownListener = this.mousedownListener.bind(this); + this.mousewheelListener = this.mousewheelListener.bind(this); + + this.changeTimer = lang.delayedCall(function() { + this.updateCompletions(true); + }.bind(this)); + + this.tooltipTimer = lang.delayedCall(this.updateDocTooltip.bind(this), 50); +}; + +(function() { + + this.$init = function() { + this.popup = new AcePopup(document.body || document.documentElement); + this.popup.on("click", function(e) { + this.insertMatch(); + e.stop(); + }.bind(this)); + this.popup.focus = this.editor.focus.bind(this.editor); + this.popup.on("show", this.tooltipTimer.bind(null, null)); + this.popup.on("select", this.tooltipTimer.bind(null, null)); + this.popup.on("changeHoverMarker", this.tooltipTimer.bind(null, null)); + return this.popup; + }; + + this.getPopup = function() { + return this.popup || this.$init(); + }; + + this.openPopup = function(editor, prefix, keepPopupPosition) { + if (!this.popup) + this.$init(); + + this.popup.setData(this.completions.filtered); + + editor.keyBinding.addKeyboardHandler(this.keyboardHandler); + + var renderer = editor.renderer; + this.popup.setRow(this.autoSelect ? 0 : -1); + if (!keepPopupPosition) { + this.popup.setTheme(editor.getTheme()); + this.popup.setFontSize(editor.getFontSize()); + + var lineHeight = renderer.layerConfig.lineHeight; + + var pos = renderer.$cursorLayer.getPixelPosition(this.base, true); + pos.left -= this.popup.getTextLeftOffset(); + + var rect = editor.container.getBoundingClientRect(); + pos.top += rect.top - renderer.layerConfig.offset; + pos.left += rect.left - editor.renderer.scrollLeft; + pos.left += renderer.$gutterLayer.gutterWidth; + + this.popup.show(pos, lineHeight); + } else if (keepPopupPosition && !prefix) { + this.detach(); + } + }; + + this.detach = function() { + this.editor.keyBinding.removeKeyboardHandler(this.keyboardHandler); + this.editor.off("changeSelection", this.changeListener); + this.editor.off("blur", this.blurListener); + this.editor.off("mousedown", this.mousedownListener); + this.editor.off("mousewheel", this.mousewheelListener); + this.changeTimer.cancel(); + this.hideDocTooltip(); + + this.gatherCompletionsId += 1; + if (this.popup && this.popup.isOpen) + this.popup.hide(); + + if (this.base) + this.base.detach(); + this.activated = false; + this.completions = this.base = null; + }; + + this.changeListener = function(e) { + var cursor = this.editor.selection.lead; + if (cursor.row != this.base.row || cursor.column < this.base.column) { + this.detach(); + } + if (this.activated) + this.changeTimer.schedule(); + else + this.detach(); + }; + + this.blurListener = function(e) { + // we have to check if activeElement is a child of popup because + // on IE preventDefault doesn't stop scrollbar from being focussed + var el = document.activeElement; + var text = this.editor.textInput.getElement() + if (el != text && el.parentNode != this.popup.container + && el != this.tooltipNode && e.relatedTarget != this.tooltipNode + && e.relatedTarget != text + ) { + this.detach(); + } + }; + + this.mousedownListener = function(e) { + this.detach(); + }; + + this.mousewheelListener = function(e) { + this.detach(); + }; + + this.goTo = function(where) { + var row = this.popup.getRow(); + var max = this.popup.session.getLength() - 1; + + switch(where) { + case "up": row = row <= 0 ? max : row - 1; break; + case "down": row = row >= max ? -1 : row + 1; break; + case "start": row = 0; break; + case "end": row = max; break; + } + + this.popup.setRow(row); + }; + + this.insertMatch = function(data) { + if (!data) + data = this.popup.getData(this.popup.getRow()); + if (!data) + return false; + + if (data.completer && data.completer.insertMatch) { + data.completer.insertMatch(this.editor, data); + } else { + if (this.completions.filterText) { + var ranges = this.editor.selection.getAllRanges(); + for (var i = 0, range; range = ranges[i]; i++) { + range.start.column -= this.completions.filterText.length; + this.editor.session.remove(range); + } + } + if (data.snippet) + snippetManager.insertSnippet(this.editor, data.snippet); + else + this.editor.execCommand("insertstring", data.value || data); + } + this.detach(); + }; + + + this.commands = { + "Up": function(editor) { editor.completer.goTo("up"); }, + "Down": function(editor) { editor.completer.goTo("down"); }, + "Ctrl-Up|Ctrl-Home": function(editor) { editor.completer.goTo("start"); }, + "Ctrl-Down|Ctrl-End": function(editor) { editor.completer.goTo("end"); }, + + "Esc": function(editor) { editor.completer.detach(); }, + "Space": function(editor) { editor.completer.detach(); editor.insert(" ");}, + "Return": function(editor) { return editor.completer.insertMatch(); }, + "Shift-Return": function(editor) { editor.completer.insertMatch(true); }, + "Tab": function(editor) { + var result = editor.completer.insertMatch(); + if (!result && !editor.tabstopManager) + editor.completer.goTo("down"); + else + return result; + }, + + "PageUp": function(editor) { editor.completer.popup.gotoPageUp(); }, + "PageDown": function(editor) { editor.completer.popup.gotoPageDown(); } + }; + + this.gatherCompletions = function(editor, callback) { + var session = editor.getSession(); + var pos = editor.getCursorPosition(); + + var line = session.getLine(pos.row); + var prefix = util.retrievePrecedingIdentifier(line, pos.column); + + this.base = session.doc.createAnchor(pos.row, pos.column - prefix.length); + this.base.$insertRight = true; + + var matches = []; + var total = editor.completers.length; + editor.completers.forEach(function(completer, i) { + completer.getCompletions(editor, session, pos, prefix, function(err, results) { + if (!err) + matches = matches.concat(results); + // Fetch prefix again, because they may have changed by now + var pos = editor.getCursorPosition(); + var line = session.getLine(pos.row); + callback(null, { + prefix: util.retrievePrecedingIdentifier(line, pos.column, results[0] && results[0].identifierRegex), + matches: matches, + finished: (--total === 0) + }); + }); + }); + return true; + }; + + this.showPopup = function(editor) { + if (this.editor) + this.detach(); + + this.activated = true; + + this.editor = editor; + if (editor.completer != this) { + if (editor.completer) + editor.completer.detach(); + editor.completer = this; + } + + editor.on("changeSelection", this.changeListener); + editor.on("blur", this.blurListener); + editor.on("mousedown", this.mousedownListener); + editor.on("mousewheel", this.mousewheelListener); + + this.updateCompletions(); + }; + + this.updateCompletions = function(keepPopupPosition) { + if (keepPopupPosition && this.base && this.completions) { + var pos = this.editor.getCursorPosition(); + var prefix = this.editor.session.getTextRange({start: this.base, end: pos}); + if (prefix == this.completions.filterText) + return; + this.completions.setFilter(prefix); + if (!this.completions.filtered.length) + return this.detach(); + if (this.completions.filtered.length == 1 + && this.completions.filtered[0].value == prefix + && !this.completions.filtered[0].snippet) + return this.detach(); + this.openPopup(this.editor, prefix, keepPopupPosition); + return; + } + + // Save current gatherCompletions session, session is close when a match is insert + var _id = this.gatherCompletionsId; + this.gatherCompletions(this.editor, function(err, results) { + // Only detach if result gathering is finished + var detachIfFinished = function() { + if (!results.finished) return; + return this.detach(); + }.bind(this); + + var prefix = results.prefix; + var matches = results && results.matches; + + if (!matches || !matches.length) + return detachIfFinished(); + + // Wrong prefix or wrong session -> ignore + if (prefix.indexOf(results.prefix) !== 0 || _id != this.gatherCompletionsId) + return; + + this.completions = new FilteredList(matches); + + if (this.exactMatch) + this.completions.exactMatch = true; + + this.completions.setFilter(prefix); + var filtered = this.completions.filtered; + + // No results + if (!filtered.length) + return detachIfFinished(); + + // One result equals to the prefix + if (filtered.length == 1 && filtered[0].value == prefix && !filtered[0].snippet) + return detachIfFinished(); + + // Autoinsert if one result + if (this.autoInsert && filtered.length == 1 && results.finished) + return this.insertMatch(filtered[0]); + + this.openPopup(this.editor, prefix, keepPopupPosition); + }.bind(this)); + }; + + this.cancelContextMenu = function() { + this.editor.$mouseHandler.cancelContextMenu(); + }; + + this.updateDocTooltip = function() { + var popup = this.popup; + var all = popup.data; + var selected = all && (all[popup.getHoveredRow()] || all[popup.getRow()]); + var doc = null; + if (!selected || !this.editor || !this.popup.isOpen) + return this.hideDocTooltip(); + this.editor.completers.some(function(completer) { + if (completer.getDocTooltip) + doc = completer.getDocTooltip(selected); + return doc; + }); + if (!doc) + doc = selected; + + if (typeof doc == "string") + doc = {docText: doc} + if (!doc || !(doc.docHTML || doc.docText)) + return this.hideDocTooltip(); + this.showDocTooltip(doc); + }; + + this.showDocTooltip = function(item) { + if (!this.tooltipNode) { + this.tooltipNode = dom.createElement("div"); + this.tooltipNode.className = "ace_tooltip ace_doc-tooltip"; + this.tooltipNode.style.margin = 0; + this.tooltipNode.style.pointerEvents = "auto"; + this.tooltipNode.tabIndex = -1; + this.tooltipNode.onblur = this.blurListener.bind(this); + } + + var tooltipNode = this.tooltipNode; + if (item.docHTML) { + tooltipNode.innerHTML = item.docHTML; + } else if (item.docText) { + tooltipNode.textContent = item.docText; + } + + if (!tooltipNode.parentNode) + document.body.appendChild(tooltipNode); + var popup = this.popup; + var rect = popup.container.getBoundingClientRect(); + tooltipNode.style.top = popup.container.style.top; + tooltipNode.style.bottom = popup.container.style.bottom; + + if (window.innerWidth - rect.right < 320) { + tooltipNode.style.right = window.innerWidth - rect.left + "px"; + tooltipNode.style.left = ""; + } else { + tooltipNode.style.left = (rect.right + 1) + "px"; + tooltipNode.style.right = ""; + } + tooltipNode.style.display = "block"; + }; + + this.hideDocTooltip = function() { + this.tooltipTimer.cancel(); + if (!this.tooltipNode) return; + var el = this.tooltipNode; + if (!this.editor.isFocused() && document.activeElement == el) + this.editor.focus(); + this.tooltipNode = null; + if (el.parentNode) + el.parentNode.removeChild(el); + }; + +}).call(Autocomplete.prototype); + +Autocomplete.startCommand = { + name: "startAutocomplete", + exec: function(editor) { + if (!editor.completer) + editor.completer = new Autocomplete(); + editor.completer.autoInsert = false; + editor.completer.autoSelect = true; + editor.completer.showPopup(editor); + // prevent ctrl-space opening context menu on firefox on mac + editor.completer.cancelContextMenu(); + }, + bindKey: "Ctrl-Space|Ctrl-Shift-Space|Alt-Space" +}; + +var FilteredList = function(array, filterText, mutateData) { + this.all = array; + this.filtered = array; + this.filterText = filterText || ""; + this.exactMatch = false; +}; +(function(){ + this.setFilter = function(str) { + if (str.length > this.filterText && str.lastIndexOf(this.filterText, 0) === 0) + var matches = this.filtered; + else + var matches = this.all; + + this.filterText = str; + matches = this.filterCompletions(matches, this.filterText); + matches = matches.sort(function(a, b) { + return b.exactMatch - a.exactMatch || b.score - a.score; + }); + + // make unique + var prev = null; + matches = matches.filter(function(item){ + var caption = item.snippet || item.caption || item.value; + if (caption === prev) return false; + prev = caption; + return true; + }); + + this.filtered = matches; + }; + this.filterCompletions = function(items, needle) { + var results = []; + var upper = needle.toUpperCase(); + var lower = needle.toLowerCase(); + loop: for (var i = 0, item; item = items[i]; i++) { + var caption = item.value || item.caption || item.snippet; + if (!caption) continue; + var lastIndex = -1; + var matchMask = 0; + var penalty = 0; + var index, distance; + + if (this.exactMatch) { + if (needle !== caption.substr(0, needle.length)) + continue loop; + }else{ + // caption char iteration is faster in Chrome but slower in Firefox, so lets use indexOf + for (var j = 0; j < needle.length; j++) { + // TODO add penalty on case mismatch + var i1 = caption.indexOf(lower[j], lastIndex + 1); + var i2 = caption.indexOf(upper[j], lastIndex + 1); + index = (i1 >= 0) ? ((i2 < 0 || i1 < i2) ? i1 : i2) : i2; + if (index < 0) + continue loop; + distance = index - lastIndex - 1; + if (distance > 0) { + // first char mismatch should be more sensitive + if (lastIndex === -1) + penalty += 10; + penalty += distance; + } + matchMask = matchMask | (1 << index); + lastIndex = index; + } + } + item.matchMask = matchMask; + item.exactMatch = penalty ? 0 : 1; + item.score = (item.score || 0) - penalty; + results.push(item); + } + return results; + }; +}).call(FilteredList.prototype); + +exports.Autocomplete = Autocomplete; +exports.FilteredList = FilteredList; + +}); diff --git a/node_modules/ace/lib/ace/autocomplete/popup.js b/node_modules/ace/lib/ace/autocomplete/popup.js new file mode 100644 index 00000000..2852650f --- /dev/null +++ b/node_modules/ace/lib/ace/autocomplete/popup.js @@ -0,0 +1,339 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var EditSession = require("../edit_session").EditSession; +var Renderer = require("../virtual_renderer").VirtualRenderer; +var Editor = require("../editor").Editor; +var Range = require("../range").Range; +var event = require("../lib/event"); +var lang = require("../lib/lang"); +var dom = require("../lib/dom"); + +var $singleLineEditor = function(el) { + var renderer = new Renderer(el); + + renderer.$maxLines = 4; + + var editor = new Editor(renderer); + + editor.setHighlightActiveLine(false); + editor.setShowPrintMargin(false); + editor.renderer.setShowGutter(false); + editor.renderer.setHighlightGutterLine(false); + + editor.$mouseHandler.$focusWaitTimout = 0; + editor.$highlightTagPending = true; + + return editor; +}; + +var AcePopup = function(parentNode) { + var el = dom.createElement("div"); + var popup = new $singleLineEditor(el); + + if (parentNode) + parentNode.appendChild(el); + el.style.display = "none"; + popup.renderer.content.style.cursor = "default"; + popup.renderer.setStyle("ace_autocomplete"); + + popup.setOption("displayIndentGuides", false); + popup.setOption("dragDelay", 150); + + var noop = function(){}; + + popup.focus = noop; + popup.$isFocused = true; + + popup.renderer.$cursorLayer.restartTimer = noop; + popup.renderer.$cursorLayer.element.style.opacity = 0; + + popup.renderer.$maxLines = 8; + popup.renderer.$keepTextAreaAtCursor = false; + + popup.setHighlightActiveLine(false); + // set default highlight color + popup.session.highlight(""); + popup.session.$searchHighlight.clazz = "ace_highlight-marker"; + + popup.on("mousedown", function(e) { + var pos = e.getDocumentPosition(); + popup.selection.moveToPosition(pos); + selectionMarker.start.row = selectionMarker.end.row = pos.row; + e.stop(); + }); + + var lastMouseEvent; + var hoverMarker = new Range(-1,0,-1,Infinity); + var selectionMarker = new Range(-1,0,-1,Infinity); + selectionMarker.id = popup.session.addMarker(selectionMarker, "ace_active-line", "fullLine"); + popup.setSelectOnHover = function(val) { + if (!val) { + hoverMarker.id = popup.session.addMarker(hoverMarker, "ace_line-hover", "fullLine"); + } else if (hoverMarker.id) { + popup.session.removeMarker(hoverMarker.id); + hoverMarker.id = null; + } + }; + popup.setSelectOnHover(false); + popup.on("mousemove", function(e) { + if (!lastMouseEvent) { + lastMouseEvent = e; + return; + } + if (lastMouseEvent.x == e.x && lastMouseEvent.y == e.y) { + return; + } + lastMouseEvent = e; + lastMouseEvent.scrollTop = popup.renderer.scrollTop; + var row = lastMouseEvent.getDocumentPosition().row; + if (hoverMarker.start.row != row) { + if (!hoverMarker.id) + popup.setRow(row); + setHoverMarker(row); + } + }); + popup.renderer.on("beforeRender", function() { + if (lastMouseEvent && hoverMarker.start.row != -1) { + lastMouseEvent.$pos = null; + var row = lastMouseEvent.getDocumentPosition().row; + if (!hoverMarker.id) + popup.setRow(row); + setHoverMarker(row, true); + } + }); + popup.renderer.on("afterRender", function() { + var row = popup.getRow(); + var t = popup.renderer.$textLayer; + var selected = t.element.childNodes[row - t.config.firstRow]; + if (selected == t.selectedNode) + return; + if (t.selectedNode) + dom.removeCssClass(t.selectedNode, "ace_selected"); + t.selectedNode = selected; + if (selected) + dom.addCssClass(selected, "ace_selected"); + }); + var hideHoverMarker = function() { setHoverMarker(-1) }; + var setHoverMarker = function(row, suppressRedraw) { + if (row !== hoverMarker.start.row) { + hoverMarker.start.row = hoverMarker.end.row = row; + if (!suppressRedraw) + popup.session._emit("changeBackMarker"); + popup._emit("changeHoverMarker"); + } + }; + popup.getHoveredRow = function() { + return hoverMarker.start.row; + }; + + event.addListener(popup.container, "mouseout", hideHoverMarker); + popup.on("hide", hideHoverMarker); + popup.on("changeSelection", hideHoverMarker); + + popup.session.doc.getLength = function() { + return popup.data.length; + }; + popup.session.doc.getLine = function(i) { + var data = popup.data[i]; + if (typeof data == "string") + return data; + return (data && data.value) || ""; + }; + + var bgTokenizer = popup.session.bgTokenizer; + bgTokenizer.$tokenizeRow = function(row) { + var data = popup.data[row]; + var tokens = []; + if (!data) + return tokens; + if (typeof data == "string") + data = {value: data}; + if (!data.caption) + data.caption = data.value || data.name; + + var last = -1; + var flag, c; + for (var i = 0; i < data.caption.length; i++) { + c = data.caption[i]; + flag = data.matchMask & (1 << i) ? 1 : 0; + if (last !== flag) { + tokens.push({type: data.className || "" + ( flag ? "completion-highlight" : ""), value: c}); + last = flag; + } else { + tokens[tokens.length - 1].value += c; + } + } + + if (data.meta) { + var maxW = popup.renderer.$size.scrollerWidth / popup.renderer.layerConfig.characterWidth; + if (data.meta.length + data.caption.length < maxW - 2) + tokens.push({type: "rightAlignedText", value: data.meta}); + } + return tokens; + }; + bgTokenizer.$updateOnChange = noop; + bgTokenizer.start = noop; + + popup.session.$computeWidth = function() { + return this.screenWidth = 0; + }; + + // public + popup.isOpen = false; + popup.isTopdown = false; + + popup.data = []; + popup.setData = function(list) { + popup.setValue(lang.stringRepeat("\n", list.length), -1); + popup.data = list || []; + popup.setRow(0); + }; + popup.getData = function(row) { + return popup.data[row]; + }; + + popup.getRow = function() { + return selectionMarker.start.row; + }; + popup.setRow = function(line) { + line = Math.max(-1, Math.min(this.data.length, line)); + if (selectionMarker.start.row != line) { + popup.selection.clearSelection(); + selectionMarker.start.row = selectionMarker.end.row = line || 0; + popup.session._emit("changeBackMarker"); + popup.moveCursorTo(line || 0, 0); + if (popup.isOpen) + popup._signal("select"); + } + }; + + popup.on("changeSelection", function() { + if (popup.isOpen) + popup.setRow(popup.selection.lead.row); + popup.renderer.scrollCursorIntoView(); + }); + + popup.hide = function() { + this.container.style.display = "none"; + this._signal("hide"); + popup.isOpen = false; + }; + popup.show = function(pos, lineHeight, topdownOnly) { + var el = this.container; + var screenHeight = window.innerHeight; + var screenWidth = window.innerWidth; + var renderer = this.renderer; + // var maxLines = Math.min(renderer.$maxLines, this.session.getLength()); + var maxH = renderer.$maxLines * lineHeight * 1.4; + var top = pos.top + this.$borderSize; + if (top + maxH > screenHeight - lineHeight && !topdownOnly) { + el.style.top = ""; + el.style.bottom = screenHeight - top + "px"; + popup.isTopdown = false; + } else { + top += lineHeight; + el.style.top = top + "px"; + el.style.bottom = ""; + popup.isTopdown = true; + } + + el.style.display = ""; + this.renderer.$textLayer.checkForSizeChanges(); + + var left = pos.left; + if (left + el.offsetWidth > screenWidth) + left = screenWidth - el.offsetWidth; + + el.style.left = left + "px"; + + this._signal("show"); + lastMouseEvent = null; + popup.isOpen = true; + }; + + popup.getTextLeftOffset = function() { + return this.$borderSize + this.renderer.$padding + this.$imageSize; + }; + + popup.$imageSize = 0; + popup.$borderSize = 1; + + return popup; +}; + +dom.importCssString("\ +.ace_autocomplete.ace-tm .ace_marker-layer .ace_active-line {\ + background-color: #CAD6FA;\ + z-index: 1;\ +}\ +.ace_autocomplete.ace-tm .ace_line-hover {\ + border: 1px solid #abbffe;\ + margin-top: -1px;\ + background: rgba(233,233,253,0.4);\ +}\ +.ace_autocomplete .ace_line-hover {\ + position: absolute;\ + z-index: 2;\ +}\ +.ace_autocomplete .ace_scroller {\ + background: none;\ + border: none;\ + box-shadow: none;\ +}\ +.ace_rightAlignedText {\ + color: gray;\ + display: inline-block;\ + position: absolute;\ + right: 4px;\ + text-align: right;\ + z-index: -1;\ +}\ +.ace_autocomplete .ace_completion-highlight{\ + color: #000;\ + text-shadow: 0 0 0.01em;\ +}\ +.ace_autocomplete {\ + width: 280px;\ + z-index: 200000;\ + background: #fbfbfb;\ + color: #444;\ + border: 1px lightgray solid;\ + position: fixed;\ + box-shadow: 2px 3px 5px rgba(0,0,0,.2);\ + line-height: 1.4;\ +}"); + +exports.AcePopup = AcePopup; + +}); \ No newline at end of file diff --git a/node_modules/ace/lib/ace/autocomplete/text_completer.js b/node_modules/ace/lib/ace/autocomplete/text_completer.js new file mode 100644 index 00000000..17a4bdad --- /dev/null +++ b/node_modules/ace/lib/ace/autocomplete/text_completer.js @@ -0,0 +1,78 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + var Range = require("../range").Range; + + var splitRegex = /[^a-zA-Z_0-9\$\-\u00C0-\u1FFF\u2C00-\uD7FF\w]+/; + + function getWordIndex(doc, pos) { + var textBefore = doc.getTextRange(Range.fromPoints({row: 0, column:0}, pos)); + return textBefore.split(splitRegex).length - 1; + } + + /** + * Does a distance analysis of the word `prefix` at position `pos` in `doc`. + * @return Map + */ + function wordDistance(doc, pos) { + var prefixPos = getWordIndex(doc, pos); + var words = doc.getValue().split(splitRegex); + var wordScores = Object.create(null); + + var currentWord = words[prefixPos]; + + words.forEach(function(word, idx) { + if (!word || word === currentWord) return; + + var distance = Math.abs(prefixPos - idx); + var score = words.length - distance; + if (wordScores[word]) { + wordScores[word] = Math.max(score, wordScores[word]); + } else { + wordScores[word] = score; + } + }); + return wordScores; + } + + exports.getCompletions = function(editor, session, pos, prefix, callback) { + var wordScore = wordDistance(session, pos, prefix); + var wordList = Object.keys(wordScore); + callback(null, wordList.map(function(word) { + return { + caption: word, + value: word, + score: wordScore[word], + meta: "local" + }; + })); + }; +}); diff --git a/node_modules/ace/lib/ace/autocomplete/util.js b/node_modules/ace/lib/ace/autocomplete/util.js new file mode 100644 index 00000000..767b983e --- /dev/null +++ b/node_modules/ace/lib/ace/autocomplete/util.js @@ -0,0 +1,74 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +exports.parForEach = function(array, fn, callback) { + var completed = 0; + var arLength = array.length; + if (arLength === 0) + callback(); + for (var i = 0; i < arLength; i++) { + fn(array[i], function(result, err) { + completed++; + if (completed === arLength) + callback(result, err); + }); + } +}; + +var ID_REGEX = /[a-zA-Z_0-9\$\-\u00A2-\uFFFF]/; + +exports.retrievePrecedingIdentifier = function(text, pos, regex) { + regex = regex || ID_REGEX; + var buf = []; + for (var i = pos-1; i >= 0; i--) { + if (regex.test(text[i])) + buf.push(text[i]); + else + break; + } + return buf.reverse().join(""); +}; + +exports.retrieveFollowingIdentifier = function(text, pos, regex) { + regex = regex || ID_REGEX; + var buf = []; + for (var i = pos; i < text.length; i++) { + if (regex.test(text[i])) + buf.push(text[i]); + else + break; + } + return buf; +}; + +}); diff --git a/node_modules/ace/lib/ace/background_tokenizer.js b/node_modules/ace/lib/ace/background_tokenizer.js new file mode 100644 index 00000000..00273647 --- /dev/null +++ b/node_modules/ace/lib/ace/background_tokenizer.js @@ -0,0 +1,249 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("./lib/oop"); +var EventEmitter = require("./lib/event_emitter").EventEmitter; + + +/** + * Tokenizes the current [[Document `Document`]] in the background, and caches the tokenized rows for future use. + * + * If a certain row is changed, everything below that row is re-tokenized. + * + * @class BackgroundTokenizer + **/ + +/** + * Creates a new `BackgroundTokenizer` object. + * @param {Tokenizer} tokenizer The tokenizer to use + * @param {Editor} editor The editor to associate with + * + * @constructor + **/ + +var BackgroundTokenizer = function(tokenizer, editor) { + this.running = false; + this.lines = []; + this.states = []; + this.currentLine = 0; + this.tokenizer = tokenizer; + + var self = this; + + this.$worker = function() { + if (!self.running) { return; } + + var workerStart = new Date(); + var currentLine = self.currentLine; + var endLine = -1; + var doc = self.doc; + + while (self.lines[currentLine]) + currentLine++; + + var startLine = currentLine; + + var len = doc.getLength(); + var processedLines = 0; + self.running = false; + while (currentLine < len) { + self.$tokenizeRow(currentLine); + endLine = currentLine; + do { + currentLine++; + } while (self.lines[currentLine]); + + // only check every 5 lines + processedLines ++; + if ((processedLines % 5 === 0) && (new Date() - workerStart) > 20) { + self.running = setTimeout(self.$worker, 20); + break; + } + } + self.currentLine = currentLine; + + if (startLine <= endLine) + self.fireUpdateEvent(startLine, endLine); + }; +}; + +(function(){ + + oop.implement(this, EventEmitter); + + /** + * Sets a new tokenizer for this object. + * + * @param {Tokenizer} tokenizer The new tokenizer to use + * + **/ + this.setTokenizer = function(tokenizer) { + this.tokenizer = tokenizer; + this.lines = []; + this.states = []; + + this.start(0); + }; + + /** + * Sets a new document to associate with this object. + * @param {Document} doc The new document to associate with + **/ + this.setDocument = function(doc) { + this.doc = doc; + this.lines = []; + this.states = []; + + this.stop(); + }; + + /** + * Fires whenever the background tokeniziers between a range of rows are going to be updated. + * + * @event update + * @param {Object} e An object containing two properties, `first` and `last`, which indicate the rows of the region being updated. + * + **/ + /** + * Emits the `'update'` event. `firstRow` and `lastRow` are used to define the boundaries of the region to be updated. + * @param {Number} firstRow The starting row region + * @param {Number} lastRow The final row region + * + **/ + this.fireUpdateEvent = function(firstRow, lastRow) { + var data = { + first: firstRow, + last: lastRow + }; + this._signal("update", {data: data}); + }; + + /** + * Starts tokenizing at the row indicated. + * + * @param {Number} startRow The row to start at + * + **/ + this.start = function(startRow) { + this.currentLine = Math.min(startRow || 0, this.currentLine, this.doc.getLength()); + + // remove all cached items below this line + this.lines.splice(this.currentLine, this.lines.length); + this.states.splice(this.currentLine, this.states.length); + + this.stop(); + // pretty long delay to prevent the tokenizer from interfering with the user + this.running = setTimeout(this.$worker, 700); + }; + + this.scheduleStart = function() { + if (!this.running) + this.running = setTimeout(this.$worker, 700); + } + + this.$updateOnChange = function(delta) { + var startRow = delta.start.row; + var len = delta.end.row - startRow; + + if (len === 0) { + this.lines[startRow] = null; + } else if (delta.action == "remove") { + this.lines.splice(startRow, len + 1, null); + this.states.splice(startRow, len + 1, null); + } else { + var args = Array(len + 1); + args.unshift(startRow, 1); + this.lines.splice.apply(this.lines, args); + this.states.splice.apply(this.states, args); + } + + this.currentLine = Math.min(startRow, this.currentLine, this.doc.getLength()); + + this.stop(); + }; + + /** + * Stops tokenizing. + * + **/ + this.stop = function() { + if (this.running) + clearTimeout(this.running); + this.running = false; + }; + + /** + * Gives list of tokens of the row. (tokens are cached) + * + * @param {Number} row The row to get tokens at + * + * + * + **/ + this.getTokens = function(row) { + return this.lines[row] || this.$tokenizeRow(row); + }; + + /** + * [Returns the state of tokenization at the end of a row.]{: #BackgroundTokenizer.getState} + * + * @param {Number} row The row to get state at + **/ + this.getState = function(row) { + if (this.currentLine == row) + this.$tokenizeRow(row); + return this.states[row] || "start"; + }; + + this.$tokenizeRow = function(row) { + var line = this.doc.getLine(row); + var state = this.states[row - 1]; + + var data = this.tokenizer.getLineTokens(line, state, row); + + if (this.states[row] + "" !== data.state + "") { + this.states[row] = data.state; + this.lines[row + 1] = null; + if (this.currentLine > row + 1) + this.currentLine = row + 1; + } else if (this.currentLine == row) { + this.currentLine = row + 1; + } + + return this.lines[row] = data.tokens; + }; + +}).call(BackgroundTokenizer.prototype); + +exports.BackgroundTokenizer = BackgroundTokenizer; +}); diff --git a/node_modules/ace/lib/ace/background_tokenizer_test.js b/node_modules/ace/lib/ace/background_tokenizer_test.js new file mode 100644 index 00000000..7a4cc78c --- /dev/null +++ b/node_modules/ace/lib/ace/background_tokenizer_test.js @@ -0,0 +1,85 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +if (typeof process !== "undefined") { + require("amd-loader"); +} + +define(function(require, exports, module) { +"use strict"; + +var EditSession = require("./edit_session").EditSession; +var JavaScriptMode = require("./mode/javascript").Mode; +var Range = require("./range").Range; +var assert = require("./test/assertions"); + +function forceTokenize(session){ + for (var i = 0, l = session.getLength(); i < l; i++) + session.getTokens(i) +} + +function testStates(session, states) { + for (var i = 0, l = session.getLength(); i < l; i++) + assert.equal(session.bgTokenizer.states[i], states[i]) + assert.ok(l == states.length) +} + +module.exports = { + + "test background tokenizer update on session change" : function() { + var doc = new EditSession([ + "/*", + "*/", + "var juhu" + ]); + doc.setMode("./mode/javascript") + + forceTokenize(doc) + testStates(doc, ["comment_regex_allowed", "start", "no_regex"]) + + doc.remove(new Range(0,2,1,2)) + testStates(doc, [null, "no_regex"]) + + forceTokenize(doc) + testStates(doc, ["comment_regex_allowed", "comment_regex_allowed"]) + + doc.insert({row:0, column:2}, "\n*/") + testStates(doc, [undefined, undefined, "comment_regex_allowed"]) + + forceTokenize(doc) + testStates(doc, ["comment_regex_allowed", "start", "no_regex"]) + } +}; + +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec() +} diff --git a/node_modules/ace/lib/ace/commands/command_manager.js b/node_modules/ace/lib/ace/commands/command_manager.js new file mode 100644 index 00000000..df30ef9b --- /dev/null +++ b/node_modules/ace/lib/ace/commands/command_manager.js @@ -0,0 +1,118 @@ +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var MultiHashHandler = require("../keyboard/hash_handler").MultiHashHandler; +var EventEmitter = require("../lib/event_emitter").EventEmitter; + +/** + * @class CommandManager + * + **/ + +/** + * new CommandManager(platform, commands) + * @param {String} platform Identifier for the platform; must be either `"mac"` or `"win"` + * @param {Array} commands A list of commands + * + **/ + +var CommandManager = function(platform, commands) { + MultiHashHandler.call(this, commands, platform); + this.byName = this.commands; + this.setDefaultHandler("exec", function(e) { + return e.command.exec(e.editor, e.args || {}); + }); +}; + +oop.inherits(CommandManager, MultiHashHandler); + +(function() { + + oop.implement(this, EventEmitter); + + this.exec = function(command, editor, args) { + if (Array.isArray(command)) { + for (var i = command.length; i--; ) { + if (this.exec(command[i], editor, args)) return true; + } + return false; + } + + if (typeof command === "string") + command = this.commands[command]; + + if (!command) + return false; + + if (editor && editor.$readOnly && !command.readOnly) + return false; + + var e = {editor: editor, command: command, args: args}; + e.returnValue = this._emit("exec", e); + this._signal("afterExec", e); + + return e.returnValue === false ? false : true; + }; + + this.toggleRecording = function(editor) { + if (this.$inReplay) + return; + + editor && editor._emit("changeStatus"); + if (this.recording) { + this.macro.pop(); + this.removeEventListener("exec", this.$addCommandToMacro); + + if (!this.macro.length) + this.macro = this.oldMacro; + + return this.recording = false; + } + if (!this.$addCommandToMacro) { + this.$addCommandToMacro = function(e) { + this.macro.push([e.command, e.args]); + }.bind(this); + } + + this.oldMacro = this.macro; + this.macro = []; + this.on("exec", this.$addCommandToMacro); + return this.recording = true; + }; + + this.replay = function(editor) { + if (this.$inReplay || !this.macro) + return; + + if (this.recording) + return this.toggleRecording(editor); + + try { + this.$inReplay = true; + this.macro.forEach(function(x) { + if (typeof x == "string") + this.exec(x, editor); + else + this.exec(x[0], editor, x[1]); + }, this); + } finally { + this.$inReplay = false; + } + }; + + this.trimMacro = function(m) { + return m.map(function(x){ + if (typeof x[0] != "string") + x[0] = x[0].name; + if (!x[1]) + x = x[0]; + return x; + }); + }; + +}).call(CommandManager.prototype); + +exports.CommandManager = CommandManager; + +}); diff --git a/node_modules/ace/lib/ace/commands/command_manager_test.js b/node_modules/ace/lib/ace/commands/command_manager_test.js new file mode 100644 index 00000000..902600be --- /dev/null +++ b/node_modules/ace/lib/ace/commands/command_manager_test.js @@ -0,0 +1,199 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +if (typeof process !== "undefined") { + require("amd-loader"); +} + +define(function(require, exports, module) { +"use strict"; + +var CommandManager = require("./command_manager").CommandManager; +var keys = require("../lib/keys"); +var assert = require("../test/assertions"); + +module.exports = { + + setUp: function() { + this.command = { + name: "gotoline", + bindKey: { + mac: "Command-L", + win: "Ctrl-L" + }, + called: false, + exec: function(editor) { this.called = true; } + }; + + this.cm = new CommandManager("mac", [this.command]); + }, + + "test: register command": function() { + this.cm.exec("gotoline"); + assert.ok(this.command.called); + }, + + "test: mac hotkeys": function() { + var command = this.cm.findKeyCommand(keys.KEY_MODS.command, "l"); + assert.equal(command, this.command); + + var command = this.cm.findKeyCommand(keys.KEY_MODS.ctrl, "l"); + assert.equal(command, undefined); + }, + + "test: win hotkeys": function() { + var cm = new CommandManager("win", [this.command]); + + var command = cm.findKeyCommand(keys.KEY_MODS.command, "l"); + assert.equal(command, undefined); + + var command = cm.findKeyCommand(keys.KEY_MODS.ctrl, "l"); + assert.equal(command, this.command); + }, + + "test: remove command by object": function() { + this.cm.removeCommand(this.command); + + this.cm.exec("gotoline"); + assert.ok(!this.command.called); + + var command = this.cm.findKeyCommand(keys.KEY_MODS.command, "l"); + assert.equal(command, null); + }, + + "test: remove command by name": function() { + this.cm.removeCommand("gotoline"); + + this.cm.exec("gotoline"); + assert.ok(!this.command.called); + + var command = this.cm.findKeyCommand(keys.KEY_MODS.command, "l"); + assert.equal(command, null); + }, + + "test: adding a new command with the same name as an existing one should remove the old one first": function() { + var command = { + name: "gotoline", + bindKey: { + mac: "Command-L", + win: "Ctrl-L" + }, + called: false, + exec: function(editor) { this.called = true; } + }; + this.cm.addCommand(command); + + this.cm.exec("gotoline"); + assert.ok(command.called); + assert.ok(!this.command.called); + + assert.equal(this.cm.findKeyCommand(keys.KEY_MODS.command, "l"), command); + }, + + "test: adding commands and recording a macro": function() { + var called = ""; + this.cm.addCommands({ + togglerecording: function(editor) { + editor.cm.toggleRecording(editor); + }, + replay: function(editor) { + editor.cm.replay(); + }, + cm1: function(editor, arg) { + called += "1" + (arg || ""); + }, + cm2: function(editor) { + called += "2"; + } + }); + + + var statusUpdateEmitted = false; + this._emit = function() {statusUpdateEmitted = true}; + + this.cm.exec("togglerecording", this); + assert.ok(this.cm.recording); + assert.ok(statusUpdateEmitted); + + this.cm.exec("cm1", this, "-"); + this.cm.exec("cm2"); + this.cm.exec("replay", this); + assert.ok(!this.cm.recording); + assert.equal(called, "1-2"); + + called = ""; + this.cm.exec("replay", this); + assert.equal(called, "1-2"); + }, + + "test: bindkeys": function() { + this.cm.bindKeys({ + "Ctrl-L|Command-C": "cm1", + "Ctrl-R": "cm2" + }); + + var command = this.cm.findKeyCommand(keys.KEY_MODS.command, "c"); + assert.equal(command, "cm1"); + + var command = this.cm.findKeyCommand(keys.KEY_MODS.ctrl, "r"); + assert.equal(command, "cm2"); + + this.cm.bindKeys({ + "Ctrl-R": null + }); + + var command = this.cm.findKeyCommand(keys.KEY_MODS.ctrl, "r"); + assert.equal(command, null); + }, + + "test: binding keys without modifiers": function() { + this.cm.bindKeys({ + "R": "cm1", + "Shift-r": "cm2", + "Return": "cm4", + "Enter": "cm3" + }); + + var command = this.cm.findKeyCommand(-1, "r"); + assert.equal(command, "cm1"); + + var command = this.cm.findKeyCommand(-1, "R"); + assert.equal(command, "cm2"); + + var command = this.cm.findKeyCommand(0, "return"); + assert.equal(command + "", ["cm4", "cm3"] + ""); + } +}; + +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec(); +} diff --git a/node_modules/ace/lib/ace/commands/default_commands.js b/node_modules/ace/lib/ace/commands/default_commands.js new file mode 100644 index 00000000..e941806b --- /dev/null +++ b/node_modules/ace/lib/ace/commands/default_commands.js @@ -0,0 +1,725 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var lang = require("../lib/lang"); +var config = require("../config"); +var Range = require("../range").Range; + +function bindKey(win, mac) { + return {win: win, mac: mac}; +} + +/* + multiSelectAction: "forEach"|"forEachLine"|function|undefined, + scrollIntoView: true|"cursor"|"center"|"selectionPart" +*/ +exports.commands = [{ + name: "showSettingsMenu", + bindKey: bindKey("Ctrl-,", "Command-,"), + exec: function(editor) { + config.loadModule("ace/ext/settings_menu", function(module) { + module.init(editor); + editor.showSettingsMenu(); + }); + }, + readOnly: true +}, { + name: "goToNextError", + bindKey: bindKey("Alt-E", "Ctrl-E"), + exec: function(editor) { + config.loadModule("ace/ext/error_marker", function(module) { + module.showErrorMarker(editor, 1); + }); + }, + scrollIntoView: "animate", + readOnly: true +}, { + name: "goToPreviousError", + bindKey: bindKey("Alt-Shift-E", "Ctrl-Shift-E"), + exec: function(editor) { + config.loadModule("ace/ext/error_marker", function(module) { + module.showErrorMarker(editor, -1); + }); + }, + scrollIntoView: "animate", + readOnly: true +}, { + name: "selectall", + bindKey: bindKey("Ctrl-A", "Command-A"), + exec: function(editor) { editor.selectAll(); }, + readOnly: true +}, { + name: "centerselection", + bindKey: bindKey(null, "Ctrl-L"), + exec: function(editor) { editor.centerSelection(); }, + readOnly: true +}, { + name: "gotoline", + bindKey: bindKey("Ctrl-L", "Command-L"), + exec: function(editor) { + var line = parseInt(prompt("Enter line number:"), 10); + if (!isNaN(line)) { + editor.gotoLine(line); + } + }, + readOnly: true +}, { + name: "fold", + bindKey: bindKey("Alt-L|Ctrl-F1", "Command-Alt-L|Command-F1"), + exec: function(editor) { editor.session.toggleFold(false); }, + multiSelectAction: "forEach", + scrollIntoView: "center", + readOnly: true +}, { + name: "unfold", + bindKey: bindKey("Alt-Shift-L|Ctrl-Shift-F1", "Command-Alt-Shift-L|Command-Shift-F1"), + exec: function(editor) { editor.session.toggleFold(true); }, + multiSelectAction: "forEach", + scrollIntoView: "center", + readOnly: true +}, { + name: "toggleFoldWidget", + bindKey: bindKey("F2", "F2"), + exec: function(editor) { editor.session.toggleFoldWidget(); }, + multiSelectAction: "forEach", + scrollIntoView: "center", + readOnly: true +}, { + name: "toggleParentFoldWidget", + bindKey: bindKey("Alt-F2", "Alt-F2"), + exec: function(editor) { editor.session.toggleFoldWidget(true); }, + multiSelectAction: "forEach", + scrollIntoView: "center", + readOnly: true +}, { + name: "foldall", + bindKey: bindKey("Ctrl-Alt-0", "Ctrl-Command-Option-0"), + exec: function(editor) { editor.session.foldAll(); }, + scrollIntoView: "center", + readOnly: true +}, { + name: "foldOther", + bindKey: bindKey("Alt-0", "Command-Option-0"), + exec: function(editor) { + editor.session.foldAll(); + editor.session.unfold(editor.selection.getAllRanges()); + }, + scrollIntoView: "center", + readOnly: true +}, { + name: "unfoldall", + bindKey: bindKey("Alt-Shift-0", "Command-Option-Shift-0"), + exec: function(editor) { editor.session.unfold(); }, + scrollIntoView: "center", + readOnly: true +}, { + name: "findnext", + bindKey: bindKey("Ctrl-K", "Command-G"), + exec: function(editor) { editor.findNext(); }, + multiSelectAction: "forEach", + scrollIntoView: "center", + readOnly: true +}, { + name: "findprevious", + bindKey: bindKey("Ctrl-Shift-K", "Command-Shift-G"), + exec: function(editor) { editor.findPrevious(); }, + multiSelectAction: "forEach", + scrollIntoView: "center", + readOnly: true +}, { + name: "selectOrFindNext", + bindKey: bindKey("Alt-K", "Ctrl-G"), + exec: function(editor) { + if (editor.selection.isEmpty()) + editor.selection.selectWord(); + else + editor.findNext(); + }, + readOnly: true +}, { + name: "selectOrFindPrevious", + bindKey: bindKey("Alt-Shift-K", "Ctrl-Shift-G"), + exec: function(editor) { + if (editor.selection.isEmpty()) + editor.selection.selectWord(); + else + editor.findPrevious(); + }, + readOnly: true +}, { + name: "find", + bindKey: bindKey("Ctrl-F", "Command-F"), + exec: function(editor) { + config.loadModule("ace/ext/searchbox", function(e) {e.Search(editor)}); + }, + readOnly: true +}, { + name: "overwrite", + bindKey: "Insert", + exec: function(editor) { editor.toggleOverwrite(); }, + readOnly: true +}, { + name: "selecttostart", + bindKey: bindKey("Ctrl-Shift-Home", "Command-Shift-Up"), + exec: function(editor) { editor.getSelection().selectFileStart(); }, + multiSelectAction: "forEach", + readOnly: true, + scrollIntoView: "animate", + aceCommandGroup: "fileJump" +}, { + name: "gotostart", + bindKey: bindKey("Ctrl-Home", "Command-Home|Command-Up"), + exec: function(editor) { editor.navigateFileStart(); }, + multiSelectAction: "forEach", + readOnly: true, + scrollIntoView: "animate", + aceCommandGroup: "fileJump" +}, { + name: "selectup", + bindKey: bindKey("Shift-Up", "Shift-Up"), + exec: function(editor) { editor.getSelection().selectUp(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}, { + name: "golineup", + bindKey: bindKey("Up", "Up|Ctrl-P"), + exec: function(editor, args) { editor.navigateUp(args.times); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}, { + name: "selecttoend", + bindKey: bindKey("Ctrl-Shift-End", "Command-Shift-Down"), + exec: function(editor) { editor.getSelection().selectFileEnd(); }, + multiSelectAction: "forEach", + readOnly: true, + scrollIntoView: "animate", + aceCommandGroup: "fileJump" +}, { + name: "gotoend", + bindKey: bindKey("Ctrl-End", "Command-End|Command-Down"), + exec: function(editor) { editor.navigateFileEnd(); }, + multiSelectAction: "forEach", + readOnly: true, + scrollIntoView: "animate", + aceCommandGroup: "fileJump" +}, { + name: "selectdown", + bindKey: bindKey("Shift-Down", "Shift-Down"), + exec: function(editor) { editor.getSelection().selectDown(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}, { + name: "golinedown", + bindKey: bindKey("Down", "Down|Ctrl-N"), + exec: function(editor, args) { editor.navigateDown(args.times); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}, { + name: "selectwordleft", + bindKey: bindKey("Ctrl-Shift-Left", "Option-Shift-Left"), + exec: function(editor) { editor.getSelection().selectWordLeft(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}, { + name: "gotowordleft", + bindKey: bindKey("Ctrl-Left", "Option-Left"), + exec: function(editor) { editor.navigateWordLeft(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}, { + name: "selecttolinestart", + bindKey: bindKey("Alt-Shift-Left", "Command-Shift-Left"), + exec: function(editor) { editor.getSelection().selectLineStart(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}, { + name: "gotolinestart", + bindKey: bindKey("Alt-Left|Home", "Command-Left|Home|Ctrl-A"), + exec: function(editor) { editor.navigateLineStart(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}, { + name: "selectleft", + bindKey: bindKey("Shift-Left", "Shift-Left"), + exec: function(editor) { editor.getSelection().selectLeft(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}, { + name: "gotoleft", + bindKey: bindKey("Left", "Left|Ctrl-B"), + exec: function(editor, args) { editor.navigateLeft(args.times); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}, { + name: "selectwordright", + bindKey: bindKey("Ctrl-Shift-Right", "Option-Shift-Right"), + exec: function(editor) { editor.getSelection().selectWordRight(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}, { + name: "gotowordright", + bindKey: bindKey("Ctrl-Right", "Option-Right"), + exec: function(editor) { editor.navigateWordRight(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}, { + name: "selecttolineend", + bindKey: bindKey("Alt-Shift-Right", "Command-Shift-Right"), + exec: function(editor) { editor.getSelection().selectLineEnd(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}, { + name: "gotolineend", + bindKey: bindKey("Alt-Right|End", "Command-Right|End|Ctrl-E"), + exec: function(editor) { editor.navigateLineEnd(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}, { + name: "selectright", + bindKey: bindKey("Shift-Right", "Shift-Right"), + exec: function(editor) { editor.getSelection().selectRight(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}, { + name: "gotoright", + bindKey: bindKey("Right", "Right|Ctrl-F"), + exec: function(editor, args) { editor.navigateRight(args.times); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}, { + name: "selectpagedown", + bindKey: "Shift-PageDown", + exec: function(editor) { editor.selectPageDown(); }, + readOnly: true +}, { + name: "pagedown", + bindKey: bindKey(null, "Option-PageDown"), + exec: function(editor) { editor.scrollPageDown(); }, + readOnly: true +}, { + name: "gotopagedown", + bindKey: bindKey("PageDown", "PageDown|Ctrl-V"), + exec: function(editor) { editor.gotoPageDown(); }, + readOnly: true +}, { + name: "selectpageup", + bindKey: "Shift-PageUp", + exec: function(editor) { editor.selectPageUp(); }, + readOnly: true +}, { + name: "pageup", + bindKey: bindKey(null, "Option-PageUp"), + exec: function(editor) { editor.scrollPageUp(); }, + readOnly: true +}, { + name: "gotopageup", + bindKey: "PageUp", + exec: function(editor) { editor.gotoPageUp(); }, + readOnly: true +}, { + name: "scrollup", + bindKey: bindKey("Ctrl-Up", null), + exec: function(e) { e.renderer.scrollBy(0, -2 * e.renderer.layerConfig.lineHeight); }, + readOnly: true +}, { + name: "scrolldown", + bindKey: bindKey("Ctrl-Down", null), + exec: function(e) { e.renderer.scrollBy(0, 2 * e.renderer.layerConfig.lineHeight); }, + readOnly: true +}, { + name: "selectlinestart", + bindKey: "Shift-Home", + exec: function(editor) { editor.getSelection().selectLineStart(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}, { + name: "selectlineend", + bindKey: "Shift-End", + exec: function(editor) { editor.getSelection().selectLineEnd(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}, { + name: "togglerecording", + bindKey: bindKey("Ctrl-Alt-E", "Command-Option-E"), + exec: function(editor) { editor.commands.toggleRecording(editor); }, + readOnly: true +}, { + name: "replaymacro", + bindKey: bindKey("Ctrl-Shift-E", "Command-Shift-E"), + exec: function(editor) { editor.commands.replay(editor); }, + readOnly: true +}, { + name: "jumptomatching", + bindKey: bindKey("Ctrl-P", "Ctrl-P"), + exec: function(editor) { editor.jumpToMatching(); }, + multiSelectAction: "forEach", + scrollIntoView: "animate", + readOnly: true +}, { + name: "selecttomatching", + bindKey: bindKey("Ctrl-Shift-P", "Ctrl-Shift-P"), + exec: function(editor) { editor.jumpToMatching(true); }, + multiSelectAction: "forEach", + scrollIntoView: "animate", + readOnly: true +}, { + name: "expandToMatching", + bindKey: bindKey("Ctrl-Shift-M", "Ctrl-Shift-M"), + exec: function(editor) { editor.jumpToMatching(true, true); }, + multiSelectAction: "forEach", + scrollIntoView: "animate", + readOnly: true +}, { + name: "passKeysToBrowser", + bindKey: bindKey(null, null), + exec: function() {}, + passEvent: true, + readOnly: true +}, + +// commands disabled in readOnly mode +{ + name: "cut", + exec: function(editor) { + var range = editor.getSelectionRange(); + editor._emit("cut", range); + + if (!editor.selection.isEmpty()) { + editor.session.remove(range); + editor.clearSelection(); + } + }, + scrollIntoView: "cursor", + multiSelectAction: "forEach" +}, { + name: "removeline", + bindKey: bindKey("Ctrl-D", "Command-D"), + exec: function(editor) { editor.removeLines(); }, + scrollIntoView: "cursor", + multiSelectAction: "forEachLine" +}, { + name: "duplicateSelection", + bindKey: bindKey("Ctrl-Shift-D", "Command-Shift-D"), + exec: function(editor) { editor.duplicateSelection(); }, + scrollIntoView: "cursor", + multiSelectAction: "forEach" +}, { + name: "sortlines", + bindKey: bindKey("Ctrl-Alt-S", "Command-Alt-S"), + exec: function(editor) { editor.sortLines(); }, + scrollIntoView: "selection", + multiSelectAction: "forEachLine" +}, { + name: "togglecomment", + bindKey: bindKey("Ctrl-/", "Command-/"), + exec: function(editor) { editor.toggleCommentLines(); }, + multiSelectAction: "forEachLine", + scrollIntoView: "selectionPart" +}, { + name: "toggleBlockComment", + bindKey: bindKey("Ctrl-Shift-/", "Command-Shift-/"), + exec: function(editor) { editor.toggleBlockComment(); }, + multiSelectAction: "forEach", + scrollIntoView: "selectionPart" +}, { + name: "modifyNumberUp", + bindKey: bindKey("Ctrl-Shift-Up", "Alt-Shift-Up"), + exec: function(editor) { editor.modifyNumber(1); }, + scrollIntoView: "cursor", + multiSelectAction: "forEach" +}, { + name: "modifyNumberDown", + bindKey: bindKey("Ctrl-Shift-Down", "Alt-Shift-Down"), + exec: function(editor) { editor.modifyNumber(-1); }, + scrollIntoView: "cursor", + multiSelectAction: "forEach" +}, { + name: "replace", + bindKey: bindKey("Ctrl-H", "Command-Option-F"), + exec: function(editor) { + config.loadModule("ace/ext/searchbox", function(e) {e.Search(editor, true)}); + } +}, { + name: "undo", + bindKey: bindKey("Ctrl-Z", "Command-Z"), + exec: function(editor) { editor.undo(); } +}, { + name: "redo", + bindKey: bindKey("Ctrl-Shift-Z|Ctrl-Y", "Command-Shift-Z|Command-Y"), + exec: function(editor) { editor.redo(); } +}, { + name: "copylinesup", + bindKey: bindKey("Alt-Shift-Up", "Command-Option-Up"), + exec: function(editor) { editor.copyLinesUp(); }, + scrollIntoView: "cursor" +}, { + name: "movelinesup", + bindKey: bindKey("Alt-Up", "Option-Up"), + exec: function(editor) { editor.moveLinesUp(); }, + scrollIntoView: "cursor" +}, { + name: "copylinesdown", + bindKey: bindKey("Alt-Shift-Down", "Command-Option-Down"), + exec: function(editor) { editor.copyLinesDown(); }, + scrollIntoView: "cursor" +}, { + name: "movelinesdown", + bindKey: bindKey("Alt-Down", "Option-Down"), + exec: function(editor) { editor.moveLinesDown(); }, + scrollIntoView: "cursor" +}, { + name: "del", + bindKey: bindKey("Delete", "Delete|Ctrl-D|Shift-Delete"), + exec: function(editor) { editor.remove("right"); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor" +}, { + name: "backspace", + bindKey: bindKey( + "Shift-Backspace|Backspace", + "Ctrl-Backspace|Shift-Backspace|Backspace|Ctrl-H" + ), + exec: function(editor) { editor.remove("left"); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor" +}, { + name: "cut_or_delete", + bindKey: bindKey("Shift-Delete", null), + exec: function(editor) { + if (editor.selection.isEmpty()) { + editor.remove("left"); + } else { + return false; + } + }, + multiSelectAction: "forEach", + scrollIntoView: "cursor" +}, { + name: "removetolinestart", + bindKey: bindKey("Alt-Backspace", "Command-Backspace"), + exec: function(editor) { editor.removeToLineStart(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor" +}, { + name: "removetolineend", + bindKey: bindKey("Alt-Delete", "Ctrl-K"), + exec: function(editor) { editor.removeToLineEnd(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor" +}, { + name: "removewordleft", + bindKey: bindKey("Ctrl-Backspace", "Alt-Backspace|Ctrl-Alt-Backspace"), + exec: function(editor) { editor.removeWordLeft(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor" +}, { + name: "removewordright", + bindKey: bindKey("Ctrl-Delete", "Alt-Delete"), + exec: function(editor) { editor.removeWordRight(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor" +}, { + name: "outdent", + bindKey: bindKey("Shift-Tab", "Shift-Tab"), + exec: function(editor) { editor.blockOutdent(); }, + multiSelectAction: "forEach", + scrollIntoView: "selectionPart" +}, { + name: "indent", + bindKey: bindKey("Tab", "Tab"), + exec: function(editor) { editor.indent(); }, + multiSelectAction: "forEach", + scrollIntoView: "selectionPart" +}, { + name: "blockoutdent", + bindKey: bindKey("Ctrl-[", "Ctrl-["), + exec: function(editor) { editor.blockOutdent(); }, + multiSelectAction: "forEachLine", + scrollIntoView: "selectionPart" +}, { + name: "blockindent", + bindKey: bindKey("Ctrl-]", "Ctrl-]"), + exec: function(editor) { editor.blockIndent(); }, + multiSelectAction: "forEachLine", + scrollIntoView: "selectionPart" +}, { + name: "insertstring", + exec: function(editor, str) { editor.insert(str); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor" +}, { + name: "inserttext", + exec: function(editor, args) { + editor.insert(lang.stringRepeat(args.text || "", args.times || 1)); + }, + multiSelectAction: "forEach", + scrollIntoView: "cursor" +}, { + name: "splitline", + bindKey: bindKey(null, "Ctrl-O"), + exec: function(editor) { editor.splitLine(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor" +}, { + name: "transposeletters", + bindKey: bindKey("Ctrl-T", "Ctrl-T"), + exec: function(editor) { editor.transposeLetters(); }, + multiSelectAction: function(editor) {editor.transposeSelections(1); }, + scrollIntoView: "cursor" +}, { + name: "touppercase", + bindKey: bindKey("Ctrl-U", "Ctrl-U"), + exec: function(editor) { editor.toUpperCase(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor" +}, { + name: "tolowercase", + bindKey: bindKey("Ctrl-Shift-U", "Ctrl-Shift-U"), + exec: function(editor) { editor.toLowerCase(); }, + multiSelectAction: "forEach", + scrollIntoView: "cursor" +}, { + name: "expandtoline", + bindKey: bindKey("Ctrl-Shift-L", "Command-Shift-L"), + exec: function(editor) { + var range = editor.selection.getRange(); + + range.start.column = range.end.column = 0; + range.end.row++; + editor.selection.setRange(range, false); + }, + multiSelectAction: "forEach", + scrollIntoView: "cursor", + readOnly: true +}, { + name: "joinlines", + bindKey: bindKey(null, null), + exec: function(editor) { + var isBackwards = editor.selection.isBackwards(); + var selectionStart = isBackwards ? editor.selection.getSelectionLead() : editor.selection.getSelectionAnchor(); + var selectionEnd = isBackwards ? editor.selection.getSelectionAnchor() : editor.selection.getSelectionLead(); + var firstLineEndCol = editor.session.doc.getLine(selectionStart.row).length; + var selectedText = editor.session.doc.getTextRange(editor.selection.getRange()); + var selectedCount = selectedText.replace(/\n\s*/, " ").length; + var insertLine = editor.session.doc.getLine(selectionStart.row); + + for (var i = selectionStart.row + 1; i <= selectionEnd.row + 1; i++) { + var curLine = lang.stringTrimLeft(lang.stringTrimRight(editor.session.doc.getLine(i))); + if (curLine.length !== 0) { + curLine = " " + curLine; + } + insertLine += curLine; + } + + if (selectionEnd.row + 1 < (editor.session.doc.getLength() - 1)) { + // Don't insert a newline at the end of the document + insertLine += editor.session.doc.getNewLineCharacter(); + } + + editor.clearSelection(); + editor.session.doc.replace(new Range(selectionStart.row, 0, selectionEnd.row + 2, 0), insertLine); + + if (selectedCount > 0) { + // Select the text that was previously selected + editor.selection.moveCursorTo(selectionStart.row, selectionStart.column); + editor.selection.selectTo(selectionStart.row, selectionStart.column + selectedCount); + } else { + // If the joined line had something in it, start the cursor at that something + firstLineEndCol = editor.session.doc.getLine(selectionStart.row).length > firstLineEndCol ? (firstLineEndCol + 1) : firstLineEndCol; + editor.selection.moveCursorTo(selectionStart.row, firstLineEndCol); + } + }, + multiSelectAction: "forEach", + readOnly: true +}, { + name: "invertSelection", + bindKey: bindKey(null, null), + exec: function(editor) { + var endRow = editor.session.doc.getLength() - 1; + var endCol = editor.session.doc.getLine(endRow).length; + var ranges = editor.selection.rangeList.ranges; + var newRanges = []; + + // If multiple selections don't exist, rangeList will return 0 so replace with single range + if (ranges.length < 1) { + ranges = [editor.selection.getRange()]; + } + + for (var i = 0; i < ranges.length; i++) { + if (i == (ranges.length - 1)) { + // The last selection must connect to the end of the document, unless it already does + if (!(ranges[i].end.row === endRow && ranges[i].end.column === endCol)) { + newRanges.push(new Range(ranges[i].end.row, ranges[i].end.column, endRow, endCol)); + } + } + + if (i === 0) { + // The first selection must connect to the start of the document, unless it already does + if (!(ranges[i].start.row === 0 && ranges[i].start.column === 0)) { + newRanges.push(new Range(0, 0, ranges[i].start.row, ranges[i].start.column)); + } + } else { + newRanges.push(new Range(ranges[i-1].end.row, ranges[i-1].end.column, ranges[i].start.row, ranges[i].start.column)); + } + } + + editor.exitMultiSelectMode(); + editor.clearSelection(); + + for(var i = 0; i < newRanges.length; i++) { + editor.selection.addRange(newRanges[i], false); + } + }, + readOnly: true, + scrollIntoView: "none" +}]; + +}); diff --git a/node_modules/ace/lib/ace/commands/incremental_search_commands.js b/node_modules/ace/lib/ace/commands/incremental_search_commands.js new file mode 100644 index 00000000..a0a0fe5f --- /dev/null +++ b/node_modules/ace/lib/ace/commands/incremental_search_commands.js @@ -0,0 +1,232 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + +var config = require("../config"); +var oop = require("../lib/oop"); +var HashHandler = require("../keyboard/hash_handler").HashHandler; +var occurStartCommand = require("./occur_commands").occurStartCommand; + +// These commands can be installed in a normal key handler to start iSearch: +exports.iSearchStartCommands = [{ + name: "iSearch", + bindKey: {win: "Ctrl-F", mac: "Command-F"}, + exec: function(editor, options) { + config.loadModule(["core", "ace/incremental_search"], function(e) { + var iSearch = e.iSearch = e.iSearch || new e.IncrementalSearch(); + iSearch.activate(editor, options.backwards); + if (options.jumpToFirstMatch) iSearch.next(options); + }); + }, + readOnly: true +}, { + name: "iSearchBackwards", + exec: function(editor, jumpToNext) { editor.execCommand('iSearch', {backwards: true}); }, + readOnly: true +}, { + name: "iSearchAndGo", + bindKey: {win: "Ctrl-K", mac: "Command-G"}, + exec: function(editor, jumpToNext) { editor.execCommand('iSearch', {jumpToFirstMatch: true, useCurrentOrPrevSearch: true}); }, + readOnly: true +}, { + name: "iSearchBackwardsAndGo", + bindKey: {win: "Ctrl-Shift-K", mac: "Command-Shift-G"}, + exec: function(editor) { editor.execCommand('iSearch', {jumpToFirstMatch: true, backwards: true, useCurrentOrPrevSearch: true}); }, + readOnly: true +}]; + +// These commands are only available when incremental search mode is active: +exports.iSearchCommands = [{ + name: "restartSearch", + bindKey: {win: "Ctrl-F", mac: "Command-F"}, + exec: function(iSearch) { + iSearch.cancelSearch(true); + }, + readOnly: true, + isIncrementalSearchCommand: true +}, { + name: "searchForward", + bindKey: {win: "Ctrl-S|Ctrl-K", mac: "Ctrl-S|Command-G"}, + exec: function(iSearch, options) { + options.useCurrentOrPrevSearch = true; + iSearch.next(options); + }, + readOnly: true, + isIncrementalSearchCommand: true +}, { + name: "searchBackward", + bindKey: {win: "Ctrl-R|Ctrl-Shift-K", mac: "Ctrl-R|Command-Shift-G"}, + exec: function(iSearch, options) { + options.useCurrentOrPrevSearch = true; + options.backwards = true; + iSearch.next(options); + }, + readOnly: true, + isIncrementalSearchCommand: true +}, { + name: "extendSearchTerm", + exec: function(iSearch, string) { + iSearch.addString(string); + }, + readOnly: true, + isIncrementalSearchCommand: true +}, { + name: "extendSearchTermSpace", + bindKey: "space", + exec: function(iSearch) { iSearch.addString(' '); }, + readOnly: true, + isIncrementalSearchCommand: true +}, { + name: "shrinkSearchTerm", + bindKey: "backspace", + exec: function(iSearch) { + iSearch.removeChar(); + }, + readOnly: true, + isIncrementalSearchCommand: true +}, { + name: 'confirmSearch', + bindKey: 'return', + exec: function(iSearch) { iSearch.deactivate(); }, + readOnly: true, + isIncrementalSearchCommand: true +}, { + name: 'cancelSearch', + bindKey: 'esc|Ctrl-G', + exec: function(iSearch) { iSearch.deactivate(true); }, + readOnly: true, + isIncrementalSearchCommand: true +}, { + name: 'occurisearch', + bindKey: 'Ctrl-O', + exec: function(iSearch) { + var options = oop.mixin({}, iSearch.$options); + iSearch.deactivate(); + occurStartCommand.exec(iSearch.$editor, options); + }, + readOnly: true, + isIncrementalSearchCommand: true +}, { + name: "yankNextWord", + bindKey: "Ctrl-w", + exec: function(iSearch) { + var ed = iSearch.$editor, + range = ed.selection.getRangeOfMovements(function(sel) { sel.moveCursorWordRight(); }), + string = ed.session.getTextRange(range); + iSearch.addString(string); + }, + readOnly: true, + isIncrementalSearchCommand: true +}, { + name: "yankNextChar", + bindKey: "Ctrl-Alt-y", + exec: function(iSearch) { + var ed = iSearch.$editor, + range = ed.selection.getRangeOfMovements(function(sel) { sel.moveCursorRight(); }), + string = ed.session.getTextRange(range); + iSearch.addString(string); + }, + readOnly: true, + isIncrementalSearchCommand: true +}, { + name: 'recenterTopBottom', + bindKey: 'Ctrl-l', + exec: function(iSearch) { iSearch.$editor.execCommand('recenterTopBottom'); }, + readOnly: true, + isIncrementalSearchCommand: true +}, { + name: 'selectAllMatches', + bindKey: 'Ctrl-space', + exec: function(iSearch) { + var ed = iSearch.$editor, + hl = ed.session.$isearchHighlight, + ranges = hl && hl.cache ? hl.cache + .reduce(function(ranges, ea) { + return ranges.concat(ea ? ea : []); }, []) : []; + iSearch.deactivate(false); + ranges.forEach(ed.selection.addRange.bind(ed.selection)); + }, + readOnly: true, + isIncrementalSearchCommand: true +}, { + name: 'searchAsRegExp', + bindKey: 'Alt-r', + exec: function(iSearch) { + iSearch.convertNeedleToRegExp(); + }, + readOnly: true, + isIncrementalSearchCommand: true +}]; + +function IncrementalSearchKeyboardHandler(iSearch) { + this.$iSearch = iSearch; +} + +oop.inherits(IncrementalSearchKeyboardHandler, HashHandler); + +;(function() { + + this.attach = function(editor) { + var iSearch = this.$iSearch; + HashHandler.call(this, exports.iSearchCommands, editor.commands.platform); + this.$commandExecHandler = editor.commands.addEventListener('exec', function(e) { + if (!e.command.isIncrementalSearchCommand) return undefined; + e.stopPropagation(); + e.preventDefault(); + return e.command.exec(iSearch, e.args || {}); + }); + } + + this.detach = function(editor) { + if (!this.$commandExecHandler) return; + editor.commands.removeEventListener('exec', this.$commandExecHandler); + delete this.$commandExecHandler; + } + + var handleKeyboard$super = this.handleKeyboard; + this.handleKeyboard = function(data, hashId, key, keyCode) { + if (((hashId === 1/*ctrl*/ || hashId === 8/*command*/) && key === 'v') + || (hashId === 1/*ctrl*/ && key === 'y')) return null; + var cmd = handleKeyboard$super.call(this, data, hashId, key, keyCode); + if (cmd.command) { return cmd; } + if (hashId == -1) { + var extendCmd = this.commands.extendSearchTerm; + if (extendCmd) { return {command: extendCmd, args: key}; } + } + return {command: "null", passEvent: hashId == 0 || hashId == 4}; + } + +}).call(IncrementalSearchKeyboardHandler.prototype); + + +exports.IncrementalSearchKeyboardHandler = IncrementalSearchKeyboardHandler; + +}); diff --git a/node_modules/ace/lib/ace/commands/multi_select_commands.js b/node_modules/ace/lib/ace/commands/multi_select_commands.js new file mode 100644 index 00000000..ba6392bc --- /dev/null +++ b/node_modules/ace/lib/ace/commands/multi_select_commands.js @@ -0,0 +1,113 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + +// commands to enter multiselect mode +exports.defaultCommands = [{ + name: "addCursorAbove", + exec: function(editor) { editor.selectMoreLines(-1); }, + bindKey: {win: "Ctrl-Alt-Up", mac: "Ctrl-Alt-Up"}, + scrollIntoView: "cursor", + readonly: true +}, { + name: "addCursorBelow", + exec: function(editor) { editor.selectMoreLines(1); }, + bindKey: {win: "Ctrl-Alt-Down", mac: "Ctrl-Alt-Down"}, + scrollIntoView: "cursor", + readonly: true +}, { + name: "addCursorAboveSkipCurrent", + exec: function(editor) { editor.selectMoreLines(-1, true); }, + bindKey: {win: "Ctrl-Alt-Shift-Up", mac: "Ctrl-Alt-Shift-Up"}, + scrollIntoView: "cursor", + readonly: true +}, { + name: "addCursorBelowSkipCurrent", + exec: function(editor) { editor.selectMoreLines(1, true); }, + bindKey: {win: "Ctrl-Alt-Shift-Down", mac: "Ctrl-Alt-Shift-Down"}, + scrollIntoView: "cursor", + readonly: true +}, { + name: "selectMoreBefore", + exec: function(editor) { editor.selectMore(-1); }, + bindKey: {win: "Ctrl-Alt-Left", mac: "Ctrl-Alt-Left"}, + scrollIntoView: "cursor", + readonly: true +}, { + name: "selectMoreAfter", + exec: function(editor) { editor.selectMore(1); }, + bindKey: {win: "Ctrl-Alt-Right", mac: "Ctrl-Alt-Right"}, + scrollIntoView: "cursor", + readonly: true +}, { + name: "selectNextBefore", + exec: function(editor) { editor.selectMore(-1, true); }, + bindKey: {win: "Ctrl-Alt-Shift-Left", mac: "Ctrl-Alt-Shift-Left"}, + scrollIntoView: "cursor", + readonly: true +}, { + name: "selectNextAfter", + exec: function(editor) { editor.selectMore(1, true); }, + bindKey: {win: "Ctrl-Alt-Shift-Right", mac: "Ctrl-Alt-Shift-Right"}, + scrollIntoView: "cursor", + readonly: true +}, { + name: "splitIntoLines", + exec: function(editor) { editor.multiSelect.splitIntoLines(); }, + bindKey: {win: "Ctrl-Alt-L", mac: "Ctrl-Alt-L"}, + readonly: true +}, { + name: "alignCursors", + exec: function(editor) { editor.alignCursors(); }, + bindKey: {win: "Ctrl-Alt-A", mac: "Ctrl-Alt-A"}, + scrollIntoView: "cursor" +}, { + name: "findAll", + exec: function(editor) { editor.findAll(); }, + bindKey: {win: "Ctrl-Alt-K", mac: "Ctrl-Alt-G"}, + scrollIntoView: "cursor", + readonly: true +}]; + +// commands active only in multiselect mode +exports.multiSelectCommands = [{ + name: "singleSelection", + bindKey: "esc", + exec: function(editor) { editor.exitMultiSelectMode(); }, + scrollIntoView: "cursor", + readonly: true, + isAvailable: function(editor) {return editor && editor.inMultiSelectMode} +}]; + +var HashHandler = require("../keyboard/hash_handler").HashHandler; +exports.keyboardHandler = new HashHandler(exports.multiSelectCommands); + +}); diff --git a/node_modules/ace/lib/ace/commands/occur_commands.js b/node_modules/ace/lib/ace/commands/occur_commands.js new file mode 100644 index 00000000..b45fbf61 --- /dev/null +++ b/node_modules/ace/lib/ace/commands/occur_commands.js @@ -0,0 +1,110 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + +var config = require("../config"), + Occur = require("../occur").Occur; + +// These commands can be installed in a normal command handler to start occur: +var occurStartCommand = { + name: "occur", + exec: function(editor, options) { + var alreadyInOccur = !!editor.session.$occur; + var occurSessionActive = new Occur().enter(editor, options); + if (occurSessionActive && !alreadyInOccur) + OccurKeyboardHandler.installIn(editor); + }, + readOnly: true +}; + +var occurCommands = [{ + name: "occurexit", + bindKey: 'esc|Ctrl-G', + exec: function(editor) { + var occur = editor.session.$occur; + if (!occur) return; + occur.exit(editor, {}); + if (!editor.session.$occur) OccurKeyboardHandler.uninstallFrom(editor); + }, + readOnly: true +}, { + name: "occuraccept", + bindKey: 'enter', + exec: function(editor) { + var occur = editor.session.$occur; + if (!occur) return; + occur.exit(editor, {translatePosition: true}); + if (!editor.session.$occur) OccurKeyboardHandler.uninstallFrom(editor); + }, + readOnly: true +}]; + +var HashHandler = require("../keyboard/hash_handler").HashHandler; +var oop = require("../lib/oop"); + + +function OccurKeyboardHandler() {} + +oop.inherits(OccurKeyboardHandler, HashHandler); + +;(function() { + + this.isOccurHandler = true; + + this.attach = function(editor) { + HashHandler.call(this, occurCommands, editor.commands.platform); + this.$editor = editor; + } + + var handleKeyboard$super = this.handleKeyboard; + this.handleKeyboard = function(data, hashId, key, keyCode) { + var cmd = handleKeyboard$super.call(this, data, hashId, key, keyCode); + return (cmd && cmd.command) ? cmd : undefined; + } + +}).call(OccurKeyboardHandler.prototype); + +OccurKeyboardHandler.installIn = function(editor) { + var handler = new this(); + editor.keyBinding.addKeyboardHandler(handler); + editor.commands.addCommands(occurCommands); +} + +OccurKeyboardHandler.uninstallFrom = function(editor) { + editor.commands.removeCommands(occurCommands); + var handler = editor.getKeyboardHandler(); + if (handler.isOccurHandler) + editor.keyBinding.removeKeyboardHandler(handler); +} + +exports.occurStartCommand = occurStartCommand; + +}); diff --git a/node_modules/ace/lib/ace/config.js b/node_modules/ace/lib/ace/config.js new file mode 100644 index 00000000..34bf50fd --- /dev/null +++ b/node_modules/ace/lib/ace/config.js @@ -0,0 +1,202 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"no use strict"; + +var lang = require("./lib/lang"); +var oop = require("./lib/oop"); +var net = require("./lib/net"); +var AppConfig = require("./lib/app_config").AppConfig; + +module.exports = exports = new AppConfig(); + +var global = (function() { + return this; +})(); + +var options = { + packaged: false, + workerPath: null, + modePath: null, + themePath: null, + basePath: "", + suffix: ".js", + $moduleUrls: {} +}; + +exports.get = function(key) { + if (!options.hasOwnProperty(key)) + throw new Error("Unknown config key: " + key); + + return options[key]; +}; + +exports.set = function(key, value) { + if (!options.hasOwnProperty(key)) + throw new Error("Unknown config key: " + key); + + options[key] = value; +}; + +exports.all = function() { + return lang.copyObject(options); +}; + +// module loading +exports.moduleUrl = function(name, component) { + if (options.$moduleUrls[name]) + return options.$moduleUrls[name]; + + var parts = name.split("/"); + component = component || parts[parts.length - 2] || ""; + + // todo make this configurable or get rid of '-' + var sep = component == "snippets" ? "/" : "-"; + var base = parts[parts.length - 1]; + if (component == "worker" && sep == "-") { + var re = new RegExp("^" + component + "[\\-_]|[\\-_]" + component + "$", "g"); + base = base.replace(re, ""); + } + + if ((!base || base == component) && parts.length > 1) + base = parts[parts.length - 2]; + var path = options[component + "Path"]; + if (path == null) { + path = options.basePath; + } else if (sep == "/") { + component = sep = ""; + } + if (path && path.slice(-1) != "/") + path += "/"; + return path + component + sep + base + this.get("suffix"); +}; + +exports.setModuleUrl = function(name, subst) { + return options.$moduleUrls[name] = subst; +}; + +exports.$loading = {}; +exports.loadModule = function(moduleName, onLoad) { + var module, moduleType; + if (Array.isArray(moduleName)) { + moduleType = moduleName[0]; + moduleName = moduleName[1]; + } + + try { + module = require(moduleName); + } catch (e) {} + // require(moduleName) can return empty object if called after require([moduleName], callback) + if (module && !exports.$loading[moduleName]) + return onLoad && onLoad(module); + + if (!exports.$loading[moduleName]) + exports.$loading[moduleName] = []; + + exports.$loading[moduleName].push(onLoad); + + if (exports.$loading[moduleName].length > 1) + return; + + var afterLoad = function() { + require([moduleName], function(module) { + exports._emit("load.module", {name: moduleName, module: module}); + var listeners = exports.$loading[moduleName]; + exports.$loading[moduleName] = null; + listeners.forEach(function(onLoad) { + onLoad && onLoad(module); + }); + }); + }; + + if (!exports.get("packaged")) + return afterLoad(); + net.loadScript(exports.moduleUrl(moduleName, moduleType), afterLoad); +}; + +// initialization +function init(packaged) { + options.packaged = packaged || require.packaged || module.packaged || (global.define && define.packaged); + + if (!global.document) + return ""; + + var scriptOptions = {}; + var scriptUrl = ""; + + // Use currentScript.ownerDocument in case this file was loaded from imported document. (HTML Imports) + var currentScript = (document.currentScript || document._currentScript ); // native or polyfill + var currentDocument = currentScript && currentScript.ownerDocument || document; + + var scripts = currentDocument.getElementsByTagName("script"); + for (var i=0; i*-{@IKxT-e*Hm6e;L;i*OLTOK@PW z(cUAx#7p88gBpFzp_4YyZns0z>9j%hPvRGY8hy-Fqg(NK{QY1sD9z{d?~BFa2ZI`Y z%%PJq;dZ;7Xs3y)6iGS_ZBOgI>5vFcGxoaJ&kHv=tJJGU51D;~#PhO{v7iEBnR;cGM+2Mn~M(dZl340MK#*uV-C zw;3|<5vv~6#It6z>0!t~6{{ZTq(0Hh%gcSbg?H%srU=ZT^LRX`)oS&y)oKaB96Biz z^?Lo#<#OTW+Z2I0boAz*hr{8cPN#D$0(0o3Ow4Ap1N=+7-F}~Hiyrhbhi)>NJob9M zzDOi;)a&(pdeFxlI@zOq^ZNSwHN9j{mL28jV-6jlQ}s=)T~3zI@E|mjl2nm2yv(p1DzpN=@EsRWm-|FS*8_+8l0fTVo_mGi$V>3 zYGth!wJ6k3hWMh@q85c3m;m`qCc~LxWvD@zf%b1g4Z;kxW}${n=rV;k)Bv+kqs1iD ph!KYx#yr$8>rk@}HUCwp`3*kwRI8RHvCaSh002ovPDHLkV1gg!UI_pI literal 0 HcmV?d00001 diff --git a/node_modules/ace/lib/ace/css/editor.css b/node_modules/ace/lib/ace/css/editor.css new file mode 100644 index 00000000..574ab9ae --- /dev/null +++ b/node_modules/ace/lib/ace/css/editor.css @@ -0,0 +1,429 @@ +.ace_editor { + position: relative; + overflow: hidden; + font: 12px/normal 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace; + direction: ltr; +} + +.ace_scroller { + position: absolute; + overflow: hidden; + top: 0; + bottom: 0; + background-color: inherit; + -ms-user-select: none; + -moz-user-select: none; + -webkit-user-select: none; + user-select: none; + cursor: text; +} + +.ace_content { + position: absolute; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; + min-width: 100%; +} + +.ace_dragging .ace_scroller:before{ + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + content: ''; + background: rgba(250, 250, 250, 0.01); + z-index: 1000; +} +.ace_dragging.ace_dark .ace_scroller:before{ + background: rgba(0, 0, 0, 0.01); +} + +/*.ace_selecting, .ace_selecting * { + cursor: text !important; +}*/ + +.ace_gutter { + position: absolute; + overflow : hidden; + width: auto; + top: 0; + bottom: 0; + left: 0; + cursor: default; + z-index: 4; + -ms-user-select: none; + -moz-user-select: none; + -webkit-user-select: none; + user-select: none; +} + +.ace_gutter-active-line { + position: absolute; + left: 0; + right: 0; +} + +.ace_scroller.ace_scroll-left { + box-shadow: 17px 0 16px -16px rgba(0, 0, 0, 0.4) inset; +} + +.ace_gutter-cell { + padding-left: 19px; + padding-right: 6px; + background-repeat: no-repeat; +} + +.ace_gutter-cell.ace_error { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABOFBMVEX/////////QRswFAb/Ui4wFAYwFAYwFAaWGAfDRymzOSH/PxswFAb/SiUwFAYwFAbUPRvjQiDllog5HhHdRybsTi3/Tyv9Tir+Syj/UC3////XurebMBIwFAb/RSHbPx/gUzfdwL3kzMivKBAwFAbbvbnhPx66NhowFAYwFAaZJg8wFAaxKBDZurf/RB6mMxb/SCMwFAYwFAbxQB3+RB4wFAb/Qhy4Oh+4QifbNRcwFAYwFAYwFAb/QRzdNhgwFAYwFAbav7v/Uy7oaE68MBK5LxLewr/r2NXewLswFAaxJw4wFAbkPRy2PyYwFAaxKhLm1tMwFAazPiQwFAaUGAb/QBrfOx3bvrv/VC/maE4wFAbRPBq6MRO8Qynew8Dp2tjfwb0wFAbx6eju5+by6uns4uH9/f36+vr/GkHjAAAAYnRSTlMAGt+64rnWu/bo8eAA4InH3+DwoN7j4eLi4xP99Nfg4+b+/u9B/eDs1MD1mO7+4PHg2MXa347g7vDizMLN4eG+Pv7i5evs/v79yu7S3/DV7/498Yv24eH+4ufQ3Ozu/v7+y13sRqwAAADLSURBVHjaZc/XDsFgGIBhtDrshlitmk2IrbHFqL2pvXf/+78DPokj7+Fz9qpU/9UXJIlhmPaTaQ6QPaz0mm+5gwkgovcV6GZzd5JtCQwgsxoHOvJO15kleRLAnMgHFIESUEPmawB9ngmelTtipwwfASilxOLyiV5UVUyVAfbG0cCPHig+GBkzAENHS0AstVF6bacZIOzgLmxsHbt2OecNgJC83JERmePUYq8ARGkJx6XtFsdddBQgZE2nPR6CICZhawjA4Fb/chv+399kfR+MMMDGOQAAAABJRU5ErkJggg=="); + background-repeat: no-repeat; + background-position: 2px center; +} + +.ace_gutter-cell.ace_warning { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAmVBMVEX///8AAAD///8AAAAAAABPSzb/5sAAAAB/blH/73z/ulkAAAAAAAD85pkAAAAAAAACAgP/vGz/rkDerGbGrV7/pkQICAf////e0IsAAAD/oED/qTvhrnUAAAD/yHD/njcAAADuv2r/nz//oTj/p064oGf/zHAAAAA9Nir/tFIAAAD/tlTiuWf/tkIAAACynXEAAAAAAAAtIRW7zBpBAAAAM3RSTlMAABR1m7RXO8Ln31Z36zT+neXe5OzooRDfn+TZ4p3h2hTf4t3k3ucyrN1K5+Xaks52Sfs9CXgrAAAAjklEQVR42o3PbQ+CIBQFYEwboPhSYgoYunIqqLn6/z8uYdH8Vmdnu9vz4WwXgN/xTPRD2+sgOcZjsge/whXZgUaYYvT8QnuJaUrjrHUQreGczuEafQCO/SJTufTbroWsPgsllVhq3wJEk2jUSzX3CUEDJC84707djRc5MTAQxoLgupWRwW6UB5fS++NV8AbOZgnsC7BpEAAAAABJRU5ErkJggg=="); + background-position: 2px center; +} + +.ace_gutter-cell.ace_info { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAJ0Uk5TAAB2k804AAAAPklEQVQY02NgIB68QuO3tiLznjAwpKTgNyDbMegwisCHZUETUZV0ZqOquBpXj2rtnpSJT1AEnnRmL2OgGgAAIKkRQap2htgAAAAASUVORK5CYII="); + background-position: 2px center; +} +.ace_dark .ace_gutter-cell.ace_info { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAJFBMVEUAAAChoaGAgIAqKiq+vr6tra1ZWVmUlJSbm5s8PDxubm56enrdgzg3AAAAAXRSTlMAQObYZgAAAClJREFUeNpjYMAPdsMYHegyJZFQBlsUlMFVCWUYKkAZMxZAGdxlDMQBAG+TBP4B6RyJAAAAAElFTkSuQmCC"); +} + +.ace_scrollbar { + position: absolute; + right: 0; + bottom: 0; + z-index: 6; +} + +.ace_scrollbar-inner { + position: absolute; + cursor: text; + left: 0; + top: 0; +} + +.ace_scrollbar-v{ + overflow-x: hidden; + overflow-y: scroll; + top: 0; +} + +.ace_scrollbar-h { + overflow-x: scroll; + overflow-y: hidden; + left: 0; + top: auto!important; +} + +.ace_print-margin { + position: absolute; + height: 100%; +} + +.ace_text-input { + position: absolute; + z-index: 0; + width: 0.5em; + height: 1em; + opacity: 0; + background: transparent; + -moz-appearance: none; + appearance: none; + border: none; + resize: none; + outline: none; + overflow: hidden; + font: inherit; + padding: 0 1px; + margin: 0 -1px; + text-indent: -1em; + -ms-user-select: text; + -moz-user-select: text; + -webkit-user-select: text; + user-select: text; +} + +.ace_text-input.ace_composition { + background: inherit; + color: inherit; + z-index: 1000; + opacity: 1; + text-indent: 0; +} + +.ace_layer { + z-index: 1; + position: absolute; + overflow: hidden; + white-space: pre; + height: 100%; + width: 100%; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; + /* setting pointer-events: auto; on node under the mouse, which changes + during scroll, will break mouse wheel scrolling in Safari */ + pointer-events: none; +} + +.ace_gutter-layer { + position: relative; + width: auto; + text-align: right; + pointer-events: auto; +} + +.ace_text-layer { + font: inherit !important; +} + +.ace_cjk { + display: inline-block; + text-align: center; +} + +.ace_cursor-layer { + z-index: 4; +} + +.ace_cursor { + z-index: 4; + position: absolute; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; + border-left: 2px solid; + /* workaround for smooth cursor repaintng whole screen in chrome */ + transform: translatez(0); +} + +.ace_slim-cursors .ace_cursor { + border-left-width: 1px; +} + +.ace_overwrite-cursors .ace_cursor { + border-left-width: 0; + border-bottom: 1px solid; +} + +.ace_hidden-cursors .ace_cursor { + opacity: 0.2; +} + +.ace_smooth-blinking .ace_cursor { + -webkit-transition: opacity 0.18s; + transition: opacity 0.18s; +} + +.ace_editor.ace_multiselect .ace_cursor { + border-left-width: 1px; +} + +.ace_marker-layer .ace_step, .ace_marker-layer .ace_stack { + position: absolute; + z-index: 3; +} + +.ace_marker-layer .ace_selection { + position: absolute; + z-index: 5; +} + +.ace_marker-layer .ace_bracket { + position: absolute; + z-index: 6; +} + +.ace_marker-layer .ace_active-line { + position: absolute; + z-index: 2; +} + +.ace_marker-layer .ace_selected-word { + position: absolute; + z-index: 4; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + +.ace_line .ace_fold { + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; + + display: inline-block; + height: 11px; + margin-top: -2px; + vertical-align: middle; + + background-image: + url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJpJREFUeNpi/P//PwOlgAXGYGRklAVSokD8GmjwY1wasKljQpYACtpCFeADcHVQfQyMQAwzwAZI3wJKvCLkfKBaMSClBlR7BOQikCFGQEErIH0VqkabiGCAqwUadAzZJRxQr/0gwiXIal8zQQPnNVTgJ1TdawL0T5gBIP1MUJNhBv2HKoQHHjqNrA4WO4zY0glyNKLT2KIfIMAAQsdgGiXvgnYAAAAASUVORK5CYII="), + url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAA3CAYAAADNNiA5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACJJREFUeNpi+P//fxgTAwPDBxDxD078RSX+YeEyDFMCIMAAI3INmXiwf2YAAAAASUVORK5CYII="); + background-repeat: no-repeat, repeat-x; + background-position: center center, top left; + color: transparent; + + border: 1px solid black; + border-radius: 2px; + + cursor: pointer; + pointer-events: auto; +} + +.ace_dark .ace_fold { +} + +.ace_fold:hover{ + background-image: + url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJpJREFUeNpi/P//PwOlgAXGYGRklAVSokD8GmjwY1wasKljQpYACtpCFeADcHVQfQyMQAwzwAZI3wJKvCLkfKBaMSClBlR7BOQikCFGQEErIH0VqkabiGCAqwUadAzZJRxQr/0gwiXIal8zQQPnNVTgJ1TdawL0T5gBIP1MUJNhBv2HKoQHHjqNrA4WO4zY0glyNKLT2KIfIMAAQsdgGiXvgnYAAAAASUVORK5CYII="), + url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAA3CAYAAADNNiA5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACBJREFUeNpi+P//fz4TAwPDZxDxD5X4i5fLMEwJgAADAEPVDbjNw87ZAAAAAElFTkSuQmCC"); +} + +.ace_tooltip { + background-color: #FFF; + background-image: -webkit-linear-gradient(top, transparent, rgba(0, 0, 0, 0.1)); + background-image: linear-gradient(to bottom, transparent, rgba(0, 0, 0, 0.1)); + border: 1px solid gray; + border-radius: 1px; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3); + color: black; + max-width: 100%; + padding: 3px 4px; + position: fixed; + z-index: 999999; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; + cursor: default; + white-space: pre; + word-wrap: break-word; + line-height: normal; + font-style: normal; + font-weight: normal; + letter-spacing: normal; + pointer-events: none; +} + +.ace_folding-enabled > .ace_gutter-cell { + padding-right: 13px; +} + +.ace_fold-widget { + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; + + margin: 0 -12px 0 1px; + display: none; + width: 11px; + vertical-align: top; + + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAANElEQVR42mWKsQ0AMAzC8ixLlrzQjzmBiEjp0A6WwBCSPgKAXoLkqSot7nN3yMwR7pZ32NzpKkVoDBUxKAAAAABJRU5ErkJggg=="); + background-repeat: no-repeat; + background-position: center; + + border-radius: 3px; + + border: 1px solid transparent; + cursor: pointer; +} + +.ace_folding-enabled .ace_fold-widget { + display: inline-block; +} + +.ace_fold-widget.ace_end { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAANElEQVR42m3HwQkAMAhD0YzsRchFKI7sAikeWkrxwScEB0nh5e7KTPWimZki4tYfVbX+MNl4pyZXejUO1QAAAABJRU5ErkJggg=="); +} + +.ace_fold-widget.ace_closed { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAGCAYAAAAG5SQMAAAAOUlEQVR42jXKwQkAMAgDwKwqKD4EwQ26sSOkVWjgIIHAzPiCgaqiqnJHZnKICBERHN194O5b9vbLuAVRL+l0YWnZAAAAAElFTkSuQmCCXA=="); +} + +.ace_fold-widget:hover { + border: 1px solid rgba(0, 0, 0, 0.3); + background-color: rgba(255, 255, 255, 0.2); + box-shadow: 0 1px 1px rgba(255, 255, 255, 0.7); +} + +.ace_fold-widget:active { + border: 1px solid rgba(0, 0, 0, 0.4); + background-color: rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 1px rgba(255, 255, 255, 0.8); +} +/** + * Dark version for fold widgets + */ +.ace_dark .ace_fold-widget { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHklEQVQIW2P4//8/AzoGEQ7oGCaLLAhWiSwB146BAQCSTPYocqT0AAAAAElFTkSuQmCC"); +} +.ace_dark .ace_fold-widget.ace_end { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAH0lEQVQIW2P4//8/AxQ7wNjIAjDMgC4AxjCVKBirIAAF0kz2rlhxpAAAAABJRU5ErkJggg=="); +} +.ace_dark .ace_fold-widget.ace_closed { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAHElEQVQIW2P4//+/AxAzgDADlOOAznHAKgPWAwARji8UIDTfQQAAAABJRU5ErkJggg=="); +} +.ace_dark .ace_fold-widget:hover { + box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2); + background-color: rgba(255, 255, 255, 0.1); +} +.ace_dark .ace_fold-widget:active { + box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2); +} + +.ace_fold-widget.ace_invalid { + background-color: #FFB4B4; + border-color: #DE5555; +} + +.ace_fade-fold-widgets .ace_fold-widget { + -webkit-transition: opacity 0.4s ease 0.05s; + transition: opacity 0.4s ease 0.05s; + opacity: 0; +} + +.ace_fade-fold-widgets:hover .ace_fold-widget { + -webkit-transition: opacity 0.05s ease 0.05s; + transition: opacity 0.05s ease 0.05s; + opacity:1; +} + +.ace_underline { + text-decoration: underline; +} + +.ace_bold { + font-weight: bold; +} + +.ace_nobold .ace_bold { + font-weight: normal; +} + +.ace_italic { + font-style: italic; +} + + +.ace_error-marker { + background-color: rgba(255, 0, 0,0.2); + position: absolute; + z-index: 9; +} + +.ace_highlight-marker { + background-color: rgba(255, 255, 0,0.2); + position: absolute; + z-index: 8; +} +.ace_lineWidgetContainer { + z-index: 5; + position: absolute; +} diff --git a/node_modules/ace/lib/ace/css/expand-marker.png b/node_modules/ace/lib/ace/css/expand-marker.png new file mode 100644 index 0000000000000000000000000000000000000000..535e81922a6e8b6b047024171bca89149730c832 GIT binary patch literal 290 zcmeAS@N?(olHy`uVBq!ia0vp^3P5bh!3HG57i%sDQZGGS978H@y`6HJ>yUwf>u=@1 zY#$jHaV+ZCAtV^WB3Kyv<$w6rgPN^}mk4&16mz$?oHnuK^xU*br+VqTIh{}QCzbwQ z#1x(MbFxM9Gg0O2k3UQ29cYXAr*Lnob`1;br1jm literal 0 HcmV?d00001 diff --git a/node_modules/ace/lib/ace/document.js b/node_modules/ace/lib/ace/document.js new file mode 100644 index 00000000..7b3e6221 --- /dev/null +++ b/node_modules/ace/lib/ace/document.js @@ -0,0 +1,692 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("./lib/oop"); +var applyDelta = require("./apply_delta").applyDelta; +var EventEmitter = require("./lib/event_emitter").EventEmitter; +var Range = require("./range").Range; +var Anchor = require("./anchor").Anchor; + +/** + * Contains the text of the document. Document can be attached to several [[EditSession `EditSession`]]s. + * At its core, `Document`s are just an array of strings, with each row in the document matching up to the array index. + * + * @class Document + **/ + +/** + * + * Creates a new `Document`. If `text` is included, the `Document` contains those strings; otherwise, it's empty. + * @param {String | Array} text The starting text + * @constructor + **/ + +var Document = function(textOrLines) { + this.$lines = [""]; + + // There has to be one line at least in the document. If you pass an empty + // string to the insert function, nothing will happen. Workaround. + if (textOrLines.length === 0) { + this.$lines = [""]; + } else if (Array.isArray(textOrLines)) { + this.insertMergedLines({row: 0, column: 0}, textOrLines); + } else { + this.insert({row: 0, column:0}, textOrLines); + } +}; + +(function() { + + oop.implement(this, EventEmitter); + + /** + * Replaces all the lines in the current `Document` with the value of `text`. + * + * @param {String} text The text to use + **/ + this.setValue = function(text) { + var len = this.getLength() - 1; + this.remove(new Range(0, 0, len, this.getLine(len).length)); + this.insert({row: 0, column: 0}, text); + }; + + /** + * Returns all the lines in the document as a single string, joined by the new line character. + **/ + this.getValue = function() { + return this.getAllLines().join(this.getNewLineCharacter()); + }; + + /** + * Creates a new `Anchor` to define a floating point in the document. + * @param {Number} row The row number to use + * @param {Number} column The column number to use + * + **/ + this.createAnchor = function(row, column) { + return new Anchor(this, row, column); + }; + + /** + * Splits a string of text on any newline (`\n`) or carriage-return (`\r`) characters. + * + * @method $split + * @param {String} text The text to work with + * @returns {String} A String array, with each index containing a piece of the original `text` string. + * + **/ + + // check for IE split bug + if ("aaa".split(/a/).length === 0) { + this.$split = function(text) { + return text.replace(/\r\n|\r/g, "\n").split("\n"); + }; + } else { + this.$split = function(text) { + return text.split(/\r\n|\r|\n/); + }; + } + + + this.$detectNewLine = function(text) { + var match = text.match(/^.*?(\r\n|\r|\n)/m); + this.$autoNewLine = match ? match[1] : "\n"; + this._signal("changeNewLineMode"); + }; + + /** + * Returns the newline character that's being used, depending on the value of `newLineMode`. + * @returns {String} If `newLineMode == windows`, `\r\n` is returned. + * If `newLineMode == unix`, `\n` is returned. + * If `newLineMode == auto`, the value of `autoNewLine` is returned. + * + **/ + this.getNewLineCharacter = function() { + switch (this.$newLineMode) { + case "windows": + return "\r\n"; + case "unix": + return "\n"; + default: + return this.$autoNewLine || "\n"; + } + }; + + this.$autoNewLine = ""; + this.$newLineMode = "auto"; + /** + * [Sets the new line mode.]{: #Document.setNewLineMode.desc} + * @param {String} newLineMode [The newline mode to use; can be either `windows`, `unix`, or `auto`]{: #Document.setNewLineMode.param} + * + **/ + this.setNewLineMode = function(newLineMode) { + if (this.$newLineMode === newLineMode) + return; + + this.$newLineMode = newLineMode; + this._signal("changeNewLineMode"); + }; + + /** + * [Returns the type of newlines being used; either `windows`, `unix`, or `auto`]{: #Document.getNewLineMode} + * @returns {String} + **/ + this.getNewLineMode = function() { + return this.$newLineMode; + }; + + /** + * Returns `true` if `text` is a newline character (either `\r\n`, `\r`, or `\n`). + * @param {String} text The text to check + * + **/ + this.isNewLine = function(text) { + return (text == "\r\n" || text == "\r" || text == "\n"); + }; + + /** + * Returns a verbatim copy of the given line as it is in the document + * @param {Number} row The row index to retrieve + * + **/ + this.getLine = function(row) { + return this.$lines[row] || ""; + }; + + /** + * Returns an array of strings of the rows between `firstRow` and `lastRow`. This function is inclusive of `lastRow`. + * @param {Number} firstRow The first row index to retrieve + * @param {Number} lastRow The final row index to retrieve + * + **/ + this.getLines = function(firstRow, lastRow) { + return this.$lines.slice(firstRow, lastRow + 1); + }; + + /** + * Returns all lines in the document as string array. + **/ + this.getAllLines = function() { + return this.getLines(0, this.getLength()); + }; + + /** + * Returns the number of rows in the document. + **/ + this.getLength = function() { + return this.$lines.length; + }; + + /** + * Returns all the text within `range` as a single string. + * @param {Range} range The range to work with. + * + * @returns {String} + **/ + this.getTextRange = function(range) { + return this.getLinesForRange(range).join(this.getNewLineCharacter()); + }; + + /** + * Returns all the text within `range` as an array of lines. + * @param {Range} range The range to work with. + * + * @returns {Array} + **/ + this.getLinesForRange = function(range) { + var lines; + if (range.start.row === range.end.row) { + // Handle a single-line range. + lines = [this.getLine(range.start.row).substring(range.start.column, range.end.column)]; + } else { + // Handle a multi-line range. + lines = this.getLines(range.start.row, range.end.row); + lines[0] = (lines[0] || "").substring(range.start.column); + var l = lines.length - 1; + if (range.end.row - range.start.row == l) + lines[l] = lines[l].substring(0, range.end.column); + } + return lines; + }; + + // Deprecated methods retained for backwards compatibility. + this.insertLines = function(row, lines) { + console.warn("Use of document.insertLines is deprecated. Use the insertFullLines method instead."); + return this.insertFullLines(row, lines); + }; + this.removeLines = function(firstRow, lastRow) { + console.warn("Use of document.removeLines is deprecated. Use the removeFullLines method instead."); + return this.removeFullLines(firstRow, lastRow); + }; + this.insertNewLine = function(position) { + console.warn("Use of document.insertNewLine is deprecated. Use insertMergedLines(position, [\'\', \'\']) instead."); + return this.insertMergedLines(position, ["", ""]); + }; + + /** + * Inserts a block of `text` at the indicated `position`. + * @param {Object} position The position to start inserting at; it's an object that looks like `{ row: row, column: column}` + * @param {String} text A chunk of text to insert + * @returns {Object} The position ({row, column}) of the last line of `text`. If the length of `text` is 0, this function simply returns `position`. + * + **/ + this.insert = function(position, text) { + // Only detect new lines if the document has no line break yet. + if (this.getLength() <= 1) + this.$detectNewLine(text); + + return this.insertMergedLines(position, this.$split(text)); + }; + + /** + * Inserts `text` into the `position` at the current row. This method also triggers the `"change"` event. + * + * This differs from the `insert` method in two ways: + * 1. This does NOT handle newline characters (single-line text only). + * 2. This is faster than the `insert` method for single-line text insertions. + * + * @param {Object} position The position to insert at; it's an object that looks like `{ row: row, column: column}` + * @param {String} text A chunk of text + * @returns {Object} Returns an object containing the final row and column, like this: + * ``` + * {row: endRow, column: 0} + * ``` + **/ + this.insertInLine = function(position, text) { + var start = this.clippedPos(position.row, position.column); + var end = this.pos(position.row, position.column + text.length); + + this.applyDelta({ + start: start, + end: end, + action: "insert", + lines: [text] + }, true); + + return this.clonePos(end); + }; + + this.clippedPos = function(row, column) { + var length = this.getLength(); + if (row === undefined) { + row = length; + } else if (row < 0) { + row = 0; + } else if (row >= length) { + row = length - 1; + column = undefined; + } + var line = this.getLine(row); + if (column == undefined) + column = line.length; + column = Math.min(Math.max(column, 0), line.length); + return {row: row, column: column}; + }; + + this.clonePos = function(pos) { + return {row: pos.row, column: pos.column}; + }; + + this.pos = function(row, column) { + return {row: row, column: column}; + }; + + this.$clipPosition = function(position) { + var length = this.getLength(); + if (position.row >= length) { + position.row = Math.max(0, length - 1); + position.column = this.getLine(length - 1).length; + } else { + position.row = Math.max(0, position.row); + position.column = Math.min(Math.max(position.column, 0), this.getLine(position.row).length); + } + return position; + }; + + /** + * Fires whenever the document changes. + * + * Several methods trigger different `"change"` events. Below is a list of each action type, followed by each property that's also available: + * + * * `"insert"` + * * `range`: the [[Range]] of the change within the document + * * `lines`: the lines being added + * * `"remove"` + * * `range`: the [[Range]] of the change within the document + * * `lines`: the lines being removed + * + * @event change + * @param {Object} e Contains at least one property called `"action"`. `"action"` indicates the action that triggered the change. Each action also has a set of additional properties. + * + **/ + + /** + * Inserts the elements in `lines` into the document as full lines (does not merge with existing line), starting at the row index given by `row`. This method also triggers the `"change"` event. + * @param {Number} row The index of the row to insert at + * @param {Array} lines An array of strings + * @returns {Object} Contains the final row and column, like this: + * ``` + * {row: endRow, column: 0} + * ``` + * If `lines` is empty, this function returns an object containing the current row, and column, like this: + * ``` + * {row: row, column: 0} + * ``` + * + **/ + this.insertFullLines = function(row, lines) { + // Clip to document. + // Allow one past the document end. + row = Math.min(Math.max(row, 0), this.getLength()); + + // Calculate insertion point. + var column = 0; + if (row < this.getLength()) { + // Insert before the specified row. + lines = lines.concat([""]); + column = 0; + } else { + // Insert after the last row in the document. + lines = [""].concat(lines); + row--; + column = this.$lines[row].length; + } + + // Insert. + this.insertMergedLines({row: row, column: column}, lines); + }; + + /** + * Inserts the elements in `lines` into the document, starting at the position index given by `row`. This method also triggers the `"change"` event. + * @param {Number} row The index of the row to insert at + * @param {Array} lines An array of strings + * @returns {Object} Contains the final row and column, like this: + * ``` + * {row: endRow, column: 0} + * ``` + * If `lines` is empty, this function returns an object containing the current row, and column, like this: + * ``` + * {row: row, column: 0} + * ``` + * + **/ + this.insertMergedLines = function(position, lines) { + var start = this.clippedPos(position.row, position.column); + var end = { + row: start.row + lines.length - 1, + column: (lines.length == 1 ? start.column : 0) + lines[lines.length - 1].length + }; + + this.applyDelta({ + start: start, + end: end, + action: "insert", + lines: lines + }); + + return this.clonePos(end); + }; + + /** + * Removes the `range` from the document. + * @param {Range} range A specified Range to remove + * @returns {Object} Returns the new `start` property of the range, which contains `startRow` and `startColumn`. If `range` is empty, this function returns the unmodified value of `range.start`. + * + **/ + this.remove = function(range) { + var start = this.clippedPos(range.start.row, range.start.column); + var end = this.clippedPos(range.end.row, range.end.column); + this.applyDelta({ + start: start, + end: end, + action: "remove", + lines: this.getLinesForRange({start: start, end: end}) + }); + return this.clonePos(start); + }; + + /** + * Removes the specified columns from the `row`. This method also triggers a `"change"` event. + * @param {Number} row The row to remove from + * @param {Number} startColumn The column to start removing at + * @param {Number} endColumn The column to stop removing at + * @returns {Object} Returns an object containing `startRow` and `startColumn`, indicating the new row and column values.
      If `startColumn` is equal to `endColumn`, this function returns nothing. + * + **/ + this.removeInLine = function(row, startColumn, endColumn) { + var start = this.clippedPos(row, startColumn); + var end = this.clippedPos(row, endColumn); + + this.applyDelta({ + start: start, + end: end, + action: "remove", + lines: this.getLinesForRange({start: start, end: end}) + }, true); + + return this.clonePos(start); + }; + + /** + * Removes a range of full lines. This method also triggers the `"change"` event. + * @param {Number} firstRow The first row to be removed + * @param {Number} lastRow The last row to be removed + * @returns {[String]} Returns all the removed lines. + * + **/ + this.removeFullLines = function(firstRow, lastRow) { + // Clip to document. + firstRow = Math.min(Math.max(0, firstRow), this.getLength() - 1); + lastRow = Math.min(Math.max(0, lastRow ), this.getLength() - 1); + + // Calculate deletion range. + // Delete the ending new line unless we're at the end of the document. + // If we're at the end of the document, delete the starting new line. + var deleteFirstNewLine = lastRow == this.getLength() - 1 && firstRow > 0; + var deleteLastNewLine = lastRow < this.getLength() - 1; + var startRow = ( deleteFirstNewLine ? firstRow - 1 : firstRow ); + var startCol = ( deleteFirstNewLine ? this.getLine(startRow).length : 0 ); + var endRow = ( deleteLastNewLine ? lastRow + 1 : lastRow ); + var endCol = ( deleteLastNewLine ? 0 : this.getLine(endRow).length ); + var range = new Range(startRow, startCol, endRow, endCol); + + // Store delelted lines with bounding newlines ommitted (maintains previous behavior). + var deletedLines = this.$lines.slice(firstRow, lastRow + 1); + + this.applyDelta({ + start: range.start, + end: range.end, + action: "remove", + lines: this.getLinesForRange(range) + }); + + // Return the deleted lines. + return deletedLines; + }; + + /** + * Removes the new line between `row` and the row immediately following it. This method also triggers the `"change"` event. + * @param {Number} row The row to check + * + **/ + this.removeNewLine = function(row) { + if (row < this.getLength() - 1 && row >= 0) { + this.applyDelta({ + start: this.pos(row, this.getLine(row).length), + end: this.pos(row + 1, 0), + action: "remove", + lines: ["", ""] + }); + } + }; + + /** + * Replaces a range in the document with the new `text`. + * @param {Range} range A specified Range to replace + * @param {String} text The new text to use as a replacement + * @returns {Object} Returns an object containing the final row and column, like this: + * {row: endRow, column: 0} + * If the text and range are empty, this function returns an object containing the current `range.start` value. + * If the text is the exact same as what currently exists, this function returns an object containing the current `range.end` value. + * + **/ + this.replace = function(range, text) { + if (!range instanceof Range) + range = Range.fromPoints(range.start, range.end); + if (text.length === 0 && range.isEmpty()) + return range.start; + + // Shortcut: If the text we want to insert is the same as it is already + // in the document, we don't have to replace anything. + if (text == this.getTextRange(range)) + return range.end; + + this.remove(range); + var end; + if (text) { + end = this.insert(range.start, text); + } + else { + end = range.start; + } + + return end; + }; + + /** + * Applies all changes in `deltas` to the document. + * @param {Array} deltas An array of delta objects (can include "insert" and "remove" actions) + **/ + this.applyDeltas = function(deltas) { + for (var i=0; i=0; i--) { + this.revertDelta(deltas[i]); + } + }; + + /** + * Applies `delta` to the document. + * @param {Object} delta A delta object (can include "insert" and "remove" actions) + **/ + this.applyDelta = function(delta, doNotValidate) { + var isInsert = delta.action == "insert"; + // An empty range is a NOOP. + if (isInsert ? delta.lines.length <= 1 && !delta.lines[0] + : !Range.comparePoints(delta.start, delta.end)) { + return; + } + + if (isInsert && delta.lines.length > 20000) + this.$splitAndapplyLargeDelta(delta, 20000); + + // Apply. + applyDelta(this.$lines, delta, doNotValidate); + this._signal("change", delta); + }; + + this.$splitAndapplyLargeDelta = function(delta, MAX) { + // Split large insert deltas. This is necessary because: + // 1. We need to support splicing delta lines into the document via $lines.splice.apply(...) + // 2. fn.apply() doesn't work for a large number of params. The smallest threshold is on chrome 40 ~42000. + // we use 20000 to leave some space for actual stack + // + // To Do: Ideally we'd be consistent and also split 'delete' deltas. We don't do this now, because delete + // delta handling is too slow. If we make delete delta handling faster we can split all large deltas + // as shown in https://gist.github.com/aldendaniels/8367109#file-document-snippet-js + // If we do this, update validateDelta() to limit the number of lines in a delete delta. + var lines = delta.lines; + var l = lines.length; + var row = delta.start.row; + var column = delta.start.column; + var from = 0, to = 0; + do { + from = to; + to += MAX - 1; + var chunk = lines.slice(from, to); + if (to > l) { + // Update remaining delta. + delta.lines = chunk; + delta.start.row = row + from; + delta.start.column = column; + break; + } + chunk.push(""); + this.applyDelta({ + start: this.pos(row + from, column), + end: this.pos(row + to, column = 0), + action: delta.action, + lines: chunk + }, true); + } while(true); + }; + + /** + * Reverts `delta` from the document. + * @param {Object} delta A delta object (can include "insert" and "remove" actions) + **/ + this.revertDelta = function(delta) { + this.applyDelta({ + start: this.clonePos(delta.start), + end: this.clonePos(delta.end), + action: (delta.action == "insert" ? "remove" : "insert"), + lines: delta.lines.slice() + }); + }; + + /** + * Converts an index position in a document to a `{row, column}` object. + * + * Index refers to the "absolute position" of a character in the document. For example: + * + * ```javascript + * var x = 0; // 10 characters, plus one for newline + * var y = -1; + * ``` + * + * Here, `y` is an index 15: 11 characters for the first row, and 5 characters until `y` in the second. + * + * @param {Number} index An index to convert + * @param {Number} startRow=0 The row from which to start the conversion + * @returns {Object} A `{row, column}` object of the `index` position + */ + this.indexToPosition = function(index, startRow) { + var lines = this.$lines || this.getAllLines(); + var newlineLength = this.getNewLineCharacter().length; + for (var i = startRow || 0, l = lines.length; i < l; i++) { + index -= lines[i].length + newlineLength; + if (index < 0) + return {row: i, column: index + lines[i].length + newlineLength}; + } + return {row: l-1, column: lines[l-1].length}; + }; + + /** + * Converts the `{row, column}` position in a document to the character's index. + * + * Index refers to the "absolute position" of a character in the document. For example: + * + * ```javascript + * var x = 0; // 10 characters, plus one for newline + * var y = -1; + * ``` + * + * Here, `y` is an index 15: 11 characters for the first row, and 5 characters until `y` in the second. + * + * @param {Object} pos The `{row, column}` to convert + * @param {Number} startRow=0 The row from which to start the conversion + * @returns {Number} The index position in the document + */ + this.positionToIndex = function(pos, startRow) { + var lines = this.$lines || this.getAllLines(); + var newlineLength = this.getNewLineCharacter().length; + var index = 0; + var row = Math.min(pos.row, lines.length); + for (var i = startRow || 0; i < row; ++i) + index += lines[i].length + newlineLength; + + return index + pos.column; + }; + +}).call(Document.prototype); + +exports.Document = Document; +}); diff --git a/node_modules/ace/lib/ace/document_test.js b/node_modules/ace/lib/ace/document_test.js new file mode 100644 index 00000000..ada56cd2 --- /dev/null +++ b/node_modules/ace/lib/ace/document_test.js @@ -0,0 +1,335 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +if (typeof process !== "undefined") { + require("amd-loader"); + require("./test/mockdom"); +} + +define(function(require, exports, module) { +"use strict"; + +var Document = require("./document").Document; +var Range = require("./range").Range; +var assert = require("./test/assertions"); + +module.exports = { + + "test: insert text in line" : function() { + var doc = new Document(["12", "34"]); + + var deltas = []; + doc.on("change", function(e) { deltas.push(e); }); + + doc.insert({row: 0, column: 1}, "juhu"); + assert.equal(doc.getValue(), ["1juhu2", "34"].join("\n")); + + var d = deltas.concat(); + doc.revertDeltas(d); + assert.equal(doc.getValue(), ["12", "34"].join("\n")); + + doc.applyDeltas(d); + assert.equal(doc.getValue(), ["1juhu2", "34"].join("\n")); + }, + + "test: insert new line" : function() { + var doc = new Document(["12", "34"]); + + var deltas = []; + doc.on("change", function(e) { deltas.push(e); }); + + doc.insertMergedLines({row: 0, column: 1}, ['', '']); + assert.equal(doc.getValue(), ["1", "2", "34"].join("\n")); + + var d = deltas.concat(); + doc.revertDeltas(d); + assert.equal(doc.getValue(), ["12", "34"].join("\n")); + + doc.applyDeltas(d); + assert.equal(doc.getValue(), ["1", "2", "34"].join("\n")); + }, + + "test: insert lines at the beginning" : function() { + var doc = new Document(["12", "34"]); + + var deltas = []; + doc.on("change", function(e) { deltas.push(e); }); + + doc.insertFullLines(0, ["aa", "bb"]); + assert.equal(doc.getValue(), ["aa", "bb", "12", "34"].join("\n")); + + var d = deltas.concat(); + doc.revertDeltas(d); + assert.equal(doc.getValue(), ["12", "34"].join("\n")); + + doc.applyDeltas(d); + assert.equal(doc.getValue(), ["aa", "bb", "12", "34"].join("\n")); + }, + + "test: insert lines at the end" : function() { + var doc = new Document(["12", "34"]); + + var deltas = []; + doc.on("change", function(e) { deltas.push(e); }); + + doc.insertFullLines(2, ["aa", "bb"]); + assert.equal(doc.getValue(), ["12", "34", "aa", "bb"].join("\n")); + }, + + "test: insert lines in the middle" : function() { + var doc = new Document(["12", "34"]); + + var deltas = []; + doc.on("change", function(e) { deltas.push(e); }); + + doc.insertFullLines(1, ["aa", "bb"]); + assert.equal(doc.getValue(), ["12", "aa", "bb", "34"].join("\n")); + + var d = deltas.concat(); + doc.revertDeltas(d); + assert.equal(doc.getValue(), ["12", "34"].join("\n")); + + doc.applyDeltas(d); + assert.equal(doc.getValue(), ["12", "aa", "bb", "34"].join("\n")); + }, + + "test: insert multi line string at the start" : function() { + var doc = new Document(["12", "34"]); + + var deltas = []; + doc.on("change", function(e) { deltas.push(e); }); + + doc.insert({row: 0, column: 0}, "aa\nbb\ncc"); + assert.equal(doc.getValue(), ["aa", "bb", "cc12", "34"].join("\n")); + + var d = deltas.concat(); + doc.revertDeltas(d); + assert.equal(doc.getValue(), ["12", "34"].join("\n")); + + doc.applyDeltas(d); + assert.equal(doc.getValue(), ["aa", "bb", "cc12", "34"].join("\n")); + }, + + "test: insert multi line string at the end" : function() { + var doc = new Document(["12", "34"]); + + var deltas = []; + doc.on("change", function(e) { deltas.push(e); }); + + doc.insert({row: 1, column: 2}, "aa\nbb\ncc"); + assert.equal(doc.getValue(), ["12", "34aa", "bb", "cc"].join("\n")); + + var d = deltas.concat(); + doc.revertDeltas(d); + assert.equal(doc.getValue(), ["12", "34"].join("\n")); + + doc.applyDeltas(d); + assert.equal(doc.getValue(), ["12", "34aa", "bb", "cc"].join("\n")); + }, + + "test: insert multi line string in the middle" : function() { + var doc = new Document(["12", "34"]); + + var deltas = []; + doc.on("change", function(e) { deltas.push(e); }); + + doc.insert({row: 0, column: 1}, "aa\nbb\ncc"); + assert.equal(doc.getValue(), ["1aa", "bb", "cc2", "34"].join("\n")); + + var d = deltas.concat(); + doc.revertDeltas(d); + assert.equal(doc.getValue(), ["12", "34"].join("\n")); + + doc.applyDeltas(d); + assert.equal(doc.getValue(), ["1aa", "bb", "cc2", "34"].join("\n")); + }, + + "test: delete in line" : function() { + var doc = new Document(["1234", "5678"]); + + var deltas = []; + doc.on("change", function(e) { deltas.push(e); }); + + doc.remove(new Range(0, 1, 0, 3)); + assert.equal(doc.getValue(), ["14", "5678"].join("\n")); + + var d = deltas.concat(); + doc.revertDeltas(d); + assert.equal(doc.getValue(), ["1234", "5678"].join("\n")); + + doc.applyDeltas(d); + assert.equal(doc.getValue(), ["14", "5678"].join("\n")); + }, + + "test: delete new line" : function() { + var doc = new Document(["1234", "5678"]); + + var deltas = []; + doc.on("change", function(e) { deltas.push(e); }); + + doc.remove(new Range(0, 4, 1, 0)); + assert.equal(doc.getValue(), ["12345678"].join("\n")); + + var d = deltas.concat(); + doc.revertDeltas(d); + assert.equal(doc.getValue(), ["1234", "5678"].join("\n")); + + doc.applyDeltas(d); + assert.equal(doc.getValue(), ["12345678"].join("\n")); + }, + + "test: delete multi line range line" : function() { + var doc = new Document(["1234", "5678", "abcd"]); + + var deltas = []; + doc.on("change", function(e) { deltas.push(e); }); + + doc.remove(new Range(0, 2, 2, 2)); + assert.equal(doc.getValue(), ["12cd"].join("\n")); + + var d = deltas.concat(); + doc.revertDeltas(d); + assert.equal(doc.getValue(), ["1234", "5678", "abcd"].join("\n")); + + doc.applyDeltas(d); + assert.equal(doc.getValue(), ["12cd"].join("\n")); + }, + + "test: delete full lines" : function() { + var doc = new Document(["1234", "5678", "abcd"]); + + var deltas = []; + doc.on("change", function(e) { deltas.push(e); }); + + doc.remove(new Range(1, 0, 3, 0)); + assert.equal(doc.getValue(), ["1234", ""].join("\n")); + }, + + "test: remove lines should return the removed lines" : function() { + var doc = new Document(["1234", "5678", "abcd"]); + + var removed = doc.removeFullLines(1, 2); + assert.equal(removed.join("\n"), ["5678", "abcd"].join("\n")); + }, + + "test: should handle unix style new lines" : function() { + var doc = new Document(["1", "2", "3"]); + assert.equal(doc.getValue(), ["1", "2", "3"].join("\n")); + }, + + "test: should handle windows style new lines" : function() { + var doc = new Document(["1", "2", "3"].join("\r\n")); + + doc.setNewLineMode("unix"); + assert.equal(doc.getValue(), ["1", "2", "3"].join("\n")); + }, + + "test: set new line mode to 'windows' should use '\\r\\n' as new lines": function() { + var doc = new Document(["1", "2", "3"].join("\n")); + doc.setNewLineMode("windows"); + assert.equal(doc.getValue(), ["1", "2", "3"].join("\r\n")); + }, + + "test: set new line mode to 'unix' should use '\\n' as new lines": function() { + var doc = new Document(["1", "2", "3"].join("\r\n")); + + doc.setNewLineMode("unix"); + assert.equal(doc.getValue(), ["1", "2", "3"].join("\n")); + }, + + "test: set new line mode to 'auto' should detect the incoming nl type": function() { + var doc = new Document(["1", "2", "3"].join("\n")); + + doc.setNewLineMode("auto"); + assert.equal(doc.getValue(), ["1", "2", "3"].join("\n")); + + var doc = new Document(["1", "2", "3"].join("\r\n")); + + doc.setNewLineMode("auto"); + assert.equal(doc.getValue(), ["1", "2", "3"].join("\r\n")); + + doc.replace(new Range(0, 0, 2, 1), ["4", "5", "6"].join("\n")); + assert.equal(["4", "5", "6"].join("\n"), doc.getValue()); + }, + + "test: set value": function() { + var doc = new Document("1"); + assert.equal("1", doc.getValue()); + + doc.setValue(doc.getValue()); + assert.equal("1", doc.getValue()); + + var doc = new Document("1\n2"); + assert.equal("1\n2", doc.getValue()); + + doc.setValue(doc.getValue()); + assert.equal("1\n2", doc.getValue()); + }, + + "test: empty document has to contain one line": function() { + var doc = new Document(""); + assert.equal(doc.$lines.length, 1); + }, + + "test: ignore empty delta": function() { + var doc = new Document(""); + doc.on("change", function() { + throw "should ignore empty delta"; + }) + doc.insert({row: 0, column: 0}, ""); + doc.insert({row: 1, column: 1}, ""); + doc.remove({start: {row: 1, column: 1}, end: {row: 1, column: 1}}); + }, + + "test: inserting huge delta": function() { + var doc = new Document(""); + var val = ""; + var MAX = 0xF000; + for (var i = 0; i < 10 * MAX; i++) { + val += i + "\n" + } + doc.setValue(val); + assert.equal(doc.getValue(), val); + + for (var i = 3 * MAX + 2; i >= 3 * MAX - 2; i--) { + val = doc.getLines(0, i).join("\n"); + doc.setValue("\nab"); + assert.equal(doc.getValue(), "\nab"); + doc.insert({row: 1, column: 1}, val); + assert.equal(doc.getValue(), "\na" + val + "b"); + } + } +}; + +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec() +} diff --git a/node_modules/ace/lib/ace/edit_session.js b/node_modules/ace/lib/ace/edit_session.js new file mode 100644 index 00000000..dd6ca39c --- /dev/null +++ b/node_modules/ace/lib/ace/edit_session.js @@ -0,0 +1,2565 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("./lib/oop"); +var lang = require("./lib/lang"); +var config = require("./config"); +var EventEmitter = require("./lib/event_emitter").EventEmitter; +var Selection = require("./selection").Selection; +var TextMode = require("./mode/text").Mode; +var Range = require("./range").Range; +var Document = require("./document").Document; +var BackgroundTokenizer = require("./background_tokenizer").BackgroundTokenizer; +var SearchHighlight = require("./search_highlight").SearchHighlight; + +/** + * Stores all the data about [[Editor `Editor`]] state providing easy way to change editors state. + * + * `EditSession` can be attached to only one [[Document `Document`]]. Same `Document` can be attached to several `EditSession`s. + * @class EditSession + **/ + +//{ events +/** + * + * Emitted when the document changes. + * @event change + * @param {Object} e An object containing a `delta` of information about the change. + **/ +/** + * Emitted when the tab size changes, via [[EditSession.setTabSize]]. + * + * @event changeTabSize + **/ +/** + * Emitted when the ability to overwrite text changes, via [[EditSession.setOverwrite]]. + * + * @event changeOverwrite + **/ +/** + * Emitted when the gutter changes, either by setting or removing breakpoints, or when the gutter decorations change. + * + * @event changeBreakpoint + **/ +/** + * Emitted when a front marker changes. + * + * @event changeFrontMarker + **/ +/** + * Emitted when a back marker changes. + * + * @event changeBackMarker + **/ +/** + * Emitted when an annotation changes, like through [[EditSession.setAnnotations]]. + * + * @event changeAnnotation + **/ +/** + * Emitted when a background tokenizer asynchronously processes new rows. + * @event tokenizerUpdate + * + * @param {Object} e An object containing one property, `"data"`, that contains information about the changing rows + * + **/ +/** + * Emitted when the current mode changes. + * + * @event changeMode + * + **/ +/** + * Emitted when the wrap mode changes. + * + * @event changeWrapMode + * + **/ +/** + * Emitted when the wrapping limit changes. + * + * @event changeWrapLimit + * + **/ +/** + * Emitted when a code fold is added or removed. + * + * @event changeFold + * + **/ + /** + * Emitted when the scroll top changes. + * @event changeScrollTop + * + * @param {Number} scrollTop The new scroll top value + **/ +/** + * Emitted when the scroll left changes. + * @event changeScrollLeft + * + * @param {Number} scrollLeft The new scroll left value + **/ +//} + +/** + * + * Sets up a new `EditSession` and associates it with the given `Document` and `TextMode`. + * @param {Document | String} text [If `text` is a `Document`, it associates the `EditSession` with it. Otherwise, a new `Document` is created, with the initial text]{: #textParam} + * @param {TextMode} mode [The inital language mode to use for the document]{: #modeParam} + * + * @constructor + **/ + +var EditSession = function(text, mode) { + this.$breakpoints = []; + this.$decorations = []; + this.$frontMarkers = {}; + this.$backMarkers = {}; + this.$markerId = 1; + this.$undoSelect = true; + + this.$foldData = []; + this.$foldData.toString = function() { + return this.join("\n"); + } + this.on("changeFold", this.onChangeFold.bind(this)); + this.$onChange = this.onChange.bind(this); + + if (typeof text != "object" || !text.getLine) + text = new Document(text); + + this.setDocument(text); + this.selection = new Selection(this); + + config.resetOptions(this); + this.setMode(mode); + config._signal("session", this); +}; + + +(function() { + + oop.implement(this, EventEmitter); + + /** + * Sets the `EditSession` to point to a new `Document`. If a `BackgroundTokenizer` exists, it also points to `doc`. + * + * @param {Document} doc The new `Document` to use + * + **/ + this.setDocument = function(doc) { + if (this.doc) + this.doc.removeListener("change", this.$onChange); + + this.doc = doc; + doc.on("change", this.$onChange); + + if (this.bgTokenizer) + this.bgTokenizer.setDocument(this.getDocument()); + + this.resetCaches(); + }; + + /** + * Returns the `Document` associated with this session. + * @return {Document} + **/ + this.getDocument = function() { + return this.doc; + }; + + /** + * @param {Number} row The row to work with + * + **/ + this.$resetRowCache = function(docRow) { + if (!docRow) { + this.$docRowCache = []; + this.$screenRowCache = []; + return; + } + var l = this.$docRowCache.length; + var i = this.$getRowCacheIndex(this.$docRowCache, docRow) + 1; + if (l > i) { + this.$docRowCache.splice(i, l); + this.$screenRowCache.splice(i, l); + } + }; + + this.$getRowCacheIndex = function(cacheArray, val) { + var low = 0; + var hi = cacheArray.length - 1; + + while (low <= hi) { + var mid = (low + hi) >> 1; + var c = cacheArray[mid]; + + if (val > c) + low = mid + 1; + else if (val < c) + hi = mid - 1; + else + return mid; + } + + return low -1; + }; + + this.resetCaches = function() { + this.$modified = true; + this.$wrapData = []; + this.$rowLengthCache = []; + this.$resetRowCache(0); + if (this.bgTokenizer) + this.bgTokenizer.start(0); + }; + + this.onChangeFold = function(e) { + var fold = e.data; + this.$resetRowCache(fold.start.row); + }; + + this.onChange = function(delta) { + this.$modified = true; + + this.$resetRowCache(delta.start.row); + + var removedFolds = this.$updateInternalDataOnChange(delta); + if (!this.$fromUndo && this.$undoManager && !delta.ignore) { + this.$deltasDoc.push(delta); + if (removedFolds && removedFolds.length != 0) { + this.$deltasFold.push({ + action: "removeFolds", + folds: removedFolds + }); + } + + this.$informUndoManager.schedule(); + } + + this.bgTokenizer && this.bgTokenizer.$updateOnChange(delta); + this._signal("change", delta); + }; + + /** + * Sets the session text. + * @param {String} text The new text to place + * + **/ + this.setValue = function(text) { + this.doc.setValue(text); + this.selection.moveTo(0, 0); + + this.$resetRowCache(0); + this.$deltas = []; + this.$deltasDoc = []; + this.$deltasFold = []; + this.setUndoManager(this.$undoManager); + this.getUndoManager().reset(); + }; + + /** + * Returns the current [[Document `Document`]] as a string. + * @method toString + * @returns {String} + * @alias EditSession.getValue + * + **/ + + /** + * Returns the current [[Document `Document`]] as a string. + * @method getValue + * @returns {String} + * @alias EditSession.toString + **/ + this.getValue = + this.toString = function() { + return this.doc.getValue(); + }; + + /** + * Returns the string of the current selection. + **/ + this.getSelection = function() { + return this.selection; + }; + + /** + * {:BackgroundTokenizer.getState} + * @param {Number} row The row to start at + * + * @related BackgroundTokenizer.getState + **/ + this.getState = function(row) { + return this.bgTokenizer.getState(row); + }; + + /** + * Starts tokenizing at the row indicated. Returns a list of objects of the tokenized rows. + * @param {Number} row The row to start at + * + * + * + **/ + this.getTokens = function(row) { + return this.bgTokenizer.getTokens(row); + }; + + /** + * Returns an object indicating the token at the current row. The object has two properties: `index` and `start`. + * @param {Number} row The row number to retrieve from + * @param {Number} column The column number to retrieve from + * + * + **/ + this.getTokenAt = function(row, column) { + var tokens = this.bgTokenizer.getTokens(row); + var token, c = 0; + if (column == null) { + i = tokens.length - 1; + c = this.getLine(row).length; + } else { + for (var i = 0; i < tokens.length; i++) { + c += tokens[i].value.length; + if (c >= column) + break; + } + } + token = tokens[i]; + if (!token) + return null; + token.index = i; + token.start = c - token.value.length; + return token; + }; + + /** + * Sets the undo manager. + * @param {UndoManager} undoManager The new undo manager + * + * + **/ + this.setUndoManager = function(undoManager) { + this.$undoManager = undoManager; + this.$deltas = []; + this.$deltasDoc = []; + this.$deltasFold = []; + + if (this.$informUndoManager) + this.$informUndoManager.cancel(); + + if (undoManager) { + var self = this; + + this.$syncInformUndoManager = function() { + self.$informUndoManager.cancel(); + + if (self.$deltasFold.length) { + self.$deltas.push({ + group: "fold", + deltas: self.$deltasFold + }); + self.$deltasFold = []; + } + + if (self.$deltasDoc.length) { + self.$deltas.push({ + group: "doc", + deltas: self.$deltasDoc + }); + self.$deltasDoc = []; + } + + if (self.$deltas.length > 0) { + undoManager.execute({ + action: "aceupdate", + args: [self.$deltas, self], + merge: self.mergeUndoDeltas + }); + } + self.mergeUndoDeltas = false; + self.$deltas = []; + }; + this.$informUndoManager = lang.delayedCall(this.$syncInformUndoManager); + } + }; + + /** + * starts a new group in undo history + **/ + this.markUndoGroup = function() { + if (this.$syncInformUndoManager) + this.$syncInformUndoManager(); + }; + + this.$defaultUndoManager = { + undo: function() {}, + redo: function() {}, + reset: function() {} + }; + + /** + * Returns the current undo manager. + **/ + this.getUndoManager = function() { + return this.$undoManager || this.$defaultUndoManager; + }; + + /** + * Returns the current value for tabs. If the user is using soft tabs, this will be a series of spaces (defined by [[EditSession.getTabSize `getTabSize()`]]); otherwise it's simply `'\t'`. + **/ + this.getTabString = function() { + if (this.getUseSoftTabs()) { + return lang.stringRepeat(" ", this.getTabSize()); + } else { + return "\t"; + } + }; + + /** + /** + * Pass `true` to enable the use of soft tabs. Soft tabs means you're using spaces instead of the tab character (`'\t'`). + * @param {Boolean} useSoftTabs Value indicating whether or not to use soft tabs + **/ + this.setUseSoftTabs = function(val) { + this.setOption("useSoftTabs", val); + }; + /** + * Returns `true` if soft tabs are being used, `false` otherwise. + * @returns {Boolean} + **/ + this.getUseSoftTabs = function() { + // todo might need more general way for changing settings from mode, but this is ok for now + return this.$useSoftTabs && !this.$mode.$indentWithTabs; + }; + /** + * Set the number of spaces that define a soft tab; for example, passing in `4` transforms the soft tabs to be equivalent to four spaces. This function also emits the `changeTabSize` event. + * @param {Number} tabSize The new tab size + **/ + this.setTabSize = function(tabSize) { + this.setOption("tabSize", tabSize); + }; + /** + * Returns the current tab size. + **/ + this.getTabSize = function() { + return this.$tabSize; + }; + + /** + * Returns `true` if the character at the position is a soft tab. + * @param {Object} position The position to check + * + * + **/ + this.isTabStop = function(position) { + return this.$useSoftTabs && (position.column % this.$tabSize === 0); + }; + + this.$overwrite = false; + /** + * Pass in `true` to enable overwrites in your session, or `false` to disable. + * + * If overwrites is enabled, any text you enter will type over any text after it. If the value of `overwrite` changes, this function also emites the `changeOverwrite` event. + * + * @param {Boolean} overwrite Defines wheter or not to set overwrites + * + * + **/ + this.setOverwrite = function(overwrite) { + this.setOption("overwrite", overwrite); + }; + + /** + * Returns `true` if overwrites are enabled; `false` otherwise. + **/ + this.getOverwrite = function() { + return this.$overwrite; + }; + + /** + * Sets the value of overwrite to the opposite of whatever it currently is. + **/ + this.toggleOverwrite = function() { + this.setOverwrite(!this.$overwrite); + }; + + /** + * Adds `className` to the `row`, to be used for CSS stylings and whatnot. + * @param {Number} row The row number + * @param {String} className The class to add + * + * + **/ + this.addGutterDecoration = function(row, className) { + if (!this.$decorations[row]) + this.$decorations[row] = ""; + this.$decorations[row] += " " + className; + this._signal("changeBreakpoint", {}); + }; + + /** + * Removes `className` from the `row`. + * @param {Number} row The row number + * @param {String} className The class to add + * + * + **/ + this.removeGutterDecoration = function(row, className) { + this.$decorations[row] = (this.$decorations[row] || "").replace(" " + className, ""); + this._signal("changeBreakpoint", {}); + }; + + /** + * Returns an array of numbers, indicating which rows have breakpoints. + * @returns {[Number]} + **/ + this.getBreakpoints = function() { + return this.$breakpoints; + }; + + /** + * Sets a breakpoint on every row number given by `rows`. This function also emites the `'changeBreakpoint'` event. + * @param {Array} rows An array of row indices + * + * + * + **/ + this.setBreakpoints = function(rows) { + this.$breakpoints = []; + for (var i=0; i 0) + inToken = !!line.charAt(column - 1).match(this.tokenRe); + + if (!inToken) + inToken = !!line.charAt(column).match(this.tokenRe); + + if (inToken) + var re = this.tokenRe; + else if (/^\s+$/.test(line.slice(column-1, column+1))) + var re = /\s/; + else + var re = this.nonTokenRe; + + var start = column; + if (start > 0) { + do { + start--; + } + while (start >= 0 && line.charAt(start).match(re)); + start++; + } + + var end = column; + while (end < line.length && line.charAt(end).match(re)) { + end++; + } + + return new Range(row, start, row, end); + }; + + /** + * Gets the range of a word, including its right whitespace. + * @param {Number} row The row number to start from + * @param {Number} column The column number to start from + * + * @return {Range} + **/ + this.getAWordRange = function(row, column) { + var wordRange = this.getWordRange(row, column); + var line = this.getLine(wordRange.end.row); + + while (line.charAt(wordRange.end.column).match(/[ \t]/)) { + wordRange.end.column += 1; + } + return wordRange; + }; + + /** + * {:Document.setNewLineMode.desc} + * @param {String} newLineMode {:Document.setNewLineMode.param} + * + * + * @related Document.setNewLineMode + **/ + this.setNewLineMode = function(newLineMode) { + this.doc.setNewLineMode(newLineMode); + }; + + /** + * + * Returns the current new line mode. + * @returns {String} + * @related Document.getNewLineMode + **/ + this.getNewLineMode = function() { + return this.doc.getNewLineMode(); + }; + + /** + * Identifies if you want to use a worker for the `EditSession`. + * @param {Boolean} useWorker Set to `true` to use a worker + * + **/ + this.setUseWorker = function(useWorker) { this.setOption("useWorker", useWorker); }; + + /** + * Returns `true` if workers are being used. + **/ + this.getUseWorker = function() { return this.$useWorker; }; + + /** + * Reloads all the tokens on the current session. This function calls [[BackgroundTokenizer.start `BackgroundTokenizer.start ()`]] to all the rows; it also emits the `'tokenizerUpdate'` event. + **/ + this.onReloadTokenizer = function(e) { + var rows = e.data; + this.bgTokenizer.start(rows.first); + this._signal("tokenizerUpdate", e); + }; + + this.$modes = {}; + + /** + * Sets a new text mode for the `EditSession`. This method also emits the `'changeMode'` event. If a [[BackgroundTokenizer `BackgroundTokenizer`]] is set, the `'tokenizerUpdate'` event is also emitted. + * @param {TextMode} mode Set a new text mode + * @param {cb} optional callback + * + **/ + this.$mode = null; + this.$modeId = null; + this.setMode = function(mode, cb) { + if (mode && typeof mode === "object") { + if (mode.getTokenizer) + return this.$onChangeMode(mode); + var options = mode; + var path = options.path; + } else { + path = mode || "ace/mode/text"; + } + + // this is needed if ace isn't on require path (e.g tests in node) + if (!this.$modes["ace/mode/text"]) + this.$modes["ace/mode/text"] = new TextMode(); + + if (this.$modes[path] && !options) { + this.$onChangeMode(this.$modes[path]); + cb && cb(); + return; + } + // load on demand + this.$modeId = path; + config.loadModule(["mode", path], function(m) { + if (this.$modeId !== path) + return cb && cb(); + if (this.$modes[path] && !options) { + this.$onChangeMode(this.$modes[path]); + } else if (m && m.Mode) { + m = new m.Mode(options); + if (!options) { + this.$modes[path] = m; + m.$id = path; + } + this.$onChangeMode(m); + } + cb && cb(); + }.bind(this)); + + // set mode to text until loading is finished + if (!this.$mode) + this.$onChangeMode(this.$modes["ace/mode/text"], true); + }; + + this.$onChangeMode = function(mode, $isPlaceholder) { + if (!$isPlaceholder) + this.$modeId = mode.$id; + if (this.$mode === mode) + return; + + this.$mode = mode; + + this.$stopWorker(); + + if (this.$useWorker) + this.$startWorker(); + + var tokenizer = mode.getTokenizer(); + + if(tokenizer.addEventListener !== undefined) { + var onReloadTokenizer = this.onReloadTokenizer.bind(this); + tokenizer.addEventListener("update", onReloadTokenizer); + } + + if (!this.bgTokenizer) { + this.bgTokenizer = new BackgroundTokenizer(tokenizer); + var _self = this; + this.bgTokenizer.addEventListener("update", function(e) { + _self._signal("tokenizerUpdate", e); + }); + } else { + this.bgTokenizer.setTokenizer(tokenizer); + } + + this.bgTokenizer.setDocument(this.getDocument()); + + this.tokenRe = mode.tokenRe; + this.nonTokenRe = mode.nonTokenRe; + + + if (!$isPlaceholder) { + // experimental method, used by c9 findiniles + if (mode.attachToSession) + mode.attachToSession(this); + this.$options.wrapMethod.set.call(this, this.$wrapMethod); + this.$setFolding(mode.foldingRules); + this.bgTokenizer.start(0); + this._emit("changeMode"); + } + }; + + this.$stopWorker = function() { + if (this.$worker) { + this.$worker.terminate(); + this.$worker = null; + } + }; + + this.$startWorker = function() { + try { + this.$worker = this.$mode.createWorker(this); + } catch (e) { + config.warn("Could not load worker", e); + this.$worker = null; + } + }; + + /** + * Returns the current text mode. + * @returns {TextMode} The current text mode + **/ + this.getMode = function() { + return this.$mode; + }; + + this.$scrollTop = 0; + /** + * This function sets the scroll top value. It also emits the `'changeScrollTop'` event. + * @param {Number} scrollTop The new scroll top value + * + **/ + this.setScrollTop = function(scrollTop) { + // TODO: should we force integer lineheight instead? scrollTop = Math.round(scrollTop); + if (this.$scrollTop === scrollTop || isNaN(scrollTop)) + return; + + this.$scrollTop = scrollTop; + this._signal("changeScrollTop", scrollTop); + }; + + /** + * [Returns the value of the distance between the top of the editor and the topmost part of the visible content.]{: #EditSession.getScrollTop} + * @returns {Number} + **/ + this.getScrollTop = function() { + return this.$scrollTop; + }; + + this.$scrollLeft = 0; + /** + * [Sets the value of the distance between the left of the editor and the leftmost part of the visible content.]{: #EditSession.setScrollLeft} + **/ + this.setScrollLeft = function(scrollLeft) { + // scrollLeft = Math.round(scrollLeft); + if (this.$scrollLeft === scrollLeft || isNaN(scrollLeft)) + return; + + this.$scrollLeft = scrollLeft; + this._signal("changeScrollLeft", scrollLeft); + }; + + /** + * [Returns the value of the distance between the left of the editor and the leftmost part of the visible content.]{: #EditSession.getScrollLeft} + * @returns {Number} + **/ + this.getScrollLeft = function() { + return this.$scrollLeft; + }; + + /** + * Returns the width of the screen. + * @returns {Number} + **/ + this.getScreenWidth = function() { + this.$computeWidth(); + if (this.lineWidgets) + return Math.max(this.getLineWidgetMaxWidth(), this.screenWidth); + return this.screenWidth; + }; + + this.getLineWidgetMaxWidth = function() { + if (this.lineWidgetsWidth != null) return this.lineWidgetsWidth; + var width = 0; + this.lineWidgets.forEach(function(w) { + if (w && w.screenWidth > width) + width = w.screenWidth; + }); + return this.lineWidgetWidth = width; + }; + + this.$computeWidth = function(force) { + if (this.$modified || force) { + this.$modified = false; + + if (this.$useWrapMode) + return this.screenWidth = this.$wrapLimit; + + var lines = this.doc.getAllLines(); + var cache = this.$rowLengthCache; + var longestScreenLine = 0; + var foldIndex = 0; + var foldLine = this.$foldData[foldIndex]; + var foldStart = foldLine ? foldLine.start.row : Infinity; + var len = lines.length; + + for (var i = 0; i < len; i++) { + if (i > foldStart) { + i = foldLine.end.row + 1; + if (i >= len) + break; + foldLine = this.$foldData[foldIndex++]; + foldStart = foldLine ? foldLine.start.row : Infinity; + } + + if (cache[i] == null) + cache[i] = this.$getStringScreenWidth(lines[i])[0]; + + if (cache[i] > longestScreenLine) + longestScreenLine = cache[i]; + } + this.screenWidth = longestScreenLine; + } + }; + + /** + * Returns a verbatim copy of the given line as it is in the document + * @param {Number} row The row to retrieve from + * + * + * @returns {String} + * + **/ + this.getLine = function(row) { + return this.doc.getLine(row); + }; + + /** + * Returns an array of strings of the rows between `firstRow` and `lastRow`. This function is inclusive of `lastRow`. + * @param {Number} firstRow The first row index to retrieve + * @param {Number} lastRow The final row index to retrieve + * + * @returns {[String]} + * + **/ + this.getLines = function(firstRow, lastRow) { + return this.doc.getLines(firstRow, lastRow); + }; + + /** + * Returns the number of rows in the document. + * @returns {Number} + **/ + this.getLength = function() { + return this.doc.getLength(); + }; + + /** + * {:Document.getTextRange.desc} + * @param {Range} range The range to work with + * + * @returns {String} + **/ + this.getTextRange = function(range) { + return this.doc.getTextRange(range || this.selection.getRange()); + }; + + /** + * Inserts a block of `text` and the indicated `position`. + * @param {Object} position The position {row, column} to start inserting at + * @param {String} text A chunk of text to insert + * @returns {Object} The position of the last line of `text`. If the length of `text` is 0, this function simply returns `position`. + * + * + **/ + this.insert = function(position, text) { + return this.doc.insert(position, text); + }; + + /** + * Removes the `range` from the document. + * @param {Range} range A specified Range to remove + * @returns {Object} The new `start` property of the range, which contains `startRow` and `startColumn`. If `range` is empty, this function returns the unmodified value of `range.start`. + * + * @related Document.remove + * + **/ + this.remove = function(range) { + return this.doc.remove(range); + }; + + /** + * Removes a range of full lines. This method also triggers the `'change'` event. + * @param {Number} firstRow The first row to be removed + * @param {Number} lastRow The last row to be removed + * @returns {[String]} Returns all the removed lines. + * + * @related Document.removeFullLines + * + **/ + this.removeFullLines = function(firstRow, lastRow){ + return this.doc.removeFullLines(firstRow, lastRow); + }; + + /** + * Reverts previous changes to your document. + * @param {Array} deltas An array of previous changes + * @param {Boolean} dontSelect [If `true`, doesn't select the range of where the change occured]{: #dontSelect} + * + * + * @returns {Range} + **/ + this.undoChanges = function(deltas, dontSelect) { + if (!deltas.length) + return; + + this.$fromUndo = true; + var lastUndoRange = null; + for (var i = deltas.length - 1; i != -1; i--) { + var delta = deltas[i]; + if (delta.group == "doc") { + this.doc.revertDeltas(delta.deltas); + lastUndoRange = + this.$getUndoSelection(delta.deltas, true, lastUndoRange); + } else { + delta.deltas.forEach(function(foldDelta) { + this.addFolds(foldDelta.folds); + }, this); + } + } + this.$fromUndo = false; + lastUndoRange && + this.$undoSelect && + !dontSelect && + this.selection.setSelectionRange(lastUndoRange); + return lastUndoRange; + }; + + /** + * Re-implements a previously undone change to your document. + * @param {Array} deltas An array of previous changes + * @param {Boolean} dontSelect {:dontSelect} + * + * + * @returns {Range} + **/ + this.redoChanges = function(deltas, dontSelect) { + if (!deltas.length) + return; + + this.$fromUndo = true; + var lastUndoRange = null; + for (var i = 0; i < deltas.length; i++) { + var delta = deltas[i]; + if (delta.group == "doc") { + this.doc.applyDeltas(delta.deltas); + lastUndoRange = + this.$getUndoSelection(delta.deltas, false, lastUndoRange); + } + } + this.$fromUndo = false; + lastUndoRange && + this.$undoSelect && + !dontSelect && + this.selection.setSelectionRange(lastUndoRange); + return lastUndoRange; + }; + + /** + * Enables or disables highlighting of the range where an undo occured. + * @param {Boolean} enable If `true`, selects the range of the reinserted change + * + **/ + this.setUndoSelect = function(enable) { + this.$undoSelect = enable; + }; + + this.$getUndoSelection = function(deltas, isUndo, lastUndoRange) { + function isInsert(delta) { + return isUndo ? delta.action !== "insert" : delta.action === "insert"; + } + + var delta = deltas[0]; + var range, point; + var lastDeltaIsInsert = false; + if (isInsert(delta)) { + range = Range.fromPoints(delta.start, delta.end); + lastDeltaIsInsert = true; + } else { + range = Range.fromPoints(delta.start, delta.start); + lastDeltaIsInsert = false; + } + + for (var i = 1; i < deltas.length; i++) { + delta = deltas[i]; + if (isInsert(delta)) { + point = delta.start; + if (range.compare(point.row, point.column) == -1) { + range.setStart(point); + } + point = delta.end; + if (range.compare(point.row, point.column) == 1) { + range.setEnd(point); + } + lastDeltaIsInsert = true; + } else { + point = delta.start; + if (range.compare(point.row, point.column) == -1) { + range = Range.fromPoints(delta.start, delta.start); + } + lastDeltaIsInsert = false; + } + } + + // Check if this range and the last undo range has something in common. + // If true, merge the ranges. + if (lastUndoRange != null) { + if (Range.comparePoints(lastUndoRange.start, range.start) === 0) { + lastUndoRange.start.column += range.end.column - range.start.column; + lastUndoRange.end.column += range.end.column - range.start.column; + } + + var cmp = lastUndoRange.compareRange(range); + if (cmp == 1) { + range.setStart(lastUndoRange.start); + } else if (cmp == -1) { + range.setEnd(lastUndoRange.end); + } + } + + return range; + }; + + /** + * Replaces a range in the document with the new `text`. + * + * @param {Range} range A specified Range to replace + * @param {String} text The new text to use as a replacement + * @returns {Object} An object containing the final row and column, like this: + * ``` + * {row: endRow, column: 0} + * ``` + * If the text and range are empty, this function returns an object containing the current `range.start` value. + * If the text is the exact same as what currently exists, this function returns an object containing the current `range.end` value. + * + * + * + * @related Document.replace + * + * + **/ + this.replace = function(range, text) { + return this.doc.replace(range, text); + }; + + /** + * Moves a range of text from the given range to the given position. `toPosition` is an object that looks like this: + * ```json + * { row: newRowLocation, column: newColumnLocation } + * ``` + * @param {Range} fromRange The range of text you want moved within the document + * @param {Object} toPosition The location (row and column) where you want to move the text to + * @returns {Range} The new range where the text was moved to. + * + * + * + **/ + this.moveText = function(fromRange, toPosition, copy) { + var text = this.getTextRange(fromRange); + var folds = this.getFoldsInRange(fromRange); + + var toRange = Range.fromPoints(toPosition, toPosition); + if (!copy) { + this.remove(fromRange); + var rowDiff = fromRange.start.row - fromRange.end.row; + var collDiff = rowDiff ? -fromRange.end.column : fromRange.start.column - fromRange.end.column; + if (collDiff) { + if (toRange.start.row == fromRange.end.row && toRange.start.column > fromRange.end.column) + toRange.start.column += collDiff; + if (toRange.end.row == fromRange.end.row && toRange.end.column > fromRange.end.column) + toRange.end.column += collDiff; + } + if (rowDiff && toRange.start.row >= fromRange.end.row) { + toRange.start.row += rowDiff; + toRange.end.row += rowDiff; + } + } + + toRange.end = this.insert(toRange.start, text); + if (folds.length) { + var oldStart = fromRange.start; + var newStart = toRange.start; + var rowDiff = newStart.row - oldStart.row; + var collDiff = newStart.column - oldStart.column; + this.addFolds(folds.map(function(x) { + x = x.clone(); + if (x.start.row == oldStart.row) + x.start.column += collDiff; + if (x.end.row == oldStart.row) + x.end.column += collDiff; + x.start.row += rowDiff; + x.end.row += rowDiff; + return x; + })); + } + + return toRange; + }; + + /** + * Indents all the rows, from `startRow` to `endRow` (inclusive), by prefixing each row with the token in `indentString`. + * + * If `indentString` contains the `'\t'` character, it's replaced by whatever is defined by [[EditSession.getTabString `getTabString()`]]. + * @param {Number} startRow Starting row + * @param {Number} endRow Ending row + * @param {String} indentString The indent token + * + * + **/ + this.indentRows = function(startRow, endRow, indentString) { + indentString = indentString.replace(/\t/g, this.getTabString()); + for (var row=startRow; row<=endRow; row++) + this.doc.insertInLine({row: row, column: 0}, indentString); + }; + + /** + * Outdents all the rows defined by the `start` and `end` properties of `range`. + * @param {Range} range A range of rows + * + * + **/ + this.outdentRows = function (range) { + var rowRange = range.collapseRows(); + var deleteRange = new Range(0, 0, 0, 0); + var size = this.getTabSize(); + + for (var i = rowRange.start.row; i <= rowRange.end.row; ++i) { + var line = this.getLine(i); + + deleteRange.start.row = i; + deleteRange.end.row = i; + for (var j = 0; j < size; ++j) + if (line.charAt(j) != ' ') + break; + if (j < size && line.charAt(j) == '\t') { + deleteRange.start.column = j; + deleteRange.end.column = j + 1; + } else { + deleteRange.start.column = 0; + deleteRange.end.column = j; + } + this.remove(deleteRange); + } + }; + + this.$moveLines = function(firstRow, lastRow, dir) { + firstRow = this.getRowFoldStart(firstRow); + lastRow = this.getRowFoldEnd(lastRow); + if (dir < 0) { + var row = this.getRowFoldStart(firstRow + dir); + if (row < 0) return 0; + var diff = row-firstRow; + } else if (dir > 0) { + var row = this.getRowFoldEnd(lastRow + dir); + if (row > this.doc.getLength()-1) return 0; + var diff = row-lastRow; + } else { + firstRow = this.$clipRowToDocument(firstRow); + lastRow = this.$clipRowToDocument(lastRow); + var diff = lastRow - firstRow + 1; + } + + var range = new Range(firstRow, 0, lastRow, Number.MAX_VALUE); + var folds = this.getFoldsInRange(range).map(function(x){ + x = x.clone(); + x.start.row += diff; + x.end.row += diff; + return x; + }); + + var lines = dir == 0 + ? this.doc.getLines(firstRow, lastRow) + : this.doc.removeFullLines(firstRow, lastRow); + this.doc.insertFullLines(firstRow+diff, lines); + folds.length && this.addFolds(folds); + return diff; + }; + /** + * Shifts all the lines in the document up one, starting from `firstRow` and ending at `lastRow`. + * @param {Number} firstRow The starting row to move up + * @param {Number} lastRow The final row to move up + * @returns {Number} If `firstRow` is less-than or equal to 0, this function returns 0. Otherwise, on success, it returns -1. + * + **/ + this.moveLinesUp = function(firstRow, lastRow) { + return this.$moveLines(firstRow, lastRow, -1); + }; + + /** + * Shifts all the lines in the document down one, starting from `firstRow` and ending at `lastRow`. + * @param {Number} firstRow The starting row to move down + * @param {Number} lastRow The final row to move down + * @returns {Number} If `firstRow` is less-than or equal to 0, this function returns 0. Otherwise, on success, it returns -1. + **/ + this.moveLinesDown = function(firstRow, lastRow) { + return this.$moveLines(firstRow, lastRow, 1); + }; + + /** + * Duplicates all the text between `firstRow` and `lastRow`. + * @param {Number} firstRow The starting row to duplicate + * @param {Number} lastRow The final row to duplicate + * @returns {Number} Returns the number of new rows added; in other words, `lastRow - firstRow + 1`. + * + * + **/ + this.duplicateLines = function(firstRow, lastRow) { + return this.$moveLines(firstRow, lastRow, 0); + }; + + + this.$clipRowToDocument = function(row) { + return Math.max(0, Math.min(row, this.doc.getLength()-1)); + }; + + this.$clipColumnToRow = function(row, column) { + if (column < 0) + return 0; + return Math.min(this.doc.getLine(row).length, column); + }; + + + this.$clipPositionToDocument = function(row, column) { + column = Math.max(0, column); + + if (row < 0) { + row = 0; + column = 0; + } else { + var len = this.doc.getLength(); + if (row >= len) { + row = len - 1; + column = this.doc.getLine(len-1).length; + } else { + column = Math.min(this.doc.getLine(row).length, column); + } + } + + return { + row: row, + column: column + }; + }; + + this.$clipRangeToDocument = function(range) { + if (range.start.row < 0) { + range.start.row = 0; + range.start.column = 0; + } else { + range.start.column = this.$clipColumnToRow( + range.start.row, + range.start.column + ); + } + + var len = this.doc.getLength() - 1; + if (range.end.row > len) { + range.end.row = len; + range.end.column = this.doc.getLine(len).length; + } else { + range.end.column = this.$clipColumnToRow( + range.end.row, + range.end.column + ); + } + return range; + }; + + // WRAPMODE + this.$wrapLimit = 80; + this.$useWrapMode = false; + this.$wrapLimitRange = { + min : null, + max : null + }; + + /** + * Sets whether or not line wrapping is enabled. If `useWrapMode` is different than the current value, the `'changeWrapMode'` event is emitted. + * @param {Boolean} useWrapMode Enable (or disable) wrap mode + * + * + **/ + this.setUseWrapMode = function(useWrapMode) { + if (useWrapMode != this.$useWrapMode) { + this.$useWrapMode = useWrapMode; + this.$modified = true; + this.$resetRowCache(0); + + // If wrapMode is activaed, the wrapData array has to be initialized. + if (useWrapMode) { + var len = this.getLength(); + this.$wrapData = Array(len); + this.$updateWrapData(0, len - 1); + } + + this._signal("changeWrapMode"); + } + }; + + /** + * Returns `true` if wrap mode is being used; `false` otherwise. + * @returns {Boolean} + **/ + this.getUseWrapMode = function() { + return this.$useWrapMode; + }; + + // Allow the wrap limit to move freely between min and max. Either + // parameter can be null to allow the wrap limit to be unconstrained + // in that direction. Or set both parameters to the same number to pin + // the limit to that value. + /** + * Sets the boundaries of wrap. Either value can be `null` to have an unconstrained wrap, or, they can be the same number to pin the limit. If the wrap limits for `min` or `max` are different, this method also emits the `'changeWrapMode'` event. + * @param {Number} min The minimum wrap value (the left side wrap) + * @param {Number} max The maximum wrap value (the right side wrap) + * + * + **/ + this.setWrapLimitRange = function(min, max) { + if (this.$wrapLimitRange.min !== min || this.$wrapLimitRange.max !== max) { + this.$wrapLimitRange = { min: min, max: max }; + this.$modified = true; + // This will force a recalculation of the wrap limit + if (this.$useWrapMode) + this._signal("changeWrapMode"); + } + }; + + /** + * This should generally only be called by the renderer when a resize is detected. + * @param {Number} desiredLimit The new wrap limit + * @returns {Boolean} + * + * @private + **/ + this.adjustWrapLimit = function(desiredLimit, $printMargin) { + var limits = this.$wrapLimitRange; + if (limits.max < 0) + limits = {min: $printMargin, max: $printMargin}; + var wrapLimit = this.$constrainWrapLimit(desiredLimit, limits.min, limits.max); + if (wrapLimit != this.$wrapLimit && wrapLimit > 1) { + this.$wrapLimit = wrapLimit; + this.$modified = true; + if (this.$useWrapMode) { + this.$updateWrapData(0, this.getLength() - 1); + this.$resetRowCache(0); + this._signal("changeWrapLimit"); + } + return true; + } + return false; + }; + + this.$constrainWrapLimit = function(wrapLimit, min, max) { + if (min) + wrapLimit = Math.max(min, wrapLimit); + + if (max) + wrapLimit = Math.min(max, wrapLimit); + + return wrapLimit; + }; + + /** + * Returns the value of wrap limit. + * @returns {Number} The wrap limit. + **/ + this.getWrapLimit = function() { + return this.$wrapLimit; + }; + + /** + * Sets the line length for soft wrap in the editor. Lines will break + * at a minimum of the given length minus 20 chars and at a maximum + * of the given number of chars. + * @param {number} limit The maximum line length in chars, for soft wrapping lines. + */ + this.setWrapLimit = function (limit) { + this.setWrapLimitRange(limit, limit); + }; + + /** + * Returns an object that defines the minimum and maximum of the wrap limit; it looks something like this: + * + * { min: wrapLimitRange_min, max: wrapLimitRange_max } + * + * @returns {Object} + **/ + this.getWrapLimitRange = function() { + // Avoid unexpected mutation by returning a copy + return { + min : this.$wrapLimitRange.min, + max : this.$wrapLimitRange.max + }; + }; + + this.$updateInternalDataOnChange = function(delta) { + var useWrapMode = this.$useWrapMode; + var action = delta.action; + var start = delta.start; + var end = delta.end; + var firstRow = start.row; + var lastRow = end.row; + var len = lastRow - firstRow; + var removedFolds = null; + + this.$updating = true; + if (len != 0) { + if (action === "remove") { + this[useWrapMode ? "$wrapData" : "$rowLengthCache"].splice(firstRow, len); + + var foldLines = this.$foldData; + removedFolds = this.getFoldsInRange(delta); + this.removeFolds(removedFolds); + + var foldLine = this.getFoldLine(end.row); + var idx = 0; + if (foldLine) { + foldLine.addRemoveChars(end.row, end.column, start.column - end.column); + foldLine.shiftRow(-len); + + var foldLineBefore = this.getFoldLine(firstRow); + if (foldLineBefore && foldLineBefore !== foldLine) { + foldLineBefore.merge(foldLine); + foldLine = foldLineBefore; + } + idx = foldLines.indexOf(foldLine) + 1; + } + + for (idx; idx < foldLines.length; idx++) { + var foldLine = foldLines[idx]; + if (foldLine.start.row >= end.row) { + foldLine.shiftRow(-len); + } + } + + lastRow = firstRow; + } else { + var args = Array(len); + args.unshift(firstRow, 0); + var arr = useWrapMode ? this.$wrapData : this.$rowLengthCache + arr.splice.apply(arr, args); + + // If some new line is added inside of a foldLine, then split + // the fold line up. + var foldLines = this.$foldData; + var foldLine = this.getFoldLine(firstRow); + var idx = 0; + if (foldLine) { + var cmp = foldLine.range.compareInside(start.row, start.column); + // Inside of the foldLine range. Need to split stuff up. + if (cmp == 0) { + foldLine = foldLine.split(start.row, start.column); + if (foldLine) { + foldLine.shiftRow(len); + foldLine.addRemoveChars(lastRow, 0, end.column - start.column); + } + } else + // Infront of the foldLine but same row. Need to shift column. + if (cmp == -1) { + foldLine.addRemoveChars(firstRow, 0, end.column - start.column); + foldLine.shiftRow(len); + } + // Nothing to do if the insert is after the foldLine. + idx = foldLines.indexOf(foldLine) + 1; + } + + for (idx; idx < foldLines.length; idx++) { + var foldLine = foldLines[idx]; + if (foldLine.start.row >= firstRow) { + foldLine.shiftRow(len); + } + } + } + } else { + // Realign folds. E.g. if you add some new chars before a fold, the + // fold should "move" to the right. + len = Math.abs(delta.start.column - delta.end.column); + if (action === "remove") { + // Get all the folds in the change range and remove them. + removedFolds = this.getFoldsInRange(delta); + this.removeFolds(removedFolds); + + len = -len; + } + var foldLine = this.getFoldLine(firstRow); + if (foldLine) { + foldLine.addRemoveChars(firstRow, start.column, len); + } + } + + if (useWrapMode && this.$wrapData.length != this.doc.getLength()) { + console.error("doc.getLength() and $wrapData.length have to be the same!"); + } + this.$updating = false; + + if (useWrapMode) + this.$updateWrapData(firstRow, lastRow); + else + this.$updateRowLengthCache(firstRow, lastRow); + + return removedFolds; + }; + + this.$updateRowLengthCache = function(firstRow, lastRow, b) { + this.$rowLengthCache[firstRow] = null; + this.$rowLengthCache[lastRow] = null; + }; + + this.$updateWrapData = function(firstRow, lastRow) { + var lines = this.doc.getAllLines(); + var tabSize = this.getTabSize(); + var wrapData = this.$wrapData; + var wrapLimit = this.$wrapLimit; + var tokens; + var foldLine; + + var row = firstRow; + lastRow = Math.min(lastRow, lines.length - 1); + while (row <= lastRow) { + foldLine = this.getFoldLine(row, foldLine); + if (!foldLine) { + tokens = this.$getDisplayTokens(lines[row]); + wrapData[row] = this.$computeWrapSplits(tokens, wrapLimit, tabSize); + row ++; + } else { + tokens = []; + foldLine.walk(function(placeholder, row, column, lastColumn) { + var walkTokens; + if (placeholder != null) { + walkTokens = this.$getDisplayTokens( + placeholder, tokens.length); + walkTokens[0] = PLACEHOLDER_START; + for (var i = 1; i < walkTokens.length; i++) { + walkTokens[i] = PLACEHOLDER_BODY; + } + } else { + walkTokens = this.$getDisplayTokens( + lines[row].substring(lastColumn, column), + tokens.length); + } + tokens = tokens.concat(walkTokens); + }.bind(this), + foldLine.end.row, + lines[foldLine.end.row].length + 1 + ); + + wrapData[foldLine.start.row] = this.$computeWrapSplits(tokens, wrapLimit, tabSize); + row = foldLine.end.row + 1; + } + } + }; + + // "Tokens" + var CHAR = 1, + CHAR_EXT = 2, + PLACEHOLDER_START = 3, + PLACEHOLDER_BODY = 4, + PUNCTUATION = 9, + SPACE = 10, + TAB = 11, + TAB_SPACE = 12; + + + this.$computeWrapSplits = function(tokens, wrapLimit) { + if (tokens.length == 0) { + return []; + } + + var splits = []; + var displayLength = tokens.length; + var lastSplit = 0, lastDocSplit = 0; + + var isCode = this.$wrapAsCode; + + function addSplit(screenPos) { + var displayed = tokens.slice(lastSplit, screenPos); + + // The document size is the current size - the extra width for tabs + // and multipleWidth characters. + var len = displayed.length; + displayed.join(""). + // Get all the TAB_SPACEs. + replace(/12/g, function() { + len -= 1; + }). + // Get all the CHAR_EXT/multipleWidth characters. + replace(/2/g, function() { + len -= 1; + }); + + lastDocSplit += len; + splits.push(lastDocSplit); + lastSplit = screenPos; + } + + while (displayLength - lastSplit > wrapLimit) { + // This is, where the split should be. + var split = lastSplit + wrapLimit; + + // If there is a space or tab at this split position, then making + // a split is simple. + if (tokens[split - 1] >= SPACE && tokens[split] >= SPACE) { + /* disabled see https://github.com/ajaxorg/ace/issues/1186 + // Include all following spaces + tabs in this split as well. + while (tokens[split] >= SPACE) { + split ++; + } */ + addSplit(split); + continue; + } + + // === ELSE === + // Check if split is inside of a placeholder. Placeholder are + // not splitable. Therefore, seek the beginning of the placeholder + // and try to place the split beofre the placeholder's start. + if (tokens[split] == PLACEHOLDER_START || tokens[split] == PLACEHOLDER_BODY) { + // Seek the start of the placeholder and do the split + // before the placeholder. By definition there always + // a PLACEHOLDER_START between split and lastSplit. + for (split; split != lastSplit - 1; split--) { + if (tokens[split] == PLACEHOLDER_START) { + // split++; << No incremental here as we want to + // have the position before the Placeholder. + break; + } + } + + // If the PLACEHOLDER_START is not the index of the + // last split, then we can do the split + if (split > lastSplit) { + addSplit(split); + continue; + } + + // If the PLACEHOLDER_START IS the index of the last + // split, then we have to place the split after the + // placeholder. So, let's seek for the end of the placeholder. + split = lastSplit + wrapLimit; + for (split; split < tokens.length; split++) { + if (tokens[split] != PLACEHOLDER_BODY) { + break; + } + } + + // If spilt == tokens.length, then the placeholder is the last + // thing in the line and adding a new split doesn't make sense. + if (split == tokens.length) { + break; // Breaks the while-loop. + } + + // Finally, add the split... + addSplit(split); + continue; + } + + // === ELSE === + // Search for the first non space/tab/placeholder/punctuation token backwards. + var minSplit = Math.max(split - (isCode ? 10 : wrapLimit-(wrapLimit>>2)), lastSplit - 1); + while (split > minSplit && tokens[split] < PLACEHOLDER_START) { + split --; + } + if (isCode) { + while (split > minSplit && tokens[split] < PLACEHOLDER_START) { + split --; + } + while (split > minSplit && tokens[split] == PUNCTUATION) { + split --; + } + } else { + while (split > minSplit && tokens[split] < SPACE) { + split --; + } + } + // If we found one, then add the split. + if (split > minSplit) { + addSplit(++split); + continue; + } + + // === ELSE === + split = lastSplit + wrapLimit; + // The split is inside of a CHAR or CHAR_EXT token and no space + // around -> force a split. + if (tokens[split] == CHAR_EXT) + split--; + addSplit(split); + } + return splits; + }; + + /** + * Given a string, returns an array of the display characters, including tabs and spaces. + * @param {String} str The string to check + * @param {Number} offset The value to start at + * + * + **/ + this.$getDisplayTokens = function(str, offset) { + var arr = []; + var tabSize; + offset = offset || 0; + + for (var i = 0; i < str.length; i++) { + var c = str.charCodeAt(i); + // Tab + if (c == 9) { + tabSize = this.getScreenTabSize(arr.length + offset); + arr.push(TAB); + for (var n = 1; n < tabSize; n++) { + arr.push(TAB_SPACE); + } + } + // Space + else if (c == 32) { + arr.push(SPACE); + } else if((c > 39 && c < 48) || (c > 57 && c < 64)) { + arr.push(PUNCTUATION); + } + // full width characters + else if (c >= 0x1100 && isFullWidth(c)) { + arr.push(CHAR, CHAR_EXT); + } else { + arr.push(CHAR); + } + } + return arr; + }; + + /** + * Calculates the width of the string `str` on the screen while assuming that the string starts at the first column on the screen. + * @param {String} str The string to calculate the screen width of + * @param {Number} maxScreenColumn + * @param {Number} screenColumn + * @returns {[Number]} Returns an `int[]` array with two elements:
      + * The first position indicates the number of columns for `str` on screen.
      + * The second value contains the position of the document column that this function read until. + * + **/ + this.$getStringScreenWidth = function(str, maxScreenColumn, screenColumn) { + if (maxScreenColumn == 0) + return [0, 0]; + if (maxScreenColumn == null) + maxScreenColumn = Infinity; + screenColumn = screenColumn || 0; + + var c, column; + for (column = 0; column < str.length; column++) { + c = str.charCodeAt(column); + // tab + if (c == 9) { + screenColumn += this.getScreenTabSize(screenColumn); + } + // full width characters + else if (c >= 0x1100 && isFullWidth(c)) { + screenColumn += 2; + } else { + screenColumn += 1; + } + if (screenColumn > maxScreenColumn) { + break; + } + } + + return [screenColumn, column]; + }; + + this.lineWidgets = null; + /** + * Returns number of screenrows in a wrapped line. + * @param {Number} row The row number to check + * + * @returns {Number} + **/ + this.getRowLength = function(row) { + if (this.lineWidgets) + var h = this.lineWidgets[row] && this.lineWidgets[row].rowCount || 0; + else + h = 0 + if (!this.$useWrapMode || !this.$wrapData[row]) { + return 1 + h; + } else { + return this.$wrapData[row].length + 1 + h; + } + }; + this.getRowLineCount = function(row) { + if (!this.$useWrapMode || !this.$wrapData[row]) { + return 1; + } else { + return this.$wrapData[row].length + 1; + } + }; + + /** + * Returns the position (on screen) for the last character in the provided screen row. + * @param {Number} screenRow The screen row to check + * @returns {Number} + * + * @related EditSession.documentToScreenColumn + **/ + this.getScreenLastRowColumn = function(screenRow) { + var pos = this.screenToDocumentPosition(screenRow, Number.MAX_VALUE); + return this.documentToScreenColumn(pos.row, pos.column); + }; + + /** + * For the given document row and column, this returns the column position of the last screen row. + * @param {Number} docRow + * + * @param {Number} docColumn + **/ + this.getDocumentLastRowColumn = function(docRow, docColumn) { + var screenRow = this.documentToScreenRow(docRow, docColumn); + return this.getScreenLastRowColumn(screenRow); + }; + + /** + * For the given document row and column, this returns the document position of the last row. + * @param {Number} docRow + * @param {Number} docColumn + * + * + **/ + this.getDocumentLastRowColumnPosition = function(docRow, docColumn) { + var screenRow = this.documentToScreenRow(docRow, docColumn); + return this.screenToDocumentPosition(screenRow, Number.MAX_VALUE / 10); + }; + + /** + * For the given row, this returns the split data. + * @returns {String} + **/ + this.getRowSplitData = function(row) { + if (!this.$useWrapMode) { + return undefined; + } else { + return this.$wrapData[row]; + } + }; + + /** + * The distance to the next tab stop at the specified screen column. + * @param {Number} screenColumn The screen column to check + * + * + * @returns {Number} + **/ + this.getScreenTabSize = function(screenColumn) { + return this.$tabSize - screenColumn % this.$tabSize; + }; + + + this.screenToDocumentRow = function(screenRow, screenColumn) { + return this.screenToDocumentPosition(screenRow, screenColumn).row; + }; + + + this.screenToDocumentColumn = function(screenRow, screenColumn) { + return this.screenToDocumentPosition(screenRow, screenColumn).column; + }; + + /** + * Converts characters coordinates on the screen to characters coordinates within the document. [This takes into account code folding, word wrap, tab size, and any other visual modifications.]{: #conversionConsiderations} + * @param {Number} screenRow The screen row to check + * @param {Number} screenColumn The screen column to check + * @returns {Object} The object returned has two properties: `row` and `column`. + * + * + * @related EditSession.documentToScreenPosition + * + **/ + this.screenToDocumentPosition = function(screenRow, screenColumn) { + if (screenRow < 0) + return {row: 0, column: 0}; + + var line; + var docRow = 0; + var docColumn = 0; + var column; + var row = 0; + var rowLength = 0; + + var rowCache = this.$screenRowCache; + var i = this.$getRowCacheIndex(rowCache, screenRow); + var l = rowCache.length; + if (l && i >= 0) { + var row = rowCache[i]; + var docRow = this.$docRowCache[i]; + var doCache = screenRow > rowCache[l - 1]; + } else { + var doCache = !l; + } + + var maxRow = this.getLength() - 1; + var foldLine = this.getNextFoldLine(docRow); + var foldStart = foldLine ? foldLine.start.row : Infinity; + + while (row <= screenRow) { + rowLength = this.getRowLength(docRow); + if (row + rowLength > screenRow || docRow >= maxRow) { + break; + } else { + row += rowLength; + docRow++; + if (docRow > foldStart) { + docRow = foldLine.end.row+1; + foldLine = this.getNextFoldLine(docRow, foldLine); + foldStart = foldLine ? foldLine.start.row : Infinity; + } + } + + if (doCache) { + this.$docRowCache.push(docRow); + this.$screenRowCache.push(row); + } + } + + if (foldLine && foldLine.start.row <= docRow) { + line = this.getFoldDisplayLine(foldLine); + docRow = foldLine.start.row; + } else if (row + rowLength <= screenRow || docRow > maxRow) { + // clip at the end of the document + return { + row: maxRow, + column: this.getLine(maxRow).length + }; + } else { + line = this.getLine(docRow); + foldLine = null; + } + + if (this.$useWrapMode) { + var splits = this.$wrapData[docRow]; + if (splits) { + var splitIndex = Math.floor(screenRow - row); + column = splits[splitIndex]; + if(splitIndex > 0 && splits.length) { + docColumn = splits[splitIndex - 1] || splits[splits.length - 1]; + line = line.substring(docColumn); + } + } + } + + docColumn += this.$getStringScreenWidth(line, screenColumn)[1]; + + // We remove one character at the end so that the docColumn + // position returned is not associated to the next row on the screen. + if (this.$useWrapMode && docColumn >= column) + docColumn = column - 1; + + if (foldLine) + return foldLine.idxToPosition(docColumn); + + return {row: docRow, column: docColumn}; + }; + + /** + * Converts document coordinates to screen coordinates. {:conversionConsiderations} + * @param {Number} docRow The document row to check + * @param {Number} docColumn The document column to check + * @returns {Object} The object returned by this method has two properties: `row` and `column`. + * + * + * @related EditSession.screenToDocumentPosition + * + **/ + this.documentToScreenPosition = function(docRow, docColumn) { + // Normalize the passed in arguments. + if (typeof docColumn === "undefined") + var pos = this.$clipPositionToDocument(docRow.row, docRow.column); + else + pos = this.$clipPositionToDocument(docRow, docColumn); + + docRow = pos.row; + docColumn = pos.column; + + var screenRow = 0; + var foldStartRow = null; + var fold = null; + + // Clamp the docRow position in case it's inside of a folded block. + fold = this.getFoldAt(docRow, docColumn, 1); + if (fold) { + docRow = fold.start.row; + docColumn = fold.start.column; + } + + var rowEnd, row = 0; + + + var rowCache = this.$docRowCache; + var i = this.$getRowCacheIndex(rowCache, docRow); + var l = rowCache.length; + if (l && i >= 0) { + var row = rowCache[i]; + var screenRow = this.$screenRowCache[i]; + var doCache = docRow > rowCache[l - 1]; + } else { + var doCache = !l; + } + + var foldLine = this.getNextFoldLine(row); + var foldStart = foldLine ?foldLine.start.row :Infinity; + + while (row < docRow) { + if (row >= foldStart) { + rowEnd = foldLine.end.row + 1; + if (rowEnd > docRow) + break; + foldLine = this.getNextFoldLine(rowEnd, foldLine); + foldStart = foldLine ?foldLine.start.row :Infinity; + } + else { + rowEnd = row + 1; + } + + screenRow += this.getRowLength(row); + row = rowEnd; + + if (doCache) { + this.$docRowCache.push(row); + this.$screenRowCache.push(screenRow); + } + } + + // Calculate the text line that is displayed in docRow on the screen. + var textLine = ""; + // Check if the final row we want to reach is inside of a fold. + if (foldLine && row >= foldStart) { + textLine = this.getFoldDisplayLine(foldLine, docRow, docColumn); + foldStartRow = foldLine.start.row; + } else { + textLine = this.getLine(docRow).substring(0, docColumn); + foldStartRow = docRow; + } + // Clamp textLine if in wrapMode. + if (this.$useWrapMode) { + var wrapRow = this.$wrapData[foldStartRow]; + if (wrapRow) { + var screenRowOffset = 0; + while (textLine.length >= wrapRow[screenRowOffset]) { + screenRow ++; + screenRowOffset++; + } + textLine = textLine.substring( + wrapRow[screenRowOffset - 1] || 0, textLine.length + ); + } + } + + return { + row: screenRow, + column: this.$getStringScreenWidth(textLine)[0] + }; + }; + + /** + * For the given document row and column, returns the screen column. + * @param {Number} row + * @param {Number} docColumn + * @returns {Number} + * + **/ + this.documentToScreenColumn = function(row, docColumn) { + return this.documentToScreenPosition(row, docColumn).column; + }; + + /** + * For the given document row and column, returns the screen row. + * @param {Number} docRow + * @param {Number} docColumn + * + * + **/ + this.documentToScreenRow = function(docRow, docColumn) { + return this.documentToScreenPosition(docRow, docColumn).row; + }; + + /** + * Returns the length of the screen. + * @returns {Number} + **/ + this.getScreenLength = function() { + var screenRows = 0; + var fold = null; + if (!this.$useWrapMode) { + screenRows = this.getLength(); + + // Remove the folded lines again. + var foldData = this.$foldData; + for (var i = 0; i < foldData.length; i++) { + fold = foldData[i]; + screenRows -= fold.end.row - fold.start.row; + } + } else { + var lastRow = this.$wrapData.length; + var row = 0, i = 0; + var fold = this.$foldData[i++]; + var foldStart = fold ? fold.start.row :Infinity; + + while (row < lastRow) { + var splits = this.$wrapData[row]; + screenRows += splits ? splits.length + 1 : 1; + row ++; + if (row > foldStart) { + row = fold.end.row+1; + fold = this.$foldData[i++]; + foldStart = fold ?fold.start.row :Infinity; + } + } + } + + // todo + if (this.lineWidgets) + screenRows += this.$getWidgetScreenLength(); + + return screenRows; + }; + + /** + * @private + * + */ + this.$setFontMetrics = function(fm) { + this.$getStringScreenWidth = function(str, maxScreenColumn, screenColumn) { + if (maxScreenColumn === 0) + return [0, 0]; + if (!maxScreenColumn) + maxScreenColumn = Infinity; + screenColumn = screenColumn || 0; + + var c, column; + for (column = 0; column < str.length; column++) { + c = str.charAt(column); + // tab + if (c === "\t") { + screenColumn += this.getScreenTabSize(screenColumn); + } else { + screenColumn += fm.getCharacterWidth(c); + } + if (screenColumn > maxScreenColumn) { + break; + } + } + + return [screenColumn, column]; + }; + }; + + this.destroy = function() { + if (this.bgTokenizer) { + this.bgTokenizer.setDocument(null); + this.bgTokenizer = null; + } + this.$stopWorker(); + }; + + // For every keystroke this gets called once per char in the whole doc!! + // Wouldn't hurt to make it a bit faster for c >= 0x1100 + function isFullWidth(c) { + if (c < 0x1100) + return false; + return c >= 0x1100 && c <= 0x115F || + c >= 0x11A3 && c <= 0x11A7 || + c >= 0x11FA && c <= 0x11FF || + c >= 0x2329 && c <= 0x232A || + c >= 0x2E80 && c <= 0x2E99 || + c >= 0x2E9B && c <= 0x2EF3 || + c >= 0x2F00 && c <= 0x2FD5 || + c >= 0x2FF0 && c <= 0x2FFB || + c >= 0x3000 && c <= 0x303E || + c >= 0x3041 && c <= 0x3096 || + c >= 0x3099 && c <= 0x30FF || + c >= 0x3105 && c <= 0x312D || + c >= 0x3131 && c <= 0x318E || + c >= 0x3190 && c <= 0x31BA || + c >= 0x31C0 && c <= 0x31E3 || + c >= 0x31F0 && c <= 0x321E || + c >= 0x3220 && c <= 0x3247 || + c >= 0x3250 && c <= 0x32FE || + c >= 0x3300 && c <= 0x4DBF || + c >= 0x4E00 && c <= 0xA48C || + c >= 0xA490 && c <= 0xA4C6 || + c >= 0xA960 && c <= 0xA97C || + c >= 0xAC00 && c <= 0xD7A3 || + c >= 0xD7B0 && c <= 0xD7C6 || + c >= 0xD7CB && c <= 0xD7FB || + c >= 0xF900 && c <= 0xFAFF || + c >= 0xFE10 && c <= 0xFE19 || + c >= 0xFE30 && c <= 0xFE52 || + c >= 0xFE54 && c <= 0xFE66 || + c >= 0xFE68 && c <= 0xFE6B || + c >= 0xFF01 && c <= 0xFF60 || + c >= 0xFFE0 && c <= 0xFFE6; + }; + +}).call(EditSession.prototype); + +require("./edit_session/folding").Folding.call(EditSession.prototype); +require("./edit_session/bracket_match").BracketMatch.call(EditSession.prototype); + + +config.defineOptions(EditSession.prototype, "session", { + wrap: { + set: function(value) { + if (!value || value == "off") + value = false; + else if (value == "free") + value = true; + else if (value == "printMargin") + value = -1; + else if (typeof value == "string") + value = parseInt(value, 10) || false; + + if (this.$wrap == value) + return; + this.$wrap = value; + if (!value) { + this.setUseWrapMode(false); + } else { + var col = typeof value == "number" ? value : null; + this.setWrapLimitRange(col, col); + this.setUseWrapMode(true); + } + }, + get: function() { + if (this.getUseWrapMode()) { + if (this.$wrap == -1) + return "printMargin"; + if (!this.getWrapLimitRange().min) + return "free"; + return this.$wrap; + } + return "off"; + }, + handlesSet: true + }, + wrapMethod: { + // code|text|auto + set: function(val) { + val = val == "auto" + ? this.$mode.type != "text" + : val != "text"; + if (val != this.$wrapAsCode) { + this.$wrapAsCode = val; + if (this.$useWrapMode) { + this.$modified = true; + this.$resetRowCache(0); + this.$updateWrapData(0, this.getLength() - 1); + } + } + }, + initialValue: "auto" + }, + firstLineNumber: { + set: function() {this._signal("changeBreakpoint");}, + initialValue: 1 + }, + useWorker: { + set: function(useWorker) { + this.$useWorker = useWorker; + + this.$stopWorker(); + if (useWorker) + this.$startWorker(); + }, + initialValue: true + }, + useSoftTabs: {initialValue: true}, + tabSize: { + set: function(tabSize) { + if (isNaN(tabSize) || this.$tabSize === tabSize) return; + + this.$modified = true; + this.$rowLengthCache = []; + this.$tabSize = tabSize; + this._signal("changeTabSize"); + }, + initialValue: 4, + handlesSet: true + }, + overwrite: { + set: function(val) {this._signal("changeOverwrite");}, + initialValue: false + }, + newLineMode: { + set: function(val) {this.doc.setNewLineMode(val)}, + get: function() {return this.doc.getNewLineMode()}, + handlesSet: true + }, + mode: { + set: function(val) { this.setMode(val) }, + get: function() { return this.$modeId } + } +}); + +exports.EditSession = EditSession; +}); diff --git a/node_modules/ace/lib/ace/edit_session/bracket_match.js b/node_modules/ace/lib/ace/edit_session/bracket_match.js new file mode 100644 index 00000000..064ee3dc --- /dev/null +++ b/node_modules/ace/lib/ace/edit_session/bracket_match.js @@ -0,0 +1,221 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var TokenIterator = require("../token_iterator").TokenIterator; +var Range = require("../range").Range; + + +function BracketMatch() { + + this.findMatchingBracket = function(position, chr) { + if (position.column == 0) return null; + + var charBeforeCursor = chr || this.getLine(position.row).charAt(position.column-1); + if (charBeforeCursor == "") return null; + + var match = charBeforeCursor.match(/([\(\[\{])|([\)\]\}])/); + if (!match) + return null; + + if (match[1]) + return this.$findClosingBracket(match[1], position); + else + return this.$findOpeningBracket(match[2], position); + }; + + this.getBracketRange = function(pos) { + var line = this.getLine(pos.row); + var before = true, range; + + var chr = line.charAt(pos.column-1); + var match = chr && chr.match(/([\(\[\{])|([\)\]\}])/); + if (!match) { + chr = line.charAt(pos.column); + pos = {row: pos.row, column: pos.column + 1}; + match = chr && chr.match(/([\(\[\{])|([\)\]\}])/); + before = false; + } + if (!match) + return null; + + if (match[1]) { + var bracketPos = this.$findClosingBracket(match[1], pos); + if (!bracketPos) + return null; + range = Range.fromPoints(pos, bracketPos); + if (!before) { + range.end.column++; + range.start.column--; + } + range.cursor = range.end; + } else { + var bracketPos = this.$findOpeningBracket(match[2], pos); + if (!bracketPos) + return null; + range = Range.fromPoints(bracketPos, pos); + if (!before) { + range.start.column++; + range.end.column--; + } + range.cursor = range.start; + } + + return range; + }; + + this.$brackets = { + ")": "(", + "(": ")", + "]": "[", + "[": "]", + "{": "}", + "}": "{" + }; + + this.$findOpeningBracket = function(bracket, position, typeRe) { + var openBracket = this.$brackets[bracket]; + var depth = 1; + + var iterator = new TokenIterator(this, position.row, position.column); + var token = iterator.getCurrentToken(); + if (!token) + token = iterator.stepForward(); + if (!token) + return; + + if (!typeRe){ + typeRe = new RegExp( + "(\\.?" + + token.type.replace(".", "\\.").replace("rparen", ".paren") + .replace(/\b(?:end|start|begin)\b/, "") + + ")+" + ); + } + + // Start searching in token, just before the character at position.column + var valueIndex = position.column - iterator.getCurrentTokenColumn() - 2; + var value = token.value; + + while (true) { + + while (valueIndex >= 0) { + var chr = value.charAt(valueIndex); + if (chr == openBracket) { + depth -= 1; + if (depth == 0) { + return {row: iterator.getCurrentTokenRow(), + column: valueIndex + iterator.getCurrentTokenColumn()}; + } + } + else if (chr == bracket) { + depth += 1; + } + valueIndex -= 1; + } + + // Scan backward through the document, looking for the next token + // whose type matches typeRe + do { + token = iterator.stepBackward(); + } while (token && !typeRe.test(token.type)); + + if (token == null) + break; + + value = token.value; + valueIndex = value.length - 1; + } + + return null; + }; + + this.$findClosingBracket = function(bracket, position, typeRe) { + var closingBracket = this.$brackets[bracket]; + var depth = 1; + + var iterator = new TokenIterator(this, position.row, position.column); + var token = iterator.getCurrentToken(); + if (!token) + token = iterator.stepForward(); + if (!token) + return; + + if (!typeRe){ + typeRe = new RegExp( + "(\\.?" + + token.type.replace(".", "\\.").replace("lparen", ".paren") + .replace(/\b(?:end|start|begin)\b/, "") + + ")+" + ); + } + + // Start searching in token, after the character at position.column + var valueIndex = position.column - iterator.getCurrentTokenColumn(); + + while (true) { + + var value = token.value; + var valueLength = value.length; + while (valueIndex < valueLength) { + var chr = value.charAt(valueIndex); + if (chr == closingBracket) { + depth -= 1; + if (depth == 0) { + return {row: iterator.getCurrentTokenRow(), + column: valueIndex + iterator.getCurrentTokenColumn()}; + } + } + else if (chr == bracket) { + depth += 1; + } + valueIndex += 1; + } + + // Scan forward through the document, looking for the next token + // whose type matches typeRe + do { + token = iterator.stepForward(); + } while (token && !typeRe.test(token.type)); + + if (token == null) + break; + + valueIndex = 0; + } + + return null; + }; +} +exports.BracketMatch = BracketMatch; + +}); diff --git a/node_modules/ace/lib/ace/edit_session/fold.js b/node_modules/ace/lib/ace/edit_session/fold.js new file mode 100644 index 00000000..232101bd --- /dev/null +++ b/node_modules/ace/lib/ace/edit_session/fold.js @@ -0,0 +1,140 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var Range = require("../range").Range; +var RangeList = require("../range_list").RangeList; +var oop = require("../lib/oop") +/* + * Simple fold-data struct. + **/ +var Fold = exports.Fold = function(range, placeholder) { + this.foldLine = null; + this.placeholder = placeholder; + this.range = range; + this.start = range.start; + this.end = range.end; + + this.sameRow = range.start.row == range.end.row; + this.subFolds = this.ranges = []; +}; + +oop.inherits(Fold, RangeList); + +(function() { + + this.toString = function() { + return '"' + this.placeholder + '" ' + this.range.toString(); + }; + + this.setFoldLine = function(foldLine) { + this.foldLine = foldLine; + this.subFolds.forEach(function(fold) { + fold.setFoldLine(foldLine); + }); + }; + + this.clone = function() { + var range = this.range.clone(); + var fold = new Fold(range, this.placeholder); + this.subFolds.forEach(function(subFold) { + fold.subFolds.push(subFold.clone()); + }); + fold.collapseChildren = this.collapseChildren; + return fold; + }; + + this.addSubFold = function(fold) { + if (this.range.isEqual(fold)) + return; + + if (!this.range.containsRange(fold)) + throw new Error("A fold can't intersect already existing fold" + fold.range + this.range); + + // transform fold to local coordinates + consumeRange(fold, this.start); + + var row = fold.start.row, column = fold.start.column; + for (var i = 0, cmp = -1; i < this.subFolds.length; i++) { + cmp = this.subFolds[i].range.compare(row, column); + if (cmp != 1) + break; + } + var afterStart = this.subFolds[i]; + + if (cmp == 0) + return afterStart.addSubFold(fold); + + // cmp == -1 + var row = fold.range.end.row, column = fold.range.end.column; + for (var j = i, cmp = -1; j < this.subFolds.length; j++) { + cmp = this.subFolds[j].range.compare(row, column); + if (cmp != 1) + break; + } + var afterEnd = this.subFolds[j]; + + if (cmp == 0) + throw new Error("A fold can't intersect already existing fold" + fold.range + this.range); + + var consumedFolds = this.subFolds.splice(i, j - i, fold); + fold.setFoldLine(this.foldLine); + + return fold; + }; + + this.restoreRange = function(range) { + return restoreRange(range, this.start); + }; + +}).call(Fold.prototype); + +function consumePoint(point, anchor) { + point.row -= anchor.row; + if (point.row == 0) + point.column -= anchor.column; +} +function consumeRange(range, anchor) { + consumePoint(range.start, anchor); + consumePoint(range.end, anchor); +} +function restorePoint(point, anchor) { + if (point.row == 0) + point.column += anchor.column; + point.row += anchor.row; +} +function restoreRange(range, anchor) { + restorePoint(range.start, anchor); + restorePoint(range.end, anchor); +} + +}); diff --git a/node_modules/ace/lib/ace/edit_session/fold_line.js b/node_modules/ace/lib/ace/edit_session/fold_line.js new file mode 100644 index 00000000..9d73154d --- /dev/null +++ b/node_modules/ace/lib/ace/edit_session/fold_line.js @@ -0,0 +1,269 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var Range = require("../range").Range; + +/* + * If an array is passed in, the folds are expected to be sorted already. + */ +function FoldLine(foldData, folds) { + this.foldData = foldData; + if (Array.isArray(folds)) { + this.folds = folds; + } else { + folds = this.folds = [ folds ]; + } + + var last = folds[folds.length - 1]; + this.range = new Range(folds[0].start.row, folds[0].start.column, + last.end.row, last.end.column); + this.start = this.range.start; + this.end = this.range.end; + + this.folds.forEach(function(fold) { + fold.setFoldLine(this); + }, this); +} + +(function() { + /* + * Note: This doesn't update wrapData! + */ + this.shiftRow = function(shift) { + this.start.row += shift; + this.end.row += shift; + this.folds.forEach(function(fold) { + fold.start.row += shift; + fold.end.row += shift; + }); + }; + + this.addFold = function(fold) { + if (fold.sameRow) { + if (fold.start.row < this.startRow || fold.endRow > this.endRow) { + throw new Error("Can't add a fold to this FoldLine as it has no connection"); + } + this.folds.push(fold); + this.folds.sort(function(a, b) { + return -a.range.compareEnd(b.start.row, b.start.column); + }); + if (this.range.compareEnd(fold.start.row, fold.start.column) > 0) { + this.end.row = fold.end.row; + this.end.column = fold.end.column; + } else if (this.range.compareStart(fold.end.row, fold.end.column) < 0) { + this.start.row = fold.start.row; + this.start.column = fold.start.column; + } + } else if (fold.start.row == this.end.row) { + this.folds.push(fold); + this.end.row = fold.end.row; + this.end.column = fold.end.column; + } else if (fold.end.row == this.start.row) { + this.folds.unshift(fold); + this.start.row = fold.start.row; + this.start.column = fold.start.column; + } else { + throw new Error("Trying to add fold to FoldRow that doesn't have a matching row"); + } + fold.foldLine = this; + }; + + this.containsRow = function(row) { + return row >= this.start.row && row <= this.end.row; + }; + + this.walk = function(callback, endRow, endColumn) { + var lastEnd = 0, + folds = this.folds, + fold, + cmp, stop, isNewRow = true; + + if (endRow == null) { + endRow = this.end.row; + endColumn = this.end.column; + } + + for (var i = 0; i < folds.length; i++) { + fold = folds[i]; + + cmp = fold.range.compareStart(endRow, endColumn); + // This fold is after the endRow/Column. + if (cmp == -1) { + callback(null, endRow, endColumn, lastEnd, isNewRow); + return; + } + + stop = callback(null, fold.start.row, fold.start.column, lastEnd, isNewRow); + stop = !stop && callback(fold.placeholder, fold.start.row, fold.start.column, lastEnd); + + // If the user requested to stop the walk or endRow/endColumn is + // inside of this fold (cmp == 0), then end here. + if (stop || cmp === 0) { + return; + } + + // Note the new lastEnd might not be on the same line. However, + // it's the callback's job to recognize this. + isNewRow = !fold.sameRow; + lastEnd = fold.end.column; + } + callback(null, endRow, endColumn, lastEnd, isNewRow); + }; + + this.getNextFoldTo = function(row, column) { + var fold, cmp; + for (var i = 0; i < this.folds.length; i++) { + fold = this.folds[i]; + cmp = fold.range.compareEnd(row, column); + if (cmp == -1) { + return { + fold: fold, + kind: "after" + }; + } else if (cmp === 0) { + return { + fold: fold, + kind: "inside" + }; + } + } + return null; + }; + + this.addRemoveChars = function(row, column, len) { + var ret = this.getNextFoldTo(row, column), + fold, folds; + if (ret) { + fold = ret.fold; + if (ret.kind == "inside" + && fold.start.column != column + && fold.start.row != row) + { + //throwing here breaks whole editor + //TODO: properly handle this + window.console && window.console.log(row, column, fold); + } else if (fold.start.row == row) { + folds = this.folds; + var i = folds.indexOf(fold); + if (i === 0) { + this.start.column += len; + } + for (i; i < folds.length; i++) { + fold = folds[i]; + fold.start.column += len; + if (!fold.sameRow) { + return; + } + fold.end.column += len; + } + this.end.column += len; + } + } + }; + + this.split = function(row, column) { + var pos = this.getNextFoldTo(row, column); + + if (!pos || pos.kind == "inside") + return null; + + var fold = pos.fold; + var folds = this.folds; + var foldData = this.foldData; + + var i = folds.indexOf(fold); + var foldBefore = folds[i - 1]; + this.end.row = foldBefore.end.row; + this.end.column = foldBefore.end.column; + + // Remove the folds after row/column and create a new FoldLine + // containing these removed folds. + folds = folds.splice(i, folds.length - i); + + var newFoldLine = new FoldLine(foldData, folds); + foldData.splice(foldData.indexOf(this) + 1, 0, newFoldLine); + return newFoldLine; + }; + + this.merge = function(foldLineNext) { + var folds = foldLineNext.folds; + for (var i = 0; i < folds.length; i++) { + this.addFold(folds[i]); + } + // Remove the foldLineNext - no longer needed, as + // it's merged now with foldLineNext. + var foldData = this.foldData; + foldData.splice(foldData.indexOf(foldLineNext), 1); + }; + + this.toString = function() { + var ret = [this.range.toString() + ": [" ]; + + this.folds.forEach(function(fold) { + ret.push(" " + fold.toString()); + }); + ret.push("]"); + return ret.join("\n"); + }; + + this.idxToPosition = function(idx) { + var lastFoldEndColumn = 0; + + for (var i = 0; i < this.folds.length; i++) { + var fold = this.folds[i]; + + idx -= fold.start.column - lastFoldEndColumn; + if (idx < 0) { + return { + row: fold.start.row, + column: fold.start.column + idx + }; + } + + idx -= fold.placeholder.length; + if (idx < 0) { + return fold.start; + } + + lastFoldEndColumn = fold.end.column; + } + + return { + row: this.end.row, + column: this.end.column + idx + }; + }; +}).call(FoldLine.prototype); + +exports.FoldLine = FoldLine; +}); diff --git a/node_modules/ace/lib/ace/edit_session/folding.js b/node_modules/ace/lib/ace/edit_session/folding.js new file mode 100644 index 00000000..77c0f22d --- /dev/null +++ b/node_modules/ace/lib/ace/edit_session/folding.js @@ -0,0 +1,857 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var Range = require("../range").Range; +var FoldLine = require("./fold_line").FoldLine; +var Fold = require("./fold").Fold; +var TokenIterator = require("../token_iterator").TokenIterator; + +function Folding() { + /* + * Looks up a fold at a given row/column. Possible values for side: + * -1: ignore a fold if fold.start = row/column + * +1: ignore a fold if fold.end = row/column + */ + this.getFoldAt = function(row, column, side) { + var foldLine = this.getFoldLine(row); + if (!foldLine) + return null; + + var folds = foldLine.folds; + for (var i = 0; i < folds.length; i++) { + var fold = folds[i]; + if (fold.range.contains(row, column)) { + if (side == 1 && fold.range.isEnd(row, column)) { + continue; + } else if (side == -1 && fold.range.isStart(row, column)) { + continue; + } + return fold; + } + } + }; + + /* + * Returns all folds in the given range. Note, that this will return folds + * + */ + this.getFoldsInRange = function(range) { + var start = range.start; + var end = range.end; + var foldLines = this.$foldData; + var foundFolds = []; + + start.column += 1; + end.column -= 1; + + for (var i = 0; i < foldLines.length; i++) { + var cmp = foldLines[i].range.compareRange(range); + if (cmp == 2) { + // Range is before foldLine. No intersection. This means, + // there might be other foldLines that intersect. + continue; + } + else if (cmp == -2) { + // Range is after foldLine. There can't be any other foldLines then, + // so let's give up. + break; + } + + var folds = foldLines[i].folds; + for (var j = 0; j < folds.length; j++) { + var fold = folds[j]; + cmp = fold.range.compareRange(range); + if (cmp == -2) { + break; + } else if (cmp == 2) { + continue; + } else + // WTF-state: Can happen due to -1/+1 to start/end column. + if (cmp == 42) { + break; + } + foundFolds.push(fold); + } + } + start.column -= 1; + end.column += 1; + + return foundFolds; + }; + + this.getFoldsInRangeList = function(ranges) { + if (Array.isArray(ranges)) { + var folds = []; + ranges.forEach(function(range) { + folds = folds.concat(this.getFoldsInRange(range)); + }, this); + } else { + var folds = this.getFoldsInRange(ranges); + } + return folds; + } + + /* + * Returns all folds in the document + */ + this.getAllFolds = function() { + var folds = []; + var foldLines = this.$foldData; + + for (var i = 0; i < foldLines.length; i++) + for (var j = 0; j < foldLines[i].folds.length; j++) + folds.push(foldLines[i].folds[j]); + + return folds; + }; + + /* + * Returns the string between folds at the given position. + * E.g. + * foob|arwolrd -> "bar" + * foobarwol|rd -> "world" + * foobarwolrd -> + * + * where | means the position of row/column + * + * The trim option determs if the return string should be trimed according + * to the "side" passed with the trim value: + * + * E.g. + * foob|arwolrd -trim=-1> "b" + * foobarwol|rd -trim=+1> "rld" + * fo|obarwolrd -trim=00> "foo" + */ + this.getFoldStringAt = function(row, column, trim, foldLine) { + foldLine = foldLine || this.getFoldLine(row); + if (!foldLine) + return null; + + var lastFold = { + end: { column: 0 } + }; + // TODO: Refactor to use getNextFoldTo function. + var str, fold; + for (var i = 0; i < foldLine.folds.length; i++) { + fold = foldLine.folds[i]; + var cmp = fold.range.compareEnd(row, column); + if (cmp == -1) { + str = this + .getLine(fold.start.row) + .substring(lastFold.end.column, fold.start.column); + break; + } + else if (cmp === 0) { + return null; + } + lastFold = fold; + } + if (!str) + str = this.getLine(fold.start.row).substring(lastFold.end.column); + + if (trim == -1) + return str.substring(0, column - lastFold.end.column); + else if (trim == 1) + return str.substring(column - lastFold.end.column); + else + return str; + }; + + this.getFoldLine = function(docRow, startFoldLine) { + var foldData = this.$foldData; + var i = 0; + if (startFoldLine) + i = foldData.indexOf(startFoldLine); + if (i == -1) + i = 0; + for (i; i < foldData.length; i++) { + var foldLine = foldData[i]; + if (foldLine.start.row <= docRow && foldLine.end.row >= docRow) { + return foldLine; + } else if (foldLine.end.row > docRow) { + return null; + } + } + return null; + }; + + // returns the fold which starts after or contains docRow + this.getNextFoldLine = function(docRow, startFoldLine) { + var foldData = this.$foldData; + var i = 0; + if (startFoldLine) + i = foldData.indexOf(startFoldLine); + if (i == -1) + i = 0; + for (i; i < foldData.length; i++) { + var foldLine = foldData[i]; + if (foldLine.end.row >= docRow) { + return foldLine; + } + } + return null; + }; + + this.getFoldedRowCount = function(first, last) { + var foldData = this.$foldData, rowCount = last-first+1; + for (var i = 0; i < foldData.length; i++) { + var foldLine = foldData[i], + end = foldLine.end.row, + start = foldLine.start.row; + if (end >= last) { + if(start < last) { + if(start >= first) + rowCount -= last-start; + else + rowCount = 0;//in one fold + } + break; + } else if(end >= first){ + if (start >= first) //fold inside range + rowCount -= end-start; + else + rowCount -= end-first+1; + } + } + return rowCount; + }; + + this.$addFoldLine = function(foldLine) { + this.$foldData.push(foldLine); + this.$foldData.sort(function(a, b) { + return a.start.row - b.start.row; + }); + return foldLine; + }; + + /** + * Adds a new fold. + * + * @returns + * The new created Fold object or an existing fold object in case the + * passed in range fits an existing fold exactly. + */ + this.addFold = function(placeholder, range) { + var foldData = this.$foldData; + var added = false; + var fold; + + if (placeholder instanceof Fold) + fold = placeholder; + else { + fold = new Fold(range, placeholder); + fold.collapseChildren = range.collapseChildren; + } + this.$clipRangeToDocument(fold.range); + + var startRow = fold.start.row; + var startColumn = fold.start.column; + var endRow = fold.end.row; + var endColumn = fold.end.column; + + // --- Some checking --- + if (!(startRow < endRow || + startRow == endRow && startColumn <= endColumn - 2)) + throw new Error("The range has to be at least 2 characters width"); + + var startFold = this.getFoldAt(startRow, startColumn, 1); + var endFold = this.getFoldAt(endRow, endColumn, -1); + if (startFold && endFold == startFold) + return startFold.addSubFold(fold); + + if (startFold && !startFold.range.isStart(startRow, startColumn)) + this.removeFold(startFold); + + if (endFold && !endFold.range.isEnd(endRow, endColumn)) + this.removeFold(endFold); + + // Check if there are folds in the range we create the new fold for. + var folds = this.getFoldsInRange(fold.range); + if (folds.length > 0) { + // Remove the folds from fold data. + this.removeFolds(folds); + // Add the removed folds as subfolds on the new fold. + folds.forEach(function(subFold) { + fold.addSubFold(subFold); + }); + } + + for (var i = 0; i < foldData.length; i++) { + var foldLine = foldData[i]; + if (endRow == foldLine.start.row) { + foldLine.addFold(fold); + added = true; + break; + } else if (startRow == foldLine.end.row) { + foldLine.addFold(fold); + added = true; + if (!fold.sameRow) { + // Check if we might have to merge two FoldLines. + var foldLineNext = foldData[i + 1]; + if (foldLineNext && foldLineNext.start.row == endRow) { + // We need to merge! + foldLine.merge(foldLineNext); + break; + } + } + break; + } else if (endRow <= foldLine.start.row) { + break; + } + } + + if (!added) + foldLine = this.$addFoldLine(new FoldLine(this.$foldData, fold)); + + if (this.$useWrapMode) + this.$updateWrapData(foldLine.start.row, foldLine.start.row); + else + this.$updateRowLengthCache(foldLine.start.row, foldLine.start.row); + + // Notify that fold data has changed. + this.$modified = true; + this._emit("changeFold", { data: fold, action: "add" }); + + return fold; + }; + + this.addFolds = function(folds) { + folds.forEach(function(fold) { + this.addFold(fold); + }, this); + }; + + this.removeFold = function(fold) { + var foldLine = fold.foldLine; + var startRow = foldLine.start.row; + var endRow = foldLine.end.row; + + var foldLines = this.$foldData; + var folds = foldLine.folds; + // Simple case where there is only one fold in the FoldLine such that + // the entire fold line can get removed directly. + if (folds.length == 1) { + foldLines.splice(foldLines.indexOf(foldLine), 1); + } else + // If the fold is the last fold of the foldLine, just remove it. + if (foldLine.range.isEnd(fold.end.row, fold.end.column)) { + folds.pop(); + foldLine.end.row = folds[folds.length - 1].end.row; + foldLine.end.column = folds[folds.length - 1].end.column; + } else + // If the fold is the first fold of the foldLine, just remove it. + if (foldLine.range.isStart(fold.start.row, fold.start.column)) { + folds.shift(); + foldLine.start.row = folds[0].start.row; + foldLine.start.column = folds[0].start.column; + } else + // We know there are more then 2 folds and the fold is not at the edge. + // This means, the fold is somewhere in between. + // + // If the fold is in one row, we just can remove it. + if (fold.sameRow) { + folds.splice(folds.indexOf(fold), 1); + } else + // The fold goes over more then one row. This means remvoing this fold + // will cause the fold line to get splitted up. newFoldLine is the second part + { + var newFoldLine = foldLine.split(fold.start.row, fold.start.column); + folds = newFoldLine.folds; + folds.shift(); + newFoldLine.start.row = folds[0].start.row; + newFoldLine.start.column = folds[0].start.column; + } + + if (!this.$updating) { + if (this.$useWrapMode) + this.$updateWrapData(startRow, endRow); + else + this.$updateRowLengthCache(startRow, endRow); + } + + // Notify that fold data has changed. + this.$modified = true; + this._emit("changeFold", { data: fold, action: "remove" }); + }; + + this.removeFolds = function(folds) { + // We need to clone the folds array passed in as it might be the folds + // array of a fold line and as we call this.removeFold(fold), folds + // are removed from folds and changes the current index. + var cloneFolds = []; + for (var i = 0; i < folds.length; i++) { + cloneFolds.push(folds[i]); + } + + cloneFolds.forEach(function(fold) { + this.removeFold(fold); + }, this); + this.$modified = true; + }; + + this.expandFold = function(fold) { + this.removeFold(fold); + fold.subFolds.forEach(function(subFold) { + fold.restoreRange(subFold); + this.addFold(subFold); + }, this); + if (fold.collapseChildren > 0) { + this.foldAll(fold.start.row+1, fold.end.row, fold.collapseChildren-1); + } + fold.subFolds = []; + }; + + this.expandFolds = function(folds) { + folds.forEach(function(fold) { + this.expandFold(fold); + }, this); + }; + + this.unfold = function(location, expandInner) { + var range, folds; + if (location == null) { + range = new Range(0, 0, this.getLength(), 0); + expandInner = true; + } else if (typeof location == "number") + range = new Range(location, 0, location, this.getLine(location).length); + else if ("row" in location) + range = Range.fromPoints(location, location); + else + range = location; + + folds = this.getFoldsInRangeList(range); + if (expandInner) { + this.removeFolds(folds); + } else { + var subFolds = folds; + // TODO: might be better to remove and add folds in one go instead of using + // expandFolds several times. + while (subFolds.length) { + this.expandFolds(subFolds); + subFolds = this.getFoldsInRangeList(range); + } + } + if (folds.length) + return folds; + }; + + /* + * Checks if a given documentRow is folded. This is true if there are some + * folded parts such that some parts of the line is still visible. + **/ + this.isRowFolded = function(docRow, startFoldRow) { + return !!this.getFoldLine(docRow, startFoldRow); + }; + + this.getRowFoldEnd = function(docRow, startFoldRow) { + var foldLine = this.getFoldLine(docRow, startFoldRow); + return foldLine ? foldLine.end.row : docRow; + }; + + this.getRowFoldStart = function(docRow, startFoldRow) { + var foldLine = this.getFoldLine(docRow, startFoldRow); + return foldLine ? foldLine.start.row : docRow; + }; + + this.getFoldDisplayLine = function(foldLine, endRow, endColumn, startRow, startColumn) { + if (startRow == null) + startRow = foldLine.start.row; + if (startColumn == null) + startColumn = 0; + if (endRow == null) + endRow = foldLine.end.row; + if (endColumn == null) + endColumn = this.getLine(endRow).length; + + + // Build the textline using the FoldLine walker. + var doc = this.doc; + var textLine = ""; + + foldLine.walk(function(placeholder, row, column, lastColumn) { + if (row < startRow) + return; + if (row == startRow) { + if (column < startColumn) + return; + lastColumn = Math.max(startColumn, lastColumn); + } + + if (placeholder != null) { + textLine += placeholder; + } else { + textLine += doc.getLine(row).substring(lastColumn, column); + } + }, endRow, endColumn); + return textLine; + }; + + this.getDisplayLine = function(row, endColumn, startRow, startColumn) { + var foldLine = this.getFoldLine(row); + + if (!foldLine) { + var line; + line = this.doc.getLine(row); + return line.substring(startColumn || 0, endColumn || line.length); + } else { + return this.getFoldDisplayLine( + foldLine, row, endColumn, startRow, startColumn); + } + }; + + this.$cloneFoldData = function() { + var fd = []; + fd = this.$foldData.map(function(foldLine) { + var folds = foldLine.folds.map(function(fold) { + return fold.clone(); + }); + return new FoldLine(fd, folds); + }); + + return fd; + }; + + this.toggleFold = function(tryToUnfold) { + var selection = this.selection; + var range = selection.getRange(); + var fold; + var bracketPos; + + if (range.isEmpty()) { + var cursor = range.start; + fold = this.getFoldAt(cursor.row, cursor.column); + + if (fold) { + this.expandFold(fold); + return; + } else if (bracketPos = this.findMatchingBracket(cursor)) { + if (range.comparePoint(bracketPos) == 1) { + range.end = bracketPos; + } else { + range.start = bracketPos; + range.start.column++; + range.end.column--; + } + } else if (bracketPos = this.findMatchingBracket({row: cursor.row, column: cursor.column + 1})) { + if (range.comparePoint(bracketPos) == 1) + range.end = bracketPos; + else + range.start = bracketPos; + + range.start.column++; + } else { + range = this.getCommentFoldRange(cursor.row, cursor.column) || range; + } + } else { + var folds = this.getFoldsInRange(range); + if (tryToUnfold && folds.length) { + this.expandFolds(folds); + return; + } else if (folds.length == 1 ) { + fold = folds[0]; + } + } + + if (!fold) + fold = this.getFoldAt(range.start.row, range.start.column); + + if (fold && fold.range.toString() == range.toString()) { + this.expandFold(fold); + return; + } + + var placeholder = "..."; + if (!range.isMultiLine()) { + placeholder = this.getTextRange(range); + if(placeholder.length < 4) + return; + placeholder = placeholder.trim().substring(0, 2) + ".."; + } + + this.addFold(placeholder, range); + }; + + this.getCommentFoldRange = function(row, column, dir) { + var iterator = new TokenIterator(this, row, column); + var token = iterator.getCurrentToken(); + if (token && /^comment|string/.test(token.type)) { + var range = new Range(); + var re = new RegExp(token.type.replace(/\..*/, "\\.")); + if (dir != 1) { + do { + token = iterator.stepBackward(); + } while(token && re.test(token.type)); + iterator.stepForward(); + } + + range.start.row = iterator.getCurrentTokenRow(); + range.start.column = iterator.getCurrentTokenColumn() + 2; + + iterator = new TokenIterator(this, row, column); + + if (dir != -1) { + do { + token = iterator.stepForward(); + } while(token && re.test(token.type)); + token = iterator.stepBackward(); + } else + token = iterator.getCurrentToken(); + + range.end.row = iterator.getCurrentTokenRow(); + range.end.column = iterator.getCurrentTokenColumn() + token.value.length - 2; + return range; + } + }; + + this.foldAll = function(startRow, endRow, depth) { + if (depth == undefined) + depth = 100000; // JSON.stringify doesn't hanle Infinity + var foldWidgets = this.foldWidgets; + if (!foldWidgets) + return; // mode doesn't support folding + endRow = endRow || this.getLength(); + startRow = startRow || 0; + for (var row = startRow; row < endRow; row++) { + if (foldWidgets[row] == null) + foldWidgets[row] = this.getFoldWidget(row); + if (foldWidgets[row] != "start") + continue; + + var range = this.getFoldWidgetRange(row); + // sometimes range can be incompatible with existing fold + // TODO change addFold to return null istead of throwing + if (range && range.isMultiLine() + && range.end.row <= endRow + && range.start.row >= startRow + ) { + row = range.end.row; + try { + // addFold can change the range + var fold = this.addFold("...", range); + if (fold) + fold.collapseChildren = depth; + } catch(e) {} + } + } + }; + + // structured folding + this.$foldStyles = { + "manual": 1, + "markbegin": 1, + "markbeginend": 1 + }; + this.$foldStyle = "markbegin"; + this.setFoldStyle = function(style) { + if (!this.$foldStyles[style]) + throw new Error("invalid fold style: " + style + "[" + Object.keys(this.$foldStyles).join(", ") + "]"); + + if (this.$foldStyle == style) + return; + + this.$foldStyle = style; + + if (style == "manual") + this.unfold(); + + // reset folding + var mode = this.$foldMode; + this.$setFolding(null); + this.$setFolding(mode); + }; + + this.$setFolding = function(foldMode) { + if (this.$foldMode == foldMode) + return; + + this.$foldMode = foldMode; + + this.off('change', this.$updateFoldWidgets); + this.off('tokenizerUpdate', this.$tokenizerUpdateFoldWidgets); + this._emit("changeAnnotation"); + + if (!foldMode || this.$foldStyle == "manual") { + this.foldWidgets = null; + return; + } + + this.foldWidgets = []; + this.getFoldWidget = foldMode.getFoldWidget.bind(foldMode, this, this.$foldStyle); + this.getFoldWidgetRange = foldMode.getFoldWidgetRange.bind(foldMode, this, this.$foldStyle); + + this.$updateFoldWidgets = this.updateFoldWidgets.bind(this); + this.$tokenizerUpdateFoldWidgets = this.tokenizerUpdateFoldWidgets.bind(this); + this.on('change', this.$updateFoldWidgets); + this.on('tokenizerUpdate', this.$tokenizerUpdateFoldWidgets); + }; + + this.getParentFoldRangeData = function (row, ignoreCurrent) { + var fw = this.foldWidgets; + if (!fw || (ignoreCurrent && fw[row])) + return {}; + + var i = row - 1, firstRange; + while (i >= 0) { + var c = fw[i]; + if (c == null) + c = fw[i] = this.getFoldWidget(i); + + if (c == "start") { + var range = this.getFoldWidgetRange(i); + if (!firstRange) + firstRange = range; + if (range && range.end.row >= row) + break; + } + i--; + } + + return { + range: i !== -1 && range, + firstRange: firstRange + }; + } + + this.onFoldWidgetClick = function(row, e) { + e = e.domEvent; + var options = { + children: e.shiftKey, + all: e.ctrlKey || e.metaKey, + siblings: e.altKey + }; + + var range = this.$toggleFoldWidget(row, options); + if (!range) { + var el = (e.target || e.srcElement) + if (el && /ace_fold-widget/.test(el.className)) + el.className += " ace_invalid"; + } + }; + + this.$toggleFoldWidget = function(row, options) { + if (!this.getFoldWidget) + return; + var type = this.getFoldWidget(row); + var line = this.getLine(row); + + var dir = type === "end" ? -1 : 1; + var fold = this.getFoldAt(row, dir === -1 ? 0 : line.length, dir); + + if (fold) { + if (options.children || options.all) + this.removeFold(fold); + else + this.expandFold(fold); + return; + } + + var range = this.getFoldWidgetRange(row, true); + // sometimes singleline folds can be missed by the code above + if (range && !range.isMultiLine()) { + fold = this.getFoldAt(range.start.row, range.start.column, 1); + if (fold && range.isEqual(fold.range)) { + this.removeFold(fold); + return; + } + } + + if (options.siblings) { + var data = this.getParentFoldRangeData(row); + if (data.range) { + var startRow = data.range.start.row + 1; + var endRow = data.range.end.row; + } + this.foldAll(startRow, endRow, options.all ? 10000 : 0); + } else if (options.children) { + endRow = range ? range.end.row : this.getLength(); + this.foldAll(row + 1, endRow, options.all ? 10000 : 0); + } else if (range) { + if (options.all) + range.collapseChildren = 10000; + this.addFold("...", range); + } + + return range; + }; + + + + this.toggleFoldWidget = function(toggleParent) { + var row = this.selection.getCursor().row; + row = this.getRowFoldStart(row); + var range = this.$toggleFoldWidget(row, {}); + + if (range) + return; + // handle toggleParent + var data = this.getParentFoldRangeData(row, true); + range = data.range || data.firstRange; + + if (range) { + row = range.start.row; + var fold = this.getFoldAt(row, this.getLine(row).length, 1); + + if (fold) { + this.removeFold(fold); + } else { + this.addFold("...", range); + } + } + }; + + this.updateFoldWidgets = function(delta) { + var firstRow = delta.start.row; + var len = delta.end.row - firstRow; + + if (len === 0) { + this.foldWidgets[firstRow] = null; + } else if (delta.action == 'remove') { + this.foldWidgets.splice(firstRow, len + 1, null); + } else { + var args = Array(len + 1); + args.unshift(firstRow, 1); + this.foldWidgets.splice.apply(this.foldWidgets, args); + } + }; + this.tokenizerUpdateFoldWidgets = function(e) { + var rows = e.data; + if (rows.first != rows.last) { + if (this.foldWidgets.length > rows.first) + this.foldWidgets.splice(rows.first, this.foldWidgets.length); + } + } +} + +exports.Folding = Folding; + +}); diff --git a/node_modules/ace/lib/ace/edit_session_test.js b/node_modules/ace/lib/ace/edit_session_test.js new file mode 100644 index 00000000..75abf468 --- /dev/null +++ b/node_modules/ace/lib/ace/edit_session_test.js @@ -0,0 +1,1075 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +if (typeof process !== "undefined") { + require("amd-loader"); + require("./test/mockdom"); +} + +define(function(require, exports, module) { +"use strict"; + +var lang = require("./lib/lang"); +var EditSession = require("./edit_session").EditSession; +var Editor = require("./editor").Editor; +var UndoManager = require("./undomanager").UndoManager; +var MockRenderer = require("./test/mockrenderer").MockRenderer; +var Range = require("./range").Range; +var assert = require("./test/assertions"); +var JavaScriptMode = require("./mode/javascript").Mode; + +function createFoldTestSession() { + var lines = [ + "function foo(items) {", + " for (var i=0; i>", [1, 2], 1); + + // Test wrapping for punctuation in + EditSession.prototype.$wrapAsCode = false; + computeAndAssert("ab cde, Juhu kinners", [3, 8, 13, 19], 6); + }, + + "test get longest line" : function() { + var session = new EditSession(["12"]); + session.setTabSize(4); + assert.equal(session.getScreenWidth(), 2); + + session.doc.insertMergedLines({row: 0, column: Infinity}, ['', '']); + session.doc.insertFullLines(1, ["123"]); + assert.equal(session.getScreenWidth(), 3); + + session.doc.insertMergedLines({row: 0, column: Infinity}, ['', '']); + session.doc.insertFullLines(1, ["\t\t"]); + + assert.equal(session.getScreenWidth(), 8); + + session.setTabSize(2); + assert.equal(session.getScreenWidth(), 4); + }, + + "test getDisplayString": function() { + var session = new EditSession(["12"]); + session.setTabSize(4); + + assert.equal(session.$getDisplayTokens("\t").length, 4); + assert.equal(session.$getDisplayTokens("abc").length, 3); + assert.equal(session.$getDisplayTokens("abc\t").length, 4); + }, + + "test issue 83": function() { + var session = new EditSession(""); + var editor = new Editor(new MockRenderer(), session); + var document = session.getDocument(); + + session.setUseWrapMode(true); + + document.insertFullLines(0, ["a", "b"]); + document.insertFullLines(2, ["c", "d"]); + document.removeFullLines(1, 2); + }, + + "test wrapMode init has to create wrapData array": function() { + var session = new EditSession("foo bar\nfoo bar"); + var editor = new Editor(new MockRenderer(), session); + var document = session.getDocument(); + + session.setUseWrapMode(true); + session.setWrapLimitRange(3, 3); + session.adjustWrapLimit(80); + + // Test if wrapData is there and was computed. + assert.equal(session.$wrapData.length, 2); + assert.equal(session.$wrapData[0].length, 1); + assert.equal(session.$wrapData[1].length, 1); + }, + + "test first line blank with wrap": function() { + var session = new EditSession("\nfoo"); + session.setUseWrapMode(true); + assert.equal(session.doc.getValue(), ["", "foo"].join("\n")); + }, + + "test first line blank with wrap 2" : function() { + var session = new EditSession(""); + session.setUseWrapMode(true); + session.setValue("\nfoo"); + + assert.equal(session.doc.getValue(), ["", "foo"].join("\n")); + }, + + "test fold getFoldDisplayLine": function() { + var session = createFoldTestSession(); + function assertDisplayLine(foldLine, str) { + var line = session.getLine(foldLine.end.row); + var displayLine = + session.getFoldDisplayLine(foldLine, foldLine.end.row, line.length); + assert.equal(displayLine, str); + } + + assertDisplayLine(session.$foldData[0], "function foo(args...) {") + assertDisplayLine(session.$foldData[1], " for (vfoo...ert(items[bar...\"juhu\");"); + }, + + "test foldLine idxToPosition": function() { + var session = createFoldTestSession(); + + function assertIdx2Pos(foldLineIdx, idx, row, column) { + var foldLine = session.$foldData[foldLineIdx]; + assert.position(foldLine.idxToPosition(idx), row, column); + } + +// "function foo(items) {", +// " for (var i=0; iThe cursor in this paragraph text will be offset by 1 row.

      ", + "

      Everything after this will be offset as well due to the folds in the row before too.

      " + ].join("\n")); + session.addFold('...', new Range(0, 8, 0, 42)); + session.addFold('...', new Range(1, 8, 1, 42)); + session.addFold('...', new Range(3, 7, 3, 51)); + session.setOption("wrap", 40); + session.remove(new Range(0,0, 2, 5)); + // needed because adjustWrapLimit is called async from renderer + session.adjustWrapLimit(80); + + assert.equal(session.$wrapData + "", [[], [], [40, 76]] + ""); + }, + + "test add fold": function() { + var session = createFoldTestSession(); + var fold; + + function tryAddFold(placeholder, range, shouldFail) { + var fail = false; + try { + fold = session.addFold(placeholder, range); + } catch (e) { + fail = true; + } + if (fail != shouldFail) { + throw new Error("Expected to get an exception"); + } + } + + tryAddFold("foo", new Range(0, 13, 0, 17), false); + tryAddFold("foo", new Range(0, 14, 0, 18), true); + tryAddFold("foo", new Range(0, 13, 0, 18), false); + assert.equal(session.$foldData[0].folds.length, 1); + + tryAddFold("f", new Range(0, 13, 0, 18), false); + tryAddFold("foo", new Range(0, 18, 0, 21), false); + assert.equal(session.$foldData[0].folds.length, 2); + session.removeFold(fold); + + tryAddFold("foo", new Range(0, 18, 0, 22), false); + tryAddFold("foo", new Range(0, 18, 0, 19), true); + tryAddFold("foo", new Range(0, 22, 1, 10), false); + }, + + "test add subfolds": function() { + var session = createFoldTestSession(); + var fold, oldFold; + var foldData = session.$foldData; + + oldFold = foldData[0].folds[0]; + + fold = session.addFold("fold0", new Range(0, 10, 0, 21)); + assert.equal(foldData[0].folds.length, 1); + assert.equal(fold.subFolds.length, 1); + assert.equal(fold.subFolds[0], oldFold); + + session.expandFold(fold); + assert.equal(foldData[0].folds.length, 1); + assert.equal(foldData[0].folds[0], oldFold); + assert.equal(fold.subFolds.length, 0); + + fold = session.addFold("fold0", new Range(0, 13, 2, 10)); + assert.equal(foldData.length, 1); + assert.equal(fold.subFolds.length, 2); + assert.equal(fold.subFolds[0], oldFold); + + session.expandFold(fold); + assert.equal(foldData.length, 2); + assert.equal(foldData[0].folds.length, 1); + assert.equal(foldData[0].folds[0], oldFold); + assert.equal(fold.subFolds.length, 0); + + session.unfold(null, true); + fold = session.addFold("fold0", new Range(0, 0, 0, 21)); + session.addFold("fold0", new Range(0, 1, 0, 5)); + session.addFold("fold0", new Range(0, 6, 0, 8)); + assert.equal(fold.subFolds.length, 2); + }, + + "test row cache": function() { + var session = createFoldTestSession(); + + session.screenToDocumentPosition(2,3); + assertArray(session.$docRowCache, [1,3]); + assertArray(session.$screenRowCache, [1,2]); + + session.screenToDocumentPosition(5,3); + assertArray(session.$docRowCache, [1,3,4]); + assertArray(session.$screenRowCache, [1,2,3]); + + session.screenToDocumentPosition(0,3); + assertArray(session.$docRowCache, [1,3,4]); + assertArray(session.$screenRowCache, [1,2,3]); + + var pos = session.screenToDocumentPosition(0,0); + assert.equal(pos.row, 0); + assertArray(session.$docRowCache, [1,3,4]); + assertArray(session.$screenRowCache, [1,2,3]); + + session.screenToDocumentPosition(1,0); + assertArray(session.$docRowCache, [1,3,4]); + assertArray(session.$screenRowCache, [1,2,3]); + + session.$resetRowCache(); + assertArray(session.$docRowCache, []); + assertArray(session.$screenRowCache, []); + + session.screenToDocumentPosition(1,3); + assertArray(session.$docRowCache, [1]); + assertArray(session.$screenRowCache, [1]); + + session.screenToDocumentPosition(5,3); + assertArray(session.$docRowCache, [1,3,4]); + assertArray(session.$screenRowCache, [1,2,3]); + + session = new EditSession(new Array(30).join("\n")); + session.documentToScreenPosition(2,0); + session.documentToScreenPosition(2,0); + assertArray(session.$docRowCache, [1,2]); + assertArray(session.$screenRowCache, [1,2]); + }, + + "test annotations": function() { + var session = new EditSession([]), + annotation = {row: 0, type: 'info', text: "This is a test."}; + + session.clearAnnotations(); + assertArray(session.getAnnotations(), []); + session.setAnnotations([annotation]); + assertArray(session.getAnnotations(), [annotation]); + }, + + "test: mode loading" : function(next) { + if (!require.undef) { + console.log("Skipping test: This test only runs in the browser"); + next(); + return; + } + var session = new EditSession([]); + session.setMode("ace/mode/javascript"); + assert.equal(session.$modeid, "ace/mode/javascript"); + session.on("changeMode", function() { + assert.equal(session.$modeid, "ace/mode/javascript"); + }); + session.setMode("ace/mode/sh", function(mode) { + assert.ok(!mode); + }); + setTimeout(function() { + session.setMode("ace/mode/javascript", function(mode) { + session.setMode("ace/mode/javascript"); + assert.equal(session.$modeid, "ace/mode/javascript"); + next(); + }); + }, 0); + } +}; +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec(); +} diff --git a/node_modules/ace/lib/ace/editor.js b/node_modules/ace/lib/ace/editor.js new file mode 100644 index 00000000..1dc7321b --- /dev/null +++ b/node_modules/ace/lib/ace/editor.js @@ -0,0 +1,2660 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +require("./lib/fixoldbrowsers"); + +var oop = require("./lib/oop"); +var dom = require("./lib/dom"); +var lang = require("./lib/lang"); +var useragent = require("./lib/useragent"); +var TextInput = require("./keyboard/textinput").TextInput; +var MouseHandler = require("./mouse/mouse_handler").MouseHandler; +var FoldHandler = require("./mouse/fold_handler").FoldHandler; +var KeyBinding = require("./keyboard/keybinding").KeyBinding; +var EditSession = require("./edit_session").EditSession; +var Search = require("./search").Search; +var Range = require("./range").Range; +var EventEmitter = require("./lib/event_emitter").EventEmitter; +var CommandManager = require("./commands/command_manager").CommandManager; +var defaultCommands = require("./commands/default_commands").commands; +var config = require("./config"); +var TokenIterator = require("./token_iterator").TokenIterator; + +/** + * The main entry point into the Ace functionality. + * + * The `Editor` manages the [[EditSession]] (which manages [[Document]]s), as well as the [[VirtualRenderer]], which draws everything to the screen. + * + * Event sessions dealing with the mouse and keyboard are bubbled up from `Document` to the `Editor`, which decides what to do with them. + * @class Editor + **/ + +/** + * Creates a new `Editor` object. + * + * @param {VirtualRenderer} renderer Associated `VirtualRenderer` that draws everything + * @param {EditSession} session The `EditSession` to refer to + * + * + * @constructor + **/ +var Editor = function(renderer, session) { + var container = renderer.getContainerElement(); + this.container = container; + this.renderer = renderer; + + this.commands = new CommandManager(useragent.isMac ? "mac" : "win", defaultCommands); + this.textInput = new TextInput(renderer.getTextAreaContainer(), this); + this.renderer.textarea = this.textInput.getElement(); + this.keyBinding = new KeyBinding(this); + + // TODO detect touch event support + this.$mouseHandler = new MouseHandler(this); + new FoldHandler(this); + + this.$search = new Search().set({ + wrap: true + }); + + this.$historyTracker = this.$historyTracker.bind(this); + this.commands.on("exec", this.$historyTracker); + + this.$initOperationListeners(); + + this._$emitInputEvent = lang.delayedCall(function() { + this._signal("input", {}); + if (this.session && this.session.bgTokenizer) + this.session.bgTokenizer.scheduleStart(); + }.bind(this)); + + this.on("change", function(_, _self) { + _self._$emitInputEvent.schedule(31); + }); + + this.setSession(session || new EditSession("")); + config.resetOptions(this); + config._signal("editor", this); +}; + +(function(){ + + oop.implement(this, EventEmitter); + + this.$initOperationListeners = function() { + function last(a) {return a[a.length - 1]} + + this.selections = []; + this.commands.on("exec", this.startOperation.bind(this), true); + this.commands.on("afterExec", this.endOperation.bind(this), true); + + this.$opResetTimer = lang.delayedCall(this.endOperation.bind(this)); + + this.on("change", function() { + this.curOp || this.startOperation(); + this.curOp.docChanged = true; + }.bind(this), true); + + this.on("changeSelection", function() { + this.curOp || this.startOperation(); + this.curOp.selectionChanged = true; + }.bind(this), true); + }; + + this.curOp = null; + this.prevOp = {}; + this.startOperation = function(commadEvent) { + if (this.curOp) { + if (!commadEvent || this.curOp.command) + return; + this.prevOp = this.curOp; + } + if (!commadEvent) { + this.previousCommand = null; + commadEvent = {}; + } + + this.$opResetTimer.schedule(); + this.curOp = { + command: commadEvent.command || {}, + args: commadEvent.args, + scrollTop: this.renderer.scrollTop + }; + + // this.selections.push(this.selection.toJSON()); + }; + + this.endOperation = function(e) { + if (this.curOp) { + if (e && e.returnValue === false) + return this.curOp = null; + this._signal("beforeEndOperation"); + var command = this.curOp.command; + var scrollIntoView = command && command.scrollIntoView; + if (scrollIntoView) { + switch (scrollIntoView) { + case "center-animate": + scrollIntoView = "animate"; + /* fall through */ + case "center": + this.renderer.scrollCursorIntoView(null, 0.5); + break; + case "animate": + case "cursor": + this.renderer.scrollCursorIntoView(); + break; + case "selectionPart": + var range = this.selection.getRange(); + var config = this.renderer.layerConfig; + if (range.start.row >= config.lastRow || range.end.row <= config.firstRow) { + this.renderer.scrollSelectionIntoView(this.selection.anchor, this.selection.lead); + } + break; + default: + break; + } + if (scrollIntoView == "animate") + this.renderer.animateScrolling(this.curOp.scrollTop); + } + + this.prevOp = this.curOp; + this.curOp = null; + } + }; + + // TODO use property on commands instead of this + this.$mergeableCommands = ["backspace", "del", "insertstring"]; + this.$historyTracker = function(e) { + if (!this.$mergeUndoDeltas) + return; + + var prev = this.prevOp; + var mergeableCommands = this.$mergeableCommands; + // previous command was the same + var shouldMerge = prev.command && (e.command.name == prev.command.name); + if (e.command.name == "insertstring") { + var text = e.args; + if (this.mergeNextCommand === undefined) + this.mergeNextCommand = true; + + shouldMerge = shouldMerge + && this.mergeNextCommand // previous command allows to coalesce with + && (!/\s/.test(text) || /\s/.test(prev.args)); // previous insertion was of same type + + this.mergeNextCommand = true; + } else { + shouldMerge = shouldMerge + && mergeableCommands.indexOf(e.command.name) !== -1; // the command is mergeable + } + + if ( + this.$mergeUndoDeltas != "always" + && Date.now() - this.sequenceStartTime > 2000 + ) { + shouldMerge = false; // the sequence is too long + } + + if (shouldMerge) + this.session.mergeUndoDeltas = true; + else if (mergeableCommands.indexOf(e.command.name) !== -1) + this.sequenceStartTime = Date.now(); + }; + + /** + * Sets a new key handler, such as "vim" or "windows". + * @param {String} keyboardHandler The new key handler + * + **/ + this.setKeyboardHandler = function(keyboardHandler, cb) { + if (keyboardHandler && typeof keyboardHandler === "string") { + this.$keybindingId = keyboardHandler; + var _self = this; + config.loadModule(["keybinding", keyboardHandler], function(module) { + if (_self.$keybindingId == keyboardHandler) + _self.keyBinding.setKeyboardHandler(module && module.handler); + cb && cb(); + }); + } else { + this.$keybindingId = null; + this.keyBinding.setKeyboardHandler(keyboardHandler); + cb && cb(); + } + }; + + /** + * Returns the keyboard handler, such as "vim" or "windows". + * + * @returns {String} + * + **/ + this.getKeyboardHandler = function() { + return this.keyBinding.getKeyboardHandler(); + }; + + + /** + * Emitted whenever the [[EditSession]] changes. + * @event changeSession + * @param {Object} e An object with two properties, `oldSession` and `session`, that represent the old and new [[EditSession]]s. + * + **/ + /** + * Sets a new editsession to use. This method also emits the `'changeSession'` event. + * @param {EditSession} session The new session to use + * + **/ + this.setSession = function(session) { + if (this.session == session) + return; + + var oldSession = this.session; + if (oldSession) { + this.session.removeEventListener("change", this.$onDocumentChange); + this.session.removeEventListener("changeMode", this.$onChangeMode); + this.session.removeEventListener("tokenizerUpdate", this.$onTokenizerUpdate); + this.session.removeEventListener("changeTabSize", this.$onChangeTabSize); + this.session.removeEventListener("changeWrapLimit", this.$onChangeWrapLimit); + this.session.removeEventListener("changeWrapMode", this.$onChangeWrapMode); + this.session.removeEventListener("onChangeFold", this.$onChangeFold); + this.session.removeEventListener("changeFrontMarker", this.$onChangeFrontMarker); + this.session.removeEventListener("changeBackMarker", this.$onChangeBackMarker); + this.session.removeEventListener("changeBreakpoint", this.$onChangeBreakpoint); + this.session.removeEventListener("changeAnnotation", this.$onChangeAnnotation); + this.session.removeEventListener("changeOverwrite", this.$onCursorChange); + this.session.removeEventListener("changeScrollTop", this.$onScrollTopChange); + this.session.removeEventListener("changeScrollLeft", this.$onScrollLeftChange); + + var selection = this.session.getSelection(); + selection.removeEventListener("changeCursor", this.$onCursorChange); + selection.removeEventListener("changeSelection", this.$onSelectionChange); + } + + this.session = session; + if (session) { + this.$onDocumentChange = this.onDocumentChange.bind(this); + session.addEventListener("change", this.$onDocumentChange); + this.renderer.setSession(session); + + this.$onChangeMode = this.onChangeMode.bind(this); + session.addEventListener("changeMode", this.$onChangeMode); + + this.$onTokenizerUpdate = this.onTokenizerUpdate.bind(this); + session.addEventListener("tokenizerUpdate", this.$onTokenizerUpdate); + + this.$onChangeTabSize = this.renderer.onChangeTabSize.bind(this.renderer); + session.addEventListener("changeTabSize", this.$onChangeTabSize); + + this.$onChangeWrapLimit = this.onChangeWrapLimit.bind(this); + session.addEventListener("changeWrapLimit", this.$onChangeWrapLimit); + + this.$onChangeWrapMode = this.onChangeWrapMode.bind(this); + session.addEventListener("changeWrapMode", this.$onChangeWrapMode); + + this.$onChangeFold = this.onChangeFold.bind(this); + session.addEventListener("changeFold", this.$onChangeFold); + + this.$onChangeFrontMarker = this.onChangeFrontMarker.bind(this); + this.session.addEventListener("changeFrontMarker", this.$onChangeFrontMarker); + + this.$onChangeBackMarker = this.onChangeBackMarker.bind(this); + this.session.addEventListener("changeBackMarker", this.$onChangeBackMarker); + + this.$onChangeBreakpoint = this.onChangeBreakpoint.bind(this); + this.session.addEventListener("changeBreakpoint", this.$onChangeBreakpoint); + + this.$onChangeAnnotation = this.onChangeAnnotation.bind(this); + this.session.addEventListener("changeAnnotation", this.$onChangeAnnotation); + + this.$onCursorChange = this.onCursorChange.bind(this); + this.session.addEventListener("changeOverwrite", this.$onCursorChange); + + this.$onScrollTopChange = this.onScrollTopChange.bind(this); + this.session.addEventListener("changeScrollTop", this.$onScrollTopChange); + + this.$onScrollLeftChange = this.onScrollLeftChange.bind(this); + this.session.addEventListener("changeScrollLeft", this.$onScrollLeftChange); + + this.selection = session.getSelection(); + this.selection.addEventListener("changeCursor", this.$onCursorChange); + + this.$onSelectionChange = this.onSelectionChange.bind(this); + this.selection.addEventListener("changeSelection", this.$onSelectionChange); + + this.onChangeMode(); + + this.onCursorChange(); + + this.onScrollTopChange(); + this.onScrollLeftChange(); + this.onSelectionChange(); + this.onChangeFrontMarker(); + this.onChangeBackMarker(); + this.onChangeBreakpoint(); + this.onChangeAnnotation(); + this.session.getUseWrapMode() && this.renderer.adjustWrapLimit(); + this.renderer.updateFull(); + } else { + this.selection = null; + this.renderer.setSession(session); + } + + this._signal("changeSession", { + session: session, + oldSession: oldSession + }); + + oldSession && oldSession._signal("changeEditor", {oldEditor: this}); + session && session._signal("changeEditor", {editor: this}); + }; + + /** + * Returns the current session being used. + * @returns {EditSession} + **/ + this.getSession = function() { + return this.session; + }; + + /** + * Sets the current document to `val`. + * @param {String} val The new value to set for the document + * @param {Number} cursorPos Where to set the new value. `undefined` or 0 is selectAll, -1 is at the document start, and 1 is at the end + * + * @returns {String} The current document value + * @related Document.setValue + **/ + this.setValue = function(val, cursorPos) { + this.session.doc.setValue(val); + + if (!cursorPos) + this.selectAll(); + else if (cursorPos == 1) + this.navigateFileEnd(); + else if (cursorPos == -1) + this.navigateFileStart(); + + return val; + }; + + /** + * Returns the current session's content. + * + * @returns {String} + * @related EditSession.getValue + **/ + this.getValue = function() { + return this.session.getValue(); + }; + + /** + * + * Returns the currently highlighted selection. + * @returns {String} The highlighted selection + **/ + this.getSelection = function() { + return this.selection; + }; + + /** + * {:VirtualRenderer.onResize} + * @param {Boolean} force If `true`, recomputes the size, even if the height and width haven't changed + * + * + * @related VirtualRenderer.onResize + **/ + this.resize = function(force) { + this.renderer.onResize(force); + }; + + /** + * {:VirtualRenderer.setTheme} + * @param {String} theme The path to a theme + * @param {Function} cb optional callback called when theme is loaded + **/ + this.setTheme = function(theme, cb) { + this.renderer.setTheme(theme, cb); + }; + + /** + * {:VirtualRenderer.getTheme} + * + * @returns {String} The set theme + * @related VirtualRenderer.getTheme + **/ + this.getTheme = function() { + return this.renderer.getTheme(); + }; + + /** + * {:VirtualRenderer.setStyle} + * @param {String} style A class name + * + * + * @related VirtualRenderer.setStyle + **/ + this.setStyle = function(style) { + this.renderer.setStyle(style); + }; + + /** + * {:VirtualRenderer.unsetStyle} + * @related VirtualRenderer.unsetStyle + **/ + this.unsetStyle = function(style) { + this.renderer.unsetStyle(style); + }; + + /** + * Gets the current font size of the editor text. + */ + this.getFontSize = function () { + return this.getOption("fontSize") || + dom.computedStyle(this.container, "fontSize"); + }; + + /** + * Set a new font size (in pixels) for the editor text. + * @param {String} size A font size ( _e.g._ "12px") + * + * + **/ + this.setFontSize = function(size) { + this.setOption("fontSize", size); + }; + + this.$highlightBrackets = function() { + if (this.session.$bracketHighlight) { + this.session.removeMarker(this.session.$bracketHighlight); + this.session.$bracketHighlight = null; + } + + if (this.$highlightPending) { + return; + } + + // perform highlight async to not block the browser during navigation + var self = this; + this.$highlightPending = true; + setTimeout(function() { + self.$highlightPending = false; + var session = self.session; + if (!session || !session.bgTokenizer) return; + var pos = session.findMatchingBracket(self.getCursorPosition()); + if (pos) { + var range = new Range(pos.row, pos.column, pos.row, pos.column + 1); + } else if (session.$mode.getMatching) { + var range = session.$mode.getMatching(self.session); + } + if (range) + session.$bracketHighlight = session.addMarker(range, "ace_bracket", "text"); + }, 50); + }; + + // todo: move to mode.getMatching + this.$highlightTags = function() { + if (this.$highlightTagPending) + return; + + // perform highlight async to not block the browser during navigation + var self = this; + this.$highlightTagPending = true; + setTimeout(function() { + self.$highlightTagPending = false; + + var session = self.session; + if (!session || !session.bgTokenizer) return; + + var pos = self.getCursorPosition(); + var iterator = new TokenIterator(self.session, pos.row, pos.column); + var token = iterator.getCurrentToken(); + + if (!token || !/\b(?:tag-open|tag-name)/.test(token.type)) { + session.removeMarker(session.$tagHighlight); + session.$tagHighlight = null; + return; + } + + if (token.type.indexOf("tag-open") != -1) { + token = iterator.stepForward(); + if (!token) + return; + } + + var tag = token.value; + var depth = 0; + var prevToken = iterator.stepBackward(); + + if (prevToken.value == '<'){ + //find closing tag + do { + prevToken = token; + token = iterator.stepForward(); + + if (token && token.value === tag && token.type.indexOf('tag-name') !== -1) { + if (prevToken.value === '<'){ + depth++; + } else if (prevToken.value === '= 0); + } else { + //find opening tag + do { + token = prevToken; + prevToken = iterator.stepBackward(); + + if (token && token.value === tag && token.type.indexOf('tag-name') !== -1) { + if (prevToken.value === '<') { + depth++; + } else if (prevToken.value === ' 1)) + highlight = false; + } + + if (session.$highlightLineMarker && !highlight) { + session.removeMarker(session.$highlightLineMarker.id); + session.$highlightLineMarker = null; + } else if (!session.$highlightLineMarker && highlight) { + var range = new Range(highlight.row, highlight.column, highlight.row, Infinity); + range.id = session.addMarker(range, "ace_active-line", "screenLine"); + session.$highlightLineMarker = range; + } else if (highlight) { + session.$highlightLineMarker.start.row = highlight.row; + session.$highlightLineMarker.end.row = highlight.row; + session.$highlightLineMarker.start.column = highlight.column; + session._signal("changeBackMarker"); + } + }; + + this.onSelectionChange = function(e) { + var session = this.session; + + if (session.$selectionMarker) { + session.removeMarker(session.$selectionMarker); + } + session.$selectionMarker = null; + + if (!this.selection.isEmpty()) { + var range = this.selection.getRange(); + var style = this.getSelectionStyle(); + session.$selectionMarker = session.addMarker(range, "ace_selection", style); + } else { + this.$updateHighlightActiveLine(); + } + + var re = this.$highlightSelectedWord && this.$getSelectionHighLightRegexp(); + this.session.highlight(re); + + this._signal("changeSelection"); + }; + + this.$getSelectionHighLightRegexp = function() { + var session = this.session; + + var selection = this.getSelectionRange(); + if (selection.isEmpty() || selection.isMultiLine()) + return; + + var startOuter = selection.start.column - 1; + var endOuter = selection.end.column + 1; + var line = session.getLine(selection.start.row); + var lineCols = line.length; + var needle = line.substring(Math.max(startOuter, 0), + Math.min(endOuter, lineCols)); + + // Make sure the outer characters are not part of the word. + if ((startOuter >= 0 && /^[\w\d]/.test(needle)) || + (endOuter <= lineCols && /[\w\d]$/.test(needle))) + return; + + needle = line.substring(selection.start.column, selection.end.column); + if (!/^[\w\d]+$/.test(needle)) + return; + + var re = this.$search.$assembleRegExp({ + wholeWord: true, + caseSensitive: true, + needle: needle + }); + + return re; + }; + + + this.onChangeFrontMarker = function() { + this.renderer.updateFrontMarkers(); + }; + + this.onChangeBackMarker = function() { + this.renderer.updateBackMarkers(); + }; + + + this.onChangeBreakpoint = function() { + this.renderer.updateBreakpoints(); + }; + + this.onChangeAnnotation = function() { + this.renderer.setAnnotations(this.session.getAnnotations()); + }; + + + this.onChangeMode = function(e) { + this.renderer.updateText(); + this._emit("changeMode", e); + }; + + + this.onChangeWrapLimit = function() { + this.renderer.updateFull(); + }; + + this.onChangeWrapMode = function() { + this.renderer.onResize(true); + }; + + + this.onChangeFold = function() { + // Update the active line marker as due to folding changes the current + // line range on the screen might have changed. + this.$updateHighlightActiveLine(); + // TODO: This might be too much updating. Okay for now. + this.renderer.updateFull(); + }; + + + /** + * Returns the string of text currently highlighted. + * @returns {String} + **/ + this.getSelectedText = function(newLineCharacter) { + return this.session.getTextRange(this.getSelectionRange(), newLineCharacter); + }; + + /** + * Emitted when text is copied. + * @event copy + * @param {String} text The copied text + * + **/ + /** + * Returns the string of text currently highlighted. + * @returns {String} + * @deprecated Use getSelectedText instead. + **/ + this.getCopyText = function() { + var text = this.getSelectedText(useragent.isWin ? "\r\n" : "\n"); + this._signal("copy", text); + return text; + }; + + /** + * Called whenever a text "copy" happens. + **/ + this.onCopy = function() { + this.commands.exec("copy", this); + }; + + /** + * Called whenever a text "cut" happens. + **/ + this.onCut = function() { + this.commands.exec("cut", this); + }; + + /** + * Emitted when text is pasted. + * @event paste + * @param {Object} an object which contains one property, `text`, that represents the text to be pasted. Editing this property will alter the text that is pasted. + * + * + **/ + /** + * Called whenever a text "paste" happens. + * @param {String} text The pasted text + * + * + **/ + this.onPaste = function(text) { + // todo this should change when paste becomes a command + if (this.$readOnly) + return; + + var e = {text: text}; + this._signal("paste", e); + text = e.text; + if (!this.inMultiSelectMode || this.inVirtualSelectionMode) { + this.insert(text); + } else { + var lines = text.split(/\r\n|\r|\n/); + var ranges = this.selection.rangeList.ranges; + + if (lines.length > ranges.length || lines.length < 2 || !lines[1]) + return this.commands.exec("insertstring", this, text); + + for (var i = ranges.length; i--;) { + var range = ranges[i]; + if (!range.isEmpty()) + this.session.remove(range); + + this.session.insert(range.start, lines[i]); + } + } + this.renderer.scrollCursorIntoView(); + }; + + this.execCommand = function(command, args) { + return this.commands.exec(command, this, args); + }; + + this.transformAction = function(type, text) { + + }; + + /** + * Inserts `text` into wherever the cursor is pointing. + * @param {String} text The new text to add + * + **/ + this.insert = function(text, pasted) { + var session = this.session; + var mode = session.getMode(); + var cursor = this.getCursorPosition(); + + if (this.getBehavioursEnabled() && !pasted) { + // Get a transform if the current mode wants one. + var transform = mode.transformAction(session.getState(cursor.row), 'insertion', this, session, text); + if (transform) { + if (text !== transform.text) { + this.session.mergeUndoDeltas = false; + this.$mergeNextCommand = false; + } + text = transform.text; + + } + } + + if (text == "\t") + text = this.session.getTabString(); + + // remove selected text + if (!this.selection.isEmpty()) { + var range = this.getSelectionRange(); + cursor = this.session.remove(range); + this.clearSelection(); + } + else if (this.session.getOverwrite()) { + var range = new Range.fromPoints(cursor, cursor); + range.end.column += text.length; + this.session.remove(range); + } + + if (text == "\n" || text == "\r\n") { + var line = session.getLine(cursor.row); + if (cursor.column > line.search(/\S|$/)) { + var d = line.substr(cursor.column).search(/\S|$/); + session.doc.removeInLine(cursor.row, cursor.column, cursor.column + d); + } + } + this.clearSelection(); + + var start = cursor.column; + var lineState = session.getState(cursor.row); + var line = session.getLine(cursor.row); + var shouldOutdent = mode.checkOutdent(lineState, line, text); + var end = session.insert(cursor, text); + + if (transform && transform.selection) { + if (transform.selection.length == 2) { // Transform relative to the current column + this.selection.setSelectionRange( + new Range(cursor.row, start + transform.selection[0], + cursor.row, start + transform.selection[1])); + } else { // Transform relative to the current row. + this.selection.setSelectionRange( + new Range(cursor.row + transform.selection[0], + transform.selection[1], + cursor.row + transform.selection[2], + transform.selection[3])); + } + } + + if (session.getDocument().isNewLine(text)) { + var lineIndent = mode.getNextLineIndent(lineState, line.slice(0, cursor.column), session.getTabString()); + + session.insert({row: cursor.row+1, column: 0}, lineIndent); + } + if (shouldOutdent) + mode.autoOutdent(lineState, session, cursor.row); + }; + + this.onTextInput = function(text) { + this.keyBinding.onTextInput(text); + }; + + this.onCommandKey = function(e, hashId, keyCode) { + this.keyBinding.onCommandKey(e, hashId, keyCode); + }; + + /** + * Pass in `true` to enable overwrites in your session, or `false` to disable. If overwrites is enabled, any text you enter will type over any text after it. If the value of `overwrite` changes, this function also emites the `changeOverwrite` event. + * @param {Boolean} overwrite Defines wheter or not to set overwrites + * + * + * @related EditSession.setOverwrite + **/ + this.setOverwrite = function(overwrite) { + this.session.setOverwrite(overwrite); + }; + + /** + * Returns `true` if overwrites are enabled; `false` otherwise. + * @returns {Boolean} + * @related EditSession.getOverwrite + **/ + this.getOverwrite = function() { + return this.session.getOverwrite(); + }; + + /** + * Sets the value of overwrite to the opposite of whatever it currently is. + * @related EditSession.toggleOverwrite + **/ + this.toggleOverwrite = function() { + this.session.toggleOverwrite(); + }; + + /** + * Sets how fast the mouse scrolling should do. + * @param {Number} speed A value indicating the new speed (in milliseconds) + **/ + this.setScrollSpeed = function(speed) { + this.setOption("scrollSpeed", speed); + }; + + /** + * Returns the value indicating how fast the mouse scroll speed is (in milliseconds). + * @returns {Number} + **/ + this.getScrollSpeed = function() { + return this.getOption("scrollSpeed"); + }; + + /** + * Sets the delay (in milliseconds) of the mouse drag. + * @param {Number} dragDelay A value indicating the new delay + **/ + this.setDragDelay = function(dragDelay) { + this.setOption("dragDelay", dragDelay); + }; + + /** + * Returns the current mouse drag delay. + * @returns {Number} + **/ + this.getDragDelay = function() { + return this.getOption("dragDelay"); + }; + + /** + * Emitted when the selection style changes, via [[Editor.setSelectionStyle]]. + * @event changeSelectionStyle + * @param {Object} data Contains one property, `data`, which indicates the new selection style + **/ + /** + * Draw selection markers spanning whole line, or only over selected text. Default value is "line" + * @param {String} style The new selection style "line"|"text" + * + **/ + this.setSelectionStyle = function(val) { + this.setOption("selectionStyle", val); + }; + + /** + * Returns the current selection style. + * @returns {String} + **/ + this.getSelectionStyle = function() { + return this.getOption("selectionStyle"); + }; + + /** + * Determines whether or not the current line should be highlighted. + * @param {Boolean} shouldHighlight Set to `true` to highlight the current line + **/ + this.setHighlightActiveLine = function(shouldHighlight) { + this.setOption("highlightActiveLine", shouldHighlight); + }; + /** + * Returns `true` if current lines are always highlighted. + * @return {Boolean} + **/ + this.getHighlightActiveLine = function() { + return this.getOption("highlightActiveLine"); + }; + this.setHighlightGutterLine = function(shouldHighlight) { + this.setOption("highlightGutterLine", shouldHighlight); + }; + + this.getHighlightGutterLine = function() { + return this.getOption("highlightGutterLine"); + }; + + /** + * Determines if the currently selected word should be highlighted. + * @param {Boolean} shouldHighlight Set to `true` to highlight the currently selected word + * + **/ + this.setHighlightSelectedWord = function(shouldHighlight) { + this.setOption("highlightSelectedWord", shouldHighlight); + }; + + /** + * Returns `true` if currently highlighted words are to be highlighted. + * @returns {Boolean} + **/ + this.getHighlightSelectedWord = function() { + return this.$highlightSelectedWord; + }; + + this.setAnimatedScroll = function(shouldAnimate){ + this.renderer.setAnimatedScroll(shouldAnimate); + }; + + this.getAnimatedScroll = function(){ + return this.renderer.getAnimatedScroll(); + }; + + /** + * If `showInvisibles` is set to `true`, invisible characters—like spaces or new lines—are show in the editor. + * @param {Boolean} showInvisibles Specifies whether or not to show invisible characters + * + **/ + this.setShowInvisibles = function(showInvisibles) { + this.renderer.setShowInvisibles(showInvisibles); + }; + + /** + * Returns `true` if invisible characters are being shown. + * @returns {Boolean} + **/ + this.getShowInvisibles = function() { + return this.renderer.getShowInvisibles(); + }; + + this.setDisplayIndentGuides = function(display) { + this.renderer.setDisplayIndentGuides(display); + }; + + this.getDisplayIndentGuides = function() { + return this.renderer.getDisplayIndentGuides(); + }; + + /** + * If `showPrintMargin` is set to `true`, the print margin is shown in the editor. + * @param {Boolean} showPrintMargin Specifies whether or not to show the print margin + * + **/ + this.setShowPrintMargin = function(showPrintMargin) { + this.renderer.setShowPrintMargin(showPrintMargin); + }; + + /** + * Returns `true` if the print margin is being shown. + * @returns {Boolean} + **/ + this.getShowPrintMargin = function() { + return this.renderer.getShowPrintMargin(); + }; + + /** + * Sets the column defining where the print margin should be. + * @param {Number} showPrintMargin Specifies the new print margin + * + **/ + this.setPrintMarginColumn = function(showPrintMargin) { + this.renderer.setPrintMarginColumn(showPrintMargin); + }; + + /** + * Returns the column number of where the print margin is. + * @returns {Number} + **/ + this.getPrintMarginColumn = function() { + return this.renderer.getPrintMarginColumn(); + }; + + /** + * If `readOnly` is true, then the editor is set to read-only mode, and none of the content can change. + * @param {Boolean} readOnly Specifies whether the editor can be modified or not + * + **/ + this.setReadOnly = function(readOnly) { + this.setOption("readOnly", readOnly); + }; + + /** + * Returns `true` if the editor is set to read-only mode. + * @returns {Boolean} + **/ + this.getReadOnly = function() { + return this.getOption("readOnly"); + }; + + /** + * Specifies whether to use behaviors or not. ["Behaviors" in this case is the auto-pairing of special characters, like quotation marks, parenthesis, or brackets.]{: #BehaviorsDef} + * @param {Boolean} enabled Enables or disables behaviors + * + **/ + this.setBehavioursEnabled = function (enabled) { + this.setOption("behavioursEnabled", enabled); + }; + + /** + * Returns `true` if the behaviors are currently enabled. {:BehaviorsDef} + * + * @returns {Boolean} + **/ + this.getBehavioursEnabled = function () { + return this.getOption("behavioursEnabled"); + }; + + /** + * Specifies whether to use wrapping behaviors or not, i.e. automatically wrapping the selection with characters such as brackets + * when such a character is typed in. + * @param {Boolean} enabled Enables or disables wrapping behaviors + * + **/ + this.setWrapBehavioursEnabled = function (enabled) { + this.setOption("wrapBehavioursEnabled", enabled); + }; + + /** + * Returns `true` if the wrapping behaviors are currently enabled. + **/ + this.getWrapBehavioursEnabled = function () { + return this.getOption("wrapBehavioursEnabled"); + }; + + /** + * Indicates whether the fold widgets should be shown or not. + * @param {Boolean} show Specifies whether the fold widgets are shown + **/ + this.setShowFoldWidgets = function(show) { + this.setOption("showFoldWidgets", show); + + }; + /** + * Returns `true` if the fold widgets are shown. + * @return {Boolean} + **/ + this.getShowFoldWidgets = function() { + return this.getOption("showFoldWidgets"); + }; + + this.setFadeFoldWidgets = function(fade) { + this.setOption("fadeFoldWidgets", fade); + }; + + this.getFadeFoldWidgets = function() { + return this.getOption("fadeFoldWidgets"); + }; + + /** + * Removes the current selection or one character. + * @param {String} dir The direction of the deletion to occur, either "left" or "right" + * + **/ + this.remove = function(dir) { + if (this.selection.isEmpty()){ + if (dir == "left") + this.selection.selectLeft(); + else + this.selection.selectRight(); + } + + var range = this.getSelectionRange(); + if (this.getBehavioursEnabled()) { + var session = this.session; + var state = session.getState(range.start.row); + var new_range = session.getMode().transformAction(state, 'deletion', this, session, range); + + if (range.end.column === 0) { + var text = session.getTextRange(range); + if (text[text.length - 1] == "\n") { + var line = session.getLine(range.end.row); + if (/^\s+$/.test(line)) { + range.end.column = line.length; + } + } + } + if (new_range) + range = new_range; + } + + this.session.remove(range); + this.clearSelection(); + }; + + /** + * Removes the word directly to the right of the current selection. + **/ + this.removeWordRight = function() { + if (this.selection.isEmpty()) + this.selection.selectWordRight(); + + this.session.remove(this.getSelectionRange()); + this.clearSelection(); + }; + + /** + * Removes the word directly to the left of the current selection. + **/ + this.removeWordLeft = function() { + if (this.selection.isEmpty()) + this.selection.selectWordLeft(); + + this.session.remove(this.getSelectionRange()); + this.clearSelection(); + }; + + /** + * Removes all the words to the left of the current selection, until the start of the line. + **/ + this.removeToLineStart = function() { + if (this.selection.isEmpty()) + this.selection.selectLineStart(); + + this.session.remove(this.getSelectionRange()); + this.clearSelection(); + }; + + /** + * Removes all the words to the right of the current selection, until the end of the line. + **/ + this.removeToLineEnd = function() { + if (this.selection.isEmpty()) + this.selection.selectLineEnd(); + + var range = this.getSelectionRange(); + if (range.start.column == range.end.column && range.start.row == range.end.row) { + range.end.column = 0; + range.end.row++; + } + + this.session.remove(range); + this.clearSelection(); + }; + + /** + * Splits the line at the current selection (by inserting an `'\n'`). + **/ + this.splitLine = function() { + if (!this.selection.isEmpty()) { + this.session.remove(this.getSelectionRange()); + this.clearSelection(); + } + + var cursor = this.getCursorPosition(); + this.insert("\n"); + this.moveCursorToPosition(cursor); + }; + + /** + * Transposes current line. + **/ + this.transposeLetters = function() { + if (!this.selection.isEmpty()) { + return; + } + + var cursor = this.getCursorPosition(); + var column = cursor.column; + if (column === 0) + return; + + var line = this.session.getLine(cursor.row); + var swap, range; + if (column < line.length) { + swap = line.charAt(column) + line.charAt(column-1); + range = new Range(cursor.row, column-1, cursor.row, column+1); + } + else { + swap = line.charAt(column-1) + line.charAt(column-2); + range = new Range(cursor.row, column-2, cursor.row, column); + } + this.session.replace(range, swap); + }; + + /** + * Converts the current selection entirely into lowercase. + **/ + this.toLowerCase = function() { + var originalRange = this.getSelectionRange(); + if (this.selection.isEmpty()) { + this.selection.selectWord(); + } + + var range = this.getSelectionRange(); + var text = this.session.getTextRange(range); + this.session.replace(range, text.toLowerCase()); + this.selection.setSelectionRange(originalRange); + }; + + /** + * Converts the current selection entirely into uppercase. + **/ + this.toUpperCase = function() { + var originalRange = this.getSelectionRange(); + if (this.selection.isEmpty()) { + this.selection.selectWord(); + } + + var range = this.getSelectionRange(); + var text = this.session.getTextRange(range); + this.session.replace(range, text.toUpperCase()); + this.selection.setSelectionRange(originalRange); + }; + + /** + * Inserts an indentation into the current cursor position or indents the selected lines. + * + * @related EditSession.indentRows + **/ + this.indent = function() { + var session = this.session; + var range = this.getSelectionRange(); + + if (range.start.row < range.end.row) { + var rows = this.$getSelectedRows(); + session.indentRows(rows.first, rows.last, "\t"); + return; + } else if (range.start.column < range.end.column) { + var text = session.getTextRange(range); + if (!/^\s+$/.test(text)) { + var rows = this.$getSelectedRows(); + session.indentRows(rows.first, rows.last, "\t"); + return; + } + } + + var line = session.getLine(range.start.row); + var position = range.start; + var size = session.getTabSize(); + var column = session.documentToScreenColumn(position.row, position.column); + + if (this.session.getUseSoftTabs()) { + var count = (size - column % size); + var indentString = lang.stringRepeat(" ", count); + } else { + var count = column % size; + while (line[range.start.column] == " " && count) { + range.start.column--; + count--; + } + this.selection.setSelectionRange(range); + indentString = "\t"; + } + return this.insert(indentString); + }; + + /** + * Indents the current line. + * @related EditSession.indentRows + **/ + this.blockIndent = function() { + var rows = this.$getSelectedRows(); + this.session.indentRows(rows.first, rows.last, "\t"); + }; + + /** + * Outdents the current line. + * @related EditSession.outdentRows + **/ + this.blockOutdent = function() { + var selection = this.session.getSelection(); + this.session.outdentRows(selection.getRange()); + }; + + // TODO: move out of core when we have good mechanism for managing extensions + this.sortLines = function() { + var rows = this.$getSelectedRows(); + var session = this.session; + + var lines = []; + for (i = rows.first; i <= rows.last; i++) + lines.push(session.getLine(i)); + + lines.sort(function(a, b) { + if (a.toLowerCase() < b.toLowerCase()) return -1; + if (a.toLowerCase() > b.toLowerCase()) return 1; + return 0; + }); + + var deleteRange = new Range(0, 0, 0, 0); + for (var i = rows.first; i <= rows.last; i++) { + var line = session.getLine(i); + deleteRange.start.row = i; + deleteRange.end.row = i; + deleteRange.end.column = line.length; + session.replace(deleteRange, lines[i-rows.first]); + } + }; + + /** + * Given the currently selected range, this function either comments all the lines, or uncomments all of them. + **/ + this.toggleCommentLines = function() { + var state = this.session.getState(this.getCursorPosition().row); + var rows = this.$getSelectedRows(); + this.session.getMode().toggleCommentLines(state, this.session, rows.first, rows.last); + }; + + this.toggleBlockComment = function() { + var cursor = this.getCursorPosition(); + var state = this.session.getState(cursor.row); + var range = this.getSelectionRange(); + this.session.getMode().toggleBlockComment(state, this.session, range, cursor); + }; + + /** + * Works like [[EditSession.getTokenAt]], except it returns a number. + * @returns {Number} + **/ + this.getNumberAt = function(row, column) { + var _numberRx = /[\-]?[0-9]+(?:\.[0-9]+)?/g; + _numberRx.lastIndex = 0; + + var s = this.session.getLine(row); + while (_numberRx.lastIndex < column) { + var m = _numberRx.exec(s); + if(m.index <= column && m.index+m[0].length >= column){ + var number = { + value: m[0], + start: m.index, + end: m.index+m[0].length + }; + return number; + } + } + return null; + }; + + /** + * If the character before the cursor is a number, this functions changes its value by `amount`. + * @param {Number} amount The value to change the numeral by (can be negative to decrease value) + * + **/ + this.modifyNumber = function(amount) { + var row = this.selection.getCursor().row; + var column = this.selection.getCursor().column; + + // get the char before the cursor + var charRange = new Range(row, column-1, row, column); + + var c = this.session.getTextRange(charRange); + // if the char is a digit + if (!isNaN(parseFloat(c)) && isFinite(c)) { + // get the whole number the digit is part of + var nr = this.getNumberAt(row, column); + // if number found + if (nr) { + var fp = nr.value.indexOf(".") >= 0 ? nr.start + nr.value.indexOf(".") + 1 : nr.end; + var decimals = nr.start + nr.value.length - fp; + + var t = parseFloat(nr.value); + t *= Math.pow(10, decimals); + + + if(fp !== nr.end && column < fp){ + amount *= Math.pow(10, nr.end - column - 1); + } else { + amount *= Math.pow(10, nr.end - column); + } + + t += amount; + t /= Math.pow(10, decimals); + var nnr = t.toFixed(decimals); + + //update number + var replaceRange = new Range(row, nr.start, row, nr.end); + this.session.replace(replaceRange, nnr); + + //reposition the cursor + this.moveCursorTo(row, Math.max(nr.start +1, column + nnr.length - nr.value.length)); + + } + } + }; + + /** + * Removes all the lines in the current selection + * @related EditSession.remove + **/ + this.removeLines = function() { + var rows = this.$getSelectedRows(); + this.session.removeFullLines(rows.first, rows.last); + this.clearSelection(); + }; + + this.duplicateSelection = function() { + var sel = this.selection; + var doc = this.session; + var range = sel.getRange(); + var reverse = sel.isBackwards(); + if (range.isEmpty()) { + var row = range.start.row; + doc.duplicateLines(row, row); + } else { + var point = reverse ? range.start : range.end; + var endPoint = doc.insert(point, doc.getTextRange(range), false); + range.start = point; + range.end = endPoint; + + sel.setSelectionRange(range, reverse); + } + }; + + /** + * Shifts all the selected lines down one row. + * + * @returns {Number} On success, it returns -1. + * @related EditSession.moveLinesUp + **/ + this.moveLinesDown = function() { + this.$moveLines(1, false); + }; + + /** + * Shifts all the selected lines up one row. + * @returns {Number} On success, it returns -1. + * @related EditSession.moveLinesDown + **/ + this.moveLinesUp = function() { + this.$moveLines(-1, false); + }; + + /** + * Moves a range of text from the given range to the given position. `toPosition` is an object that looks like this: + * ```json + * { row: newRowLocation, column: newColumnLocation } + * ``` + * @param {Range} fromRange The range of text you want moved within the document + * @param {Object} toPosition The location (row and column) where you want to move the text to + * + * @returns {Range} The new range where the text was moved to. + * @related EditSession.moveText + **/ + this.moveText = function(range, toPosition, copy) { + return this.session.moveText(range, toPosition, copy); + }; + + /** + * Copies all the selected lines up one row. + * @returns {Number} On success, returns 0. + * + **/ + this.copyLinesUp = function() { + this.$moveLines(-1, true); + }; + + /** + * Copies all the selected lines down one row. + * @returns {Number} On success, returns the number of new rows added; in other words, `lastRow - firstRow + 1`. + * @related EditSession.duplicateLines + * + **/ + this.copyLinesDown = function() { + this.$moveLines(1, true); + }; + + /** + * for internal use + * @ignore + * + **/ + this.$moveLines = function(dir, copy) { + var rows, moved; + var selection = this.selection; + if (!selection.inMultiSelectMode || this.inVirtualSelectionMode) { + var range = selection.toOrientedRange(); + rows = this.$getSelectedRows(range); + moved = this.session.$moveLines(rows.first, rows.last, copy ? 0 : dir); + if (copy && dir == -1) moved = 0; + range.moveBy(moved, 0); + selection.fromOrientedRange(range); + } else { + var ranges = selection.rangeList.ranges; + selection.rangeList.detach(this.session); + this.inVirtualSelectionMode = true; + + var diff = 0; + var totalDiff = 0; + var l = ranges.length; + for (var i = 0; i < l; i++) { + var rangeIndex = i; + ranges[i].moveBy(diff, 0); + rows = this.$getSelectedRows(ranges[i]); + var first = rows.first; + var last = rows.last; + while (++i < l) { + if (totalDiff) ranges[i].moveBy(totalDiff, 0); + var subRows = this.$getSelectedRows(ranges[i]); + if (copy && subRows.first != last) + break; + else if (!copy && subRows.first > last + 1) + break; + last = subRows.last; + } + i--; + diff = this.session.$moveLines(first, last, copy ? 0 : dir); + if (copy && dir == -1) rangeIndex = i + 1; + while (rangeIndex <= i) { + ranges[rangeIndex].moveBy(diff, 0); + rangeIndex++; + } + if (!copy) diff = 0; + totalDiff += diff; + } + + selection.fromOrientedRange(selection.ranges[0]); + selection.rangeList.attach(this.session); + this.inVirtualSelectionMode = false; + } + }; + + /** + * Returns an object indicating the currently selected rows. The object looks like this: + * + * ```json + * { first: range.start.row, last: range.end.row } + * ``` + * + * @returns {Object} + **/ + this.$getSelectedRows = function(range) { + range = (range || this.getSelectionRange()).collapseRows(); + + return { + first: this.session.getRowFoldStart(range.start.row), + last: this.session.getRowFoldEnd(range.end.row) + }; + }; + + this.onCompositionStart = function(text) { + this.renderer.showComposition(this.getCursorPosition()); + }; + + this.onCompositionUpdate = function(text) { + this.renderer.setCompositionText(text); + }; + + this.onCompositionEnd = function() { + this.renderer.hideComposition(); + }; + + /** + * {:VirtualRenderer.getFirstVisibleRow} + * + * @returns {Number} + * @related VirtualRenderer.getFirstVisibleRow + **/ + this.getFirstVisibleRow = function() { + return this.renderer.getFirstVisibleRow(); + }; + + /** + * {:VirtualRenderer.getLastVisibleRow} + * + * @returns {Number} + * @related VirtualRenderer.getLastVisibleRow + **/ + this.getLastVisibleRow = function() { + return this.renderer.getLastVisibleRow(); + }; + + /** + * Indicates if the row is currently visible on the screen. + * @param {Number} row The row to check + * + * @returns {Boolean} + **/ + this.isRowVisible = function(row) { + return (row >= this.getFirstVisibleRow() && row <= this.getLastVisibleRow()); + }; + + /** + * Indicates if the entire row is currently visible on the screen. + * @param {Number} row The row to check + * + * + * @returns {Boolean} + **/ + this.isRowFullyVisible = function(row) { + return (row >= this.renderer.getFirstFullyVisibleRow() && row <= this.renderer.getLastFullyVisibleRow()); + }; + + /** + * Returns the number of currently visibile rows. + * @returns {Number} + **/ + this.$getVisibleRowCount = function() { + return this.renderer.getScrollBottomRow() - this.renderer.getScrollTopRow() + 1; + }; + + this.$moveByPage = function(dir, select) { + var renderer = this.renderer; + var config = this.renderer.layerConfig; + var rows = dir * Math.floor(config.height / config.lineHeight); + + if (select === true) { + this.selection.$moveSelection(function(){ + this.moveCursorBy(rows, 0); + }); + } else if (select === false) { + this.selection.moveCursorBy(rows, 0); + this.selection.clearSelection(); + } + + var scrollTop = renderer.scrollTop; + + renderer.scrollBy(0, rows * config.lineHeight); + if (select != null) + renderer.scrollCursorIntoView(null, 0.5); + + renderer.animateScrolling(scrollTop); + }; + + /** + * Selects the text from the current position of the document until where a "page down" finishes. + **/ + this.selectPageDown = function() { + this.$moveByPage(1, true); + }; + + /** + * Selects the text from the current position of the document until where a "page up" finishes. + **/ + this.selectPageUp = function() { + this.$moveByPage(-1, true); + }; + + /** + * Shifts the document to wherever "page down" is, as well as moving the cursor position. + **/ + this.gotoPageDown = function() { + this.$moveByPage(1, false); + }; + + /** + * Shifts the document to wherever "page up" is, as well as moving the cursor position. + **/ + this.gotoPageUp = function() { + this.$moveByPage(-1, false); + }; + + /** + * Scrolls the document to wherever "page down" is, without changing the cursor position. + **/ + this.scrollPageDown = function() { + this.$moveByPage(1); + }; + + /** + * Scrolls the document to wherever "page up" is, without changing the cursor position. + **/ + this.scrollPageUp = function() { + this.$moveByPage(-1); + }; + + /** + * Moves the editor to the specified row. + * @related VirtualRenderer.scrollToRow + **/ + this.scrollToRow = function(row) { + this.renderer.scrollToRow(row); + }; + + /** + * Scrolls to a line. If `center` is `true`, it puts the line in middle of screen (or attempts to). + * @param {Number} line The line to scroll to + * @param {Boolean} center If `true` + * @param {Boolean} animate If `true` animates scrolling + * @param {Function} callback Function to be called when the animation has finished + * + * + * @related VirtualRenderer.scrollToLine + **/ + this.scrollToLine = function(line, center, animate, callback) { + this.renderer.scrollToLine(line, center, animate, callback); + }; + + /** + * Attempts to center the current selection on the screen. + **/ + this.centerSelection = function() { + var range = this.getSelectionRange(); + var pos = { + row: Math.floor(range.start.row + (range.end.row - range.start.row) / 2), + column: Math.floor(range.start.column + (range.end.column - range.start.column) / 2) + }; + this.renderer.alignCursor(pos, 0.5); + }; + + /** + * Gets the current position of the cursor. + * @returns {Object} An object that looks something like this: + * + * ```json + * { row: currRow, column: currCol } + * ``` + * + * @related Selection.getCursor + **/ + this.getCursorPosition = function() { + return this.selection.getCursor(); + }; + + /** + * Returns the screen position of the cursor. + * @returns {Number} + * @related EditSession.documentToScreenPosition + **/ + this.getCursorPositionScreen = function() { + return this.session.documentToScreenPosition(this.getCursorPosition()); + }; + + /** + * {:Selection.getRange} + * @returns {Range} + * @related Selection.getRange + **/ + this.getSelectionRange = function() { + return this.selection.getRange(); + }; + + + /** + * Selects all the text in editor. + * @related Selection.selectAll + **/ + this.selectAll = function() { + this.selection.selectAll(); + }; + + /** + * {:Selection.clearSelection} + * @related Selection.clearSelection + **/ + this.clearSelection = function() { + this.selection.clearSelection(); + }; + + /** + * Moves the cursor to the specified row and column. Note that this does not de-select the current selection. + * @param {Number} row The new row number + * @param {Number} column The new column number + * + * + * @related Selection.moveCursorTo + **/ + this.moveCursorTo = function(row, column) { + this.selection.moveCursorTo(row, column); + }; + + /** + * Moves the cursor to the position indicated by `pos.row` and `pos.column`. + * @param {Object} pos An object with two properties, row and column + * + * + * @related Selection.moveCursorToPosition + **/ + this.moveCursorToPosition = function(pos) { + this.selection.moveCursorToPosition(pos); + }; + + /** + * Moves the cursor's row and column to the next matching bracket or HTML tag. + * + **/ + this.jumpToMatching = function(select, expand) { + var cursor = this.getCursorPosition(); + var iterator = new TokenIterator(this.session, cursor.row, cursor.column); + var prevToken = iterator.getCurrentToken(); + var token = prevToken || iterator.stepForward(); + + if (!token) return; + + //get next closing tag or bracket + var matchType; + var found = false; + var depth = {}; + var i = cursor.column - token.start; + var bracketType; + var brackets = { + ")": "(", + "(": "(", + "]": "[", + "[": "[", + "{": "{", + "}": "{" + }; + + do { + if (token.value.match(/[{}()\[\]]/g)) { + for (; i < token.value.length && !found; i++) { + if (!brackets[token.value[i]]) { + continue; + } + + bracketType = brackets[token.value[i]] + '.' + token.type.replace("rparen", "lparen"); + + if (isNaN(depth[bracketType])) { + depth[bracketType] = 0; + } + + switch (token.value[i]) { + case '(': + case '[': + case '{': + depth[bracketType]++; + break; + case ')': + case ']': + case '}': + depth[bracketType]--; + + if (depth[bracketType] === -1) { + matchType = 'bracket'; + found = true; + } + break; + } + } + } + else if (token && token.type.indexOf('tag-name') !== -1) { + if (isNaN(depth[token.value])) { + depth[token.value] = 0; + } + + if (prevToken.value === '<') { + depth[token.value]++; + } + else if (prevToken.value === '= 0; --i) { + if(this.$tryReplace(ranges[i], replacement)) { + replaced++; + } + } + + this.selection.setSelectionRange(selection); + + return replaced; + }; + + this.$tryReplace = function(range, replacement) { + var input = this.session.getTextRange(range); + replacement = this.$search.replace(input, replacement); + if (replacement !== null) { + range.end = this.session.replace(range, replacement); + return range; + } else { + return null; + } + }; + + /** + * {:Search.getOptions} For more information on `options`, see [[Search `Search`]]. + * @related Search.getOptions + * @returns {Object} + **/ + this.getLastSearchOptions = function() { + return this.$search.getOptions(); + }; + + /** + * Attempts to find `needle` within the document. For more information on `options`, see [[Search `Search`]]. + * @param {String} needle The text to search for (optional) + * @param {Object} options An object defining various search properties + * @param {Boolean} animate If `true` animate scrolling + * + * + * @related Search.find + **/ + this.find = function(needle, options, animate) { + if (!options) + options = {}; + + if (typeof needle == "string" || needle instanceof RegExp) + options.needle = needle; + else if (typeof needle == "object") + oop.mixin(options, needle); + + var range = this.selection.getRange(); + if (options.needle == null) { + needle = this.session.getTextRange(range) + || this.$search.$options.needle; + if (!needle) { + range = this.session.getWordRange(range.start.row, range.start.column); + needle = this.session.getTextRange(range); + } + this.$search.set({needle: needle}); + } + + this.$search.set(options); + if (!options.start) + this.$search.set({start: range}); + + var newRange = this.$search.find(this.session); + if (options.preventScroll) + return newRange; + if (newRange) { + this.revealRange(newRange, animate); + return newRange; + } + // clear selection if nothing is found + if (options.backwards) + range.start = range.end; + else + range.end = range.start; + this.selection.setRange(range); + }; + + /** + * Performs another search for `needle` in the document. For more information on `options`, see [[Search `Search`]]. + * @param {Object} options search options + * @param {Boolean} animate If `true` animate scrolling + * + * + * @related Editor.find + **/ + this.findNext = function(options, animate) { + this.find({skipCurrent: true, backwards: false}, options, animate); + }; + + /** + * Performs a search for `needle` backwards. For more information on `options`, see [[Search `Search`]]. + * @param {Object} options search options + * @param {Boolean} animate If `true` animate scrolling + * + * + * @related Editor.find + **/ + this.findPrevious = function(options, animate) { + this.find(options, {skipCurrent: true, backwards: true}, animate); + }; + + this.revealRange = function(range, animate) { + this.session.unfold(range); + this.selection.setSelectionRange(range); + + var scrollTop = this.renderer.scrollTop; + this.renderer.scrollSelectionIntoView(range.start, range.end, 0.5); + if (animate !== false) + this.renderer.animateScrolling(scrollTop); + }; + + /** + * {:UndoManager.undo} + * @related UndoManager.undo + **/ + this.undo = function() { + this.session.getUndoManager().undo(); + this.renderer.scrollCursorIntoView(null, 0.5); + }; + + /** + * {:UndoManager.redo} + * @related UndoManager.redo + **/ + this.redo = function() { + this.session.getUndoManager().redo(); + this.renderer.scrollCursorIntoView(null, 0.5); + }; + + /** + * + * Cleans up the entire editor. + **/ + this.destroy = function() { + this.renderer.destroy(); + this._signal("destroy", this); + if (this.session) { + this.session.destroy(); + } + }; + + /** + * Enables automatic scrolling of the cursor into view when editor itself is inside scrollable element + * @param {Boolean} enable default true + **/ + this.setAutoScrollEditorIntoView = function(enable) { + if (!enable) + return; + var rect; + var self = this; + var shouldScroll = false; + if (!this.$scrollAnchor) + this.$scrollAnchor = document.createElement("div"); + var scrollAnchor = this.$scrollAnchor; + scrollAnchor.style.cssText = "position:absolute"; + this.container.insertBefore(scrollAnchor, this.container.firstChild); + var onChangeSelection = this.on("changeSelection", function() { + shouldScroll = true; + }); + // needed to not trigger sync reflow + var onBeforeRender = this.renderer.on("beforeRender", function() { + if (shouldScroll) + rect = self.renderer.container.getBoundingClientRect(); + }); + var onAfterRender = this.renderer.on("afterRender", function() { + if (shouldScroll && rect && (self.isFocused() + || self.searchBox && self.searchBox.isFocused()) + ) { + var renderer = self.renderer; + var pos = renderer.$cursorLayer.$pixelPos; + var config = renderer.layerConfig; + var top = pos.top - config.offset; + if (pos.top >= 0 && top + rect.top < 0) { + shouldScroll = true; + } else if (pos.top < config.height && + pos.top + rect.top + config.lineHeight > window.innerHeight) { + shouldScroll = false; + } else { + shouldScroll = null; + } + if (shouldScroll != null) { + scrollAnchor.style.top = top + "px"; + scrollAnchor.style.left = pos.left + "px"; + scrollAnchor.style.height = config.lineHeight + "px"; + scrollAnchor.scrollIntoView(shouldScroll); + } + shouldScroll = rect = null; + } + }); + this.setAutoScrollEditorIntoView = function(enable) { + if (enable) + return; + delete this.setAutoScrollEditorIntoView; + this.removeEventListener("changeSelection", onChangeSelection); + this.renderer.removeEventListener("afterRender", onAfterRender); + this.renderer.removeEventListener("beforeRender", onBeforeRender); + }; + }; + + + this.$resetCursorStyle = function() { + var style = this.$cursorStyle || "ace"; + var cursorLayer = this.renderer.$cursorLayer; + if (!cursorLayer) + return; + cursorLayer.setSmoothBlinking(/smooth/.test(style)); + cursorLayer.isBlinking = !this.$readOnly && style != "wide"; + dom.setCssClass(cursorLayer.element, "ace_slim-cursors", /slim/.test(style)); + }; + +}).call(Editor.prototype); + + + +config.defineOptions(Editor.prototype, "editor", { + selectionStyle: { + set: function(style) { + this.onSelectionChange(); + this._signal("changeSelectionStyle", {data: style}); + }, + initialValue: "line" + }, + highlightActiveLine: { + set: function() {this.$updateHighlightActiveLine();}, + initialValue: true + }, + highlightSelectedWord: { + set: function(shouldHighlight) {this.$onSelectionChange();}, + initialValue: true + }, + readOnly: { + set: function(readOnly) { + // disabled to not break vim mode! + // this.textInput.setReadOnly(readOnly); + this.$resetCursorStyle(); + }, + initialValue: false + }, + cursorStyle: { + set: function(val) { this.$resetCursorStyle(); }, + values: ["ace", "slim", "smooth", "wide"], + initialValue: "ace" + }, + mergeUndoDeltas: { + values: [false, true, "always"], + initialValue: true + }, + behavioursEnabled: {initialValue: true}, + wrapBehavioursEnabled: {initialValue: true}, + autoScrollEditorIntoView: { + set: function(val) {this.setAutoScrollEditorIntoView(val)} + }, + + hScrollBarAlwaysVisible: "renderer", + vScrollBarAlwaysVisible: "renderer", + highlightGutterLine: "renderer", + animatedScroll: "renderer", + showInvisibles: "renderer", + showPrintMargin: "renderer", + printMarginColumn: "renderer", + printMargin: "renderer", + fadeFoldWidgets: "renderer", + showFoldWidgets: "renderer", + showLineNumbers: "renderer", + showGutter: "renderer", + displayIndentGuides: "renderer", + fontSize: "renderer", + fontFamily: "renderer", + maxLines: "renderer", + minLines: "renderer", + scrollPastEnd: "renderer", + fixedWidthGutter: "renderer", + theme: "renderer", + + scrollSpeed: "$mouseHandler", + dragDelay: "$mouseHandler", + dragEnabled: "$mouseHandler", + focusTimout: "$mouseHandler", + tooltipFollowsMouse: "$mouseHandler", + + firstLineNumber: "session", + overwrite: "session", + newLineMode: "session", + useWorker: "session", + useSoftTabs: "session", + tabSize: "session", + wrap: "session", + foldStyle: "session", + mode: "session" +}); + +exports.Editor = Editor; +}); diff --git a/node_modules/ace/lib/ace/editor_change_document_test.js b/node_modules/ace/lib/ace/editor_change_document_test.js new file mode 100644 index 00000000..a1fdaad9 --- /dev/null +++ b/node_modules/ace/lib/ace/editor_change_document_test.js @@ -0,0 +1,188 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +if (typeof process !== "undefined") { + require("amd-loader"); + require("./test/mockdom"); +} + +define(function(require, exports, module) { +"use strict"; + +var EditSession = require("./edit_session").EditSession; +var Editor = require("./editor").Editor; +var Text = require("./mode/text").Mode; +var JavaScriptMode = require("./mode/javascript").Mode; +var CssMode = require("./mode/css").Mode; +var HtmlMode = require("./mode/html").Mode; +var MockRenderer = require("./test/mockrenderer").MockRenderer; +var assert = require("./test/assertions"); + +module.exports = { + + setUp : function(next) { + this.session1 = new EditSession(["abc", "def"]); + this.session2 = new EditSession(["ghi", "jkl"]); + + + this.editor = new Editor(new MockRenderer()); + next(); + }, + + "test: change document" : function() { + this.editor.setSession(this.session1); + assert.equal(this.editor.getSession(), this.session1); + + this.editor.setSession(this.session2); + assert.equal(this.editor.getSession(), this.session2); + }, + + "test: only changes to the new document should have effect" : function() { + var called = false; + this.editor.onDocumentChange = function() { + called = true; + }; + + this.editor.setSession(this.session1); + this.editor.setSession(this.session2); + + this.session1.duplicateLines(0, 0); + assert.notOk(called); + + this.session2.duplicateLines(0, 0); + assert.ok(called); + }, + + "test: should use cursor of new document" : function() { + this.session1.getSelection().moveCursorTo(0, 1); + this.session2.getSelection().moveCursorTo(1, 0); + + this.editor.setSession(this.session1); + assert.position(this.editor.getCursorPosition(), 0, 1); + + this.editor.setSession(this.session2); + assert.position(this.editor.getCursorPosition(), 1, 0); + }, + + "test: only changing the cursor of the new doc should not have an effect" : function() { + this.editor.onCursorChange = function() { + called = true; + }; + + this.editor.setSession(this.session1); + this.editor.setSession(this.session2); + assert.position(this.editor.getCursorPosition(), 0, 0); + + var called = false; + this.session1.getSelection().moveCursorTo(0, 1); + assert.position(this.editor.getCursorPosition(), 0, 0); + assert.notOk(called); + + this.session2.getSelection().moveCursorTo(1, 1); + assert.position(this.editor.getCursorPosition(), 1, 1); + assert.ok(called); + }, + + "test: should use selection of new document" : function() { + this.session1.getSelection().selectTo(0, 1); + this.session2.getSelection().selectTo(1, 0); + + this.editor.setSession(this.session1); + assert.position(this.editor.getSelection().getSelectionLead(), 0, 1); + + this.editor.setSession(this.session2); + assert.position(this.editor.getSelection().getSelectionLead(), 1, 0); + }, + + "test: only changing the selection of the new doc should not have an effect" : function() { + this.editor.onSelectionChange = function() { + called = true; + }; + + this.editor.setSession(this.session1); + this.editor.setSession(this.session2); + assert.position(this.editor.getSelection().getSelectionLead(), 0, 0); + + var called = false; + this.session1.getSelection().selectTo(0, 1); + assert.position(this.editor.getSelection().getSelectionLead(), 0, 0); + assert.notOk(called); + + this.session2.getSelection().selectTo(1, 1); + assert.position(this.editor.getSelection().getSelectionLead(), 1, 1); + assert.ok(called); + }, + + "test: should use mode of new document" : function() { + this.editor.onChangeMode = function() { + called = true; + }; + this.editor.setSession(this.session1); + this.editor.setSession(this.session2); + + var called = false; + this.session1.setMode(new Text()); + assert.notOk(called); + + this.session2.setMode(new JavaScriptMode()); + assert.ok(called); + }, + + "test: should use stop worker of old document" : function(next) { + var self = this; + + // 1. Open an editor and set the session to CssMode + self.editor.setSession(self.session1); + self.session1.setMode(new CssMode()); + + // 2. Add a line or two of valid CSS. + self.session1.setValue("DIV { color: red; }"); + + // 3. Clear the session value. + self.session1.setValue(""); + + // 4. Set the session to HtmlMode + self.session1.setMode(new HtmlMode()); + + // 5. Try to type valid HTML + self.session1.insert({row: 0, column: 0}, ""); + + setTimeout(function() { + assert.equal(Object.keys(self.session1.getAnnotations()).length, 0); + next(); + }, 600); + } +}; + +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec() +} diff --git a/node_modules/ace/lib/ace/editor_highlight_selected_word_test.js b/node_modules/ace/lib/ace/editor_highlight_selected_word_test.js new file mode 100644 index 00000000..13e19c23 --- /dev/null +++ b/node_modules/ace/lib/ace/editor_highlight_selected_word_test.js @@ -0,0 +1,223 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +if (typeof process !== "undefined") { + require("amd-loader"); + require("./test/mockdom"); +} + +define(function(require, exports, module) { +"use strict"; + +var EditSession = require("./edit_session").EditSession; +var Editor = require("./editor").Editor; +var MockRenderer = require("./test/mockrenderer").MockRenderer; +var assert = require("./test/assertions"); + +var lipsum = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " + + "Mauris at arcu mi, eu lobortis mauris. Quisque ut libero eget " + + "diam congue vehicula. Quisque ut odio ut mi aliquam tincidunt. " + + "Duis lacinia aliquam lorem eget eleifend. Morbi eget felis mi. " + + "Duis quam ligula, consequat vitae convallis volutpat, blandit " + + "nec neque. Nulla facilisi. Etiam suscipit lorem ac justo " + + "sollicitudin tristique. Phasellus ut posuere nunc. Aliquam " + + "scelerisque mollis felis non gravida. Vestibulum lacus sem, " + + "posuere non bibendum id, luctus non dolor. Aenean id metus " + + "lorem, vel dapibus est. Donec gravida feugiat augue nec " + + "accumsan.Lorem ipsum dolor sit amet, consectetur adipiscing " + + "elit. Nulla vulputate, velit vitae tincidunt congue, nunc " + + "augue accumsan velit, eu consequat turpis lectus ac orci. " + + "Pellentesque ornare dolor feugiat dui auctor eu varius nulla " + + "fermentum. Sed aliquam odio at velit lacinia vel fermentum " + + "felis sodales. In dignissim magna eget nunc lobortis non " + + "fringilla nibh ullamcorper. Donec facilisis malesuada elit " + + "at egestas. Etiam bibendum, diam vitae tempor aliquet, dui " + + "libero vehicula odio, eget bibendum mauris velit eu lorem.\n" + + "consectetur"; + +function callHighlighterUpdate(session, firstRow, lastRow) { + var rangeCount = 0; + var mockMarkerLayer = { drawSingleLineMarker: function() {rangeCount++;} } + session.$searchHighlight.update([], mockMarkerLayer, session, { + firstRow: firstRow, + lastRow: lastRow + }); + return rangeCount; +} + +module.exports = { + setUp: function(next) { + this.session = new EditSession(lipsum); + this.editor = new Editor(new MockRenderer(), this.session); + this.selection = this.session.getSelection(); + this.search = this.editor.$search; + next(); + }, + + "test: highlight selected words by default": function() { + assert.equal(this.editor.getHighlightSelectedWord(), true); + }, + + "test: highlight a word": function() { + this.editor.moveCursorTo(0, 9); + this.selection.selectWord(); + + var highlighter = this.editor.session.$searchHighlight; + assert.ok(highlighter != null); + + var range = this.selection.getRange(); + assert.equal(this.session.getTextRange(range), "ipsum"); + assert.equal(highlighter.cache.length, 0); + assert.equal(callHighlighterUpdate(this.session, 0, 0), 2); + }, + + "test: highlight a word and clear highlight": function() { + this.editor.moveCursorTo(0, 8); + this.selection.selectWord(); + + var range = this.selection.getRange(); + assert.equal(this.session.getTextRange(range), "ipsum"); + assert.equal(callHighlighterUpdate(this.session, 0, 0), 2); + + this.session.highlight(""); + assert.equal(this.session.$searchHighlight.cache.length, 0); + assert.equal(callHighlighterUpdate(this.session, 0, 0), 0); + }, + + "test: highlight another word": function() { + this.selection.moveCursorTo(0, 14); + this.selection.selectWord(); + + var range = this.selection.getRange(); + assert.equal(this.session.getTextRange(range), "dolor"); + assert.equal(callHighlighterUpdate(this.session, 0, 0), 4); + }, + + "test: no selection, no highlight": function() { + this.selection.clearSelection(); + assert.equal(callHighlighterUpdate(this.session, 0, 0), 0); + }, + + "test: select a word, no highlight": function() { + this.selection.moveCursorTo(0, 14); + this.selection.selectWord(); + + this.editor.setHighlightSelectedWord(false); + + var range = this.selection.getRange(); + assert.equal(this.session.getTextRange(range), "dolor"); + assert.equal(callHighlighterUpdate(this.session, 0, 0), 0); + }, + + "test: select a word with no matches": function() { + this.editor.setHighlightSelectedWord(true); + + var currentOptions = this.search.getOptions(); + var newOptions = { + wrap: true, + wholeWord: true, + caseSensitive: true, + needle: "Mauris" + }; + this.search.set(newOptions); + + var match = this.search.find(this.session); + assert.notEqual(match, null, "found a match for 'Mauris'"); + + this.search.set(currentOptions); + + this.selection.setSelectionRange(match); + + assert.equal(this.session.getTextRange(match), "Mauris"); + assert.equal(callHighlighterUpdate(this.session, 0, 0), 1); + }, + + "test: partial word selection 1": function() { + this.selection.moveCursorTo(0, 14); + this.selection.selectWord(); + this.selection.selectLeft(); + + var range = this.selection.getRange(); + assert.equal(this.session.getTextRange(range), "dolo"); + assert.equal(callHighlighterUpdate(this.session, 0, 0), 0); + }, + + "test: partial word selection 2": function() { + this.selection.moveCursorTo(0, 13); + this.selection.selectWord(); + this.selection.selectRight(); + + var range = this.selection.getRange(); + assert.equal(this.session.getTextRange(range), "dolor "); + assert.equal(callHighlighterUpdate(this.session, 0, 0), 0); + }, + + "test: partial word selection 3": function() { + this.selection.moveCursorTo(0, 14); + this.selection.selectWord(); + this.selection.selectLeft(); + this.selection.shiftSelection(1); + + var range = this.selection.getRange(); + assert.equal(this.session.getTextRange(range), "olor"); + assert.equal(callHighlighterUpdate(this.session, 0, 0), 0); + }, + + "test: select last word": function() { + this.selection.moveCursorTo(0, 1); + + var currentOptions = this.search.getOptions(); + var newOptions = { + wrap: true, + wholeWord: true, + caseSensitive: true, + backwards: true, + needle: "consectetur" + }; + this.search.set(newOptions); + + var match = this.search.find(this.session); + assert.notEqual(match, null, "found a match for 'consectetur'"); + assert.position(match.start, 1, 0); + + this.search.set(currentOptions); + + this.selection.setSelectionRange(match); + + assert.equal(this.session.getTextRange(match), "consectetur"); + assert.equal(callHighlighterUpdate(this.session, 0, 1), 3); + } +}; + +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec(); +} diff --git a/node_modules/ace/lib/ace/editor_navigation_test.js b/node_modules/ace/lib/ace/editor_navigation_test.js new file mode 100644 index 00000000..ab348241 --- /dev/null +++ b/node_modules/ace/lib/ace/editor_navigation_test.js @@ -0,0 +1,164 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +if (typeof process !== "undefined") { + require("amd-loader"); + require("./test/mockdom"); +} + +define(function(require, exports, module) { +"use strict"; + +var EditSession = require("./edit_session").EditSession; +var Editor = require("./editor").Editor; +var MockRenderer = require("./test/mockrenderer").MockRenderer; +var assert = require("./test/assertions"); + +module.exports = { + createEditSession : function(rows, cols) { + var line = new Array(cols + 1).join("a"); + var text = new Array(rows).join(line + "\n") + line; + return new EditSession(text); + }, + + "test: navigate to end of file should scroll the last line into view" : function() { + var doc = this.createEditSession(200, 10); + var editor = new Editor(new MockRenderer(), doc); + + editor.navigateFileEnd(); + var cursor = editor.getCursorPosition(); + + assert.ok(editor.getFirstVisibleRow() <= cursor.row); + assert.ok(editor.getLastVisibleRow() >= cursor.row); + }, + + "test: navigate to start of file should scroll the first row into view" : function() { + var doc = this.createEditSession(200, 10); + var editor = new Editor(new MockRenderer(), doc); + + editor.moveCursorTo(editor.getLastVisibleRow() + 20); + editor.navigateFileStart(); + + assert.equal(editor.getFirstVisibleRow(), 0); + }, + + "test: goto hidden line should scroll the line into the middle of the viewport" : function() { + var editor = new Editor(new MockRenderer(), this.createEditSession(200, 5)); + + editor.navigateTo(0, 0); + editor.gotoLine(101); + assert.position(editor.getCursorPosition(), 100, 0); + assert.equal(editor.getFirstVisibleRow(), 89); + + editor.navigateTo(100, 0); + editor.gotoLine(11); + assert.position(editor.getCursorPosition(), 10, 0); + assert.equal(editor.getFirstVisibleRow(), 0); + + editor.navigateTo(100, 0); + editor.gotoLine(6); + assert.position(editor.getCursorPosition(), 5, 0); + assert.equal(0, editor.getFirstVisibleRow(), 0); + + editor.navigateTo(100, 0); + editor.gotoLine(1); + assert.position(editor.getCursorPosition(), 0, 0); + assert.equal(editor.getFirstVisibleRow(), 0); + + editor.navigateTo(0, 0); + editor.gotoLine(191); + assert.position(editor.getCursorPosition(), 190, 0); + assert.equal(editor.getFirstVisibleRow(), 179); + + editor.navigateTo(0, 0); + editor.gotoLine(196); + assert.position(editor.getCursorPosition(), 195, 0); + assert.equal(editor.getFirstVisibleRow(), 180); + }, + + "test: goto visible line should only move the cursor and not scroll": function() { + var editor = new Editor(new MockRenderer(), this.createEditSession(200, 5)); + + editor.navigateTo(0, 0); + editor.gotoLine(12); + assert.position(editor.getCursorPosition(), 11, 0); + assert.equal(editor.getFirstVisibleRow(), 0); + + editor.navigateTo(30, 0); + editor.gotoLine(33); + assert.position(editor.getCursorPosition(), 32, 0); + assert.equal(editor.getFirstVisibleRow(), 30); + }, + + "test: navigate from the end of a long line down to a short line and back should maintain the curser column": function() { + var editor = new Editor(new MockRenderer(), new EditSession(["123456", "1"])); + + editor.navigateTo(0, 6); + assert.position(editor.getCursorPosition(), 0, 6); + + editor.navigateDown(); + assert.position(editor.getCursorPosition(), 1, 1); + + editor.navigateUp(); + assert.position(editor.getCursorPosition(), 0, 6); + }, + + "test: reset desired column on navigate left or right": function() { + var editor = new Editor(new MockRenderer(), new EditSession(["123456", "12"])); + + editor.navigateTo(0, 6); + assert.position(editor.getCursorPosition(), 0, 6); + + editor.navigateDown(); + assert.position(editor.getCursorPosition(), 1, 2); + + editor.navigateLeft(); + assert.position(editor.getCursorPosition(), 1, 1); + + editor.navigateUp(); + assert.position(editor.getCursorPosition(), 0, 1); + }, + + "test: typing text should update the desired column": function() { + var editor = new Editor(new MockRenderer(), new EditSession(["1234", "1234567890"])); + + editor.navigateTo(0, 3); + editor.insert("juhu"); + + editor.navigateDown(); + assert.position(editor.getCursorPosition(), 1, 7); + } +}; + +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec() +} diff --git a/node_modules/ace/lib/ace/editor_text_edit_test.js b/node_modules/ace/lib/ace/editor_text_edit_test.js new file mode 100644 index 00000000..77ec34ed --- /dev/null +++ b/node_modules/ace/lib/ace/editor_text_edit_test.js @@ -0,0 +1,557 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +if (typeof process !== "undefined") { + require("amd-loader"); + require("./test/mockdom"); +} + +define(function(require, exports, module) { +"use strict"; + +var EditSession = require("./edit_session").EditSession; +var Editor = require("./editor").Editor; +var JavaScriptMode = require("./mode/javascript").Mode; +var UndoManager = require("./undomanager").UndoManager; +var MockRenderer = require("./test/mockrenderer").MockRenderer; +var assert = require("./test/assertions"); +var whitespace = require("./ext/whitespace"); + +module.exports = { + "test: delete line from the middle" : function() { + var session = new EditSession(["a", "b", "c", "d"].join("\n")); + var editor = new Editor(new MockRenderer(), session); + + editor.moveCursorTo(1, 1); + editor.removeLines(); + + assert.equal(session.toString(), "a\nc\nd"); + assert.position(editor.getCursorPosition(), 1, 0); + + editor.removeLines(); + + assert.equal(session.toString(), "a\nd"); + assert.position(editor.getCursorPosition(), 1, 0); + + editor.removeLines(); + + assert.equal(session.toString(), "a"); + assert.position(editor.getCursorPosition(), 0, 1); + + editor.removeLines(); + + assert.equal(session.toString(), ""); + assert.position(editor.getCursorPosition(), 0, 0); + }, + + "test: delete multiple selected lines" : function() { + var session = new EditSession(["a", "b", "c", "d"].join("\n")); + var editor = new Editor(new MockRenderer(), session); + + editor.moveCursorTo(1, 1); + editor.getSelection().selectDown(); + + editor.removeLines(); + assert.equal(session.toString(), "a\nd"); + assert.position(editor.getCursorPosition(), 1, 0); + }, + + "test: delete first line" : function() { + var session = new EditSession(["a", "b", "c"].join("\n")); + var editor = new Editor(new MockRenderer(), session); + + editor.removeLines(); + + assert.equal(session.toString(), "b\nc"); + assert.position(editor.getCursorPosition(), 0, 0); + }, + + "test: delete last should also delete the new line of the previous line" : function() { + var session = new EditSession(["a", "b", "c", ""].join("\n")); + var editor = new Editor(new MockRenderer(), session); + + editor.moveCursorTo(3, 0); + + editor.removeLines(); + assert.equal(session.toString(), "a\nb\nc"); + assert.position(editor.getCursorPosition(), 2, 1); + + editor.removeLines(); + assert.equal(session.toString(), "a\nb"); + assert.position(editor.getCursorPosition(), 1, 1); + }, + + "test: indent block" : function() { + var session = new EditSession(["a12345", "b12345", "c12345"].join("\n")); + var editor = new Editor(new MockRenderer(), session); + + editor.moveCursorTo(1, 3); + editor.getSelection().selectDown(); + + editor.indent(); + + assert.equal(["a12345", " b12345", " c12345"].join("\n"), session.toString()); + + assert.position(editor.getCursorPosition(), 2, 7); + + var range = editor.getSelectionRange(); + assert.position(range.start, 1, 7); + assert.position(range.end, 2, 7); + }, + + "test: indent selected lines" : function() { + var session = new EditSession(["a12345", "b12345", "c12345"].join("\n")); + var editor = new Editor(new MockRenderer(), session); + + editor.moveCursorTo(1, 0); + editor.getSelection().selectDown(); + + editor.indent(); + assert.equal(["a12345", " b12345", "c12345"].join("\n"), session.toString()); + }, + + "test: no auto indent if cursor is before the {" : function() { + var session = new EditSession("{", new JavaScriptMode()); + var editor = new Editor(new MockRenderer(), session); + + editor.moveCursorTo(0, 0); + editor.onTextInput("\n"); + assert.equal(["", "{"].join("\n"), session.toString()); + }, + + "test: outdent block" : function() { + var session = new EditSession([" a12345", " b12345", " c12345"].join("\n")); + var editor = new Editor(new MockRenderer(), session); + + editor.moveCursorTo(0, 5); + editor.getSelection().selectDown(); + editor.getSelection().selectDown(); + + editor.blockOutdent(); + assert.equal(session.toString(), [" a12345", "b12345", " c12345"].join("\n")); + + assert.position(editor.getCursorPosition(), 2, 1); + + var range = editor.getSelectionRange(); + assert.position(range.start, 0, 1); + assert.position(range.end, 2, 1); + + editor.blockOutdent(); + assert.equal(session.toString(), ["a12345", "b12345", "c12345"].join("\n")); + + var range = editor.getSelectionRange(); + assert.position(range.start, 0, 0); + assert.position(range.end, 2, 0); + }, + + "test: outent without a selection should update cursor" : function() { + var session = new EditSession(" 12"); + var editor = new Editor(new MockRenderer(), session); + + editor.moveCursorTo(0, 3); + editor.blockOutdent(" "); + + assert.equal(session.toString(), " 12"); + assert.position(editor.getCursorPosition(), 0, 0); + }, + + "test: comment lines should perserve selection" : function() { + var session = new EditSession([" abc", "cde"].join("\n"), new JavaScriptMode()); + var editor = new Editor(new MockRenderer(), session); + whitespace.detectIndentation(session); + + editor.moveCursorTo(0, 2); + editor.getSelection().selectDown(); + editor.toggleCommentLines(); + + assert.equal(["// abc", "// cde"].join("\n"), session.toString()); + + var selection = editor.getSelectionRange(); + assert.position(selection.start, 0, 5); + assert.position(selection.end, 1, 5); + }, + + "test: uncomment lines should perserve selection" : function() { + var session = new EditSession(["// abc", "//cde"].join("\n"), new JavaScriptMode()); + var editor = new Editor(new MockRenderer(), session); + session.setTabSize(2); + + editor.moveCursorTo(0, 1); + editor.getSelection().selectDown(); + editor.getSelection().selectRight(); + editor.getSelection().selectRight(); + + editor.toggleCommentLines(); + + assert.equal([" abc", "cde"].join("\n"), session.toString()); + assert.range(editor.getSelectionRange(), 0, 0, 1, 1); + }, + + "test: toggle comment lines twice should return the original text" : function() { + var session = new EditSession([" abc", "cde", "fg"], new JavaScriptMode()); + var editor = new Editor(new MockRenderer(), session); + + editor.moveCursorTo(0, 0); + editor.getSelection().selectDown(); + editor.getSelection().selectDown(); + + editor.toggleCommentLines(); + editor.toggleCommentLines(); + + assert.equal([" abc", "cde", "fg"].join("\n"), session.toString()); + }, + + + "test: comment lines - if the selection end is at the line start it should stay there": function() { + //select down + var session = new EditSession(["abc", "cde"].join("\n"), new JavaScriptMode()); + var editor = new Editor(new MockRenderer(), session); + + editor.moveCursorTo(0, 0); + editor.getSelection().selectDown(); + + editor.toggleCommentLines(); + assert.range(editor.getSelectionRange(), 0, 3, 1, 0); + + // select up + var session = new EditSession(["abc", "cde"].join("\n"), new JavaScriptMode()); + var editor = new Editor(new MockRenderer(), session); + + editor.moveCursorTo(1, 0); + editor.getSelection().selectUp(); + + editor.toggleCommentLines(); + assert.range(editor.getSelectionRange(), 0, 3, 1, 0); + }, + + "test: move lines down should keep selection on moved lines" : function() { + var session = new EditSession(["11", "22", "33", "44"].join("\n")); + var editor = new Editor(new MockRenderer(), session); + + editor.moveCursorTo(0, 1); + editor.getSelection().selectDown(); + + editor.moveLinesDown(); + assert.equal(["33", "11", "22", "44"].join("\n"), session.toString()); + assert.position(editor.getCursorPosition(), 2, 1); + assert.position(editor.getSelection().getSelectionAnchor(), 1, 1); + assert.position(editor.getSelection().getSelectionLead(), 2, 1); + + editor.moveLinesDown(); + assert.equal(["33", "44", "11", "22"].join("\n"), session.toString()); + assert.position(editor.getCursorPosition(), 3, 1); + assert.position(editor.getSelection().getSelectionAnchor(), 2, 1); + assert.position(editor.getSelection().getSelectionLead(), 3, 1); + + // moving again should have no effect + editor.moveLinesDown(); + assert.equal(["33", "44", "11", "22"].join("\n"), session.toString()); + assert.position(editor.getCursorPosition(), 3, 1); + assert.position(editor.getSelection().getSelectionAnchor(), 2, 1); + assert.position(editor.getSelection().getSelectionLead(), 3, 1); + }, + + "test: move lines up should keep selection on moved lines" : function() { + var session = new EditSession(["11", "22", "33", "44"].join("\n")); + var editor = new Editor(new MockRenderer(), session); + + editor.moveCursorTo(2, 1); + editor.getSelection().selectDown(); + + editor.moveLinesUp(); + assert.equal(session.toString(), ["11", "33", "44", "22"].join("\n")); + assert.position(editor.getCursorPosition(), 2, 1); + assert.position(editor.getSelection().getSelectionAnchor(), 1, 1); + assert.position(editor.getSelection().getSelectionLead(), 2, 1); + + editor.moveLinesUp(); + assert.equal(session.toString(), ["33", "44", "11", "22"].join("\n")); + assert.position(editor.getCursorPosition(), 1, 1); + assert.position(editor.getSelection().getSelectionAnchor(), 0, 1); + assert.position(editor.getSelection().getSelectionLead(), 1, 1); + }, + + "test: move line without active selection should not move cursor relative to the moved line" : function() { + var session = new EditSession(["11", "22", "33", "44"].join("\n")); + var editor = new Editor(new MockRenderer(), session); + + editor.moveCursorTo(1, 1); + editor.clearSelection(); + + editor.moveLinesDown(); + assert.equal(["11", "33", "22", "44"].join("\n"), session.toString()); + assert.position(editor.getCursorPosition(), 2, 1); + + editor.clearSelection(); + + editor.moveLinesUp(); + assert.equal(["11", "22", "33", "44"].join("\n"), session.toString()); + assert.position(editor.getCursorPosition(), 1, 1); + }, + + "test: copy lines down should keep selection" : function() { + var session = new EditSession(["11", "22", "33", "44"].join("\n")); + var editor = new Editor(new MockRenderer(), session); + + editor.moveCursorTo(1, 1); + editor.getSelection().selectDown(); + + editor.copyLinesDown(); + assert.equal(["11", "22", "33", "22", "33", "44"].join("\n"), session.toString()); + + assert.position(editor.getCursorPosition(), 4, 1); + assert.position(editor.getSelection().getSelectionAnchor(), 3, 1); + assert.position(editor.getSelection().getSelectionLead(), 4, 1); + }, + + "test: copy lines up should keep selection" : function() { + var session = new EditSession(["11", "22", "33", "44"].join("\n")); + var editor = new Editor(new MockRenderer(), session); + + editor.moveCursorTo(1, 1); + editor.getSelection().selectDown(); + + editor.copyLinesUp(); + assert.equal(["11", "22", "33", "22", "33", "44"].join("\n"), session.toString()); + + assert.position(editor.getCursorPosition(), 2, 1); + assert.position(editor.getSelection().getSelectionAnchor(), 1, 1); + assert.position(editor.getSelection().getSelectionLead(), 2, 1); + }, + + "test: input a tab with soft tab should convert it to spaces" : function() { + var session = new EditSession(""); + var editor = new Editor(new MockRenderer(), session); + + session.setTabSize(2); + session.setUseSoftTabs(true); + + editor.onTextInput("\t"); + assert.equal(session.toString(), " "); + + session.setTabSize(5); + editor.onTextInput("\t"); + assert.equal(session.toString(), " "); + }, + + "test: input tab without soft tabs should keep the tab character" : function() { + var session = new EditSession(""); + var editor = new Editor(new MockRenderer(), session); + + session.setUseSoftTabs(false); + + editor.onTextInput("\t"); + assert.equal(session.toString(), "\t"); + }, + + "test: undo/redo for delete line" : function() { + var session = new EditSession(["111", "222", "333"]); + var undoManager = new UndoManager(); + session.setUndoManager(undoManager); + + var initialText = session.toString(); + var editor = new Editor(new MockRenderer(), session); + + editor.removeLines(); + var step1 = session.toString(); + assert.equal(step1, "222\n333"); + session.$syncInformUndoManager(); + + editor.removeLines(); + var step2 = session.toString(); + assert.equal(step2, "333"); + session.$syncInformUndoManager(); + + editor.removeLines(); + var step3 = session.toString(); + assert.equal(step3, ""); + session.$syncInformUndoManager(); + + undoManager.undo(); + session.$syncInformUndoManager(); + assert.equal(session.toString(), step2); + + undoManager.undo(); + session.$syncInformUndoManager(); + assert.equal(session.toString(), step1); + + undoManager.undo(); + session.$syncInformUndoManager(); + assert.equal(session.toString(), initialText); + + undoManager.undo(); + session.$syncInformUndoManager(); + assert.equal(session.toString(), initialText); + }, + + "test: remove left should remove character left of the cursor" : function() { + var session = new EditSession(["123", "456"]); + + var editor = new Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 1); + editor.remove("left"); + assert.equal(session.toString(), "123\n56"); + }, + + "test: remove left should remove line break if cursor is at line start" : function() { + var session = new EditSession(["123", "456"]); + + var editor = new Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 0); + editor.remove("left"); + assert.equal(session.toString(), "123456"); + }, + + "test: remove left should remove tabsize spaces if cursor is on a tab stop and preceeded by spaces" : function() { + var session = new EditSession(["123", " 456"]); + session.setUseSoftTabs(true); + session.setTabSize(4); + + var editor = new Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 8); + editor.remove("left"); + assert.equal(session.toString(), "123\n 456"); + }, + + "test: transpose at line start should be a noop": function() { + var session = new EditSession(["123", "4567", "89"]); + + var editor = new Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 0); + editor.transposeLetters(); + + assert.equal(session.getValue(), ["123", "4567", "89"].join("\n")); + }, + + "test: transpose in line should swap the charaters before and after the cursor": function() { + var session = new EditSession(["123", "4567", "89"]); + + var editor = new Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 2); + editor.transposeLetters(); + + assert.equal(session.getValue(), ["123", "4657", "89"].join("\n")); + }, + + "test: transpose at line end should swap the last two characters": function() { + var session = new EditSession(["123", "4567", "89"]); + + var editor = new Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 4); + editor.transposeLetters(); + + assert.equal(session.getValue(), ["123", "4576", "89"].join("\n")); + }, + + "test: transpose with non empty selection should be a noop": function() { + var session = new EditSession(["123", "4567", "89"]); + + var editor = new Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 1); + editor.getSelection().selectRight(); + editor.transposeLetters(); + + assert.equal(session.getValue(), ["123", "4567", "89"].join("\n")); + }, + + "test: transpose should move the cursor behind the last swapped character": function() { + var session = new EditSession(["123", "4567", "89"]); + + var editor = new Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 2); + editor.transposeLetters(); + assert.position(editor.getCursorPosition(), 1, 3); + }, + + "test: remove to line end": function() { + var session = new EditSession(["123", "4567", "89"]); + + var editor = new Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 2); + editor.removeToLineEnd(); + assert.equal(session.getValue(), ["123", "45", "89"].join("\n")); + }, + + "test: remove to line end at line end should remove the new line": function() { + var session = new EditSession(["123", "4567", "89"]); + + var editor = new Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 4); + editor.removeToLineEnd(); + assert.position(editor.getCursorPosition(), 1, 4); + assert.equal(session.getValue(), ["123", "456789"].join("\n")); + }, + + "test: transform selection to uppercase": function() { + var session = new EditSession(["ajax", "dot", "org"]); + + var editor = new Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 0); + editor.getSelection().selectLineEnd(); + editor.toUpperCase() + assert.equal(session.getValue(), ["ajax", "DOT", "org"].join("\n")); + }, + + "test: transform word to uppercase": function() { + var session = new EditSession(["ajax", "dot", "org"]); + + var editor = new Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 0); + editor.toUpperCase() + assert.equal(session.getValue(), ["ajax", "DOT", "org"].join("\n")); + assert.position(editor.getCursorPosition(), 1, 0); + }, + + "test: transform selection to lowercase": function() { + var session = new EditSession(["AJAX", "DOT", "ORG"]); + + var editor = new Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 0); + editor.getSelection().selectLineEnd(); + editor.toLowerCase() + assert.equal(session.getValue(), ["AJAX", "dot", "ORG"].join("\n")); + }, + + "test: transform word to lowercase": function() { + var session = new EditSession(["AJAX", "DOT", "ORG"]); + + var editor = new Editor(new MockRenderer(), session); + editor.moveCursorTo(1, 0); + editor.toLowerCase() + assert.equal(session.getValue(), ["AJAX", "dot", "ORG"].join("\n")); + assert.position(editor.getCursorPosition(), 1, 0); + } +}; + +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec() +} diff --git a/node_modules/ace/lib/ace/ext/beautify.js b/node_modules/ace/lib/ace/ext/beautify.js new file mode 100644 index 00000000..d0fa1799 --- /dev/null +++ b/node_modules/ace/lib/ace/ext/beautify.js @@ -0,0 +1,57 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +// [WIP] + +define(function(require, exports, module) { +"use strict"; +var TokenIterator = require("ace/token_iterator").TokenIterator; + +var phpTransform = require("./beautify/php_rules").transform; + +exports.beautify = function(session) { + var iterator = new TokenIterator(session, 0, 0); + var token = iterator.getCurrentToken(); + + var context = session.$modeId.split("/").pop(); + + var code = phpTransform(iterator, context); + session.doc.setValue(code); +}; + +exports.commands = [{ + name: "beautify", + exec: function(editor) { + exports.beautify(editor.session); + }, + bindKey: "Ctrl-Shift-B" +}] + +}); \ No newline at end of file diff --git a/node_modules/ace/lib/ace/ext/beautify/php_rules.js b/node_modules/ace/lib/ace/ext/beautify/php_rules.js new file mode 100644 index 00000000..9a5bed36 --- /dev/null +++ b/node_modules/ace/lib/ace/ext/beautify/php_rules.js @@ -0,0 +1,366 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; +var TokenIterator = require("ace/token_iterator").TokenIterator; +exports.newLines = [{ + type: 'support.php_tag', + value: '' +}, { + type: 'paren.lparen', + value: '{', + indent: true +}, { + type: 'paren.rparen', + breakBefore: true, + value: '}', + indent: false +}, { + type: 'paren.rparen', + breakBefore: true, + value: '})', + indent: false, + dontBreak: true +}, { + type: 'comment' +}, { + type: 'text', + value: ';' +}, { + type: 'text', + value: ':', + context: 'php' +}, { + type: 'keyword', + value: 'case', + indent: true, + dontBreak: true +}, { + type: 'keyword', + value: 'default', + indent: true, + dontBreak: true +}, { + type: 'keyword', + value: 'break', + indent: false, + dontBreak: true +}, { + type: 'punctuation.doctype.end', + value: '>' +}, { + type: 'meta.tag.punctuation.end', + value: '>' +}, { + type: 'meta.tag.punctuation.begin', + value: '<', + blockTag: true, + indent: true, + dontBreak: true +}, { + type: 'meta.tag.punctuation.begin', + value: '' ){ + context = 'php'; + } + else if( token.type == 'support.php_tag' && token.value == '?>' ){ + context = 'html'; + } + //css + else if( token.type == 'meta.tag.name.style' && context != 'css' ){ + context = 'css'; + } + else if( token.type == 'meta.tag.name.style' && context == 'css' ){ + context = 'html'; + } + //js + else if( token.type == 'meta.tag.name.script' && context != 'js' ){ + context = 'js'; + } + else if( token.type == 'meta.tag.name.script' && context == 'js' ){ + context = 'html'; + } + + nextToken = iterator.stepForward(); + + //tag name + if (nextToken && nextToken.type.indexOf('meta.tag.name') == 0) { + nextTag = nextToken.value; + } + + //don't linebreak + if ( lastToken.type == 'support.php_tag' && lastToken.value == '' ) { + dontBreak = false; + } + + //next token + lastTag = tag; + + lastToken = token; + + token = nextToken; + + if (token===null) { + break; + } + } + + return code; +}; + + + +}); \ No newline at end of file diff --git a/node_modules/ace/lib/ace/ext/chromevox.js b/node_modules/ace/lib/ace/ext/chromevox.js new file mode 100644 index 00000000..52a180d4 --- /dev/null +++ b/node_modules/ace/lib/ace/ext/chromevox.js @@ -0,0 +1,979 @@ +define(function(require, exports, module) { + +/* ChromeVox Ace namespace. */ +var cvoxAce = {}; + +/* Typedefs for Closure compiler. */ +/** + * @typedef {{ + rate: number, + pitch: number, + volume: number, + relativePitch: number, + punctuationEcho: string + }} + */ +/* TODO(peterxiao): Export this typedef through cvox.Api. */ +cvoxAce.SpeechProperty; + +/** + * @typedef {{ + * row: number, + * column: number + * }} + */ +cvoxAce.Cursor; + +/** + * @typedef {{ + type: string, + value: string + }} + } + */ +cvoxAce.Token; + +/** + * These are errors and information that Ace will display in the gutter. + * @typedef {{ + row: number, + column: number, + value: string + }} + } + */ +cvoxAce.Annotation; + +/* Speech Properties. */ +/** + * Speech property for speaking constant tokens. + * @type {cvoxAce.SpeechProperty} + */ +var CONSTANT_PROP = { + 'rate': 0.8, + 'pitch': 0.4, + 'volume': 0.9 +}; + +/** + * Default speech property for speaking tokens. + * @type {cvoxAce.SpeechProperty} + */ +var DEFAULT_PROP = { + 'rate': 1, + 'pitch': 0.5, + 'volume': 0.9 +}; + +/** + * Speech property for speaking entity tokens. + * @type {cvoxAce.SpeechProperty} + */ +var ENTITY_PROP = { + 'rate': 0.8, + 'pitch': 0.8, + 'volume': 0.9 +}; + +/** + * Speech property for speaking keywords. + * @type {cvoxAce.SpeechProperty} + */ +var KEYWORD_PROP = { + 'rate': 0.8, + 'pitch': 0.3, + 'volume': 0.9 +}; + +/** + * Speech property for speaking storage tokens. + * @type {cvoxAce.SpeechProperty} + */ +var STORAGE_PROP = { + 'rate': 0.8, + 'pitch': 0.7, + 'volume': 0.9 +}; + +/** + * Speech property for speaking variable tokens. + * @type {cvoxAce.SpeechProperty} + */ +var VARIABLE_PROP = { + 'rate': 0.8, + 'pitch': 0.8, + 'volume': 0.9 +}; + +/** + * Speech property for speaking deleted text. + * @type {cvoxAce.SpeechProperty} + */ +var DELETED_PROP = { + 'punctuationEcho': 'none', + 'relativePitch': -0.6 +}; + +/* Constants for Earcons. */ +var ERROR_EARCON = 'ALERT_NONMODAL'; +var MODE_SWITCH_EARCON = 'ALERT_MODAL'; +var NO_MATCH_EARCON = 'INVALID_KEYPRESS'; + +/* Constants for vim state. */ +var INSERT_MODE_STATE = 'insertMode'; +var COMMAND_MODE_STATE = 'start'; + +var REPLACE_LIST = [ + { + substr: ';', + newSubstr: ' semicolon ' + }, + { + substr: ':', + newSubstr: ' colon ' + } +]; + +/** + * Context menu commands. + */ +var Command = { + SPEAK_ANNOT: 'annots', + SPEAK_ALL_ANNOTS: 'all_annots', + TOGGLE_LOCATION: 'toggle_location', + SPEAK_MODE: 'mode', + SPEAK_ROW_COL: 'row_col', + TOGGLE_DISPLACEMENT: 'toggle_displacement', + FOCUS_TEXT: 'focus_text' +}; + +/** + * Key prefix for each shortcut. + */ +var KEY_PREFIX = 'CONTROL + SHIFT '; + +/* Globals. */ +cvoxAce.editor = null; +/** + * Last cursor position. + * @type {cvoxAce.Cursor} + */ +var lastCursor = null; + +/** + * Table of annotations. + * @typedef {!Object.>} + */ +var annotTable = {}; + +/** + * Whether to speak character, word, and then line. This allows blind users + * to know the location of the cursor when they change lines. + * @typedef {boolean} + */ +var shouldSpeakRowLocation = false; + +/** + * Whether to speak displacement. + * @typedef {boolean} + */ +var shouldSpeakDisplacement = false; + +/** + * Whether text was changed to cause a cursor change event. + * @typedef {boolean} + */ +var changed = false; + +/** + * Current state vim is in. + */ +var vimState = null; + +/** + * Mapping from key code to shortcut. + */ +var keyCodeToShortcutMap = {}; + +/** + * Mapping from command to shortcut. + */ +var cmdToShortcutMap = {}; + +/** + * Get shortcut string from keyCode. + * @param {number} keyCode Key code of shortcut. + * @return {string} String representation of shortcut. + */ +var getKeyShortcutString = function(keyCode) { + return KEY_PREFIX + String.fromCharCode(keyCode); +}; + +/** + * Return if in vim mode. + * @return {boolean} True if in Vim mode. + */ +var isVimMode = function() { + var keyboardHandler = cvoxAce.editor.keyBinding.getKeyboardHandler(); + return keyboardHandler.$id === 'ace/keyboard/vim'; +}; + +/** + * Gets the current token. + * @param {!cvoxAce.Cursor} cursor Current position of the cursor. + * @return {!cvoxAce.Token} Token at the current position. + */ +var getCurrentToken = function(cursor) { + return cvoxAce.editor.getSession().getTokenAt(cursor.row, cursor.column + 1); +}; + +/** + * Gets the current line the cursor is under. + * @param {!cvoxAce.Cursor} cursor Current cursor position. + */ +var getCurrentLine = function(cursor) { + return cvoxAce.editor.getSession().getLine(cursor.row); +}; + +/** + * Event handler for row changes. When the user changes rows we want to speak + * the line so the user can work on this line. If shouldSpeakRowLocation is on + * then we speak the character, then the row, then the line so the user knows + * where the cursor is. + * @param {!cvoxAce.Cursor} currCursor Current cursor position. + */ +var onRowChange = function(currCursor) { + /* Notify that this line has an annotation. */ + if (annotTable[currCursor.row]) { + cvox.Api.playEarcon(ERROR_EARCON); + } + if (shouldSpeakRowLocation) { + cvox.Api.stop(); + speakChar(currCursor); + speakTokenQueue(getCurrentToken(currCursor)); + speakLine(currCursor.row, 1); + } else { + speakLine(currCursor.row, 0); + } +}; + +/** + * Returns whether the cursor is at the beginning of a word. A word is + * a grouping of alphanumeric characters including underscores. + * @param {!cvoxAce.Cursor} cursor Current cursor position. + * @return {boolean} Whether there is word. + */ +var isWord = function(cursor) { + var line = getCurrentLine(cursor); + var lineSuffix = line.substr(cursor.column - 1); + if (cursor.column === 0) { + lineSuffix = ' ' + line; + } + /* Use regex to tell if the suffix is at the start of a new word. */ + var firstWordRegExp = /^\W(\w+)/; + var words = firstWordRegExp.exec(lineSuffix); + return words !== null; +}; + +/** + * A mapping of syntax type to speech properties / expanding rules. + */ +var rules = { + 'constant': { + prop: CONSTANT_PROP + }, + 'entity': { + prop: ENTITY_PROP + }, + 'keyword': { + prop: KEYWORD_PROP + }, + 'storage': { + prop: STORAGE_PROP + }, + 'variable': { + prop: VARIABLE_PROP + }, + 'meta': { + prop: DEFAULT_PROP, + replace: [ + { + substr: '', + newSubstr: ' close tag ' + }, + { + substr: '<', + newSubstr: ' tag start ' + }, + { + substr: '>', + newSubstr: ' tag end ' + } + ] + } +}; + +/** + * Default rule to be used. + */ +var DEFAULT_RULE = { + prop: DEFAULT_RULE +}; + +/** + * Expands substrings to how they are read based on the given rules. + * @param {string} value Text to be expanded. + * @param {Array.} replaceRules Rules to determine expansion. + * @return {string} New expanded value. + */ +var expand = function(value, replaceRules) { + var newValue = value; + for (var i = 0; i < replaceRules.length; i++) { + var replaceRule = replaceRules[i]; + var regexp = new RegExp(replaceRule.substr, 'g'); + newValue = newValue.replace(regexp, replaceRule.newSubstr); + } + return newValue; +}; + +/** + * Merges tokens from start inclusive to end exclusive. + * @param {Array.} Tokens to be merged. + * @param {number} start Start index inclusive. + * @param {number} end End index exclusive. + * @return {cvoxAce.Token} Merged token. + */ +var mergeTokens = function(tokens, start, end) { + /* Different type of token found! Merge all previous like tokens. */ + var newToken = {}; + newToken.value = ''; + newToken.type = tokens[start].type; + for (var j = start; j < end; j++) { + newToken.value += tokens[j].value; + } + return newToken; +}; + +/** + * Merges tokens that use the same speech properties. + * @param {Array.} tokens Tokens to be merged. + * @return {Array.} Merged tokens. + */ +var mergeLikeTokens = function(tokens) { + if (tokens.length <= 1) { + return tokens; + } + var newTokens = []; + var lastLikeIndex = 0; + for (var i = 1; i < tokens.length; i++) { + var lastLikeToken = tokens[lastLikeIndex]; + var currToken = tokens[i]; + if (getTokenRule(lastLikeToken) !== getTokenRule(currToken)) { + newTokens.push(mergeTokens(tokens, lastLikeIndex, i)); + lastLikeIndex = i; + } + } + newTokens.push(mergeTokens(tokens, lastLikeIndex, tokens.length)); + return newTokens; +}; + +/** + * Returns if given row is a whitespace row. + * @param {number} row Row. + * @return {boolean} True if row is whitespaces. + */ +var isRowWhiteSpace = function(row) { + var line = cvoxAce.editor.getSession().getLine(row); + var whiteSpaceRegexp = /^\s*$/; + return whiteSpaceRegexp.exec(line) !== null; +}; + +/** + * Speak the line with syntax properties. + * @param {number} row Row to speak. + * @param {number} queue Queue mode to speak. + */ +var speakLine = function(row, queue) { + var tokens = cvoxAce.editor.getSession().getTokens(row); + if (tokens.length === 0 || isRowWhiteSpace(row)) { + cvox.Api.playEarcon('EDITABLE_TEXT'); + return; + } + tokens = mergeLikeTokens(tokens); + var firstToken = tokens[0]; + /* Filter out first token. */ + tokens = tokens.filter(function(token) { + return token !== firstToken; + }); + /* Speak first token separately to flush if queue. */ + speakToken_(firstToken, queue); + /* Speak rest of tokens. */ + tokens.forEach(speakTokenQueue); +}; + +/** + * Speak the token based on the syntax of the token, flushing. + * @param {!cvoxAce.Token} token Token to speak. + * @param {number} queue Queue mode. + */ +var speakTokenFlush = function(token) { + speakToken_(token, 0); +}; + +/** + * Speak the token based on the syntax of the token, queueing. + * @param {!cvoxAce.Token} token Token to speak. + * @param {number} queue Queue mode. + */ +var speakTokenQueue = function(token) { + speakToken_(token, 1); +}; + +/** + * @param {!cvoxAce.Token} token Token to speak. + * Get the token speech property. + */ +var getTokenRule = function(token) { + /* Types are period delimited. In this case, we only syntax speak the outer + * most type of token. */ + if (!token || !token.type) { + return; + } + var split = token.type.split('.'); + if (split.length === 0) { + return; + } + var type = split[0]; + var rule = rules[type]; + if (!rule) { + return DEFAULT_RULE; + } + return rule; +}; + +/** + * Speak the token based on the syntax of the token. + * @private + * @param {!cvoxAce.Token} token Token to speak. + * @param {number} queue Queue mode. + */ +var speakToken_ = function(token, queue) { + var rule = getTokenRule(token); + var value = expand(token.value, REPLACE_LIST); + if (rule.replace) { + value = expand(value, rule.replace); + } + cvox.Api.speak(value, queue, rule.prop); +}; + +/** + * Speaks the character under the cursor. This is queued. + * @param {!cvoxAce.Cursor} cursor Current cursor position. + * @return {string} Character. + */ +var speakChar = function(cursor) { + var line = getCurrentLine(cursor); + cvox.Api.speak(line[cursor.column], 1); +}; + +/** + * Speaks the jump from lastCursor to currCursor. This function assumes the + * jump takes place on the current line. + * @param {!cvoxAce.Cursor} lastCursor Previous cursor position. + * @param {!cvoxAce.Cursor} currCursor Current cursor position. + */ +var speakDisplacement = function(lastCursor, currCursor) { + var line = getCurrentLine(currCursor); + + /* Get the text that we jumped past. */ + var displace = line.substring(lastCursor.column, currCursor.column); + + /* Speak out loud spaces. */ + displace = displace.replace(/ /g, ' space '); + cvox.Api.speak(displace); +}; + +/** + * Speaks the word if the cursor jumped to a new word or to the beginning + * of the line. Otherwise speak the charactor. + * @param {!cvoxAce.Cursor} lastCursor Previous cursor position. + * @param {!cvoxAce.Cursor} currCursor Current cursor position. + */ +var speakCharOrWordOrLine = function(lastCursor, currCursor) { + /* Say word only if jump. */ + if (Math.abs(lastCursor.column - currCursor.column) !== 1) { + var currLineLength = getCurrentLine(currCursor).length; + /* Speak line if jumping to beginning or end of line. */ + if (currCursor.column === 0 || currCursor.column === currLineLength) { + speakLine(currCursor.row, 0); + return; + } + if (isWord(currCursor)) { + cvox.Api.stop(); + speakTokenQueue(getCurrentToken(currCursor)); + return; + } + } + speakChar(currCursor); +}; + +/** + * Event handler for column changes. If shouldSpeakDisplacement is on, then + * we just speak displacements in row changes. Otherwise, we either speak + * the character for single character movements, the word when jumping to the + * next word, or the entire line if jumping to beginning or end of the line. + * @param {!cvoxAce.Cursor} lastCursor Previous cursor position. + * @param {!cvoxAce.Cursor} currCursor Current cursor position. + */ +var onColumnChange = function(lastCursor, currCursor) { + if (!cvoxAce.editor.selection.isEmpty()) { + speakDisplacement(lastCursor, currCursor); + cvox.Api.speak('selected', 1); + } + else if (shouldSpeakDisplacement) { + speakDisplacement(lastCursor, currCursor); + } else { + speakCharOrWordOrLine(lastCursor, currCursor); + } +}; + +/** + * Event handler for cursor changes. Classify cursor changes as either row or + * column changes, then delegate accordingly. + * @param {!Event} evt The event. + */ +var onCursorChange = function(evt) { + /* Do not speak if cursor change was a result of text insertion. We want to + * speak the text that was inserted and not where the cursor lands. */ + if (changed) { + changed = false; + return; + } + var currCursor = cvoxAce.editor.selection.getCursor(); + if (currCursor.row !== lastCursor.row) { + onRowChange(currCursor); + } else { + onColumnChange(lastCursor, currCursor); + } + lastCursor = currCursor; +}; + +/** + * Event handler for selection changes. + * @param {!Event} evt The event. + */ +var onSelectionChange = function(evt) { + /* Assumes that when selection changes to empty, the user has unselected. */ + if (cvoxAce.editor.selection.isEmpty()) { + cvox.Api.speak('unselected'); + } +}; + +/** + * Event handler for source changes. We want auditory feedback for inserting + * and deleting text. + * @param {!Event} evt The event. + */ +var onChange = function(delta) { + switch (data.action) { + case 'remove': + cvox.Api.speak(data.text, 0, DELETED_PROP); + /* Let the future cursor change event know it's from text change. */ + changed = true; + break; + case 'insert': + cvox.Api.speak(data.text, 0); + /* Let the future cursor change event know it's from text change. */ + changed = true; + break; + } +}; + +/** + * Returns whether or not the annotation is new. + * @param {!cvoxAce.Annotation} annot Annotation in question. + * @return {boolean} Whether annot is new. + */ +var isNewAnnotation = function(annot) { + var row = annot.row; + var col = annot.column; + return !annotTable[row] || !annotTable[row][col]; +}; + +/** + * Populates the annotation table. + * @param {!Array.} annotations Array of annotations. + */ +var populateAnnotations = function(annotations) { + annotTable = {}; + for (var i = 0; i < annotations.length; i++) { + var annotation = annotations[i]; + var row = annotation.row; + var col = annotation.column; + if (!annotTable[row]) { + annotTable[row] = {}; + } + annotTable[row][col] = annotation; + } +}; + +/** + * Event handler for annotation changes. We want to notify the user when an + * a new annotation appears. + * @param {!Event} evt Event. + */ +var onAnnotationChange = function(evt) { + var annotations = cvoxAce.editor.getSession().getAnnotations(); + var newAnnotations = annotations.filter(isNewAnnotation); + if (newAnnotations.length > 0) { + cvox.Api.playEarcon(ERROR_EARCON); + } + populateAnnotations(annotations); +}; + +/** + * Speak annotation. + * @param {!cvoxAce.Annotation} annot Annotation to speak. + */ +var speakAnnot = function(annot) { + var annotText = annot.type + ' ' + annot.text + ' on ' + + rowColToString(annot.row, annot.column); + annotText = annotText.replace(';', 'semicolon'); + cvox.Api.speak(annotText, 1); +}; + +/** + * Speak annotations in a row. + * @param {number} row Row of annotations to speak. + */ +var speakAnnotsByRow = function(row) { + var annots = annotTable[row]; + for (var col in annots) { + speakAnnot(annots[col]); + } +}; + +/** + * Get a string representation of a row and column. + * @param {boolean} row Zero indexed row. + * @param {boolean} col Zero indexed column. + * @return {string} Row and column to be spoken. + */ +var rowColToString = function(row, col) { + return 'row ' + (row + 1) + ' column ' + (col + 1); +}; + +/** + * Speaks the row and column. + */ +var speakCurrRowAndCol = function() { + cvox.Api.speak(rowColToString(lastCursor.row, lastCursor.column)); +}; + +/** + * Speaks all annotations. + */ +var speakAllAnnots = function() { + for (var row in annotTable) { + speakAnnotsByRow(row); + } +}; + +/** + * Speak the vim mode. If no vim mode, this function does nothing. + */ +var speakMode = function() { + if (!isVimMode()) { + return; + } + switch (cvoxAce.editor.keyBinding.$data.state) { + case INSERT_MODE_STATE: + cvox.Api.speak('Insert mode'); + break; + case COMMAND_MODE_STATE: + cvox.Api.speak('Command mode'); + break; + } +}; + +/** + * Toggle speak location. + */ +var toggleSpeakRowLocation = function() { + shouldSpeakRowLocation = !shouldSpeakRowLocation; + /* Auditory feedback of the change. */ + if (shouldSpeakRowLocation) { + cvox.Api.speak('Speak location on row change enabled.'); + } else { + cvox.Api.speak('Speak location on row change disabled.'); + } +}; + +/** + * Toggle speak displacement. + */ +var toggleSpeakDisplacement = function() { + shouldSpeakDisplacement = !shouldSpeakDisplacement; + /* Auditory feedback of the change. */ + if (shouldSpeakDisplacement) { + cvox.Api.speak('Speak displacement on column changes.'); + } else { + cvox.Api.speak('Speak current character or word on column changes.'); + } +}; + +/** + * Event handler for key down events. Gets the right shortcut from the map, + * and calls the associated function. + * @param {!Event} evt Keyboard event. + */ +var onKeyDown = function(evt) { + if (evt.ctrlKey && evt.shiftKey) { + var shortcut = keyCodeToShortcutMap[evt.keyCode]; + if (shortcut) { + shortcut.func(); + } + } +}; + +/** + * Event handler for status change events. Auditory feedback of changing + * between vim states. + * @param {!Event} evt Change status event. + * @param {!Object} editor Editor state. + */ +var onChangeStatus = function(evt, editor) { + if (!isVimMode()) { + return; + } + var state = editor.keyBinding.$data.state; + if (state === vimState) { + /* State hasn't changed, do nothing. */ + return; + } + switch (state) { + case INSERT_MODE_STATE: + cvox.Api.playEarcon(MODE_SWITCH_EARCON); + /* When in insert mode, we want to speak out keys as feedback. */ + cvox.Api.setKeyEcho(true); + break; + case COMMAND_MODE_STATE: + cvox.Api.playEarcon(MODE_SWITCH_EARCON); + /* When in command mode, we want don't speak out keys because those keys + * are not being inserted in the document. */ + cvox.Api.setKeyEcho(false); + break; + } + vimState = state; +}; + +/** + * Handles context menu events. This is a ChromeVox feature where hitting + * the shortcut ChromeVox + comma will open up a search bar where you can + * type in various commands. All keyboard shortcuts are also commands that + * can be invoked. This handles the event that ChromeVox sends to the page. + * @param {Event} evt Event received. + */ +var contextMenuHandler = function(evt) { + var cmd = evt.detail['customCommand']; + var shortcut = cmdToShortcutMap[cmd]; + if (shortcut) { + shortcut.func(); + /* ChromeVox will bring focus to an element near the cursor instead of the + * text input. */ + cvoxAce.editor.focus(); + } +}; + +/** + * Initialize the ChromeVox context menu. + */ +var initContextMenu = function() { + var ACTIONS = SHORTCUTS.map(function(shortcut) { + return { + desc: shortcut.desc + getKeyShortcutString(shortcut.keyCode), + cmd: shortcut.cmd + }; + }); + + /* Attach ContextMenuActions. */ + var body = document.querySelector('body'); + body.setAttribute('contextMenuActions', JSON.stringify(ACTIONS)); + + /* Listen for ContextMenu events. */ + body.addEventListener('ATCustomEvent', contextMenuHandler, true); +}; + +/** + * Event handler for find events. When there is a match, we want to speak the + * line we are now at. Otherwise, we want to notify the user there was no + * match + * @param {!Event} evt The event. + */ +var onFindSearchbox = function(evt) { + if (evt.match) { + /* There is still a match! Speak the line. */ + speakLine(lastCursor.row, 0); + } else { + /* No match, give auditory feedback! */ + cvox.Api.playEarcon(NO_MATCH_EARCON); + } +}; + +/** + * Focus to text input. + */ +var focus = function() { + cvoxAce.editor.focus(); +}; + +/** + * Shortcut definitions. + */ +var SHORTCUTS = [ + { + /* 1 key. */ + keyCode: 49, + func: function() { + speakAnnotsByRow(lastCursor.row); + }, + cmd: Command.SPEAK_ANNOT, + desc: 'Speak annotations on line' + }, + { + /* 2 key. */ + keyCode: 50, + func: speakAllAnnots, + cmd: Command.SPEAK_ALL_ANNOTS, + desc: 'Speak all annotations' + }, + { + /* 3 key. */ + keyCode: 51, + func: speakMode, + cmd: Command.SPEAK_MODE, + desc: 'Speak Vim mode' + }, + { + /* 4 key. */ + keyCode: 52, + func: toggleSpeakRowLocation, + cmd: Command.TOGGLE_LOCATION, + desc: 'Toggle speak row location' + }, + { + /* 5 key. */ + keyCode: 53, + func: speakCurrRowAndCol, + cmd: Command.SPEAK_ROW_COL, + desc: 'Speak row and column' + }, + { + /* 6 key. */ + keyCode: 54, + func: toggleSpeakDisplacement, + cmd: Command.TOGGLE_DISPLACEMENT, + desc: 'Toggle speak displacement' + }, + { + /* 7 key. */ + keyCode: 55, + func: focus, + cmd: Command.FOCUS_TEXT, + desc: 'Focus text' + } +]; + +/** + * Event handler for focus events. + */ +var onFocus = function() { + cvoxAce.editor = editor; + + /* Set up listeners. */ + editor.getSession().selection.on('changeCursor', onCursorChange); + editor.getSession().selection.on('changeSelection', onSelectionChange); + editor.getSession().on('change', onChange); + editor.getSession().on('changeAnnotation', onAnnotationChange); + editor.on('changeStatus', onChangeStatus); + editor.on('findSearchBox', onFindSearchbox); + editor.container.addEventListener('keydown', onKeyDown); + + lastCursor = editor.selection.getCursor(); +}; + +/** + * Initialize the theme. + * @param {Object} editor Editor to use. + */ +var init = function(editor) { + onFocus(); + + /* Construct maps. */ + SHORTCUTS.forEach(function(shortcut) { + keyCodeToShortcutMap[shortcut.keyCode] = shortcut; + cmdToShortcutMap[shortcut.cmd] = shortcut; + }); + + editor.on('focus', onFocus); + + /* Assume we start in command mode if vim. */ + if (isVimMode()) { + cvox.Api.setKeyEcho(false); + } + initContextMenu(); +}; + +/** + * Returns if cvox exists, and the api exists. + * @return {boolean} Whether not Cvox Api exists. + */ +function cvoxApiExists() { + return (typeof(cvox) !== 'undefined') && cvox && cvox.Api; +} + +/** + * Number of tries for Cvox loading. + * @type {number} + */ +var tries = 0; + +/** + * Max number of tries to watch for Cvox loading. + * @type {number} + */ +var MAX_TRIES = 15; + +/** + * Check for ChromeVox load. + * @param {Object} editor Editor to use. + */ +function watchForCvoxLoad(editor) { + if (cvoxApiExists()) { + init(editor); + } else { + tries++; + if (tries >= MAX_TRIES) { + return; + } + window.setTimeout(watchForCvoxLoad, 500, editor); + } +} + +var Editor = require('../editor').Editor; +require('../config').defineOptions(Editor.prototype, 'editor', { + enableChromevoxEnhancements: { + set: function(val) { + if (val) { + watchForCvoxLoad(this); + } + }, + value: true // turn it on by default or check for window.cvox + } +}); + +}); diff --git a/node_modules/ace/lib/ace/ext/elastic_tabstops_lite.js b/node_modules/ace/lib/ace/ext/elastic_tabstops_lite.js new file mode 100644 index 00000000..0f89423a --- /dev/null +++ b/node_modules/ace/lib/ace/ext/elastic_tabstops_lite.js @@ -0,0 +1,318 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var ElasticTabstopsLite = function(editor) { + this.$editor = editor; + var self = this; + var changedRows = []; + var recordChanges = false; + this.onAfterExec = function() { + recordChanges = false; + self.processRows(changedRows); + changedRows = []; + }; + this.onExec = function() { + recordChanges = true; + }; + this.onChange = function(delta) { + if (recordChanges) { + if (changedRows.indexOf(delta.start.row) == -1) + changedRows.push(delta.start.row); + if (delta.end.row != delta.start.row) + changedRows.push(delta.end.row); + } + }; +}; + +(function() { + this.processRows = function(rows) { + this.$inChange = true; + var checkedRows = []; + + for (var r = 0, rowCount = rows.length; r < rowCount; r++) { + var row = rows[r]; + + if (checkedRows.indexOf(row) > -1) + continue; + + var cellWidthObj = this.$findCellWidthsForBlock(row); + var cellWidths = this.$setBlockCellWidthsToMax(cellWidthObj.cellWidths); + var rowIndex = cellWidthObj.firstRow; + + for (var w = 0, l = cellWidths.length; w < l; w++) { + var widths = cellWidths[w]; + checkedRows.push(rowIndex); + this.$adjustRow(rowIndex, widths); + rowIndex++; + } + } + this.$inChange = false; + }; + + this.$findCellWidthsForBlock = function(row) { + var cellWidths = [], widths; + + // starting row and backward + var rowIter = row; + while (rowIter >= 0) { + widths = this.$cellWidthsForRow(rowIter); + if (widths.length == 0) + break; + + cellWidths.unshift(widths); + rowIter--; + } + var firstRow = rowIter + 1; + + // forward (not including starting row) + rowIter = row; + var numRows = this.$editor.session.getLength(); + + while (rowIter < numRows - 1) { + rowIter++; + + widths = this.$cellWidthsForRow(rowIter); + if (widths.length == 0) + break; + + cellWidths.push(widths); + } + + return { cellWidths: cellWidths, firstRow: firstRow }; + }; + + this.$cellWidthsForRow = function(row) { + var selectionColumns = this.$selectionColumnsForRow(row); + // todo: support multicursor + + var tabs = [-1].concat(this.$tabsForRow(row)); + var widths = tabs.map(function(el) { return 0; } ).slice(1); + var line = this.$editor.session.getLine(row); + + for (var i = 0, len = tabs.length - 1; i < len; i++) { + var leftEdge = tabs[i]+1; + var rightEdge = tabs[i+1]; + + var rightmostSelection = this.$rightmostSelectionInCell(selectionColumns, rightEdge); + var cell = line.substring(leftEdge, rightEdge); + widths[i] = Math.max(cell.replace(/\s+$/g,'').length, rightmostSelection - leftEdge); + } + + return widths; + }; + + this.$selectionColumnsForRow = function(row) { + var selections = [], cursor = this.$editor.getCursorPosition(); + if (this.$editor.session.getSelection().isEmpty()) { + // todo: support multicursor + if (row == cursor.row) + selections.push(cursor.column); + } + + return selections; + }; + + this.$setBlockCellWidthsToMax = function(cellWidths) { + var startingNewBlock = true, blockStartRow, blockEndRow, maxWidth; + var columnInfo = this.$izip_longest(cellWidths); + + for (var c = 0, l = columnInfo.length; c < l; c++) { + var column = columnInfo[c]; + if (!column.push) { + console.error(column); + continue; + } + // add an extra None to the end so that the end of the column automatically + // finishes a block + column.push(NaN); + + for (var r = 0, s = column.length; r < s; r++) { + var width = column[r]; + if (startingNewBlock) { + blockStartRow = r; + maxWidth = 0; + startingNewBlock = false; + } + if (isNaN(width)) { + // block ended + blockEndRow = r; + + for (var j = blockStartRow; j < blockEndRow; j++) { + cellWidths[j][c] = maxWidth; + } + startingNewBlock = true; + } + + maxWidth = Math.max(maxWidth, width); + } + } + + return cellWidths; + }; + + this.$rightmostSelectionInCell = function(selectionColumns, cellRightEdge) { + var rightmost = 0; + + if (selectionColumns.length) { + var lengths = []; + for (var s = 0, length = selectionColumns.length; s < length; s++) { + if (selectionColumns[s] <= cellRightEdge) + lengths.push(s); + else + lengths.push(0); + } + rightmost = Math.max.apply(Math, lengths); + } + + return rightmost; + }; + + this.$tabsForRow = function(row) { + var rowTabs = [], line = this.$editor.session.getLine(row), + re = /\t/g, match; + + while ((match = re.exec(line)) != null) { + rowTabs.push(match.index); + } + + return rowTabs; + }; + + this.$adjustRow = function(row, widths) { + var rowTabs = this.$tabsForRow(row); + + if (rowTabs.length == 0) + return; + + var bias = 0, location = -1; + + // this always only contains two elements, so we're safe in the loop below + var expandedSet = this.$izip(widths, rowTabs); + + for (var i = 0, l = expandedSet.length; i < l; i++) { + var w = expandedSet[i][0], it = expandedSet[i][1]; + location += 1 + w; + it += bias; + var difference = location - it; + + if (difference == 0) + continue; + + var partialLine = this.$editor.session.getLine(row).substr(0, it ); + var strippedPartialLine = partialLine.replace(/\s*$/g, ""); + var ispaces = partialLine.length - strippedPartialLine.length; + + if (difference > 0) { + // put the spaces after the tab and then delete the tab, so any insertion + // points behave as expected + this.$editor.session.getDocument().insertInLine({row: row, column: it + 1}, Array(difference + 1).join(" ") + "\t"); + this.$editor.session.getDocument().removeInLine(row, it, it + 1); + + bias += difference; + } + + if (difference < 0 && ispaces >= -difference) { + this.$editor.session.getDocument().removeInLine(row, it + difference, it); + bias += difference; + } + } + }; + + // the is a (naive) Python port--but works for these purposes + this.$izip_longest = function(iterables) { + if (!iterables[0]) + return []; + var longest = iterables[0].length; + var iterablesLength = iterables.length; + + for (var i = 1; i < iterablesLength; i++) { + var iLength = iterables[i].length; + if (iLength > longest) + longest = iLength; + } + + var expandedSet = []; + + for (var l = 0; l < longest; l++) { + var set = []; + for (var i = 0; i < iterablesLength; i++) { + if (iterables[i][l] === "") + set.push(NaN); + else + set.push(iterables[i][l]); + } + + expandedSet.push(set); + } + + + return expandedSet; + }; + + // an even more (naive) Python port + this.$izip = function(widths, tabs) { + // grab the shorter size + var size = widths.length >= tabs.length ? tabs.length : widths.length; + + var expandedSet = []; + for (var i = 0; i < size; i++) { + var set = [ widths[i], tabs[i] ]; + expandedSet.push(set); + } + return expandedSet; + }; + +}).call(ElasticTabstopsLite.prototype); + +exports.ElasticTabstopsLite = ElasticTabstopsLite; + +var Editor = require("../editor").Editor; +require("../config").defineOptions(Editor.prototype, "editor", { + useElasticTabstops: { + set: function(val) { + if (val) { + if (!this.elasticTabstops) + this.elasticTabstops = new ElasticTabstopsLite(this); + this.commands.on("afterExec", this.elasticTabstops.onAfterExec); + this.commands.on("exec", this.elasticTabstops.onExec); + this.on("change", this.elasticTabstops.onChange); + } else if (this.elasticTabstops) { + this.commands.removeListener("afterExec", this.elasticTabstops.onAfterExec); + this.commands.removeListener("exec", this.elasticTabstops.onExec); + this.removeListener("change", this.elasticTabstops.onChange); + } + } + } +}); + +}); \ No newline at end of file diff --git a/node_modules/ace/lib/ace/ext/emmet.js b/node_modules/ace/lib/ace/ext/emmet.js new file mode 100644 index 00000000..ceb155ef --- /dev/null +++ b/node_modules/ace/lib/ace/ext/emmet.js @@ -0,0 +1,434 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; +var HashHandler = require("ace/keyboard/hash_handler").HashHandler; +var Editor = require("ace/editor").Editor; +var snippetManager = require("ace/snippets").snippetManager; +var Range = require("ace/range").Range; +var emmet, emmetPath; + +/** + * Implementation of {@link IEmmetEditor} interface for Ace + */ +function AceEmmetEditor() {} + +AceEmmetEditor.prototype = { + setupContext: function(editor) { + this.ace = editor; + this.indentation = editor.session.getTabString(); + if (!emmet) + emmet = window.emmet; + emmet.require("resources").setVariable("indentation", this.indentation); + this.$syntax = null; + this.$syntax = this.getSyntax(); + }, + /** + * Returns character indexes of selected text: object with start + * and end properties. If there's no selection, should return + * object with start and end properties referring + * to current caret position + * @return {Object} + * @example + * var selection = editor.getSelectionRange(); + * alert(selection.start + ', ' + selection.end); + */ + getSelectionRange: function() { + // TODO should start be caret position instead? + var range = this.ace.getSelectionRange(); + var doc = this.ace.session.doc; + return { + start: doc.positionToIndex(range.start), + end: doc.positionToIndex(range.end) + }; + }, + + /** + * Creates selection from start to end character + * indexes. If end is ommited, this method should place caret + * and start index + * @param {Number} start + * @param {Number} [end] + * @example + * editor.createSelection(10, 40); + * + * //move caret to 15th character + * editor.createSelection(15); + */ + createSelection: function(start, end) { + var doc = this.ace.session.doc; + this.ace.selection.setRange({ + start: doc.indexToPosition(start), + end: doc.indexToPosition(end) + }); + }, + + /** + * Returns current line's start and end indexes as object with start + * and end properties + * @return {Object} + * @example + * var range = editor.getCurrentLineRange(); + * alert(range.start + ', ' + range.end); + */ + getCurrentLineRange: function() { + var ace = this.ace; + var row = ace.getCursorPosition().row; + var lineLength = ace.session.getLine(row).length; + var index = ace.session.doc.positionToIndex({row: row, column: 0}); + return { + start: index, + end: index + lineLength + }; + }, + + /** + * Returns current caret position + * @return {Number|null} + */ + getCaretPos: function(){ + var pos = this.ace.getCursorPosition(); + return this.ace.session.doc.positionToIndex(pos); + }, + + /** + * Set new caret position + * @param {Number} index Caret position + */ + setCaretPos: function(index){ + var pos = this.ace.session.doc.indexToPosition(index); + this.ace.selection.moveToPosition(pos); + }, + + /** + * Returns content of current line + * @return {String} + */ + getCurrentLine: function() { + var row = this.ace.getCursorPosition().row; + return this.ace.session.getLine(row); + }, + + /** + * Replace editor's content or it's part (from start to + * end index). If value contains + * caret_placeholder, the editor will put caret into + * this position. If you skip start and end + * arguments, the whole target's content will be replaced with + * value. + * + * If you pass start argument only, + * the value will be placed at start string + * index of current content. + * + * If you pass start and end arguments, + * the corresponding substring of current target's content will be + * replaced with value. + * @param {String} value Content you want to paste + * @param {Number} [start] Start index of editor's content + * @param {Number} [end] End index of editor's content + * @param {Boolean} [noIndent] Do not auto indent value + */ + replaceContent: function(value, start, end, noIndent) { + if (end == null) + end = start == null ? this.getContent().length : start; + if (start == null) + start = 0; + + var editor = this.ace; + var doc = editor.session.doc; + var range = Range.fromPoints(doc.indexToPosition(start), doc.indexToPosition(end)); + editor.session.remove(range); + + range.end = range.start; + //editor.selection.setRange(range); + + value = this.$updateTabstops(value); + snippetManager.insertSnippet(editor, value); + }, + + /** + * Returns editor's content + * @return {String} + */ + getContent: function(){ + return this.ace.getValue(); + }, + + /** + * Returns current editor's syntax mode + * @return {String} + */ + getSyntax: function() { + if (this.$syntax) + return this.$syntax; + var syntax = this.ace.session.$modeId.split("/").pop(); + if (syntax == "html" || syntax == "php") { + var cursor = this.ace.getCursorPosition(); + var state = this.ace.session.getState(cursor.row); + if (typeof state != "string") + state = state[0]; + if (state) { + state = state.split("-"); + if (state.length > 1) + syntax = state[0]; + else if (syntax == "php") + syntax = "html"; + } + } + return syntax; + }, + + /** + * Returns current output profile name (@see emmet#setupProfile) + * @return {String} + */ + getProfileName: function() { + switch(this.getSyntax()) { + case "css": return "css"; + case "xml": + case "xsl": + return "xml"; + case "html": + var profile = emmet.require("resources").getVariable("profile"); + // no forced profile, guess from content html or xhtml? + if (!profile) + profile = this.ace.session.getLines(0,2).join("").search(/]+XHTML/i) != -1 ? "xhtml": "html"; + return profile; + } + return "xhtml"; + }, + + /** + * Ask user to enter something + * @param {String} title Dialog title + * @return {String} Entered data + * @since 0.65 + */ + prompt: function(title) { + return prompt(title); + }, + + /** + * Returns current selection + * @return {String} + * @since 0.65 + */ + getSelection: function() { + return this.ace.session.getTextRange(); + }, + + /** + * Returns current editor's file path + * @return {String} + * @since 0.65 + */ + getFilePath: function() { + return ""; + }, + + // update tabstops: make sure all caret placeholders are unique + // by default, abbreviation parser generates all unlinked (un-mirrored) + // tabstops as ${0}, so we have upgrade all caret tabstops with unique + // positions but make sure that all other tabstops are not linked accidentally + // based on https://github.com/sergeche/emmet-sublime/blob/master/editor.js#L119-L171 + $updateTabstops: function(value) { + var base = 1000; + var zeroBase = 0; + var lastZero = null; + var range = emmet.require('range'); + var ts = emmet.require('tabStops'); + var settings = emmet.require('resources').getVocabulary("user"); + var tabstopOptions = { + tabstop: function(data) { + var group = parseInt(data.group, 10); + var isZero = group === 0; + if (isZero) + group = ++zeroBase; + else + group += base; + + var placeholder = data.placeholder; + if (placeholder) { + // recursively update nested tabstops + placeholder = ts.processText(placeholder, tabstopOptions); + } + + var result = '${' + group + (placeholder ? ':' + placeholder : '') + '}'; + + if (isZero) { + lastZero = range.create(data.start, result); + } + + return result; + }, + escape: function(ch) { + if (ch == '$') return '\\$'; + if (ch == '\\') return '\\\\'; + return ch; + } + }; + + value = ts.processText(value, tabstopOptions); + + if (settings.variables['insert_final_tabstop'] && !/\$\{0\}$/.test(value)) { + value += '${0}'; + } else if (lastZero) { + value = emmet.require('utils').replaceSubstring(value, '${0}', lastZero); + } + + return value; + } +}; + + +var keymap = { + expand_abbreviation: {"mac": "ctrl+alt+e", "win": "alt+e"}, + match_pair_outward: {"mac": "ctrl+d", "win": "ctrl+,"}, + match_pair_inward: {"mac": "ctrl+j", "win": "ctrl+shift+0"}, + matching_pair: {"mac": "ctrl+alt+j", "win": "alt+j"}, + next_edit_point: "alt+right", + prev_edit_point: "alt+left", + toggle_comment: {"mac": "command+/", "win": "ctrl+/"}, + split_join_tag: {"mac": "shift+command+'", "win": "shift+ctrl+`"}, + remove_tag: {"mac": "command+'", "win": "shift+ctrl+;"}, + evaluate_math_expression: {"mac": "shift+command+y", "win": "shift+ctrl+y"}, + increment_number_by_1: "ctrl+up", + decrement_number_by_1: "ctrl+down", + increment_number_by_01: "alt+up", + decrement_number_by_01: "alt+down", + increment_number_by_10: {"mac": "alt+command+up", "win": "shift+alt+up"}, + decrement_number_by_10: {"mac": "alt+command+down", "win": "shift+alt+down"}, + select_next_item: {"mac": "shift+command+.", "win": "shift+ctrl+."}, + select_previous_item: {"mac": "shift+command+,", "win": "shift+ctrl+,"}, + reflect_css_value: {"mac": "shift+command+r", "win": "shift+ctrl+r"}, + + encode_decode_data_url: {"mac": "shift+ctrl+d", "win": "ctrl+'"}, + // update_image_size: {"mac": "shift+ctrl+i", "win": "ctrl+u"}, + // expand_as_you_type: "ctrl+alt+enter", + // wrap_as_you_type: {"mac": "shift+ctrl+g", "win": "shift+ctrl+g"}, + expand_abbreviation_with_tab: "Tab", + wrap_with_abbreviation: {"mac": "shift+ctrl+a", "win": "shift+ctrl+a"} +}; + +var editorProxy = new AceEmmetEditor(); +exports.commands = new HashHandler(); +exports.runEmmetCommand = function(editor) { + try { + editorProxy.setupContext(editor); + if (editorProxy.getSyntax() == "php") + return false; + var actions = emmet.require("actions"); + + if (this.action == "expand_abbreviation_with_tab") { + if (!editor.selection.isEmpty()) + return false; + } + + if (this.action == "wrap_with_abbreviation") { + // without setTimeout prompt doesn't work on firefox + return setTimeout(function() { + actions.run("wrap_with_abbreviation", editorProxy); + }, 0); + } + + var pos = editor.selection.lead; + var token = editor.session.getTokenAt(pos.row, pos.column); + if (token && /\btag\b/.test(token.type)) + return false; + + var result = actions.run(this.action, editorProxy); + } catch(e) { + editor._signal("changeStatus", typeof e == "string" ? e : e.message); + console.log(e); + result = false; + } + return result; +}; + +for (var command in keymap) { + exports.commands.addCommand({ + name: "emmet:" + command, + action: command, + bindKey: keymap[command], + exec: exports.runEmmetCommand, + multiSelectAction: "forEach" + }); +} + +exports.updateCommands = function(editor, enabled) { + if (enabled) { + editor.keyBinding.addKeyboardHandler(exports.commands); + } else { + editor.keyBinding.removeKeyboardHandler(exports.commands); + } +}; + +exports.isSupportedMode = function(modeId) { + return modeId && /css|less|scss|sass|stylus|html|php|twig|ejs/.test(modeId); +}; + +var onChangeMode = function(e, target) { + var editor = target; + if (!editor) + return; + var enabled = exports.isSupportedMode(editor.session.$modeId); + if (e.enableEmmet === false) + enabled = false; + if (enabled) { + if (typeof emmetPath == "string") { + require("ace/config").loadModule(emmetPath, function() { + emmetPath = null; + }); + } + } + exports.updateCommands(editor, enabled); +}; + +exports.AceEmmetEditor = AceEmmetEditor; +require("ace/config").defineOptions(Editor.prototype, "editor", { + enableEmmet: { + set: function(val) { + this[val ? "on" : "removeListener"]("changeMode", onChangeMode); + onChangeMode({enableEmmet: !!val}, this); + }, + value: true + } +}); + +exports.setCore = function(e) { + if (typeof e == "string") + emmetPath = e; + else + emmet = e; +}; +}); + diff --git a/node_modules/ace/lib/ace/ext/error_marker.js b/node_modules/ace/lib/ace/ext/error_marker.js new file mode 100644 index 00000000..5dbe3d2e --- /dev/null +++ b/node_modules/ace/lib/ace/ext/error_marker.js @@ -0,0 +1,214 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; +var LineWidgets = require("../line_widgets").LineWidgets; +var dom = require("../lib/dom"); +var Range = require("../range").Range; + +function binarySearch(array, needle, comparator) { + var first = 0; + var last = array.length - 1; + + while (first <= last) { + var mid = (first + last) >> 1; + var c = comparator(needle, array[mid]); + if (c > 0) + first = mid + 1; + else if (c < 0) + last = mid - 1; + else + return mid; + } + + // Return the nearest lesser index, "-1" means "0, "-2" means "1", etc. + return -(first + 1); +} + +function findAnnotations(session, row, dir) { + var annotations = session.getAnnotations().sort(Range.comparePoints); + if (!annotations.length) + return; + + var i = binarySearch(annotations, {row: row, column: -1}, Range.comparePoints); + if (i < 0) + i = -i - 1; + + if (i >= annotations.length) + i = dir > 0 ? 0 : annotations.length - 1; + else if (i === 0 && dir < 0) + i = annotations.length - 1; + + var annotation = annotations[i]; + if (!annotation || !dir) + return; + + if (annotation.row === row) { + do { + annotation = annotations[i += dir]; + } while (annotation && annotation.row === row); + if (!annotation) + return annotations.slice(); + } + + + var matched = []; + row = annotation.row; + do { + matched[dir < 0 ? "unshift" : "push"](annotation); + annotation = annotations[i += dir]; + } while (annotation && annotation.row == row); + return matched.length && matched; +} + +exports.showErrorMarker = function(editor, dir) { + var session = editor.session; + if (!session.widgetManager) { + session.widgetManager = new LineWidgets(session); + session.widgetManager.attach(editor); + } + + var pos = editor.getCursorPosition(); + var row = pos.row; + var oldWidget = session.lineWidgets && session.lineWidgets[row]; + if (oldWidget) { + oldWidget.destroy(); + } else { + row -= dir; + } + var annotations = findAnnotations(session, row, dir); + var gutterAnno; + if (annotations) { + var annotation = annotations[0]; + pos.column = (annotation.pos && typeof annotation.column != "number" + ? annotation.pos.sc + : annotation.column) || 0; + pos.row = annotation.row; + gutterAnno = editor.renderer.$gutterLayer.$annotations[pos.row]; + } else if (oldWidget) { + return; + } else { + gutterAnno = { + text: ["Looks good!"], + className: "ace_ok" + }; + } + editor.session.unfold(pos.row); + editor.selection.moveToPosition(pos); + + var w = { + row: pos.row, + fixedWidth: true, + coverGutter: true, + el: dom.createElement("div") + }; + var el = w.el.appendChild(dom.createElement("div")); + var arrow = w.el.appendChild(dom.createElement("div")); + arrow.className = "error_widget_arrow " + gutterAnno.className; + + var left = editor.renderer.$cursorLayer + .getPixelPosition(pos).left; + arrow.style.left = left + editor.renderer.gutterWidth - 5 + "px"; + + w.el.className = "error_widget_wrapper"; + el.className = "error_widget " + gutterAnno.className; + el.innerHTML = gutterAnno.text.join("
      "); + + el.appendChild(dom.createElement("div")); + + var kb = function(_, hashId, keyString) { + if (hashId === 0 && (keyString === "esc" || keyString === "return")) { + w.destroy(); + return {command: "null"}; + } + }; + + w.destroy = function() { + if (editor.$mouseHandler.isMousePressed) + return; + editor.keyBinding.removeKeyboardHandler(kb); + session.widgetManager.removeLineWidget(w); + editor.off("changeSelection", w.destroy); + editor.off("changeSession", w.destroy); + editor.off("mouseup", w.destroy); + editor.off("change", w.destroy); + }; + + editor.keyBinding.addKeyboardHandler(kb); + editor.on("changeSelection", w.destroy); + editor.on("changeSession", w.destroy); + editor.on("mouseup", w.destroy); + editor.on("change", w.destroy); + + editor.session.widgetManager.addLineWidget(w); + + w.el.onmousedown = editor.focus.bind(editor); + + editor.renderer.scrollCursorIntoView(null, 0.5, {bottom: w.el.offsetHeight}); +}; + + +dom.importCssString("\ + .error_widget_wrapper {\ + background: inherit;\ + color: inherit;\ + border:none\ + }\ + .error_widget {\ + border-top: solid 2px;\ + border-bottom: solid 2px;\ + margin: 5px 0;\ + padding: 10px 40px;\ + white-space: pre-wrap;\ + }\ + .error_widget.ace_error, .error_widget_arrow.ace_error{\ + border-color: #ff5a5a\ + }\ + .error_widget.ace_warning, .error_widget_arrow.ace_warning{\ + border-color: #F1D817\ + }\ + .error_widget.ace_info, .error_widget_arrow.ace_info{\ + border-color: #5a5a5a\ + }\ + .error_widget.ace_ok, .error_widget_arrow.ace_ok{\ + border-color: #5aaa5a\ + }\ + .error_widget_arrow {\ + position: absolute;\ + border: solid 5px;\ + border-top-color: transparent!important;\ + border-right-color: transparent!important;\ + border-left-color: transparent!important;\ + top: -5px;\ + }\ +", ""); + +}); \ No newline at end of file diff --git a/node_modules/ace/lib/ace/ext/keybinding_menu.js b/node_modules/ace/lib/ace/ext/keybinding_menu.js new file mode 100644 index 00000000..bf8189a5 --- /dev/null +++ b/node_modules/ace/lib/ace/ext/keybinding_menu.js @@ -0,0 +1,86 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2013 Matthew Christopher Kastor-Inare III, Atropa Inc. Intl + * All rights reserved. + * + * Contributed to Ajax.org under the BSD license. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +/*jslint indent: 4, maxerr: 50, white: true, browser: true, vars: true*/ +/*global define, require */ + +/** + * Show Keyboard Shortcuts + * @fileOverview Show Keyboard Shortcuts
      + * Generates a menu which displays the keyboard shortcuts. + * @author + * Matthew Christopher Kastor-Inare III
      + * ☭ Hial Atropa!! ☭ + */ + +define(function(require, exports, module) { + "use strict"; + var Editor = require("ace/editor").Editor; + /** + * Generates a menu which displays the keyboard shortcuts. + * @author + * Matthew Christopher Kastor-Inare III
      + * ☭ Hial Atropa!! ☭ + * @param {ace.Editor} editor An instance of the ace editor. + */ + function showKeyboardShortcuts (editor) { + // make sure the menu isn't open already. + if(!document.getElementById('kbshortcutmenu')) { + var overlayPage = require('./menu_tools/overlay_page').overlayPage; + var getEditorKeybordShortcuts = require('./menu_tools/get_editor_keyboard_shortcuts').getEditorKeybordShortcuts; + var kb = getEditorKeybordShortcuts(editor); + var el = document.createElement('div'); + var commands = kb.reduce(function(previous, current) { + return previous + '
      ' + + current.command + ' : ' + + '' + current.key + '
      '; + }, ''); + + el.id = 'kbshortcutmenu'; + el.innerHTML = '

      Keyboard Shortcuts

      ' + commands + ''; + overlayPage(editor, el, '0', '0', '0', null); + } + }; + module.exports.init = function(editor) { + Editor.prototype.showKeyboardShortcuts = function() { + showKeyboardShortcuts(this); + }; + editor.commands.addCommands([{ + name: "showKeyboardShortcuts", + bindKey: {win: "Ctrl-Alt-h", mac: "Command-Alt-h"}, + exec: function(editor, line) { + editor.showKeyboardShortcuts(); + } + }]); + }; + +}); \ No newline at end of file diff --git a/node_modules/ace/lib/ace/ext/language_tools.js b/node_modules/ace/lib/ace/ext/language_tools.js new file mode 100644 index 00000000..f02390ee --- /dev/null +++ b/node_modules/ace/lib/ace/ext/language_tools.js @@ -0,0 +1,226 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var snippetManager = require("../snippets").snippetManager; +var Autocomplete = require("../autocomplete").Autocomplete; +var config = require("../config"); +var lang = require("../lib/lang"); +var util = require("../autocomplete/util"); + +var textCompleter = require("../autocomplete/text_completer"); +var keyWordCompleter = { + getCompletions: function(editor, session, pos, prefix, callback) { + if (session.$mode.completer) { + return session.$mode.completer.getCompletions(editor, session, pos, prefix, callback); + } + var state = editor.session.getState(pos.row); + var completions = session.$mode.getCompletions(state, session, pos, prefix); + callback(null, completions); + } +}; + +var snippetCompleter = { + getCompletions: function(editor, session, pos, prefix, callback) { + var snippetMap = snippetManager.snippetMap; + var completions = []; + snippetManager.getActiveScopes(editor).forEach(function(scope) { + var snippets = snippetMap[scope] || []; + for (var i = snippets.length; i--;) { + var s = snippets[i]; + var caption = s.name || s.tabTrigger; + if (!caption) + continue; + completions.push({ + caption: caption, + snippet: s.content, + meta: s.tabTrigger && !s.name ? s.tabTrigger + "\u21E5 " : "snippet", + type: "snippet" + }); + } + }, this); + callback(null, completions); + }, + getDocTooltip: function(item) { + if (item.type == "snippet" && !item.docHTML) { + item.docHTML = [ + "", lang.escapeHTML(item.caption), "", "
      ", + lang.escapeHTML(item.snippet) + ].join(""); + } + } +}; + +var completers = [snippetCompleter, textCompleter, keyWordCompleter]; +// Allows default completers to be removed or replaced with a explict set of completers +// A null argument here will result in an empty completer array, not a null attribute +exports.setCompleters = function(val) { + completers = val || []; +}; +exports.addCompleter = function(completer) { + completers.push(completer); +}; + +// Exports existing completer so that user can construct his own set of completers. +exports.textCompleter = textCompleter; +exports.keyWordCompleter = keyWordCompleter; +exports.snippetCompleter = snippetCompleter; + +var expandSnippet = { + name: "expandSnippet", + exec: function(editor) { + return snippetManager.expandWithTab(editor); + }, + bindKey: "Tab" +}; + +var onChangeMode = function(e, editor) { + loadSnippetsForMode(editor.session.$mode); +}; + +var loadSnippetsForMode = function(mode) { + var id = mode.$id; + if (!snippetManager.files) + snippetManager.files = {}; + loadSnippetFile(id); + if (mode.modes) + mode.modes.forEach(loadSnippetsForMode); +}; + +var loadSnippetFile = function(id) { + if (!id || snippetManager.files[id]) + return; + var snippetFilePath = id.replace("mode", "snippets"); + snippetManager.files[id] = {}; + config.loadModule(snippetFilePath, function(m) { + if (m) { + snippetManager.files[id] = m; + if (!m.snippets && m.snippetText) + m.snippets = snippetManager.parseSnippetFile(m.snippetText); + snippetManager.register(m.snippets || [], m.scope); + if (m.includeScopes) { + snippetManager.snippetMap[m.scope].includeScopes = m.includeScopes; + m.includeScopes.forEach(function(x) { + loadSnippetFile("ace/mode/" + x); + }); + } + } + }); +}; + +function getCompletionPrefix(editor) { + var pos = editor.getCursorPosition(); + var line = editor.session.getLine(pos.row); + var prefix; + // Try to find custom prefixes on the completers + editor.completers.forEach(function(completer) { + if (completer.identifierRegexps) { + completer.identifierRegexps.forEach(function(identifierRegex) { + if (!prefix && identifierRegex) + prefix = util.retrievePrecedingIdentifier(line, pos.column, identifierRegex); + }); + } + }); + return prefix || util.retrievePrecedingIdentifier(line, pos.column); +} + +var doLiveAutocomplete = function(e) { + var editor = e.editor; + var text = e.args || ""; + var hasCompleter = editor.completer && editor.completer.activated; + + // We don't want to autocomplete with no prefix + if (e.command.name === "backspace") { + if (hasCompleter && !getCompletionPrefix(editor)) + editor.completer.detach(); + } + else if (e.command.name === "insertstring") { + var prefix = getCompletionPrefix(editor); + // Only autocomplete if there's a prefix that can be matched + if (prefix && !hasCompleter) { + if (!editor.completer) { + // Create new autocompleter + editor.completer = new Autocomplete(); + } + // Disable autoInsert + editor.completer.autoInsert = false; + editor.completer.showPopup(editor); + } + } +}; + +var Editor = require("../editor").Editor; +require("../config").defineOptions(Editor.prototype, "editor", { + enableBasicAutocompletion: { + set: function(val) { + if (val) { + if (!this.completers) + this.completers = Array.isArray(val)? val: completers; + this.commands.addCommand(Autocomplete.startCommand); + } else { + this.commands.removeCommand(Autocomplete.startCommand); + } + }, + value: false + }, + /** + * Enable live autocomplete. If the value is an array, it is assumed to be an array of completers + * and will use them instead of the default completers. + */ + enableLiveAutocompletion: { + set: function(val) { + if (val) { + if (!this.completers) + this.completers = Array.isArray(val)? val: completers; + // On each change automatically trigger the autocomplete + this.commands.on('afterExec', doLiveAutocomplete); + } else { + this.commands.removeListener('afterExec', doLiveAutocomplete); + } + }, + value: false + }, + enableSnippets: { + set: function(val) { + if (val) { + this.commands.addCommand(expandSnippet); + this.on("changeMode", onChangeMode); + onChangeMode(null, this); + } else { + this.commands.removeCommand(expandSnippet); + this.off("changeMode", onChangeMode); + } + }, + value: false + } +}); +}); diff --git a/node_modules/ace/lib/ace/ext/linking.js b/node_modules/ace/lib/ace/ext/linking.js new file mode 100644 index 00000000..cfd333b2 --- /dev/null +++ b/node_modules/ace/lib/ace/ext/linking.js @@ -0,0 +1,78 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + +var Editor = require("ace/editor").Editor; + +require("../config").defineOptions(Editor.prototype, "editor", { + enableLinking: { + set: function(val) { + if (val) { + this.on("click", onClick); + this.on("mousemove", onMouseMove); + } else { + this.off("click", onClick); + this.off("mousemove", onMouseMove); + } + }, + value: false + } +}) + +function onMouseMove(e) { + var editor = e.editor; + var ctrl = e.getAccelKey(); + + if (ctrl) { + var editor = e.editor; + var docPos = e.getDocumentPosition(); + var session = editor.session; + var token = session.getTokenAt(docPos.row, docPos.column); + + editor._emit("linkHover", {position: docPos, token: token}); + } +} + +function onClick(e) { + var ctrl = e.getAccelKey(); + var button = e.getButton(); + + if (button == 0 && ctrl) { + var editor = e.editor; + var docPos = e.getDocumentPosition(); + var session = editor.session; + var token = session.getTokenAt(docPos.row, docPos.column); + + editor._emit("linkClick", {position: docPos, token: token}); + } +} + +}); diff --git a/node_modules/ace/lib/ace/ext/menu_tools/add_editor_menu_options.js b/node_modules/ace/lib/ace/ext/menu_tools/add_editor_menu_options.js new file mode 100644 index 00000000..eb90e31d --- /dev/null +++ b/node_modules/ace/lib/ace/ext/menu_tools/add_editor_menu_options.js @@ -0,0 +1,109 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2013 Matthew Christopher Kastor-Inare III, Atropa Inc. Intl + * All rights reserved. + * + * Contributed to Ajax.org under the BSD license. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +/*jslint indent: 4, maxerr: 50, white: true, browser: true, vars: true*/ +/*global define, require */ + +/** + * Add Editor Menu Options + * @fileOverview Add Editor Menu Options
      + * The menu options property needs to be added to the editor + * so that the settings menu can know about options for + * selection elements and track which option is selected. + * @author + * Matthew Christopher Kastor-Inare III
      + * ☭ Hial Atropa!! ☭ + */ + +define(function(require, exports, module) { +'use strict'; + +/** + * The menu options property needs to be added to the editor + * so that the settings menu can know about options for + * selection elements and track which option is selected. + * @author + * Matthew Christopher Kastor-Inare III
      + * ☭ Hial Atropa!! ☭ + * @param {ace.Editor} editor An instance of the ace editor. + */ +module.exports.addEditorMenuOptions = function addEditorMenuOptions (editor) { + var modelist = require('../modelist'); + var themelist = require('../themelist'); + editor.menuOptions = { + setNewLineMode: [{ + textContent: "unix", + value: "unix" + }, { + textContent: "windows", + value: "windows" + }, { + textContent: "auto", + value: "auto" + }], + setTheme: [], + setMode: [], + setKeyboardHandler: [{ + textContent: "ace", + value: "" + }, { + textContent: "vim", + value: "ace/keyboard/vim" + }, { + textContent: "emacs", + value: "ace/keyboard/emacs" + }, { + textContent: "textarea", + value: "ace/keyboard/textarea" + }, { + textContent: "sublime", + value: "ace/keyboard/sublime" + }] + }; + + editor.menuOptions.setTheme = themelist.themes.map(function(theme) { + return { + textContent: theme.caption, + value: theme.theme + }; + }); + + editor.menuOptions.setMode = modelist.modes.map(function(mode) { + return { + textContent: mode.name, + value: mode.mode + }; + }); +}; + + +}); diff --git a/node_modules/ace/lib/ace/ext/menu_tools/element_generator.js b/node_modules/ace/lib/ace/ext/menu_tools/element_generator.js new file mode 100644 index 00000000..ec6ba93b --- /dev/null +++ b/node_modules/ace/lib/ace/ext/menu_tools/element_generator.js @@ -0,0 +1,148 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2013 Matthew Christopher Kastor-Inare III, Atropa Inc. Intl + * All rights reserved. + * + * Contributed to Ajax.org under the BSD license. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +/*jslint indent: 4, maxerr: 50, white: true, browser: true, vars: true*/ +/*global define, require */ + +/** + * Element Generator + * @fileOverview Element Generator
      + * Contains methods for generating elements. + * @author + * Matthew Christopher Kastor-Inare III
      + * ☭ Hial Atropa!! ☭ + */ + +define(function(require, exports, module) { +'use strict'; +/** + * Creates a DOM option element + * @author + * Matthew Christopher Kastor-Inare III
      + * ☭ Hial Atropa!! ☭ + * @param {object} obj An object containing properties to add to the dom + * element. If one of those properties is named `selected` then it will be + * added as an attribute on the element instead. + */ +module.exports.createOption = function createOption (obj) { + var attribute; + var el = document.createElement('option'); + for(attribute in obj) { + if(obj.hasOwnProperty(attribute)) { + if(attribute === 'selected') { + el.setAttribute(attribute, obj[attribute]); + } else { + el[attribute] = obj[attribute]; + } + } + } + return el; +}; +/** + * Creates a DOM checkbox element. + * @author + * Matthew Christopher Kastor-Inare III
      + * ☭ Hial Atropa!! ☭ + * @param {string} id The id of the element. + * @param {boolean} checked Whether or not the element is checked. + * @param {string} clss The class of the element. + * @returns {DOMElement} Returns a checkbox element reference. + */ +module.exports.createCheckbox = function createCheckbox (id, checked, clss) { + var el = document.createElement('input'); + el.setAttribute('type', 'checkbox'); + el.setAttribute('id', id); + el.setAttribute('name', id); + el.setAttribute('value', checked); + el.setAttribute('class', clss); + if(checked) { + el.setAttribute('checked', 'checked'); + } + return el; +}; +/** + * Creates a DOM text input element. + * @author + * Matthew Christopher Kastor-Inare III
      + * ☭ Hial Atropa!! ☭ + * @param {string} id The id of the element. + * @param {string} value The default value of the input element. + * @param {string} clss The class of the element. + * @returns {DOMElement} Returns an input element reference. + */ +module.exports.createInput = function createInput (id, value, clss) { + var el = document.createElement('input'); + el.setAttribute('type', 'text'); + el.setAttribute('id', id); + el.setAttribute('name', id); + el.setAttribute('value', value); + el.setAttribute('class', clss); + return el; +}; +/** + * Creates a DOM label element. + * @author + * Matthew Christopher Kastor-Inare III
      + * ☭ Hial Atropa!! ☭ + * @param {string} text The label text. + * @param {string} labelFor The id of the element being labeled. + * @returns {DOMElement} Returns a label element reference. + */ +module.exports.createLabel = function createLabel (text, labelFor) { + var el = document.createElement('label'); + el.setAttribute('for', labelFor); + el.textContent = text; + return el; +}; +/** + * Creates a DOM selection element. + * @author + * Matthew Christopher Kastor-Inare III
      + * ☭ Hial Atropa!! ☭ + * @param {string} id The id of the element. + * @param {string} values An array of objects suitable for `createOption` + * @param {string} clss The class of the element. + * @returns {DOMElement} Returns a selection element reference. + * @see ace/ext/element_generator.createOption + */ +module.exports.createSelection = function createSelection (id, values, clss) { + var el = document.createElement('select'); + el.setAttribute('id', id); + el.setAttribute('name', id); + el.setAttribute('class', clss); + values.forEach(function(item) { + el.appendChild(module.exports.createOption(item)); + }); + return el; +}; + +}); \ No newline at end of file diff --git a/node_modules/ace/lib/ace/ext/menu_tools/generate_settings_menu.js b/node_modules/ace/lib/ace/ext/menu_tools/generate_settings_menu.js new file mode 100644 index 00000000..89931062 --- /dev/null +++ b/node_modules/ace/lib/ace/ext/menu_tools/generate_settings_menu.js @@ -0,0 +1,264 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2013 Matthew Christopher Kastor-Inare III, Atropa Inc. Intl + * All rights reserved. + * + * Contributed to Ajax.org under the BSD license. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +/*jslint indent: 4, maxerr: 50, white: true, browser: true, vars: true*/ +/*global define*/ + +/** + * Generates the settings menu + * @fileOverview Generates the settings menu. + * @author + * Matthew Christopher Kastor-Inare III
      + * ☭ Hial Atropa!! ☭ + */ + +define(function(require, exports, module) { +'use strict'; +var egen = require('./element_generator'); +var addEditorMenuOptions = require('./add_editor_menu_options').addEditorMenuOptions; +var getSetFunctions = require('./get_set_functions').getSetFunctions; + +/** + * Generates an interactive menu with settings useful to end users. + * @author + * Matthew Christopher Kastor-Inare III
      + * ☭ Hial Atropa!! ☭ + * @param {ace.Editor} editor An instance of the ace editor. + */ +module.exports.generateSettingsMenu = function generateSettingsMenu (editor) { + /** + * container for dom elements that will go in the menu. + * @author + * Matthew Christopher Kastor-Inare III
      + * ☭ Hial Atropa!! ☭ + */ + var elements = []; + /** + * Sorts the menu entries (elements var) so they'll appear in alphabetical order + * the sort is performed based on the value of the contains property + * of each element. Since this is an `array.sort` the array is sorted + * in place. + * @author + * Matthew Christopher Kastor-Inare III
      + * ☭ Hial Atropa!! ☭ + */ + function cleanupElementsList() { + elements.sort(function(a, b) { + var x = a.getAttribute('contains'); + var y = b.getAttribute('contains'); + return x.localeCompare(y); + }); + } + /** + * Wraps all dom elements contained in the elements var with a single + * div. + * @author + * Matthew Christopher Kastor-Inare III
      + * ☭ Hial Atropa!! ☭ + */ + function wrapElements() { + var topmenu = document.createElement('div'); + topmenu.setAttribute('id', 'ace_settingsmenu'); + elements.forEach(function(element) { + topmenu.appendChild(element); + }); + + var el = topmenu.appendChild(document.createElement('div')); + var version = "1.1.8"; + el.style.padding = "1em"; + el.textContent = "Ace version " + version; + + return topmenu; + } + /** + * Creates a new menu entry. + * @author + * Matthew Christopher Kastor-Inare III
      + * ☭ Hial Atropa!! ☭ + * @param {object} obj This is a reference to the object containing the + * set function. It is used to set up event listeners for when the + * menu options change. + * @param {string} clss Maps to the class of the dom element. This is + * the name of the object containing the set function e.g. `editor`, + * `session`, `renderer`. + * @param {string} item This is the set function name. It maps to the + * id of the dom element (check, select, input) and to the "contains" + * attribute of the div holding both the element and its label. + * @param {mixed} val This is the value of the setting. It is mapped to + * the dom element's value, checked, or selected option accordingly. + */ + function createNewEntry(obj, clss, item, val) { + var el; + var div = document.createElement('div'); + div.setAttribute('contains', item); + div.setAttribute('class', 'ace_optionsMenuEntry'); + div.setAttribute('style', 'clear: both;'); + + div.appendChild(egen.createLabel( + item.replace(/^set/, '').replace(/([A-Z])/g, ' $1').trim(), + item + )); + + if (Array.isArray(val)) { + el = egen.createSelection(item, val, clss); + el.addEventListener('change', function(e) { + try{ + editor.menuOptions[e.target.id].forEach(function(x) { + if(x.textContent !== e.target.textContent) { + delete x.selected; + } + }); + obj[e.target.id](e.target.value); + } catch (err) { + throw new Error(err); + } + }); + } else if(typeof val === 'boolean') { + el = egen.createCheckbox(item, val, clss); + el.addEventListener('change', function(e) { + try{ + // renderer['setHighlightGutterLine'](true); + obj[e.target.id](!!e.target.checked); + } catch (err) { + throw new Error(err); + } + }); + } else { + // this aids in giving the ability to specify settings through + // post and get requests. + // /ace_editor.html?setMode=ace/mode/html&setOverwrite=true + el = egen.createInput(item, val, clss); + el.addEventListener('change', function(e) { + try{ + if(e.target.value === 'true') { + obj[e.target.id](true); + } else if(e.target.value === 'false') { + obj[e.target.id](false); + } else { + obj[e.target.id](e.target.value); + } + } catch (err) { + throw new Error(err); + } + }); + } + el.style.cssText = 'float:right;'; + div.appendChild(el); + return div; + } + /** + * Generates selection fields for the menu and populates their options + * using information from `editor.menuOptions` + * @author + * Matthew Christopher Kastor-Inare III
      + * ☭ Hial Atropa!! ☭ + * @param {string} item The set function name. + * @param {object} esr A reference to the object having the set function. + * @param {string} clss The name of the object containing the set function. + * @param {string} fn The matching get function's function name. + * @returns {DOMElement} Returns a dom element containing a selection + * element populated with options. The option whose value matches that + * returned from `esr[fn]()` will be selected. + */ + function makeDropdown(item, esr, clss, fn) { + var val = editor.menuOptions[item]; + var currentVal = esr[fn](); + if (typeof currentVal == 'object') + currentVal = currentVal.$id; + val.forEach(function(valuex) { + if (valuex.value === currentVal) + valuex.selected = 'selected'; + }); + return createNewEntry(esr, clss, item, val); + } + /** + * Processes the set functions returned from `getSetFunctions`. First it + * checks for menu options defined in `editor.menuOptions`. If no + * options are specified then it checks whether there is a get function + * (replace set with get) for the setting. When either of those + * conditions are met it will attempt to create a new entry for the + * settings menu and push it into the elements array defined above. + * It can only do so for get functions which return + * strings, numbers, and booleans. A special case is written in for + * `getMode` where it looks at the returned objects `$id` property and + * forwards that through instead. Other special cases could be written + * in but that would get a bit ridiculous. + * @author + * Matthew Christopher Kastor-Inare III
      + * ☭ Hial Atropa!! ☭ + * @param {object} setObj An item from the array returned by + * `getSetFunctions`. + */ + function handleSet(setObj) { + var item = setObj.functionName; + var esr = setObj.parentObj; + var clss = setObj.parentName; + var val; + var fn = item.replace(/^set/, 'get'); + if(editor.menuOptions[item] !== undefined) { + // has options for select element + elements.push(makeDropdown(item, esr, clss, fn)); + } else if(typeof esr[fn] === 'function') { + // has get function + try { + val = esr[fn](); + if(typeof val === 'object') { + // setMode takes a string, getMode returns an object + // the $id property of that object is the string + // which may be given to setMode... + val = val.$id; + } + // the rest of the get functions return strings, + // booleans, or numbers. + elements.push( + createNewEntry(esr, clss, item, val) + ); + } catch (e) { + // if there are errors it is because the element + // does not belong in the settings menu + } + } + } + addEditorMenuOptions(editor); + // gather the set functions + getSetFunctions(editor).forEach(function(setObj) { + // populate the elements array with good stuff. + handleSet(setObj); + }); + // sort the menu entries in the elements list so people can find + // the settings in alphabetical order. + cleanupElementsList(); + // dump the entries from the elements list and wrap them up in a div + return wrapElements(); +}; + +}); \ No newline at end of file diff --git a/node_modules/ace/lib/ace/ext/menu_tools/get_editor_keyboard_shortcuts.js b/node_modules/ace/lib/ace/ext/menu_tools/get_editor_keyboard_shortcuts.js new file mode 100644 index 00000000..99e006b0 --- /dev/null +++ b/node_modules/ace/lib/ace/ext/menu_tools/get_editor_keyboard_shortcuts.js @@ -0,0 +1,91 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2013 Matthew Christopher Kastor-Inare III, Atropa Inc. Intl + * All rights reserved. + * + * Contributed to Ajax.org under the BSD license. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +/*jslint indent: 4, maxerr: 50, white: true, browser: true, vars: true*/ +/*global define, require */ + +/** + * Get Editor Keyboard Shortcuts + * @fileOverview Get Editor Keyboard Shortcuts
      + * Gets a map of keyboard shortcuts to command names for the current platform. + * @author + * Matthew Christopher Kastor-Inare III
      + * ☭ Hial Atropa!! ☭ + */ + +define(function(require, exports, module) { +"use strict"; +var keys = require("../../lib/keys"); + +/** + * Gets a map of keyboard shortcuts to command names for the current platform. + * @author + * Matthew Christopher Kastor-Inare III
      + * ☭ Hial Atropa!! ☭ + * @param {ace.Editor} editor An editor instance. + * @returns {Array} Returns an array of objects representing the keyboard + * shortcuts for the given editor. + * @example + * var getKbShortcuts = require('./get_keyboard_shortcuts'); + * console.log(getKbShortcuts(editor)); + * // [ + * // {'command' : aCommand, 'key' : 'Control-d'}, + * // {'command' : aCommand, 'key' : 'Control-d'} + * // ] + */ +module.exports.getEditorKeybordShortcuts = function(editor) { + var KEY_MODS = keys.KEY_MODS; + var keybindings = []; + var commandMap = {}; + editor.keyBinding.$handlers.forEach(function(handler) { + var ckb = handler.commandKeyBinding; + for (var i in ckb) { + var key = i.replace(/(^|-)\w/g, function(x) { return x.toUpperCase(); }); + var commands = ckb[i]; + if (!Array.isArray(commands)) + commands = [commands]; + commands.forEach(function(command) { + if (typeof command != "string") + command = command.name + if (commandMap[command]) { + commandMap[command].key += "|" + key; + } else { + commandMap[command] = {key: key, command: command}; + keybindings.push(commandMap[command]); + } + }); + } + }); + return keybindings; +}; + +}); \ No newline at end of file diff --git a/node_modules/ace/lib/ace/ext/menu_tools/get_set_functions.js b/node_modules/ace/lib/ace/ext/menu_tools/get_set_functions.js new file mode 100644 index 00000000..4cd65508 --- /dev/null +++ b/node_modules/ace/lib/ace/ext/menu_tools/get_set_functions.js @@ -0,0 +1,141 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2013 Matthew Christopher Kastor-Inare III, Atropa Inc. Intl + * All rights reserved. + * + * Contributed to Ajax.org under the BSD license. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +/*jslint indent: 4, maxerr: 50, white: true, browser: true, vars: true */ +/*global define*/ + +/** + * Get Set Functions + * @fileOverview Get Set Functions
      + * Gets various functions for setting settings. + * @author + * Matthew Christopher Kastor-Inare III
      + * ☭ Hial Atropa!! ☭ + */ + +define(function(require, exports, module) { +'use strict'; +/** + * Generates a list of set functions for the settings menu. + * @author + * Matthew Christopher Kastor-Inare III
      + * ☭ Hial Atropa!! ☭ + * @param {object} editor The editor instance + * @return {array} Returns an array of objects. Each object contains the + * following properties: functionName, parentObj, and parentName. The + * function name will be the name of a method beginning with the string + * `set` which was found. The parent object will be a reference to the + * object having the method matching the function name. The parent name + * will be a string representing the identifier of the parent object e.g. + * `editor`, `session`, or `renderer`. + */ +module.exports.getSetFunctions = function getSetFunctions (editor) { + /** + * Output array. Will hold the objects described above. + * @author + * Matthew Christopher Kastor-Inare III
      + * ☭ Hial Atropa!! ☭ + */ + var out = []; + /** + * This object provides a map between the objects which will be + * traversed and the parent name which will appear in the output. + * @author + * Matthew Christopher Kastor-Inare III
      + * ☭ Hial Atropa!! ☭ + */ + var my = { + 'editor' : editor, + 'session' : editor.session, + 'renderer' : editor.renderer + }; + /** + * This array will hold the set function names which have already been + * found so that they are not added to the output multiple times. + * @author + * Matthew Christopher Kastor-Inare III
      + * ☭ Hial Atropa!! ☭ + */ + var opts = []; + /** + * This is a list of set functions which will not appear in the settings + * menu. I don't know what to do with setKeyboardHandler. When I tried + * to use it, it didn't appear to be working. Someone who knows better + * could remove it from this list and add it's options to + * add_editor_menu_options.js + * @author + * Matthew Christopher Kastor-Inare III
      + * ☭ Hial Atropa!! ☭ + */ + var skip = [ + 'setOption', + 'setUndoManager', + 'setDocument', + 'setValue', + 'setBreakpoints', + 'setScrollTop', + 'setScrollLeft', + 'setSelectionStyle', + 'setWrapLimitRange' + ]; + + + /** + * This will search the objects mapped to the `my` variable above. When + * it finds a set function in the object that is not listed in the + * `skip` list or the `opts` list it will push a new object to the + * output array. + * @author + * Matthew Christopher Kastor-Inare III
      + * ☭ Hial Atropa!! ☭ + */ + ['renderer', 'session', 'editor'].forEach(function(esra) { + var esr = my[esra]; + var clss = esra; + for(var fn in esr) { + if(skip.indexOf(fn) === -1) { + if(/^set/.test(fn) && opts.indexOf(fn) === -1) { + // found set function + opts.push(fn); + out.push({ + 'functionName' : fn, + 'parentObj' : esr, + 'parentName' : clss + }); + } + } + } + }); + return out; +}; + +}); \ No newline at end of file diff --git a/node_modules/ace/lib/ace/ext/menu_tools/overlay_page.js b/node_modules/ace/lib/ace/ext/menu_tools/overlay_page.js new file mode 100644 index 00000000..bf985e29 --- /dev/null +++ b/node_modules/ace/lib/ace/ext/menu_tools/overlay_page.js @@ -0,0 +1,116 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2013 Matthew Christopher Kastor-Inare III, Atropa Inc. Intl + * All rights reserved. + * + * Contributed to Ajax.org under the BSD license. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +/*jslint indent: 4, maxerr: 50, white: true, browser: true, vars: true*/ +/*global define, require */ + +/** + * Overlay Page + * @fileOverview Overlay Page
      + * Generates an overlay for displaying menus. The overlay is an absolutely + * positioned div. + * @author + * Matthew Christopher Kastor-Inare III
      + * ☭ Hial Atropa!! ☭ + */ + +define(function(require, exports, module) { +'use strict'; +var dom = require("../../lib/dom"); +var cssText = require("../../requirejs/text!./settings_menu.css"); +dom.importCssString(cssText); + +/** + * Generates an overlay for displaying menus. The overlay is an absolutely + * positioned div. + * @author + * Matthew Christopher Kastor-Inare III
      + * ☭ Hial Atropa!! ☭ + * @param {DOMElement} contentElement Any element which may be presented inside + * a div. + * @param {string|number} top absolute position value. + * @param {string|number} right absolute position value. + * @param {string|number} bottom absolute position value. + * @param {string|number} left absolute position value. + */ +module.exports.overlayPage = function overlayPage(editor, contentElement, top, right, bottom, left) { + top = top ? 'top: ' + top + ';' : ''; + bottom = bottom ? 'bottom: ' + bottom + ';' : ''; + right = right ? 'right: ' + right + ';' : ''; + left = left ? 'left: ' + left + ';' : ''; + + var closer = document.createElement('div'); + var contentContainer = document.createElement('div'); + + function documentEscListener(e) { + if (e.keyCode === 27) { + closer.click(); + } + } + + closer.style.cssText = 'margin: 0; padding: 0; ' + + 'position: fixed; top:0; bottom:0; left:0; right:0;' + + 'z-index: 9990; ' + + 'background-color: rgba(0, 0, 0, 0.3);'; + closer.addEventListener('click', function() { + document.removeEventListener('keydown', documentEscListener); + closer.parentNode.removeChild(closer); + editor.focus(); + closer = null; + }); + // click closer if esc key is pressed + document.addEventListener('keydown', documentEscListener); + + contentContainer.style.cssText = top + right + bottom + left; + contentContainer.addEventListener('click', function(e) { + e.stopPropagation(); + }); + + var wrapper = dom.createElement("div"); + wrapper.style.position = "relative"; + + var closeButton = dom.createElement("div"); + closeButton.className = "ace_closeButton"; + closeButton.addEventListener('click', function() { + closer.click(); + }); + + wrapper.appendChild(closeButton); + contentContainer.appendChild(wrapper); + + contentContainer.appendChild(contentElement); + closer.appendChild(contentContainer); + document.body.appendChild(closer); + editor.blur(); +}; + +}); \ No newline at end of file diff --git a/node_modules/ace/lib/ace/ext/menu_tools/settings_menu.css b/node_modules/ace/lib/ace/ext/menu_tools/settings_menu.css new file mode 100644 index 00000000..f8b761ce --- /dev/null +++ b/node_modules/ace/lib/ace/ext/menu_tools/settings_menu.css @@ -0,0 +1,48 @@ +#ace_settingsmenu, #kbshortcutmenu { + background-color: #F7F7F7; + color: black; + box-shadow: -5px 4px 5px rgba(126, 126, 126, 0.55); + padding: 1em 0.5em 2em 1em; + overflow: auto; + position: absolute; + margin: 0; + bottom: 0; + right: 0; + top: 0; + z-index: 9991; + cursor: default; +} + +.ace_dark #ace_settingsmenu, .ace_dark #kbshortcutmenu { + box-shadow: -20px 10px 25px rgba(126, 126, 126, 0.25); + background-color: rgba(255, 255, 255, 0.6); + color: black; +} + +.ace_optionsMenuEntry:hover { + background-color: rgba(100, 100, 100, 0.1); + -webkit-transition: all 0.5s; + transition: all 0.3s +} + +.ace_closeButton { + background: rgba(245, 146, 146, 0.5); + border: 1px solid #F48A8A; + border-radius: 50%; + padding: 7px; + position: absolute; + right: -8px; + top: -8px; + z-index: 1000; +} +.ace_closeButton{ + background: rgba(245, 146, 146, 0.9); +} +.ace_optionsMenuKey { + color: darkslateblue; + font-weight: bold; +} +.ace_optionsMenuCommand { + color: darkcyan; + font-weight: normal; +} \ No newline at end of file diff --git a/node_modules/ace/lib/ace/ext/modelist.js b/node_modules/ace/lib/ace/ext/modelist.js new file mode 100644 index 00000000..cba800ac --- /dev/null +++ b/node_modules/ace/lib/ace/ext/modelist.js @@ -0,0 +1,193 @@ +define(function(require, exports, module) { +"use strict"; + +var modes = []; +/** + * Suggests a mode based on the file extension present in the given path + * @param {string} path The path to the file + * @returns {object} Returns an object containing information about the + * suggested mode. + */ +function getModeForPath(path) { + var mode = modesByName.text; + var fileName = path.split(/[\/\\]/).pop(); + for (var i = 0; i < modes.length; i++) { + if (modes[i].supportsFile(fileName)) { + mode = modes[i]; + break; + } + } + return mode; +} + +var Mode = function(name, caption, extensions) { + this.name = name; + this.caption = caption; + this.mode = "ace/mode/" + name; + this.extensions = extensions; + if (/\^/.test(extensions)) { + var re = extensions.replace(/\|(\^)?/g, function(a, b){ + return "$|" + (b ? "^" : "^.*\\."); + }) + "$"; + } else { + var re = "^.*\\.(" + extensions + ")$"; + } + + this.extRe = new RegExp(re, "gi"); +}; + +Mode.prototype.supportsFile = function(filename) { + return filename.match(this.extRe); +}; + +// todo firstlinematch +var supportedModes = { + ABAP: ["abap"], + ABC: ["abc"], + ActionScript:["as"], + ADA: ["ada|adb"], + Apache_Conf: ["^htaccess|^htgroups|^htpasswd|^conf|htaccess|htgroups|htpasswd"], + AsciiDoc: ["asciidoc"], + Assembly_x86:["asm"], + AutoHotKey: ["ahk"], + BatchFile: ["bat|cmd"], + C9Search: ["c9search_results"], + C_Cpp: ["cpp|c|cc|cxx|h|hh|hpp"], + Cirru: ["cirru|cr"], + Clojure: ["clj|cljs"], + Cobol: ["CBL|COB"], + coffee: ["coffee|cf|cson|^Cakefile"], + ColdFusion: ["cfm"], + CSharp: ["cs"], + CSS: ["css"], + Curly: ["curly"], + D: ["d|di"], + Dart: ["dart"], + Diff: ["diff|patch"], + Dockerfile: ["^Dockerfile"], + Dot: ["dot"], + Dummy: ["dummy"], + DummySyntax: ["dummy"], + Eiffel: ["e"], + EJS: ["ejs"], + Elixir: ["ex|exs"], + Elm: ["elm"], + Erlang: ["erl|hrl"], + Forth: ["frt|fs|ldr"], + FTL: ["ftl"], + Gcode: ["gcode"], + Gherkin: ["feature"], + Gitignore: ["^.gitignore"], + Glsl: ["glsl|frag|vert"], + golang: ["go"], + Groovy: ["groovy"], + HAML: ["haml"], + Handlebars: ["hbs|handlebars|tpl|mustache"], + Haskell: ["hs"], + haXe: ["hx"], + HTML: ["html|htm|xhtml"], + HTML_Ruby: ["erb|rhtml|html.erb"], + INI: ["ini|conf|cfg|prefs"], + Io: ["io"], + Jack: ["jack"], + Jade: ["jade"], + Java: ["java"], + JavaScript: ["js|jsm"], + JSON: ["json"], + JSONiq: ["jq"], + JSP: ["jsp"], + JSX: ["jsx"], + Julia: ["jl"], + LaTeX: ["tex|latex|ltx|bib"], + LESS: ["less"], + Liquid: ["liquid"], + Lisp: ["lisp"], + LiveScript: ["ls"], + LogiQL: ["logic|lql"], + LSL: ["lsl"], + Lua: ["lua"], + LuaPage: ["lp"], + Lucene: ["lucene"], + Makefile: ["^Makefile|^GNUmakefile|^makefile|^OCamlMakefile|make"], + Markdown: ["md|markdown"], + Mask: ["mask"], + MATLAB: ["matlab"], + MEL: ["mel"], + MUSHCode: ["mc|mush"], + MySQL: ["mysql"], + Nix: ["nix"], + ObjectiveC: ["m|mm"], + OCaml: ["ml|mli"], + Pascal: ["pas|p"], + Perl: ["pl|pm"], + pgSQL: ["pgsql"], + PHP: ["php|phtml"], + Powershell: ["ps1"], + Praat: ["praat|praatscript|psc|proc"], + Prolog: ["plg|prolog"], + Properties: ["properties"], + Protobuf: ["proto"], + Python: ["py"], + R: ["r"], + RDoc: ["Rd"], + RHTML: ["Rhtml"], + Ruby: ["rb|ru|gemspec|rake|^Guardfile|^Rakefile|^Gemfile"], + Rust: ["rs"], + SASS: ["sass"], + SCAD: ["scad"], + Scala: ["scala"], + Scheme: ["scm|rkt"], + SCSS: ["scss"], + SH: ["sh|bash|^.bashrc"], + SJS: ["sjs"], + Smarty: ["smarty|tpl"], + snippets: ["snippets"], + Soy_Template:["soy"], + Space: ["space"], + SQL: ["sql"], + Stylus: ["styl|stylus"], + SVG: ["svg"], + Tcl: ["tcl"], + Tex: ["tex"], + Text: ["txt"], + Textile: ["textile"], + Toml: ["toml"], + Twig: ["twig"], + Typescript: ["ts|typescript|str"], + Vala: ["vala"], + VBScript: ["vbs|vb"], + Velocity: ["vm"], + Verilog: ["v|vh|sv|svh"], + VHDL: ["vhd|vhdl"], + XML: ["xml|rdf|rss|wsdl|xslt|atom|mathml|mml|xul|xbl"], + XQuery: ["xq"], + YAML: ["yaml|yml"] +}; + +var nameOverrides = { + ObjectiveC: "Objective-C", + CSharp: "C#", + golang: "Go", + C_Cpp: "C and C++", + coffee: "CoffeeScript", + HTML_Ruby: "HTML (Ruby)", + FTL: "FreeMarker" +}; +var modesByName = {}; +for (var name in supportedModes) { + var data = supportedModes[name]; + var displayName = (nameOverrides[name] || name).replace(/_/g, " "); + var filename = name.toLowerCase(); + var mode = new Mode(filename, displayName, data[0]); + modesByName[filename] = mode; + modes.push(mode); +} + +module.exports = { + getModeForPath: getModeForPath, + modes: modes, + modesByName: modesByName +}; + +}); + diff --git a/node_modules/ace/lib/ace/ext/old_ie.js b/node_modules/ace/lib/ace/ext/old_ie.js new file mode 100644 index 00000000..8b8ce977 --- /dev/null +++ b/node_modules/ace/lib/ace/ext/old_ie.js @@ -0,0 +1,114 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; +var MAX_TOKEN_COUNT = 1000; +var useragent = require("../lib/useragent"); +var TokenizerModule = require("../tokenizer"); + +function patch(obj, name, regexp, replacement) { + eval("obj['" + name + "']=" + obj[name].toString().replace( + regexp, replacement + )); +} + +if (useragent.isIE && useragent.isIE < 10 && window.top.document.compatMode === "BackCompat") + useragent.isOldIE = true; + +if (typeof document != "undefined" && !document.documentElement.querySelector) { + useragent.isOldIE = true; + var qs = function(el, selector) { + if (selector.charAt(0) == ".") { + var classNeme = selector.slice(1); + } else { + var m = selector.match(/(\w+)=(\w+)/); + var attr = m && m[1]; + var attrVal = m && m[2]; + } + for (var i = 0; i < el.all.length; i++) { + var ch = el.all[i]; + if (classNeme) { + if (ch.className.indexOf(classNeme) != -1) + return ch; + } else if (attr) { + if (ch.getAttribute(attr) == attrVal) + return ch; + } + } + }; + var sb = require("./searchbox").SearchBox.prototype; + patch( + sb, "$initElements", + /([^\s=]*).querySelector\((".*?")\)/g, + "qs($1, $2)" + ); +} + +var compliantExecNpcg = /()??/.exec("")[1] === undefined; +if (compliantExecNpcg) + return; +var proto = TokenizerModule.Tokenizer.prototype; +TokenizerModule.Tokenizer_orig = TokenizerModule.Tokenizer; +proto.getLineTokens_orig = proto.getLineTokens; + +patch( + TokenizerModule, "Tokenizer", + "ruleRegExps.push(adjustedregex);\n", + function(m) { + return m + '\ + if (state[i].next && RegExp(adjustedregex).test(""))\n\ + rule._qre = RegExp(adjustedregex, "g");\n\ + '; + } +); +TokenizerModule.Tokenizer.prototype = proto; +patch( + proto, "getLineTokens", + /if \(match\[i \+ 1\] === undefined\)\s*continue;/, + "if (!match[i + 1]) {\n\ + if (value)continue;\n\ + var qre = state[mapping[i]]._qre;\n\ + if (!qre) continue;\n\ + qre.lastIndex = lastIndex;\n\ + if (!qre.exec(line) || qre.lastIndex != lastIndex)\n\ + continue;\n\ + }" +); + +patch( + require("../mode/text").Mode.prototype, "getTokenizer", + /Tokenizer/, + "TokenizerModule.Tokenizer" +); + +useragent.isOldIE = true; + +}); diff --git a/node_modules/ace/lib/ace/ext/old_ie_test.js b/node_modules/ace/lib/ace/ext/old_ie_test.js new file mode 100644 index 00000000..98652e14 --- /dev/null +++ b/node_modules/ace/lib/ace/ext/old_ie_test.js @@ -0,0 +1,77 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +if (typeof process !== "undefined") { + require("amd-loader"); +} + +define(function(require, exports, module) { +"use strict"; + +var assert = require("../test/assertions"); + +module.exports = { + "test: getTokenizer() (smoke test)" : function() { + var exec = RegExp.prototype.exec + var brokenExec = function(str) { + var result = exec.call(this, str); + if (result) { + for (var i = result.length; i--;) + if (!result[i]) + result[i] = ""; + } + return result; + } + + try { + // break this to emulate old ie + RegExp.prototype.exec = brokenExec; + require("./old_ie"); + var Tokenizer = require("../tokenizer").Tokenizer; + var JavaScriptHighlightRules = require("../mode/javascript_highlight_rules").JavaScriptHighlightRules; + var tokenizer = new Tokenizer((new JavaScriptHighlightRules).getRules()); + + var tokens = tokenizer.getLineTokens("'juhu'", "start").tokens; + assert.equal("string", tokens[0].type); + } finally { + // restore modified functions + RegExp.prototype.exec = exec; + var module = require("../tokenizer"); + module.Tokenizer = module.Tokenizer_orig; + module.Tokenizer.prototype.getLineTokens = module.Tokenizer.prototype.getLineTokens_orig; + } + } +}; + +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec() +} diff --git a/node_modules/ace/lib/ace/ext/searchbox.css b/node_modules/ace/lib/ace/ext/searchbox.css new file mode 100644 index 00000000..5de8d847 --- /dev/null +++ b/node_modules/ace/lib/ace/ext/searchbox.css @@ -0,0 +1,153 @@ + + +/* ------------------------------------------------------------------------------------------ + * Editor Search Form + * --------------------------------------------------------------------------------------- */ + .ace_search { + background-color: #ddd; + border: 1px solid #cbcbcb; + border-top: 0 none; + max-width: 325px; + overflow: hidden; + margin: 0; + padding: 4px; + padding-right: 6px; + padding-bottom: 0; + position: absolute; + top: 0px; + z-index: 99; + white-space: normal; +} +.ace_search.left { + border-left: 0 none; + border-radius: 0px 0px 5px 0px; + left: 0; +} +.ace_search.right { + border-radius: 0px 0px 0px 5px; + border-right: 0 none; + right: 0; +} + +.ace_search_form, .ace_replace_form { + border-radius: 3px; + border: 1px solid #cbcbcb; + float: left; + margin-bottom: 4px; + overflow: hidden; +} +.ace_search_form.ace_nomatch { + outline: 1px solid red; +} + +.ace_search_field { + background-color: white; + border-right: 1px solid #cbcbcb; + border: 0 none; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + float: left; + height: 22px; + outline: 0; + padding: 0 7px; + width: 214px; + margin: 0; +} +.ace_searchbtn, +.ace_replacebtn { + background: #fff; + border: 0 none; + border-left: 1px solid #dcdcdc; + cursor: pointer; + float: left; + height: 22px; + margin: 0; + padding: 0; + position: relative; +} +.ace_searchbtn:last-child, +.ace_replacebtn:last-child { + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; +} +.ace_searchbtn:disabled { + background: none; + cursor: default; +} +.ace_searchbtn { + background-position: 50% 50%; + background-repeat: no-repeat; + width: 27px; +} +.ace_searchbtn.prev { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAFCAYAAAB4ka1VAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAADFJREFUeNpiSU1NZUAC/6E0I0yACYskCpsJiySKIiY0SUZk40FyTEgCjGgKwTRAgAEAQJUIPCE+qfkAAAAASUVORK5CYII=); +} +.ace_searchbtn.next { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAFCAYAAAB4ka1VAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAADRJREFUeNpiTE1NZQCC/0DMyIAKwGJMUAYDEo3M/s+EpvM/mkKwCQxYjIeLMaELoLMBAgwAU7UJObTKsvAAAAAASUVORK5CYII=); +} +.ace_searchbtn_close { + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAcCAYAAABRVo5BAAAAZ0lEQVR42u2SUQrAMAhDvazn8OjZBilCkYVVxiis8H4CT0VrAJb4WHT3C5xU2a2IQZXJjiQIRMdkEoJ5Q2yMqpfDIo+XY4k6h+YXOyKqTIj5REaxloNAd0xiKmAtsTHqW8sR2W5f7gCu5nWFUpVjZwAAAABJRU5ErkJggg==) no-repeat 50% 0; + border-radius: 50%; + border: 0 none; + color: #656565; + cursor: pointer; + float: right; + font: 16px/16px Arial; + height: 14px; + margin: 5px 1px 9px 5px; + padding: 0; + text-align: center; + width: 14px; +} +.ace_searchbtn_close:hover { + background-color: #656565; + background-position: 50% 100%; + color: white; +} +.ace_replacebtn.prev { + width: 54px +} +.ace_replacebtn.next { + width: 27px +} + +.ace_button { + margin-left: 2px; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -o-user-select: none; + -ms-user-select: none; + user-select: none; + overflow: hidden; + opacity: 0.7; + border: 1px solid rgba(100,100,100,0.23); + padding: 1px; + -moz-box-sizing: border-box; + box-sizing: border-box; + color: black; +} + +.ace_button:hover { + background-color: #eee; + opacity:1; +} +.ace_button:active { + background-color: #ddd; +} + +.ace_button.checked { + border-color: #3399ff; + opacity:1; +} + +.ace_search_options{ + margin-bottom: 3px; + text-align: right; + -webkit-user-select: none; + -moz-user-select: none; + -o-user-select: none; + -ms-user-select: none; + user-select: none; +} \ No newline at end of file diff --git a/node_modules/ace/lib/ace/ext/searchbox.js b/node_modules/ace/lib/ace/ext/searchbox.js new file mode 100644 index 00000000..b316aa75 --- /dev/null +++ b/node_modules/ace/lib/ace/ext/searchbox.js @@ -0,0 +1,308 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var dom = require("../lib/dom"); +var lang = require("../lib/lang"); +var event = require("../lib/event"); +var searchboxCss = require("../requirejs/text!./searchbox.css"); +var HashHandler = require("../keyboard/hash_handler").HashHandler; +var keyUtil = require("../lib/keys"); + +dom.importCssString(searchboxCss, "ace_searchbox"); + +var html = ''.replace(/>\s+/g, ">"); + +var SearchBox = function(editor, range, showReplaceForm) { + var div = dom.createElement("div"); + div.innerHTML = html; + this.element = div.firstChild; + + this.$init(); + this.setEditor(editor); +}; + +(function() { + this.setEditor = function(editor) { + editor.searchBox = this; + editor.container.appendChild(this.element); + this.editor = editor; + }; + + this.$initElements = function(sb) { + this.searchBox = sb.querySelector(".ace_search_form"); + this.replaceBox = sb.querySelector(".ace_replace_form"); + this.searchOptions = sb.querySelector(".ace_search_options"); + this.regExpOption = sb.querySelector("[action=toggleRegexpMode]"); + this.caseSensitiveOption = sb.querySelector("[action=toggleCaseSensitive]"); + this.wholeWordOption = sb.querySelector("[action=toggleWholeWords]"); + this.searchInput = this.searchBox.querySelector(".ace_search_field"); + this.replaceInput = this.replaceBox.querySelector(".ace_search_field"); + }; + + this.$init = function() { + var sb = this.element; + + this.$initElements(sb); + + var _this = this; + event.addListener(sb, "mousedown", function(e) { + setTimeout(function(){ + _this.activeInput.focus(); + }, 0); + event.stopPropagation(e); + }); + event.addListener(sb, "click", function(e) { + var t = e.target || e.srcElement; + var action = t.getAttribute("action"); + if (action && _this[action]) + _this[action](); + else if (_this.$searchBarKb.commands[action]) + _this.$searchBarKb.commands[action].exec(_this); + event.stopPropagation(e); + }); + + event.addCommandKeyListener(sb, function(e, hashId, keyCode) { + var keyString = keyUtil.keyCodeToString(keyCode); + var command = _this.$searchBarKb.findKeyCommand(hashId, keyString); + if (command && command.exec) { + command.exec(_this); + event.stopEvent(e); + } + }); + + this.$onChange = lang.delayedCall(function() { + _this.find(false, false); + }); + + event.addListener(this.searchInput, "input", function() { + _this.$onChange.schedule(20); + }); + event.addListener(this.searchInput, "focus", function() { + _this.activeInput = _this.searchInput; + _this.searchInput.value && _this.highlight(); + }); + event.addListener(this.replaceInput, "focus", function() { + _this.activeInput = _this.replaceInput; + _this.searchInput.value && _this.highlight(); + }); + }; + + //keybinging outsite of the searchbox + this.$closeSearchBarKb = new HashHandler([{ + bindKey: "Esc", + name: "closeSearchBar", + exec: function(editor) { + editor.searchBox.hide(); + } + }]); + + //keybinging outsite of the searchbox + this.$searchBarKb = new HashHandler(); + this.$searchBarKb.bindKeys({ + "Ctrl-f|Command-f|Ctrl-H|Command-Option-F": function(sb) { + var isReplace = sb.isReplace = !sb.isReplace; + sb.replaceBox.style.display = isReplace ? "" : "none"; + sb[isReplace ? "replaceInput" : "searchInput"].focus(); + }, + "Ctrl-G|Command-G": function(sb) { + sb.findNext(); + }, + "Ctrl-Shift-G|Command-Shift-G": function(sb) { + sb.findPrev(); + }, + "esc": function(sb) { + setTimeout(function() { sb.hide();}); + }, + "Return": function(sb) { + if (sb.activeInput == sb.replaceInput) + sb.replace(); + sb.findNext(); + }, + "Shift-Return": function(sb) { + if (sb.activeInput == sb.replaceInput) + sb.replace(); + sb.findPrev(); + }, + "Alt-Return": function(sb) { + if (sb.activeInput == sb.replaceInput) + sb.replaceAll(); + sb.findAll(); + }, + "Tab": function(sb) { + (sb.activeInput == sb.replaceInput ? sb.searchInput : sb.replaceInput).focus(); + } + }); + + this.$searchBarKb.addCommands([{ + name: "toggleRegexpMode", + bindKey: {win: "Alt-R|Alt-/", mac: "Ctrl-Alt-R|Ctrl-Alt-/"}, + exec: function(sb) { + sb.regExpOption.checked = !sb.regExpOption.checked; + sb.$syncOptions(); + } + }, { + name: "toggleCaseSensitive", + bindKey: {win: "Alt-C|Alt-I", mac: "Ctrl-Alt-R|Ctrl-Alt-I"}, + exec: function(sb) { + sb.caseSensitiveOption.checked = !sb.caseSensitiveOption.checked; + sb.$syncOptions(); + } + }, { + name: "toggleWholeWords", + bindKey: {win: "Alt-B|Alt-W", mac: "Ctrl-Alt-B|Ctrl-Alt-W"}, + exec: function(sb) { + sb.wholeWordOption.checked = !sb.wholeWordOption.checked; + sb.$syncOptions(); + } + }]); + + this.$syncOptions = function() { + dom.setCssClass(this.regExpOption, "checked", this.regExpOption.checked); + dom.setCssClass(this.wholeWordOption, "checked", this.wholeWordOption.checked); + dom.setCssClass(this.caseSensitiveOption, "checked", this.caseSensitiveOption.checked); + this.find(false, false); + }; + + this.highlight = function(re) { + this.editor.session.highlight(re || this.editor.$search.$options.re); + this.editor.renderer.updateBackMarkers() + }; + this.find = function(skipCurrent, backwards) { + var range = this.editor.find(this.searchInput.value, { + skipCurrent: skipCurrent, + backwards: backwards, + wrap: true, + regExp: this.regExpOption.checked, + caseSensitive: this.caseSensitiveOption.checked, + wholeWord: this.wholeWordOption.checked + }); + var noMatch = !range && this.searchInput.value; + dom.setCssClass(this.searchBox, "ace_nomatch", noMatch); + this.editor._emit("findSearchBox", { match: !noMatch }); + this.highlight(); + }; + this.findNext = function() { + this.find(true, false); + }; + this.findPrev = function() { + this.find(true, true); + }; + this.findAll = function(){ + var range = this.editor.findAll(this.searchInput.value, { + regExp: this.regExpOption.checked, + caseSensitive: this.caseSensitiveOption.checked, + wholeWord: this.wholeWordOption.checked + }); + var noMatch = !range && this.searchInput.value; + dom.setCssClass(this.searchBox, "ace_nomatch", noMatch); + this.editor._emit("findSearchBox", { match: !noMatch }); + this.highlight(); + this.hide(); + }; + this.replace = function() { + if (!this.editor.getReadOnly()) + this.editor.replace(this.replaceInput.value); + }; + this.replaceAndFindNext = function() { + if (!this.editor.getReadOnly()) { + this.editor.replace(this.replaceInput.value); + this.findNext() + } + }; + this.replaceAll = function() { + if (!this.editor.getReadOnly()) + this.editor.replaceAll(this.replaceInput.value); + }; + + this.hide = function() { + this.element.style.display = "none"; + this.editor.keyBinding.removeKeyboardHandler(this.$closeSearchBarKb); + this.editor.focus(); + }; + this.show = function(value, isReplace) { + this.element.style.display = ""; + this.replaceBox.style.display = isReplace ? "" : "none"; + + this.isReplace = isReplace; + + if (value) + this.searchInput.value = value; + this.searchInput.focus(); + this.searchInput.select(); + + this.editor.keyBinding.addKeyboardHandler(this.$closeSearchBarKb); + }; + + this.isFocused = function() { + var el = document.activeElement; + return el == this.searchInput || el == this.replaceInput; + } +}).call(SearchBox.prototype); + +exports.SearchBox = SearchBox; + +exports.Search = function(editor, isReplace) { + var sb = editor.searchBox || new SearchBox(editor); + sb.show(editor.session.getTextRange(), isReplace); +}; + +}); + + +/* ------------------------------------------------------------------------------------------ + * TODO + * --------------------------------------------------------------------------------------- */ +/* +- move search form to the left if it masks current word +- includ all options that search has. ex: regex +- searchbox.searchbox is not that pretty. we should have just searchbox +- disable prev button if it makes sence +*/ diff --git a/node_modules/ace/lib/ace/ext/settings_menu.js b/node_modules/ace/lib/ace/ext/settings_menu.js new file mode 100644 index 00000000..44f6d6ad --- /dev/null +++ b/node_modules/ace/lib/ace/ext/settings_menu.js @@ -0,0 +1,76 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2013 Matthew Christopher Kastor-Inare III, Atropa Inc. Intl + * All rights reserved. + * + * Contributed to Ajax.org under the BSD license. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +/*jslint indent: 4, maxerr: 50, white: true, browser: true, vars: true*/ +/*global define, require */ + +/** + * Show Settings Menu + * @fileOverview Show Settings Menu
      + * Displays an interactive settings menu mostly generated on the fly based on + * the current state of the editor. + * @author + * Matthew Christopher Kastor-Inare III
      + * ☭ Hial Atropa!! ☭ + */ + +define(function(require, exports, module) { +"use strict"; +var generateSettingsMenu = require('./menu_tools/generate_settings_menu').generateSettingsMenu; +var overlayPage = require('./menu_tools/overlay_page').overlayPage; +/** + * This displays the settings menu if it is not already being shown. + * @author + * Matthew Christopher Kastor-Inare III
      + * ☭ Hial Atropa!! ☭ + * @param {ace.Editor} editor An instance of the ace editor. + */ +function showSettingsMenu(editor) { + // make sure the menu isn't open already. + var sm = document.getElementById('ace_settingsmenu'); + if (!sm) + overlayPage(editor, generateSettingsMenu(editor), '0', '0', '0'); +} + +/** + * Initializes the settings menu extension. It adds the showSettingsMenu + * method to the given editor object and adds the showSettingsMenu command + * to the editor with appropriate keyboard shortcuts. + * @param {ace.Editor} editor An instance of the Editor. + */ +module.exports.init = function(editor) { + var Editor = require("ace/editor").Editor; + Editor.prototype.showSettingsMenu = function() { + showSettingsMenu(this); + }; +}; +}); \ No newline at end of file diff --git a/node_modules/ace/lib/ace/ext/spellcheck.js b/node_modules/ace/lib/ace/ext/spellcheck.js new file mode 100644 index 00000000..08bf2189 --- /dev/null +++ b/node_modules/ace/lib/ace/ext/spellcheck.js @@ -0,0 +1,69 @@ +define(function(require, exports, module) { +"use strict"; +var event = require("../lib/event"); + +exports.contextMenuHandler = function(e){ + var host = e.target; + var text = host.textInput.getElement(); + if (!host.selection.isEmpty()) + return; + var c = host.getCursorPosition(); + var r = host.session.getWordRange(c.row, c.column); + var w = host.session.getTextRange(r); + + host.session.tokenRe.lastIndex = 0; + if (!host.session.tokenRe.test(w)) + return; + var PLACEHOLDER = "\x01\x01"; + var value = w + " " + PLACEHOLDER; + text.value = value; + text.setSelectionRange(w.length, w.length + 1); + text.setSelectionRange(0, 0); + text.setSelectionRange(0, w.length); + + var afterKeydown = false; + event.addListener(text, "keydown", function onKeydown() { + event.removeListener(text, "keydown", onKeydown); + afterKeydown = true; + }); + + host.textInput.setInputHandler(function(newVal) { + console.log(newVal , value, text.selectionStart, text.selectionEnd) + if (newVal == value) + return ''; + if (newVal.lastIndexOf(value, 0) === 0) + return newVal.slice(value.length); + if (newVal.substr(text.selectionEnd) == value) + return newVal.slice(0, -value.length); + if (newVal.slice(-2) == PLACEHOLDER) { + var val = newVal.slice(0, -2); + if (val.slice(-1) == " ") { + if (afterKeydown) + return val.substring(0, text.selectionEnd); + val = val.slice(0, -1); + host.session.replace(r, val); + return ""; + } + } + + return newVal; + }); +}; +// todo support highlighting with typo.js +var Editor = require("../editor").Editor; +require("../config").defineOptions(Editor.prototype, "editor", { + spellcheck: { + set: function(val) { + var text = this.textInput.getElement(); + text.spellcheck = !!val; + if (!val) + this.removeListener("nativecontextmenu", exports.contextMenuHandler); + else + this.on("nativecontextmenu", exports.contextMenuHandler); + }, + value: true + } +}); + +}); + diff --git a/node_modules/ace/lib/ace/ext/split.js b/node_modules/ace/lib/ace/ext/split.js new file mode 100644 index 00000000..8316562f --- /dev/null +++ b/node_modules/ace/lib/ace/ext/split.js @@ -0,0 +1,40 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +/** + * this is experimental, and subject to change, use at your own risk! + */ +module.exports = require("../split"); + +}); + diff --git a/node_modules/ace/lib/ace/ext/static.css b/node_modules/ace/lib/ace/ext/static.css new file mode 100644 index 00000000..cc7da8a6 --- /dev/null +++ b/node_modules/ace/lib/ace/ext/static.css @@ -0,0 +1,31 @@ +.ace_static_highlight { + font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', 'Droid Sans Mono', monospace; + font-size: 12px; +} + +.ace_static_highlight .ace_gutter { + width: 25px !important; + float: left; + text-align: right; + padding: 0 3px 0 0; + margin-right: 3px; + position: static !important; +} + +.ace_static_highlight .ace_line { clear: both; } + +.ace_static_highlight .ace_gutter-cell { + -moz-user-select: -moz-none; + -khtml-user-select: none; + -webkit-user-select: none; + user-select: none; +} + + +.ace_static_highlight .ace_gutter-cell:before { + content: counter(ace_line, decimal); + counter-increment: ace_line; +} +.ace_static_highlight { + counter-reset: ace_line; +} diff --git a/node_modules/ace/lib/ace/ext/static_highlight.js b/node_modules/ace/lib/ace/ext/static_highlight.js new file mode 100644 index 00000000..9116467b --- /dev/null +++ b/node_modules/ace/lib/ace/ext/static_highlight.js @@ -0,0 +1,190 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var EditSession = require("../edit_session").EditSession; +var TextLayer = require("../layer/text").Text; +var baseStyles = require("../requirejs/text!./static.css"); +var config = require("../config"); +var dom = require("../lib/dom"); + + +var highlight = function(el, opts, callback) { + var m = el.className.match(/lang-(\w+)/); + var mode = opts.mode || m && ("ace/mode/" + m[1]); + if (!mode) + return false; + var theme = opts.theme || "ace/theme/textmate"; + + var data = ""; + var nodes = []; + + if (el.firstElementChild) { + var textLen = 0; + for (var i = 0; i < el.childNodes.length; i++) { + var ch = el.childNodes[i]; + if (ch.nodeType == 3) { + textLen += ch.data.length; + data += ch.data; + } else { + nodes.push(textLen, ch); + } + } + } else { + data = dom.getInnerText(el); + if (opts.trim) + data = data.trim(); + } + + highlight.render(data, mode, theme, opts.firstLineNumber, !opts.showGutter, function (highlighted) { + dom.importCssString(highlighted.css, "ace_highlight"); + el.innerHTML = highlighted.html; + var container = el.firstChild.firstChild; + for (var i = 0; i < nodes.length; i += 2) { + var pos = highlighted.session.doc.indexToPosition(nodes[i]); + var node = nodes[i + 1]; + var lineEl = container.children[pos.row]; + lineEl && lineEl.appendChild(node); + } + callback && callback(); + }); +}; + +/** + * Transforms a given input code snippet into HTML using the given mode + * + * @param {string} input Code snippet + * @param {string|mode} mode String specifying the mode to load such as + * `ace/mode/javascript` or, a mode loaded from `/ace/mode` + * (use 'ServerSideHiglighter.getMode'). + * @param {string|theme} theme String specifying the theme to load such as + * `ace/theme/twilight` or, a theme loaded from `/ace/theme`. + * @param {number} lineStart A number indicating the first line number. Defaults + * to 1. + * @param {boolean} disableGutter Specifies whether or not to disable the gutter. + * `true` disables the gutter, `false` enables the gutter. Defaults to `false`. + * @param {function} callback When specifying the mode or theme as a string, + * this method has no return value and you must specify a callback function. The + * callback will receive the rendered object containing the properties `html` + * and `css`. + * @returns {object} An object containing the properties `html` and `css`. + */ +highlight.render = function(input, mode, theme, lineStart, disableGutter, callback) { + var waiting = 1; + var modeCache = EditSession.prototype.$modes; + + // if either the theme or the mode were specified as objects + // then we need to lazily load them. + if (typeof theme == "string") { + waiting++; + config.loadModule(['theme', theme], function(m) { + theme = m; + --waiting || done(); + }); + } + // allow setting mode options e.h {path: "ace/mode/php", inline:true} + var modeOptions; + if (mode && typeof mode === "object" && !mode.getTokenizer) { + modeOptions = mode; + mode = modeOptions.path; + } + if (typeof mode == "string") { + waiting++; + config.loadModule(['mode', mode], function(m) { + if (!modeCache[mode] || modeOptions) + modeCache[mode] = new m.Mode(modeOptions); + mode = modeCache[mode]; + --waiting || done(); + }); + } + + // loads or passes the specified mode module then calls renderer + function done() { + var result = highlight.renderSync(input, mode, theme, lineStart, disableGutter); + return callback ? callback(result) : result; + } + return --waiting || done(); +}; + +/** + * Transforms a given input code snippet into HTML using the given mode + * @param {string} input Code snippet + * @param {mode} mode Mode loaded from /ace/mode (use 'ServerSideHiglighter.getMode') + * @param {string} r Code snippet + * @returns {object} An object containing: html, css + */ +highlight.renderSync = function(input, mode, theme, lineStart, disableGutter) { + lineStart = parseInt(lineStart || 1, 10); + + var session = new EditSession(""); + session.setUseWorker(false); + session.setMode(mode); + + var textLayer = new TextLayer(document.createElement("div")); + textLayer.setSession(session); + textLayer.config = { + characterWidth: 10, + lineHeight: 20 + }; + + session.setValue(input); + + var stringBuilder = []; + var length = session.getLength(); + + for(var ix = 0; ix < length; ix++) { + stringBuilder.push("
      "); + if (!disableGutter) + stringBuilder.push("" + /*(ix + lineStart) + */ ""); + textLayer.$renderLine(stringBuilder, ix, true, false); + stringBuilder.push("\n
      "); + } + + // let's prepare the whole html + var html = "
      " + + "
      " + + stringBuilder.join("") + + "
      " + + "
      "; + + textLayer.destroy(); + + return { + css: baseStyles + theme.cssText, + html: html, + session: session + }; +}; + +module.exports = highlight; +module.exports.highlight =highlight; +}); diff --git a/node_modules/ace/lib/ace/ext/static_highlight_test.js b/node_modules/ace/lib/ace/ext/static_highlight_test.js new file mode 100644 index 00000000..075cea7b --- /dev/null +++ b/node_modules/ace/lib/ace/ext/static_highlight_test.js @@ -0,0 +1,96 @@ +if (typeof process !== "undefined") { + require("amd-loader"); + require("../test/mockdom"); +} + +define(function(require, exports, module) { +"use strict"; + +var assert = require("assert"); +var highlighter = require("./static_highlight"); +var JavaScriptMode = require("../mode/javascript").Mode; +var TextMode = require("../mode/text").Mode; + +// Execution ORDER: test.setUpSuite, setUp, testFn, tearDown, test.tearDownSuite +module.exports = { + timeout: 10000, + + "test simple snippet": function(next) { + var theme = require("../theme/tomorrow"); + var snippet = [ + "/** this is a function", + "*", + "*/", + "function hello (a, b, c) {", + " console.log(a * b + c + 'sup$');", + "}" + ].join("\n"); + var mode = new JavaScriptMode(); + + var result = highlighter.render(snippet, mode, theme); + assert.equal(result.html, "
      " + + "
      /**\xa0this\xa0is\xa0a\xa0function\n
      " + + "
      *\n
      " + + "
      */\n
      " + + "
      function\xa0hello\xa0(a,\xa0b,\xa0c)\xa0{\n
      " + + "
      \xa0\xa0\xa0\xa0console.log(a\xa0*\xa0b\xa0+\xa0c\xa0+\xa0'sup$');\n
      " + + "
      }\n
      " + + "
      "); + assert.ok(!!result.css); + next(); + }, + + "test css from theme is used": function(next) { + var theme = require("../theme/tomorrow"); + var snippet = [ + "/** this is a function", + "*", + "*/", + "function hello (a, b, c) {", + " console.log(a * b + c + 'sup?');", + "}" + ].join("\n"); + var mode = new JavaScriptMode(); + + var result = highlighter.render(snippet, mode, theme); + + assert.ok(result.css.indexOf(theme.cssText) !== -1); + + next(); + }, + + "test theme classname should be in output html": function(next) { + var theme = require("../theme/tomorrow"); + var snippet = [ + "/** this is a function", + "*", + "*/", + "function hello (a, b, c) {", + " console.log(a * b + c + 'sup?');", + "}" + ].join("\n"); + var mode = new JavaScriptMode(); + + var result = highlighter.render(snippet, mode, theme); + assert.equal(!!result.html.match(/
      /), true); + + next(); + }, + + "test js string replace specials": function(next) { + var theme = require("../theme/tomorrow"); + var snippet = "$'$1$2$$$&"; + var mode = new TextMode(); + + var result = highlighter.render(snippet, mode, theme); + assert.ok(result.html.indexOf(snippet) != -1); + + next(); + } +}; + +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec(); +} diff --git a/node_modules/ace/lib/ace/ext/statusbar.js b/node_modules/ace/lib/ace/ext/statusbar.js new file mode 100644 index 00000000..5e5b0572 --- /dev/null +++ b/node_modules/ace/lib/ace/ext/statusbar.js @@ -0,0 +1,48 @@ +define(function(require, exports, module) { +"use strict"; +/** simple statusbar **/ +var dom = require("ace/lib/dom"); +var lang = require("ace/lib/lang"); + +var StatusBar = function(editor, parentNode) { + this.element = dom.createElement("div"); + this.element.className = "ace_status-indicator"; + this.element.style.cssText = "display: inline-block;"; + parentNode.appendChild(this.element); + + var statusUpdate = lang.delayedCall(function(){ + this.updateStatus(editor) + }.bind(this)); + editor.on("changeStatus", function() { + statusUpdate.schedule(100); + }); + editor.on("changeSelection", function() { + statusUpdate.schedule(100); + }); +}; + +(function(){ + this.updateStatus = function(editor) { + var status = []; + function add(str, separator) { + str && status.push(str, separator || "|"); + } + + add(editor.keyBinding.getStatusText(editor)); + if (editor.commands.recording) + add("REC"); + + var c = editor.selection.lead; + add(c.row + ":" + c.column, " "); + if (!editor.selection.isEmpty()) { + var r = editor.getSelectionRange(); + add("(" + (r.end.row - r.start.row) + ":" +(r.end.column - r.start.column) + ")"); + } + status.pop(); + this.element.textContent = status.join(""); + }; +}).call(StatusBar.prototype); + +exports.StatusBar = StatusBar; + +}); \ No newline at end of file diff --git a/node_modules/ace/lib/ace/ext/textarea.js b/node_modules/ace/lib/ace/ext/textarea.js new file mode 100644 index 00000000..c9972488 --- /dev/null +++ b/node_modules/ace/lib/ace/ext/textarea.js @@ -0,0 +1,521 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var event = require("../lib/event"); +var UA = require("../lib/useragent"); +var net = require("../lib/net"); +var ace = require("../ace"); + +require("../theme/textmate"); + +module.exports = exports = ace; + +/* + * Returns the CSS property of element. + * 1) If the CSS property is on the style object of the element, use it, OR + * 2) Compute the CSS property + * + * If the property can't get computed, is 'auto' or 'intrinsic', the former + * calculated property is used (this can happen in cases where the textarea + * is hidden and has no dimension styles). + */ +var getCSSProperty = function(element, container, property) { + var ret = element.style[property]; + + if (!ret) { + if (window.getComputedStyle) { + ret = window.getComputedStyle(element, '').getPropertyValue(property); + } else { + ret = element.currentStyle[property]; + } + } + + if (!ret || ret == 'auto' || ret == 'intrinsic') { + ret = container.style[property]; + } + return ret; +}; + +function applyStyles(elm, styles) { + for (var style in styles) { + elm.style[style] = styles[style]; + } +} + +function setupContainer(element, getValue) { + if (element.type != 'textarea') { + throw new Error("Textarea required!"); + } + + var parentNode = element.parentNode; + + // This will hold the editor. + var container = document.createElement('div'); + + // To put Ace in the place of the textarea, we have to copy a few of the + // textarea's style attributes to the div container. + // + // The problem is that the properties have to get computed (they might be + // defined by a CSS file on the page - you can't access such rules that + // apply to an element via elm.style). Computed properties are converted to + // pixels although the dimension might be given as percentage. When the + // window resizes, the dimensions defined by percentages changes, so the + // properties have to get recomputed to get the new/true pixels. + var resizeEvent = function() { + var style = 'position:relative;'; + [ + 'margin-top', 'margin-left', 'margin-right', 'margin-bottom' + ].forEach(function(item) { + style += item + ':' + + getCSSProperty(element, container, item) + ';'; + }); + + // Calculating the width/height of the textarea is somewhat tricky. To + // do it right, you have to include the paddings to the sides as well + // (eg. width = width + padding-left, -right). This works well, as + // long as the width of the element is not set or given in pixels. In + // this case and after the textarea is hidden, getCSSProperty(element, + // container, 'width') will still return pixel value. If the element + // has realtiv dimensions (e.g. width='95') + // getCSSProperty(...) will return pixel values only as long as the + // textarea is visible. After it is hidden getCSSProperty will return + // the relative dimensions as they are set on the element (in the case + // of width, 95). + // Making the sum of pixel vaules (e.g. padding) and realtive values + // (e.g. ) is not possible. As such the padding styles are + // ignored. + + // The complete width is the width of the textarea + the padding + // to the left and right. + var width = getCSSProperty(element, container, 'width') || (element.clientWidth + "px"); + var height = getCSSProperty(element, container, 'height') || (element.clientHeight + "px"); + style += 'height:' + height + ';width:' + width + ';'; + + // Set the display property to 'inline-block'. + style += 'display:inline-block;'; + container.setAttribute('style', style); + }; + event.addListener(window, 'resize', resizeEvent); + + // Call the resizeEvent once, so that the size of the container is + // calculated. + resizeEvent(); + + // Insert the div container after the element. + parentNode.insertBefore(container, element.nextSibling); + + // Override the forms onsubmit function. Set the innerHTML and value + // of the textarea before submitting. + while (parentNode !== document) { + if (parentNode.tagName.toUpperCase() === 'FORM') { + var oldSumit = parentNode.onsubmit; + // Override the onsubmit function of the form. + parentNode.onsubmit = function(evt) { + element.value = getValue(); + // If there is a onsubmit function already, then call + // it with the current context and pass the event. + if (oldSumit) { + oldSumit.call(this, evt); + } + }; + break; + } + parentNode = parentNode.parentNode; + } + return container; +} + +exports.transformTextarea = function(element, options) { + var session; + var container = setupContainer(element, function() { + return session.getValue(); + }); + + // Hide the element. + element.style.display = 'none'; + container.style.background = 'white'; + + // + var editorDiv = document.createElement("div"); + applyStyles(editorDiv, { + top: "0px", + left: "0px", + right: "0px", + bottom: "0px", + border: "1px solid gray", + position: "absolute" + }); + container.appendChild(editorDiv); + + var settingOpener = document.createElement("div"); + applyStyles(settingOpener, { + position: "absolute", + right: "0px", + bottom: "0px", + background: "red", + cursor: "nw-resize", + borderStyle: "solid", + borderWidth: "9px 8px 10px 9px", + width: "2px", + borderColor: "lightblue gray gray lightblue", + zIndex: 101 + }); + + var settingDiv = document.createElement("div"); + var settingDivStyles = { + top: "0px", + left: "20%", + right: "0px", + bottom: "0px", + position: "absolute", + padding: "5px", + zIndex: 100, + color: "white", + display: "none", + overflow: "auto", + fontSize: "14px", + boxShadow: "-5px 2px 3px gray" + }; + if (!UA.isOldIE) { + settingDivStyles.backgroundColor = "rgba(0, 0, 0, 0.6)"; + } else { + settingDivStyles.backgroundColor = "#333"; + } + + applyStyles(settingDiv, settingDivStyles); + container.appendChild(settingDiv); + + options = options || exports.defaultOptions; + // Power up ace on the textarea: + var editor = ace.edit(editorDiv); + session = editor.getSession(); + + session.setValue(element.value || element.innerHTML); + editor.focus(); + + // Add the settingPanel opener to the editor's div. + container.appendChild(settingOpener); + + // Create the API. + setupApi(editor, editorDiv, settingDiv, ace, options, load); + + // Create the setting's panel. + setupSettingPanel(settingDiv, settingOpener, editor); + + var state = ""; + event.addListener(settingOpener, "mousemove", function(e) { + var rect = this.getBoundingClientRect(); + var x = e.clientX - rect.left, y = e.clientY - rect.top; + if (x + y < (rect.width + rect.height)/2) { + this.style.cursor = "pointer"; + state = "toggle"; + } else { + state = "resize"; + this.style.cursor = "nw-resize"; + } + }); + + event.addListener(settingOpener, "mousedown", function(e) { + if (state == "toggle") { + editor.setDisplaySettings(); + return; + } + container.style.zIndex = 100000; + var rect = container.getBoundingClientRect(); + var startX = rect.width + rect.left - e.clientX; + var startY = rect.height + rect.top - e.clientY; + event.capture(settingOpener, function(e) { + container.style.width = e.clientX - rect.left + startX + "px"; + container.style.height = e.clientY - rect.top + startY + "px"; + editor.resize(); + }, function() {}); + }); + + return editor; +}; + +function load(url, module, callback) { + net.loadScript(url, function() { + require([module], callback); + }); +} + +function setupApi(editor, editorDiv, settingDiv, ace, options, loader) { + var session = editor.getSession(); + var renderer = editor.renderer; + loader = loader || load; + + function toBool(value) { + return value === "true" || value == true; + } + + editor.setDisplaySettings = function(display) { + if (display == null) + display = settingDiv.style.display == "none"; + if (display) { + settingDiv.style.display = "block"; + settingDiv.hideButton.focus(); + editor.on("focus", function onFocus() { + editor.removeListener("focus", onFocus); + settingDiv.style.display = "none"; + }); + } else { + editor.focus(); + } + }; + + editor.$setOption = editor.setOption; + editor.$getOption = editor.getOption; + editor.setOption = function(key, value) { + switch (key) { + case "mode": + editor.$setOption("mode", "ace/mode/" + value) + break; + case "theme": + editor.$setOption("theme", "ace/theme/" + value) + break; + case "keybindings": + switch (value) { + case "vim": + editor.setKeyboardHandler("ace/keyboard/vim"); + break; + case "emacs": + editor.setKeyboardHandler("ace/keyboard/emacs"); + break; + default: + editor.setKeyboardHandler(null); + } + break; + + case "softWrap": + case "fontSize": + editor.$setOption(key, value); + break; + + default: + editor.$setOption(key, toBool(value)); + } + }; + + editor.getOption = function(key) { + switch (key) { + case "mode": + return editor.$getOption("mode").substr("ace/mode/".length) + break; + + case "theme": + return editor.$getOption("theme").substr("ace/theme/".length) + break; + + case "keybindings": + var value = editor.getKeyboardHandler() + switch (value && value.$id) { + case "ace/keyboard/vim": + return "vim"; + case "ace/keyboard/emacs": + return "emacs"; + default: + return "ace"; + } + break; + + default: + return editor.$getOption(key); + } + }; + + editor.setOptions(options); + return editor; +} + +function setupSettingPanel(settingDiv, settingOpener, editor) { + var BOOL = null; + + var desc = { + mode: "Mode:", + wrap: "Soft Wrap:", + theme: "Theme:", + fontSize: "Font Size:", + showGutter: "Display Gutter:", + keybindings: "Keyboard", + showPrintMargin: "Show Print Margin:", + useSoftTabs: "Use Soft Tabs:", + showInvisibles: "Show Invisibles" + }; + + var optionValues = { + mode: { + text: "Plain", + javascript: "JavaScript", + xml: "XML", + html: "HTML", + css: "CSS", + scss: "SCSS", + python: "Python", + php: "PHP", + java: "Java", + ruby: "Ruby", + c_cpp: "C/C++", + coffee: "CoffeeScript", + json: "json", + perl: "Perl", + clojure: "Clojure", + ocaml: "OCaml", + csharp: "C#", + haxe: "haXe", + svg: "SVG", + textile: "Textile", + groovy: "Groovy", + liquid: "Liquid", + Scala: "Scala" + }, + theme: { + clouds: "Clouds", + clouds_midnight: "Clouds Midnight", + cobalt: "Cobalt", + crimson_editor: "Crimson Editor", + dawn: "Dawn", + eclipse: "Eclipse", + idle_fingers: "Idle Fingers", + kr_theme: "Kr Theme", + merbivore: "Merbivore", + merbivore_soft: "Merbivore Soft", + mono_industrial: "Mono Industrial", + monokai: "Monokai", + pastel_on_dark: "Pastel On Dark", + solarized_dark: "Solarized Dark", + solarized_light: "Solarized Light", + textmate: "Textmate", + twilight: "Twilight", + vibrant_ink: "Vibrant Ink" + }, + showGutter: BOOL, + fontSize: { + "10px": "10px", + "11px": "11px", + "12px": "12px", + "14px": "14px", + "16px": "16px" + }, + wrap: { + off: "Off", + 40: "40", + 80: "80", + free: "Free" + }, + keybindings: { + ace: "ace", + vim: "vim", + emacs: "emacs" + }, + showPrintMargin: BOOL, + useSoftTabs: BOOL, + showInvisibles: BOOL + }; + + var table = []; + table.push(""); + + function renderOption(builder, option, obj, cValue) { + if (!obj) { + builder.push( + "" + ); + return; + } + builder.push(""); + } + + for (var option in exports.defaultOptions) { + table.push(""); + table.push(""); + } + table.push("
      SettingValue
      ", desc[option], ""); + renderOption(table, option, optionValues[option], editor.getOption(option)); + table.push("
      "); + settingDiv.innerHTML = table.join(""); + + var onChange = function(e) { + var select = e.currentTarget; + editor.setOption(select.title, select.value); + }; + var onClick = function(e) { + var cb = e.currentTarget; + editor.setOption(cb.title, cb.checked); + }; + var selects = settingDiv.getElementsByTagName("select"); + for (var i = 0; i < selects.length; i++) + selects[i].onchange = onChange; + var cbs = settingDiv.getElementsByTagName("input"); + for (var i = 0; i < cbs.length; i++) + cbs[i].onclick = onClick; + + + var button = document.createElement("input"); + button.type = "button"; + button.value = "Hide"; + event.addListener(button, "click", function() { + editor.setDisplaySettings(false); + }); + settingDiv.appendChild(button); + settingDiv.hideButton = button; +} + +// Default startup options. +exports.defaultOptions = { + mode: "javascript", + theme: "textmate", + wrap: "off", + fontSize: "12px", + showGutter: "false", + keybindings: "ace", + showPrintMargin: "false", + useSoftTabs: "true", + showInvisibles: "false" +}; + +}); diff --git a/node_modules/ace/lib/ace/ext/themelist.js b/node_modules/ace/lib/ace/ext/themelist.js new file mode 100644 index 00000000..8914c776 --- /dev/null +++ b/node_modules/ace/lib/ace/ext/themelist.js @@ -0,0 +1,100 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2013 Matthew Christopher Kastor-Inare III, Atropa Inc. Intl + * All rights reserved. + * + * Contributed to Ajax.org under the BSD license. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + + +/** + * Generates a list of themes available when ace was built. + * @fileOverview Generates a list of themes available when ace was built. + * @author + * Matthew Christopher Kastor-Inare III
      + * ☭ Hial Atropa!! ☭ + */ + +define(function(require, exports, module) { +"use strict"; +require("ace/lib/fixoldbrowsers"); + +var themeData = [ + ["Chrome" ], + ["Clouds" ], + ["Crimson Editor" ], + ["Dawn" ], + ["Dreamweaver" ], + ["Eclipse" ], + ["GitHub" ], + ["Solarized Light"], + ["TextMate" ], + ["Tomorrow" ], + ["XCode" ], + ["Kuroir"], + ["KatzenMilch"], + ["Ambiance" ,"ambiance" , "dark"], + ["Chaos" ,"chaos" , "dark"], + ["Clouds Midnight" ,"clouds_midnight" , "dark"], + ["Cobalt" ,"cobalt" , "dark"], + ["idle Fingers" ,"idle_fingers" , "dark"], + ["krTheme" ,"kr_theme" , "dark"], + ["Merbivore" ,"merbivore" , "dark"], + ["Merbivore Soft" ,"merbivore_soft" , "dark"], + ["Mono Industrial" ,"mono_industrial" , "dark"], + ["Monokai" ,"monokai" , "dark"], + ["Pastel on dark" ,"pastel_on_dark" , "dark"], + ["Solarized Dark" ,"solarized_dark" , "dark"], + ["Terminal" ,"terminal" , "dark"], + ["Tomorrow Night" ,"tomorrow_night" , "dark"], + ["Tomorrow Night Blue" ,"tomorrow_night_blue" , "dark"], + ["Tomorrow Night Bright","tomorrow_night_bright" , "dark"], + ["Tomorrow Night 80s" ,"tomorrow_night_eighties" , "dark"], + ["Twilight" ,"twilight" , "dark"], + ["Vibrant Ink" ,"vibrant_ink" , "dark"] +]; + + +exports.themesByName = {}; + +/** + * An array containing information about available themes. + */ +exports.themes = themeData.map(function(data) { + var name = data[1] || data[0].replace(/ /g, "_").toLowerCase(); + var theme = { + caption: data[0], + theme: "ace/theme/" + name, + isDark: data[2] == "dark", + name: name + }; + exports.themesByName[name] = theme; + return theme; +}); + +}); + diff --git a/node_modules/ace/lib/ace/ext/whitespace.js b/node_modules/ace/lib/ace/ext/whitespace.js new file mode 100644 index 00000000..27ee223e --- /dev/null +++ b/node_modules/ace/lib/ace/ext/whitespace.js @@ -0,0 +1,213 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var lang = require("../lib/lang"); + +// based on http://www.freehackers.org/Indent_Finder +exports.$detectIndentation = function(lines, fallback) { + var stats = []; + var changes = []; + var tabIndents = 0; + var prevSpaces = 0; + var max = Math.min(lines.length, 1000); + for (var i = 0; i < max; i++) { + var line = lines[i]; + // ignore empty and comment lines + if (!/^\s*[^*+\-\s]/.test(line)) + continue; + + if (line[0] == "\t") + tabIndents++; + + var spaces = line.match(/^ */)[0].length; + if (spaces && line[spaces] != "\t") { + var diff = spaces - prevSpaces; + if (diff > 0 && !(prevSpaces%diff) && !(spaces%diff)) + changes[diff] = (changes[diff] || 0) + 1; + + stats[spaces] = (stats[spaces] || 0) + 1; + } + prevSpaces = spaces; + + // ignore lines ending with backslash + while (i < max && line[line.length - 1] == "\\") + line = lines[i++]; + } + + function getScore(indent) { + var score = 0; + for (var i = indent; i < stats.length; i += indent) + score += stats[i] || 0; + return score; + } + + var changesTotal = changes.reduce(function(a,b){return a+b}, 0); + + var first = {score: 0, length: 0}; + var spaceIndents = 0; + for (var i = 1; i < 12; i++) { + var score = getScore(i); + if (i == 1) { + spaceIndents = score; + score = stats[1] ? 0.9 : 0.8; + if (!stats.length) + score = 0 + } else + score /= spaceIndents; + + if (changes[i]) + score += changes[i] / changesTotal; + + if (score > first.score) + first = {score: score, length: i}; + } + + if (first.score && first.score > 1.4) + var tabLength = first.length; + + if (tabIndents > spaceIndents + 1) + return {ch: "\t", length: tabLength}; + + if (spaceIndents > tabIndents + 1) + return {ch: " ", length: tabLength}; +}; + +exports.detectIndentation = function(session) { + var lines = session.getLines(0, 1000); + var indent = exports.$detectIndentation(lines) || {}; + + if (indent.ch) + session.setUseSoftTabs(indent.ch == " "); + + if (indent.length) + session.setTabSize(indent.length); + return indent; +}; + +exports.trimTrailingSpace = function(session, trimEmpty) { + var doc = session.getDocument(); + var lines = doc.getAllLines(); + + var min = trimEmpty ? -1 : 0; + + for (var i = 0, l=lines.length; i < l; i++) { + var line = lines[i]; + var index = line.search(/\s+$/); + + if (index > min) + doc.removeInLine(i, index, line.length); + } +}; + +exports.convertIndentation = function(session, ch, len) { + var oldCh = session.getTabString()[0]; + var oldLen = session.getTabSize(); + if (!len) len = oldLen; + if (!ch) ch = oldCh; + + var tab = ch == "\t" ? ch: lang.stringRepeat(ch, len); + + var doc = session.doc; + var lines = doc.getAllLines(); + + var cache = {}; + var spaceCache = {}; + for (var i = 0, l=lines.length; i < l; i++) { + var line = lines[i]; + var match = line.match(/^\s*/)[0]; + if (match) { + var w = session.$getStringScreenWidth(match)[0]; + var tabCount = Math.floor(w/oldLen); + var reminder = w%oldLen; + var toInsert = cache[tabCount] || (cache[tabCount] = lang.stringRepeat(tab, tabCount)); + toInsert += spaceCache[reminder] || (spaceCache[reminder] = lang.stringRepeat(" ", reminder)); + + if (toInsert != match) { + doc.removeInLine(i, 0, match.length); + doc.insertInLine({row: i, column: 0}, toInsert); + } + } + } + session.setTabSize(len); + session.setUseSoftTabs(ch == " "); +}; + +exports.$parseStringArg = function(text) { + var indent = {}; + if (/t/.test(text)) + indent.ch = "\t"; + else if (/s/.test(text)) + indent.ch = " "; + var m = text.match(/\d+/); + if (m) + indent.length = parseInt(m[0], 10); + return indent; +}; + +exports.$parseArg = function(arg) { + if (!arg) + return {}; + if (typeof arg == "string") + return exports.$parseStringArg(arg); + if (typeof arg.text == "string") + return exports.$parseStringArg(arg.text); + return arg; +}; + +exports.commands = [{ + name: "detectIndentation", + exec: function(editor) { + exports.detectIndentation(editor.session); + // todo show message? + } +}, { + name: "trimTrailingSpace", + exec: function(editor) { + exports.trimTrailingSpace(editor.session); + } +}, { + name: "convertIndentation", + exec: function(editor, arg) { + var indent = exports.$parseArg(arg); + exports.convertIndentation(editor.session, indent.ch, indent.length); + } +}, { + name: "setIndentation", + exec: function(editor, arg) { + var indent = exports.$parseArg(arg); + indent.length && editor.session.setTabSize(indent.length); + indent.ch && editor.session.setUseSoftTabs(indent.ch == " "); + } +}]; + +}); diff --git a/node_modules/ace/lib/ace/ext/whitespace_test.js b/node_modules/ace/lib/ace/ext/whitespace_test.js new file mode 100644 index 00000000..be4f360f --- /dev/null +++ b/node_modules/ace/lib/ace/ext/whitespace_test.js @@ -0,0 +1,116 @@ +if (typeof process !== "undefined") { + require("amd-loader"); + require("../test/mockdom"); +} + +define(function(require, exports, module) { +"use strict"; + +var assert = require("assert"); +var EditSession = require("../edit_session").EditSession; +var whitespace = require("./whitespace"); + +// Execution ORDER: test.setUpSuite, setUp, testFn, tearDown, test.tearDownSuite +module.exports = { + timeout: 10000, + + "test tab detection": function(next) { + var s = new EditSession([ + "define({", + "\tfoo:1,", + "\tbar:2,", + "\tbaz:{,", + "\t\tx:3", + "\t}", + "})" + ]); + + var indent = whitespace.$detectIndentation(s.doc.$lines); + assert.equal(indent.ch, "\t"); + assert.equal(indent.length, undefined); + + s.insert({row: 0, column: 0}, " "); + indent = whitespace.$detectIndentation(s.doc.$lines); + assert.equal(indent.ch, "\t"); + assert.equal(indent.length, 4); + + s.setValue(""); + indent = whitespace.$detectIndentation(s.doc.$lines); + assert.ok(!indent); + + next(); + }, + + "test empty session": function(next) { + var s = new EditSession([ + "define({", + "foo:1,", + "})" + ]); + var indent = whitespace.$detectIndentation(s.doc.$lines); + assert.ok(!indent); + s.insert({row: 1, column: 0}, " x\n "); + + indent = whitespace.$detectIndentation(s.doc.$lines); + assert.equal(indent.ch, " "); + assert.equal(indent.length, 4); + + next(); + }, + + "!test one line": function(next) { + var s = new EditSession([ + "define({", + " foo:1,", + "})" + ]); + var indent = whitespace.$detectIndentation(s.doc.$lines); + assert.equal(indent.ch, " "); + assert.equal(indent.length, 4); + + next(); + }, + + "test 1 width indents": function(next) { + var s = new EditSession([ + "define({", + " foo:1,", + "})", + "define({", + " bar:1,", + "})", + " t", + " t", + " t", + " t", + " t", + " t", + " t", + " t" + ]); + var indent = whitespace.$detectIndentation(s.doc.$lines); + // assert.equal(indent.ch, " "); + // assert.equal(indent.length, 4); + + s = new EditSession([ + "{", + " foo:1,", + " bar: {", + " baz:2", + " }", + "}" + ]); + indent = whitespace.$detectIndentation(s.doc.$lines); + assert.equal(indent.ch, " "); + assert.equal(indent.length, 1); + + next(); + }, + +}; + +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec(); +} diff --git a/node_modules/ace/lib/ace/incremental_search.js b/node_modules/ace/lib/ace/incremental_search.js new file mode 100644 index 00000000..a64e1857 --- /dev/null +++ b/node_modules/ace/lib/ace/incremental_search.js @@ -0,0 +1,317 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("./lib/oop"); +var Range = require("./range").Range; +var Search = require("./search").Search; +var SearchHighlight = require("./search_highlight").SearchHighlight; +var iSearchCommandModule = require("./commands/incremental_search_commands"); +var ISearchKbd = iSearchCommandModule.IncrementalSearchKeyboardHandler; + +/** + * @class IncrementalSearch + * + * Implements immediate searching while the user is typing. When incremental + * search is activated, keystrokes into the editor will be used for composing + * a search term. Immediately after every keystroke the search is updated: + * - so-far-matching characters are highlighted + * - the cursor is moved to the next match + * + **/ + + +/** + * + * + * Creates a new `IncrementalSearch` object. + * + * @constructor + **/ +function IncrementalSearch() { + this.$options = {wrap: false, skipCurrent: false}; + this.$keyboardHandler = new ISearchKbd(this); +} + +oop.inherits(IncrementalSearch, Search); + +// regexp handling + +function isRegExp(obj) { + return obj instanceof RegExp; +} + +function regExpToObject(re) { + var string = String(re), + start = string.indexOf('/'), + flagStart = string.lastIndexOf('/'); + return { + expression: string.slice(start+1, flagStart), + flags: string.slice(flagStart+1) + } +} + +function stringToRegExp(string, flags) { + try { + return new RegExp(string, flags); + } catch (e) { return string; } +} + +function objectToRegExp(obj) { + return stringToRegExp(obj.expression, obj.flags); +} + +// iSearch class + +;(function() { + + this.activate = function(ed, backwards) { + this.$editor = ed; + this.$startPos = this.$currentPos = ed.getCursorPosition(); + this.$options.needle = ''; + this.$options.backwards = backwards; + ed.keyBinding.addKeyboardHandler(this.$keyboardHandler); + // we need to completely intercept paste, just registering an event handler does not work + this.$originalEditorOnPaste = ed.onPaste; ed.onPaste = this.onPaste.bind(this); + this.$mousedownHandler = ed.addEventListener('mousedown', this.onMouseDown.bind(this)); + this.selectionFix(ed); + this.statusMessage(true); + } + + this.deactivate = function(reset) { + this.cancelSearch(reset); + var ed = this.$editor; + ed.keyBinding.removeKeyboardHandler(this.$keyboardHandler); + if (this.$mousedownHandler) { + ed.removeEventListener('mousedown', this.$mousedownHandler); + delete this.$mousedownHandler; + } + ed.onPaste = this.$originalEditorOnPaste; + this.message(''); + } + + this.selectionFix = function(editor) { + // Fix selection bug: When clicked inside the editor + // editor.selection.$isEmpty is false even if the mouse click did not + // open a selection. This is interpreted by the move commands to + // extend the selection. To only extend the selection when there is + // one, we clear it here + if (editor.selection.isEmpty() && !editor.session.$emacsMark) { + editor.clearSelection(); + } + } + + this.highlight = function(regexp) { + var sess = this.$editor.session, + hl = sess.$isearchHighlight = sess.$isearchHighlight || sess.addDynamicMarker( + new SearchHighlight(null, "ace_isearch-result", "text")); + hl.setRegexp(regexp); + sess._emit("changeBackMarker"); // force highlight layer redraw + } + + this.cancelSearch = function(reset) { + var e = this.$editor; + this.$prevNeedle = this.$options.needle; + this.$options.needle = ''; + if (reset) { + e.moveCursorToPosition(this.$startPos); + this.$currentPos = this.$startPos; + } else { + e.pushEmacsMark && e.pushEmacsMark(this.$startPos, false); + } + this.highlight(null); + return Range.fromPoints(this.$currentPos, this.$currentPos); + } + + this.highlightAndFindWithNeedle = function(moveToNext, needleUpdateFunc) { + if (!this.$editor) return null; + var options = this.$options; + + // get search term + if (needleUpdateFunc) { + options.needle = needleUpdateFunc.call(this, options.needle || '') || ''; + } + if (options.needle.length === 0) { + this.statusMessage(true); + return this.cancelSearch(true); + }; + + // try to find the next occurence and enable highlighting marker + options.start = this.$currentPos; + var session = this.$editor.session, + found = this.find(session), + shouldSelect = this.$editor.emacsMark ? + !!this.$editor.emacsMark() : !this.$editor.selection.isEmpty(); + if (found) { + if (options.backwards) found = Range.fromPoints(found.end, found.start); + this.$editor.selection.setRange(Range.fromPoints(shouldSelect ? this.$startPos : found.end, found.end)); + if (moveToNext) this.$currentPos = found.end; + // highlight after cursor move, so selection works properly + this.highlight(options.re) + } + + this.statusMessage(found); + + return found; + } + + this.addString = function(s) { + return this.highlightAndFindWithNeedle(false, function(needle) { + if (!isRegExp(needle)) + return needle + s; + var reObj = regExpToObject(needle); + reObj.expression += s; + return objectToRegExp(reObj); + }); + } + + this.removeChar = function(c) { + return this.highlightAndFindWithNeedle(false, function(needle) { + if (!isRegExp(needle)) + return needle.substring(0, needle.length-1); + var reObj = regExpToObject(needle); + reObj.expression = reObj.expression.substring(0, reObj.expression.length-1); + return objectToRegExp(reObj); + }); + } + + this.next = function(options) { + // try to find the next occurence of whatever we have searched for + // earlier. + // options = {[backwards: BOOL], [useCurrentOrPrevSearch: BOOL]} + options = options || {}; + this.$options.backwards = !!options.backwards; + this.$currentPos = this.$editor.getCursorPosition(); + return this.highlightAndFindWithNeedle(true, function(needle) { + return options.useCurrentOrPrevSearch && needle.length === 0 ? + this.$prevNeedle || '' : needle; + }); + } + + this.onMouseDown = function(evt) { + // when mouse interaction happens then we quit incremental search + this.deactivate(); + return true; + } + + this.onPaste = function(text) { + this.addString(text); + } + + this.convertNeedleToRegExp = function() { + return this.highlightAndFindWithNeedle(false, function(needle) { + return isRegExp(needle) ? needle : stringToRegExp(needle, 'ig'); + }); + } + + this.convertNeedleToString = function() { + return this.highlightAndFindWithNeedle(false, function(needle) { + return isRegExp(needle) ? regExpToObject(needle).expression : needle; + }); + } + + this.statusMessage = function(found) { + var options = this.$options, msg = ''; + msg += options.backwards ? 'reverse-' : ''; + msg += 'isearch: ' + options.needle; + msg += found ? '' : ' (not found)'; + this.message(msg); + } + + this.message = function(msg) { + if (this.$editor.showCommandLine) { + this.$editor.showCommandLine(msg); + this.$editor.focus(); + } else { + console.log(msg); + } + } + +}).call(IncrementalSearch.prototype); + + +exports.IncrementalSearch = IncrementalSearch; + + +/** + * + * Config settings for enabling/disabling [[IncrementalSearch `IncrementalSearch`]]. + * + **/ + +var dom = require('./lib/dom'); +dom.importCssString && dom.importCssString("\ +.ace_marker-layer .ace_isearch-result {\ + position: absolute;\ + z-index: 6;\ + -moz-box-sizing: border-box;\ + -webkit-box-sizing: border-box;\ + box-sizing: border-box;\ +}\ +div.ace_isearch-result {\ + border-radius: 4px;\ + background-color: rgba(255, 200, 0, 0.5);\ + box-shadow: 0 0 4px rgb(255, 200, 0);\ +}\ +.ace_dark div.ace_isearch-result {\ + background-color: rgb(100, 110, 160);\ + box-shadow: 0 0 4px rgb(80, 90, 140);\ +}", "incremental-search-highlighting"); + +// support for default keyboard handler +var commands = require("./commands/command_manager"); +(function() { + this.setupIncrementalSearch = function(editor, val) { + if (this.usesIncrementalSearch == val) return; + this.usesIncrementalSearch = val; + var iSearchCommands = iSearchCommandModule.iSearchStartCommands; + var method = val ? 'addCommands' : 'removeCommands'; + this[method](iSearchCommands); + }; +}).call(commands.CommandManager.prototype); + +// incremental search config option +var Editor = require("./editor").Editor; +require("./config").defineOptions(Editor.prototype, "editor", { + useIncrementalSearch: { + set: function(val) { + this.keyBinding.$handlers.forEach(function(handler) { + if (handler.setupIncrementalSearch) { + handler.setupIncrementalSearch(this, val); + } + }); + this._emit('incrementalSearchSettingChanged', {isEnabled: val}); + } + } +}); + +}); diff --git a/node_modules/ace/lib/ace/incremental_search_test.js b/node_modules/ace/lib/ace/incremental_search_test.js new file mode 100644 index 00000000..d1303b42 --- /dev/null +++ b/node_modules/ace/lib/ace/incremental_search_test.js @@ -0,0 +1,213 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +if (typeof process !== "undefined") { + require("amd-loader"); +} + +define(function(require, exports, module) { +"use strict"; + +var emacs = require('./keyboard/emacs'); +var EditSession = require("./edit_session").EditSession; +var Editor = require("./editor").Editor; +var MockRenderer = require("./test/mockrenderer").MockRenderer; +var Range = require("./range").Range; +var MultiSelect = require("./multi_select").MultiSelect; +var assert = require("./test/assertions"); +var IncrementalSearch = require("./incremental_search").IncrementalSearch; + +require("./multi_select"); + +var editor, iSearch; +function testRanges(str, ranges) { + ranges = ranges || editor.selection.getAllRanges(); + assert.equal(ranges + "", str + ""); +} + +// force "rerender" +function callHighlighterUpdate() { + var session = editor.session, + ranges = [], + mockMarkerLayer = { + drawSingleLineMarker: function(_, markerRanges) { + ranges = ranges.concat(markerRanges); + } + } + session.$isearchHighlight.update([], mockMarkerLayer, session, { + firstRow: 0, lastRow: session.getRowLength()}); + return ranges; +} + +module.exports = { + + name: "ACE incremental_search.js", + + setUp: function() { + var session = new EditSession(["abc123", "xyz124"]); + editor = new Editor(new MockRenderer(), session); + new MultiSelect(editor); + iSearch = new IncrementalSearch(); + }, + + "test: keyboard handler setup" : function() { + iSearch.activate(editor); + assert.equal(editor.getKeyboardHandler(), iSearch.$keyboardHandler); + iSearch.deactivate(); + assert.notEqual(editor.getKeyboardHandler(), iSearch.$keyboardHandler); + }, + + "test: isearch highlight setup" : function() { + var sess = editor.session; + iSearch.activate(editor); + iSearch.highlight('foo'); + var highl = sess.$isearchHighlight.id; + assert.ok(sess.$isearchHighlight, 'session has no isearch highlighter'); + assert.equal(sess.getMarkers()[highl.id], highl.id, 'isearch highlight not in markers'); + iSearch.deactivate(); + iSearch.activate(editor); + iSearch.highlight('bar'); + var highl2 = sess.$isearchHighlight.id; + assert.equal(highl2, highl, 'multiple isearch highlights'); + }, + + "test: find simple text incrementally" : function() { + iSearch.activate(editor); + var range = iSearch.addString('1'), // "1" + highlightRanges = callHighlighterUpdate(editor.session); + testRanges("Range: [0/3] -> [0/4]", [range], "range"); + testRanges("Range: [0/3] -> [0/4],Range: [1/3] -> [1/4]", highlightRanges, "highlight"); + + range = iSearch.addString('2'); // "12" + highlightRanges = callHighlighterUpdate(editor.session); + testRanges("Range: [0/3] -> [0/5]", [range], "range"); + testRanges("Range: [0/3] -> [0/5],Range: [1/3] -> [1/5]", highlightRanges, "highlight"); + + range = iSearch.addString('3'); // "123" + highlightRanges = callHighlighterUpdate(editor.session); + testRanges("Range: [0/3] -> [0/6]", [range], "range"); + testRanges("Range: [0/3] -> [0/6]", highlightRanges, "highlight"); + + range = iSearch.removeChar(); // "12" + highlightRanges = callHighlighterUpdate(editor.session); + testRanges("Range: [0/3] -> [0/5]", [range], "range"); + testRanges("Range: [0/3] -> [0/5],Range: [1/3] -> [1/5]", highlightRanges, "highlight"); + }, + + "test: forward / backward" : function() { + iSearch.activate(editor); + iSearch.addString('1'); iSearch.addString('2'); + var range = iSearch.next(); + testRanges("Range: [1/3] -> [1/5]", [range], "range"); + + range = iSearch.next(); // nothing to find + testRanges("", [range], "range"); + + range = iSearch.next({backwards: true}); // backwards + testRanges("Range: [1/5] -> [1/3]", [range], "range"); + }, + + "test: cancelSearch" : function() { + iSearch.activate(editor); + iSearch.addString('1'); iSearch.addString('2'); + var range = iSearch.cancelSearch(true); + testRanges("Range: [0/0] -> [0/0]", [range], "range"); + + iSearch.addString('1'); range = iSearch.addString('2'); + testRanges("Range: [0/3] -> [0/5]", [range], "range"); + }, + + "test: failing search keeps pos" : function() { + iSearch.activate(editor); + iSearch.addString('1'); iSearch.addString('2'); + var range = iSearch.addString('x'); + testRanges("", [range], "range"); + assert.position(editor.getCursorPosition(), 0, 5); + }, + + "test: backwards search" : function() { + editor.moveCursorTo(1,0); + iSearch.activate(editor, true); + iSearch.addString('1'); var range = iSearch.addString('2');; + testRanges("Range: [0/5] -> [0/3]", [range], "range"); + assert.position(editor.getCursorPosition(), 0, 3); + }, + + "test: forwards then backwards, same result, reoriented range" : function() { + iSearch.activate(editor); + iSearch.addString('1'); var range = iSearch.addString('2');; + testRanges("Range: [0/3] -> [0/5]", [range], "range"); + assert.position(editor.getCursorPosition(), 0, 5); + + range = iSearch.next({backwards: true}); + testRanges("Range: [0/5] -> [0/3]", [range], "range"); + assert.position(editor.getCursorPosition(), 0, 3); + }, + + "test: reuse prev search via option" : function() { + iSearch.activate(editor); + iSearch.addString('1'); iSearch.addString('2');; + assert.position(editor.getCursorPosition(), 0, 5); + iSearch.deactivate(); + + iSearch.activate(editor); + iSearch.next({backwards: false, useCurrentOrPrevSearch: true}); + assert.position(editor.getCursorPosition(), 1, 5); + }, + + "test: don't extend selection range if selection is empty" : function() { + iSearch.activate(editor); + iSearch.addString('1'); iSearch.addString('2');; + testRanges("Range: [0/5] -> [0/5]", [editor.getSelectionRange()], "sel range"); + }, + + "test: extend selection range if selection exists" : function() { + iSearch.activate(editor); + editor.selection.selectTo(0, 1); + iSearch.addString('1'); iSearch.addString('2');; + testRanges("Range: [0/0] -> [0/5]", [editor.getSelectionRange()], "sel range"); + }, + + "test: extend selection in emacs mark mode" : function() { + var emacs = require('./keyboard/emacs'); + editor.keyBinding.addKeyboardHandler(emacs.handler); + emacs.handler.commands.setMark.exec(editor); + iSearch.activate(editor); + iSearch.addString('1'); iSearch.addString('2'); + testRanges("Range: [0/0] -> [0/5]", [editor.getSelectionRange()], "sel range"); + } + +}; + +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec() +} diff --git a/node_modules/ace/lib/ace/keyboard/emacs.js b/node_modules/ace/lib/ace/keyboard/emacs.js new file mode 100644 index 00000000..945eddf3 --- /dev/null +++ b/node_modules/ace/lib/ace/keyboard/emacs.js @@ -0,0 +1,652 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var dom = require("../lib/dom"); +require("../incremental_search"); +var iSearchCommandModule = require("../commands/incremental_search_commands"); + + +var screenToTextBlockCoordinates = function(x, y) { + var canvasPos = this.scroller.getBoundingClientRect(); + + var col = Math.floor( + (x + this.scrollLeft - canvasPos.left - this.$padding) / this.characterWidth + ); + var row = Math.floor( + (y + this.scrollTop - canvasPos.top) / this.lineHeight + ); + + return this.session.screenToDocumentPosition(row, col); +}; + +var HashHandler = require("./hash_handler").HashHandler; +exports.handler = new HashHandler(); + +exports.handler.isEmacs = true; +exports.handler.$id = "ace/keyboard/emacs"; + +var initialized = false; +var $formerLongWords; +var $formerLineStart; + +exports.handler.attach = function(editor) { + if (!initialized) { + initialized = true; + dom.importCssString('\ + .emacs-mode .ace_cursor{\ + border: 1px rgba(50,250,50,0.8) solid!important;\ + -moz-box-sizing: border-box!important;\ + -webkit-box-sizing: border-box!important;\ + box-sizing: border-box!important;\ + background-color: rgba(0,250,0,0.9);\ + opacity: 0.5;\ + }\ + .emacs-mode .ace_hidden-cursors .ace_cursor{\ + opacity: 1;\ + background-color: transparent;\ + }\ + .emacs-mode .ace_overwrite-cursors .ace_cursor {\ + opacity: 1;\ + background-color: transparent;\ + border-width: 0 0 2px 2px !important;\ + }\ + .emacs-mode .ace_text-layer {\ + z-index: 4\ + }\ + .emacs-mode .ace_cursor-layer {\ + z-index: 2\ + }', 'emacsMode' + ); + } + // in emacs, gotowordleft/right should not count a space as a word.. + $formerLongWords = editor.session.$selectLongWords; + editor.session.$selectLongWords = true; + // CTRL-A should go to actual beginning of line + $formerLineStart = editor.session.$useEmacsStyleLineStart; + editor.session.$useEmacsStyleLineStart = true; + + editor.session.$emacsMark = null; // the active mark + editor.session.$emacsMarkRing = editor.session.$emacsMarkRing || []; + + editor.emacsMark = function() { + return this.session.$emacsMark; + }; + + editor.setEmacsMark = function(p) { + // to deactivate pass in a falsy value + this.session.$emacsMark = p; + }; + + editor.pushEmacsMark = function(p, activate) { + var prevMark = this.session.$emacsMark; + if (prevMark) + this.session.$emacsMarkRing.push(prevMark); + if (!p || activate) this.setEmacsMark(p); + else this.session.$emacsMarkRing.push(p); + }; + + editor.popEmacsMark = function() { + var mark = this.emacsMark(); + if (mark) { this.setEmacsMark(null); return mark; } + return this.session.$emacsMarkRing.pop(); + }; + + editor.getLastEmacsMark = function(p) { + return this.session.$emacsMark || this.session.$emacsMarkRing.slice(-1)[0]; + }; + + editor.emacsMarkForSelection = function(replacement) { + // find the mark in $emacsMarkRing corresponding to the current + // selection + var sel = this.selection, + multiRangeLength = this.multiSelect ? + this.multiSelect.getAllRanges().length : 1, + selIndex = sel.index || 0, + markRing = this.session.$emacsMarkRing, + markIndex = markRing.length - (multiRangeLength - selIndex), + lastMark = markRing[markIndex] || sel.anchor; + if (replacement) { + markRing.splice(markIndex, 1, + "row" in replacement && "column" in replacement ? + replacement : undefined); + } + return lastMark; + } + + editor.on("click", $resetMarkMode); + editor.on("changeSession", $kbSessionChange); + editor.renderer.screenToTextCoordinates = screenToTextBlockCoordinates; + editor.setStyle("emacs-mode"); + editor.commands.addCommands(commands); + exports.handler.platform = editor.commands.platform; + editor.$emacsModeHandler = this; + editor.addEventListener('copy', this.onCopy); + editor.addEventListener('paste', this.onPaste); +}; + +exports.handler.detach = function(editor) { + delete editor.renderer.screenToTextCoordinates; + editor.session.$selectLongWords = $formerLongWords; + editor.session.$useEmacsStyleLineStart = $formerLineStart; + editor.removeEventListener("click", $resetMarkMode); + editor.removeEventListener("changeSession", $kbSessionChange); + editor.unsetStyle("emacs-mode"); + editor.commands.removeCommands(commands); + editor.removeEventListener('copy', this.onCopy); + editor.removeEventListener('paste', this.onPaste); + editor.$emacsModeHandler = null; +}; + +var $kbSessionChange = function(e) { + if (e.oldSession) { + e.oldSession.$selectLongWords = $formerLongWords; + e.oldSession.$useEmacsStyleLineStart = $formerLineStart; + } + + $formerLongWords = e.session.$selectLongWords; + e.session.$selectLongWords = true; + $formerLineStart = e.session.$useEmacsStyleLineStart; + e.session.$useEmacsStyleLineStart = true; + + if (!e.session.hasOwnProperty('$emacsMark')) + e.session.$emacsMark = null; + if (!e.session.hasOwnProperty('$emacsMarkRing')) + e.session.$emacsMarkRing = []; +}; + +var $resetMarkMode = function(e) { + e.editor.session.$emacsMark = null; +}; + +var keys = require("../lib/keys").KEY_MODS; +var eMods = {C: "ctrl", S: "shift", M: "alt", CMD: "command"}; +var combinations = ["C-S-M-CMD", + "S-M-CMD", "C-M-CMD", "C-S-CMD", "C-S-M", + "M-CMD", "S-CMD", "S-M", "C-CMD", "C-M", "C-S", + "CMD", "M", "S", "C"]; +combinations.forEach(function(c) { + var hashId = 0; + c.split("-").forEach(function(c) { + hashId = hashId | keys[eMods[c]]; + }); + eMods[hashId] = c.toLowerCase() + "-"; +}); + +exports.handler.onCopy = function(e, editor) { + if (editor.$handlesEmacsOnCopy) return; + editor.$handlesEmacsOnCopy = true; + exports.handler.commands.killRingSave.exec(editor); + editor.$handlesEmacsOnCopy = false; +}; + +exports.handler.onPaste = function(e, editor) { + editor.pushEmacsMark(editor.getCursorPosition()); +}; + +exports.handler.bindKey = function(key, command) { + if (typeof key == "object") + key = key[this.platform]; + if (!key) + return; + + var ckb = this.commandKeyBinding; + key.split("|").forEach(function(keyPart) { + keyPart = keyPart.toLowerCase(); + ckb[keyPart] = command; + // register all partial key combos as null commands + // to be able to activate key combos with arbitrary length + // Example: if keyPart is "C-c C-l t" then "C-c C-l t" will + // get command assigned and "C-c" and "C-c C-l" will get + // a null command assigned in this.commandKeyBinding. For + // the lookup logic see handleKeyboard() + var keyParts = keyPart.split(" ").slice(0,-1); + keyParts.reduce(function(keyMapKeys, keyPart, i) { + var prefix = keyMapKeys[i-1] ? keyMapKeys[i-1] + ' ' : ''; + return keyMapKeys.concat([prefix + keyPart]); + }, []).forEach(function(keyPart) { + if (!ckb[keyPart]) ckb[keyPart] = "null"; + }); + }, this); +}; + +exports.handler.getStatusText = function(editor, data) { + var str = ""; + if (data.count) + str += data.count; + if (data.keyChain) + str += " " + data.keyChain + return str; +}; + +exports.handler.handleKeyboard = function(data, hashId, key, keyCode) { + // if keyCode == -1 a non-printable key was pressed, such as just + // control. Handling those is currently not supported in this handler + if (keyCode === -1) return undefined; + + var editor = data.editor; + editor._signal("changeStatus"); + // insertstring data.count times + if (hashId == -1) { + editor.pushEmacsMark(); + if (data.count) { + var str = new Array(data.count + 1).join(key); + data.count = null; + return {command: "insertstring", args: str}; + } + } + + var modifier = eMods[hashId]; + + // CTRL + number / universalArgument for setting data.count + if (modifier == "c-" || data.count) { + var count = parseInt(key[key.length - 1]); + if (typeof count === 'number' && !isNaN(count)) { + data.count = Math.max(data.count, 0) || 0; + data.count = 10 * data.count + count; + return {command: "null"}; + } + } + + // this.commandKeyBinding maps key specs like "c-p" (for CTRL + P) to + // command objects, for lookup key needs to include the modifier + if (modifier) key = modifier + key; + + // Key combos like CTRL+X H build up the data.keyChain + if (data.keyChain) key = data.keyChain += " " + key; + + // Key combo prefixes get stored as "null" (String!) in this + // this.commandKeyBinding. When encountered no command is invoked but we + // buld up data.keyChain + var command = this.commandKeyBinding[key]; + data.keyChain = command == "null" ? key : ""; + + // there really is no command + if (!command) return undefined; + + // we pass b/c of key combo or universalArgument + if (command === "null") return {command: "null"}; + + if (command === "universalArgument") { + // if no number pressed emacs repeats action 4 times. + // minus sign is needed to allow next keypress to replace it + data.count = -4; + return {command: "null"}; + } + + // lookup command + // TODO extract special handling of markmode + // TODO special case command.command is really unnecessary, remove + var args; + if (typeof command !== "string") { + args = command.args; + if (command.command) command = command.command; + if (command === "goorselect") { + command = editor.emacsMark() ? args[1] : args[0]; + args = null; + } + } + + if (typeof command === "string") { + if (command === "insertstring" || + command === "splitline" || + command === "togglecomment") { + editor.pushEmacsMark(); + } + command = this.commands[command] || editor.commands.commands[command]; + if (!command) return undefined; + } + + if (!command.readOnly && !command.isYank) + data.lastCommand = null; + + if (!command.readOnly && editor.emacsMark()) + editor.setEmacsMark(null) + + if (data.count) { + var count = data.count; + data.count = 0; + if (!command || !command.handlesCount) { + return { + args: args, + command: { + exec: function(editor, args) { + for (var i = 0; i < count; i++) + command.exec(editor, args); + }, + multiSelectAction: command.multiSelectAction + } + }; + } else { + if (!args) args = {}; + if (typeof args === 'object') args.count = count; + } + } + + return {command: command, args: args}; +}; + +exports.emacsKeys = { + // movement + "Up|C-p" : {command: "goorselect", args: ["golineup","selectup"]}, + "Down|C-n" : {command: "goorselect", args: ["golinedown","selectdown"]}, + "Left|C-b" : {command: "goorselect", args: ["gotoleft","selectleft"]}, + "Right|C-f" : {command: "goorselect", args: ["gotoright","selectright"]}, + "C-Left|M-b" : {command: "goorselect", args: ["gotowordleft","selectwordleft"]}, + "C-Right|M-f" : {command: "goorselect", args: ["gotowordright","selectwordright"]}, + "Home|C-a" : {command: "goorselect", args: ["gotolinestart","selecttolinestart"]}, + "End|C-e" : {command: "goorselect", args: ["gotolineend","selecttolineend"]}, + "C-Home|S-M-,": {command: "goorselect", args: ["gotostart","selecttostart"]}, + "C-End|S-M-." : {command: "goorselect", args: ["gotoend","selecttoend"]}, + + // selection + "S-Up|S-C-p" : "selectup", + "S-Down|S-C-n" : "selectdown", + "S-Left|S-C-b" : "selectleft", + "S-Right|S-C-f" : "selectright", + "S-C-Left|S-M-b" : "selectwordleft", + "S-C-Right|S-M-f" : "selectwordright", + "S-Home|S-C-a" : "selecttolinestart", + "S-End|S-C-e" : "selecttolineend", + "S-C-Home" : "selecttostart", + "S-C-End" : "selecttoend", + + "C-l" : "recenterTopBottom", + "M-s" : "centerselection", + "M-g": "gotoline", + "C-x C-p": "selectall", + + // todo fix these + "C-Down": {command: "goorselect", args: ["gotopagedown","selectpagedown"]}, + "C-Up": {command: "goorselect", args: ["gotopageup","selectpageup"]}, + "PageDown|C-v": {command: "goorselect", args: ["gotopagedown","selectpagedown"]}, + "PageUp|M-v": {command: "goorselect", args: ["gotopageup","selectpageup"]}, + "S-C-Down": "selectpagedown", + "S-C-Up": "selectpageup", + + "C-s": "iSearch", + "C-r": "iSearchBackwards", + + "M-C-s": "findnext", + "M-C-r": "findprevious", + "S-M-5": "replace", + + // basic editing + "Backspace": "backspace", + "Delete|C-d": "del", + "Return|C-m": {command: "insertstring", args: "\n"}, // "newline" + "C-o": "splitline", + + "M-d|C-Delete": {command: "killWord", args: "right"}, + "C-Backspace|M-Backspace|M-Delete": {command: "killWord", args: "left"}, + "C-k": "killLine", + + "C-y|S-Delete": "yank", + "M-y": "yankRotate", + "C-g": "keyboardQuit", + + "C-w|C-S-W": "killRegion", + "M-w": "killRingSave", + "C-Space": "setMark", + "C-x C-x": "exchangePointAndMark", + + "C-t": "transposeletters", + "M-u": "touppercase", // Doesn't work + "M-l": "tolowercase", + "M-/": "autocomplete", // Doesn't work + "C-u": "universalArgument", + + "M-;": "togglecomment", + + "C-/|C-x u|S-C--|C-z": "undo", + "S-C-/|S-C-x u|C--|S-C-z": "redo", //infinite undo? + // vertical editing + "C-x r": "selectRectangularRegion", + "M-x": {command: "focusCommandLine", args: "M-x "} + // todo + // "C-x C-t" "M-t" "M-c" "F11" "C-M- "M-q" +}; + + +exports.handler.bindKeys(exports.emacsKeys); + +exports.handler.addCommands({ + recenterTopBottom: function(editor) { + var renderer = editor.renderer; + var pos = renderer.$cursorLayer.getPixelPosition(); + var h = renderer.$size.scrollerHeight - renderer.lineHeight; + var scrollTop = renderer.scrollTop; + if (Math.abs(pos.top - scrollTop) < 2) { + scrollTop = pos.top - h; + } else if (Math.abs(pos.top - scrollTop - h * 0.5) < 2) { + scrollTop = pos.top; + } else { + scrollTop = pos.top - h * 0.5; + } + editor.session.setScrollTop(scrollTop); + }, + selectRectangularRegion: function(editor) { + editor.multiSelect.toggleBlockSelection(); + }, + setMark: { + exec: function(editor, args) { + // Sets mark-mode and clears current selection. + // When mark is set, keyboard cursor movement commands become + // selection modification commands. That is, + // "goto" commands become "select" commands. + // Any insertion or mouse click resets mark-mode. + // setMark twice in a row at the same place resets markmode. + // in multi select mode, ea selection is handled individually + + if (args && args.count) { + if (editor.inMultiSelectMode) editor.forEachSelection(moveToMark); + else moveToMark(); + moveToMark(); + return; + } + + var mark = editor.emacsMark(), + ranges = editor.selection.getAllRanges(), + rangePositions = ranges.map(function(r) { return {row: r.start.row, column: r.start.column}; }), + transientMarkModeActive = true, + hasNoSelection = ranges.every(function(range) { return range.isEmpty(); }); + // if transientMarkModeActive then mark behavior is a little + // different. Deactivate the mark when setMark is run with active + // mark + if (transientMarkModeActive && (mark || !hasNoSelection)) { + if (editor.inMultiSelectMode) editor.forEachSelection({exec: editor.clearSelection.bind(editor)}) + else editor.clearSelection(); + if (mark) editor.pushEmacsMark(null); + return; + } + + if (!mark) { + rangePositions.forEach(function(pos) { editor.pushEmacsMark(pos); }); + editor.setEmacsMark(rangePositions[rangePositions.length-1]); + return; + } + + // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + + function moveToMark() { + var mark = editor.popEmacsMark(); + mark && editor.moveCursorToPosition(mark); + } + + }, + readOnly: true, + handlesCount: true + }, + exchangePointAndMark: { + exec: function exchangePointAndMark$exec(editor, args) { + var sel = editor.selection; + if (!args.count && !sel.isEmpty()) { // just invert selection + sel.setSelectionRange(sel.getRange(), !sel.isBackwards()); + return; + } + + if (args.count) { // replace mark and point + var pos = {row: sel.lead.row, column: sel.lead.column}; + sel.clearSelection(); + sel.moveCursorToPosition(editor.emacsMarkForSelection(pos)); + } else { // create selection to last mark + sel.selectToPosition(editor.emacsMarkForSelection()); + } + }, + readOnly: true, + handlesCount: true, + multiSelectAction: "forEach" + }, + killWord: { + exec: function(editor, dir) { + editor.clearSelection(); + if (dir == "left") + editor.selection.selectWordLeft(); + else + editor.selection.selectWordRight(); + + var range = editor.getSelectionRange(); + var text = editor.session.getTextRange(range); + exports.killRing.add(text); + + editor.session.remove(range); + editor.clearSelection(); + }, + multiSelectAction: "forEach" + }, + killLine: function(editor) { + editor.pushEmacsMark(null); + var pos = editor.getCursorPosition(); + if (pos.column === 0 && + editor.session.doc.getLine(pos.row).length === 0) { + // If an already empty line is killed, remove + // the line entirely + editor.selection.selectLine(); + } else { + // otherwise just remove from the current cursor position + // to the end (but don't delete the selection if it's before + // the cursor) + editor.clearSelection(); + editor.selection.selectLineEnd(); + } + var range = editor.getSelectionRange(); + var text = editor.session.getTextRange(range); + exports.killRing.add(text); + + editor.session.remove(range); + editor.clearSelection(); + }, + yank: function(editor) { + editor.onPaste(exports.killRing.get() || ''); + editor.keyBinding.$data.lastCommand = "yank"; + }, + yankRotate: function(editor) { + if (editor.keyBinding.$data.lastCommand != "yank") + return; + editor.undo(); + editor.session.$emacsMarkRing.pop(); // also undo recording mark + editor.onPaste(exports.killRing.rotate()); + editor.keyBinding.$data.lastCommand = "yank"; + }, + killRegion: { + exec: function(editor) { + exports.killRing.add(editor.getCopyText()); + editor.commands.byName.cut.exec(editor); + }, + readOnly: true, + multiSelectAction: "forEach" + }, + killRingSave: { + exec: function(editor) { + // copy text and deselect. will save marks for starts of the + // selection(s) + + editor.$handlesEmacsOnCopy = true; + var marks = editor.session.$emacsMarkRing.slice(), + deselectedMarks = []; + exports.killRing.add(editor.getCopyText()); + + setTimeout(function() { + function deselect() { + var sel = editor.selection, range = sel.getRange(), + pos = sel.isBackwards() ? range.end : range.start; + deselectedMarks.push({row: pos.row, column: pos.column}); + sel.clearSelection(); + } + editor.$handlesEmacsOnCopy = false; + if (editor.inMultiSelectMode) editor.forEachSelection({exec: deselect}); + else deselect(); + editor.session.$emacsMarkRing = marks.concat(deselectedMarks.reverse()); + }, 0); + }, + readOnly: true + }, + keyboardQuit: function(editor) { + editor.selection.clearSelection(); + editor.setEmacsMark(null); + editor.keyBinding.$data.count = null; + }, + focusCommandLine: function(editor, arg) { + if (editor.showCommandLine) + editor.showCommandLine(arg); + } +}); + +exports.handler.addCommands(iSearchCommandModule.iSearchStartCommands); + +var commands = exports.handler.commands; +commands.yank.isYank = true; +commands.yankRotate.isYank = true; + +exports.killRing = { + $data: [], + add: function(str) { + str && this.$data.push(str); + if (this.$data.length > 30) + this.$data.shift(); + }, + get: function(n) { + n = n || 1; + return this.$data.slice(this.$data.length-n, this.$data.length).reverse().join('\n'); + }, + pop: function() { + if (this.$data.length > 1) + this.$data.pop(); + return this.get(); + }, + rotate: function() { + this.$data.unshift(this.$data.pop()); + return this.get(); + } +}; + +}); diff --git a/node_modules/ace/lib/ace/keyboard/emacs_test.js b/node_modules/ace/lib/ace/keyboard/emacs_test.js new file mode 100644 index 00000000..3ba5efaa --- /dev/null +++ b/node_modules/ace/lib/ace/keyboard/emacs_test.js @@ -0,0 +1,151 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +if (typeof process !== "undefined") { + require("amd-loader"); +} + +define(function(require, exports, module) { +"use strict"; + +require("../multi_select"); + +var EditSession = require("./../edit_session").EditSession, + Editor = require("./../editor").Editor, + Range = require("./../range").Range, + MockRenderer = require("./../test/mockrenderer").MockRenderer, + emacs = require('./emacs'), + assert = require("./../test/assertions"), + editor, sel; + +function initEditor(docString) { + var doc = new EditSession(docString.split("\n")); + editor = new Editor(new MockRenderer(), doc); + editor.setKeyboardHandler(emacs.handler); + sel = editor.selection; +} + +function print(obj) { + return JSON.stringify(obj, null, 2); +} + +function pluck(arr, what) { + return arr.map(function(ea) { return ea[what]; }); +} + +module.exports = { + + "test: detach removes emacs commands from command manager": function() { + initEditor(''); + assert.ok(!!editor.commands.byName["keyboardQuit"], 'setup error: emacs commands not installed'); + editor.keyBinding.removeKeyboardHandler(editor.getKeyboardHandler()); + assert.ok(!editor.commands.byName["keyboardQuit"], 'emacs commands not removed'); + }, + + "test: keyboardQuit clears selection": function() { + initEditor('foo'); + editor.selectAll(); + editor.execCommand('keyboardQuit'); + assert.ok(editor.selection.isEmpty(), 'selection non-empty'); + }, + + "test: exchangePointAndMark without mark set": function() { + initEditor('foo'); + sel.setRange(Range.fromPoints({row: 0, column: 1}, {row: 0, column: 3})); + editor.execCommand('exchangePointAndMark'); + assert.deepEqual({row: 0, column: 1}, editor.getCursorPosition(), print(editor.getCursorPosition())); + }, + + "test: exchangePointAndMark with mark set": function() { + initEditor('foo'); + editor.pushEmacsMark({row: 0, column: 1}); + editor.pushEmacsMark({row: 0, column: 2}); + editor.execCommand('exchangePointAndMark', {count: 4}); + assert.deepEqual({row: 0, column: 2}, editor.getCursorPosition(), print(editor.getCursorPosition())); + assert.deepEqual([{row: 0, column: 1}, {row: 0, column: 0}], editor.session.$emacsMarkRing, print(editor.session.$emacsMarkRing)); + }, + + "test: exchangePointAndMark with selection": function() { + initEditor('foo'); + editor.pushEmacsMark({row: 0, column: 1}); + editor.pushEmacsMark({row: 0, column: 2}); + sel.setRange(Range.fromPoints({row: 0, column: 0}, {row: 0, column: 1}), true); + editor.execCommand('exchangePointAndMark'); + assert.deepEqual({row: 0, column: 1}, editor.getCursorPosition(), print(editor.getCursorPosition())); + assert.deepEqual([{row: 0, column: 1}, {row: 0, column: 2}], editor.session.$emacsMarkRing, print(editor.session.$emacsMarkRing)); + }, + + "test: exchangePointAndMark with multi selection": function() { + initEditor('foo\nhello world\n123'); + var ranges = [[{row: 0, column: 0}, {row: 0, column: 3}], + [{row: 1, column: 0}, {row: 1, column: 5}], + [{row: 1, column: 6}, {row: 1, column: 11}]] + ranges.forEach(function(r) { + sel.addRange(Range.fromPoints(r[0], r[1])); + }); + assert.equal("foo\nhello\nworld", editor.getSelectedText()); + editor.execCommand('exchangePointAndMark'); + assert.equal("foo\nhello\nworld", editor.getSelectedText()); + assert.deepEqual(pluck(ranges, 0), pluck(sel.getAllRanges(), 'cursor'), "selections dir not inverted"); + }, + + "test: exchangePointAndMark with multi cursors": function() { + initEditor('foo\nhello world\n123'); + var ranges = [[{row: 0, column: 0}, {row: 0, column: 3}], + [{row: 1, column: 0}, {row: 1, column: 5}], + [{row: 1, column: 6}, {row: 1, column: 11}]]; + // move cursors to the start of each range and set a mark to its end + // without selecting anything + ranges.forEach(function(r) { + editor.pushEmacsMark(r[1]); + sel.addRange(Range.fromPoints(r[0], r[0])); + }); + assert.deepEqual(pluck(ranges, 0), pluck(sel.getAllRanges(), 'cursor'), print(sel.getAllRanges())); + editor.execCommand('exchangePointAndMark'); + assert.deepEqual(pluck(ranges, 1), pluck(sel.getAllRanges(), 'cursor'), "not inverted: " + print(sel.getAllRanges())); + }, + + "test: setMark with multi cursors": function() { + initEditor('foo\nhello world\n123'); + var positions = [{row: 0, column: 0}, + {row: 1, column: 0}, + {row: 1, column: 6}]; + positions.forEach(function(p) { sel.addRange(Range.fromPoints(p,p)); }); + editor.execCommand('setMark'); + assert.deepEqual(positions, editor.session.$emacsMarkRing, print(editor.session.$emacsMarkRing)); + } + +}; + +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec() +} diff --git a/node_modules/ace/lib/ace/keyboard/hash_handler.js b/node_modules/ace/lib/ace/keyboard/hash_handler.js new file mode 100644 index 00000000..7a0396fc --- /dev/null +++ b/node_modules/ace/lib/ace/keyboard/hash_handler.js @@ -0,0 +1,248 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var keyUtil = require("../lib/keys"); +var useragent = require("../lib/useragent"); +var KEY_MODS = keyUtil.KEY_MODS; + +function HashHandler(config, platform) { + this.platform = platform || (useragent.isMac ? "mac" : "win"); + this.commands = {}; + this.commandKeyBinding = {}; + this.addCommands(config); + this.$singleCommand = true; +} + +function MultiHashHandler(config, platform) { + HashHandler.call(this, config, platform); + this.$singleCommand = false; +} + +MultiHashHandler.prototype = HashHandler.prototype; + +(function() { + + + this.addCommand = function(command) { + if (this.commands[command.name]) + this.removeCommand(command); + + this.commands[command.name] = command; + + if (command.bindKey) + this._buildKeyHash(command); + }; + + this.removeCommand = function(command, keepCommand) { + var name = command && (typeof command === 'string' ? command : command.name); + command = this.commands[name]; + if (!keepCommand) + delete this.commands[name]; + + // exhaustive search is brute force but since removeCommand is + // not a performance critical operation this should be OK + var ckb = this.commandKeyBinding; + for (var keyId in ckb) { + var cmdGroup = ckb[keyId]; + if (cmdGroup == command) { + delete ckb[keyId]; + } else if (Array.isArray(cmdGroup)) { + var i = cmdGroup.indexOf(command); + if (i != -1) { + cmdGroup.splice(i, 1); + if (cmdGroup.length == 1) + ckb[keyId] = cmdGroup[0]; + } + } + } + }; + + this.bindKey = function(key, command, position) { + if (typeof key == "object") { + if (position == undefined) + position = key.position; + key = key[this.platform]; + } + if (!key) + return; + if (typeof command == "function") + return this.addCommand({exec: command, bindKey: key, name: command.name || key}); + + key.split("|").forEach(function(keyPart) { + var chain = ""; + if (keyPart.indexOf(" ") != -1) { + var parts = keyPart.split(/\s+/); + keyPart = parts.pop(); + parts.forEach(function(keyPart) { + var binding = this.parseKeys(keyPart); + var id = KEY_MODS[binding.hashId] + binding.key; + chain += (chain ? " " : "") + id; + this._addCommandToBinding(chain, "chainKeys"); + }, this); + chain += " "; + } + var binding = this.parseKeys(keyPart); + var id = KEY_MODS[binding.hashId] + binding.key; + this._addCommandToBinding(chain + id, command, position); + }, this); + }; + + function getPosition(command) { + return typeof command == "object" && command.bindKey + && command.bindKey.position || 0; + } + this._addCommandToBinding = function(keyId, command, position) { + var ckb = this.commandKeyBinding, i; + if (!command) { + delete ckb[keyId]; + } else if (!ckb[keyId] || this.$singleCommand) { + ckb[keyId] = command; + } else { + if (!Array.isArray(ckb[keyId])) { + ckb[keyId] = [ckb[keyId]]; + } else if ((i = ckb[keyId].indexOf(command)) != -1) { + ckb[keyId].splice(i, 1); + } + + if (typeof position != "number") { + if (position || command.isDefault) + position = -100; + else + position = getPosition(command); + } + var commands = ckb[keyId]; + for (i = 0; i < commands.length; i++) { + var other = commands[i]; + var otherPos = getPosition(other); + if (otherPos > position) + break; + } + commands.splice(i, 0, command); + } + }; + + this.addCommands = function(commands) { + commands && Object.keys(commands).forEach(function(name) { + var command = commands[name]; + if (!command) + return; + + if (typeof command === "string") + return this.bindKey(command, name); + + if (typeof command === "function") + command = { exec: command }; + + if (typeof command !== "object") + return; + + if (!command.name) + command.name = name; + + this.addCommand(command); + }, this); + }; + + this.removeCommands = function(commands) { + Object.keys(commands).forEach(function(name) { + this.removeCommand(commands[name]); + }, this); + }; + + this.bindKeys = function(keyList) { + Object.keys(keyList).forEach(function(key) { + this.bindKey(key, keyList[key]); + }, this); + }; + + this._buildKeyHash = function(command) { + this.bindKey(command.bindKey, command); + }; + + // accepts keys in the form ctrl+Enter or ctrl-Enter + // keys without modifiers or shift only + this.parseKeys = function(keys) { + var parts = keys.toLowerCase().split(/[\-\+]([\-\+])?/).filter(function(x){return x}); + var key = parts.pop(); + + var keyCode = keyUtil[key]; + if (keyUtil.FUNCTION_KEYS[keyCode]) + key = keyUtil.FUNCTION_KEYS[keyCode].toLowerCase(); + else if (!parts.length) + return {key: key, hashId: -1}; + else if (parts.length == 1 && parts[0] == "shift") + return {key: key.toUpperCase(), hashId: -1}; + + var hashId = 0; + for (var i = parts.length; i--;) { + var modifier = keyUtil.KEY_MODS[parts[i]]; + if (modifier == null) { + if (typeof console != "undefined") + console.error("invalid modifier " + parts[i] + " in " + keys); + return false; + } + hashId |= modifier; + } + return {key: key, hashId: hashId}; + }; + + this.findKeyCommand = function findKeyCommand(hashId, keyString) { + var key = KEY_MODS[hashId] + keyString; + return this.commandKeyBinding[key]; + }; + + this.handleKeyboard = function(data, hashId, keyString, keyCode) { + var key = KEY_MODS[hashId] + keyString; + var command = this.commandKeyBinding[key]; + if (data.$keyChain) { + data.$keyChain += " " + key; + command = this.commandKeyBinding[data.$keyChain] || command; + } + + if (command) { + if (command == "chainKeys" || command[command.length - 1] == "chainKeys") { + data.$keyChain = data.$keyChain || key; + return {command: "null"}; + } + } + + if (data.$keyChain && keyCode > 0) + data.$keyChain = ""; + return {command: command}; + }; + +}).call(HashHandler.prototype); + +exports.HashHandler = HashHandler; +exports.MultiHashHandler = MultiHashHandler; +}); diff --git a/node_modules/ace/lib/ace/keyboard/keybinding.js b/node_modules/ace/lib/ace/keyboard/keybinding.js new file mode 100644 index 00000000..cddf0666 --- /dev/null +++ b/node_modules/ace/lib/ace/keyboard/keybinding.js @@ -0,0 +1,145 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var keyUtil = require("../lib/keys"); +var event = require("../lib/event"); + +var KeyBinding = function(editor) { + this.$editor = editor; + this.$data = {editor: editor}; + this.$handlers = []; + this.setDefaultHandler(editor.commands); +}; + +(function() { + this.setDefaultHandler = function(kb) { + this.removeKeyboardHandler(this.$defaultHandler); + this.$defaultHandler = kb; + this.addKeyboardHandler(kb, 0); + }; + + this.setKeyboardHandler = function(kb) { + var h = this.$handlers; + if (h[h.length - 1] == kb) + return; + + while (h[h.length - 1] && h[h.length - 1] != this.$defaultHandler) + this.removeKeyboardHandler(h[h.length - 1]); + + this.addKeyboardHandler(kb, 1); + }; + + this.addKeyboardHandler = function(kb, pos) { + if (!kb) + return; + if (typeof kb == "function" && !kb.handleKeyboard) + kb.handleKeyboard = kb; + var i = this.$handlers.indexOf(kb); + if (i != -1) + this.$handlers.splice(i, 1); + + if (pos == undefined) + this.$handlers.push(kb); + else + this.$handlers.splice(pos, 0, kb); + + if (i == -1 && kb.attach) + kb.attach(this.$editor); + }; + + this.removeKeyboardHandler = function(kb) { + var i = this.$handlers.indexOf(kb); + if (i == -1) + return false; + this.$handlers.splice(i, 1); + kb.detach && kb.detach(this.$editor); + return true; + }; + + this.getKeyboardHandler = function() { + return this.$handlers[this.$handlers.length - 1]; + }; + + this.getStatusText = function() { + var data = this.$data; + var editor = data.editor; + return this.$handlers.map(function(h) { + return h.getStatusText && h.getStatusText(editor, data) || ""; + }).filter(Boolean).join(" "); + }; + + this.$callKeyboardHandlers = function(hashId, keyString, keyCode, e) { + var toExecute; + var success = false; + var commands = this.$editor.commands; + + for (var i = this.$handlers.length; i--;) { + toExecute = this.$handlers[i].handleKeyboard( + this.$data, hashId, keyString, keyCode, e + ); + if (!toExecute || !toExecute.command) + continue; + + // allow keyboardHandler to consume keys + if (toExecute.command == "null") { + success = true; + } else { + success = commands.exec(toExecute.command, this.$editor, toExecute.args, e); + } + // do not stop input events to not break repeating + if (success && e && hashId != -1 && + toExecute.passEvent != true && toExecute.command.passEvent != true + ) { + event.stopEvent(e); + } + if (success) + break; + } + return success; + }; + + this.onCommandKey = function(e, hashId, keyCode) { + var keyString = keyUtil.keyCodeToString(keyCode); + this.$callKeyboardHandlers(hashId, keyString, keyCode, e); + }; + + this.onTextInput = function(text) { + var success = this.$callKeyboardHandlers(-1, text); + if (!success) + this.$editor.commands.exec("insertstring", this.$editor, text); + }; + +}).call(KeyBinding.prototype); + +exports.KeyBinding = KeyBinding; +}); diff --git a/node_modules/ace/lib/ace/keyboard/keybinding_test.js b/node_modules/ace/lib/ace/keyboard/keybinding_test.js new file mode 100644 index 00000000..617d99c4 --- /dev/null +++ b/node_modules/ace/lib/ace/keyboard/keybinding_test.js @@ -0,0 +1,69 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +if (typeof process !== "undefined") { + require("amd-loader"); +} + +define(function(require, exports, module) { +"use strict"; + +var EditSession = require("./../edit_session").EditSession, + Editor = require("./../editor").Editor, + MockRenderer = require("./../test/mockrenderer").MockRenderer, + assert = require("./../test/assertions"), + HashHandler = require('./hash_handler').HashHandler, + keys = require('../lib/keys'), + editor; + +function initEditor(docString) { + var doc = new EditSession(docString.split("\n")); + editor = new Editor(new MockRenderer(), doc); +} + +module.exports = { + + "test: adding a new keyboard handler does not remove the default handler": function() { + initEditor('abc'); + var handler = new HashHandler({'del': 'f1'}); + editor.keyBinding.setKeyboardHandler(handler); + editor.onCommandKey({}, 0, keys['f1']); + assert.equal('bc', editor.getValue(), "binding of new handler"); + editor.onCommandKey({}, 0, keys['delete']); + assert.equal('c', editor.getValue(), "bindings of the old handler should still work"); + } + +}; + +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec() +} diff --git a/node_modules/ace/lib/ace/keyboard/state_handler.js b/node_modules/ace/lib/ace/keyboard/state_handler.js new file mode 100644 index 00000000..8265bbe1 --- /dev/null +++ b/node_modules/ace/lib/ace/keyboard/state_handler.js @@ -0,0 +1,249 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +// If you're developing a new keymapping and want to get an idea what's going +// on, then enable debugging. +var DEBUG = false; + +function StateHandler(keymapping) { + this.keymapping = this.$buildKeymappingRegex(keymapping); +} + +StateHandler.prototype = { + /* + * Build the RegExp from the keymapping as RegExp can't stored directly + * in the metadata JSON and as the RegExp used to match the keys/buffer + * need to be adapted. + */ + $buildKeymappingRegex: function(keymapping) { + for (var state in keymapping) { + this.$buildBindingsRegex(keymapping[state]); + } + return keymapping; + }, + + $buildBindingsRegex: function(bindings) { + // Escape a given Regex string. + bindings.forEach(function(binding) { + if (binding.key) { + binding.key = new RegExp('^' + binding.key + '$'); + } else if (Array.isArray(binding.regex)) { + if (!('key' in binding)) + binding.key = new RegExp('^' + binding.regex[1] + '$'); + binding.regex = new RegExp(binding.regex.join('') + '$'); + } else if (binding.regex) { + binding.regex = new RegExp(binding.regex + '$'); + } + }); + }, + + $composeBuffer: function(data, hashId, key, e) { + // Initialize the data object. + if (data.state == null || data.buffer == null) { + data.state = "start"; + data.buffer = ""; + } + + var keyArray = []; + if (hashId & 1) keyArray.push("ctrl"); + if (hashId & 8) keyArray.push("command"); + if (hashId & 2) keyArray.push("option"); + if (hashId & 4) keyArray.push("shift"); + if (key) keyArray.push(key); + + var symbolicName = keyArray.join("-"); + var bufferToUse = data.buffer + symbolicName; + + // Don't add the symbolic name to the key buffer if the alt_ key is + // part of the symbolic name. If it starts with alt_, this means + // that the user hit an alt keycombo and there will be a single, + // new character detected after this event, which then will be + // added to the buffer (e.g. alt_j will result in ∆). + // + // We test for 2 and not for & 2 as we only want to exclude the case where + // the option key is pressed alone. + if (hashId != 2) { + data.buffer = bufferToUse; + } + + var bufferObj = { + bufferToUse: bufferToUse, + symbolicName: symbolicName + }; + + if (e) { + bufferObj.keyIdentifier = e.keyIdentifier; + } + + return bufferObj; + }, + + $find: function(data, buffer, symbolicName, hashId, key, keyIdentifier) { + // Holds the command to execute and the args if a command matched. + var result = {}; + + // Loop over all the bindings of the keymap until a match is found. + this.keymapping[data.state].some(function(binding) { + var match; + + // Check if the key matches. + if (binding.key && !binding.key.test(symbolicName)) { + return false; + } + + // Check if the regex matches. + if (binding.regex && !(match = binding.regex.exec(buffer))) { + return false; + } + + // Check if the match function matches. + if (binding.match && !binding.match(buffer, hashId, key, symbolicName, keyIdentifier)) { + return false; + } + + // Check for disallowed matches. + if (binding.disallowMatches) { + for (var i = 0; i < binding.disallowMatches.length; i++) { + if (!!match[binding.disallowMatches[i]]) { + return false; + } + } + } + + // If there is a command to execute, then figure out the + // command and the arguments. + if (binding.exec) { + result.command = binding.exec; + + // Build the arguments. + if (binding.params) { + var value; + result.args = {}; + binding.params.forEach(function(param) { + if (param.match != null && match != null) { + value = match[param.match] || param.defaultValue; + } else { + value = param.defaultValue; + } + + if (param.type === 'number') { + value = parseInt(value); + } + + result.args[param.name] = value; + }); + } + data.buffer = ""; + } + + // Handle the 'then' property. + if (binding.then) { + data.state = binding.then; + data.buffer = ""; + } + + // If no command is set, then execute the "null" fake command. + if (result.command == null) { + result.command = "null"; + } + + if (DEBUG) { + console.log("KeyboardStateMapper#find", binding); + } + return true; + }); + + if (result.command) { + return result; + } else { + data.buffer = ""; + return false; + } + }, + + /* + * This function is called by keyBinding. + */ + handleKeyboard: function(data, hashId, key, keyCode, e) { + if (hashId == -1) + hashId = 0 + // If we pressed any command key but no other key, then ignore the input. + // Otherwise "shift-" is added to the buffer, and later on "shift-g" + // which results in "shift-shift-g" which doesn't make sense. + if (hashId != 0 && (key == "" || key == String.fromCharCode(0))) { + return null; + } + + // Compute the current value of the keyboard input buffer. + var r = this.$composeBuffer(data, hashId, key, e); + var buffer = r.bufferToUse; + var symbolicName = r.symbolicName; + var keyId = r.keyIdentifier; + + r = this.$find(data, buffer, symbolicName, hashId, key, keyId); + if (DEBUG) { + console.log("KeyboardStateMapper#match", buffer, symbolicName, r); + } + + return r; + } +} + +/* + * This is a useful matching function and therefore is defined here so that + * users of KeyboardStateMapper can use it. + * + * @return {Boolean} If no command key (Command|Option|Shift|Ctrl) is pressed, it + * returns true. If the only the Shift key is pressed + a character + * true is returned as well. Otherwise, false is returned. + * Summing up, the function returns true whenever the user typed + * a normal character on the keyboard and no shortcut. + */ +exports.matchCharacterOnly = function(buffer, hashId, key, symbolicName) { + // If no command keys are pressed, then catch the input. + if (hashId == 0) { + return true; + } + // If only the shift key is pressed and a character key, then + // catch that input as well. + else if ((hashId == 4) && key.length == 1) { + return true; + } + // Otherwise, we let the input got through. + else { + return false; + } +}; + +exports.StateHandler = StateHandler; +}); diff --git a/node_modules/ace/lib/ace/keyboard/sublime.js b/node_modules/ace/lib/ace/keyboard/sublime.js new file mode 100644 index 00000000..006dc391 --- /dev/null +++ b/node_modules/ace/lib/ace/keyboard/sublime.js @@ -0,0 +1,465 @@ +// DO NOT COMMIT TO OPEN SOURCE ACE! + +define(function(require, exports, module) { +"use strict"; + +var keyUtil = require("../lib/keys"); +var oop = require("../lib/oop"); +var useragent = require("../lib/useragent"); +var HashHandler = require("../keyboard/hash_handler").HashHandler; + + +var keyMods = (function() { + var keyMods = []; + var mods = ["meta", "ctrl", "alt", "shift"]; + for (var i = mods.length; i--;) { + keyMods[i] = mods.filter(function(x) { + return i & keyUtil.KEY_MODS[x]; + }).join("-") + "-"; + } + return keyMods; +})(); + +var commandMap = { + "auto_complete" : "complete", + "build" : "build", + "clear_bookmarks" : false, + "clear_fields" : false, + "close" : false, + "close_file" : "closetab", + "close_pane" : "closepane", + "close_tag" : false, + "close_window" : "closealltabs", + "commit_completion": false, + "context_menu" : false, + "decrease_font_size" : "smallerfont", + "increase_font_size" : "largerfont", + // "copy" + // "cut" + // "delete_to_mark" + // "delete_word" : + // "duplicate_line" : "duplicate" + // "exec" + // "expand_selection" + // "find_all" + // "find_all_under" + // "find_next" + // "find_prev" + // "find_under" + // "find_under_expand" + // "find_under_expand_skip" + // "find_under_prev" + // "focus_group" + // "focus_neighboring_group" + // "focus_side_bar" + // "fold" + // "fold_by_level" + // "fold_tag_attributes" + // "goto_definition" + // "goto_symbol_in_project" + // "hide_auto_complete" + // "hide_overlay" + // "hide_panel" + // "indent" + // "insert" + // "insert_best_completion" + // "insert_snippet" + // "join_lines" + // "jump_back" + // "jump_forward" + // "left_delete" + // "lower_case" + // "move" + // "move_to" + // "move_to_group" + // "move_to_neighboring_group" + // "new_file" + // "new_pane" + // "new_window" + // "next_bookmark" + // "next_field" + // "next_misspelling" + // "next_result" + // "next_view" + // "next_view_in_stack" + // "paste" + // "paste_and_indent" + // "paste_from_history" + // "prev_bookmark" + // "prev_field" + // "prev_misspelling" + // "prev_result" + // "prev_view" + // "prev_view_in_stack" + // "prompt_open_file" + // "prompt_save_as" + // "prompt_select_workspace" + // "redo" + // "redo_or_repeat" + // "reindent" + // "reopen_last_file" + // "replace_all" + // "replace_completion_with_auto_complete" + // "replace_completion_with_next_completion" + // "replace_next" + // "right_delete" + // "run_macro" + // "run_macro_file" + // "save" + // "scroll_lines" + // "select_all" + // "select_all_bookmarks" + // "select_by_index" + // "select_lines" + // "select_to_mark" + // "set_layout" + // "set_mark" + // "show_at_center" + // "show_overlay" + // "show_panel" + // "show_scope_name" + // "single_selection" + // "slurp_find_string" + // "slurp_replace_string" + // "soft_redo" + // "soft_undo" + // "sort_lines" + // "split_selection_into_lines" + // "swap_line_down" + // "swap_line_up" + // "swap_with_mark" + // "switch_file" + // "toggle_bookmark" + // "toggle_case_sensitive" + // "toggle_comment" + // "toggle_distraction_free" + // "toggle_full_screen" + // "toggle_overwrite" + // "toggle_preserve_case" + // "toggle_record_macro" + // "toggle_regex" + // "toggle_setting" + // "toggle_side_bar" + // "toggle_whole_word" + // "transpose" + // "undo" + // "unfold" + // "unfold_all" + // "unindent" + // "upper_case" + // "wrap_block" + // "wrap_lines" + // "yank" +}; + +function getKeyValue(key, ace) { + switch (key) { + case "auto_complete_visible": + // Returns true if the autocomplete list is visible. + break; + case "has_next_field": + // Returns true if a next snippet field is available. + break; + case "has_prev_field": + // Returns true if a previous snippet field is available. + break; + case "num_selections": + // Returns the number of selections. + return ace.selection.ranges.length || 1; + break; + case "overlay_visible": + // Returns true if any overlay is visible. + break; + case "panel_visible": + // Returns true if any panel is visible. + break; + case "following_text": + // Restricts the test just to the text following the caret. + var pos = ace.getCursorPosition(); + return ace.session.getLine(pos.row).substr(pos.column); + break; + case "preceding_text": + // Restricts the test just to the text preceding the caret. + pos = ace.getCursorPosition(); + return ace.session.getLine(pos.row).substr(pos.column); + break; + case "selection_empty": + // Returns true if the selection is an empty region. + break; + case "text": + // Restricts the test just to the selected text. + return ace.getSelectedText(); + break; + case "selector": + // Returns the current scope. + break; + case "panel_has_focus": + // Returns true if the current focus is on a panel. + break; + case "panel": + // Returns true if the panel given as operand is visible. + break; + default: + // case "setting.x": + // Returns the value of the x setting. x can be any string. + } +} + +var operators = { + isTrue: function(a){return !!a}, + equal: function(a,b){return a === b}, + not_equal: function(a,b){return a !== b}, + regex_match: function(a,b){ return typeof a == "string" && a.match(b) }, + not_regex_match: function(a,b){return typeof a == "string" && !a.match(b)}, + regex_contains: function(a,b){return typeof a == "string" && a.search(b) !== -1}, + not_regex_contains: function(a,b){return typeof a == "string" && a.search(b) === -1} +}; + +function testIsAvailable(editor, args, e) { + if (!this.context) + return true; + return this.context.some(function(ctx) { + if (!ctx.key) + return; + if (ctx.operator && ctx.operator.indexOf("regex") != -1) { + if (ctx.operand && typeof ctx.operand == "string") + ctx.operand = new RegExp(ctx.operand); + } + var op = operators[ctx.operator] || ( + ctx.operand ? operators.equal : operators.isTrue); + + var key = getKeyValue(ctx.key, editor, args, e); + return op(key, ctx.operand); + }); +} + +function SublimeHandler() { + this.commands = {}; + this.commandKeyBinding = {}; +} + +(function() { + oop.implement(this, HashHandler.prototype); + + var sublimeToAceKey = { + keypad0: "numpad0", + keypad1: "numpad1", + keypad2: "numpad2", + keypad3: "numpad3", + keypad4: "numpad4", + keypad5: "numpad5", + keypad6: "numpad6", + keypad7: "numpad7", + keypad8: "numpad8", + keypad9: "numpad9", + keypad_period: ".", + keypad_divide: "/", + keypad_multiply: "*", + keypad_minus: "-", + keypad_plus: "+", + keypad_enter: "numpadEnter", + equals: "=", + plus: "+", + }; + + this.setKeyMap = function(keyMap) { + var prev + var all = keyMap.map(function(cm) { + return cm.context && cm.context.operator + }).sort().filter(function(x) { + if (x == prev) + return false; + prev = x; + return true; + }); + console.log(all) + ace.setValue(JSON.stringify(all)) + }; + + this.addCommand = function(command) { + if (this.commands[command.name]) + this.removeCommand(command); + + this.commands[command.name] = command; + + if (command.bindKey) + this._buildKeyHash(command); + }; + + this.removeCommand = function(command) { + var name = (typeof command === 'string' ? command : command.name); + command = this.commands[name]; + delete this.commands[name]; + + // exhaustive search is brute force but since removeCommand is + // not a performance critical operation this should be OK + var ckb = this.commandKeyBinding; + for (var hashId in ckb) { + for (var key in ckb[hashId]) { + if (ckb[hashId][key] == command) + delete ckb[hashId][key]; + } + } + }; + + this.bindKey = function(key, command) { + if(!key) + return; + if (typeof command == "function") { + this.addCommand({exec: command, bindKey: key, name: command.name || key}); + return; + } + + var ckb = this.commandKeyBinding; + key.split("|").forEach(function(keyPart) { + var binding = this.parseKeys(keyPart, command); + var hashId = binding.hashId; + (ckb[hashId] || (ckb[hashId] = {}))[binding.key] = command; + }, this); + }; + + this.addCommands = function(commands) { + commands && Object.keys(commands).forEach(function(name) { + var command = commands[name]; + if (!command) + return; + + if (typeof command === "string") + return this.bindKey(command, name); + + if (typeof command === "function") + command = { exec: command }; + + if (typeof command !== "object") + return; + + if (!command.name) + command.name = name; + + this.addCommand(command); + }, this); + }; + + this.removeCommands = function(commands) { + Object.keys(commands).forEach(function(name) { + this.removeCommand(commands[name]); + }, this); + }; + + this.bindKeys = function(keyList) { + Object.keys(keyList).forEach(function(key) { + this.bindKey(key, keyList[key]); + }, this); + }; + + this._buildKeyHash = function(command) { + var binding = command.bindKey; + if (!binding) + return; + + var key = typeof binding == "string" ? binding: binding[this.platform]; + this.bindKey(key, command); + }; + + // accepts keys in the form ctrl+Enter or ctrl-Enter + // keys without modifiers or shift only + this.parseKeys = function(keys) { + // todo support keychains + if (keys.indexOf(" ") != -1) + keys = keys.split(/\s+/).pop(); + + var parts = keys.toLowerCase().split(/[\-\+]([\-\+])?/).filter(function(x){return x}); + var key = parts.pop(); + + var keyCode = keyUtil[key]; + if (keyUtil.FUNCTION_KEYS[keyCode]) + key = keyUtil.FUNCTION_KEYS[keyCode].toLowerCase(); + else if (!parts.length) + return {key: key, hashId: -1}; + else if (parts.length == 1 && parts[0] == "shift") + return {key: key.toUpperCase(), hashId: -1}; + + var hashId = 0; + for (var i = parts.length; i--;) { + var modifier = keyUtil.KEY_MODS[parts[i]]; + if (modifier == null) { + if (typeof console != "undefined") + console.error("invalid modifier " + parts[i] + " in " + keys); + return false; + } + hashId |= modifier; + } + return {key: key, hashId: hashId}; + }; + + this.bindKey = function(key, command) { + if (!key) + return; + + var ckb = this.commandKeyBinding; + key.split("|").forEach(function(keyPart) { + keyPart = keyPart.toLowerCase(); + ckb[keyPart] = command; + // register all partial key combos as null commands + // to be able to activate key combos with arbitrary length + // Example: if keyPart is "C-c C-l t" then "C-c C-l t" will + // get command assigned and "C-c" and "C-c C-l" will get + // a null command assigned in this.commandKeyBinding. For + // the lookup logic see handleKeyboard() + var keyParts = keyPart.split(" ").slice(0,-1); + keyParts.reduce(function(keyMapKeys, keyPart, i) { + var prefix = keyMapKeys[i-1] ? keyMapKeys[i-1] + ' ' : ''; + return keyMapKeys.concat([prefix + keyPart]); + }, []).forEach(function(keyPart) { + if (!ckb[keyPart]) ckb[keyPart] = "null"; + }); + }, this); + }; + + this.handleKeyboard = function(data, hashId, key, keyCode) { + var editor = data.editor; + // insertstring data.count times + if (hashId == -1) { + editor.pushEmacsMark(); + if (data.count) { + var str = new Array(data.count + 1).join(key); + data.count = null; + return {command: "insertstring", args: str}; + } + } + + if (key == "\x00") return undefined; + + var modifier = keyMods[hashId]; + + if (modifier) key = modifier + key; + + // Key combos like CTRL+X H build up the data.keyChain + if (data.keyChain) key = data.keyChain += " " + key; + + // Key combo prefixes get stored as "null" (String!) in this + // this.commandKeyBinding. When encountered no command is invoked but we + // buld up data.keyChain + var command = this.commandKeyBinding[key]; + data.keyChain = command == "null" ? key : ""; + + // there really is no command + if (!command) return undefined; + + // we pass b/c of key combo + if (command === "null") return {command: "null"}; + + + + return {command: command, args: command.args}; + }; + + +}).call(SublimeHandler.prototype); + + +exports.handler = new SublimeHandler(); +var keyMap = require("../requirejs/text!./sublime/windows.sublime-keymap"); +exports.handler.setKeyMap(eval("(" + keyMap + ")")) + +}); diff --git a/node_modules/ace/lib/ace/keyboard/textarea.js b/node_modules/ace/lib/ace/keyboard/textarea.js new file mode 100644 index 00000000..470b2940 --- /dev/null +++ b/node_modules/ace/lib/ace/keyboard/textarea.js @@ -0,0 +1,82 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var HashHandler = require("./hash_handler").HashHandler; +exports.handler = new HashHandler(); + +[{ + bindKey: "Shift-Tab|Tab", + command: "passKeysToBrowser" +}, { + bindKey: {win: "Ctrl-L", mac: "Cmd-L"}, + command: "passKeysToBrowser" +}, { + bindKey: {win: "Ctrl-G", mac: "Cmd-G"}, + command: "gotoline" +}, { + bindKey: {win: "Ctrl-T|Ctrl-Shift-T", mac: "Cmd-T|Cmd-Shift-T"}, + command: "passKeysToBrowser" +}, { + bindKey: {win: "Ctrl-G", mac: "Cmd-G"}, + command: "passKeysToBrowser" +}, { + bindKey: {win: "Ctrl-G", mac: "Cmd-G"}, + command: "passKeysToBrowser" +}, { + name: "golineup", + bindKey: {win: null, mac: "Ctrl-P"}, +}, { + name: "golinedown", + bindKey: {win: null, mac: "Ctrl-N"}, +}, { + name: "gotoleft", + bindKey: {win: null, mac: "Ctrl-B"}, +}, { + name: "gotoright", + bindKey: {win: null, mac: "Ctrl-F"}, +}, { + name: "gotolineend", + bindKey: {win: null, mac: "Ctrl-E"}, +}, { + name: "gotolinestart", + bindKey: {win: null, mac: "Ctrl-A"}, +} +].forEach(function(k) { + var bindKey = k.bindKey; + if (typeof bindKey == "object") + bindKey = bindKey[exports.handler.platform]; + exports.handler.bindKey(bindKey, k.command); +}); +exports.handler.$id = "ace/keyboard/textarea"; + +}); diff --git a/node_modules/ace/lib/ace/keyboard/textinput.js b/node_modules/ace/lib/ace/keyboard/textinput.js new file mode 100644 index 00000000..3f3ad937 --- /dev/null +++ b/node_modules/ace/lib/ace/keyboard/textinput.js @@ -0,0 +1,511 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var event = require("../lib/event"); +var useragent = require("../lib/useragent"); +var dom = require("../lib/dom"); +var lang = require("../lib/lang"); +var BROKEN_SETDATA = useragent.isChrome < 18; +var USE_IE_MIME_TYPE = useragent.isIE; + +var TextInput = function(parentNode, host) { + var text = dom.createElement("textarea"); + text.className = "ace_text-input"; + + if (useragent.isTouchPad) + text.setAttribute("x-palm-disable-auto-cap", true); + + text.setAttribute("wrap", "off"); + text.setAttribute("autocorrect", "off"); + text.setAttribute("autocapitalize", "off"); + text.setAttribute("spellcheck", false); + + text.style.opacity = "0"; + if (useragent.isOldIE) text.style.top = "-100px"; + parentNode.insertBefore(text, parentNode.firstChild); + + var PLACEHOLDER = "\x01\x01"; + + var copied = false; + var pasted = false; + var inComposition = false; + var tempStyle = ''; + var isSelectionEmpty = true; + + // FOCUS + // ie9 throws error if document.activeElement is accessed too soon + try { var isFocused = document.activeElement === text; } catch(e) {} + + event.addListener(text, "blur", function(e) { + host.onBlur(e); + isFocused = false; + }); + event.addListener(text, "focus", function(e) { + isFocused = true; + host.onFocus(e); + resetSelection(); + }); + this.focus = function() { + text.style.position = "fixed"; + text.style.top = "-10000000px"; + text.focus(); + setTimeout(function() { + text.style.position = ""; + }, 0); + }; + this.blur = function() { + text.blur(); + }; + this.isFocused = function() { + return isFocused; + }; + + // modifying selection of blured textarea can focus it (chrome mac/linux) + var syncSelection = lang.delayedCall(function() { + isFocused && resetSelection(isSelectionEmpty); + }); + var syncValue = lang.delayedCall(function() { + if (!inComposition) { + text.value = PLACEHOLDER; + isFocused && resetSelection(); + } + }); + + function resetSelection(isEmpty) { + if (inComposition) + return; + + // this prevents infinite recursion on safari 8 + // see https://github.com/ajaxorg/ace/issues/2114 + inComposition = true; + + if (inputHandler) { + selectionStart = 0; + selectionEnd = isEmpty ? 0 : text.value.length - 1; + } else { + var selectionStart = isEmpty ? 2 : 1; + var selectionEnd = 2; + } + // on firefox this throws if textarea is hidden + try { + text.setSelectionRange(selectionStart, selectionEnd); + } catch(e){} + + inComposition = false; + } + + function resetValue() { + if (inComposition) + return; + text.value = PLACEHOLDER; + //http://code.google.com/p/chromium/issues/detail?id=76516 + if (useragent.isWebKit) + syncValue.schedule(); + } + + useragent.isWebKit || host.addEventListener('changeSelection', function() { + if (host.selection.isEmpty() != isSelectionEmpty) { + isSelectionEmpty = !isSelectionEmpty; + syncSelection.schedule(); + } + }); + + resetValue(); + if (isFocused) + host.onFocus(); + + + var isAllSelected = function(text) { + return text.selectionStart === 0 && text.selectionEnd === text.value.length; + }; + // IE8 does not support setSelectionRange + if (!text.setSelectionRange && text.createTextRange) { + text.setSelectionRange = function(selectionStart, selectionEnd) { + var range = this.createTextRange(); + range.collapse(true); + range.moveStart('character', selectionStart); + range.moveEnd('character', selectionEnd); + range.select(); + }; + isAllSelected = function(text) { + try { + var range = text.ownerDocument.selection.createRange(); + }catch(e) {} + if (!range || range.parentElement() != text) return false; + return range.text == text.value; + } + } + if (useragent.isOldIE) { + var inPropertyChange = false; + var onPropertyChange = function(e){ + if (inPropertyChange) + return; + var data = text.value; + if (inComposition || !data || data == PLACEHOLDER) + return; + // can happen either after delete or during insert operation + if (e && data == PLACEHOLDER[0]) + return syncProperty.schedule(); + + sendText(data); + // ie8 calls propertychange handlers synchronously! + inPropertyChange = true; + resetValue(); + inPropertyChange = false; + }; + var syncProperty = lang.delayedCall(onPropertyChange); + event.addListener(text, "propertychange", onPropertyChange); + + var keytable = { 13:1, 27:1 }; + event.addListener(text, "keyup", function (e) { + if (inComposition && (!text.value || keytable[e.keyCode])) + setTimeout(onCompositionEnd, 0); + if ((text.value.charCodeAt(0)||0) < 129) { + return syncProperty.call(); + } + inComposition ? onCompositionUpdate() : onCompositionStart(); + }); + // when user presses backspace after focusing the editor + // propertychange isn't called for the next character + event.addListener(text, "keydown", function (e) { + syncProperty.schedule(50); + }); + } + + var onSelect = function(e) { + if (copied) { + copied = false; + } else if (isAllSelected(text)) { + host.selectAll(); + resetSelection(); + } else if (inputHandler) { + resetSelection(host.selection.isEmpty()); + } + }; + + var inputHandler = null; + this.setInputHandler = function(cb) {inputHandler = cb}; + this.getInputHandler = function() {return inputHandler}; + var afterContextMenu = false; + + var sendText = function(data) { + if (inputHandler) { + data = inputHandler(data); + inputHandler = null; + } + if (pasted) { + resetSelection(); + if (data) + host.onPaste(data); + pasted = false; + } else if (data == PLACEHOLDER.charAt(0)) { + if (afterContextMenu) + host.execCommand("del", {source: "ace"}); + else // some versions of android do not fire keydown when pressing backspace + host.execCommand("backspace", {source: "ace"}); + } else { + if (data.substring(0, 2) == PLACEHOLDER) + data = data.substr(2); + else if (data.charAt(0) == PLACEHOLDER.charAt(0)) + data = data.substr(1); + else if (data.charAt(data.length - 1) == PLACEHOLDER.charAt(0)) + data = data.slice(0, -1); + // can happen if undo in textarea isn't stopped + if (data.charAt(data.length - 1) == PLACEHOLDER.charAt(0)) + data = data.slice(0, -1); + + if (data) + host.onTextInput(data); + } + if (afterContextMenu) + afterContextMenu = false; + }; + var onInput = function(e) { + // console.log("onInput", inComposition) + if (inComposition) + return; + var data = text.value; + sendText(data); + resetValue(); + }; + + var handleClipboardData = function(e, data) { + var clipboardData = e.clipboardData || window.clipboardData; + if (!clipboardData || BROKEN_SETDATA) + return; + // using "Text" doesn't work on old webkit but ie needs it + // TODO are there other browsers that require "Text"? + var mime = USE_IE_MIME_TYPE ? "Text" : "text/plain"; + if (data) { + // Safari 5 has clipboardData object, but does not handle setData() + return clipboardData.setData(mime, data) !== false; + } else { + return clipboardData.getData(mime); + } + }; + + var doCopy = function(e, isCut) { + var data = host.getCopyText(); + if (!data) + return event.preventDefault(e); + + if (handleClipboardData(e, data)) { + isCut ? host.onCut() : host.onCopy(); + event.preventDefault(e); + } else { + copied = true; + text.value = data; + text.select(); + setTimeout(function(){ + copied = false; + resetValue(); + resetSelection(); + isCut ? host.onCut() : host.onCopy(); + }); + } + }; + + var onCut = function(e) { + doCopy(e, true); + }; + + var onCopy = function(e) { + doCopy(e, false); + }; + + var onPaste = function(e) { + var data = handleClipboardData(e); + if (typeof data == "string") { + if (data) + host.onPaste(data); + if (useragent.isIE) + setTimeout(resetSelection); + event.preventDefault(e); + } + else { + text.value = ""; + pasted = true; + } + }; + + event.addCommandKeyListener(text, host.onCommandKey.bind(host)); + + event.addListener(text, "select", onSelect); + + event.addListener(text, "input", onInput); + + event.addListener(text, "cut", onCut); + event.addListener(text, "copy", onCopy); + event.addListener(text, "paste", onPaste); + + + // Opera has no clipboard events + if (!('oncut' in text) || !('oncopy' in text) || !('onpaste' in text)){ + event.addListener(parentNode, "keydown", function(e) { + if ((useragent.isMac && !e.metaKey) || !e.ctrlKey) + return; + + switch (e.keyCode) { + case 67: + onCopy(e); + break; + case 86: + onPaste(e); + break; + case 88: + onCut(e); + break; + } + }); + } + + + // COMPOSITION + var onCompositionStart = function(e) { + if (inComposition || !host.onCompositionStart || host.$readOnly) + return; + // console.log("onCompositionStart", inComposition) + inComposition = {}; + host.onCompositionStart(); + setTimeout(onCompositionUpdate, 0); + host.on("mousedown", onCompositionEnd); + if (!host.selection.isEmpty()) { + host.insert(""); + host.session.markUndoGroup(); + host.selection.clearSelection(); + } + host.session.markUndoGroup(); + }; + + var onCompositionUpdate = function() { + // console.log("onCompositionUpdate", inComposition && JSON.stringify(text.value)) + if (!inComposition || !host.onCompositionUpdate || host.$readOnly) + return; + var val = text.value.replace(/\x01/g, ""); + if (inComposition.lastValue === val) return; + + host.onCompositionUpdate(val); + if (inComposition.lastValue) + host.undo(); + inComposition.lastValue = val; + if (inComposition.lastValue) { + var r = host.selection.getRange(); + host.insert(inComposition.lastValue); + host.session.markUndoGroup(); + inComposition.range = host.selection.getRange(); + host.selection.setRange(r); + host.selection.clearSelection(); + } + }; + + var onCompositionEnd = function(e) { + if (!host.onCompositionEnd || host.$readOnly) return; + // console.log("onCompositionEnd", inComposition &&inComposition.lastValue) + var c = inComposition; + inComposition = false; + var timer = setTimeout(function() { + timer = null; + var str = text.value.replace(/\x01/g, ""); + // console.log(str, c.lastValue) + if (inComposition) + return; + else if (str == c.lastValue) + resetValue(); + else if (!c.lastValue && str) { + resetValue(); + sendText(str); + } + }); + inputHandler = function compositionInputHandler(str) { + // console.log("onCompositionEnd", str, c.lastValue) + if (timer) + clearTimeout(timer); + str = str.replace(/\x01/g, ""); + if (str == c.lastValue) + return ""; + if (c.lastValue && timer) + host.undo(); + return str; + }; + host.onCompositionEnd(); + host.removeListener("mousedown", onCompositionEnd); + if (e.type == "compositionend" && c.range) { + host.selection.setRange(c.range); + } + }; + + + + var syncComposition = lang.delayedCall(onCompositionUpdate, 50); + + event.addListener(text, "compositionstart", onCompositionStart); + if (useragent.isGecko) { + event.addListener(text, "text", function(){syncComposition.schedule()}); + } else { + event.addListener(text, "keyup", function(){syncComposition.schedule()}); + event.addListener(text, "keydown", function(){syncComposition.schedule()}); + } + event.addListener(text, "compositionend", onCompositionEnd); + + this.getElement = function() { + return text; + }; + + this.setReadOnly = function(readOnly) { + text.readOnly = readOnly; + }; + + this.onContextMenu = function(e) { + afterContextMenu = true; + resetSelection(host.selection.isEmpty()); + host._emit("nativecontextmenu", {target: host, domEvent: e}); + this.moveToMouse(e, true); + }; + + this.moveToMouse = function(e, bringToFront) { + if (!bringToFront && useragent.isOldIE) + return; + if (!tempStyle) + tempStyle = text.style.cssText; + text.style.cssText = (bringToFront ? "z-index:100000;" : "") + + "height:" + text.style.height + ";" + + (useragent.isIE ? "opacity:0.1;" : ""); + + var rect = host.container.getBoundingClientRect(); + var style = dom.computedStyle(host.container); + var top = rect.top + (parseInt(style.borderTopWidth) || 0); + var left = rect.left + (parseInt(rect.borderLeftWidth) || 0); + var maxTop = rect.bottom - top - text.clientHeight -2; + var move = function(e) { + text.style.left = e.clientX - left - 2 + "px"; + text.style.top = Math.min(e.clientY - top - 2, maxTop) + "px"; + }; + move(e); + + if (e.type != "mousedown") + return; + + if (host.renderer.$keepTextAreaAtCursor) + host.renderer.$keepTextAreaAtCursor = null; + + // on windows context menu is opened after mouseup + if (useragent.isWin && !useragent.isOldIE) + event.capture(host.container, move, onContextMenuClose); + }; + + this.onContextMenuClose = onContextMenuClose; + var closeTimeout; + function onContextMenuClose() { + clearTimeout(closeTimeout); + closeTimeout = setTimeout(function () { + if (tempStyle) { + text.style.cssText = tempStyle; + tempStyle = ''; + } + if (host.renderer.$keepTextAreaAtCursor == null) { + host.renderer.$keepTextAreaAtCursor = true; + host.renderer.$moveTextAreaToCursor(); + } + }, useragent.isOldIE ? 200 : 0); + } + + var onContextMenu = function(e) { + host.textInput.onContextMenu(e); + onContextMenuClose(); + }; + event.addListener(host.renderer.scroller, "contextmenu", onContextMenu); + event.addListener(text, "contextmenu", onContextMenu); +}; + +exports.TextInput = TextInput; +}); diff --git a/node_modules/ace/lib/ace/keyboard/vim.js b/node_modules/ace/lib/ace/keyboard/vim.js new file mode 100644 index 00000000..d3066bf1 --- /dev/null +++ b/node_modules/ace/lib/ace/keyboard/vim.js @@ -0,0 +1,6065 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +/** + * Supported keybindings: + * + * Motion: + * h, j, k, l + * gj, gk + * e, E, w, W, b, B, ge, gE + * f, F, t, T + * $, ^, 0, -, +, _ + * gg, G + * % + * ', ` + * + * Operator: + * d, y, c + * dd, yy, cc + * g~, g~g~ + * >, <, >>, << + * + * Operator-Motion: + * x, X, D, Y, C, ~ + * + * Action: + * a, i, s, A, I, S, o, O + * zz, z., z, zt, zb, z- + * J + * u, Ctrl-r + * m + * r + * + * Modes: + * ESC - leave insert mode, visual mode, and clear input state. + * Ctrl-[, Ctrl-c - same as ESC. + * + * Registers: unnamed, -, a-z, A-Z, 0-9 + * (Does not respect the special case for number registers when delete + * operator is made with these commands: %, (, ), , /, ?, n, N, {, } ) + * TODO: Implement the remaining registers. + * Marks: a-z, A-Z, and 0-9 + * TODO: Implement the remaining special marks. They have more complex + * behavior. + * + * Events: + * 'vim-mode-change' - raised on the editor anytime the current mode changes, + * Event object: {mode: "visual", subMode: "linewise"} + * + * Code structure: + * 1. Default keymap + * 2. Variable declarations and short basic helpers + * 3. Instance (External API) implementation + * 4. Internal state tracking objects (input state, counter) implementation + * and instanstiation + * 5. Key handler (the main command dispatcher) implementation + * 6. Motion, operator, and action implementations + * 7. Helper functions for the key handler, motions, operators, and actions + * 8. Set up Vim to work as a keymap for CodeMirror. + */ + +define(function(require, exports, module) { + 'use strict'; + + function log() { + var d = ""; + function format(p) { + if (typeof p != "object") + return p + ""; + if ("line" in p) { + return p.line + ":" + p.ch; + } + if ("anchor" in p) { + return format(p.anchor) + "->" + format(p.head); + } + if (Array.isArray(p)) + return "[" + p.map(function(x) { + return format(x); + }) + "]"; + return JSON.stringify(p); + } + for (var i = 0; i < arguments.length; i++) { + var p = arguments[i]; + var f = format(p); + d += f + " "; + } + console.log(d); + } + var Range = require("../range").Range; + var EventEmitter = require("../lib/event_emitter").EventEmitter; + var dom = require("../lib/dom"); + var oop = require("../lib/oop"); + var KEYS = require("../lib/keys"); + var event = require("../lib/event"); + var Search = require("../search").Search; + var useragent = require("../lib/useragent"); + var SearchHighlight = require("../search_highlight").SearchHighlight; + var multiSelectCommands = require("../commands/multi_select_commands"); + var TextModeTokenRe = require("ace/mode/text").Mode.prototype.tokenRe; + require("../multi_select"); + + var CodeMirror = function(ace) { + this.ace = ace; + this.state = {}; + this.marks = {}; + this.$uid = 0; + this.onChange = this.onChange.bind(this); + this.onSelectionChange = this.onSelectionChange.bind(this); + this.onBeforeEndOperation = this.onBeforeEndOperation.bind(this); + this.ace.on('change', this.onChange); + this.ace.on('changeSelection', this.onSelectionChange); + this.ace.on('beforeEndOperation', this.onBeforeEndOperation); + }; + CodeMirror.Pos = function(line, ch) { + if (!(this instanceof Pos)) return new Pos(line, ch); + this.line = line; this.ch = ch; + }; + CodeMirror.defineOption = function(name, val, setter) {}; + CodeMirror.commands = { + redo: function(cm) { cm.ace.redo(); }, + undo: function(cm) { cm.ace.undo(); }, + newlineAndIndent: function(cm) { cm.ace.insert("\n"); }, + }; + CodeMirror.keyMap = {}; + CodeMirror.addClass = CodeMirror.rmClass = + CodeMirror.e_stop = function() {}; + CodeMirror.keyName = function(e) { + if (e.key) return e.key; + var key = (KEYS[e.keyCode] || ""); + if (key.length == 1) key = key.toUpperCase(); + key = event.getModifierString(e).replace(/(^|-)\w/g, function(m) { + return m.toUpperCase(); + }) + key; + return key; + }; + CodeMirror.keyMap['default'] = function(key) { + return function(cm) { + var cmd = cm.ace.commands.commandKeyBinding[key.toLowerCase()]; + return cmd && cm.ace.execCommand(cmd) !== false; + }; + }; + CodeMirror.lookupKey = function lookupKey(key, map, handle) { + if (typeof map == "string") + map = CodeMirror.keyMap[map]; + var found = typeof map == "function" ? map(key) : map[key]; + if (found === false) return "nothing"; + if (found === "...") return "multi"; + if (found != null && handle(found)) return "handled"; + + if (map.fallthrough) { + if (!Array.isArray(map.fallthrough)) + return lookupKey(key, map.fallthrough, handle); + for (var i = 0; i < map.fallthrough.length; i++) { + var result = lookupKey(key, map.fallthrough[i], handle); + if (result) return result; + } + } + }; + + CodeMirror.signal = function(o, name, e) { return o._signal(name, e) }; + CodeMirror.on = event.addListener; + CodeMirror.off = event.removeListener; + CodeMirror.isWordChar = function(ch) { + TextModeTokenRe.lastIndex = 0; + return TextModeTokenRe.test(ch); + }; + +(function() { + oop.implement(CodeMirror.prototype, EventEmitter); + + this.destroy = function() { + this.ace.off('change', this.onChange); + this.ace.off('changeSelection', this.onSelectionChange); + this.ace.off('beforeEndOperation', this.onBeforeEndOperation); + this.removeOverlay(); + }; + this.virtualSelectionMode = function() { + return this.ace.inVirtualSelectionMode && this.ace.selection.index; + }; + this.onChange = function(delta) { + if (delta.action[0] == 'i') { + var change = { text: delta.lines }; + var curOp = this.curOp = this.curOp || {}; + if (!curOp.changeHandlers) + curOp.changeHandlers = this._eventRegistry["change"] && this._eventRegistry["change"].slice(); + if (this.virtualSelectionMode()) return; + if (!curOp.lastChange) { + curOp.lastChange = curOp.change = change; + } else { + curOp.lastChange.next = curOp.lastChange = change; + } + } + this.$updateMarkers(delta); + }; + this.onSelectionChange = function() { + var curOp = this.curOp = this.curOp || {}; + if (!curOp.cursorActivityHandlers) + curOp.cursorActivityHandlers = this._eventRegistry["cursorActivity"] && this._eventRegistry["cursorActivity"].slice(); + this.curOp.cursorActivity = true; + if (this.ace.inMultiSelectMode) { + this.ace.keyBinding.removeKeyboardHandler(multiSelectCommands.keyboardHandler); + } + }; + this.operation = function(fn, force) { + if (!force && this.curOp || force && this.curOp && this.curOp.force) { + return fn(); + } + if (force || !this.ace.curOp) { + if (this.curOp) + this.onBeforeEndOperation(); + } + if (!this.ace.curOp) { + var prevOp = this.ace.prevOp; + this.ace.startOperation({ + command: { name: "vim", scrollIntoView: "cursor" } + }); + } + var curOp = this.curOp = this.curOp || {}; + this.curOp.force = force; + var result = fn(); + if (this.ace.curOp && this.ace.curOp.command.name == "vim") { + this.ace.endOperation(); + if (!curOp.cursorActivity && !curOp.lastChange && prevOp) + this.ace.prevOp = prevOp; + } + if (force || !this.ace.curOp) { + if (this.curOp) + this.onBeforeEndOperation(); + } + return result; + }; + this.onBeforeEndOperation = function() { + var op = this.curOp; + if (op) { + if (op.change) { this.signal("change", op.change, op); } + if (op && op.cursorActivity) { this.signal("cursorActivity", null, op); } + this.curOp = null; + } + }; + + this.signal = function(eventName, e, handlers) { + var listeners = handlers ? handlers[eventName + "Handlers"] + : (this._eventRegistry || {})[eventName]; + if (!listeners) + return; + listeners = listeners.slice(); + for (var i=0; i 0) { + point.row += rowShift; + point.column += point.row == end.row ? colShift : 0; + continue; + } + if (!isInsert && cmp2 <= 0) { + point.row = start.row; + point.column = start.column; + if (cmp2 === 0) + point.bias = 1; + } + } + }; + var Marker = function(cm, id, row, column) { + this.cm = cm; + this.id = id; + this.row = row; + this.column = column; + cm.marks[this.id] = this; + }; + Marker.prototype.clear = function() { delete this.cm.marks[this.id] }; + Marker.prototype.find = function() { return toCmPos(this) }; + this.setBookmark = function(cursor, options) { + var bm = new Marker(this, this.$uid++, cursor.line, cursor.ch); + if (!options || !options.insertLeft) + bm.$insertRight = true; + this.marks[bm.id] = bm; + return bm; + }; + this.moveH = function(increment, unit) { + if (unit == 'char') { + var sel = this.ace.selection; + sel.clearSelection(); + sel.moveCursorBy(0, increment); + } + }; + this.findPosV = function(start, amount, unit, goalColumn) { + if (unit == 'page') { + var renderer = this.ace.renderer; + var config = renderer.layerConfig; + amount = amount * Math.floor(config.height / config.lineHeight); + unit = 'line'; + } + if (unit == 'line') { + var screenPos = this.ace.session.documentToScreenPosition(start.line, start.ch); + if (goalColumn != null) + screenPos.column = goalColumn; + screenPos.row += amount; + // not what codemirror does but vim mode needs only this + screenPos.row = Math.min(Math.max(0, screenPos.row), this.ace.session.getScreenLength() - 1); + var pos = this.ace.session.screenToDocumentPosition(screenPos.row, screenPos.column); + return toCmPos(pos); + } else { + debugger; + } + }; + this.charCoords = function(pos, mode) { + if (mode == 'div' || !mode) { + var sc = this.ace.session.documentToScreenPosition(pos.line, pos.ch); + return {left: sc.column, top: sc.row}; + }if (mode == 'local') { + var renderer = this.ace.renderer; + var sc = this.ace.session.documentToScreenPosition(pos.line, pos.ch); + var lh = renderer.layerConfig.lineHeight; + var cw = renderer.layerConfig.characterWidth; + var top = lh * sc.row; + return {left: sc.column * cw, top: top, bottom: top + lh}; + } + }; + this.coordsChar = function(pos, mode) { + var renderer = this.ace.renderer; + if (mode == 'local') { + var row = Math.max(0, Math.floor(pos.top / renderer.lineHeight)); + var col = Math.max(0, Math.floor(pos.left / renderer.characterWidth)); + var ch = renderer.session.screenToDocumentPosition(row, col); + return toCmPos(ch); + } else if (mode == 'div') { + throw "not implemented"; + } + }; + this.getSearchCursor = function(query, pos, caseFold) { + var caseSensitive = false; + var isRegexp = false; + if (query instanceof RegExp && !query.global) { + caseSensitive = !query.ignoreCase; + query = query.source; + isRegexp = true; + } + var search = new Search(); + if (pos.ch == undefined) pos.ch = Number.MAX_VALUE; + var acePos = {row: pos.line, column: pos.ch}; + var cm = this; + var last = null; + return { + findNext: function() { return this.find(false) }, + findPrevious: function() {return this.find(true) }, + find: function(back) { + search.setOptions({ + needle: query, + caseSensitive: caseSensitive, + wrap: false, + backwards: back, + regExp: isRegexp, + start: last || acePos + }); + var range = search.find(cm.ace.session); + if (range && range.isEmpty()) { + if (cm.getLine(range.start.row).length == range.start.column) { + search.$options.start = range; + range = search.find(cm.ace.session); + } + } + last = range; + return last; + }, + from: function() { return last && toCmPos(last.start) }, + to: function() { return last && toCmPos(last.end) }, + replace: function(text) { + if (last) { + last.end = cm.ace.session.doc.replace(last, text); + } + } + }; + }; + this.scrollTo = function(x, y) { + var renderer = this.ace.renderer; + var config = renderer.layerConfig; + var maxHeight = config.maxHeight; + maxHeight -= (renderer.$size.scrollerHeight - renderer.lineHeight) * renderer.$scrollPastEnd; + if (y != null) this.ace.session.setScrollTop(Math.max(0, Math.min(y, maxHeight))); + if (x != null) this.ace.session.setScrollLeft(Math.max(0, Math.min(x, config.width))); + }; + this.scrollInfo = function() { return 0; }; + this.scrollIntoView = function(pos, margin) { + if (pos) { + var renderer = this.ace.renderer; + var acePos = toAcePos(pos); + renderer.session.unfold(acePos); + renderer.session.selection.moveToPosition(acePos); + renderer.scrollCursorIntoView(acePos, 0.5, { + top: margin, + bottom: margin + }); + if (this.ace.curOp) + this.ace.curOp.command.scrollIntoView = "animate"; + } + }; + this.getLine = function(row) { return this.ace.session.getLine(row) }; + this.getRange = function(s, e) { + return this.ace.session.getTextRange(new Range(s.line, s.ch, e.line, e.ch)); + }; + this.replaceRange = function(text, s, e) { + if (!e) e = s; + return this.ace.session.replace(new Range(s.line, s.ch, e.line, e.ch), text); + }; + this.replaceSelections = function(p) { + var sel = this.ace.selection; + if (this.ace.inVirtualSelectionMode) { + this.ace.session.replace(sel.getRange(), p[0] || ""); + return; + } + sel.inVirtualSelectionMode = true; + var ranges = sel.rangeList.ranges; + if (!ranges.length) ranges = [this.ace.multiSelect.getRange()]; + for (var i = ranges.length; i--;) + this.ace.session.replace(ranges[i], p[i] || ""); + sel.inVirtualSelectionMode = false; + }; + this.getSelection = function() { + return this.ace.getSelectedText(); + }; + this.getSelections = function() { + return this.listSelections().map(function(x) { + return this.getRange(x.anchor, x.head); + }, this); + }; + this.getInputField = function() { + return this.ace.textInput.getElement(); + }; + this.getWrapperElement = function() { + return this.ace.containter; + }; + var optMap = { + indentWithTabs: "useSoftTabs", + indentUnit: "tabSize", + firstLineNumber: "firstLineNumber" + }; + this.setOption = function(name, val) { + this.state[name] = val; + switch (name) { + case 'indentWithTabs': + name = optMap[name]; + val = !val; + break; + default: + name = optMap[name]; + } + if (name) + this.ace.setOption(name, val); + }; + this.getOption = function(name, val) { + var aceOpt = optMap[name]; + if (aceOpt) + val = this.ace.getOption(aceOpt); + switch (name) { + case 'indentWithTabs': + name = optMap[name]; + return !val; + } + return aceOpt ? val : this.state[name]; + }; + this.toggleOverwrite = function(on) { + this.state.overwrite = on; + return this.ace.setOverwrite(on); + }; + this.addOverlay = function(o) { + if (!this.$searchHighlight || !this.$searchHighlight.session) { + var highlight = new SearchHighlight(null, "ace_highlight-marker", "text"); + var marker = this.ace.session.addDynamicMarker(highlight); + highlight.id = marker.id; + highlight.session = this.ace.session; + highlight.destroy = function(o) { + highlight.session.off("change", highlight.updateOnChange); + highlight.session.off("changeEditor", highlight.destroy); + highlight.session.removeMarker(highlight.id); + highlight.session = null; + }; + highlight.updateOnChange = function(delta) { + var row = delta.start.row; + if (row == delta.end.row) highlight.cache[row] = undefined; + else highlight.cache.splice(row, highlight.cache.length); + }; + highlight.session.on("changeEditor", highlight.destroy); + highlight.session.on("change", highlight.updateOnChange); + } + var re = new RegExp(o.query.source, "gm" + (o.query.ignoreCase ? "i" : "")); + this.$searchHighlight = o.highlight = highlight; + this.$searchHighlight.setRegexp(re); + this.ace.renderer.updateBackMarkers(); + }; + this.removeOverlay = function(o) { + if (this.$searchHighlight && this.$searchHighlight.session) { + this.$searchHighlight.destroy(); + } + }; + this.getScrollInfo = function() { + var renderer = this.ace.renderer; + var config = renderer.layerConfig; + return { + left: renderer.scrollLeft, + top: renderer.scrollTop, + height: config.maxHeight, + width: config.width, + clientHeight: config.height, + clientWidth: config.width + }; + }; + this.getValue = function() { + return this.ace.getValue(); + }; + this.setValue = function(v) { + return this.ace.setValue(v); + }; + this.getTokenTypeAt = function(pos) { + var token = this.ace.session.getTokenAt(pos.line, pos.ch); + return token && /comment|string/.test(token.type) ? "string" : ""; + }; + this.findMatchingBracket = function(pos) { + var m = this.ace.session.findMatchingBracket(toAcePos(pos)); + return {to: m && toCmPos(m)}; + }; + this.indentLine = function(line, method) { + if (method === true) + this.ace.session.indentRows(line, line, "\t"); + else if (method === false) + this.ace.session.outdentRows(new Range(line, 0, line, 0)); + }; + this.indexFromPos = function(pos) { + return this.ace.session.doc.positionToIndex(toAcePos(pos)); + }; + this.posFromIndex = function(index) { + return toCmPos(this.ace.session.doc.indexToPosition(index)); + }; + this.focus = function(index) { + return this.ace.focus(); + }; + this.blur = function(index) { + return this.ace.blur(); + }; + this.defaultTextHeight = function(index) { + return this.ace.renderer.layerConfig.lineHeight; + }; + this.scanForBracket = function(pos, dir, _, options) { + var re = options.bracketRegex.source; + if (dir == 1) { + var m = this.ace.session.$findClosingBracket(re.slice(1, 2), toAcePos(pos), /paren|text/); + } else { + var m = this.ace.session.$findOpeningBracket(re.slice(-2, -1), {row: pos.line, column: pos.ch + 1}, /paren|text/); + } + return m && {pos: toCmPos(m)}; + }; + this.refresh = function() { + return this.ace.resize(true); + }; +}).call(CodeMirror.prototype); + function toAcePos(cmPos) { + return {row: cmPos.line, column: cmPos.ch}; + } + function toCmPos(acePos) { + return new Pos(acePos.row, acePos.column); + } + + var StringStream = CodeMirror.StringStream = function(string, tabSize) { + this.pos = this.start = 0; + this.string = string; + this.tabSize = tabSize || 8; + this.lastColumnPos = this.lastColumnValue = 0; + this.lineStart = 0; + }; + + StringStream.prototype = { + eol: function() {return this.pos >= this.string.length;}, + sol: function() {return this.pos == this.lineStart;}, + peek: function() {return this.string.charAt(this.pos) || undefined;}, + next: function() { + if (this.pos < this.string.length) + return this.string.charAt(this.pos++); + }, + eat: function(match) { + var ch = this.string.charAt(this.pos); + if (typeof match == "string") var ok = ch == match; + else var ok = ch && (match.test ? match.test(ch) : match(ch)); + if (ok) {++this.pos; return ch;} + }, + eatWhile: function(match) { + var start = this.pos; + while (this.eat(match)){} + return this.pos > start; + }, + eatSpace: function() { + var start = this.pos; + while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos; + return this.pos > start; + }, + skipToEnd: function() {this.pos = this.string.length;}, + skipTo: function(ch) { + var found = this.string.indexOf(ch, this.pos); + if (found > -1) {this.pos = found; return true;} + }, + backUp: function(n) {this.pos -= n;}, + column: function() { + throw "not implemented"; + }, + indentation: function() { + throw "not implemented"; + }, + match: function(pattern, consume, caseInsensitive) { + if (typeof pattern == "string") { + var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;}; + var substr = this.string.substr(this.pos, pattern.length); + if (cased(substr) == cased(pattern)) { + if (consume !== false) this.pos += pattern.length; + return true; + } + } else { + var match = this.string.slice(this.pos).match(pattern); + if (match && match.index > 0) return null; + if (match && consume !== false) this.pos += match[0].length; + return match; + } + }, + current: function(){return this.string.slice(this.start, this.pos);}, + hideFirstChars: function(n, inner) { + this.lineStart += n; + try { return inner(); } + finally { this.lineStart -= n; } + } + }; + +// todo replace with showCommandLine +CodeMirror.defineExtension = function(name, fn) { + CodeMirror.prototype[name] = fn; +}; +dom.importCssString(".normal-mode .ace_cursor{\ + border: 0!important;\ + background-color: red;\ + opacity: 0.5;\ +}.ace_dialog {\ + position: absolute;\ + left: 0; right: 0;\ + background: white;\ + z-index: 15;\ + padding: .1em .8em;\ + overflow: hidden;\ + color: #333;\ +}\ +.ace_dialog-top {\ + border-bottom: 1px solid #eee;\ + top: 0;\ +}\ +.ace_dialog-bottom {\ + border-top: 1px solid #eee;\ + bottom: 0;\ +}\ +.ace_dialog input {\ + border: none;\ + outline: none;\ + background: transparent;\ + width: 20em;\ + color: inherit;\ + font-family: monospace;\ +}", "vimMode"); +(function() { + function dialogDiv(cm, template, bottom) { + var wrap = cm.ace.container; + var dialog; + dialog = wrap.appendChild(document.createElement("div")); + if (bottom) + dialog.className = "ace_dialog ace_dialog-bottom"; + else + dialog.className = "ace_dialog ace_dialog-top"; + + if (typeof template == "string") { + dialog.innerHTML = template; + } else { // Assuming it's a detached DOM element. + dialog.appendChild(template); + } + return dialog; + } + + function closeNotification(cm, newVal) { + if (cm.state.currentNotificationClose) + cm.state.currentNotificationClose(); + cm.state.currentNotificationClose = newVal; + } + + CodeMirror.defineExtension("openDialog", function(template, callback, options) { + if (this.virtualSelectionMode()) return; + if (!options) options = {}; + + closeNotification(this, null); + + if (!options.onKeyDown && !options.onKeyUp) { + return this.openNotification(template, {}); + } + + var closed = false, me = this; + function close(newVal) { + if (typeof newVal == 'string') { + ace.cmdLine.setValue(prefix + newVal, 1); + } else { + if (closed) return; + closed = true; + me.focus(); + + CodeMirror.off(inp, "keyup", onKeyup); + ace.cmdLine.container.removeEventListener("keydown", onKeyDown, true); + CodeMirror.off(inp, "blur", onBlur); + + ace.cmdLine.setValue(""); + } + } + + var ace = this.ace; + var cm = this; + var prefix = template; + if (prefix == ":") + return; + ace.showCommandLine(prefix, { + focus: true + }); + + if (options.value) { + var start = ace.cmdLine.getCursorPosition(); + var end = ace.cmdLine.session.insert(options.value); + ace.cmdLine.selection.setRange(Range.fromPoints(start, end)); + } + + function getVal() { + return ace.cmdLine.getValue().substring(prefix.length); + } + var inp = ace.cmdLine.textInput.getElement(); + var onKeyup = function(e) { + cm.operation(function() { + options.onKeyUp(e, getVal(), close); + if (!ace.cmdLine.getValue()) + close(); + }); + }; + var onKeyDown = function(e) { + cm.operation(function() { + var val = getVal(); + if (options && options.onKeyDown && options.onKeyDown(e, val, close)) { return; } + if (e.keyCode == 27 || (options.closeOnEnter !== false && e.keyCode == 13)) { + CodeMirror.e_stop(e); + close(); + } + if (e.keyCode == 13) callback(val); + }); + }; + var onBlur = close; + if (options.onKeyUp) + CodeMirror.on(inp, "keyup", onKeyup); + ace.cmdLine.container.addEventListener("keydown", onKeyDown, true); + if (options.closeOnBlur !== false) + CodeMirror.on(inp, "blur", onBlur); + + + return close; + }); + + CodeMirror.defineExtension("openNotification", function(template, options) { + if (this.virtualSelectionMode()) return; + closeNotification(this, close); + var ace = this.ace; + ace.showCommandLine(undefined, { + timeout: options.duration, + message: template.replace(/<[^>]+>/g, ""), + focus: false + }); + var closed = false; + + function close() { + if (closed || !ace.cmdLine) return; + closed = true; + ace.cmdLine.setMessage(""); + } + return close; + }); +})(); + + + var defaultKeymap = [ + // Key to key mapping. This goes first to make it possible to override + // existing mappings. + { keys: '', type: 'keyToKey', toKeys: 'h' }, + { keys: '', type: 'keyToKey', toKeys: 'l' }, + { keys: '', type: 'keyToKey', toKeys: 'k' }, + { keys: '', type: 'keyToKey', toKeys: 'j' }, + { keys: '', type: 'keyToKey', toKeys: 'l' }, + { keys: '', type: 'keyToKey', toKeys: 'h', context: 'normal'}, + { keys: '', type: 'keyToKey', toKeys: 'W' }, + { keys: '', type: 'keyToKey', toKeys: 'B', context: 'normal' }, + { keys: '', type: 'keyToKey', toKeys: 'w' }, + { keys: '', type: 'keyToKey', toKeys: 'b', context: 'normal' }, + { keys: '', type: 'keyToKey', toKeys: 'j' }, + { keys: '', type: 'keyToKey', toKeys: 'k' }, + { keys: '', type: 'keyToKey', toKeys: '' }, + { keys: '', type: 'keyToKey', toKeys: '' }, + { keys: '', type: 'keyToKey', toKeys: '', context: 'insert' }, + { keys: '', type: 'keyToKey', toKeys: '', context: 'insert' }, + { keys: 's', type: 'keyToKey', toKeys: 'cl', context: 'normal' }, + { keys: 's', type: 'keyToKey', toKeys: 'xi', context: 'visual'}, + { keys: 'S', type: 'keyToKey', toKeys: 'cc', context: 'normal' }, + { keys: 'S', type: 'keyToKey', toKeys: 'dcc', context: 'visual' }, + { keys: '', type: 'keyToKey', toKeys: '0' }, + { keys: '', type: 'keyToKey', toKeys: '$' }, + { keys: '', type: 'keyToKey', toKeys: '' }, + { keys: '', type: 'keyToKey', toKeys: '' }, + { keys: '', type: 'keyToKey', toKeys: 'j^', context: 'normal' }, + // Motions + { keys: 'H', type: 'motion', motion: 'moveToTopLine', motionArgs: { linewise: true, toJumplist: true }}, + { keys: 'M', type: 'motion', motion: 'moveToMiddleLine', motionArgs: { linewise: true, toJumplist: true }}, + { keys: 'L', type: 'motion', motion: 'moveToBottomLine', motionArgs: { linewise: true, toJumplist: true }}, + { keys: 'h', type: 'motion', motion: 'moveByCharacters', motionArgs: { forward: false }}, + { keys: 'l', type: 'motion', motion: 'moveByCharacters', motionArgs: { forward: true }}, + { keys: 'j', type: 'motion', motion: 'moveByLines', motionArgs: { forward: true, linewise: true }}, + { keys: 'k', type: 'motion', motion: 'moveByLines', motionArgs: { forward: false, linewise: true }}, + { keys: 'gj', type: 'motion', motion: 'moveByDisplayLines', motionArgs: { forward: true }}, + { keys: 'gk', type: 'motion', motion: 'moveByDisplayLines', motionArgs: { forward: false }}, + { keys: 'w', type: 'motion', motion: 'moveByWords', motionArgs: { forward: true, wordEnd: false }}, + { keys: 'W', type: 'motion', motion: 'moveByWords', motionArgs: { forward: true, wordEnd: false, bigWord: true }}, + { keys: 'e', type: 'motion', motion: 'moveByWords', motionArgs: { forward: true, wordEnd: true, inclusive: true }}, + { keys: 'E', type: 'motion', motion: 'moveByWords', motionArgs: { forward: true, wordEnd: true, bigWord: true, inclusive: true }}, + { keys: 'b', type: 'motion', motion: 'moveByWords', motionArgs: { forward: false, wordEnd: false }}, + { keys: 'B', type: 'motion', motion: 'moveByWords', motionArgs: { forward: false, wordEnd: false, bigWord: true }}, + { keys: 'ge', type: 'motion', motion: 'moveByWords', motionArgs: { forward: false, wordEnd: true, inclusive: true }}, + { keys: 'gE', type: 'motion', motion: 'moveByWords', motionArgs: { forward: false, wordEnd: true, bigWord: true, inclusive: true }}, + { keys: '{', type: 'motion', motion: 'moveByParagraph', motionArgs: { forward: false, toJumplist: true }}, + { keys: '}', type: 'motion', motion: 'moveByParagraph', motionArgs: { forward: true, toJumplist: true }}, + { keys: '', type: 'motion', motion: 'moveByPage', motionArgs: { forward: true }}, + { keys: '', type: 'motion', motion: 'moveByPage', motionArgs: { forward: false }}, + { keys: '', type: 'motion', motion: 'moveByScroll', motionArgs: { forward: true, explicitRepeat: true }}, + { keys: '', type: 'motion', motion: 'moveByScroll', motionArgs: { forward: false, explicitRepeat: true }}, + { keys: 'gg', type: 'motion', motion: 'moveToLineOrEdgeOfDocument', motionArgs: { forward: false, explicitRepeat: true, linewise: true, toJumplist: true }}, + { keys: 'G', type: 'motion', motion: 'moveToLineOrEdgeOfDocument', motionArgs: { forward: true, explicitRepeat: true, linewise: true, toJumplist: true }}, + { keys: '0', type: 'motion', motion: 'moveToStartOfLine' }, + { keys: '^', type: 'motion', motion: 'moveToFirstNonWhiteSpaceCharacter' }, + { keys: '+', type: 'motion', motion: 'moveByLines', motionArgs: { forward: true, toFirstChar:true }}, + { keys: '-', type: 'motion', motion: 'moveByLines', motionArgs: { forward: false, toFirstChar:true }}, + { keys: '_', type: 'motion', motion: 'moveByLines', motionArgs: { forward: true, toFirstChar:true, repeatOffset:-1 }}, + { keys: '$', type: 'motion', motion: 'moveToEol', motionArgs: { inclusive: true }}, + { keys: '%', type: 'motion', motion: 'moveToMatchedSymbol', motionArgs: { inclusive: true, toJumplist: true }}, + { keys: 'f', type: 'motion', motion: 'moveToCharacter', motionArgs: { forward: true , inclusive: true }}, + { keys: 'F', type: 'motion', motion: 'moveToCharacter', motionArgs: { forward: false }}, + { keys: 't', type: 'motion', motion: 'moveTillCharacter', motionArgs: { forward: true, inclusive: true }}, + { keys: 'T', type: 'motion', motion: 'moveTillCharacter', motionArgs: { forward: false }}, + { keys: ';', type: 'motion', motion: 'repeatLastCharacterSearch', motionArgs: { forward: true }}, + { keys: ',', type: 'motion', motion: 'repeatLastCharacterSearch', motionArgs: { forward: false }}, + { keys: '\'', type: 'motion', motion: 'goToMark', motionArgs: {toJumplist: true, linewise: true}}, + { keys: '`', type: 'motion', motion: 'goToMark', motionArgs: {toJumplist: true}}, + { keys: ']`', type: 'motion', motion: 'jumpToMark', motionArgs: { forward: true } }, + { keys: '[`', type: 'motion', motion: 'jumpToMark', motionArgs: { forward: false } }, + { keys: ']\'', type: 'motion', motion: 'jumpToMark', motionArgs: { forward: true, linewise: true } }, + { keys: '[\'', type: 'motion', motion: 'jumpToMark', motionArgs: { forward: false, linewise: true } }, + // the next two aren't motions but must come before more general motion declarations + { keys: ']p', type: 'action', action: 'paste', isEdit: true, actionArgs: { after: true, isEdit: true, matchIndent: true}}, + { keys: '[p', type: 'action', action: 'paste', isEdit: true, actionArgs: { after: false, isEdit: true, matchIndent: true}}, + { keys: ']', type: 'motion', motion: 'moveToSymbol', motionArgs: { forward: true, toJumplist: true}}, + { keys: '[', type: 'motion', motion: 'moveToSymbol', motionArgs: { forward: false, toJumplist: true}}, + { keys: '|', type: 'motion', motion: 'moveToColumn'}, + { keys: 'o', type: 'motion', motion: 'moveToOtherHighlightedEnd', context:'visual'}, + { keys: 'O', type: 'motion', motion: 'moveToOtherHighlightedEnd', motionArgs: {sameLine: true}, context:'visual'}, + // Operators + { keys: 'd', type: 'operator', operator: 'delete' }, + { keys: 'y', type: 'operator', operator: 'yank' }, + { keys: 'c', type: 'operator', operator: 'change' }, + { keys: '>', type: 'operator', operator: 'indent', operatorArgs: { indentRight: true }}, + { keys: '<', type: 'operator', operator: 'indent', operatorArgs: { indentRight: false }}, + { keys: 'g~', type: 'operator', operator: 'changeCase' }, + { keys: 'gu', type: 'operator', operator: 'changeCase', operatorArgs: {toLower: true}, isEdit: true }, + { keys: 'gU', type: 'operator', operator: 'changeCase', operatorArgs: {toLower: false}, isEdit: true }, + { keys: 'n', type: 'motion', motion: 'findNext', motionArgs: { forward: true, toJumplist: true }}, + { keys: 'N', type: 'motion', motion: 'findNext', motionArgs: { forward: false, toJumplist: true }}, + // Operator-Motion dual commands + { keys: 'x', type: 'operatorMotion', operator: 'delete', motion: 'moveByCharacters', motionArgs: { forward: true }, operatorMotionArgs: { visualLine: false }}, + { keys: 'X', type: 'operatorMotion', operator: 'delete', motion: 'moveByCharacters', motionArgs: { forward: false }, operatorMotionArgs: { visualLine: true }}, + { keys: 'D', type: 'operatorMotion', operator: 'delete', motion: 'moveToEol', motionArgs: { inclusive: true }, context: 'normal'}, + { keys: 'D', type: 'operator', operator: 'delete', operatorArgs: { linewise: true }, context: 'visual'}, + { keys: 'Y', type: 'operatorMotion', operator: 'yank', motion: 'moveToEol', motionArgs: { inclusive: true }, context: 'normal'}, + { keys: 'Y', type: 'operator', operator: 'yank', operatorArgs: { linewise: true }, context: 'visual'}, + { keys: 'C', type: 'operatorMotion', operator: 'change', motion: 'moveToEol', motionArgs: { inclusive: true }, context: 'normal'}, + { keys: 'C', type: 'operator', operator: 'change', operatorArgs: { linewise: true }, context: 'visual'}, + { keys: '~', type: 'operatorMotion', operator: 'changeCase', motion: 'moveByCharacters', motionArgs: { forward: true }, operatorArgs: { shouldMoveCursor: true }, context: 'normal'}, + { keys: '~', type: 'operator', operator: 'changeCase', context: 'visual'}, + { keys: '', type: 'operatorMotion', operator: 'delete', motion: 'moveByWords', motionArgs: { forward: false, wordEnd: false }, context: 'insert' }, + // Actions + { keys: '', type: 'action', action: 'jumpListWalk', actionArgs: { forward: true }}, + { keys: '', type: 'action', action: 'jumpListWalk', actionArgs: { forward: false }}, + { keys: '', type: 'action', action: 'scroll', actionArgs: { forward: true, linewise: true }}, + { keys: '', type: 'action', action: 'scroll', actionArgs: { forward: false, linewise: true }}, + { keys: 'a', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'charAfter' }, context: 'normal' }, + { keys: 'A', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'eol' }, context: 'normal' }, + { keys: 'A', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'endOfSelectedArea' }, context: 'visual' }, + { keys: 'i', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'inplace' }, context: 'normal' }, + { keys: 'I', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'firstNonBlank'}, context: 'normal' }, + { keys: 'I', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'startOfSelectedArea' }, context: 'visual' }, + { keys: 'o', type: 'action', action: 'newLineAndEnterInsertMode', isEdit: true, interlaceInsertRepeat: true, actionArgs: { after: true }, context: 'normal' }, + { keys: 'O', type: 'action', action: 'newLineAndEnterInsertMode', isEdit: true, interlaceInsertRepeat: true, actionArgs: { after: false }, context: 'normal' }, + { keys: 'v', type: 'action', action: 'toggleVisualMode' }, + { keys: 'V', type: 'action', action: 'toggleVisualMode', actionArgs: { linewise: true }}, + { keys: '', type: 'action', action: 'toggleVisualMode', actionArgs: { blockwise: true }}, + { keys: 'gv', type: 'action', action: 'reselectLastSelection' }, + { keys: 'J', type: 'action', action: 'joinLines', isEdit: true }, + { keys: 'p', type: 'action', action: 'paste', isEdit: true, actionArgs: { after: true, isEdit: true }}, + { keys: 'P', type: 'action', action: 'paste', isEdit: true, actionArgs: { after: false, isEdit: true }}, + { keys: 'r', type: 'action', action: 'replace', isEdit: true }, + { keys: '@', type: 'action', action: 'replayMacro' }, + { keys: 'q', type: 'action', action: 'enterMacroRecordMode' }, + // Handle Replace-mode as a special case of insert mode. + { keys: 'R', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { replace: true }}, + { keys: 'u', type: 'action', action: 'undo', context: 'normal' }, + { keys: 'u', type: 'operator', operator: 'changeCase', operatorArgs: {toLower: true}, context: 'visual', isEdit: true }, + { keys: 'U', type: 'operator', operator: 'changeCase', operatorArgs: {toLower: false}, context: 'visual', isEdit: true }, + { keys: '', type: 'action', action: 'redo' }, + { keys: 'm', type: 'action', action: 'setMark' }, + { keys: '"', type: 'action', action: 'setRegister' }, + { keys: 'zz', type: 'action', action: 'scrollToCursor', actionArgs: { position: 'center' }}, + { keys: 'z.', type: 'action', action: 'scrollToCursor', actionArgs: { position: 'center' }, motion: 'moveToFirstNonWhiteSpaceCharacter' }, + { keys: 'zt', type: 'action', action: 'scrollToCursor', actionArgs: { position: 'top' }}, + { keys: 'z', type: 'action', action: 'scrollToCursor', actionArgs: { position: 'top' }, motion: 'moveToFirstNonWhiteSpaceCharacter' }, + { keys: 'z-', type: 'action', action: 'scrollToCursor', actionArgs: { position: 'bottom' }}, + { keys: 'zb', type: 'action', action: 'scrollToCursor', actionArgs: { position: 'bottom' }, motion: 'moveToFirstNonWhiteSpaceCharacter' }, + { keys: '.', type: 'action', action: 'repeatLastEdit' }, + { keys: '', type: 'action', action: 'incrementNumberToken', isEdit: true, actionArgs: {increase: true, backtrack: false}}, + { keys: '', type: 'action', action: 'incrementNumberToken', isEdit: true, actionArgs: {increase: false, backtrack: false}}, + // Text object motions + { keys: 'a', type: 'motion', motion: 'textObjectManipulation' }, + { keys: 'i', type: 'motion', motion: 'textObjectManipulation', motionArgs: { textObjectInner: true }}, + // Search + { keys: '/', type: 'search', searchArgs: { forward: true, querySrc: 'prompt', toJumplist: true }}, + { keys: '?', type: 'search', searchArgs: { forward: false, querySrc: 'prompt', toJumplist: true }}, + { keys: '*', type: 'search', searchArgs: { forward: true, querySrc: 'wordUnderCursor', wholeWordOnly: true, toJumplist: true }}, + { keys: '#', type: 'search', searchArgs: { forward: false, querySrc: 'wordUnderCursor', wholeWordOnly: true, toJumplist: true }}, + { keys: 'g*', type: 'search', searchArgs: { forward: true, querySrc: 'wordUnderCursor', toJumplist: true }}, + { keys: 'g#', type: 'search', searchArgs: { forward: false, querySrc: 'wordUnderCursor', toJumplist: true }}, + // Ex command + { keys: ':', type: 'ex' } + ]; + + var Pos = CodeMirror.Pos; + + var Vim = function() { return vimApi; } //{ + function enterVimMode(cm) { + cm.setOption('disableInput', true); + cm.setOption('showCursorWhenSelecting', false); + CodeMirror.signal(cm, "vim-mode-change", {mode: "normal"}); + cm.on('cursorActivity', onCursorActivity); + maybeInitVimState(cm); + CodeMirror.on(cm.getInputField(), 'paste', getOnPasteFn(cm)); + } + + function leaveVimMode(cm) { + cm.setOption('disableInput', false); + cm.off('cursorActivity', onCursorActivity); + CodeMirror.off(cm.getInputField(), 'paste', getOnPasteFn(cm)); + cm.state.vim = null; + } + + function detachVimMap(cm, next) { + if (this == CodeMirror.keyMap.vim) + CodeMirror.rmClass(cm.getWrapperElement(), "cm-fat-cursor"); + + if (!next || next.attach != attachVimMap) + leaveVimMode(cm, false); + } + function attachVimMap(cm, prev) { + if (this == CodeMirror.keyMap.vim) + CodeMirror.addClass(cm.getWrapperElement(), "cm-fat-cursor"); + + if (!prev || prev.attach != attachVimMap) + enterVimMode(cm); + } + + // Deprecated, simply setting the keymap works again. + CodeMirror.defineOption('vimMode', false, function(cm, val, prev) { + if (val && cm.getOption("keyMap") != "vim") + cm.setOption("keyMap", "vim"); + else if (!val && prev != CodeMirror.Init && /^vim/.test(cm.getOption("keyMap"))) + cm.setOption("keyMap", "default"); + }); + + function cmKey(key, cm) { + if (!cm) { return undefined; } + var vimKey = cmKeyToVimKey(key); + if (!vimKey) { + return false; + } + var cmd = CodeMirror.Vim.findKey(cm, vimKey); + if (typeof cmd == 'function') { + CodeMirror.signal(cm, 'vim-keypress', vimKey); + } + return cmd; + } + + var modifiers = {'Shift': 'S', 'Ctrl': 'C', 'Alt': 'A', 'Cmd': 'D', 'Mod': 'A'}; + var specialKeys = {Enter:'CR',Backspace:'BS',Delete:'Del'}; + function cmKeyToVimKey(key) { + if (key.charAt(0) == '\'') { + // Keypress character binding of format "'a'" + return key.charAt(1); + } + var pieces = key.split('-'); + if (/-$/.test(key)) { + // If the - key was typed, split will result in 2 extra empty strings + // in the array. Replace them with 1 '-'. + pieces.splice(-2, 2, '-'); + } + var lastPiece = pieces[pieces.length - 1]; + if (pieces.length == 1 && pieces[0].length == 1) { + // No-modifier bindings use literal character bindings above. Skip. + return false; + } else if (pieces.length == 2 && pieces[0] == 'Shift' && lastPiece.length == 1) { + // Ignore Shift+char bindings as they should be handled by literal character. + return false; + } + var hasCharacter = false; + for (var i = 0; i < pieces.length; i++) { + var piece = pieces[i]; + if (piece in modifiers) { pieces[i] = modifiers[piece]; } + else { hasCharacter = true; } + if (piece in specialKeys) { pieces[i] = specialKeys[piece]; } + } + if (!hasCharacter) { + // Vim does not support modifier only keys. + return false; + } + // TODO: Current bindings expect the character to be lower case, but + // it looks like vim key notation uses upper case. + if (isUpperCase(lastPiece)) { + pieces[pieces.length - 1] = lastPiece.toLowerCase(); + } + return '<' + pieces.join('-') + '>'; + } + + function getOnPasteFn(cm) { + var vim = cm.state.vim; + if (!vim.onPasteFn) { + vim.onPasteFn = function() { + if (!vim.insertMode) { + cm.setCursor(offsetCursor(cm.getCursor(), 0, 1)); + actions.enterInsertMode(cm, {}, vim); + } + }; + } + return vim.onPasteFn; + } + + var numberRegex = /[\d]/; + var wordRegexp = [{test: CodeMirror.isWordChar}, {test: function(ch) { + return !CodeMirror.isWordChar(ch) && !/\s/.test(ch); + }}], bigWordRegexp = [(/\S/)]; + function makeKeyRange(start, size) { + var keys = []; + for (var i = start; i < start + size; i++) { + keys.push(String.fromCharCode(i)); + } + return keys; + } + var upperCaseAlphabet = makeKeyRange(65, 26); + var lowerCaseAlphabet = makeKeyRange(97, 26); + var numbers = makeKeyRange(48, 10); + var validMarks = [].concat(upperCaseAlphabet, lowerCaseAlphabet, numbers, ['<', '>']); + var validRegisters = [].concat(upperCaseAlphabet, lowerCaseAlphabet, numbers, ['-', '"', '.', ':', '/']); + + function isLine(cm, line) { + return line >= cm.firstLine() && line <= cm.lastLine(); + } + function isLowerCase(k) { + return (/^[a-z]$/).test(k); + } + function isMatchableSymbol(k) { + return '()[]{}'.indexOf(k) != -1; + } + function isNumber(k) { + return numberRegex.test(k); + } + function isUpperCase(k) { + return (/^[A-Z]$/).test(k); + } + function isWhiteSpaceString(k) { + return (/^\s*$/).test(k); + } + function inArray(val, arr) { + for (var i = 0; i < arr.length; i++) { + if (arr[i] == val) { + return true; + } + } + return false; + } + + var options = {}; + function defineOption(name, defaultValue, type) { + if (defaultValue === undefined) { throw Error('defaultValue is required'); } + if (!type) { type = 'string'; } + var opt = name; + if (typeof name == "string") + opt = { + type: type, + defaultValue: defaultValue + }; + else + name = opt.name; + options[name] = opt; + setOption(name, defaultValue); + } + + function setOption(name, value, cm) { + var option = options[name]; + if (!option) { + throw Error('Unknown option: ' + name); + } + if (option.type == 'boolean') { + if (value && value !== true) { + throw Error('Invalid argument: ' + name + '=' + value); + } else if (value !== false) { + // Boolean options are set to true if value is not defined. + value = true; + } + } + option.value = value; + if (option.set) option.set(value, cm); + } + + function getOption(name) { + var option = options[name]; + if (!option) { + throw Error('Unknown option: ' + name); + } + return option.value; + } + + var createCircularJumpList = function() { + var size = 100; + var pointer = -1; + var head = 0; + var tail = 0; + var buffer = new Array(size); + function add(cm, oldCur, newCur) { + var current = pointer % size; + var curMark = buffer[current]; + function useNextSlot(cursor) { + var next = ++pointer % size; + var trashMark = buffer[next]; + if (trashMark) { + trashMark.clear(); + } + buffer[next] = cm.setBookmark(cursor); + } + if (curMark) { + var markPos = curMark.find(); + // avoid recording redundant cursor position + if (markPos && !cursorEqual(markPos, oldCur)) { + useNextSlot(oldCur); + } + } else { + useNextSlot(oldCur); + } + useNextSlot(newCur); + head = pointer; + tail = pointer - size + 1; + if (tail < 0) { + tail = 0; + } + } + function move(cm, offset) { + pointer += offset; + if (pointer > head) { + pointer = head; + } else if (pointer < tail) { + pointer = tail; + } + var mark = buffer[(size + pointer) % size]; + // skip marks that are temporarily removed from text buffer + if (mark && !mark.find()) { + var inc = offset > 0 ? 1 : -1; + var newCur; + var oldCur = cm.getCursor(); + do { + pointer += inc; + mark = buffer[(size + pointer) % size]; + // skip marks that are the same as current position + if (mark && + (newCur = mark.find()) && + !cursorEqual(oldCur, newCur)) { + break; + } + } while (pointer < head && pointer > tail); + } + return mark; + } + return { + cachedCursor: undefined, //used for # and * jumps + add: add, + move: move + }; + }; + + // Returns an object to track the changes associated insert mode. It + // clones the object that is passed in, or creates an empty object one if + // none is provided. + var createInsertModeChanges = function(c) { + if (c) { + // Copy construction + return { + changes: c.changes, + expectCursorActivityForChange: c.expectCursorActivityForChange + }; + } + return { + // Change list + changes: [], + // Set to true on change, false on cursorActivity. + expectCursorActivityForChange: false + }; + }; + + function MacroModeState() { + this.latestRegister = undefined; + this.isPlaying = false; + this.isRecording = false; + this.replaySearchQueries = []; + this.onRecordingDone = undefined; + this.lastInsertModeChanges = createInsertModeChanges(); + } + MacroModeState.prototype = { + exitMacroRecordMode: function() { + var macroModeState = vimGlobalState.macroModeState; + if (macroModeState.onRecordingDone) { + macroModeState.onRecordingDone(); // close dialog + } + macroModeState.onRecordingDone = undefined; + macroModeState.isRecording = false; + }, + enterMacroRecordMode: function(cm, registerName) { + var register = + vimGlobalState.registerController.getRegister(registerName); + if (register) { + register.clear(); + this.latestRegister = registerName; + if (cm.openDialog) { + this.onRecordingDone = cm.openDialog( + '(recording)['+registerName+']', null, {bottom:true}); + } + this.isRecording = true; + } + } + }; + + function maybeInitVimState(cm) { + if (!cm.state.vim) { + // Store instance state in the CodeMirror object. + cm.state.vim = { + inputState: new InputState(), + // Vim's input state that triggered the last edit, used to repeat + // motions and operators with '.'. + lastEditInputState: undefined, + // Vim's action command before the last edit, used to repeat actions + // with '.' and insert mode repeat. + lastEditActionCommand: undefined, + // When using jk for navigation, if you move from a longer line to a + // shorter line, the cursor may clip to the end of the shorter line. + // If j is pressed again and cursor goes to the next line, the + // cursor should go back to its horizontal position on the longer + // line if it can. This is to keep track of the horizontal position. + lastHPos: -1, + // Doing the same with screen-position for gj/gk + lastHSPos: -1, + // The last motion command run. Cleared if a non-motion command gets + // executed in between. + lastMotion: null, + marks: {}, + // Mark for rendering fake cursor for visual mode. + fakeCursor: null, + insertMode: false, + // Repeat count for changes made in insert mode, triggered by key + // sequences like 3,i. Only exists when insertMode is true. + insertModeRepeat: undefined, + visualMode: false, + // If we are in visual line mode. No effect if visualMode is false. + visualLine: false, + visualBlock: false, + lastSelection: null, + lastPastedText: null, + sel: { + } + }; + } + return cm.state.vim; + } + var vimGlobalState; + function resetVimGlobalState() { + vimGlobalState = { + // The current search query. + searchQuery: null, + // Whether we are searching backwards. + searchIsReversed: false, + // Replace part of the last substituted pattern + lastSubstituteReplacePart: undefined, + jumpList: createCircularJumpList(), + macroModeState: new MacroModeState, + // Recording latest f, t, F or T motion command. + lastChararacterSearch: {increment:0, forward:true, selectedCharacter:''}, + registerController: new RegisterController({}), + // search history buffer + searchHistoryController: new HistoryController({}), + // ex Command history buffer + exCommandHistoryController : new HistoryController({}) + }; + for (var optionName in options) { + var option = options[optionName]; + option.value = option.defaultValue; + } + } + + var lastInsertModeKeyTimer; + var vimApi= { + buildKeyMap: function() { + // TODO: Convert keymap into dictionary format for fast lookup. + }, + // Testing hook, though it might be useful to expose the register + // controller anyways. + getRegisterController: function() { + return vimGlobalState.registerController; + }, + // Testing hook. + resetVimGlobalState_: resetVimGlobalState, + + // Testing hook. + getVimGlobalState_: function() { + return vimGlobalState; + }, + + // Testing hook. + maybeInitVimState_: maybeInitVimState, + + InsertModeKey: InsertModeKey, + map: function(lhs, rhs, ctx) { + // Add user defined key bindings. + exCommandDispatcher.map(lhs, rhs, ctx); + }, + unmap: function(lhs, ctx) { + // remove user defined key bindings. + exCommandDispatcher.unmap(lhs, ctx); + }, + setOption: setOption, + getOption: getOption, + defineOption: defineOption, + defineEx: function(name, prefix, func){ + if (name.indexOf(prefix) !== 0) { + throw new Error('(Vim.defineEx) "'+prefix+'" is not a prefix of "'+name+'", command not registered'); + } + exCommands[name]=func; + exCommandDispatcher.commandMap_[prefix]={name:name, shortName:prefix, type:'api'}; + }, + handleKey: function (cm, key, origin) { + var command = this.findKey(cm, key, origin); + if (typeof command === 'function') { + return command(); + } + }, + /** + * This is the outermost function called by CodeMirror, after keys have + * been mapped to their Vim equivalents. + * + * Finds a command based on the key (and cached keys if there is a + * multi-key sequence). Returns `undefined` if no key is matched, a noop + * function if a partial match is found (multi-key), and a function to + * execute the bound command if a a key is matched. The function always + * returns true. + */ + findKey: function(cm, key, origin) { + var vim = maybeInitVimState(cm); + function handleMacroRecording() { + var macroModeState = vimGlobalState.macroModeState; + if (macroModeState.isRecording) { + if (key == 'q') { + macroModeState.exitMacroRecordMode(); + clearInputState(cm); + return true; + } + if (origin != 'mapping') { + logKey(macroModeState, key); + } + } + } + function handleEsc() { + if (key == '') { + // Clear input state and get back to normal mode. + clearInputState(cm); + if (vim.visualMode) { + exitVisualMode(cm); + } else if (vim.insertMode) { + exitInsertMode(cm); + } + return true; + } + } + function doKeyToKey(keys) { + // TODO: prevent infinite recursion. + var match; + while (keys) { + // Pull off one command key, which is either a single character + // or a special sequence wrapped in '<' and '>', e.g. ''. + match = (/<\w+-.+?>|<\w+>|./).exec(keys); + key = match[0]; + keys = keys.substring(match.index + key.length); + CodeMirror.Vim.handleKey(cm, key, 'mapping'); + } + } + + function handleKeyInsertMode() { + if (handleEsc()) { return true; } + var keys = vim.inputState.keyBuffer = vim.inputState.keyBuffer + key; + var keysAreChars = key.length == 1; + var match = commandDispatcher.matchCommand(keys, defaultKeymap, vim.inputState, 'insert'); + // Need to check all key substrings in insert mode. + while (keys.length > 1 && match.type != 'full') { + var keys = vim.inputState.keyBuffer = keys.slice(1); + var thisMatch = commandDispatcher.matchCommand(keys, defaultKeymap, vim.inputState, 'insert'); + if (thisMatch.type != 'none') { match = thisMatch; } + } + if (match.type == 'none') { clearInputState(cm); return false; } + else if (match.type == 'partial') { + if (lastInsertModeKeyTimer) { window.clearTimeout(lastInsertModeKeyTimer); } + lastInsertModeKeyTimer = window.setTimeout( + function() { if (vim.insertMode && vim.inputState.keyBuffer) { clearInputState(cm); } }, + getOption('insertModeEscKeysTimeout')); + return !keysAreChars; + } + + if (lastInsertModeKeyTimer) { window.clearTimeout(lastInsertModeKeyTimer); } + if (keysAreChars) { + var here = cm.getCursor(); + cm.replaceRange('', offsetCursor(here, 0, -(keys.length - 1)), here, '+input'); + } + clearInputState(cm); + return match.command; + } + + function handleKeyNonInsertMode() { + if (handleMacroRecording() || handleEsc()) { return true; }; + + var keys = vim.inputState.keyBuffer = vim.inputState.keyBuffer + key; + if (/^[1-9]\d*$/.test(keys)) { return true; } + + var keysMatcher = /^(\d*)(.*)$/.exec(keys); + if (!keysMatcher) { clearInputState(cm); return false; } + var context = vim.visualMode ? 'visual' : + 'normal'; + var match = commandDispatcher.matchCommand(keysMatcher[2] || keysMatcher[1], defaultKeymap, vim.inputState, context); + if (match.type == 'none') { clearInputState(cm); return false; } + else if (match.type == 'partial') { return true; } + + vim.inputState.keyBuffer = ''; + var keysMatcher = /^(\d*)(.*)$/.exec(keys); + if (keysMatcher[1] && keysMatcher[1] != '0') { + vim.inputState.pushRepeatDigit(keysMatcher[1]); + } + return match.command; + } + + var command; + if (vim.insertMode) { command = handleKeyInsertMode(); } + else { command = handleKeyNonInsertMode(); } + if (command === false) { + return undefined; + } else if (command === true) { + // TODO: Look into using CodeMirror's multi-key handling. + // Return no-op since we are caching the key. Counts as handled, but + // don't want act on it just yet. + return function() {}; + } else { + return function() { + return cm.operation(function() { + cm.curOp.isVimOp = true; + try { + if (command.type == 'keyToKey') { + doKeyToKey(command.toKeys); + } else { + commandDispatcher.processCommand(cm, vim, command); + } + } catch (e) { + // clear VIM state in case it's in a bad state. + cm.state.vim = undefined; + maybeInitVimState(cm); + console['log'](e); + throw e; + } + return true; + }); + }; + } + }, + handleEx: function(cm, input) { + exCommandDispatcher.processCommand(cm, input); + } + }; + + // Represents the current input state. + function InputState() { + this.prefixRepeat = []; + this.motionRepeat = []; + + this.operator = null; + this.operatorArgs = null; + this.motion = null; + this.motionArgs = null; + this.keyBuffer = []; // For matching multi-key commands. + this.registerName = null; // Defaults to the unnamed register. + } + InputState.prototype.pushRepeatDigit = function(n) { + if (!this.operator) { + this.prefixRepeat = this.prefixRepeat.concat(n); + } else { + this.motionRepeat = this.motionRepeat.concat(n); + } + }; + InputState.prototype.getRepeat = function() { + var repeat = 0; + if (this.prefixRepeat.length > 0 || this.motionRepeat.length > 0) { + repeat = 1; + if (this.prefixRepeat.length > 0) { + repeat *= parseInt(this.prefixRepeat.join(''), 10); + } + if (this.motionRepeat.length > 0) { + repeat *= parseInt(this.motionRepeat.join(''), 10); + } + } + return repeat; + }; + + function clearInputState(cm, reason) { + cm.state.vim.inputState = new InputState(); + CodeMirror.signal(cm, 'vim-command-done', reason); + } + + /* + * Register stores information about copy and paste registers. Besides + * text, a register must store whether it is linewise (i.e., when it is + * pasted, should it insert itself into a new line, or should the text be + * inserted at the cursor position.) + */ + function Register(text, linewise, blockwise) { + this.clear(); + this.keyBuffer = [text || '']; + this.insertModeChanges = []; + this.searchQueries = []; + this.linewise = !!linewise; + this.blockwise = !!blockwise; + } + Register.prototype = { + setText: function(text, linewise, blockwise) { + this.keyBuffer = [text || '']; + this.linewise = !!linewise; + this.blockwise = !!blockwise; + }, + pushText: function(text, linewise) { + // if this register has ever been set to linewise, use linewise. + if (linewise) { + if (!this.linewise) { + this.keyBuffer.push('\n'); + } + this.linewise = true; + } + this.keyBuffer.push(text); + }, + pushInsertModeChanges: function(changes) { + this.insertModeChanges.push(createInsertModeChanges(changes)); + }, + pushSearchQuery: function(query) { + this.searchQueries.push(query); + }, + clear: function() { + this.keyBuffer = []; + this.insertModeChanges = []; + this.searchQueries = []; + this.linewise = false; + }, + toString: function() { + return this.keyBuffer.join(''); + } + }; + + /* + * vim registers allow you to keep many independent copy and paste buffers. + * See http://usevim.com/2012/04/13/registers/ for an introduction. + * + * RegisterController keeps the state of all the registers. An initial + * state may be passed in. The unnamed register '"' will always be + * overridden. + */ + function RegisterController(registers) { + this.registers = registers; + this.unnamedRegister = registers['"'] = new Register(); + registers['.'] = new Register(); + registers[':'] = new Register(); + registers['/'] = new Register(); + } + RegisterController.prototype = { + pushText: function(registerName, operator, text, linewise, blockwise) { + if (linewise && text.charAt(0) == '\n') { + text = text.slice(1) + '\n'; + } + if (linewise && text.charAt(text.length - 1) !== '\n'){ + text += '\n'; + } + // Lowercase and uppercase registers refer to the same register. + // Uppercase just means append. + var register = this.isValidRegister(registerName) ? + this.getRegister(registerName) : null; + // if no register/an invalid register was specified, things go to the + // default registers + if (!register) { + switch (operator) { + case 'yank': + // The 0 register contains the text from the most recent yank. + this.registers['0'] = new Register(text, linewise, blockwise); + break; + case 'delete': + case 'change': + if (text.indexOf('\n') == -1) { + // Delete less than 1 line. Update the small delete register. + this.registers['-'] = new Register(text, linewise); + } else { + // Shift down the contents of the numbered registers and put the + // deleted text into register 1. + this.shiftNumericRegisters_(); + this.registers['1'] = new Register(text, linewise); + } + break; + } + // Make sure the unnamed register is set to what just happened + this.unnamedRegister.setText(text, linewise, blockwise); + return; + } + + // If we've gotten to this point, we've actually specified a register + var append = isUpperCase(registerName); + if (append) { + register.pushText(text, linewise); + } else { + register.setText(text, linewise, blockwise); + } + // The unnamed register always has the same value as the last used + // register. + this.unnamedRegister.setText(register.toString(), linewise); + }, + // Gets the register named @name. If one of @name doesn't already exist, + // create it. If @name is invalid, return the unnamedRegister. + getRegister: function(name) { + if (!this.isValidRegister(name)) { + return this.unnamedRegister; + } + name = name.toLowerCase(); + if (!this.registers[name]) { + this.registers[name] = new Register(); + } + return this.registers[name]; + }, + isValidRegister: function(name) { + return name && inArray(name, validRegisters); + }, + shiftNumericRegisters_: function() { + for (var i = 9; i >= 2; i--) { + this.registers[i] = this.getRegister('' + (i - 1)); + } + } + }; + function HistoryController() { + this.historyBuffer = []; + this.iterator; + this.initialPrefix = null; + } + HistoryController.prototype = { + // the input argument here acts a user entered prefix for a small time + // until we start autocompletion in which case it is the autocompleted. + nextMatch: function (input, up) { + var historyBuffer = this.historyBuffer; + var dir = up ? -1 : 1; + if (this.initialPrefix === null) this.initialPrefix = input; + for (var i = this.iterator + dir; up ? i >= 0 : i < historyBuffer.length; i+= dir) { + var element = historyBuffer[i]; + for (var j = 0; j <= element.length; j++) { + if (this.initialPrefix == element.substring(0, j)) { + this.iterator = i; + return element; + } + } + } + // should return the user input in case we reach the end of buffer. + if (i >= historyBuffer.length) { + this.iterator = historyBuffer.length; + return this.initialPrefix; + } + // return the last autocompleted query or exCommand as it is. + if (i < 0 ) return input; + }, + pushInput: function(input) { + var index = this.historyBuffer.indexOf(input); + if (index > -1) this.historyBuffer.splice(index, 1); + if (input.length) this.historyBuffer.push(input); + }, + reset: function() { + this.initialPrefix = null; + this.iterator = this.historyBuffer.length; + } + }; + var commandDispatcher = { + matchCommand: function(keys, keyMap, inputState, context) { + var matches = commandMatches(keys, keyMap, context, inputState); + if (!matches.full && !matches.partial) { + return {type: 'none'}; + } else if (!matches.full && matches.partial) { + return {type: 'partial'}; + } + + var bestMatch; + for (var i = 0; i < matches.full.length; i++) { + var match = matches.full[i]; + if (!bestMatch) { + bestMatch = match; + } + } + if (bestMatch.keys.slice(-11) == '') { + inputState.selectedCharacter = lastChar(keys); + } + return {type: 'full', command: bestMatch}; + }, + processCommand: function(cm, vim, command) { + vim.inputState.repeatOverride = command.repeatOverride; + switch (command.type) { + case 'motion': + this.processMotion(cm, vim, command); + break; + case 'operator': + this.processOperator(cm, vim, command); + break; + case 'operatorMotion': + this.processOperatorMotion(cm, vim, command); + break; + case 'action': + this.processAction(cm, vim, command); + break; + case 'search': + this.processSearch(cm, vim, command); + clearInputState(cm); + break; + case 'ex': + case 'keyToEx': + this.processEx(cm, vim, command); + clearInputState(cm); + break; + default: + break; + } + }, + processMotion: function(cm, vim, command) { + vim.inputState.motion = command.motion; + vim.inputState.motionArgs = copyArgs(command.motionArgs); + this.evalInput(cm, vim); + }, + processOperator: function(cm, vim, command) { + var inputState = vim.inputState; + if (inputState.operator) { + if (inputState.operator == command.operator) { + // Typing an operator twice like 'dd' makes the operator operate + // linewise + inputState.motion = 'expandToLine'; + inputState.motionArgs = { linewise: true }; + this.evalInput(cm, vim); + return; + } else { + // 2 different operators in a row doesn't make sense. + clearInputState(cm); + } + } + inputState.operator = command.operator; + inputState.operatorArgs = copyArgs(command.operatorArgs); + if (vim.visualMode) { + // Operating on a selection in visual mode. We don't need a motion. + this.evalInput(cm, vim); + } + }, + processOperatorMotion: function(cm, vim, command) { + var visualMode = vim.visualMode; + var operatorMotionArgs = copyArgs(command.operatorMotionArgs); + if (operatorMotionArgs) { + // Operator motions may have special behavior in visual mode. + if (visualMode && operatorMotionArgs.visualLine) { + vim.visualLine = true; + } + } + this.processOperator(cm, vim, command); + if (!visualMode) { + this.processMotion(cm, vim, command); + } + }, + processAction: function(cm, vim, command) { + var inputState = vim.inputState; + var repeat = inputState.getRepeat(); + var repeatIsExplicit = !!repeat; + var actionArgs = copyArgs(command.actionArgs) || {}; + if (inputState.selectedCharacter) { + actionArgs.selectedCharacter = inputState.selectedCharacter; + } + // Actions may or may not have motions and operators. Do these first. + if (command.operator) { + this.processOperator(cm, vim, command); + } + if (command.motion) { + this.processMotion(cm, vim, command); + } + if (command.motion || command.operator) { + this.evalInput(cm, vim); + } + actionArgs.repeat = repeat || 1; + actionArgs.repeatIsExplicit = repeatIsExplicit; + actionArgs.registerName = inputState.registerName; + clearInputState(cm); + vim.lastMotion = null; + if (command.isEdit) { + this.recordLastEdit(vim, inputState, command); + } + actions[command.action](cm, actionArgs, vim); + }, + processSearch: function(cm, vim, command) { + if (!cm.getSearchCursor) { + // Search depends on SearchCursor. + return; + } + var forward = command.searchArgs.forward; + var wholeWordOnly = command.searchArgs.wholeWordOnly; + getSearchState(cm).setReversed(!forward); + var promptPrefix = (forward) ? '/' : '?'; + var originalQuery = getSearchState(cm).getQuery(); + var originalScrollPos = cm.getScrollInfo(); + originalScrollPos.cursor = cm.getCursor(); + if (getSearchState(cm).clearHighlight) // ace patch clear highlight after n + getSearchState(cm).clearHighlight(); + function handleQuery(query, ignoreCase, smartCase) { + vimGlobalState.searchHistoryController.pushInput(query); + vimGlobalState.searchHistoryController.reset(); + try { + updateSearchQuery(cm, query, ignoreCase, smartCase); + } catch (e) { + showConfirm(cm, 'Invalid regex: ' + query); + return; + } + commandDispatcher.processMotion(cm, vim, { + type: 'motion', + motion: 'findNext', + motionArgs: { forward: true, toJumplist: command.searchArgs.toJumplist } + }); + getSearchState(cm).clearHighlight = function clear() { + cm.off("cursorActivity", clear); + clearSearchHighlight(cm); + }; + cm.on("cursorActivity", getSearchState(cm).clearHighlight); + } + function onPromptClose(query) { + cm.scrollTo(originalScrollPos.left, originalScrollPos.top); + cm.setCursor(originalScrollPos.cursor); // ace patch TODO find a way to record motion without calling handleQuery + handleQuery(query, false /** ignoreCase */, false /** smartCase */); // ace patch TODO make smartcase an option + var macroModeState = vimGlobalState.macroModeState; + if (macroModeState.isRecording) { + logSearchQuery(macroModeState, query); + } + clearSearchHighlight(cm); + } + function onPromptKeyUp(e, query, close) { + var keyName = CodeMirror.keyName(e), up; + if (keyName == 'Up' || keyName == 'Down') { + up = keyName == 'Up' ? true : false; + query = vimGlobalState.searchHistoryController.nextMatch(query, up) || ''; + close(query); + } else { + if ( keyName != 'Left' && keyName != 'Right' && keyName != 'Ctrl' && keyName != 'Alt' && keyName != 'Shift') + vimGlobalState.searchHistoryController.reset(); + } + var parsedQuery; + try { + parsedQuery = updateSearchQuery(cm, query, + false /** ignoreCase */, false /** smartCase */); + } catch (e) { + // Swallow bad regexes for incremental search. + } + if (parsedQuery) { + cm.scrollIntoView(findNext(cm, !forward, parsedQuery, undefined, originalScrollPos.cursor), 30); + } else { + cm.scrollIntoView(originalScrollPos.cursor); + clearSearchHighlight(cm); + cm.scrollTo(originalScrollPos.left, originalScrollPos.top); + cm.ace.curOp.command.scrollIntoView = "animate"; + } + } + function onPromptKeyDown(e, query, close) { + var keyName = CodeMirror.keyName(e); + if (keyName == 'Esc' || keyName == 'Ctrl-C' || keyName == 'Ctrl-[') { + vimGlobalState.searchHistoryController.pushInput(query); + vimGlobalState.searchHistoryController.reset(); + updateSearchQuery(cm, originalQuery); + cm.scrollTo(originalScrollPos.left, originalScrollPos.top); + cm.scrollIntoView(originalScrollPos.cursor); + CodeMirror.e_stop(e); + close(); + cm.focus(); + clearSearchHighlight(cm); + } + } + switch (command.searchArgs.querySrc) { + case 'prompt': + var macroModeState = vimGlobalState.macroModeState; + if (macroModeState.isPlaying) { + var query = macroModeState.replaySearchQueries.shift(); + handleQuery(query, true /** ignoreCase */, false /** smartCase */); + } else { + showPrompt(cm, { + onClose: onPromptClose, + prefix: promptPrefix, + desc: searchPromptDesc, + onKeyUp: onPromptKeyUp, + onKeyDown: onPromptKeyDown + }); + } + break; + case 'wordUnderCursor': + var word = expandWordUnderCursor(cm, false /** inclusive */, + true /** forward */, false /** bigWord */, + true /** noSymbol */); + var isKeyword = true; + if (!word) { + word = expandWordUnderCursor(cm, false /** inclusive */, + true /** forward */, false /** bigWord */, + false /** noSymbol */); + isKeyword = false; + } + if (!word) { + return; + } + var query = cm.getLine(word.start.line).substring(word.start.ch, + word.end.ch); + if (isKeyword && wholeWordOnly) { + query = '\\b' + query + '\\b'; + } else { + query = escapeRegex(query); + } + + // cachedCursor is used to save the old position of the cursor + // when * or # causes vim to seek for the nearest word and shift + // the cursor before entering the motion. + vimGlobalState.jumpList.cachedCursor = cm.getCursor(); + cm.setCursor(word.start); + + handleQuery(query, true /** ignoreCase */, false /** smartCase */); + break; + } + }, + processEx: function(cm, vim, command) { + function onPromptClose(input) { + // Give the prompt some time to close so that if processCommand shows + // an error, the elements don't overlap. + vimGlobalState.exCommandHistoryController.pushInput(input); + vimGlobalState.exCommandHistoryController.reset(); + exCommandDispatcher.processCommand(cm, input); + } + function onPromptKeyDown(e, input, close) { + var keyName = CodeMirror.keyName(e), up; + if (keyName == 'Esc' || keyName == 'Ctrl-C' || keyName == 'Ctrl-[') { + vimGlobalState.exCommandHistoryController.pushInput(input); + vimGlobalState.exCommandHistoryController.reset(); + CodeMirror.e_stop(e); + close(); + cm.focus(); + } + if (keyName == 'Up' || keyName == 'Down') { + up = keyName == 'Up' ? true : false; + input = vimGlobalState.exCommandHistoryController.nextMatch(input, up) || ''; + close(input); + } else { + if ( keyName != 'Left' && keyName != 'Right' && keyName != 'Ctrl' && keyName != 'Alt' && keyName != 'Shift') + vimGlobalState.exCommandHistoryController.reset(); + } + } + if (command.type == 'keyToEx') { + // Handle user defined Ex to Ex mappings + exCommandDispatcher.processCommand(cm, command.exArgs.input); + } else { + if (vim.visualMode) { + showPrompt(cm, { onClose: onPromptClose, prefix: ':', value: '\'<,\'>', + onKeyDown: onPromptKeyDown}); + } else { + showPrompt(cm, { onClose: onPromptClose, prefix: ':', + onKeyDown: onPromptKeyDown}); + } + } + }, + evalInput: function(cm, vim) { + // If the motion comand is set, execute both the operator and motion. + // Otherwise return. + var inputState = vim.inputState; + var motion = inputState.motion; + var motionArgs = inputState.motionArgs || {}; + var operator = inputState.operator; + var operatorArgs = inputState.operatorArgs || {}; + var registerName = inputState.registerName; + var sel = vim.sel; + // TODO: Make sure cm and vim selections are identical outside visual mode. + var origHead = copyCursor(vim.visualMode ? sel.head: cm.getCursor('head')); + var origAnchor = copyCursor(vim.visualMode ? sel.anchor : cm.getCursor('anchor')); + var oldHead = copyCursor(origHead); + var oldAnchor = copyCursor(origAnchor); + var newHead, newAnchor; + var repeat; + if (operator) { + this.recordLastEdit(vim, inputState); + } + if (inputState.repeatOverride !== undefined) { + // If repeatOverride is specified, that takes precedence over the + // input state's repeat. Used by Ex mode and can be user defined. + repeat = inputState.repeatOverride; + } else { + repeat = inputState.getRepeat(); + } + if (repeat > 0 && motionArgs.explicitRepeat) { + motionArgs.repeatIsExplicit = true; + } else if (motionArgs.noRepeat || + (!motionArgs.explicitRepeat && repeat === 0)) { + repeat = 1; + motionArgs.repeatIsExplicit = false; + } + if (inputState.selectedCharacter) { + // If there is a character input, stick it in all of the arg arrays. + motionArgs.selectedCharacter = operatorArgs.selectedCharacter = + inputState.selectedCharacter; + } + motionArgs.repeat = repeat; + clearInputState(cm); + if (motion) { + var motionResult = motions[motion](cm, origHead, motionArgs, vim); + vim.lastMotion = motions[motion]; + if (!motionResult) { + return; + } + if (motionArgs.toJumplist) { + if (!operator) + cm.ace.curOp.command.scrollIntoView = "center-animate"; // ace patch + var jumpList = vimGlobalState.jumpList; + // if the current motion is # or *, use cachedCursor + var cachedCursor = jumpList.cachedCursor; + if (cachedCursor) { + recordJumpPosition(cm, cachedCursor, motionResult); + delete jumpList.cachedCursor; + } else { + recordJumpPosition(cm, origHead, motionResult); + } + } + if (motionResult instanceof Array) { + newAnchor = motionResult[0]; + newHead = motionResult[1]; + } else { + newHead = motionResult; + } + // TODO: Handle null returns from motion commands better. + if (!newHead) { + newHead = copyCursor(origHead); + } + if (vim.visualMode) { + if (!(vim.visualBlock && newHead.ch === Infinity)) { + newHead = clipCursorToContent(cm, newHead, vim.visualBlock); + } + if (newAnchor) { + newAnchor = clipCursorToContent(cm, newAnchor, true); + } + newAnchor = newAnchor || oldAnchor; + sel.anchor = newAnchor; + sel.head = newHead; + updateCmSelection(cm); + updateMark(cm, vim, '<', + cursorIsBefore(newAnchor, newHead) ? newAnchor + : newHead); + updateMark(cm, vim, '>', + cursorIsBefore(newAnchor, newHead) ? newHead + : newAnchor); + } else if (!operator) { + newHead = clipCursorToContent(cm, newHead); + cm.setCursor(newHead.line, newHead.ch); + } + } + if (operator) { + if (operatorArgs.lastSel) { + // Replaying a visual mode operation + newAnchor = oldAnchor; + var lastSel = operatorArgs.lastSel; + var lineOffset = Math.abs(lastSel.head.line - lastSel.anchor.line); + var chOffset = Math.abs(lastSel.head.ch - lastSel.anchor.ch); + if (lastSel.visualLine) { + // Linewise Visual mode: The same number of lines. + newHead = Pos(oldAnchor.line + lineOffset, oldAnchor.ch); + } else if (lastSel.visualBlock) { + // Blockwise Visual mode: The same number of lines and columns. + newHead = Pos(oldAnchor.line + lineOffset, oldAnchor.ch + chOffset); + } else if (lastSel.head.line == lastSel.anchor.line) { + // Normal Visual mode within one line: The same number of characters. + newHead = Pos(oldAnchor.line, oldAnchor.ch + chOffset); + } else { + // Normal Visual mode with several lines: The same number of lines, in the + // last line the same number of characters as in the last line the last time. + newHead = Pos(oldAnchor.line + lineOffset, oldAnchor.ch); + } + vim.visualMode = true; + vim.visualLine = lastSel.visualLine; + vim.visualBlock = lastSel.visualBlock; + sel = vim.sel = { + anchor: newAnchor, + head: newHead + }; + updateCmSelection(cm); + } else if (vim.visualMode) { + operatorArgs.lastSel = { + anchor: copyCursor(sel.anchor), + head: copyCursor(sel.head), + visualBlock: vim.visualBlock, + visualLine: vim.visualLine + }; + } + var curStart, curEnd, linewise, mode; + var cmSel; + if (vim.visualMode) { + // Init visual op + curStart = cursorMin(sel.head, sel.anchor); + curEnd = cursorMax(sel.head, sel.anchor); + linewise = vim.visualLine || operatorArgs.linewise; + mode = vim.visualBlock ? 'block' : + linewise ? 'line' : + 'char'; + cmSel = makeCmSelection(cm, { + anchor: curStart, + head: curEnd + }, mode); + if (linewise) { + var ranges = cmSel.ranges; + if (mode == 'block') { + // Linewise operators in visual block mode extend to end of line + for (var i = 0; i < ranges.length; i++) { + ranges[i].head.ch = lineLength(cm, ranges[i].head.line); + } + } else if (mode == 'line') { + ranges[0].head = Pos(ranges[0].head.line + 1, 0); + } + } + } else { + // Init motion op + curStart = copyCursor(newAnchor || oldAnchor); + curEnd = copyCursor(newHead || oldHead); + if (cursorIsBefore(curEnd, curStart)) { + var tmp = curStart; + curStart = curEnd; + curEnd = tmp; + } + linewise = motionArgs.linewise || operatorArgs.linewise; + if (linewise) { + // Expand selection to entire line. + expandSelectionToLine(cm, curStart, curEnd); + } else if (motionArgs.forward) { + // Clip to trailing newlines only if the motion goes forward. + clipToLine(cm, curStart, curEnd); + } + mode = 'char'; + var exclusive = !motionArgs.inclusive || linewise; + cmSel = makeCmSelection(cm, { + anchor: curStart, + head: curEnd + }, mode, exclusive); + } + cm.setSelections(cmSel.ranges, cmSel.primary); + vim.lastMotion = null; + operatorArgs.repeat = repeat; // For indent in visual mode. + operatorArgs.registerName = registerName; + // Keep track of linewise as it affects how paste and change behave. + operatorArgs.linewise = linewise; + var operatorMoveTo = operators[operator]( + cm, operatorArgs, cmSel.ranges, oldAnchor, newHead); + if (vim.visualMode) { + exitVisualMode(cm); + } + if (operatorMoveTo) { + cm.setCursor(operatorMoveTo); + } + } + }, + recordLastEdit: function(vim, inputState, actionCommand) { + var macroModeState = vimGlobalState.macroModeState; + if (macroModeState.isPlaying) { return; } + vim.lastEditInputState = inputState; + vim.lastEditActionCommand = actionCommand; + macroModeState.lastInsertModeChanges.changes = []; + macroModeState.lastInsertModeChanges.expectCursorActivityForChange = false; + } + }; + + /** + * typedef {Object{line:number,ch:number}} Cursor An object containing the + * position of the cursor. + */ + // All of the functions below return Cursor objects. + var motions = { + moveToTopLine: function(cm, _head, motionArgs) { + var line = getUserVisibleLines(cm).top + motionArgs.repeat -1; + return Pos(line, findFirstNonWhiteSpaceCharacter(cm.getLine(line))); + }, + moveToMiddleLine: function(cm) { + var range = getUserVisibleLines(cm); + var line = Math.floor((range.top + range.bottom) * 0.5); + return Pos(line, findFirstNonWhiteSpaceCharacter(cm.getLine(line))); + }, + moveToBottomLine: function(cm, _head, motionArgs) { + var line = getUserVisibleLines(cm).bottom - motionArgs.repeat +1; + return Pos(line, findFirstNonWhiteSpaceCharacter(cm.getLine(line))); + }, + expandToLine: function(_cm, head, motionArgs) { + // Expands forward to end of line, and then to next line if repeat is + // >1. Does not handle backward motion! + var cur = head; + return Pos(cur.line + motionArgs.repeat - 1, Infinity); + }, + findNext: function(cm, _head, motionArgs) { + var state = getSearchState(cm); + var query = state.getQuery(); + if (!query) { + return; + } + var prev = !motionArgs.forward; + // If search is initiated with ? instead of /, negate direction. + prev = (state.isReversed()) ? !prev : prev; + highlightSearchMatches(cm, query); + return findNext(cm, prev/** prev */, query, motionArgs.repeat); + }, + goToMark: function(cm, _head, motionArgs, vim) { + var mark = vim.marks[motionArgs.selectedCharacter]; + if (mark) { + var pos = mark.find(); + return motionArgs.linewise ? { line: pos.line, ch: findFirstNonWhiteSpaceCharacter(cm.getLine(pos.line)) } : pos; + } + return null; + }, + moveToOtherHighlightedEnd: function(cm, _head, motionArgs, vim) { + if (vim.visualBlock && motionArgs.sameLine) { + var sel = vim.sel; + return [ + clipCursorToContent(cm, Pos(sel.anchor.line, sel.head.ch)), + clipCursorToContent(cm, Pos(sel.head.line, sel.anchor.ch)) + ]; + } else { + return ([vim.sel.head, vim.sel.anchor]); + } + }, + jumpToMark: function(cm, head, motionArgs, vim) { + var best = head; + for (var i = 0; i < motionArgs.repeat; i++) { + var cursor = best; + for (var key in vim.marks) { + if (!isLowerCase(key)) { + continue; + } + var mark = vim.marks[key].find(); + var isWrongDirection = (motionArgs.forward) ? + cursorIsBefore(mark, cursor) : cursorIsBefore(cursor, mark); + + if (isWrongDirection) { + continue; + } + if (motionArgs.linewise && (mark.line == cursor.line)) { + continue; + } + + var equal = cursorEqual(cursor, best); + var between = (motionArgs.forward) ? + cursorIsBetween(cursor, mark, best) : + cursorIsBetween(best, mark, cursor); + + if (equal || between) { + best = mark; + } + } + } + + if (motionArgs.linewise) { + // Vim places the cursor on the first non-whitespace character of + // the line if there is one, else it places the cursor at the end + // of the line, regardless of whether a mark was found. + best = Pos(best.line, findFirstNonWhiteSpaceCharacter(cm.getLine(best.line))); + } + return best; + }, + moveByCharacters: function(_cm, head, motionArgs) { + var cur = head; + var repeat = motionArgs.repeat; + var ch = motionArgs.forward ? cur.ch + repeat : cur.ch - repeat; + return Pos(cur.line, ch); + }, + moveByLines: function(cm, head, motionArgs, vim) { + var cur = head; + var endCh = cur.ch; + // Depending what our last motion was, we may want to do different + // things. If our last motion was moving vertically, we want to + // preserve the HPos from our last horizontal move. If our last motion + // was going to the end of a line, moving vertically we should go to + // the end of the line, etc. + switch (vim.lastMotion) { + case this.moveByLines: + case this.moveByDisplayLines: + case this.moveByScroll: + case this.moveToColumn: + case this.moveToEol: + endCh = vim.lastHPos; + break; + default: + vim.lastHPos = endCh; + } + var repeat = motionArgs.repeat+(motionArgs.repeatOffset||0); + var line = motionArgs.forward ? cur.line + repeat : cur.line - repeat; + var first = cm.firstLine(); + var last = cm.lastLine(); + // Vim cancels linewise motions that start on an edge and move beyond + // that edge. It does not cancel motions that do not start on an edge. + if ((line < first && cur.line == first) || + (line > last && cur.line == last)) { + return; + } + // /ace patch + var fold = cm.ace.session.getFoldAt(line, endCh); + if (fold) { + if (motionArgs.forward) + line = fold.end.row + 1; + else + line = fold.start.row - 1; + } + // /ace patche + if (motionArgs.toFirstChar){ + endCh=findFirstNonWhiteSpaceCharacter(cm.getLine(line)); + vim.lastHPos = endCh; + } + vim.lastHSPos = cm.charCoords(Pos(line, endCh),'div').left; + return Pos(line, endCh); + }, + moveByDisplayLines: function(cm, head, motionArgs, vim) { + var cur = head; + switch (vim.lastMotion) { + case this.moveByDisplayLines: + case this.moveByScroll: + case this.moveByLines: + case this.moveToColumn: + case this.moveToEol: + break; + default: + vim.lastHSPos = cm.charCoords(cur,'div').left; + } + var repeat = motionArgs.repeat; + var res=cm.findPosV(cur,(motionArgs.forward ? repeat : -repeat),'line',vim.lastHSPos); + if (res.hitSide) { + if (motionArgs.forward) { + var lastCharCoords = cm.charCoords(res, 'div'); + var goalCoords = { top: lastCharCoords.top + 8, left: vim.lastHSPos }; + var res = cm.coordsChar(goalCoords, 'div'); + } else { + var resCoords = cm.charCoords(Pos(cm.firstLine(), 0), 'div'); + resCoords.left = vim.lastHSPos; + res = cm.coordsChar(resCoords, 'div'); + } + } + vim.lastHPos = res.ch; + return res; + }, + moveByPage: function(cm, head, motionArgs) { + // CodeMirror only exposes functions that move the cursor page down, so + // doing this bad hack to move the cursor and move it back. evalInput + // will move the cursor to where it should be in the end. + var curStart = head; + var repeat = motionArgs.repeat; + return cm.findPosV(curStart, (motionArgs.forward ? repeat : -repeat), 'page'); + }, + moveByParagraph: function(cm, head, motionArgs) { + var dir = motionArgs.forward ? 1 : -1; + return findParagraph(cm, head, motionArgs.repeat, dir); + }, + moveByScroll: function(cm, head, motionArgs, vim) { + var scrollbox = cm.getScrollInfo(); + var curEnd = null; + var repeat = motionArgs.repeat; + if (!repeat) { + repeat = scrollbox.clientHeight / (2 * cm.defaultTextHeight()); + } + var orig = cm.charCoords(head, 'local'); + motionArgs.repeat = repeat; + var curEnd = motions.moveByDisplayLines(cm, head, motionArgs, vim); + if (!curEnd) { + return null; + } + var dest = cm.charCoords(curEnd, 'local'); + cm.scrollTo(null, scrollbox.top + dest.top - orig.top); + return curEnd; + }, + moveByWords: function(cm, head, motionArgs) { + return moveToWord(cm, head, motionArgs.repeat, !!motionArgs.forward, + !!motionArgs.wordEnd, !!motionArgs.bigWord); + }, + moveTillCharacter: function(cm, _head, motionArgs) { + var repeat = motionArgs.repeat; + var curEnd = moveToCharacter(cm, repeat, motionArgs.forward, + motionArgs.selectedCharacter); + var increment = motionArgs.forward ? -1 : 1; + recordLastCharacterSearch(increment, motionArgs); + if (!curEnd) return null; + curEnd.ch += increment; + return curEnd; + }, + moveToCharacter: function(cm, head, motionArgs) { + var repeat = motionArgs.repeat; + recordLastCharacterSearch(0, motionArgs); + return moveToCharacter(cm, repeat, motionArgs.forward, + motionArgs.selectedCharacter) || head; + }, + moveToSymbol: function(cm, head, motionArgs) { + var repeat = motionArgs.repeat; + return findSymbol(cm, repeat, motionArgs.forward, + motionArgs.selectedCharacter) || head; + }, + moveToColumn: function(cm, head, motionArgs, vim) { + var repeat = motionArgs.repeat; + // repeat is equivalent to which column we want to move to! + vim.lastHPos = repeat - 1; + vim.lastHSPos = cm.charCoords(head,'div').left; + return moveToColumn(cm, repeat); + }, + moveToEol: function(cm, head, motionArgs, vim) { + var cur = head; + vim.lastHPos = Infinity; + var retval= Pos(cur.line + motionArgs.repeat - 1, Infinity); + var end=cm.clipPos(retval); + end.ch--; + vim.lastHSPos = cm.charCoords(end,'div').left; + return retval; + }, + moveToFirstNonWhiteSpaceCharacter: function(cm, head) { + // Go to the start of the line where the text begins, or the end for + // whitespace-only lines + var cursor = head; + return Pos(cursor.line, + findFirstNonWhiteSpaceCharacter(cm.getLine(cursor.line))); + }, + moveToMatchedSymbol: function(cm, head) { + var cursor = head; + var line = cursor.line; + var ch = cursor.ch; + var lineText = cm.getLine(line); + var symbol; + do { + symbol = lineText.charAt(ch++); + if (symbol && isMatchableSymbol(symbol)) { + var style = cm.getTokenTypeAt(Pos(line, ch)); + if (style !== "string" && style !== "comment") { + break; + } + } + } while (symbol); + if (symbol) { + var matched = cm.findMatchingBracket(Pos(line, ch)); + return matched.to; + } else { + return cursor; + } + }, + moveToStartOfLine: function(_cm, head) { + return Pos(head.line, 0); + }, + moveToLineOrEdgeOfDocument: function(cm, _head, motionArgs) { + var lineNum = motionArgs.forward ? cm.lastLine() : cm.firstLine(); + if (motionArgs.repeatIsExplicit) { + lineNum = motionArgs.repeat - cm.getOption('firstLineNumber'); + } + return Pos(lineNum, + findFirstNonWhiteSpaceCharacter(cm.getLine(lineNum))); + }, + textObjectManipulation: function(cm, head, motionArgs, vim) { + // TODO: lots of possible exceptions that can be thrown here. Try da( + // outside of a () block. + + // TODO: adding <> >< to this map doesn't work, presumably because + // they're operators + var mirroredPairs = {'(': ')', ')': '(', + '{': '}', '}': '{', + '[': ']', ']': '['}; + var selfPaired = {'\'': true, '"': true}; + + var character = motionArgs.selectedCharacter; + // 'b' refers to '()' block. + // 'B' refers to '{}' block. + if (character == 'b') { + character = '('; + } else if (character == 'B') { + character = '{'; + } + + // Inclusive is the difference between a and i + // TODO: Instead of using the additional text object map to perform text + // object operations, merge the map into the defaultKeyMap and use + // motionArgs to define behavior. Define separate entries for 'aw', + // 'iw', 'a[', 'i[', etc. + var inclusive = !motionArgs.textObjectInner; + + var tmp; + if (mirroredPairs[character]) { + tmp = selectCompanionObject(cm, head, character, inclusive); + } else if (selfPaired[character]) { + tmp = findBeginningAndEnd(cm, head, character, inclusive); + } else if (character === 'W') { + tmp = expandWordUnderCursor(cm, inclusive, true /** forward */, + true /** bigWord */); + } else if (character === 'w') { + tmp = expandWordUnderCursor(cm, inclusive, true /** forward */, + false /** bigWord */); + } else if (character === 'p') { + tmp = findParagraph(cm, head, motionArgs.repeat, 0, inclusive); + motionArgs.linewise = true; + if (vim.visualMode) { + if (!vim.visualLine) { vim.visualLine = true; } + } else { + var operatorArgs = vim.inputState.operatorArgs; + if (operatorArgs) { operatorArgs.linewise = true; } + tmp.end.line--; + } + } else { + // No text object defined for this, don't move. + return null; + } + + if (!cm.state.vim.visualMode) { + return [tmp.start, tmp.end]; + } else { + return expandSelection(cm, tmp.start, tmp.end); + } + }, + + repeatLastCharacterSearch: function(cm, head, motionArgs) { + var lastSearch = vimGlobalState.lastChararacterSearch; + var repeat = motionArgs.repeat; + var forward = motionArgs.forward === lastSearch.forward; + var increment = (lastSearch.increment ? 1 : 0) * (forward ? -1 : 1); + cm.moveH(-increment, 'char'); + motionArgs.inclusive = forward ? true : false; + var curEnd = moveToCharacter(cm, repeat, forward, lastSearch.selectedCharacter); + if (!curEnd) { + cm.moveH(increment, 'char'); + return head; + } + curEnd.ch += increment; + return curEnd; + } + }; + + function fillArray(val, times) { + var arr = []; + for (var i = 0; i < times; i++) { + arr.push(val); + } + return arr; + } + /** + * An operator acts on a text selection. It receives the list of selections + * as input. The corresponding CodeMirror selection is guaranteed to + * match the input selection. + */ + var operators = { + change: function(cm, args, ranges) { + var finalHead, text; + var vim = cm.state.vim; + vimGlobalState.macroModeState.lastInsertModeChanges.inVisualBlock = vim.visualBlock; + if (!vim.visualMode) { + var anchor = ranges[0].anchor, + head = ranges[0].head; + text = cm.getRange(anchor, head); + if (!isWhiteSpaceString(text)) { + // Exclude trailing whitespace if the range is not all whitespace. + var match = (/\s+$/).exec(text); + if (match) { + head = offsetCursor(head, 0, - match[0].length); + text = text.slice(0, - match[0].length); + } + } + var wasLastLine = head.line - 1 == cm.lastLine(); + cm.replaceRange('', anchor, head); + if (args.linewise && !wasLastLine) { + // Push the next line back down, if there is a next line. + CodeMirror.commands.newlineAndIndent(cm); + // null ch so setCursor moves to end of line. + anchor.ch = null; + } + finalHead = anchor; + } else { + text = cm.getSelection(); + var replacement = fillArray('', ranges.length); + cm.replaceSelections(replacement); + finalHead = cursorMin(ranges[0].head, ranges[0].anchor); + } + vimGlobalState.registerController.pushText( + args.registerName, 'change', text, + args.linewise, ranges.length > 1); + actions.enterInsertMode(cm, {head: finalHead}, cm.state.vim); + }, + // delete is a javascript keyword. + 'delete': function(cm, args, ranges) { + var finalHead, text; + var vim = cm.state.vim; + if (!vim.visualBlock) { + var anchor = ranges[0].anchor, + head = ranges[0].head; + if (args.linewise && + head.line != cm.firstLine() && + anchor.line == cm.lastLine() && + anchor.line == head.line - 1) { + // Special case for dd on last line (and first line). + if (anchor.line == cm.firstLine()) { + anchor.ch = 0; + } else { + anchor = Pos(anchor.line - 1, lineLength(cm, anchor.line - 1)); + } + } + text = cm.getRange(anchor, head); + cm.replaceRange('', anchor, head); + finalHead = anchor; + if (args.linewise) { + finalHead = motions.moveToFirstNonWhiteSpaceCharacter(cm, anchor); + } + } else { + text = cm.getSelection(); + var replacement = fillArray('', ranges.length); + cm.replaceSelections(replacement); + finalHead = ranges[0].anchor; + } + vimGlobalState.registerController.pushText( + args.registerName, 'delete', text, + args.linewise, vim.visualBlock); + return finalHead; + }, + indent: function(cm, args, ranges) { + var vim = cm.state.vim; + var startLine = ranges[0].anchor.line; + var endLine = vim.visualBlock ? + ranges[ranges.length - 1].anchor.line : + ranges[0].head.line; + // In visual mode, n> shifts the selection right n times, instead of + // shifting n lines right once. + var repeat = (vim.visualMode) ? args.repeat : 1; + if (args.linewise) { + // The only way to delete a newline is to delete until the start of + // the next line, so in linewise mode evalInput will include the next + // line. We don't want this in indent, so we go back a line. + endLine--; + } + for (var i = startLine; i <= endLine; i++) { + for (var j = 0; j < repeat; j++) { + cm.indentLine(i, args.indentRight); + } + } + return motions.moveToFirstNonWhiteSpaceCharacter(cm, ranges[0].anchor); + }, + changeCase: function(cm, args, ranges, oldAnchor, newHead) { + var selections = cm.getSelections(); + var swapped = []; + var toLower = args.toLower; + for (var j = 0; j < selections.length; j++) { + var toSwap = selections[j]; + var text = ''; + if (toLower === true) { + text = toSwap.toLowerCase(); + } else if (toLower === false) { + text = toSwap.toUpperCase(); + } else { + for (var i = 0; i < toSwap.length; i++) { + var character = toSwap.charAt(i); + text += isUpperCase(character) ? character.toLowerCase() : + character.toUpperCase(); + } + } + swapped.push(text); + } + cm.replaceSelections(swapped); + if (args.shouldMoveCursor){ + return newHead; + } else if (!cm.state.vim.visualMode && args.linewise && ranges[0].anchor.line + 1 == ranges[0].head.line) { + return motions.moveToFirstNonWhiteSpaceCharacter(cm, oldAnchor); + } else if (args.linewise){ + return oldAnchor; + } else { + return cursorMin(ranges[0].anchor, ranges[0].head); + } + }, + yank: function(cm, args, ranges, oldAnchor) { + var vim = cm.state.vim; + var text = cm.getSelection(); + var endPos = vim.visualMode + ? cursorMin(vim.sel.anchor, vim.sel.head, ranges[0].head, ranges[0].anchor) + : oldAnchor; + vimGlobalState.registerController.pushText( + args.registerName, 'yank', + text, args.linewise, vim.visualBlock); + return endPos; + } + }; + + var actions = { + jumpListWalk: function(cm, actionArgs, vim) { + if (vim.visualMode) { + return; + } + var repeat = actionArgs.repeat; + var forward = actionArgs.forward; + var jumpList = vimGlobalState.jumpList; + + var mark = jumpList.move(cm, forward ? repeat : -repeat); + var markPos = mark ? mark.find() : undefined; + markPos = markPos ? markPos : cm.getCursor(); + cm.setCursor(markPos); + cm.ace.curOp.command.scrollIntoView = "center-animate"; // ace patch + }, + scroll: function(cm, actionArgs, vim) { + if (vim.visualMode) { + return; + } + var repeat = actionArgs.repeat || 1; + var lineHeight = cm.defaultTextHeight(); + var top = cm.getScrollInfo().top; + var delta = lineHeight * repeat; + var newPos = actionArgs.forward ? top + delta : top - delta; + var cursor = copyCursor(cm.getCursor()); + var cursorCoords = cm.charCoords(cursor, 'local'); + if (actionArgs.forward) { + if (newPos > cursorCoords.top) { + cursor.line += (newPos - cursorCoords.top) / lineHeight; + cursor.line = Math.ceil(cursor.line); + cm.setCursor(cursor); + cursorCoords = cm.charCoords(cursor, 'local'); + cm.scrollTo(null, cursorCoords.top); + } else { + // Cursor stays within bounds. Just reposition the scroll window. + cm.scrollTo(null, newPos); + } + } else { + var newBottom = newPos + cm.getScrollInfo().clientHeight; + if (newBottom < cursorCoords.bottom) { + cursor.line -= (cursorCoords.bottom - newBottom) / lineHeight; + cursor.line = Math.floor(cursor.line); + cm.setCursor(cursor); + cursorCoords = cm.charCoords(cursor, 'local'); + cm.scrollTo( + null, cursorCoords.bottom - cm.getScrollInfo().clientHeight); + } else { + // Cursor stays within bounds. Just reposition the scroll window. + cm.scrollTo(null, newPos); + } + } + }, + scrollToCursor: function(cm, actionArgs) { + var lineNum = cm.getCursor().line; + var charCoords = cm.charCoords(Pos(lineNum, 0), 'local'); + var height = cm.getScrollInfo().clientHeight; + var y = charCoords.top; + var lineHeight = charCoords.bottom - y; + switch (actionArgs.position) { + case 'center': y = y - (height / 2) + lineHeight; + break; + case 'bottom': y = y - height + lineHeight*1.4; + break; + case 'top': y = y + lineHeight*0.4; + break; + } + cm.scrollTo(null, y); + }, + replayMacro: function(cm, actionArgs, vim) { + var registerName = actionArgs.selectedCharacter; + var repeat = actionArgs.repeat; + var macroModeState = vimGlobalState.macroModeState; + if (registerName == '@') { + registerName = macroModeState.latestRegister; + } + while(repeat--){ + executeMacroRegister(cm, vim, macroModeState, registerName); + } + }, + enterMacroRecordMode: function(cm, actionArgs) { + var macroModeState = vimGlobalState.macroModeState; + var registerName = actionArgs.selectedCharacter; + macroModeState.enterMacroRecordMode(cm, registerName); + }, + enterInsertMode: function(cm, actionArgs, vim) { + if (cm.getOption('readOnly')) { return; } + vim.insertMode = true; + vim.insertModeRepeat = actionArgs && actionArgs.repeat || 1; + var insertAt = (actionArgs) ? actionArgs.insertAt : null; + var sel = vim.sel; + var head = actionArgs.head || cm.getCursor('head'); + var height = cm.listSelections().length; + if (insertAt == 'eol') { + head = Pos(head.line, lineLength(cm, head.line)); + } else if (insertAt == 'charAfter') { + head = offsetCursor(head, 0, 1); + } else if (insertAt == 'firstNonBlank') { + head = motions.moveToFirstNonWhiteSpaceCharacter(cm, head); + } else if (insertAt == 'startOfSelectedArea') { + if (!vim.visualBlock) { + if (sel.head.line < sel.anchor.line) { + head = sel.head; + } else { + head = Pos(sel.anchor.line, 0); + } + } else { + head = Pos( + Math.min(sel.head.line, sel.anchor.line), + Math.min(sel.head.ch, sel.anchor.ch)); + height = Math.abs(sel.head.line - sel.anchor.line) + 1; + } + } else if (insertAt == 'endOfSelectedArea') { + if (!vim.visualBlock) { + if (sel.head.line >= sel.anchor.line) { + head = offsetCursor(sel.head, 0, 1); + } else { + head = Pos(sel.anchor.line, 0); + } + } else { + head = Pos( + Math.min(sel.head.line, sel.anchor.line), + Math.max(sel.head.ch + 1, sel.anchor.ch)); + height = Math.abs(sel.head.line - sel.anchor.line) + 1; + } + } else if (insertAt == 'inplace') { + if (vim.visualMode){ + return; + } + } + cm.setOption('keyMap', 'vim-insert'); + cm.setOption('disableInput', false); + if (actionArgs && actionArgs.replace) { + // Handle Replace-mode as a special case of insert mode. + cm.toggleOverwrite(true); + cm.setOption('keyMap', 'vim-replace'); + CodeMirror.signal(cm, "vim-mode-change", {mode: "replace"}); + } else { + cm.setOption('keyMap', 'vim-insert'); + CodeMirror.signal(cm, "vim-mode-change", {mode: "insert"}); + } + if (!vimGlobalState.macroModeState.isPlaying) { + // Only record if not replaying. + cm.on('change', onChange); + CodeMirror.on(cm.getInputField(), 'keydown', onKeyEventTargetKeyDown); + } + if (vim.visualMode) { + exitVisualMode(cm); + } + selectForInsert(cm, head, height); + }, + toggleVisualMode: function(cm, actionArgs, vim) { + var repeat = actionArgs.repeat; + var anchor = cm.getCursor(); + var head; + // TODO: The repeat should actually select number of characters/lines + // equal to the repeat times the size of the previous visual + // operation. + if (!vim.visualMode) { + // Entering visual mode + vim.visualMode = true; + vim.visualLine = !!actionArgs.linewise; + vim.visualBlock = !!actionArgs.blockwise; + head = clipCursorToContent( + cm, Pos(anchor.line, anchor.ch + repeat - 1), + true /** includeLineBreak */); + vim.sel = { + anchor: anchor, + head: head + }; + CodeMirror.signal(cm, "vim-mode-change", {mode: "visual", subMode: vim.visualLine ? "linewise" : vim.visualBlock ? "blockwise" : ""}); + updateCmSelection(cm); + updateMark(cm, vim, '<', cursorMin(anchor, head)); + updateMark(cm, vim, '>', cursorMax(anchor, head)); + } else if (vim.visualLine ^ actionArgs.linewise || + vim.visualBlock ^ actionArgs.blockwise) { + // Toggling between modes + vim.visualLine = !!actionArgs.linewise; + vim.visualBlock = !!actionArgs.blockwise; + CodeMirror.signal(cm, "vim-mode-change", {mode: "visual", subMode: vim.visualLine ? "linewise" : vim.visualBlock ? "blockwise" : ""}); + updateCmSelection(cm); + } else { + exitVisualMode(cm); + } + }, + reselectLastSelection: function(cm, _actionArgs, vim) { + var lastSelection = vim.lastSelection; + if (vim.visualMode) { + updateLastSelection(cm, vim); + } + if (lastSelection) { + var anchor = lastSelection.anchorMark.find(); + var head = lastSelection.headMark.find(); + if (!anchor || !head) { + // If the marks have been destroyed due to edits, do nothing. + return; + } + vim.sel = { + anchor: anchor, + head: head + }; + vim.visualMode = true; + vim.visualLine = lastSelection.visualLine; + vim.visualBlock = lastSelection.visualBlock; + updateCmSelection(cm); + updateMark(cm, vim, '<', cursorMin(anchor, head)); + updateMark(cm, vim, '>', cursorMax(anchor, head)); + CodeMirror.signal(cm, 'vim-mode-change', { + mode: 'visual', + subMode: vim.visualLine ? 'linewise' : + vim.visualBlock ? 'blockwise' : ''}); + } + }, + joinLines: function(cm, actionArgs, vim) { + var curStart, curEnd; + if (vim.visualMode) { + curStart = cm.getCursor('anchor'); + curEnd = cm.getCursor('head'); + curEnd.ch = lineLength(cm, curEnd.line) - 1; + } else { + // Repeat is the number of lines to join. Minimum 2 lines. + var repeat = Math.max(actionArgs.repeat, 2); + curStart = cm.getCursor(); + curEnd = clipCursorToContent(cm, Pos(curStart.line + repeat - 1, + Infinity)); + } + var finalCh = 0; + for (var i = curStart.line; i < curEnd.line; i++) { + finalCh = lineLength(cm, curStart.line); + var tmp = Pos(curStart.line + 1, + lineLength(cm, curStart.line + 1)); + var text = cm.getRange(curStart, tmp); + text = text.replace(/\n\s*/g, ' '); + cm.replaceRange(text, curStart, tmp); + } + var curFinalPos = Pos(curStart.line, finalCh); + cm.setCursor(curFinalPos); + if (vim.visualMode) { + exitVisualMode(cm); + } + }, + newLineAndEnterInsertMode: function(cm, actionArgs, vim) { + vim.insertMode = true; + var insertAt = copyCursor(cm.getCursor()); + if (insertAt.line === cm.firstLine() && !actionArgs.after) { + // Special case for inserting newline before start of document. + cm.replaceRange('\n', Pos(cm.firstLine(), 0)); + cm.setCursor(cm.firstLine(), 0); + } else { + insertAt.line = (actionArgs.after) ? insertAt.line : + insertAt.line - 1; + insertAt.ch = lineLength(cm, insertAt.line); + cm.setCursor(insertAt); + var newlineFn = CodeMirror.commands.newlineAndIndentContinueComment || + CodeMirror.commands.newlineAndIndent; + newlineFn(cm); + } + this.enterInsertMode(cm, { repeat: actionArgs.repeat }, vim); + }, + paste: function(cm, actionArgs, vim) { + var cur = copyCursor(cm.getCursor()); + var register = vimGlobalState.registerController.getRegister( + actionArgs.registerName); + var text = register.toString(); + if (!text) { + return; + } + if (actionArgs.matchIndent) { + var tabSize = cm.getOption("tabSize"); + // length that considers tabs and tabSize + var whitespaceLength = function(str) { + var tabs = (str.split("\t").length - 1); + var spaces = (str.split(" ").length - 1); + return tabs * tabSize + spaces * 1; + }; + var currentLine = cm.getLine(cm.getCursor().line); + var indent = whitespaceLength(currentLine.match(/^\s*/)[0]); + // chomp last newline b/c don't want it to match /^\s*/gm + var chompedText = text.replace(/\n$/, ''); + var wasChomped = text !== chompedText; + var firstIndent = whitespaceLength(text.match(/^\s*/)[0]); + var text = chompedText.replace(/^\s*/gm, function(wspace) { + var newIndent = indent + (whitespaceLength(wspace) - firstIndent); + if (newIndent < 0) { + return ""; + } + else if (cm.getOption("indentWithTabs")) { + var quotient = Math.floor(newIndent / tabSize); + return Array(quotient + 1).join('\t'); + } + else { + return Array(newIndent + 1).join(' '); + } + }); + text += wasChomped ? "\n" : ""; + } + if (actionArgs.repeat > 1) { + var text = Array(actionArgs.repeat + 1).join(text); + } + var linewise = register.linewise; + var blockwise = register.blockwise; + if (linewise) { + if(vim.visualMode) { + text = vim.visualLine ? text.slice(0, -1) : '\n' + text.slice(0, text.length - 1) + '\n'; + } else if (actionArgs.after) { + // Move the newline at the end to the start instead, and paste just + // before the newline character of the line we are on right now. + text = '\n' + text.slice(0, text.length - 1); + cur.ch = lineLength(cm, cur.line); + } else { + cur.ch = 0; + } + } else { + if (blockwise) { + text = text.split('\n'); + for (var i = 0; i < text.length; i++) { + text[i] = (text[i] == '') ? ' ' : text[i]; + } + } + cur.ch += actionArgs.after ? 1 : 0; + } + var curPosFinal; + var idx; + if (vim.visualMode) { + // save the pasted text for reselection if the need arises + vim.lastPastedText = text; + var lastSelectionCurEnd; + var selectedArea = getSelectedAreaRange(cm, vim); + var selectionStart = selectedArea[0]; + var selectionEnd = selectedArea[1]; + var selectedText = cm.getSelection(); + var selections = cm.listSelections(); + var emptyStrings = new Array(selections.length).join('1').split('1'); + // save the curEnd marker before it get cleared due to cm.replaceRange. + if (vim.lastSelection) { + lastSelectionCurEnd = vim.lastSelection.headMark.find(); + } + // push the previously selected text to unnamed register + vimGlobalState.registerController.unnamedRegister.setText(selectedText); + if (blockwise) { + // first delete the selected text + cm.replaceSelections(emptyStrings); + // Set new selections as per the block length of the yanked text + selectionEnd = Pos(selectionStart.line + text.length-1, selectionStart.ch); + cm.setCursor(selectionStart); + selectBlock(cm, selectionEnd); + cm.replaceSelections(text); + curPosFinal = selectionStart; + } else if (vim.visualBlock) { + cm.replaceSelections(emptyStrings); + cm.setCursor(selectionStart); + cm.replaceRange(text, selectionStart, selectionStart); + curPosFinal = selectionStart; + } else { + cm.replaceRange(text, selectionStart, selectionEnd); + curPosFinal = cm.posFromIndex(cm.indexFromPos(selectionStart) + text.length - 1); + } + // restore the the curEnd marker + if(lastSelectionCurEnd) { + vim.lastSelection.headMark = cm.setBookmark(lastSelectionCurEnd); + } + if (linewise) { + curPosFinal.ch=0; + } + } else { + if (blockwise) { + cm.setCursor(cur); + for (var i = 0; i < text.length; i++) { + var line = cur.line+i; + if (line > cm.lastLine()) { + cm.replaceRange('\n', Pos(line, 0)); + } + var lastCh = lineLength(cm, line); + if (lastCh < cur.ch) { + extendLineToColumn(cm, line, cur.ch); + } + } + cm.setCursor(cur); + selectBlock(cm, Pos(cur.line + text.length-1, cur.ch)); + cm.replaceSelections(text); + curPosFinal = cur; + } else { + cm.replaceRange(text, cur); + // Now fine tune the cursor to where we want it. + if (linewise && actionArgs.after) { + curPosFinal = Pos( + cur.line + 1, + findFirstNonWhiteSpaceCharacter(cm.getLine(cur.line + 1))); + } else if (linewise && !actionArgs.after) { + curPosFinal = Pos( + cur.line, + findFirstNonWhiteSpaceCharacter(cm.getLine(cur.line))); + } else if (!linewise && actionArgs.after) { + idx = cm.indexFromPos(cur); + curPosFinal = cm.posFromIndex(idx + text.length - 1); + } else { + idx = cm.indexFromPos(cur); + curPosFinal = cm.posFromIndex(idx + text.length); + } + } + } + if (vim.visualMode) { + exitVisualMode(cm); + } + cm.setCursor(curPosFinal); + }, + undo: function(cm, actionArgs) { + cm.operation(function() { + repeatFn(cm, CodeMirror.commands.undo, actionArgs.repeat)(); + cm.setCursor(cm.getCursor('anchor')); + }); + }, + redo: function(cm, actionArgs) { + repeatFn(cm, CodeMirror.commands.redo, actionArgs.repeat)(); + }, + setRegister: function(_cm, actionArgs, vim) { + vim.inputState.registerName = actionArgs.selectedCharacter; + }, + setMark: function(cm, actionArgs, vim) { + var markName = actionArgs.selectedCharacter; + updateMark(cm, vim, markName, cm.getCursor()); + }, + replace: function(cm, actionArgs, vim) { + var replaceWith = actionArgs.selectedCharacter; + var curStart = cm.getCursor(); + var replaceTo; + var curEnd; + var selections = cm.listSelections(); + if (vim.visualMode) { + curStart = cm.getCursor('start'); + curEnd = cm.getCursor('end'); + } else { + var line = cm.getLine(curStart.line); + replaceTo = curStart.ch + actionArgs.repeat; + if (replaceTo > line.length) { + replaceTo=line.length; + } + curEnd = Pos(curStart.line, replaceTo); + } + if (replaceWith=='\n') { + if (!vim.visualMode) cm.replaceRange('', curStart, curEnd); + // special case, where vim help says to replace by just one line-break + (CodeMirror.commands.newlineAndIndentContinueComment || CodeMirror.commands.newlineAndIndent)(cm); + } else { + var replaceWithStr = cm.getRange(curStart, curEnd); + //replace all characters in range by selected, but keep linebreaks + replaceWithStr = replaceWithStr.replace(/[^\n]/g, replaceWith); + if (vim.visualBlock) { + // Tabs are split in visua block before replacing + var spaces = new Array(cm.getOption("tabSize")+1).join(' '); + replaceWithStr = cm.getSelection(); + replaceWithStr = replaceWithStr.replace(/\t/g, spaces).replace(/[^\n]/g, replaceWith).split('\n'); + cm.replaceSelections(replaceWithStr); + } else { + cm.replaceRange(replaceWithStr, curStart, curEnd); + } + if (vim.visualMode) { + curStart = cursorIsBefore(selections[0].anchor, selections[0].head) ? + selections[0].anchor : selections[0].head; + cm.setCursor(curStart); + exitVisualMode(cm); + } else { + cm.setCursor(offsetCursor(curEnd, 0, -1)); + } + } + }, + incrementNumberToken: function(cm, actionArgs) { + var cur = cm.getCursor(); + var lineStr = cm.getLine(cur.line); + var re = /-?\d+/g; + var match; + var start; + var end; + var numberStr; + var token; + while ((match = re.exec(lineStr)) !== null) { + token = match[0]; + start = match.index; + end = start + token.length; + if (cur.ch < end)break; + } + if (!actionArgs.backtrack && (end <= cur.ch))return; + if (token) { + var increment = actionArgs.increase ? 1 : -1; + var number = parseInt(token) + (increment * actionArgs.repeat); + var from = Pos(cur.line, start); + var to = Pos(cur.line, end); + numberStr = number.toString(); + cm.replaceRange(numberStr, from, to); + } else { + return; + } + cm.setCursor(Pos(cur.line, start + numberStr.length - 1)); + }, + repeatLastEdit: function(cm, actionArgs, vim) { + var lastEditInputState = vim.lastEditInputState; + if (!lastEditInputState) { return; } + var repeat = actionArgs.repeat; + if (repeat && actionArgs.repeatIsExplicit) { + vim.lastEditInputState.repeatOverride = repeat; + } else { + repeat = vim.lastEditInputState.repeatOverride || repeat; + } + repeatLastEdit(cm, vim, repeat, false /** repeatForInsert */); + }, + exitInsertMode: exitInsertMode + }; + + /* + * Below are miscellaneous utility functions used by vim.js + */ + + /** + * Clips cursor to ensure that line is within the buffer's range + * If includeLineBreak is true, then allow cur.ch == lineLength. + */ + function clipCursorToContent(cm, cur, includeLineBreak) { + var line = Math.min(Math.max(cm.firstLine(), cur.line), cm.lastLine() ); + var maxCh = lineLength(cm, line) - 1; + maxCh = (includeLineBreak) ? maxCh + 1 : maxCh; + var ch = Math.min(Math.max(0, cur.ch), maxCh); + return Pos(line, ch); + } + function copyArgs(args) { + var ret = {}; + for (var prop in args) { + if (args.hasOwnProperty(prop)) { + ret[prop] = args[prop]; + } + } + return ret; + } + function offsetCursor(cur, offsetLine, offsetCh) { + if (typeof offsetLine === 'object') { + offsetCh = offsetLine.ch; + offsetLine = offsetLine.line; + } + return Pos(cur.line + offsetLine, cur.ch + offsetCh); + } + function getOffset(anchor, head) { + return { + line: head.line - anchor.line, + ch: head.line - anchor.line + }; + } + function commandMatches(keys, keyMap, context, inputState) { + // Partial matches are not applied. They inform the key handler + // that the current key sequence is a subsequence of a valid key + // sequence, so that the key buffer is not cleared. + var match, partial = [], full = []; + for (var i = 0; i < keyMap.length; i++) { + var command = keyMap[i]; + if (context == 'insert' && command.context != 'insert' || + command.context && command.context != context || + inputState.operator && command.type == 'action' || + !(match = commandMatch(keys, command.keys))) { continue; } + if (match == 'partial') { partial.push(command); } + if (match == 'full') { full.push(command); } + } + return { + partial: partial.length && partial, + full: full.length && full + }; + } + function commandMatch(pressed, mapped) { + if (mapped.slice(-11) == '') { + // Last character matches anything. + var prefixLen = mapped.length - 11; + var pressedPrefix = pressed.slice(0, prefixLen); + var mappedPrefix = mapped.slice(0, prefixLen); + return pressedPrefix == mappedPrefix && pressed.length > prefixLen ? 'full' : + mappedPrefix.indexOf(pressedPrefix) == 0 ? 'partial' : false; + } else { + return pressed == mapped ? 'full' : + mapped.indexOf(pressed) == 0 ? 'partial' : false; + } + } + function lastChar(keys) { + var match = /^.*(<[\w\-]+>)$/.exec(keys); + var selectedCharacter = match ? match[1] : keys.slice(-1); + if (selectedCharacter.length > 1){ + switch(selectedCharacter){ + case '': + selectedCharacter='\n'; + break; + case '': + selectedCharacter=' '; + break; + default: + break; + } + } + return selectedCharacter; + } + function repeatFn(cm, fn, repeat) { + return function() { + for (var i = 0; i < repeat; i++) { + fn(cm); + } + }; + } + function copyCursor(cur) { + return Pos(cur.line, cur.ch); + } + function cursorEqual(cur1, cur2) { + return cur1.ch == cur2.ch && cur1.line == cur2.line; + } + function cursorIsBefore(cur1, cur2) { + if (cur1.line < cur2.line) { + return true; + } + if (cur1.line == cur2.line && cur1.ch < cur2.ch) { + return true; + } + return false; + } + function cursorMin(cur1, cur2) { + if (arguments.length > 2) { + cur2 = cursorMin.apply(undefined, Array.prototype.slice.call(arguments, 1)); + } + return cursorIsBefore(cur1, cur2) ? cur1 : cur2; + } + function cursorMax(cur1, cur2) { + if (arguments.length > 2) { + cur2 = cursorMax.apply(undefined, Array.prototype.slice.call(arguments, 1)); + } + return cursorIsBefore(cur1, cur2) ? cur2 : cur1; + } + function cursorIsBetween(cur1, cur2, cur3) { + // returns true if cur2 is between cur1 and cur3. + var cur1before2 = cursorIsBefore(cur1, cur2); + var cur2before3 = cursorIsBefore(cur2, cur3); + return cur1before2 && cur2before3; + } + function lineLength(cm, lineNum) { + return cm.getLine(lineNum).length; + } + function reverse(s){ + return s.split('').reverse().join(''); + } + function trim(s) { + if (s.trim) { + return s.trim(); + } + return s.replace(/^\s+|\s+$/g, ''); + } + function escapeRegex(s) { + return s.replace(/([.?*+$\[\]\/\\(){}|\-])/g, '\\$1'); + } + function extendLineToColumn(cm, lineNum, column) { + var endCh = lineLength(cm, lineNum); + var spaces = new Array(column-endCh+1).join(' '); + cm.setCursor(Pos(lineNum, endCh)); + cm.replaceRange(spaces, cm.getCursor()); + } + // This functions selects a rectangular block + // of text with selectionEnd as any of its corner + // Height of block: + // Difference in selectionEnd.line and first/last selection.line + // Width of the block: + // Distance between selectionEnd.ch and any(first considered here) selection.ch + function selectBlock(cm, selectionEnd) { + var selections = [], ranges = cm.listSelections(); + var head = copyCursor(cm.clipPos(selectionEnd)); + var isClipped = !cursorEqual(selectionEnd, head); + var curHead = cm.getCursor('head'); + var primIndex = getIndex(ranges, curHead); + var wasClipped = cursorEqual(ranges[primIndex].head, ranges[primIndex].anchor); + var max = ranges.length - 1; + var index = max - primIndex > primIndex ? max : 0; + var base = ranges[index].anchor; + + var firstLine = Math.min(base.line, head.line); + var lastLine = Math.max(base.line, head.line); + var baseCh = base.ch, headCh = head.ch; + + var dir = ranges[index].head.ch - baseCh; + var newDir = headCh - baseCh; + if (dir > 0 && newDir <= 0) { + baseCh++; + if (!isClipped) { headCh--; } + } else if (dir < 0 && newDir >= 0) { + baseCh--; + if (!wasClipped) { headCh++; } + } else if (dir < 0 && newDir == -1) { + baseCh--; + headCh++; + } + for (var line = firstLine; line <= lastLine; line++) { + var range = {anchor: new Pos(line, baseCh), head: new Pos(line, headCh)}; + selections.push(range); + } + primIndex = head.line == lastLine ? selections.length - 1 : 0; + cm.setSelections(selections); + selectionEnd.ch = headCh; + base.ch = baseCh; + return base; + } + function selectForInsert(cm, head, height) { + var sel = []; + for (var i = 0; i < height; i++) { + var lineHead = offsetCursor(head, i, 0); + sel.push({anchor: lineHead, head: lineHead}); + } + cm.setSelections(sel, 0); + } + // getIndex returns the index of the cursor in the selections. + function getIndex(ranges, cursor, end) { + for (var i = 0; i < ranges.length; i++) { + var atAnchor = end != 'head' && cursorEqual(ranges[i].anchor, cursor); + var atHead = end != 'anchor' && cursorEqual(ranges[i].head, cursor); + if (atAnchor || atHead) { + return i; + } + } + return -1; + } + function getSelectedAreaRange(cm, vim) { + var lastSelection = vim.lastSelection; + var getCurrentSelectedAreaRange = function() { + var selections = cm.listSelections(); + var start = selections[0]; + var end = selections[selections.length-1]; + var selectionStart = cursorIsBefore(start.anchor, start.head) ? start.anchor : start.head; + var selectionEnd = cursorIsBefore(end.anchor, end.head) ? end.head : end.anchor; + return [selectionStart, selectionEnd]; + }; + var getLastSelectedAreaRange = function() { + var selectionStart = cm.getCursor(); + var selectionEnd = cm.getCursor(); + var block = lastSelection.visualBlock; + if (block) { + var width = block.width; + var height = block.height; + selectionEnd = Pos(selectionStart.line + height, selectionStart.ch + width); + var selections = []; + // selectBlock creates a 'proper' rectangular block. + // We do not want that in all cases, so we manually set selections. + for (var i = selectionStart.line; i < selectionEnd.line; i++) { + var anchor = Pos(i, selectionStart.ch); + var head = Pos(i, selectionEnd.ch); + var range = {anchor: anchor, head: head}; + selections.push(range); + } + cm.setSelections(selections); + } else { + var start = lastSelection.anchorMark.find(); + var end = lastSelection.headMark.find(); + var line = end.line - start.line; + var ch = end.ch - start.ch; + selectionEnd = {line: selectionEnd.line + line, ch: line ? selectionEnd.ch : ch + selectionEnd.ch}; + if (lastSelection.visualLine) { + selectionStart = Pos(selectionStart.line, 0); + selectionEnd = Pos(selectionEnd.line, lineLength(cm, selectionEnd.line)); + } + cm.setSelection(selectionStart, selectionEnd); + } + return [selectionStart, selectionEnd]; + }; + if (!vim.visualMode) { + // In case of replaying the action. + return getLastSelectedAreaRange(); + } else { + return getCurrentSelectedAreaRange(); + } + } + // Updates the previous selection with the current selection's values. This + // should only be called in visual mode. + function updateLastSelection(cm, vim) { + var anchor = vim.sel.anchor; + var head = vim.sel.head; + // To accommodate the effect of lastPastedText in the last selection + if (vim.lastPastedText) { + head = cm.posFromIndex(cm.indexFromPos(anchor) + vim.lastPastedText.length); + vim.lastPastedText = null; + } + vim.lastSelection = {'anchorMark': cm.setBookmark(anchor), + 'headMark': cm.setBookmark(head), + 'anchor': copyCursor(anchor), + 'head': copyCursor(head), + 'visualMode': vim.visualMode, + 'visualLine': vim.visualLine, + 'visualBlock': vim.visualBlock}; + } + function expandSelection(cm, start, end) { + var sel = cm.state.vim.sel; + var head = sel.head; + var anchor = sel.anchor; + var tmp; + if (cursorIsBefore(end, start)) { + tmp = end; + end = start; + start = tmp; + } + if (cursorIsBefore(head, anchor)) { + head = cursorMin(start, head); + anchor = cursorMax(anchor, end); + } else { + anchor = cursorMin(start, anchor); + head = cursorMax(head, end); + head = offsetCursor(head, 0, -1); + if (head.ch == -1 && head.line != cm.firstLine()) { + head = Pos(head.line - 1, lineLength(cm, head.line - 1)); + } + } + return [anchor, head]; + } + /** + * Updates the CodeMirror selection to match the provided vim selection. + * If no arguments are given, it uses the current vim selection state. + */ + function updateCmSelection(cm, sel, mode) { + var vim = cm.state.vim; + sel = sel || vim.sel; + var mode = mode || + vim.visualLine ? 'line' : vim.visualBlock ? 'block' : 'char'; + var cmSel = makeCmSelection(cm, sel, mode); + cm.setSelections(cmSel.ranges, cmSel.primary); + updateFakeCursor(cm); + } + function makeCmSelection(cm, sel, mode, exclusive) { + var head = copyCursor(sel.head); + var anchor = copyCursor(sel.anchor); + if (mode == 'char') { + var headOffset = !exclusive && !cursorIsBefore(sel.head, sel.anchor) ? 1 : 0; + var anchorOffset = cursorIsBefore(sel.head, sel.anchor) ? 1 : 0; + head = offsetCursor(sel.head, 0, headOffset); + anchor = offsetCursor(sel.anchor, 0, anchorOffset); + return { + ranges: [{anchor: anchor, head: head}], + primary: 0 + }; + } else if (mode == 'line') { + if (!cursorIsBefore(sel.head, sel.anchor)) { + anchor.ch = 0; + + var lastLine = cm.lastLine(); + if (head.line > lastLine) { + head.line = lastLine; + } + head.ch = lineLength(cm, head.line); + } else { + head.ch = 0; + anchor.ch = lineLength(cm, anchor.line); + } + return { + ranges: [{anchor: anchor, head: head}], + primary: 0 + }; + } else if (mode == 'block') { + var top = Math.min(anchor.line, head.line), + left = Math.min(anchor.ch, head.ch), + bottom = Math.max(anchor.line, head.line), + right = Math.max(anchor.ch, head.ch) + 1; + var height = bottom - top + 1; + var primary = head.line == top ? 0 : height - 1; + var ranges = []; + for (var i = 0; i < height; i++) { + ranges.push({ + anchor: Pos(top + i, left), + head: Pos(top + i, right) + }); + } + return { + ranges: ranges, + primary: primary + }; + } + } + function getHead(cm) { + var cur = cm.getCursor('head'); + if (cm.getSelection().length == 1) { + // Small corner case when only 1 character is selected. The "real" + // head is the left of head and anchor. + cur = cursorMin(cur, cm.getCursor('anchor')); + } + return cur; + } + + /** + * If moveHead is set to false, the CodeMirror selection will not be + * touched. The caller assumes the responsibility of putting the cursor + * in the right place. + */ + function exitVisualMode(cm, moveHead) { + var vim = cm.state.vim; + if (moveHead !== false) { + cm.setCursor(clipCursorToContent(cm, vim.sel.head)); + } + updateLastSelection(cm, vim); + vim.visualMode = false; + vim.visualLine = false; + vim.visualBlock = false; + CodeMirror.signal(cm, "vim-mode-change", {mode: "normal"}); + if (vim.fakeCursor) { + vim.fakeCursor.clear(); + } + } + + // Remove any trailing newlines from the selection. For + // example, with the caret at the start of the last word on the line, + // 'dw' should word, but not the newline, while 'w' should advance the + // caret to the first character of the next line. + function clipToLine(cm, curStart, curEnd) { + var selection = cm.getRange(curStart, curEnd); + // Only clip if the selection ends with trailing newline + whitespace + if (/\n\s*$/.test(selection)) { + var lines = selection.split('\n'); + // We know this is all whitepsace. + lines.pop(); + + // Cases: + // 1. Last word is an empty line - do not clip the trailing '\n' + // 2. Last word is not an empty line - clip the trailing '\n' + var line; + // Find the line containing the last word, and clip all whitespace up + // to it. + for (var line = lines.pop(); lines.length > 0 && line && isWhiteSpaceString(line); line = lines.pop()) { + curEnd.line--; + curEnd.ch = 0; + } + // If the last word is not an empty line, clip an additional newline + if (line) { + curEnd.line--; + curEnd.ch = lineLength(cm, curEnd.line); + } else { + curEnd.ch = 0; + } + } + } + + // Expand the selection to line ends. + function expandSelectionToLine(_cm, curStart, curEnd) { + curStart.ch = 0; + curEnd.ch = 0; + curEnd.line++; + } + + function findFirstNonWhiteSpaceCharacter(text) { + if (!text) { + return 0; + } + var firstNonWS = text.search(/\S/); + return firstNonWS == -1 ? text.length : firstNonWS; + } + + function expandWordUnderCursor(cm, inclusive, _forward, bigWord, noSymbol) { + var cur = getHead(cm); + var line = cm.getLine(cur.line); + var idx = cur.ch; + + // Seek to first word or non-whitespace character, depending on if + // noSymbol is true. + var textAfterIdx = line.substring(idx); + var firstMatchedChar; + if (noSymbol) { + firstMatchedChar = textAfterIdx.search(/\w/); + } else { + firstMatchedChar = textAfterIdx.search(/\S/); + } + if (firstMatchedChar == -1) { + return null; + } + idx += firstMatchedChar; + textAfterIdx = line.substring(idx); + var textBeforeIdx = line.substring(0, idx); + + var matchRegex; + // Greedy matchers for the "word" we are trying to expand. + if (bigWord) { + matchRegex = /^\S+/; + } else { + if ((/\w/).test(line.charAt(idx))) { + matchRegex = /^\w+/; + } else { + matchRegex = /^[^\w\s]+/; + } + } + + var wordAfterRegex = matchRegex.exec(textAfterIdx); + var wordStart = idx; + var wordEnd = idx + wordAfterRegex[0].length; + // TODO: Find a better way to do this. It will be slow on very long lines. + var revTextBeforeIdx = reverse(textBeforeIdx); + var wordBeforeRegex = matchRegex.exec(revTextBeforeIdx); + if (wordBeforeRegex) { + wordStart -= wordBeforeRegex[0].length; + } + + if (inclusive) { + // If present, trim all whitespace after word. + // Otherwise, trim all whitespace before word. + var textAfterWordEnd = line.substring(wordEnd); + var whitespacesAfterWord = textAfterWordEnd.match(/^\s*/)[0].length; + if (whitespacesAfterWord > 0) { + wordEnd += whitespacesAfterWord; + } else { + var revTrim = revTextBeforeIdx.length - wordStart; + var textBeforeWordStart = revTextBeforeIdx.substring(revTrim); + var whitespacesBeforeWord = textBeforeWordStart.match(/^\s*/)[0].length; + wordStart -= whitespacesBeforeWord; + } + } + + return { start: Pos(cur.line, wordStart), + end: Pos(cur.line, wordEnd) }; + } + + function recordJumpPosition(cm, oldCur, newCur) { + if (!cursorEqual(oldCur, newCur)) { + vimGlobalState.jumpList.add(cm, oldCur, newCur); + } + } + + function recordLastCharacterSearch(increment, args) { + vimGlobalState.lastChararacterSearch.increment = increment; + vimGlobalState.lastChararacterSearch.forward = args.forward; + vimGlobalState.lastChararacterSearch.selectedCharacter = args.selectedCharacter; + } + + var symbolToMode = { + '(': 'bracket', ')': 'bracket', '{': 'bracket', '}': 'bracket', + '[': 'section', ']': 'section', + '*': 'comment', '/': 'comment', + 'm': 'method', 'M': 'method', + '#': 'preprocess' + }; + var findSymbolModes = { + bracket: { + isComplete: function(state) { + if (state.nextCh === state.symb) { + state.depth++; + if (state.depth >= 1)return true; + } else if (state.nextCh === state.reverseSymb) { + state.depth--; + } + return false; + } + }, + section: { + init: function(state) { + state.curMoveThrough = true; + state.symb = (state.forward ? ']' : '[') === state.symb ? '{' : '}'; + }, + isComplete: function(state) { + return state.index === 0 && state.nextCh === state.symb; + } + }, + comment: { + isComplete: function(state) { + var found = state.lastCh === '*' && state.nextCh === '/'; + state.lastCh = state.nextCh; + return found; + } + }, + // TODO: The original Vim implementation only operates on level 1 and 2. + // The current implementation doesn't check for code block level and + // therefore it operates on any levels. + method: { + init: function(state) { + state.symb = (state.symb === 'm' ? '{' : '}'); + state.reverseSymb = state.symb === '{' ? '}' : '{'; + }, + isComplete: function(state) { + if (state.nextCh === state.symb)return true; + return false; + } + }, + preprocess: { + init: function(state) { + state.index = 0; + }, + isComplete: function(state) { + if (state.nextCh === '#') { + var token = state.lineText.match(/#(\w+)/)[1]; + if (token === 'endif') { + if (state.forward && state.depth === 0) { + return true; + } + state.depth++; + } else if (token === 'if') { + if (!state.forward && state.depth === 0) { + return true; + } + state.depth--; + } + if (token === 'else' && state.depth === 0)return true; + } + return false; + } + } + }; + function findSymbol(cm, repeat, forward, symb) { + var cur = copyCursor(cm.getCursor()); + var increment = forward ? 1 : -1; + var endLine = forward ? cm.lineCount() : -1; + var curCh = cur.ch; + var line = cur.line; + var lineText = cm.getLine(line); + var state = { + lineText: lineText, + nextCh: lineText.charAt(curCh), + lastCh: null, + index: curCh, + symb: symb, + reverseSymb: (forward ? { ')': '(', '}': '{' } : { '(': ')', '{': '}' })[symb], + forward: forward, + depth: 0, + curMoveThrough: false + }; + var mode = symbolToMode[symb]; + if (!mode)return cur; + var init = findSymbolModes[mode].init; + var isComplete = findSymbolModes[mode].isComplete; + if (init) { init(state); } + while (line !== endLine && repeat) { + state.index += increment; + state.nextCh = state.lineText.charAt(state.index); + if (!state.nextCh) { + line += increment; + state.lineText = cm.getLine(line) || ''; + if (increment > 0) { + state.index = 0; + } else { + var lineLen = state.lineText.length; + state.index = (lineLen > 0) ? (lineLen-1) : 0; + } + state.nextCh = state.lineText.charAt(state.index); + } + if (isComplete(state)) { + cur.line = line; + cur.ch = state.index; + repeat--; + } + } + if (state.nextCh || state.curMoveThrough) { + return Pos(line, state.index); + } + return cur; + } + + /* + * Returns the boundaries of the next word. If the cursor in the middle of + * the word, then returns the boundaries of the current word, starting at + * the cursor. If the cursor is at the start/end of a word, and we are going + * forward/backward, respectively, find the boundaries of the next word. + * + * @param {CodeMirror} cm CodeMirror object. + * @param {Cursor} cur The cursor position. + * @param {boolean} forward True to search forward. False to search + * backward. + * @param {boolean} bigWord True if punctuation count as part of the word. + * False if only [a-zA-Z0-9] characters count as part of the word. + * @param {boolean} emptyLineIsWord True if empty lines should be treated + * as words. + * @return {Object{from:number, to:number, line: number}} The boundaries of + * the word, or null if there are no more words. + */ + function findWord(cm, cur, forward, bigWord, emptyLineIsWord) { + var lineNum = cur.line; + var pos = cur.ch; + var line = cm.getLine(lineNum); + var dir = forward ? 1 : -1; + var regexps = bigWord ? bigWordRegexp : wordRegexp; + + if (emptyLineIsWord && line == '') { + lineNum += dir; + line = cm.getLine(lineNum); + if (!isLine(cm, lineNum)) { + return null; + } + pos = (forward) ? 0 : line.length; + } + + while (true) { + if (emptyLineIsWord && line == '') { + return { from: 0, to: 0, line: lineNum }; + } + var stop = (dir > 0) ? line.length : -1; + var wordStart = stop, wordEnd = stop; + // Find bounds of next word. + while (pos != stop) { + var foundWord = false; + for (var i = 0; i < regexps.length && !foundWord; ++i) { + if (regexps[i].test(line.charAt(pos))) { + wordStart = pos; + // Advance to end of word. + while (pos != stop && regexps[i].test(line.charAt(pos))) { + pos += dir; + } + wordEnd = pos; + foundWord = wordStart != wordEnd; + if (wordStart == cur.ch && lineNum == cur.line && + wordEnd == wordStart + dir) { + // We started at the end of a word. Find the next one. + continue; + } else { + return { + from: Math.min(wordStart, wordEnd + 1), + to: Math.max(wordStart, wordEnd), + line: lineNum }; + } + } + } + if (!foundWord) { + pos += dir; + } + } + // Advance to next/prev line. + lineNum += dir; + if (!isLine(cm, lineNum)) { + return null; + } + line = cm.getLine(lineNum); + pos = (dir > 0) ? 0 : line.length; + } + // Should never get here. + throw new Error('The impossible happened.'); + } + + /** + * @param {CodeMirror} cm CodeMirror object. + * @param {Pos} cur The position to start from. + * @param {int} repeat Number of words to move past. + * @param {boolean} forward True to search forward. False to search + * backward. + * @param {boolean} wordEnd True to move to end of word. False to move to + * beginning of word. + * @param {boolean} bigWord True if punctuation count as part of the word. + * False if only alphabet characters count as part of the word. + * @return {Cursor} The position the cursor should move to. + */ + function moveToWord(cm, cur, repeat, forward, wordEnd, bigWord) { + var curStart = copyCursor(cur); + var words = []; + if (forward && !wordEnd || !forward && wordEnd) { + repeat++; + } + // For 'e', empty lines are not considered words, go figure. + var emptyLineIsWord = !(forward && wordEnd); + for (var i = 0; i < repeat; i++) { + var word = findWord(cm, cur, forward, bigWord, emptyLineIsWord); + if (!word) { + var eodCh = lineLength(cm, cm.lastLine()); + words.push(forward + ? {line: cm.lastLine(), from: eodCh, to: eodCh} + : {line: 0, from: 0, to: 0}); + break; + } + words.push(word); + cur = Pos(word.line, forward ? (word.to - 1) : word.from); + } + var shortCircuit = words.length != repeat; + var firstWord = words[0]; + var lastWord = words.pop(); + if (forward && !wordEnd) { + // w + if (!shortCircuit && (firstWord.from != curStart.ch || firstWord.line != curStart.line)) { + // We did not start in the middle of a word. Discard the extra word at the end. + lastWord = words.pop(); + } + return Pos(lastWord.line, lastWord.from); + } else if (forward && wordEnd) { + return Pos(lastWord.line, lastWord.to - 1); + } else if (!forward && wordEnd) { + // ge + if (!shortCircuit && (firstWord.to != curStart.ch || firstWord.line != curStart.line)) { + // We did not start in the middle of a word. Discard the extra word at the end. + lastWord = words.pop(); + } + return Pos(lastWord.line, lastWord.to); + } else { + // b + return Pos(lastWord.line, lastWord.from); + } + } + + function moveToCharacter(cm, repeat, forward, character) { + var cur = cm.getCursor(); + var start = cur.ch; + var idx; + for (var i = 0; i < repeat; i ++) { + var line = cm.getLine(cur.line); + idx = charIdxInLine(start, line, character, forward, true); + if (idx == -1) { + return null; + } + start = idx; + } + return Pos(cm.getCursor().line, idx); + } + + function moveToColumn(cm, repeat) { + // repeat is always >= 1, so repeat - 1 always corresponds + // to the column we want to go to. + var line = cm.getCursor().line; + return clipCursorToContent(cm, Pos(line, repeat - 1)); + } + + function updateMark(cm, vim, markName, pos) { + if (!inArray(markName, validMarks)) { + return; + } + if (vim.marks[markName]) { + vim.marks[markName].clear(); + } + vim.marks[markName] = cm.setBookmark(pos); + } + + function charIdxInLine(start, line, character, forward, includeChar) { + // Search for char in line. + // motion_options: {forward, includeChar} + // If includeChar = true, include it too. + // If forward = true, search forward, else search backwards. + // If char is not found on this line, do nothing + var idx; + if (forward) { + idx = line.indexOf(character, start + 1); + if (idx != -1 && !includeChar) { + idx -= 1; + } + } else { + idx = line.lastIndexOf(character, start - 1); + if (idx != -1 && !includeChar) { + idx += 1; + } + } + return idx; + } + + function findParagraph(cm, head, repeat, dir, inclusive) { + var line = head.line; + var min = cm.firstLine(); + var max = cm.lastLine(); + var start, end, i = line; + function isEmpty(i) { return !/\S/.test(cm.getLine(i)); } + function isBoundary(i, dir, any) { + if (any) { return isEmpty(i) != isEmpty(i + dir); } + return !isEmpty(i) && isEmpty(i + dir); + } + if (dir) { + while (min <= i && i <= max && repeat > 0) { + if (isBoundary(i, dir)) { repeat--; } + i += dir; + } + return new Pos(i, 0); + } + + var vim = cm.state.vim; + if (vim.visualLine && isBoundary(line, 1, true)) { + var anchor = vim.sel.anchor; + if (isBoundary(anchor.line, -1, true)) { + if (!inclusive || anchor.line != line) { + line += 1; + } + } + } + var startState = isEmpty(line); + for (i = line; i <= max && repeat; i++) { + if (isBoundary(i, 1, true)) { + if (!inclusive || isEmpty(i) != startState) { + repeat--; + } + } + } + end = new Pos(i, 0); + // select boundary before paragraph for the last one + if (i > max && !startState) { startState = true; } + else { inclusive = false; } + for (i = line; i > min; i--) { + if (!inclusive || isEmpty(i) == startState || i == line) { + if (isBoundary(i, -1, true)) { break; } + } + } + start = new Pos(i, 0); + return { start: start, end: end }; + } + + // TODO: perhaps this finagling of start and end positions belonds + // in codmirror/replaceRange? + function selectCompanionObject(cm, head, symb, inclusive) { + var cur = head, start, end; + + var bracketRegexp = ({ + '(': /[()]/, ')': /[()]/, + '[': /[[\]]/, ']': /[[\]]/, + '{': /[{}]/, '}': /[{}]/})[symb]; + var openSym = ({ + '(': '(', ')': '(', + '[': '[', ']': '[', + '{': '{', '}': '{'})[symb]; + var curChar = cm.getLine(cur.line).charAt(cur.ch); + // Due to the behavior of scanForBracket, we need to add an offset if the + // cursor is on a matching open bracket. + var offset = curChar === openSym ? 1 : 0; + + start = cm.scanForBracket(Pos(cur.line, cur.ch + offset), -1, null, {'bracketRegex': bracketRegexp}); + end = cm.scanForBracket(Pos(cur.line, cur.ch + offset), 1, null, {'bracketRegex': bracketRegexp}); + + if (!start || !end) { + return { start: cur, end: cur }; + } + + start = start.pos; + end = end.pos; + + if ((start.line == end.line && start.ch > end.ch) + || (start.line > end.line)) { + var tmp = start; + start = end; + end = tmp; + } + + if (inclusive) { + end.ch += 1; + } else { + start.ch += 1; + } + + return { start: start, end: end }; + } + + // Takes in a symbol and a cursor and tries to simulate text objects that + // have identical opening and closing symbols + // TODO support across multiple lines + function findBeginningAndEnd(cm, head, symb, inclusive) { + var cur = copyCursor(head); + var line = cm.getLine(cur.line); + var chars = line.split(''); + var start, end, i, len; + var firstIndex = chars.indexOf(symb); + + // the decision tree is to always look backwards for the beginning first, + // but if the cursor is in front of the first instance of the symb, + // then move the cursor forward + if (cur.ch < firstIndex) { + cur.ch = firstIndex; + // Why is this line even here??? + // cm.setCursor(cur.line, firstIndex+1); + } + // otherwise if the cursor is currently on the closing symbol + else if (firstIndex < cur.ch && chars[cur.ch] == symb) { + end = cur.ch; // assign end to the current cursor + --cur.ch; // make sure to look backwards + } + + // if we're currently on the symbol, we've got a start + if (chars[cur.ch] == symb && !end) { + start = cur.ch + 1; // assign start to ahead of the cursor + } else { + // go backwards to find the start + for (i = cur.ch; i > -1 && !start; i--) { + if (chars[i] == symb) { + start = i + 1; + } + } + } + + // look forwards for the end symbol + if (start && !end) { + for (i = start, len = chars.length; i < len && !end; i++) { + if (chars[i] == symb) { + end = i; + } + } + } + + // nothing found + if (!start || !end) { + return { start: cur, end: cur }; + } + + // include the symbols + if (inclusive) { + --start; ++end; + } + + return { + start: Pos(cur.line, start), + end: Pos(cur.line, end) + }; + } + + // Search functions + defineOption('pcre', true, 'boolean'); + function SearchState() {} + SearchState.prototype = { + getQuery: function() { + return vimGlobalState.query; + }, + setQuery: function(query) { + vimGlobalState.query = query; + }, + getOverlay: function() { + return this.searchOverlay; + }, + setOverlay: function(overlay) { + this.searchOverlay = overlay; + }, + isReversed: function() { + return vimGlobalState.isReversed; + }, + setReversed: function(reversed) { + vimGlobalState.isReversed = reversed; + } + }; + function getSearchState(cm) { + var vim = cm.state.vim; + return vim.searchState_ || (vim.searchState_ = new SearchState()); + } + function dialog(cm, template, shortText, onClose, options) { + if (cm.openDialog) { + cm.openDialog(template, onClose, { bottom: true, value: options.value, + onKeyDown: options.onKeyDown, onKeyUp: options.onKeyUp, closeOnBlur: false }); + } + else { + onClose(prompt(shortText, '')); + } + } + function splitBySlash(argString) { + var slashes = findUnescapedSlashes(argString) || []; + if (!slashes.length) return []; + var tokens = []; + // in case of strings like foo/bar + if (slashes[0] !== 0) return; + for (var i = 0; i < slashes.length; i++) { + if (typeof slashes[i] == 'number') + tokens.push(argString.substring(slashes[i] + 1, slashes[i+1])); + } + return tokens; + } + + function findUnescapedSlashes(str) { + var escapeNextChar = false; + var slashes = []; + for (var i = 0; i < str.length; i++) { + var c = str.charAt(i); + if (!escapeNextChar && c == '/') { + slashes.push(i); + } + escapeNextChar = !escapeNextChar && (c == '\\'); + } + return slashes; + } + + // Translates a search string from ex (vim) syntax into javascript form. + function translateRegex(str) { + // When these match, add a '\' if unescaped or remove one if escaped. + var specials = '|(){'; + // Remove, but never add, a '\' for these. + var unescape = '}'; + var escapeNextChar = false; + var out = []; + for (var i = -1; i < str.length; i++) { + var c = str.charAt(i) || ''; + var n = str.charAt(i+1) || ''; + var specialComesNext = (n && specials.indexOf(n) != -1); + if (escapeNextChar) { + if (c !== '\\' || !specialComesNext) { + out.push(c); + } + escapeNextChar = false; + } else { + if (c === '\\') { + escapeNextChar = true; + // Treat the unescape list as special for removing, but not adding '\'. + if (n && unescape.indexOf(n) != -1) { + specialComesNext = true; + } + // Not passing this test means removing a '\'. + if (!specialComesNext || n === '\\') { + out.push(c); + } + } else { + out.push(c); + if (specialComesNext && n !== '\\') { + out.push('\\'); + } + } + } + } + return out.join(''); + } + + // Translates the replace part of a search and replace from ex (vim) syntax into + // javascript form. Similar to translateRegex, but additionally fixes back references + // (translates '\[0..9]' to '$[0..9]') and follows different rules for escaping '$'. + function translateRegexReplace(str) { + var escapeNextChar = false; + var out = []; + for (var i = -1; i < str.length; i++) { + var c = str.charAt(i) || ''; + var n = str.charAt(i+1) || ''; + if (escapeNextChar) { + // At any point in the loop, escapeNextChar is true if the previous + // character was a '\' and was not escaped. + out.push(c); + escapeNextChar = false; + } else { + if (c === '\\') { + escapeNextChar = true; + if ((isNumber(n) || n === '$')) { + out.push('$'); + } else if (n !== '/' && n !== '\\') { + out.push('\\'); + } + } else { + if (c === '$') { + out.push('$'); + } + out.push(c); + if (n === '/') { + out.push('\\'); + } + } + } + } + return out.join(''); + } + + // Unescape \ and / in the replace part, for PCRE mode. + function unescapeRegexReplace(str) { + var stream = new CodeMirror.StringStream(str); + var output = []; + while (!stream.eol()) { + // Search for \. + while (stream.peek() && stream.peek() != '\\') { + output.push(stream.next()); + } + if (stream.match('\\/', true)) { + // \/ => / + output.push('/'); + } else if (stream.match('\\\\', true)) { + // \\ => \ + output.push('\\'); + } else { + // Don't change anything + output.push(stream.next()); + } + } + return output.join(''); + } + + /** + * Extract the regular expression from the query and return a Regexp object. + * Returns null if the query is blank. + * If ignoreCase is passed in, the Regexp object will have the 'i' flag set. + * If smartCase is passed in, and the query contains upper case letters, + * then ignoreCase is overridden, and the 'i' flag will not be set. + * If the query contains the /i in the flag part of the regular expression, + * then both ignoreCase and smartCase are ignored, and 'i' will be passed + * through to the Regex object. + */ + function parseQuery(query, ignoreCase, smartCase) { + // First update the last search register + var lastSearchRegister = vimGlobalState.registerController.getRegister('/'); + lastSearchRegister.setText(query); + // Check if the query is already a regex. + if (query instanceof RegExp) { return query; } + // First try to extract regex + flags from the input. If no flags found, + // extract just the regex. IE does not accept flags directly defined in + // the regex string in the form /regex/flags + var slashes = findUnescapedSlashes(query); + var regexPart; + var forceIgnoreCase; + if (!slashes.length) { + // Query looks like 'regexp' + regexPart = query; + } else { + // Query looks like 'regexp/...' + regexPart = query.substring(0, slashes[0]); + var flagsPart = query.substring(slashes[0]); + forceIgnoreCase = (flagsPart.indexOf('i') != -1); + } + if (!regexPart) { + return null; + } + if (!getOption('pcre')) { + regexPart = translateRegex(regexPart); + } + if (smartCase) { + ignoreCase = (/^[^A-Z]*$/).test(regexPart); + } + var regexp = new RegExp(regexPart, + (ignoreCase || forceIgnoreCase) ? 'i' : undefined); + return regexp; + } + function showConfirm(cm, text) { + if (cm.openNotification) { + cm.openNotification('' + text + '', + {bottom: true, duration: 5000}); + } else { + alert(text); + } + } + function makePrompt(prefix, desc) { + return prefix; + } + var searchPromptDesc = '(Javascript regexp)'; + function showPrompt(cm, options) { + var shortText = (options.prefix || '') + ' ' + (options.desc || ''); + var prompt = makePrompt(options.prefix, options.desc); + dialog(cm, prompt, shortText, options.onClose, options); + } + function regexEqual(r1, r2) { + if (r1 instanceof RegExp && r2 instanceof RegExp) { + var props = ['global', 'multiline', 'ignoreCase', 'source']; + for (var i = 0; i < props.length; i++) { + var prop = props[i]; + if (r1[prop] !== r2[prop]) { + return false; + } + } + return true; + } + return false; + } + // Returns true if the query is valid. + function updateSearchQuery(cm, rawQuery, ignoreCase, smartCase) { + if (!rawQuery) { + return; + } + var state = getSearchState(cm); + var query = parseQuery(rawQuery, !!ignoreCase, !!smartCase); + if (!query) { + return; + } + highlightSearchMatches(cm, query); + if (regexEqual(query, state.getQuery())) { + return query; + } + state.setQuery(query); + return query; + } + function searchOverlay(query) { + if (query.source.charAt(0) == '^') { + var matchSol = true; + } + return { + token: function(stream) { + if (matchSol && !stream.sol()) { + stream.skipToEnd(); + return; + } + var match = stream.match(query, false); + if (match) { + if (match[0].length == 0) { + // Matched empty string, skip to next. + stream.next(); + return 'searching'; + } + if (!stream.sol()) { + // Backtrack 1 to match \b + stream.backUp(1); + if (!query.exec(stream.next() + match[0])) { + stream.next(); + return null; + } + } + stream.match(query); + return 'searching'; + } + while (!stream.eol()) { + stream.next(); + if (stream.match(query, false)) break; + } + }, + query: query + }; + } + function highlightSearchMatches(cm, query) { + var overlay = getSearchState(cm).getOverlay(); + if (!overlay || query != overlay.query) { + if (overlay) { + cm.removeOverlay(overlay); + } + overlay = searchOverlay(query); + cm.addOverlay(overlay); + getSearchState(cm).setOverlay(overlay); + } + } + function findNext(cm, prev, query, repeat, startPos) { + if (repeat === undefined) { repeat = 1; } + return cm.operation(function() { + var pos = startPos || cm.getCursor(); + var cursor = cm.getSearchCursor(query, pos); + for (var i = 0; i < repeat; i++) { + var found = cursor.find(prev); + if (i == 0 && found && cursorEqual(cursor.from(), pos)) { found = cursor.find(prev); } + if (!found) { + // SearchCursor may have returned null because it hit EOF, wrap + // around and try again. + cursor = cm.getSearchCursor(query, + (prev) ? Pos(cm.lastLine()) : Pos(cm.firstLine(), 0) ); + if (!cursor.find(prev)) { + return; + } + } + } + return cursor.from(); + }); + } + function clearSearchHighlight(cm) { + cm.removeOverlay(getSearchState(cm).getOverlay()); + getSearchState(cm).setOverlay(null); + } + /** + * Check if pos is in the specified range, INCLUSIVE. + * Range can be specified with 1 or 2 arguments. + * If the first range argument is an array, treat it as an array of line + * numbers. Match pos against any of the lines. + * If the first range argument is a number, + * if there is only 1 range argument, check if pos has the same line + * number + * if there are 2 range arguments, then check if pos is in between the two + * range arguments. + */ + function isInRange(pos, start, end) { + if (typeof pos != 'number') { + // Assume it is a cursor position. Get the line number. + pos = pos.line; + } + if (start instanceof Array) { + return inArray(pos, start); + } else { + if (end) { + return (pos >= start && pos <= end); + } else { + return pos == start; + } + } + } + function getUserVisibleLines(cm) { + var renderer = cm.ace.renderer; + return { + top: renderer.getFirstFullyVisibleRow(), + bottom: renderer.getLastFullyVisibleRow() + } + } + + // Ex command handling + // Care must be taken when adding to the default Ex command map. For any + // pair of commands that have a shared prefix, at least one of their + // shortNames must not match the prefix of the other command. + var defaultExCommandMap = [ + { name: 'map' }, + { name: 'imap', shortName: 'im' }, + { name: 'nmap', shortName: 'nm' }, + { name: 'vmap', shortName: 'vm' }, + { name: 'unmap' }, + { name: 'write', shortName: 'w' }, + { name: 'undo', shortName: 'u' }, + { name: 'redo', shortName: 'red' }, + { name: 'set', shortName: 'set' }, + { name: 'sort', shortName: 'sor' }, + { name: 'substitute', shortName: 's', possiblyAsync: true }, + { name: 'nohlsearch', shortName: 'noh' }, + { name: 'delmarks', shortName: 'delm' }, + { name: 'registers', shortName: 'reg', excludeFromCommandHistory: true }, + { name: 'global', shortName: 'g' } + ]; + var ExCommandDispatcher = function() { + this.buildCommandMap_(); + }; + ExCommandDispatcher.prototype = { + processCommand: function(cm, input, opt_params) { + var vim = cm.state.vim; + var commandHistoryRegister = vimGlobalState.registerController.getRegister(':'); + var previousCommand = commandHistoryRegister.toString(); + if (vim.visualMode) { + exitVisualMode(cm); + } + var inputStream = new CodeMirror.StringStream(input); + // update ": with the latest command whether valid or invalid + commandHistoryRegister.setText(input); + var params = opt_params || {}; + params.input = input; + try { + this.parseInput_(cm, inputStream, params); + } catch(e) { + showConfirm(cm, e); + throw e; + } + var command; + var commandName; + if (!params.commandName) { + // If only a line range is defined, move to the line. + if (params.line !== undefined) { + commandName = 'move'; + } + } else { + command = this.matchCommand_(params.commandName); + if (command) { + commandName = command.name; + if (command.excludeFromCommandHistory) { + commandHistoryRegister.setText(previousCommand); + } + this.parseCommandArgs_(inputStream, params, command); + if (command.type == 'exToKey') { + // Handle Ex to Key mapping. + for (var i = 0; i < command.toKeys.length; i++) { + CodeMirror.Vim.handleKey(cm, command.toKeys[i], 'mapping'); + } + return; + } else if (command.type == 'exToEx') { + // Handle Ex to Ex mapping. + this.processCommand(cm, command.toInput); + return; + } + } + } + if (!commandName) { + showConfirm(cm, 'Not an editor command ":' + input + '"'); + return; + } + try { + exCommands[commandName](cm, params); + // Possibly asynchronous commands (e.g. substitute, which might have a + // user confirmation), are responsible for calling the callback when + // done. All others have it taken care of for them here. + if ((!command || !command.possiblyAsync) && params.callback) { + params.callback(); + } + } catch(e) { + showConfirm(cm, e); + throw e; + } + }, + parseInput_: function(cm, inputStream, result) { + inputStream.eatWhile(':'); + // Parse range. + if (inputStream.eat('%')) { + result.line = cm.firstLine(); + result.lineEnd = cm.lastLine(); + } else { + result.line = this.parseLineSpec_(cm, inputStream); + if (result.line !== undefined && inputStream.eat(',')) { + result.lineEnd = this.parseLineSpec_(cm, inputStream); + } + } + + // Parse command name. + var commandMatch = inputStream.match(/^(\w+)/); + if (commandMatch) { + result.commandName = commandMatch[1]; + } else { + result.commandName = inputStream.match(/.*/)[0]; + } + + return result; + }, + parseLineSpec_: function(cm, inputStream) { + var numberMatch = inputStream.match(/^(\d+)/); + if (numberMatch) { + return parseInt(numberMatch[1], 10) - 1; + } + switch (inputStream.next()) { + case '.': + return cm.getCursor().line; + case '$': + return cm.lastLine(); + case '\'': + var mark = cm.state.vim.marks[inputStream.next()]; + if (mark && mark.find()) { + return mark.find().line; + } + throw new Error('Mark not set'); + default: + inputStream.backUp(1); + return undefined; + } + }, + parseCommandArgs_: function(inputStream, params, command) { + if (inputStream.eol()) { + return; + } + params.argString = inputStream.match(/.*/)[0]; + // Parse command-line arguments + var delim = command.argDelimiter || /\s+/; + var args = trim(params.argString).split(delim); + if (args.length && args[0]) { + params.args = args; + } + }, + matchCommand_: function(commandName) { + // Return the command in the command map that matches the shortest + // prefix of the passed in command name. The match is guaranteed to be + // unambiguous if the defaultExCommandMap's shortNames are set up + // correctly. (see @code{defaultExCommandMap}). + for (var i = commandName.length; i > 0; i--) { + var prefix = commandName.substring(0, i); + if (this.commandMap_[prefix]) { + var command = this.commandMap_[prefix]; + if (command.name.indexOf(commandName) === 0) { + return command; + } + } + } + return null; + }, + buildCommandMap_: function() { + this.commandMap_ = {}; + for (var i = 0; i < defaultExCommandMap.length; i++) { + var command = defaultExCommandMap[i]; + var key = command.shortName || command.name; + this.commandMap_[key] = command; + } + }, + map: function(lhs, rhs, ctx) { + if (lhs != ':' && lhs.charAt(0) == ':') { + if (ctx) { throw Error('Mode not supported for ex mappings'); } + var commandName = lhs.substring(1); + if (rhs != ':' && rhs.charAt(0) == ':') { + // Ex to Ex mapping + this.commandMap_[commandName] = { + name: commandName, + type: 'exToEx', + toInput: rhs.substring(1), + user: true + }; + } else { + // Ex to key mapping + this.commandMap_[commandName] = { + name: commandName, + type: 'exToKey', + toKeys: rhs, + user: true + }; + } + } else { + if (rhs != ':' && rhs.charAt(0) == ':') { + // Key to Ex mapping. + var mapping = { + keys: lhs, + type: 'keyToEx', + exArgs: { input: rhs.substring(1) }, + user: true}; + if (ctx) { mapping.context = ctx; } + defaultKeymap.unshift(mapping); + } else { + // Key to key mapping + var mapping = { + keys: lhs, + type: 'keyToKey', + toKeys: rhs, + user: true + }; + if (ctx) { mapping.context = ctx; } + defaultKeymap.unshift(mapping); + } + } + }, + unmap: function(lhs, ctx) { + if (lhs != ':' && lhs.charAt(0) == ':') { + // Ex to Ex or Ex to key mapping + if (ctx) { throw Error('Mode not supported for ex mappings'); } + var commandName = lhs.substring(1); + if (this.commandMap_[commandName] && this.commandMap_[commandName].user) { + delete this.commandMap_[commandName]; + return; + } + } else { + // Key to Ex or key to key mapping + var keys = lhs; + for (var i = 0; i < defaultKeymap.length; i++) { + if (keys == defaultKeymap[i].keys + && defaultKeymap[i].context === ctx + && defaultKeymap[i].user) { + defaultKeymap.splice(i, 1); + return; + } + } + } + throw Error('No such mapping.'); + } + }; + + var exCommands = { + map: function(cm, params, ctx) { + var mapArgs = params.args; + if (!mapArgs || mapArgs.length < 2) { + if (cm) { + showConfirm(cm, 'Invalid mapping: ' + params.input); + } + return; + } + exCommandDispatcher.map(mapArgs[0], mapArgs[1], ctx); + }, + imap: function(cm, params) { this.map(cm, params, 'insert'); }, + nmap: function(cm, params) { this.map(cm, params, 'normal'); }, + vmap: function(cm, params) { this.map(cm, params, 'visual'); }, + unmap: function(cm, params, ctx) { + var mapArgs = params.args; + if (!mapArgs || mapArgs.length < 1) { + if (cm) { + showConfirm(cm, 'No such mapping: ' + params.input); + } + return; + } + exCommandDispatcher.unmap(mapArgs[0], ctx); + }, + move: function(cm, params) { + commandDispatcher.processCommand(cm, cm.state.vim, { + type: 'motion', + motion: 'moveToLineOrEdgeOfDocument', + motionArgs: { forward: false, explicitRepeat: true, + linewise: true }, + repeatOverride: params.line+1}); + }, + set: function(cm, params) { + var setArgs = params.args; + if (!setArgs || setArgs.length < 1) { + if (cm) { + showConfirm(cm, 'Invalid mapping: ' + params.input); + } + return; + } + var expr = setArgs[0].split('='); + var optionName = expr[0]; + var value = expr[1]; + var forceGet = false; + + if (optionName.charAt(optionName.length - 1) == '?') { + // If post-fixed with ?, then the set is actually a get. + if (value) { throw Error('Trailing characters: ' + params.argString); } + optionName = optionName.substring(0, optionName.length - 1); + forceGet = true; + } + if (value === undefined && optionName.substring(0, 2) == 'no') { + // To set boolean options to false, the option name is prefixed with + // 'no'. + optionName = optionName.substring(2); + value = false; + } + var optionIsBoolean = options[optionName] && options[optionName].type == 'boolean'; + if (optionIsBoolean && value == undefined) { + // Calling set with a boolean option sets it to true. + value = true; + } + if (!optionIsBoolean && !value || forceGet) { + var oldValue = getOption(optionName); + // If no value is provided, then we assume this is a get. + if (oldValue === true || oldValue === false) { + showConfirm(cm, ' ' + (oldValue ? '' : 'no') + optionName); + } else { + showConfirm(cm, ' ' + optionName + '=' + oldValue); + } + } else { + setOption(optionName, value, cm); + } + }, + registers: function(cm,params) { + var regArgs = params.args; + var registers = vimGlobalState.registerController.registers; + var regInfo = '----------Registers----------

      '; + if (!regArgs) { + for (var registerName in registers) { + var text = registers[registerName].toString(); + if (text.length) { + regInfo += '"' + registerName + ' ' + text + '
      '; + } + } + } else { + var registerName; + regArgs = regArgs.join(''); + for (var i = 0; i < regArgs.length; i++) { + registerName = regArgs.charAt(i); + if (!vimGlobalState.registerController.isValidRegister(registerName)) { + continue; + } + var register = registers[registerName] || new Register(); + regInfo += '"' + registerName + ' ' + register.toString() + '
      '; + } + } + showConfirm(cm, regInfo); + }, + sort: function(cm, params) { + var reverse, ignoreCase, unique, number; + function parseArgs() { + if (params.argString) { + var args = new CodeMirror.StringStream(params.argString); + if (args.eat('!')) { reverse = true; } + if (args.eol()) { return; } + if (!args.eatSpace()) { return 'Invalid arguments'; } + var opts = args.match(/[a-z]+/); + if (opts) { + opts = opts[0]; + ignoreCase = opts.indexOf('i') != -1; + unique = opts.indexOf('u') != -1; + var decimal = opts.indexOf('d') != -1 && 1; + var hex = opts.indexOf('x') != -1 && 1; + var octal = opts.indexOf('o') != -1 && 1; + if (decimal + hex + octal > 1) { return 'Invalid arguments'; } + number = decimal && 'decimal' || hex && 'hex' || octal && 'octal'; + } + if (args.eatSpace() && args.match(/\/.*\//)) { 'patterns not supported'; } + } + } + var err = parseArgs(); + if (err) { + showConfirm(cm, err + ': ' + params.argString); + return; + } + var lineStart = params.line || cm.firstLine(); + var lineEnd = params.lineEnd || params.line || cm.lastLine(); + if (lineStart == lineEnd) { return; } + var curStart = Pos(lineStart, 0); + var curEnd = Pos(lineEnd, lineLength(cm, lineEnd)); + var text = cm.getRange(curStart, curEnd).split('\n'); + var numberRegex = (number == 'decimal') ? /(-?)([\d]+)/ : + (number == 'hex') ? /(-?)(?:0x)?([0-9a-f]+)/i : + (number == 'octal') ? /([0-7]+)/ : null; + var radix = (number == 'decimal') ? 10 : (number == 'hex') ? 16 : (number == 'octal') ? 8 : null; + var numPart = [], textPart = []; + if (number) { + for (var i = 0; i < text.length; i++) { + if (numberRegex.exec(text[i])) { + numPart.push(text[i]); + } else { + textPart.push(text[i]); + } + } + } else { + textPart = text; + } + function compareFn(a, b) { + if (reverse) { var tmp; tmp = a; a = b; b = tmp; } + if (ignoreCase) { a = a.toLowerCase(); b = b.toLowerCase(); } + var anum = number && numberRegex.exec(a); + var bnum = number && numberRegex.exec(b); + if (!anum) { return a < b ? -1 : 1; } + anum = parseInt((anum[1] + anum[2]).toLowerCase(), radix); + bnum = parseInt((bnum[1] + bnum[2]).toLowerCase(), radix); + return anum - bnum; + } + numPart.sort(compareFn); + textPart.sort(compareFn); + text = (!reverse) ? textPart.concat(numPart) : numPart.concat(textPart); + if (unique) { // Remove duplicate lines + var textOld = text; + var lastLine; + text = []; + for (var i = 0; i < textOld.length; i++) { + if (textOld[i] != lastLine) { + text.push(textOld[i]); + } + lastLine = textOld[i]; + } + } + cm.replaceRange(text.join('\n'), curStart, curEnd); + }, + global: function(cm, params) { + // a global command is of the form + // :[range]g/pattern/[cmd] + // argString holds the string /pattern/[cmd] + var argString = params.argString; + if (!argString) { + showConfirm(cm, 'Regular Expression missing from global'); + return; + } + // range is specified here + var lineStart = (params.line !== undefined) ? params.line : cm.firstLine(); + var lineEnd = params.lineEnd || params.line || cm.lastLine(); + // get the tokens from argString + var tokens = splitBySlash(argString); + var regexPart = argString, cmd; + if (tokens.length) { + regexPart = tokens[0]; + cmd = tokens.slice(1, tokens.length).join('/'); + } + if (regexPart) { + // If regex part is empty, then use the previous query. Otherwise + // use the regex part as the new query. + try { + updateSearchQuery(cm, regexPart, true /** ignoreCase */, + true /** smartCase */); + } catch (e) { + showConfirm(cm, 'Invalid regex: ' + regexPart); + return; + } + } + // now that we have the regexPart, search for regex matches in the + // specified range of lines + var query = getSearchState(cm).getQuery(); + var matchedLines = [], content = ''; + for (var i = lineStart; i <= lineEnd; i++) { + var matched = query.test(cm.getLine(i)); + if (matched) { + matchedLines.push(i+1); + content+= cm.getLine(i) + '
      '; + } + } + // if there is no [cmd], just display the list of matched lines + if (!cmd) { + showConfirm(cm, content); + return; + } + var index = 0; + var nextCommand = function() { + if (index < matchedLines.length) { + var command = matchedLines[index] + cmd; + exCommandDispatcher.processCommand(cm, command, { + callback: nextCommand + }); + } + index++; + }; + nextCommand(); + }, + substitute: function(cm, params) { + if (!cm.getSearchCursor) { + throw new Error('Search feature not available. Requires searchcursor.js or ' + + 'any other getSearchCursor implementation.'); + } + var argString = params.argString; + var tokens = argString ? splitBySlash(argString) : []; + var regexPart, replacePart = '', trailing, flagsPart, count; + var confirm = false; // Whether to confirm each replace. + var global = false; // True to replace all instances on a line, false to replace only 1. + if (tokens.length) { + regexPart = tokens[0]; + replacePart = tokens[1]; + if (replacePart !== undefined) { + if (getOption('pcre')) { + replacePart = unescapeRegexReplace(replacePart); + } else { + replacePart = translateRegexReplace(replacePart); + } + vimGlobalState.lastSubstituteReplacePart = replacePart; + } + trailing = tokens[2] ? tokens[2].split(' ') : []; + } else { + // either the argString is empty or its of the form ' hello/world' + // actually splitBySlash returns a list of tokens + // only if the string starts with a '/' + if (argString && argString.length) { + showConfirm(cm, 'Substitutions should be of the form ' + + ':s/pattern/replace/'); + return; + } + } + // After the 3rd slash, we can have flags followed by a space followed + // by count. + if (trailing) { + flagsPart = trailing[0]; + count = parseInt(trailing[1]); + if (flagsPart) { + if (flagsPart.indexOf('c') != -1) { + confirm = true; + flagsPart.replace('c', ''); + } + if (flagsPart.indexOf('g') != -1) { + global = true; + flagsPart.replace('g', ''); + } + regexPart = regexPart + '/' + flagsPart; + } + } + if (regexPart) { + // If regex part is empty, then use the previous query. Otherwise use + // the regex part as the new query. + try { + updateSearchQuery(cm, regexPart, true /** ignoreCase */, + true /** smartCase */); + } catch (e) { + showConfirm(cm, 'Invalid regex: ' + regexPart); + return; + } + } + replacePart = replacePart || vimGlobalState.lastSubstituteReplacePart; + if (replacePart === undefined) { + showConfirm(cm, 'No previous substitute regular expression'); + return; + } + var state = getSearchState(cm); + var query = state.getQuery(); + var lineStart = (params.line !== undefined) ? params.line : cm.getCursor().line; + var lineEnd = params.lineEnd || lineStart; + if (count) { + lineStart = lineEnd; + lineEnd = lineStart + count - 1; + } + var startPos = clipCursorToContent(cm, Pos(lineStart, 0)); + var cursor = cm.getSearchCursor(query, startPos); + doReplace(cm, confirm, global, lineStart, lineEnd, cursor, query, replacePart, params.callback); + }, + redo: CodeMirror.commands.redo, + undo: CodeMirror.commands.undo, + write: function(cm) { + if (CodeMirror.commands.save) { + // If a save command is defined, call it. + CodeMirror.commands.save(cm); + } else { + // Saves to text area if no save command is defined. + cm.save(); + } + }, + nohlsearch: function(cm) { + clearSearchHighlight(cm); + }, + delmarks: function(cm, params) { + if (!params.argString || !trim(params.argString)) { + showConfirm(cm, 'Argument required'); + return; + } + + var state = cm.state.vim; + var stream = new CodeMirror.StringStream(trim(params.argString)); + while (!stream.eol()) { + stream.eatSpace(); + + // Record the streams position at the beginning of the loop for use + // in error messages. + var count = stream.pos; + + if (!stream.match(/[a-zA-Z]/, false)) { + showConfirm(cm, 'Invalid argument: ' + params.argString.substring(count)); + return; + } + + var sym = stream.next(); + // Check if this symbol is part of a range + if (stream.match('-', true)) { + // This symbol is part of a range. + + // The range must terminate at an alphabetic character. + if (!stream.match(/[a-zA-Z]/, false)) { + showConfirm(cm, 'Invalid argument: ' + params.argString.substring(count)); + return; + } + + var startMark = sym; + var finishMark = stream.next(); + // The range must terminate at an alphabetic character which + // shares the same case as the start of the range. + if (isLowerCase(startMark) && isLowerCase(finishMark) || + isUpperCase(startMark) && isUpperCase(finishMark)) { + var start = startMark.charCodeAt(0); + var finish = finishMark.charCodeAt(0); + if (start >= finish) { + showConfirm(cm, 'Invalid argument: ' + params.argString.substring(count)); + return; + } + + // Because marks are always ASCII values, and we have + // determined that they are the same case, we can use + // their char codes to iterate through the defined range. + for (var j = 0; j <= finish - start; j++) { + var mark = String.fromCharCode(start + j); + delete state.marks[mark]; + } + } else { + showConfirm(cm, 'Invalid argument: ' + startMark + '-'); + return; + } + } else { + // This symbol is a valid mark, and is not part of a range. + delete state.marks[sym]; + } + } + } + }; + + var exCommandDispatcher = new ExCommandDispatcher(); + + /** + * @param {CodeMirror} cm CodeMirror instance we are in. + * @param {boolean} confirm Whether to confirm each replace. + * @param {Cursor} lineStart Line to start replacing from. + * @param {Cursor} lineEnd Line to stop replacing at. + * @param {RegExp} query Query for performing matches with. + * @param {string} replaceWith Text to replace matches with. May contain $1, + * $2, etc for replacing captured groups using Javascript replace. + * @param {function()} callback A callback for when the replace is done. + */ + function doReplace(cm, confirm, global, lineStart, lineEnd, searchCursor, query, + replaceWith, callback) { + // Set up all the functions. + cm.state.vim.exMode = true; + var done = false; + var lastPos = searchCursor.from(); + function replaceAll() { + cm.operation(function() { + while (!done) { + replace(); + next(); + } + stop(); + }); + } + function replace() { + var text = cm.getRange(searchCursor.from(), searchCursor.to()); + var newText = text.replace(query, replaceWith); + searchCursor.replace(newText); + } + function next() { + var found; + // The below only loops to skip over multiple occurrences on the same + // line when 'global' is not true. + while(found = searchCursor.findNext() && + isInRange(searchCursor.from(), lineStart, lineEnd)) { + if (!global && lastPos && searchCursor.from().line == lastPos.line) { + continue; + } + cm.scrollIntoView(searchCursor.from(), 30); + cm.setSelection(searchCursor.from(), searchCursor.to()); + lastPos = searchCursor.from(); + done = false; + return; + } + done = true; + } + function stop(close) { + if (close) { close(); } + cm.focus(); + if (lastPos) { + cm.setCursor(lastPos); + var vim = cm.state.vim; + vim.exMode = false; + vim.lastHPos = vim.lastHSPos = lastPos.ch; + } + if (callback) { callback(); } + } + function onPromptKeyDown(e, _value, close) { + // Swallow all keys. + CodeMirror.e_stop(e); + var keyName = CodeMirror.keyName(e); + switch (keyName) { + case 'Y': + replace(); next(); break; + case 'N': + next(); break; + case 'A': + // replaceAll contains a call to close of its own. We don't want it + // to fire too early or multiple times. + var savedCallback = callback; + callback = undefined; + cm.operation(replaceAll); + callback = savedCallback; + break; + case 'L': + replace(); + // fall through and exit. + case 'Q': + case 'Esc': + case 'Ctrl-C': + case 'Ctrl-[': + stop(close); + break; + } + if (done) { stop(close); } + return true; + } + + // Actually do replace. + next(); + if (done) { + showConfirm(cm, 'No matches for ' + query.source); + return; + } + if (!confirm) { + replaceAll(); + if (callback) { callback(); }; + return; + } + showPrompt(cm, { + prefix: 'replace with ' + replaceWith + ' (y/n/a/q/l)', + onKeyDown: onPromptKeyDown + }); + } + + CodeMirror.keyMap.vim = { + attach: attachVimMap, + detach: detachVimMap, + call: cmKey + }; + + function exitInsertMode(cm) { + var vim = cm.state.vim; + var macroModeState = vimGlobalState.macroModeState; + var insertModeChangeRegister = vimGlobalState.registerController.getRegister('.'); + var isPlaying = macroModeState.isPlaying; + var lastChange = macroModeState.lastInsertModeChanges; + // In case of visual block, the insertModeChanges are not saved as a + // single word, so we convert them to a single word + // so as to update the ". register as expected in real vim. + var text = []; + if (!isPlaying) { + var selLength = lastChange.inVisualBlock ? vim.lastSelection.visualBlock.height : 1; + var changes = lastChange.changes; + var text = []; + var i = 0; + // In case of multiple selections in blockwise visual, + // the inserted text, for example: 'foo', is stored as + // 'f', 'f', InsertModeKey 'o', 'o', 'o', 'o'. (if you have a block with 2 lines). + // We push the contents of the changes array as per the following: + // 1. In case of InsertModeKey, just increment by 1. + // 2. In case of a character, jump by selLength (2 in the example). + while (i < changes.length) { + // This loop will convert 'ffoooo' to 'foo'. + text.push(changes[i]); + if (changes[i] instanceof InsertModeKey) { + i++; + } else { + i+= selLength; + } + } + lastChange.changes = text; + cm.off('change', onChange); + CodeMirror.off(cm.getInputField(), 'keydown', onKeyEventTargetKeyDown); + } + if (!isPlaying && vim.insertModeRepeat > 1) { + // Perform insert mode repeat for commands like 3,a and 3,o. + repeatLastEdit(cm, vim, vim.insertModeRepeat - 1, + true /** repeatForInsert */); + vim.lastEditInputState.repeatOverride = vim.insertModeRepeat; + } + delete vim.insertModeRepeat; + vim.insertMode = false; + cm.setCursor(cm.getCursor().line, cm.getCursor().ch-1); + cm.setOption('keyMap', 'vim'); + cm.setOption('disableInput', true); + cm.toggleOverwrite(false); // exit replace mode if we were in it. + // update the ". register before exiting insert mode + insertModeChangeRegister.setText(lastChange.changes.join('')); + CodeMirror.signal(cm, "vim-mode-change", {mode: "normal"}); + if (macroModeState.isRecording) { + logInsertModeChange(macroModeState); + } + } + + // The timeout in milliseconds for the two-character ESC keymap should be + // adjusted according to your typing speed to prevent false positives. + defineOption('insertModeEscKeysTimeout', 200, 'number'); + + CodeMirror.keyMap['vim-insert'] = { + // TODO: override navigation keys so that Esc will cancel automatic + // indentation from o, O, i_ + 'Ctrl-N': 'autocomplete', + 'Ctrl-P': 'autocomplete', + 'Enter': function(cm) { + var fn = CodeMirror.commands.newlineAndIndentContinueComment || + CodeMirror.commands.newlineAndIndent; + fn(cm); + }, + fallthrough: ['default'], + attach: attachVimMap, + detach: detachVimMap, + call: cmKey + }; + + CodeMirror.keyMap['vim-replace'] = { + 'Backspace': 'goCharLeft', + fallthrough: ['vim-insert'], + attach: attachVimMap, + detach: detachVimMap, + call: cmKey + }; + + function executeMacroRegister(cm, vim, macroModeState, registerName) { + var register = vimGlobalState.registerController.getRegister(registerName); + var keyBuffer = register.keyBuffer; + var imc = 0; + macroModeState.isPlaying = true; + macroModeState.replaySearchQueries = register.searchQueries.slice(0); + for (var i = 0; i < keyBuffer.length; i++) { + var text = keyBuffer[i]; + var match, key; + while (text) { + // Pull off one command key, which is either a single character + // or a special sequence wrapped in '<' and '>', e.g. ''. + match = (/<\w+-.+?>|<\w+>|./).exec(text); + key = match[0]; + text = text.substring(match.index + key.length); + CodeMirror.Vim.handleKey(cm, key, 'macro'); + if (vim.insertMode) { + var changes = register.insertModeChanges[imc++].changes; + vimGlobalState.macroModeState.lastInsertModeChanges.changes = + changes; + repeatInsertModeChanges(cm, changes, 1); + exitInsertMode(cm); + } + } + }; + macroModeState.isPlaying = false; + } + + function logKey(macroModeState, key) { + if (macroModeState.isPlaying) { return; } + var registerName = macroModeState.latestRegister; + var register = vimGlobalState.registerController.getRegister(registerName); + if (register) { + register.pushText(key); + } + } + + function logInsertModeChange(macroModeState) { + if (macroModeState.isPlaying) { return; } + var registerName = macroModeState.latestRegister; + var register = vimGlobalState.registerController.getRegister(registerName); + if (register) { + register.pushInsertModeChanges(macroModeState.lastInsertModeChanges); + } + } + + function logSearchQuery(macroModeState, query) { + if (macroModeState.isPlaying) { return; } + var registerName = macroModeState.latestRegister; + var register = vimGlobalState.registerController.getRegister(registerName); + if (register) { + register.pushSearchQuery(query); + } + } + + /** + * Listens for changes made in insert mode. + * Should only be active in insert mode. + */ + function onChange(_cm, changeObj) { + var macroModeState = vimGlobalState.macroModeState; + var lastChange = macroModeState.lastInsertModeChanges; + if (!macroModeState.isPlaying) { + while(changeObj) { + lastChange.expectCursorActivityForChange = true; + if (changeObj.origin == '+input' || changeObj.origin == 'paste' + || changeObj.origin === undefined /* only in testing */) { + var text = changeObj.text.join('\n'); + lastChange.changes.push(text); + } + // Change objects may be chained with next. + changeObj = changeObj.next; + } + } + } + + /** + * Listens for any kind of cursor activity on CodeMirror. + */ + function onCursorActivity(cm) { + var vim = cm.state.vim; + if (vim.insertMode) { + // Tracking cursor activity in insert mode (for macro support). + var macroModeState = vimGlobalState.macroModeState; + if (macroModeState.isPlaying) { return; } + var lastChange = macroModeState.lastInsertModeChanges; + if (lastChange.expectCursorActivityForChange) { + lastChange.expectCursorActivityForChange = false; + } else { + // Cursor moved outside the context of an edit. Reset the change. + lastChange.changes = []; + } + } else if (!cm.curOp.isVimOp) { + handleExternalSelection(cm, vim); + } + if (vim.visualMode) { + updateFakeCursor(cm); + } + } + function updateFakeCursor(cm) { + var vim = cm.state.vim; + var from = copyCursor(vim.sel.head); + var to = offsetCursor(from, 0, 1); + if (vim.fakeCursor) { + vim.fakeCursor.clear(); + } + vim.fakeCursor = cm.markText(from, to, {className: 'cm-animate-fat-cursor'}); + } + function handleExternalSelection(cm, vim) { + var anchor = cm.getCursor('anchor'); + var head = cm.getCursor('head'); + // Enter or exit visual mode to match mouse selection. + if (vim.visualMode && cursorEqual(head, anchor) && lineLength(cm, head.line) > head.ch) { + exitVisualMode(cm, false); + } else if (!vim.visualMode && !vim.insertMode && cm.somethingSelected()) { + vim.visualMode = true; + vim.visualLine = false; + CodeMirror.signal(cm, "vim-mode-change", {mode: "visual"}); + } + if (vim.visualMode) { + // Bind CodeMirror selection model to vim selection model. + // Mouse selections are considered visual characterwise. + var headOffset = !cursorIsBefore(head, anchor) ? -1 : 0; + var anchorOffset = cursorIsBefore(head, anchor) ? -1 : 0; + head = offsetCursor(head, 0, headOffset); + anchor = offsetCursor(anchor, 0, anchorOffset); + vim.sel = { + anchor: anchor, + head: head + }; + updateMark(cm, vim, '<', cursorMin(head, anchor)); + updateMark(cm, vim, '>', cursorMax(head, anchor)); + } else if (!vim.insertMode) { + // Reset lastHPos if selection was modified by something outside of vim mode e.g. by mouse. + vim.lastHPos = cm.getCursor().ch; + } + } + + /** Wrapper for special keys pressed in insert mode */ + function InsertModeKey(keyName) { + this.keyName = keyName; + } + + /** + * Handles raw key down events from the text area. + * - Should only be active in insert mode. + * - For recording deletes in insert mode. + */ + function onKeyEventTargetKeyDown(e) { + var macroModeState = vimGlobalState.macroModeState; + var lastChange = macroModeState.lastInsertModeChanges; + var keyName = CodeMirror.keyName(e); + function onKeyFound() { + lastChange.changes.push(new InsertModeKey(keyName)); + return true; + } + if (keyName.indexOf('Delete') != -1 || keyName.indexOf('Backspace') != -1) { + CodeMirror.lookupKey(keyName, 'vim-insert', onKeyFound); + } + } + + /** + * Repeats the last edit, which includes exactly 1 command and at most 1 + * insert. Operator and motion commands are read from lastEditInputState, + * while action commands are read from lastEditActionCommand. + * + * If repeatForInsert is true, then the function was called by + * exitInsertMode to repeat the insert mode changes the user just made. The + * corresponding enterInsertMode call was made with a count. + */ + function repeatLastEdit(cm, vim, repeat, repeatForInsert) { + var macroModeState = vimGlobalState.macroModeState; + macroModeState.isPlaying = true; + var isAction = !!vim.lastEditActionCommand; + var cachedInputState = vim.inputState; + function repeatCommand() { + if (isAction) { + commandDispatcher.processAction(cm, vim, vim.lastEditActionCommand); + } else { + commandDispatcher.evalInput(cm, vim); + } + } + function repeatInsert(repeat) { + if (macroModeState.lastInsertModeChanges.changes.length > 0) { + // For some reason, repeat cw in desktop VIM does not repeat + // insert mode changes. Will conform to that behavior. + repeat = !vim.lastEditActionCommand ? 1 : repeat; + var changeObject = macroModeState.lastInsertModeChanges; + repeatInsertModeChanges(cm, changeObject.changes, repeat); + } + } + vim.inputState = vim.lastEditInputState; + if (isAction && vim.lastEditActionCommand.interlaceInsertRepeat) { + // o and O repeat have to be interlaced with insert repeats so that the + // insertions appear on separate lines instead of the last line. + for (var i = 0; i < repeat; i++) { + repeatCommand(); + repeatInsert(1); + } + } else { + if (!repeatForInsert) { + // Hack to get the cursor to end up at the right place. If I is + // repeated in insert mode repeat, cursor will be 1 insert + // change set left of where it should be. + repeatCommand(); + } + repeatInsert(repeat); + } + vim.inputState = cachedInputState; + if (vim.insertMode && !repeatForInsert) { + // Don't exit insert mode twice. If repeatForInsert is set, then we + // were called by an exitInsertMode call lower on the stack. + exitInsertMode(cm); + } + macroModeState.isPlaying = false; + }; + + function repeatInsertModeChanges(cm, changes, repeat) { + function keyHandler(binding) { + if (typeof binding == 'string') { + CodeMirror.commands[binding](cm); + } else { + binding(cm); + } + return true; + } + var head = cm.getCursor('head'); + var inVisualBlock = vimGlobalState.macroModeState.lastInsertModeChanges.inVisualBlock; + if (inVisualBlock) { + // Set up block selection again for repeating the changes. + var vim = cm.state.vim; + var lastSel = vim.lastSelection; + var offset = getOffset(lastSel.anchor, lastSel.head); + selectForInsert(cm, head, offset.line + 1); + repeat = cm.listSelections().length; + cm.setCursor(head); + } + for (var i = 0; i < repeat; i++) { + if (inVisualBlock) { + cm.setCursor(offsetCursor(head, i, 0)); + } + for (var j = 0; j < changes.length; j++) { + var change = changes[j]; + if (change instanceof InsertModeKey) { + CodeMirror.lookupKey(change.keyName, 'vim-insert', keyHandler); + } else { + var cur = cm.getCursor(); + cm.replaceRange(change, cur, cur); + } + } + } + if (inVisualBlock) { + cm.setCursor(offsetCursor(head, 0, 1)); + } + } + + resetVimGlobalState(); + //}; + // Initialize Vim and make it available as an API. + CodeMirror.Vim = Vim(); + + Vim = CodeMirror.Vim; + + var specialKey = {'return':'CR',backspace:'BS','delete':'Del',esc:'Esc', + left:'Left',right:'Right',up:'Up',down:'Down',space: 'Space', + home:'Home',end:'End',pageup:'PageUp',pagedown:'PageDown', enter: 'CR' + }; + function lookupKey(hashId, key, e) { + if (key.length > 1 && key[0] == "n") { + key = key.replace("numpad", ""); + } + key = specialKey[key] || key; + var name = ''; + if (e.ctrlKey) { name += 'C-'; } + if (e.altKey) { name += 'A-'; } + if (e.shiftKey) { name += 'S-'; } + + name += key; + if (name.length > 1) { name = '<' + name + '>'; } + return name; + } + var handleKey = Vim.handleKey.bind(Vim); + Vim.handleKey = function(cm, key, origin) { + return cm.operation(function() { + return handleKey(cm, key, origin); + }, true); + } + function cloneVimState(state) { + var n = new state.constructor(); + Object.keys(state).forEach(function(key) { + var o = state[key]; + if (Array.isArray(o)) + o = o.slice(); + else if (o && typeof o == "object" && o.constructor != Object) + o = cloneVimState(o); + n[key] = o; + }); + if (state.sel) { + n.sel = { + head: state.sel.head && copyCursor(state.sel.head), + anchor: state.sel.anchor && copyCursor(state.sel.anchor) + }; + } + return n; + } + function multiSelectHandleKey(cm, key, origin) { + var isHandled = false; + var vim = Vim.maybeInitVimState_(cm); + var visualBlock = vim.visualBlock || vim.wasInVisualBlock; + if (vim.wasInVisualBlock && !cm.ace.inMultiSelectMode) { + vim.wasInVisualBlock = false; + } else if (cm.ace.inMultiSelectMode && vim.visualBlock) { + vim.wasInVisualBlock = true; + } + + if (key == '' && !vim.insertMode && !vim.visualMode && cm.ace.inMultiSelectMode) { + cm.ace.exitMultiSelectMode(); + } else if (visualBlock || !cm.ace.inMultiSelectMode || cm.ace.inVirtualSelectionMode) { + isHandled = Vim.handleKey(cm, key, origin); + } else { + var old = cloneVimState(vim); + cm.operation(function() { + cm.ace.forEachSelection(function() { + var sel = cm.ace.selection; + cm.state.vim.lastHPos = sel.$desiredColumn == null ? sel.lead.column : sel.$desiredColumn; + var head = cm.getCursor("head"); + var anchor = cm.getCursor("anchor"); + var headOffset = !cursorIsBefore(head, anchor) ? -1 : 0; + var anchorOffset = cursorIsBefore(head, anchor) ? -1 : 0; + head = offsetCursor(head, 0, headOffset); + anchor = offsetCursor(anchor, 0, anchorOffset); + cm.state.vim.sel.head = head; + cm.state.vim.sel.anchor = anchor; + + isHandled = handleKey(cm, key, origin); + sel.$desiredColumn = cm.state.vim.lastHPos == -1 ? null : cm.state.vim.lastHPos; + if (cm.virtualSelectionMode()) { + cm.state.vim = cloneVimState(old); + } + }); + if (cm.curOp.cursorActivity && !isHandled) + cm.curOp.cursorActivity = false; + }, true); + } + return isHandled; + }; + exports.CodeMirror = CodeMirror; + var getVim = Vim.maybeInitVimState_; + exports.handler = { + $id: "ace/keyboard/vim", + drawCursor: function(style, pixelPos, config, sel, session) { + var vim = this.state.vim || {}; + var w = config.characterWidth; + var h = config.lineHeight; + var top = pixelPos.top; + var left = pixelPos.left; + if (!vim.insertMode) { + var isbackwards = !sel.cursor + ? session.selection.isBackwards() || session.selection.isEmpty() + : Range.comparePoints(sel.cursor, sel.start) <= 0 + if (!isbackwards && left > w) + left -= w + } + if (!vim.insertMode && vim.status) { + h = h / 2; + top += h; + } + style.left = left + "px"; + style.top = top + "px"; + style.width = w + "px"; + style.height = h + "px"; + }, + handleKeyboard: function(data, hashId, key, keyCode, e) { + var editor = data.editor; + var cm = editor.state.cm; + var vim = getVim(cm); + if (keyCode == -1) return; + + if (key == "c" && hashId == 1) { // key == "ctrl-c" + if (!useragent.isMac && editor.getCopyText()) { + editor.once("copy", function() { + editor.selection.clearSelection(); + }); + return {command: "null", passEvent: true}; + } + } else if (!vim.insertMode) { + if (useragent.isMac && this.handleMacRepeat(data, hashId, key)) { + hashId = -1; + key = data.inputChar; + } + } + + if (hashId == -1 || hashId & 1 || hashId === 0 && key.length > 1) { + var insertMode = vim.insertMode; + var name = lookupKey(hashId, key, e || {}); + if (vim.status == null) + vim.status = ""; + var isHandled = multiSelectHandleKey(cm, name, 'user'); + vim = getVim(cm); // may be changed by multiSelectHandleKey + if (isHandled && vim.status != null) + vim.status += name; + else if (vim.status == null) + vim.status = ""; + cm._signal("changeStatus"); + if (!isHandled && (hashId != -1 || insertMode)) + return; + return {command: "null", passEvent: !isHandled}; + } + }, + attach: function(editor) { + if (!editor.state) editor.state = {}; + var cm = new CodeMirror(editor); + editor.state.cm = cm; + editor.$vimModeHandler = this; + CodeMirror.keyMap.vim.attach(cm); + getVim(cm).status = null; + cm.on('vim-command-done', function() { + if (cm.virtualSelectionMode()) return; + getVim(cm).status = null; + cm.ace._signal("changeStatus"); + cm.ace.session.markUndoGroup(); + }); + cm.on("changeStatus", function() { + cm.ace.renderer.updateCursor(); + cm.ace._signal("changeStatus"); + }); + cm.on("vim-mode-change", function() { + if (cm.virtualSelectionMode()) return; + cm.ace.renderer.setStyle("normal-mode", !getVim(cm).insertMode); + cm._signal("changeStatus"); + }); + cm.ace.renderer.setStyle("normal-mode", !getVim(cm).insertMode); + editor.renderer.$cursorLayer.drawCursor = this.drawCursor.bind(cm); + // renderVirtualNumbers.attach(editor); + this.updateMacCompositionHandlers(editor, true); + }, + detach: function(editor) { + var cm = editor.state.cm; + CodeMirror.keyMap.vim.detach(cm); + cm.destroy(); + editor.state.cm = null; + editor.$vimModeHandler = null; + editor.renderer.$cursorLayer.drawCursor = null; + editor.renderer.setStyle("normal-mode", false); + // renderVirtualNumbers.detach(editor); + this.updateMacCompositionHandlers(editor, false); + }, + getStatusText: function(editor) { + var cm = editor.state.cm; + var vim = getVim(cm); + if (vim.insertMode) + return "INSERT"; + var status = ""; + if (vim.visualMode) { + status += "VISUAL"; + if (vim.visualLine) + status += " LINE"; + if (vim.visualBlock) + status += " BLOCK"; + } + if (vim.status) + status += (status ? " " : "") + vim.status; + return status; + }, + // workaround for j not repeating with `defaults write -g ApplePressAndHoldEnabled -bool true` + handleMacRepeat: function(data, hashId, key) { + if (hashId == -1) { + // record key + data.inputChar = key; + data.lastEvent = "input"; + } else if (data.inputChar && data.$lastHash == hashId && data.$lastKey == key) { + // check for repeated keypress + if (data.lastEvent == "input") { + data.lastEvent = "input1"; + } else if (data.lastEvent == "input1") { + // simulate textinput + return true; + } + } else { + // reset + data.$lastHash = hashId; + data.$lastKey = key; + data.lastEvent = "keypress"; + } + }, + // on mac, with some keyboard layouts (e.g swedish) ^ starts composition, we don't need it in normal mode + updateMacCompositionHandlers: function(editor, enable) { + var onCompositionUpdateOverride = function(text) { + var cm = editor.state.cm; + var vim = getVim(cm); + if (!vim.insertMode) { + var el = this.textInput.getElement(); + el.blur(); + el.focus(); + el.value = text; + } else { + this.onCompositionUpdateOrig(text); + } + }; + var onCompositionStartOverride = function(text) { + var cm = editor.state.cm; + var vim = getVim(cm); + if (!vim.insertMode) { + this.onCompositionStartOrig(text); + } + }; + if (enable) { + if (!editor.onCompositionUpdateOrig) { + editor.onCompositionUpdateOrig = editor.onCompositionUpdate; + editor.onCompositionUpdate = onCompositionUpdateOverride; + editor.onCompositionStartOrig = editor.onCompositionStart; + editor.onCompositionStart = onCompositionStartOverride; + } + } else { + if (editor.onCompositionUpdateOrig) { + editor.onCompositionUpdate = editor.onCompositionUpdateOrig; + editor.onCompositionUpdateOrig = null; + editor.onCompositionStart = editor.onCompositionStartOrig; + editor.onCompositionStartOrig = null; + } + } + } + } + var renderVirtualNumbers = { + getText: function(session, row) { + return (Math.abs(session.selection.lead.row - row) || (row + 1 + (row < 9? "\xb7" : "" ))) + "" + }, + getWidth: function(session, lastLineNumber, config) { + return session.getLength().toString().length * config.characterWidth; + }, + update: function(e, editor) { + editor.renderer.$loop.schedule(editor.renderer.CHANGE_GUTTER) + }, + attach: function(editor) { + editor.renderer.$gutterLayer.$renderer = this; + editor.on("changeSelection", this.update); + }, + detach: function(editor) { + editor.renderer.$gutterLayer.$renderer = null; + editor.off("changeSelection", this.update); + } + }; + Vim.defineOption({ + name: "wrap", + set: function(value, cm) { + if (cm) {cm.ace.setOption("wrap", value)} + }, + type: "boolean" + }, false); + defaultKeymap.push( + { keys: 'zc', type: 'action', action: 'fold', actionArgs: { open: false } }, + { keys: 'zC', type: 'action', action: 'fold', actionArgs: { open: false, all: true } }, + { keys: 'zo', type: 'action', action: 'fold', actionArgs: { open: true, } }, + { keys: 'zO', type: 'action', action: 'fold', actionArgs: { open: true, all: true } }, + { keys: 'za', type: 'action', action: 'fold', actionArgs: { toggle: true } }, + { keys: 'zA', type: 'action', action: 'fold', actionArgs: { toggle: true, all: true } }, + { keys: 'zf', type: 'action', action: 'fold', actionArgs: { open: true, all: true } }, + { keys: 'zd', type: 'action', action: 'fold', actionArgs: { open: true, all: true } }, + + { keys: '', type: 'action', action: 'aceCommand', actionArgs: { name: "addCursorAbove" } }, + { keys: '', type: 'action', action: 'aceCommand', actionArgs: { name: "addCursorBelow" } }, + { keys: '', type: 'action', action: 'aceCommand', actionArgs: { name: "addCursorAboveSkipCurrent" } }, + { keys: '', type: 'action', action: 'aceCommand', actionArgs: { name: "addCursorBelowSkipCurrent" } }, + { keys: '', type: 'action', action: 'aceCommand', actionArgs: { name: "selectMoreBefore" } }, + { keys: '', type: 'action', action: 'aceCommand', actionArgs: { name: "selectMoreAfter" } }, + { keys: '', type: 'action', action: 'aceCommand', actionArgs: { name: "selectNextBefore" } }, + { keys: '', type: 'action', action: 'aceCommand', actionArgs: { name: "selectNextAfter" } } + ); + actions.aceCommand = function(cm, actionArgs, vim) { + cm.vimCmd = actionArgs; + if (cm.ace.inVirtualSelectionMode) + cm.ace.on("beforeEndOperation", delayedExecAceCommand); + else + delayedExecAceCommand(null, cm.ace) + }; + function delayedExecAceCommand(op, ace) { + ace.off("beforeEndOperation", delayedExecAceCommand); + var cmd = ace.state.cm.vimCmd; + if (cmd) { + ace.execCommand(cmd.exec ? cmd : cmd.name, cmd.args); + } + ace.curOp = ace.prevOp; + } + actions.fold = function(cm, actionArgs, vim) { + cm.ace.execCommand(['toggleFoldWidget', 'toggleFoldWidget', 'foldOther', 'unfoldall' + ][(actionArgs.all ? 2 : 0) + (actionArgs.open ? 1 : 0)]); + }, + + exports.handler.defaultKeymap = defaultKeymap; + exports.handler.actions = actions; + exports.Vim = Vim; + + Vim.map("Y", "yy"); +}); diff --git a/node_modules/ace/lib/ace/keyboard/vim_test.js b/node_modules/ace/lib/ace/keyboard/vim_test.js new file mode 100644 index 00000000..8b726a33 --- /dev/null +++ b/node_modules/ace/lib/ace/keyboard/vim_test.js @@ -0,0 +1,3866 @@ + +if (typeof process !== "undefined") { + require("amd-loader"); +} + +define(function(require, exports, module) { + +var EditSession = require("./../edit_session").EditSession; +var Editor = require("./../editor").Editor; +var UndoManager = require("./../undomanager").UndoManager; +var MockRenderer = require("./../test/mockrenderer").MockRenderer; +var JavaScriptMode = require("./../mode/javascript").Mode; +var VirtualRenderer = require("./../virtual_renderer").VirtualRenderer; +var assert = require("./../test/assertions"); +var keys = require("./../lib/keys"); +var vim = require("./vim"); + +var el = document.createElement("div"); +el.style.position = "fixed"; +el.style.left = "20px"; +el.style.top = "30px"; +el.style.width = "500px"; +el.style.height = "300px"; +document.body.appendChild(el); + +if (!el.getBoundingClientRect) + return console.log("Skipping test: This test only runs in the browser"); + +var renderer = new VirtualRenderer(el); +editor = new Editor(renderer);//(new MockRenderer()); +editor.session.setUndoManager(new UndoManager()); +editor.session.setUseWorker(false); +editor.session.setMode(new JavaScriptMode()); +function CodeMirror(place, opts) { + if (opts.value != null) + editor.session.setValue(opts.value); + editor.setOption("wrap", opts.lineWrapping); + editor.setOption("useSoftTabs", !opts.indentWithTabs); + editor.setKeyboardHandler(null); + editor.setKeyboardHandler(vim.handler); + var cm = editor.state.cm; + cm.setOption("tabSize", opts.tabSize || 4); + cm.setOption("indentUnit", opts.indentUnit || 2); + + cm.setSize = function(w, h) { + var changed = false; + if (w && editor.w != w) { + changed = true; + el.style.width = (editor.w = w) + "px"; + } + if (h && editor.h != h) { + changed = true; + el.style.height = (editor.h = h) + "px"; + } + if (changed) + editor.resize(true); + }; + cm.setSize(500, 300); + return cm; +} +for (var key in vim.CodeMirror) + CodeMirror[key] = vim.CodeMirror[key]; +var editor; +var i = 0; +function test(name, fn) { + // if (name != 'vim_search_history') return + // for (i = 0; i < 1000; i++) + // exports["test " + name + i] = fn; // vim_ex_global_confirm + if (i++ < 0 || /- /.test(name)) + exports["test " + name] = function() {}; + else + exports["test " + name] = fn; +} + +vim.CodeMirror.Vim.unmap("Y"); + + + +// cm.setBookmark({ch: 5, line: 0}) +// cm.setBookmark({ch: 4, line: 0}) +// cm.replaceRange("x-", {ch: 4, line: 0}, {ch: 5, line: 0}); [editor.$vimModeHandler.cm.marks[0].find(),editor.$vimModeHandler.cm.marks[1].find()] + +var lineText, verbose, phantom; +var Pos = CodeMirror.Pos; +var place = document.createElement("div"); +var eqPos = assert.deepEqual; +var eq = assert.equal; +var is = assert.ok; + + +var code = '' + +' wOrd1 (#%\n' + +' word3] \n' + +'aopop pop 0 1 2 3 4\n' + +' (a) [b] {c} \n' + +'int getchar(void) {\n' + +' static char buf[BUFSIZ];\n' + +' static char *bufp = buf;\n' + +' if (n == 0) { /* buffer is empty */\n' + +' n = read(0, buf, sizeof buf);\n' + +' bufp = buf;\n' + +' }\n' + +'\n' + +' return (--n >= 0) ? (unsigned char) *bufp++ : EOF;\n' + +' \n' + +'}\n'; + +var lines = (function() { + lineText = code.split('\n'); + var ret = []; + for (var i = 0; i < lineText.length; i++) { + ret[i] = { + line: i, + length: lineText[i].length, + lineText: lineText[i], + textStart: /^\s*/.exec(lineText[i])[0].length + }; + } + return ret; +})(); +var endOfDocument = makeCursor(lines.length - 1, + lines[lines.length - 1].length); +var wordLine = lines[0]; +var bigWordLine = lines[1]; +var charLine = lines[2]; +var bracesLine = lines[3]; +var seekBraceLine = lines[4]; + +var word1 = { + start: { line: wordLine.line, ch: 1 }, + end: { line: wordLine.line, ch: 5 } +}; +var word2 = { + start: { line: wordLine.line, ch: word1.end.ch + 2 }, + end: { line: wordLine.line, ch: word1.end.ch + 4 } +}; +var word3 = { + start: { line: bigWordLine.line, ch: 1 }, + end: { line: bigWordLine.line, ch: 5 } +}; +var bigWord1 = word1; +var bigWord2 = word2; +var bigWord3 = { + start: { line: bigWordLine.line, ch: 1 }, + end: { line: bigWordLine.line, ch: 7 } +}; +var bigWord4 = { + start: { line: bigWordLine.line, ch: bigWord1.end.ch + 3 }, + end: { line: bigWordLine.line, ch: bigWord1.end.ch + 7 } +}; + +var oChars = [ { line: charLine.line, ch: 1 }, + { line: charLine.line, ch: 3 }, + { line: charLine.line, ch: 7 } ]; +var pChars = [ { line: charLine.line, ch: 2 }, + { line: charLine.line, ch: 4 }, + { line: charLine.line, ch: 6 }, + { line: charLine.line, ch: 8 } ]; +var numChars = [ { line: charLine.line, ch: 10 }, + { line: charLine.line, ch: 12 }, + { line: charLine.line, ch: 14 }, + { line: charLine.line, ch: 16 }, + { line: charLine.line, ch: 18 }]; +var parens1 = { + start: { line: bracesLine.line, ch: 1 }, + end: { line: bracesLine.line, ch: 3 } +}; +var squares1 = { + start: { line: bracesLine.line, ch: 5 }, + end: { line: bracesLine.line, ch: 7 } +}; +var curlys1 = { + start: { line: bracesLine.line, ch: 9 }, + end: { line: bracesLine.line, ch: 11 } +}; +var seekOutside = { + start: { line: seekBraceLine.line, ch: 1 }, + end: { line: seekBraceLine.line, ch: 16 } +}; +var seekInside = { + start: { line: seekBraceLine.line, ch: 14 }, + end: { line: seekBraceLine.line, ch: 11 } +}; + +function copyCursor(cur) { + return { ch: cur.ch, line: cur.line }; +} + +function forEach(arr, func) { + for (var i = 0; i < arr.length; i++) { + func(arr[i], i, arr); + } +} + +function testVim(name, run, opts, expectedFail) { + var vimOpts = { + lineNumbers: true, + vimMode: true, + showCursorWhenSelecting: true, + value: code + }; + for (var prop in opts) { + if (opts.hasOwnProperty(prop)) { + vimOpts[prop] = opts[prop]; + } + } + return test('vim_' + name, function() { + var place = document.getElementById("testground"); + var cm = CodeMirror(place, vimOpts); + var vim = CodeMirror.Vim.maybeInitVimState_(cm); + + function doKeysFn(cm) { + return function(args) { + if (args instanceof Array) { + arguments = args; + } + for (var i = 0; i < arguments.length; i++) { + CodeMirror.Vim.handleKey(cm, arguments[i]); + } + } + } + function doInsertModeKeysFn(cm) { + return function(args) { + if (args instanceof Array) { arguments = args; } + function executeHandler(handler) { + if (typeof handler == 'string') { + CodeMirror.commands[handler](cm); + } else { + handler(cm); + } + return true; + } + for (var i = 0; i < arguments.length; i++) { + var key = arguments[i]; + // Find key in keymap and handle. + var handled = CodeMirror.lookupKey(key, 'vim-insert', executeHandler); + // Record for insert mode. + if (handled == "handled" && cm.state.vim.insertMode && arguments[i] != 'Esc') { + var lastChange = CodeMirror.Vim.getVimGlobalState_().macroModeState.lastInsertModeChanges; + if (lastChange) { + lastChange.changes.push(new CodeMirror.Vim.InsertModeKey(key)); + } + } + } + } + } + function doExFn(cm) { + return function(command) { + cm.openDialog = helpers.fakeOpenDialog(command); + helpers.doKeys(':'); + } + } + function assertCursorAtFn(cm) { + return function(line, ch) { + var pos; + if (ch == null && typeof line.line == 'number') { + pos = line; + } else { + pos = makeCursor(line, ch); + } + eqPos(pos, cm.getCursor()); + } + } + function fakeOpenDialog(result) { + return function(text, callback) { + return callback(result); + } + } + function fakeOpenNotification(matcher) { + return function(text) { + matcher(text); + } + } + var helpers = { + doKeys: doKeysFn(cm), + // Warning: Only emulates keymap events, not character insertions. Use + // replaceRange to simulate character insertions. + // Keys are in CodeMirror format, NOT vim format. + doInsertModeKeys: doInsertModeKeysFn(cm), + doEx: doExFn(cm), + assertCursorAt: assertCursorAtFn(cm), + fakeOpenDialog: fakeOpenDialog, + fakeOpenNotification: fakeOpenNotification, + getRegisterController: function() { + return CodeMirror.Vim.getRegisterController(); + } + } + CodeMirror.Vim.resetVimGlobalState_(); + var successful = false; + var savedOpenNotification = cm.openNotification; + try { + run(cm, vim, helpers); + successful = true; + } finally { + cm.openNotification = savedOpenNotification; + // if (!successful || verbose) { + // place.style.visibility = "visible"; + // } else { + // place.removeChild(cm.getWrapperElement()); + // } + } + }, expectedFail); +}; +testVim('qq@q', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('q', 'q', 'l', 'l', 'q'); + helpers.assertCursorAt(0,2); + helpers.doKeys('@', 'q'); + helpers.assertCursorAt(0,4); +}, { value: ' '}); +testVim('@@', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('q', 'q', 'l', 'l', 'q'); + helpers.assertCursorAt(0,2); + helpers.doKeys('@', 'q'); + helpers.assertCursorAt(0,4); + helpers.doKeys('@', '@'); + helpers.assertCursorAt(0,6); +}, { value: ' '}); +var jumplistScene = ''+ + 'word\n'+ + '(word)\n'+ + '{word\n'+ + 'word.\n'+ + '\n'+ + 'word search\n'+ + '}word\n'+ + 'word\n'+ + 'word\n'; +function testJumplist(name, keys, endPos, startPos, dialog) { + endPos = makeCursor(endPos[0], endPos[1]); + startPos = makeCursor(startPos[0], startPos[1]); + testVim(name, function(cm, vim, helpers) { + CodeMirror.Vim.resetVimGlobalState_(); + if(dialog)cm.openDialog = helpers.fakeOpenDialog('word'); + cm.setCursor(startPos); + helpers.doKeys.apply(null, keys); + helpers.assertCursorAt(endPos); + }, {value: jumplistScene}); +}; +testJumplist('jumplist_H', ['H', ''], [5,2], [5,2]); +testJumplist('jumplist_M', ['M', ''], [2,2], [2,2]); +testJumplist('jumplist_L', ['L', ''], [2,2], [2,2]); +testJumplist('jumplist_[[', ['[', '[', ''], [5,2], [5,2]); +testJumplist('jumplist_]]', [']', ']', ''], [2,2], [2,2]); +testJumplist('jumplist_G', ['G', ''], [5,2], [5,2]); +testJumplist('jumplist_gg', ['g', 'g', ''], [5,2], [5,2]); +testJumplist('jumplist_%', ['%', ''], [1,5], [1,5]); +testJumplist('jumplist_{', ['{', ''], [1,5], [1,5]); +testJumplist('jumplist_}', ['}', ''], [1,5], [1,5]); +testJumplist('jumplist_\'', ['m', 'a', 'h', '\'', 'a', 'h', ''], [1,0], [1,5]); +testJumplist('jumplist_`', ['m', 'a', 'h', '`', 'a', 'h', ''], [1,5], [1,5]); +testJumplist('jumplist_*_cachedCursor', ['*', ''], [1,3], [1,3]); +testJumplist('jumplist_#_cachedCursor', ['#', ''], [1,3], [1,3]); +testJumplist('jumplist_n', ['#', 'n', ''], [1,1], [2,3]); +testJumplist('jumplist_N', ['#', 'N', ''], [1,1], [2,3]); +testJumplist('jumplist_repeat_', ['*', '*', '*', '3', ''], [2,3], [2,3]); +testJumplist('jumplist_repeat_', ['*', '*', '*', '3', '', '2', ''], [5,0], [2,3]); +testJumplist('jumplist_repeated_motion', ['3', '*', ''], [2,3], [2,3]); +testJumplist('jumplist_/', ['/', ''], [2,3], [2,3], 'dialog'); +testJumplist('jumplist_?', ['?', ''], [2,3], [2,3], 'dialog'); +testJumplist('jumplist_skip_delted_mark', + ['*', 'n', 'n', 'k', 'd', 'k', '', '', ''], + [0,2], [0,2]); +testJumplist('jumplist_skip_delted_mark', + ['*', 'n', 'n', 'k', 'd', 'k', '', '', ''], + [1,0], [0,2]); + +/** + * @param name Name of the test + * @param keys An array of keys or a string with a single key to simulate. + * @param endPos The expected end position of the cursor. + * @param startPos The position the cursor should start at, defaults to 0, 0. + */ +function testMotion(name, keys, endPos, startPos) { + testVim(name, function(cm, vim, helpers) { + if (!startPos) { + startPos = { line: 0, ch: 0 }; + } + cm.setCursor(startPos); + helpers.doKeys(keys); + helpers.assertCursorAt(endPos); + }); +}; + +function makeCursor(line, ch) { + return { line: line, ch: ch }; +}; + +function offsetCursor(cur, offsetLine, offsetCh) { + return { line: cur.line + offsetLine, ch: cur.ch + offsetCh }; +}; + +// Motion tests +testMotion('|', '|', makeCursor(0, 0), makeCursor(0,4)); +testMotion('|_repeat', ['3', '|'], makeCursor(0, 2), makeCursor(0,4)); +testMotion('h', 'h', makeCursor(0, 0), word1.start); +testMotion('h_repeat', ['3', 'h'], offsetCursor(word1.end, 0, -3), word1.end); +testMotion('l', 'l', makeCursor(0, 1)); +testMotion('l_repeat', ['2', 'l'], makeCursor(0, 2)); +testMotion('j', 'j', offsetCursor(word1.end, 1, 0), word1.end); +testMotion('j_repeat', ['2', 'j'], offsetCursor(word1.end, 2, 0), word1.end); +testMotion('j_repeat_clip', ['1000', 'j'], endOfDocument); +testMotion('k', 'k', offsetCursor(word3.end, -1, 0), word3.end); +testMotion('k_repeat', ['2', 'k'], makeCursor(0, 4), makeCursor(2, 4)); +testMotion('k_repeat_clip', ['1000', 'k'], makeCursor(0, 4), makeCursor(2, 4)); +testMotion('w', 'w', word1.start); +testMotion('w_multiple_newlines_no_space', 'w', makeCursor(12, 2), makeCursor(11, 2)); +testMotion('w_multiple_newlines_with_space', 'w', makeCursor(14, 0), makeCursor(12, 51)); +testMotion('w_repeat', ['2', 'w'], word2.start); +testMotion('w_wrap', ['w'], word3.start, word2.start); +testMotion('w_endOfDocument', 'w', endOfDocument, endOfDocument); +testMotion('w_start_to_end', ['1000', 'w'], endOfDocument, makeCursor(0, 0)); +testMotion('W', 'W', bigWord1.start); +testMotion('W_repeat', ['2', 'W'], bigWord3.start, bigWord1.start); +testMotion('e', 'e', word1.end); +testMotion('e_repeat', ['2', 'e'], word2.end); +testMotion('e_wrap', 'e', word3.end, word2.end); +testMotion('e_endOfDocument', 'e', endOfDocument, endOfDocument); +testMotion('e_start_to_end', ['1000', 'e'], endOfDocument, makeCursor(0, 0)); +testMotion('b', 'b', word3.start, word3.end); +testMotion('b_repeat', ['2', 'b'], word2.start, word3.end); +testMotion('b_wrap', 'b', word2.start, word3.start); +testMotion('b_startOfDocument', 'b', makeCursor(0, 0), makeCursor(0, 0)); +testMotion('b_end_to_start', ['1000', 'b'], makeCursor(0, 0), endOfDocument); +testMotion('ge', ['g', 'e'], word2.end, word3.end); +testMotion('ge_repeat', ['2', 'g', 'e'], word1.end, word3.start); +testMotion('ge_wrap', ['g', 'e'], word2.end, word3.start); +testMotion('ge_startOfDocument', ['g', 'e'], makeCursor(0, 0), + makeCursor(0, 0)); +testMotion('ge_end_to_start', ['1000', 'g', 'e'], makeCursor(0, 0), endOfDocument); +testMotion('gg', ['g', 'g'], makeCursor(lines[0].line, lines[0].textStart), + makeCursor(3, 1)); +testMotion('gg_repeat', ['3', 'g', 'g'], + makeCursor(lines[2].line, lines[2].textStart)); +testMotion('G', 'G', + makeCursor(lines[lines.length - 1].line, lines[lines.length - 1].textStart), + makeCursor(3, 1)); +testMotion('G_repeat', ['3', 'G'], makeCursor(lines[2].line, + lines[2].textStart)); +// TODO: Make the test code long enough to test Ctrl-F and Ctrl-B. +testMotion('0', '0', makeCursor(0, 0), makeCursor(0, 8)); +testMotion('^', '^', makeCursor(0, lines[0].textStart), makeCursor(0, 8)); +testMotion('+', '+', makeCursor(1, lines[1].textStart), makeCursor(0, 8)); +testMotion('-', '-', makeCursor(0, lines[0].textStart), makeCursor(1, 4)); +testMotion('_', ['6','_'], makeCursor(5, lines[5].textStart), makeCursor(0, 8)); +testMotion('$', '$', makeCursor(0, lines[0].length - 1), makeCursor(0, 1)); +testMotion('$_repeat', ['2', '$'], makeCursor(1, lines[1].length - 1), + makeCursor(0, 3)); +testMotion('f', ['f', 'p'], pChars[0], makeCursor(charLine.line, 0)); +testMotion('f_repeat', ['2', 'f', 'p'], pChars[2], pChars[0]); +testMotion('f_num', ['f', '2'], numChars[2], makeCursor(charLine.line, 0)); +testMotion('t', ['t','p'], offsetCursor(pChars[0], 0, -1), + makeCursor(charLine.line, 0)); +testMotion('t_repeat', ['2', 't', 'p'], offsetCursor(pChars[2], 0, -1), + pChars[0]); +testMotion('F', ['F', 'p'], pChars[0], pChars[1]); +testMotion('F_repeat', ['2', 'F', 'p'], pChars[0], pChars[2]); +testMotion('T', ['T', 'p'], offsetCursor(pChars[0], 0, 1), pChars[1]); +testMotion('T_repeat', ['2', 'T', 'p'], offsetCursor(pChars[0], 0, 1), pChars[2]); +testMotion('%_parens', ['%'], parens1.end, parens1.start); +testMotion('%_squares', ['%'], squares1.end, squares1.start); +testMotion('%_braces', ['%'], curlys1.end, curlys1.start); +testMotion('%_seek_outside', ['%'], seekOutside.end, seekOutside.start); +testMotion('%_seek_inside', ['%'], seekInside.end, seekInside.start); +testVim('%_seek_skip', function(cm, vim, helpers) { + cm.setCursor(0,0); + helpers.doKeys(['%']); + helpers.assertCursorAt(0,9); +}, {value:'01234"("()'}); +testVim('%_skip_string', function(cm, vim, helpers) { + cm.setCursor(0,0); + helpers.doKeys(['%']); + helpers.assertCursorAt(0,4); + cm.setCursor(0,2); + helpers.doKeys(['%']); + helpers.assertCursorAt(0,0); +}, {value:'(")")'}); +(')') +testVim('%_skip_comment', function(cm, vim, helpers) { + cm.setCursor(0,0); + helpers.doKeys(['%']); + helpers.assertCursorAt(0,6); + cm.setCursor(0,3); + helpers.doKeys(['%']); + helpers.assertCursorAt(0,0); +}, {value:'(/*)*/)'}); +// Make sure that moving down after going to the end of a line always leaves you +// at the end of a line, but preserves the offset in other cases +testVim('Changing lines after Eol operation', function(cm, vim, helpers) { + cm.setCursor(0,0); + helpers.doKeys(['$']); + helpers.doKeys(['j']); + // After moving to Eol and then down, we should be at Eol of line 2 + helpers.assertCursorAt({ line: 1, ch: lines[1].length - 1 }); + helpers.doKeys(['j']); + // After moving down, we should be at Eol of line 3 + helpers.assertCursorAt({ line: 2, ch: lines[2].length - 1 }); + helpers.doKeys(['h']); + helpers.doKeys(['j']); + // After moving back one space and then down, since line 4 is shorter than line 2, we should + // be at Eol of line 2 - 1 + helpers.assertCursorAt({ line: 3, ch: lines[3].length - 1 }); + helpers.doKeys(['j']); + helpers.doKeys(['j']); + // After moving down again, since line 3 has enough characters, we should be back to the + // same place we were at on line 1 + helpers.assertCursorAt({ line: 5, ch: lines[2].length - 2 }); +}); +//making sure gj and gk recover from clipping +testVim('gj_gk_clipping', function(cm,vim,helpers){ + cm.setCursor(0, 1); + helpers.doKeys('g','j','g','j'); + helpers.assertCursorAt(2, 1); + helpers.doKeys('g','k','g','k'); + helpers.assertCursorAt(0, 1); +},{value: 'line 1\n\nline 2'}); +//testing a mix of j/k and gj/gk +testVim('j_k_and_gj_gk', function(cm,vim,helpers){ + cm.setSize(120); + cm.setCursor(0, 0); + //go to the last character on the first line + helpers.doKeys('$'); + //move up/down on the column within the wrapped line + //side-effect: cursor is not locked to eol anymore + helpers.doKeys('g','k'); + var cur=cm.getCursor(); + eq(cur.line,0); + is((cur.ch<176),'gk didn\'t move cursor back (1)'); + helpers.doKeys('g','j'); + helpers.assertCursorAt(0, 176); + //should move to character 177 on line 2 (j/k preserve character index within line) + helpers.doKeys('j'); + //due to different line wrapping, the cursor can be on a different screen-x now + //gj and gk preserve screen-x on movement, much like moveV + helpers.doKeys('3','g','k'); + cur=cm.getCursor(); + eq(cur.line,1); + is((cur.ch<176),'gk didn\'t move cursor back (2)'); + helpers.doKeys('g','j','2','g','j'); + //should return to the same character-index + helpers.doKeys('k'); + helpers.assertCursorAt(0, 176); +},{ lineWrapping:true, value: 'This line is intentially long to test movement of gj and gk over wrapped lines. I will start on the end of this line, then make a step up and back to set the origin for j and k.\nThis line is supposed to be even longer than the previous. I will jump here and make another wiggle with gj and gk, before I jump back to the line above. Both wiggles should not change my cursor\'s target character but both j/k and gj/gk change each other\'s reference position.'}); +testVim('gj_gk', function(cm, vim, helpers) { + if (phantom) return; + cm.setSize(120); + // Test top of document edge case. + cm.setCursor(0, 4); + helpers.doKeys('g', 'j'); + helpers.doKeys('10', 'g', 'k'); + helpers.assertCursorAt(0, 4); + + // Test moving down preserves column position. + helpers.doKeys('g', 'j'); + var pos1 = cm.getCursor(); + var expectedPos2 = { line: 0, ch: (pos1.ch - 4) * 2 + 4}; + helpers.doKeys('g', 'j'); + helpers.assertCursorAt(expectedPos2); + + // Move to the last character + cm.setCursor(0, 0); + // Move left to reset HSPos + helpers.doKeys('h'); + // Test bottom of document edge case. + helpers.doKeys('100', 'g', 'j'); + var endingPos = cm.getCursor(); + is(endingPos != 0, 'gj should not be on wrapped line 0'); + var topLeftCharCoords = cm.charCoords(makeCursor(0, 0)); + var endingCharCoords = cm.charCoords(endingPos); + is(topLeftCharCoords.left == endingCharCoords.left, 'gj should end up on column 0'); +},{ lineNumbers: false, lineWrapping:true, value: 'Thislineisintentiallylongtotestmovementofgjandgkoverwrappedlines.' }); +testVim('}', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('}'); + helpers.assertCursorAt(1, 0); + cm.setCursor(0, 0); + helpers.doKeys('2', '}'); + helpers.assertCursorAt(4, 0); + cm.setCursor(0, 0); + helpers.doKeys('6', '}'); + helpers.assertCursorAt(5, 0); +}, { value: 'a\n\nb\nc\n\nd' }); +testVim('{', function(cm, vim, helpers) { + cm.setCursor(5, 0); + helpers.doKeys('{'); + helpers.assertCursorAt(4, 0); + cm.setCursor(5, 0); + helpers.doKeys('2', '{'); + helpers.assertCursorAt(1, 0); + cm.setCursor(5, 0); + helpers.doKeys('6', '{'); + helpers.assertCursorAt(0, 0); +}, { value: 'a\n\nb\nc\n\nd' }); +testVim('paragraph motions', function(cm, vim, helpers) { + cm.setCursor(10, 0); + helpers.doKeys('{'); + helpers.assertCursorAt(4, 0); + helpers.doKeys('{'); + helpers.assertCursorAt(0, 0); + helpers.doKeys('2', '}'); + helpers.assertCursorAt(7, 0); + helpers.doKeys('2', '}'); + helpers.assertCursorAt(16, 0); + + cm.setCursor(9, 0); + helpers.doKeys('}'); + helpers.assertCursorAt(14, 0); + + cm.setCursor(6, 0); + helpers.doKeys('}'); + helpers.assertCursorAt(7, 0); + + // ip inside empty space + cm.setCursor(10, 0); + helpers.doKeys('v', 'i', 'p'); + eqPos(Pos(7, 0), cm.getCursor('anchor')); + eqPos(Pos(12, 0), cm.getCursor('head')); + helpers.doKeys('i', 'p'); + eqPos(Pos(7, 0), cm.getCursor('anchor')); + eqPos(Pos(13, 1), cm.getCursor('head')); + helpers.doKeys('2', 'i', 'p'); + eqPos(Pos(7, 0), cm.getCursor('anchor')); + eqPos(Pos(16, 1), cm.getCursor('head')); + + // should switch to visualLine mode + cm.setCursor(14, 0); + helpers.doKeys('', 'v', 'i', 'p'); + helpers.assertCursorAt(14, 0); + + cm.setCursor(14, 0); + helpers.doKeys('', 'V', 'i', 'p'); + eqPos(Pos(16, 1), cm.getCursor('head')); + + // ap inside empty space + cm.setCursor(10, 0); + helpers.doKeys('', 'v', 'a', 'p'); + eqPos(Pos(7, 0), cm.getCursor('anchor')); + eqPos(Pos(13, 1), cm.getCursor('head')); + helpers.doKeys('a', 'p'); + eqPos(Pos(7, 0), cm.getCursor('anchor')); + eqPos(Pos(16, 1), cm.getCursor('head')); + + cm.setCursor(13, 0); + helpers.doKeys('v', 'a', 'p'); + eqPos(Pos(13, 0), cm.getCursor('anchor')); + eqPos(Pos(14, 0), cm.getCursor('head')); + + cm.setCursor(16, 0); + helpers.doKeys('v', 'a', 'p'); + eqPos(Pos(14, 0), cm.getCursor('anchor')); + eqPos(Pos(16, 1), cm.getCursor('head')); + + cm.setCursor(0, 0); + helpers.doKeys('v', 'a', 'p'); + eqPos(Pos(0, 0), cm.getCursor('anchor')); + eqPos(Pos(4, 0), cm.getCursor('head')); + + cm.setCursor(0, 0); + helpers.doKeys('d', 'i', 'p'); + var register = helpers.getRegisterController().getRegister(); + eq('a\na\n', register.toString()); + is(register.linewise); + helpers.doKeys('3', 'j', 'p'); + helpers.doKeys('y', 'i', 'p'); + is(register.linewise); + eq('b\na\na\nc\n', register.toString()); +}, { value: 'a\na\n\n\n\nb\nc\n\n\n\n\n\n\nd\n\ne\nf' }); + +// Operator tests +testVim('dl', function(cm, vim, helpers) { + var curStart = makeCursor(0, 0); + cm.setCursor(curStart); + helpers.doKeys('d', 'l'); + eq('word1 ', cm.getValue()); + var register = helpers.getRegisterController().getRegister(); + eq(' ', register.toString()); + is(!register.linewise); + eqPos(curStart, cm.getCursor()); +}, { value: ' word1 ' }); +testVim('dl_eol', function(cm, vim, helpers) { + cm.setCursor(0, 6); + helpers.doKeys('d', 'l'); + eq(' word1', cm.getValue()); + var register = helpers.getRegisterController().getRegister(); + eq(' ', register.toString()); + is(!register.linewise); + helpers.assertCursorAt(0, 6); +}, { value: ' word1 ' }); +testVim('dl_repeat', function(cm, vim, helpers) { + var curStart = makeCursor(0, 0); + cm.setCursor(curStart); + helpers.doKeys('2', 'd', 'l'); + eq('ord1 ', cm.getValue()); + var register = helpers.getRegisterController().getRegister(); + eq(' w', register.toString()); + is(!register.linewise); + eqPos(curStart, cm.getCursor()); +}, { value: ' word1 ' }); +testVim('dh', function(cm, vim, helpers) { + var curStart = makeCursor(0, 3); + cm.setCursor(curStart); + helpers.doKeys('d', 'h'); + eq(' wrd1 ', cm.getValue()); + var register = helpers.getRegisterController().getRegister(); + eq('o', register.toString()); + is(!register.linewise); + eqPos(offsetCursor(curStart, 0 , -1), cm.getCursor()); +}, { value: ' word1 ' }); +testVim('dj', function(cm, vim, helpers) { + var curStart = makeCursor(0, 3); + cm.setCursor(curStart); + helpers.doKeys('d', 'j'); + eq(' word3', cm.getValue()); + var register = helpers.getRegisterController().getRegister(); + eq(' word1\nword2\n', register.toString()); + is(register.linewise); + helpers.assertCursorAt(0, 1); +}, { value: ' word1\nword2\n word3' }); +testVim('dj_end_of_document', function(cm, vim, helpers) { + var curStart = makeCursor(0, 3); + cm.setCursor(curStart); + helpers.doKeys('d', 'j'); + eq(' word1 ', cm.getValue()); + var register = helpers.getRegisterController().getRegister(); + eq('', register.toString()); + is(!register.linewise); + helpers.assertCursorAt(0, 3); +}, { value: ' word1 ' }); +testVim('dk', function(cm, vim, helpers) { + var curStart = makeCursor(1, 3); + cm.setCursor(curStart); + helpers.doKeys('d', 'k'); + eq(' word3', cm.getValue()); + var register = helpers.getRegisterController().getRegister(); + eq(' word1\nword2\n', register.toString()); + is(register.linewise); + helpers.assertCursorAt(0, 1); +}, { value: ' word1\nword2\n word3' }); +testVim('dk_start_of_document', function(cm, vim, helpers) { + var curStart = makeCursor(0, 3); + cm.setCursor(curStart); + helpers.doKeys('d', 'k'); + eq(' word1 ', cm.getValue()); + var register = helpers.getRegisterController().getRegister(); + eq('', register.toString()); + is(!register.linewise); + helpers.assertCursorAt(0, 3); +}, { value: ' word1 ' }); +testVim('dw_space', function(cm, vim, helpers) { + var curStart = makeCursor(0, 0); + cm.setCursor(curStart); + helpers.doKeys('d', 'w'); + eq('word1 ', cm.getValue()); + var register = helpers.getRegisterController().getRegister(); + eq(' ', register.toString()); + is(!register.linewise); + eqPos(curStart, cm.getCursor()); +}, { value: ' word1 ' }); +testVim('dw_word', function(cm, vim, helpers) { + var curStart = makeCursor(0, 1); + cm.setCursor(curStart); + helpers.doKeys('d', 'w'); + eq(' word2', cm.getValue()); + var register = helpers.getRegisterController().getRegister(); + eq('word1 ', register.toString()); + is(!register.linewise); + eqPos(curStart, cm.getCursor()); +}, { value: ' word1 word2' }); +testVim('dw_only_word', function(cm, vim, helpers) { + // Test that if there is only 1 word left, dw deletes till the end of the + // line. + cm.setCursor(0, 1); + helpers.doKeys('d', 'w'); + eq(' ', cm.getValue()); + var register = helpers.getRegisterController().getRegister(); + eq('word1 ', register.toString()); + is(!register.linewise); + helpers.assertCursorAt(0, 1); +}, { value: ' word1 ' }); +testVim('dw_eol', function(cm, vim, helpers) { + // Assert that dw does not delete the newline if last word to delete is at end + // of line. + cm.setCursor(0, 1); + helpers.doKeys('d', 'w'); + eq(' \nword2', cm.getValue()); + var register = helpers.getRegisterController().getRegister(); + eq('word1', register.toString()); + is(!register.linewise); + helpers.assertCursorAt(0, 1); +}, { value: ' word1\nword2' }); +testVim('dw_eol_with_multiple_newlines', function(cm, vim, helpers) { + // Assert that dw does not delete the newline if last word to delete is at end + // of line and it is followed by multiple newlines. + cm.setCursor(0, 1); + helpers.doKeys('d', 'w'); + eq(' \n\nword2', cm.getValue()); + var register = helpers.getRegisterController().getRegister(); + eq('word1', register.toString()); + is(!register.linewise); + helpers.assertCursorAt(0, 1); +}, { value: ' word1\n\nword2' }); +testVim('dw_empty_line_followed_by_whitespace', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('d', 'w'); + eq(' \nword', cm.getValue()); +}, { value: '\n \nword' }); +testVim('dw_empty_line_followed_by_word', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('d', 'w'); + eq('word', cm.getValue()); +}, { value: '\nword' }); +testVim('dw_empty_line_followed_by_empty_line', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('d', 'w'); + eq('\n', cm.getValue()); +}, { value: '\n\n' }); +testVim('dw_whitespace_followed_by_whitespace', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('d', 'w'); + eq('\n \n', cm.getValue()); +}, { value: ' \n \n' }); +testVim('dw_whitespace_followed_by_empty_line', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('d', 'w'); + eq('\n\n', cm.getValue()); +}, { value: ' \n\n' }); +testVim('dw_word_whitespace_word', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('d', 'w'); + eq('\n \nword2', cm.getValue()); +}, { value: 'word1\n \nword2'}) +testVim('dw_end_of_document', function(cm, vim, helpers) { + cm.setCursor(1, 2); + helpers.doKeys('d', 'w'); + eq('\nab', cm.getValue()); +}, { value: '\nabc' }); +testVim('dw_repeat', function(cm, vim, helpers) { + // Assert that dw does delete newline if it should go to the next line, and + // that repeat works properly. + cm.setCursor(0, 1); + helpers.doKeys('d', '2', 'w'); + eq(' ', cm.getValue()); + var register = helpers.getRegisterController().getRegister(); + eq('word1\nword2', register.toString()); + is(!register.linewise); + helpers.assertCursorAt(0, 1); +}, { value: ' word1\nword2' }); +testVim('de_word_start_and_empty_lines', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('d', 'e'); + eq('\n\n', cm.getValue()); +}, { value: 'word\n\n' }); +testVim('de_word_end_and_empty_lines', function(cm, vim, helpers) { + cm.setCursor(0, 3); + helpers.doKeys('d', 'e'); + eq('wor', cm.getValue()); +}, { value: 'word\n\n\n' }); +testVim('de_whitespace_and_empty_lines', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('d', 'e'); + eq('', cm.getValue()); +}, { value: ' \n\n\n' }); +testVim('de_end_of_document', function(cm, vim, helpers) { + cm.setCursor(1, 2); + helpers.doKeys('d', 'e'); + eq('\nab', cm.getValue()); +}, { value: '\nabc' }); +testVim('db_empty_lines', function(cm, vim, helpers) { + cm.setCursor(2, 0); + helpers.doKeys('d', 'b'); + eq('\n\n', cm.getValue()); +}, { value: '\n\n\n' }); +testVim('db_word_start_and_empty_lines', function(cm, vim, helpers) { + cm.setCursor(2, 0); + helpers.doKeys('d', 'b'); + eq('\nword', cm.getValue()); +}, { value: '\n\nword' }); +testVim('db_word_end_and_empty_lines', function(cm, vim, helpers) { + cm.setCursor(2, 3); + helpers.doKeys('d', 'b'); + eq('\n\nd', cm.getValue()); +}, { value: '\n\nword' }); +testVim('db_whitespace_and_empty_lines', function(cm, vim, helpers) { + cm.setCursor(2, 0); + helpers.doKeys('d', 'b'); + eq('', cm.getValue()); +}, { value: '\n \n' }); +testVim('db_start_of_document', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('d', 'b'); + eq('abc\n', cm.getValue()); +}, { value: 'abc\n' }); +testVim('dge_empty_lines', function(cm, vim, helpers) { + cm.setCursor(1, 0); + helpers.doKeys('d', 'g', 'e'); + // Note: In real VIM the result should be '', but it's not quite consistent, + // since 2 newlines are deleted. But in the similar case of word\n\n, only + // 1 newline is deleted. We'll diverge from VIM's behavior since it's much + // easier this way. + eq('\n', cm.getValue()); +}, { value: '\n\n' }); +testVim('dge_word_and_empty_lines', function(cm, vim, helpers) { + cm.setCursor(1, 0); + helpers.doKeys('d', 'g', 'e'); + eq('wor\n', cm.getValue()); +}, { value: 'word\n\n'}); +testVim('dge_whitespace_and_empty_lines', function(cm, vim, helpers) { + cm.setCursor(2, 0); + helpers.doKeys('d', 'g', 'e'); + eq('', cm.getValue()); +}, { value: '\n \n' }); +testVim('dge_start_of_document', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('d', 'g', 'e'); + eq('bc\n', cm.getValue()); +}, { value: 'abc\n' }); +testVim('d_inclusive', function(cm, vim, helpers) { + // Assert that when inclusive is set, the character the cursor is on gets + // deleted too. + var curStart = makeCursor(0, 1); + cm.setCursor(curStart); + helpers.doKeys('d', 'e'); + eq(' ', cm.getValue()); + var register = helpers.getRegisterController().getRegister(); + eq('word1', register.toString()); + is(!register.linewise); + eqPos(curStart, cm.getCursor()); +}, { value: ' word1 ' }); +testVim('d_reverse', function(cm, vim, helpers) { + // Test that deleting in reverse works. + cm.setCursor(1, 0); + helpers.doKeys('d', 'b'); + eq(' word2 ', cm.getValue()); + var register = helpers.getRegisterController().getRegister(); + eq('word1\n', register.toString()); + is(!register.linewise); + helpers.assertCursorAt(0, 1); +}, { value: ' word1\nword2 ' }); +testVim('dd', function(cm, vim, helpers) { + cm.setCursor(0, 3); + var expectedBuffer = cm.getRange({ line: 0, ch: 0 }, + { line: 1, ch: 0 }); + var expectedLineCount = cm.lineCount() - 1; + helpers.doKeys('d', 'd'); + eq(expectedLineCount, cm.lineCount()); + var register = helpers.getRegisterController().getRegister(); + eq(expectedBuffer, register.toString()); + is(register.linewise); + helpers.assertCursorAt(0, lines[1].textStart); +}); +testVim('dd_prefix_repeat', function(cm, vim, helpers) { + cm.setCursor(0, 3); + var expectedBuffer = cm.getRange({ line: 0, ch: 0 }, + { line: 2, ch: 0 }); + var expectedLineCount = cm.lineCount() - 2; + helpers.doKeys('2', 'd', 'd'); + eq(expectedLineCount, cm.lineCount()); + var register = helpers.getRegisterController().getRegister(); + eq(expectedBuffer, register.toString()); + is(register.linewise); + helpers.assertCursorAt(0, lines[2].textStart); +}); +testVim('dd_motion_repeat', function(cm, vim, helpers) { + cm.setCursor(0, 3); + var expectedBuffer = cm.getRange({ line: 0, ch: 0 }, + { line: 2, ch: 0 }); + var expectedLineCount = cm.lineCount() - 2; + helpers.doKeys('d', '2', 'd'); + eq(expectedLineCount, cm.lineCount()); + var register = helpers.getRegisterController().getRegister(); + eq(expectedBuffer, register.toString()); + is(register.linewise); + helpers.assertCursorAt(0, lines[2].textStart); +}); +testVim('dd_multiply_repeat', function(cm, vim, helpers) { + cm.setCursor(0, 3); + var expectedBuffer = cm.getRange({ line: 0, ch: 0 }, + { line: 6, ch: 0 }); + var expectedLineCount = cm.lineCount() - 6; + helpers.doKeys('2', 'd', '3', 'd'); + eq(expectedLineCount, cm.lineCount()); + var register = helpers.getRegisterController().getRegister(); + eq(expectedBuffer, register.toString()); + is(register.linewise); + helpers.assertCursorAt(0, lines[6].textStart); +}); +testVim('dd_lastline', function(cm, vim, helpers) { + cm.setCursor(cm.lineCount(), 0); + var expectedLineCount = cm.lineCount() - 1; + helpers.doKeys('d', 'd'); + eq(expectedLineCount, cm.lineCount()); + helpers.assertCursorAt(cm.lineCount() - 1, 0); +}); +testVim('dd_only_line', function(cm, vim, helpers) { + cm.setCursor(0, 0); + var expectedRegister = cm.getValue() + "\n"; + helpers.doKeys('d','d'); + eq(1, cm.lineCount()); + eq('', cm.getValue()); + var register = helpers.getRegisterController().getRegister(); + eq(expectedRegister, register.toString()); +}, { value: "thisistheonlyline" }); +// Yank commands should behave the exact same as d commands, expect that nothing +// gets deleted. +testVim('yw_repeat', function(cm, vim, helpers) { + // Assert that yw does yank newline if it should go to the next line, and + // that repeat works properly. + var curStart = makeCursor(0, 1); + cm.setCursor(curStart); + helpers.doKeys('y', '2', 'w'); + eq(' word1\nword2', cm.getValue()); + var register = helpers.getRegisterController().getRegister(); + eq('word1\nword2', register.toString()); + is(!register.linewise); + eqPos(curStart, cm.getCursor()); +}, { value: ' word1\nword2' }); +testVim('yy_multiply_repeat', function(cm, vim, helpers) { + var curStart = makeCursor(0, 3); + cm.setCursor(curStart); + var expectedBuffer = cm.getRange({ line: 0, ch: 0 }, + { line: 6, ch: 0 }); + var expectedLineCount = cm.lineCount(); + helpers.doKeys('2', 'y', '3', 'y'); + eq(expectedLineCount, cm.lineCount()); + var register = helpers.getRegisterController().getRegister(); + eq(expectedBuffer, register.toString()); + is(register.linewise); + eqPos(curStart, cm.getCursor()); +}); +// Change commands behave like d commands except that it also enters insert +// mode. In addition, when the change is linewise, an additional newline is +// inserted so that insert mode starts on that line. +testVim('cw', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('c', '2', 'w'); + eq(' word3', cm.getValue()); + helpers.assertCursorAt(0, 0); +}, { value: 'word1 word2 word3'}); +testVim('cw_repeat', function(cm, vim, helpers) { + // Assert that cw does delete newline if it should go to the next line, and + // that repeat works properly. + var curStart = makeCursor(0, 1); + cm.setCursor(curStart); + helpers.doKeys('c', '2', 'w'); + eq(' ', cm.getValue()); + var register = helpers.getRegisterController().getRegister(); + eq('word1\nword2', register.toString()); + is(!register.linewise); + eqPos(curStart, cm.getCursor()); + eq('vim-insert', cm.getOption('keyMap')); +}, { value: ' word1\nword2' }); +testVim('cc_multiply_repeat', function(cm, vim, helpers) { + cm.setCursor(0, 3); + var expectedBuffer = cm.getRange({ line: 0, ch: 0 }, + { line: 6, ch: 0 }); + var expectedLineCount = cm.lineCount() - 5; + helpers.doKeys('2', 'c', '3', 'c'); + eq(expectedLineCount, cm.lineCount()); + var register = helpers.getRegisterController().getRegister(); + eq(expectedBuffer, register.toString()); + is(register.linewise); + eq('vim-insert', cm.getOption('keyMap')); +}); +testVim('cc_should_not_append_to_document', function(cm, vim, helpers) { + var expectedLineCount = cm.lineCount(); + cm.setCursor(cm.lastLine(), 0); + helpers.doKeys('c', 'c'); + eq(expectedLineCount, cm.lineCount()); +}); +function fillArray(val, times) { + var arr = []; + for (var i = 0; i < times; i++) { + arr.push(val); + } + return arr; +} +testVim('c_visual_block', function(cm, vim, helpers) { + cm.setCursor(0, 1); + helpers.doKeys('', '2', 'j', 'l', 'l', 'l', 'c'); + var replacement = fillArray('hello', 3); + cm.replaceSelections(replacement); + eq('1hello\n5hello\nahellofg', cm.getValue()); + helpers.doKeys(''); + cm.setCursor(2, 3); + helpers.doKeys('', '2', 'k', 'h', 'C'); + replacement = fillArray('world', 3); + cm.replaceSelections(replacement); + eq('1hworld\n5hworld\nahworld', cm.getValue()); +}, {value: '1234\n5678\nabcdefg'}); +testVim('c_visual_block_replay', function(cm, vim, helpers) { + cm.setCursor(0, 1); + helpers.doKeys('', '2', 'j', 'l', 'c'); + var replacement = fillArray('fo', 3); + cm.replaceSelections(replacement); + eq('1fo4\n5fo8\nafodefg', cm.getValue()); + helpers.doKeys(''); + cm.setCursor(0, 0); + helpers.doKeys('.'); + eq('foo4\nfoo8\nfoodefg', cm.getValue()); +}, {value: '1234\n5678\nabcdefg'}); + +testVim('d_visual_block', function(cm, vim, helpers) { + cm.setCursor(0, 1); + helpers.doKeys('', '2', 'j', 'l', 'l', 'l', 'd'); + eq('1\n5\nafg', cm.getValue()); +}, {value: '1234\n5678\nabcdefg'}); +testVim('D_visual_block', function(cm, vim, helpers) { + cm.setCursor(0, 1); + helpers.doKeys('', '2', 'j', 'l', 'D'); + eq('1\n5\na', cm.getValue()); +}, {value: '1234\n5678\nabcdefg'}); + +// Swapcase commands edit in place and do not modify registers. +testVim('g~w_repeat', function(cm, vim, helpers) { + // Assert that dw does delete newline if it should go to the next line, and + // that repeat works properly. + var curStart = makeCursor(0, 1); + cm.setCursor(curStart); + helpers.doKeys('g', '~', '2', 'w'); + eq(' WORD1\nWORD2', cm.getValue()); + var register = helpers.getRegisterController().getRegister(); + eq('', register.toString()); + is(!register.linewise); + eqPos(curStart, cm.getCursor()); +}, { value: ' word1\nword2' }); +testVim('g~g~', function(cm, vim, helpers) { + var curStart = makeCursor(0, 3); + cm.setCursor(curStart); + var expectedLineCount = cm.lineCount(); + var expectedValue = cm.getValue().toUpperCase(); + helpers.doKeys('2', 'g', '~', '3', 'g', '~'); + eq(expectedValue, cm.getValue()); + var register = helpers.getRegisterController().getRegister(); + eq('', register.toString()); + is(!register.linewise); + eqPos(curStart, cm.getCursor()); +}, { value: ' word1\nword2\nword3\nword4\nword5\nword6' }); +testVim('gu_and_gU', function(cm, vim, helpers) { + var curStart = makeCursor(0, 7); + var value = cm.getValue(); + cm.setCursor(curStart); + helpers.doKeys('2', 'g', 'U', 'w'); + eq(cm.getValue(), 'wa wb xX WC wd'); + eqPos(curStart, cm.getCursor()); + helpers.doKeys('2', 'g', 'u', 'w'); + eq(cm.getValue(), value); + + helpers.doKeys('2', 'g', 'U', 'B'); + eq(cm.getValue(), 'wa WB Xx wc wd'); + eqPos(makeCursor(0, 3), cm.getCursor()); + + cm.setCursor(makeCursor(0, 4)); + helpers.doKeys('g', 'u', 'i', 'w'); + eq(cm.getValue(), 'wa wb Xx wc wd'); + eqPos(makeCursor(0, 3), cm.getCursor()); + + // TODO: support gUgU guu + // eqPos(makeCursor(0, 0), cm.getCursor()); + + var register = helpers.getRegisterController().getRegister(); + eq('', register.toString()); + is(!register.linewise); +}, { value: 'wa wb xx wc wd' }); +testVim('visual_block_~', function(cm, vim, helpers) { + cm.setCursor(1, 1); + helpers.doKeys('', 'l', 'l', 'j', '~'); + helpers.assertCursorAt(1, 1); + eq('hello\nwoRLd\naBCDe', cm.getValue()); + cm.setCursor(2, 0); + helpers.doKeys('v', 'l', 'l', '~'); + helpers.assertCursorAt(2, 0); + eq('hello\nwoRLd\nAbcDe', cm.getValue()); +},{value: 'hello\nwOrld\nabcde' }); +testVim('._swapCase_visualBlock', function(cm, vim, helpers) { + helpers.doKeys('', 'j', 'j', 'l', '~'); + cm.setCursor(0, 3); + helpers.doKeys('.'); + eq('HelLO\nWorLd\nAbcdE', cm.getValue()); +},{value: 'hEllo\nwOrlD\naBcDe' }); +testVim('._delete_visualBlock', function(cm, vim, helpers) { + helpers.doKeys('', 'j', 'x'); + eq('ive\ne\nsome\nsugar', cm.getValue()); + helpers.doKeys('.'); + eq('ve\n\nsome\nsugar', cm.getValue()); + helpers.doKeys('j', 'j', '.'); + eq('ve\n\nome\nugar', cm.getValue()); + helpers.doKeys('u', '', '.'); + eq('ve\n\nme\ngar', cm.getValue()); +},{value: 'give\nme\nsome\nsugar' }); +testVim('>{motion}', function(cm, vim, helpers) { + cm.setCursor(1, 3); + var expectedLineCount = cm.lineCount(); + var expectedValue = ' word1\n word2\nword3 '; + helpers.doKeys('>', 'k'); + eq(expectedValue, cm.getValue()); + var register = helpers.getRegisterController().getRegister(); + eq('', register.toString()); + is(!register.linewise); + helpers.assertCursorAt(0, 3); +}, { value: ' word1\nword2\nword3 ', indentUnit: 2 }); +testVim('>>', function(cm, vim, helpers) { + cm.setCursor(0, 3); + var expectedLineCount = cm.lineCount(); + var expectedValue = ' word1\n word2\nword3 '; + helpers.doKeys('2', '>', '>'); + eq(expectedValue, cm.getValue()); + var register = helpers.getRegisterController().getRegister(); + eq('', register.toString()); + is(!register.linewise); + helpers.assertCursorAt(0, 3); +}, { value: ' word1\nword2\nword3 ', indentUnit: 2 }); +testVim('<{motion}', function(cm, vim, helpers) { + cm.setCursor(1, 3); + var expectedLineCount = cm.lineCount(); + var expectedValue = ' word1\nword2\nword3 '; + helpers.doKeys('<', 'k'); + eq(expectedValue, cm.getValue()); + var register = helpers.getRegisterController().getRegister(); + eq('', register.toString()); + is(!register.linewise); + helpers.assertCursorAt(0, 1); +}, { value: ' word1\n word2\nword3 ', indentUnit: 2 }); +testVim('<<', function(cm, vim, helpers) { + cm.setCursor(0, 3); + var expectedLineCount = cm.lineCount(); + var expectedValue = ' word1\nword2\nword3 '; + helpers.doKeys('2', '<', '<'); + eq(expectedValue, cm.getValue()); + var register = helpers.getRegisterController().getRegister(); + eq('', register.toString()); + is(!register.linewise); + helpers.assertCursorAt(0, 1); +}, { value: ' word1\n word2\nword3 ', indentUnit: 2 }); + +// Edit tests +function testEdit(name, before, pos, edit, after) { + return testVim(name, function(cm, vim, helpers) { + var ch = before.search(pos) + var line = before.substring(0, ch).split('\n').length - 1; + if (line) { + ch = before.substring(0, ch).split('\n').pop().length; + } + cm.setCursor(line, ch); + helpers.doKeys.apply(this, edit.split('')); + eq(after, cm.getValue()); + }, {value: before}); +} + +// These Delete tests effectively cover word-wise Change, Visual & Yank. +// Tabs are used as differentiated whitespace to catch edge cases. +// Normal word: +testEdit('diw_mid_spc', 'foo \tbAr\t baz', /A/, 'diw', 'foo \t\t baz'); +testEdit('daw_mid_spc', 'foo \tbAr\t baz', /A/, 'daw', 'foo \tbaz'); +testEdit('diw_mid_punct', 'foo \tbAr.\t baz', /A/, 'diw', 'foo \t.\t baz'); +testEdit('daw_mid_punct', 'foo \tbAr.\t baz', /A/, 'daw', 'foo.\t baz'); +testEdit('diw_mid_punct2', 'foo \t,bAr.\t baz', /A/, 'diw', 'foo \t,.\t baz'); +testEdit('daw_mid_punct2', 'foo \t,bAr.\t baz', /A/, 'daw', 'foo \t,.\t baz'); +testEdit('diw_start_spc', 'bAr \tbaz', /A/, 'diw', ' \tbaz'); +testEdit('daw_start_spc', 'bAr \tbaz', /A/, 'daw', 'baz'); +testEdit('diw_start_punct', 'bAr. \tbaz', /A/, 'diw', '. \tbaz'); +testEdit('daw_start_punct', 'bAr. \tbaz', /A/, 'daw', '. \tbaz'); +testEdit('diw_end_spc', 'foo \tbAr', /A/, 'diw', 'foo \t'); +testEdit('daw_end_spc', 'foo \tbAr', /A/, 'daw', 'foo'); +testEdit('diw_end_punct', 'foo \tbAr.', /A/, 'diw', 'foo \t.'); +testEdit('daw_end_punct', 'foo \tbAr.', /A/, 'daw', 'foo.'); +// Big word: +testEdit('diW_mid_spc', 'foo \tbAr\t baz', /A/, 'diW', 'foo \t\t baz'); +testEdit('daW_mid_spc', 'foo \tbAr\t baz', /A/, 'daW', 'foo \tbaz'); +testEdit('diW_mid_punct', 'foo \tbAr.\t baz', /A/, 'diW', 'foo \t\t baz'); +testEdit('daW_mid_punct', 'foo \tbAr.\t baz', /A/, 'daW', 'foo \tbaz'); +testEdit('diW_mid_punct2', 'foo \t,bAr.\t baz', /A/, 'diW', 'foo \t\t baz'); +testEdit('daW_mid_punct2', 'foo \t,bAr.\t baz', /A/, 'daW', 'foo \tbaz'); +testEdit('diW_start_spc', 'bAr\t baz', /A/, 'diW', '\t baz'); +testEdit('daW_start_spc', 'bAr\t baz', /A/, 'daW', 'baz'); +testEdit('diW_start_punct', 'bAr.\t baz', /A/, 'diW', '\t baz'); +testEdit('daW_start_punct', 'bAr.\t baz', /A/, 'daW', 'baz'); +testEdit('diW_end_spc', 'foo \tbAr', /A/, 'diW', 'foo \t'); +testEdit('daW_end_spc', 'foo \tbAr', /A/, 'daW', 'foo'); +testEdit('diW_end_punct', 'foo \tbAr.', /A/, 'diW', 'foo \t'); +testEdit('daW_end_punct', 'foo \tbAr.', /A/, 'daW', 'foo'); +// Deleting text objects +// Open and close on same line +testEdit('di(_open_spc', 'foo (bAr) baz', /\(/, 'di(', 'foo () baz'); +testEdit('di)_open_spc', 'foo (bAr) baz', /\(/, 'di)', 'foo () baz'); +testEdit('dib_open_spc', 'foo (bAr) baz', /\(/, 'dib', 'foo () baz'); +testEdit('da(_open_spc', 'foo (bAr) baz', /\(/, 'da(', 'foo baz'); +testEdit('da)_open_spc', 'foo (bAr) baz', /\(/, 'da)', 'foo baz'); + +testEdit('di(_middle_spc', 'foo (bAr) baz', /A/, 'di(', 'foo () baz'); +testEdit('di)_middle_spc', 'foo (bAr) baz', /A/, 'di)', 'foo () baz'); +testEdit('da(_middle_spc', 'foo (bAr) baz', /A/, 'da(', 'foo baz'); +testEdit('da)_middle_spc', 'foo (bAr) baz', /A/, 'da)', 'foo baz'); + +testEdit('di(_close_spc', 'foo (bAr) baz', /\)/, 'di(', 'foo () baz'); +testEdit('di)_close_spc', 'foo (bAr) baz', /\)/, 'di)', 'foo () baz'); +testEdit('da(_close_spc', 'foo (bAr) baz', /\)/, 'da(', 'foo baz'); +testEdit('da)_close_spc', 'foo (bAr) baz', /\)/, 'da)', 'foo baz'); + +// delete around and inner b. +testEdit('dab_on_(_should_delete_around_()block', 'o( in(abc) )', /\(a/, 'dab', 'o( in )'); + +// delete around and inner B. +testEdit('daB_on_{_should_delete_around_{}block', 'o{ in{abc} }', /{a/, 'daB', 'o{ in }'); +testEdit('diB_on_{_should_delete_inner_{}block', 'o{ in{abc} }', /{a/, 'diB', 'o{ in{} }'); + +testEdit('da{_on_{_should_delete_inner_block', 'o{ in{abc} }', /{a/, 'da{', 'o{ in }'); +testEdit('di[_on_(_should_not_delete', 'foo (bAr) baz', /\(/, 'di[', 'foo (bAr) baz'); +testEdit('di[_on_)_should_not_delete', 'foo (bAr) baz', /\)/, 'di[', 'foo (bAr) baz'); +testEdit('da[_on_(_should_not_delete', 'foo (bAr) baz', /\(/, 'da[', 'foo (bAr) baz'); +testEdit('da[_on_)_should_not_delete', 'foo (bAr) baz', /\)/, 'da[', 'foo (bAr) baz'); +testMotion('di(_outside_should_stay', ['d', 'i', '('], { line: 0, ch: 0}, { line: 0, ch: 0}); + +// Open and close on different lines, equally indented +testEdit('di{_middle_spc', 'a{\n\tbar\n}b', /r/, 'di{', 'a{}b'); +testEdit('di}_middle_spc', 'a{\n\tbar\n}b', /r/, 'di}', 'a{}b'); +testEdit('da{_middle_spc', 'a{\n\tbar\n}b', /r/, 'da{', 'ab'); +testEdit('da}_middle_spc', 'a{\n\tbar\n}b', /r/, 'da}', 'ab'); +testEdit('daB_middle_spc', 'a{\n\tbar\n}b', /r/, 'daB', 'ab'); + +// open and close on diff lines, open indented less than close +testEdit('di{_middle_spc', 'a{\n\tbar\n\t}b', /r/, 'di{', 'a{}b'); +testEdit('di}_middle_spc', 'a{\n\tbar\n\t}b', /r/, 'di}', 'a{}b'); +testEdit('da{_middle_spc', 'a{\n\tbar\n\t}b', /r/, 'da{', 'ab'); +testEdit('da}_middle_spc', 'a{\n\tbar\n\t}b', /r/, 'da}', 'ab'); + +// open and close on diff lines, open indented more than close +testEdit('di[_middle_spc', 'a\t[\n\tbar\n]b', /r/, 'di[', 'a\t[]b'); +testEdit('di]_middle_spc', 'a\t[\n\tbar\n]b', /r/, 'di]', 'a\t[]b'); +testEdit('da[_middle_spc', 'a\t[\n\tbar\n]b', /r/, 'da[', 'a\tb'); +testEdit('da]_middle_spc', 'a\t[\n\tbar\n]b', /r/, 'da]', 'a\tb'); + +function testSelection(name, before, pos, keys, sel) { + return testVim(name, function(cm, vim, helpers) { + var ch = before.search(pos) + var line = before.substring(0, ch).split('\n').length - 1; + if (line) { + ch = before.substring(0, ch).split('\n').pop().length; + } + cm.setCursor(line, ch); + helpers.doKeys.apply(this, keys.split('')); + eq(sel, cm.getSelection()); + }, {value: before}); +} +testSelection('viw_middle_spc', 'foo \tbAr\t baz', /A/, 'viw', 'bAr'); +testSelection('vaw_middle_spc', 'foo \tbAr\t baz', /A/, 'vaw', 'bAr\t '); +testSelection('viw_middle_punct', 'foo \tbAr,\t baz', /A/, 'viw', 'bAr'); +testSelection('vaW_middle_punct', 'foo \tbAr,\t baz', /A/, 'vaW', 'bAr,\t '); +testSelection('viw_start_spc', 'foo \tbAr\t baz', /b/, 'viw', 'bAr'); +testSelection('viw_end_spc', 'foo \tbAr\t baz', /r/, 'viw', 'bAr'); +testSelection('viw_eol', 'foo \tbAr', /r/, 'viw', 'bAr'); +testSelection('vi{_middle_spc', 'a{\n\tbar\n\t}b', /r/, 'vi{', '\n\tbar\n\t'); +testSelection('va{_middle_spc', 'a{\n\tbar\n\t}b', /r/, 'va{', '{\n\tbar\n\t}'); + +testVim('mouse_select', function(cm, vim, helpers) { + cm.setSelection(Pos(0, 2), Pos(0, 4), {origin: '*mouse'}); + is(cm.state.vim.visualMode); + is(!cm.state.vim.visualLine); + is(!cm.state.vim.visualBlock); + helpers.doKeys(''); + is(!cm.somethingSelected()); + helpers.doKeys('g', 'v'); + eq('cd', cm.getSelection()); +}, {value: 'abcdef'}); + +// Operator-motion tests +testVim('D', function(cm, vim, helpers) { + cm.setCursor(0, 3); + helpers.doKeys('D'); + eq(' wo\nword2\n word3', cm.getValue()); + var register = helpers.getRegisterController().getRegister(); + eq('rd1', register.toString()); + is(!register.linewise); + helpers.assertCursorAt(0, 3); +}, { value: ' word1\nword2\n word3' }); +testVim('C', function(cm, vim, helpers) { + var curStart = makeCursor(0, 3); + cm.setCursor(curStart); + helpers.doKeys('C'); + eq(' wo\nword2\n word3', cm.getValue()); + var register = helpers.getRegisterController().getRegister(); + eq('rd1', register.toString()); + is(!register.linewise); + eqPos(curStart, cm.getCursor()); + eq('vim-insert', cm.getOption('keyMap')); +}, { value: ' word1\nword2\n word3' }); +testVim('Y', function(cm, vim, helpers) { + var curStart = makeCursor(0, 3); + cm.setCursor(curStart); + helpers.doKeys('Y'); + eq(' word1\nword2\n word3', cm.getValue()); + var register = helpers.getRegisterController().getRegister(); + eq('rd1', register.toString()); + is(!register.linewise); + helpers.assertCursorAt(0, 3); +}, { value: ' word1\nword2\n word3' }); +testVim('~', function(cm, vim, helpers) { + helpers.doKeys('3', '~'); + eq('ABCdefg', cm.getValue()); + helpers.assertCursorAt(0, 3); +}, { value: 'abcdefg' }); + +// Action tests +testVim('ctrl-a', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys(''); + eq('-9', cm.getValue()); + helpers.assertCursorAt(0, 1); + helpers.doKeys('2',''); + eq('-7', cm.getValue()); +}, {value: '-10'}); +testVim('ctrl-x', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys(''); + eq('-1', cm.getValue()); + helpers.assertCursorAt(0, 1); + helpers.doKeys('2',''); + eq('-3', cm.getValue()); +}, {value: '0'}); +testVim('/ search forward', function(cm, vim, helpers) { + forEach(['', ''], function(key) { + cm.setCursor(0, 0); + helpers.doKeys(key); + helpers.assertCursorAt(0, 5); + helpers.doKeys('l'); + helpers.doKeys(key); + helpers.assertCursorAt(0, 10); + cm.setCursor(0, 11); + helpers.doKeys(key); + helpers.assertCursorAt(0, 11); + }); +}, {value: '__jmp1 jmp2 jmp'}); +testVim('a', function(cm, vim, helpers) { + cm.setCursor(0, 1); + helpers.doKeys('a'); + helpers.assertCursorAt(0, 2); + eq('vim-insert', cm.getOption('keyMap')); +}); +testVim('a_eol', function(cm, vim, helpers) { + cm.setCursor(0, lines[0].length - 1); + helpers.doKeys('a'); + helpers.assertCursorAt(0, lines[0].length); + eq('vim-insert', cm.getOption('keyMap')); +}); +testVim('A_endOfSelectedArea', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('v', 'j', 'l'); + helpers.doKeys('A'); + helpers.assertCursorAt(1, 2); + eq('vim-insert', cm.getOption('keyMap')); +}, {value: 'foo\nbar'}); +testVim('i', function(cm, vim, helpers) { + cm.setCursor(0, 1); + helpers.doKeys('i'); + helpers.assertCursorAt(0, 1); + eq('vim-insert', cm.getOption('keyMap')); +}); +testVim('i_repeat', function(cm, vim, helpers) { + helpers.doKeys('3', 'i'); + cm.replaceRange('test', cm.getCursor()); + helpers.doKeys(''); + eq('testtesttest', cm.getValue()); + helpers.assertCursorAt(0, 11); +}, { value: '' }); +testVim('i_repeat_delete', function(cm, vim, helpers) { + cm.setCursor(0, 4); + helpers.doKeys('2', 'i'); + cm.replaceRange('z', cm.getCursor()); + helpers.doInsertModeKeys('Backspace', 'Backspace'); + helpers.doKeys(''); + eq('abe', cm.getValue()); + helpers.assertCursorAt(0, 1); +}, { value: 'abcde' }); +testVim('A', function(cm, vim, helpers) { + helpers.doKeys('A'); + helpers.assertCursorAt(0, lines[0].length); + eq('vim-insert', cm.getOption('keyMap')); +}); +testVim('A_visual_block', function(cm, vim, helpers) { + cm.setCursor(0, 1); + helpers.doKeys('', '2', 'j', 'l', 'l', 'A'); + var replacement = new Array(cm.listSelections().length+1).join('hello ').split(' '); + replacement.pop(); + cm.replaceSelections(replacement); + eq('testhello\nmehello\npleahellose', cm.getValue()); + helpers.doKeys(''); + cm.setCursor(0, 0); + helpers.doKeys('.'); + // TODO this doesn't work yet + // eq('teshellothello\nme hello hello\nplehelloahellose', cm.getValue()); +}, {value: 'test\nme\nplease'}); +testVim('I', function(cm, vim, helpers) { + cm.setCursor(0, 4); + helpers.doKeys('I'); + helpers.assertCursorAt(0, lines[0].textStart); + eq('vim-insert', cm.getOption('keyMap')); +}); +testVim('I_repeat', function(cm, vim, helpers) { + cm.setCursor(0, 1); + helpers.doKeys('3', 'I'); + cm.replaceRange('test', cm.getCursor()); + helpers.doKeys(''); + eq('testtesttestblah', cm.getValue()); + helpers.assertCursorAt(0, 11); +}, { value: 'blah' }); +testVim('I_visual_block', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('', '2', 'j', 'l', 'l', 'I'); + var replacement = new Array(cm.listSelections().length+1).join('hello ').split(' '); + replacement.pop(); + cm.replaceSelections(replacement); + eq('hellotest\nhellome\nhelloplease', cm.getValue()); +}, {value: 'test\nme\nplease'}); +testVim('o', function(cm, vim, helpers) { + cm.setCursor(0, 4); + helpers.doKeys('o'); + eq('word1\n\nword2', cm.getValue()); + helpers.assertCursorAt(1, 0); + eq('vim-insert', cm.getOption('keyMap')); +}, { value: 'word1\nword2' }); +testVim('o_repeat', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('3', 'o'); + cm.replaceRange('test', cm.getCursor()); + helpers.doKeys(''); + eq('\ntest\ntest\ntest', cm.getValue()); + helpers.assertCursorAt(3, 3); +}, { value: '' }); +testVim('O', function(cm, vim, helpers) { + cm.setCursor(0, 4); + helpers.doKeys('O'); + eq('\nword1\nword2', cm.getValue()); + helpers.assertCursorAt(0, 0); + eq('vim-insert', cm.getOption('keyMap')); +}, { value: 'word1\nword2' }); +testVim('J', function(cm, vim, helpers) { + cm.setCursor(0, 4); + helpers.doKeys('J'); + var expectedValue = 'word1 word2\nword3\n word4'; + eq(expectedValue, cm.getValue()); + helpers.assertCursorAt(0, expectedValue.indexOf('word2') - 1); +}, { value: 'word1 \n word2\nword3\n word4' }); +testVim('J_repeat', function(cm, vim, helpers) { + cm.setCursor(0, 4); + helpers.doKeys('3', 'J'); + var expectedValue = 'word1 word2 word3\n word4'; + eq(expectedValue, cm.getValue()); + helpers.assertCursorAt(0, expectedValue.indexOf('word3') - 1); +}, { value: 'word1 \n word2\nword3\n word4' }); +testVim('p', function(cm, vim, helpers) { + cm.setCursor(0, 1); + helpers.getRegisterController().pushText('"', 'yank', 'abc\ndef', false); + helpers.doKeys('p'); + eq('__abc\ndef_', cm.getValue()); + helpers.assertCursorAt(1, 2); +}, { value: '___' }); +testVim('p_register', function(cm, vim, helpers) { + cm.setCursor(0, 1); + helpers.getRegisterController().getRegister('a').setText('abc\ndef', false); + helpers.doKeys('"', 'a', 'p'); + eq('__abc\ndef_', cm.getValue()); + helpers.assertCursorAt(1, 2); +}, { value: '___' }); +testVim('p_wrong_register', function(cm, vim, helpers) { + cm.setCursor(0, 1); + helpers.getRegisterController().getRegister('a').setText('abc\ndef', false); + helpers.doKeys('p'); + eq('___', cm.getValue()); + helpers.assertCursorAt(0, 1); +}, { value: '___' }); +testVim('p_line', function(cm, vim, helpers) { + cm.setCursor(0, 1); + helpers.getRegisterController().pushText('"', 'yank', ' a\nd\n', true); + helpers.doKeys('2', 'p'); + eq('___\n a\nd\n a\nd', cm.getValue()); + helpers.assertCursorAt(1, 2); +}, { value: '___' }); +testVim('p_lastline', function(cm, vim, helpers) { + cm.setCursor(0, 1); + helpers.getRegisterController().pushText('"', 'yank', ' a\nd', true); + helpers.doKeys('2', 'p'); + eq('___\n a\nd\n a\nd', cm.getValue()); + helpers.assertCursorAt(1, 2); +}, { value: '___' }); +testVim(']p_first_indent_is_smaller', function(cm, vim, helpers) { + helpers.getRegisterController().pushText('"', 'yank', ' abc\n def\n', true); + helpers.doKeys(']', 'p'); + eq(' ___\n abc\n def', cm.getValue()); +}, { value: ' ___' }); +testVim(']p_first_indent_is_larger', function(cm, vim, helpers) { + helpers.getRegisterController().pushText('"', 'yank', ' abc\n def\n', true); + helpers.doKeys(']', 'p'); + eq(' ___\n abc\ndef', cm.getValue()); +}, { value: ' ___' }); +testVim(']p_with_tab_indents', function(cm, vim, helpers) { + helpers.getRegisterController().pushText('"', 'yank', '\t\tabc\n\t\t\tdef\n', true); + helpers.doKeys(']', 'p'); + eq('\t___\n\tabc\n\t\tdef', cm.getValue()); +}, { value: '\t___', indentWithTabs: true}); +testVim(']p_with_spaces_translated_to_tabs', function(cm, vim, helpers) { + helpers.getRegisterController().pushText('"', 'yank', ' abc\n def\n', true); + helpers.doKeys(']', 'p'); + eq('\t___\n\tabc\n\t\tdef', cm.getValue()); +}, { value: '\t___', indentWithTabs: true, tabSize: 2 }); +testVim('[p', function(cm, vim, helpers) { + helpers.getRegisterController().pushText('"', 'yank', ' abc\n def\n', true); + helpers.doKeys('[', 'p'); + eq(' abc\n def\n ___', cm.getValue()); +}, { value: ' ___' }); +testVim('P', function(cm, vim, helpers) { + cm.setCursor(0, 1); + helpers.getRegisterController().pushText('"', 'yank', 'abc\ndef', false); + helpers.doKeys('P'); + eq('_abc\ndef__', cm.getValue()); + helpers.assertCursorAt(1, 3); +}, { value: '___' }); +testVim('P_line', function(cm, vim, helpers) { + cm.setCursor(0, 1); + helpers.getRegisterController().pushText('"', 'yank', ' a\nd\n', true); + helpers.doKeys('2', 'P'); + eq(' a\nd\n a\nd\n___', cm.getValue()); + helpers.assertCursorAt(0, 2); +}, { value: '___' }); +testVim('r', function(cm, vim, helpers) { + cm.setCursor(0, 1); + helpers.doKeys('3', 'r', 'u'); + eq('wuuuet\nanother', cm.getValue(),'3r failed'); + helpers.assertCursorAt(0, 3); + cm.setCursor(0, 4); + helpers.doKeys('v', 'j', 'h', 'r', ''); + eq('wuuu \n her', cm.getValue(),'Replacing selection by space-characters failed'); +}, { value: 'wordet\nanother' }); +testVim('r_visual_block', function(cm, vim, helpers) { + cm.setCursor(2, 3); + helpers.doKeys('', 'k', 'k', 'h', 'h', 'r', 'l'); + eq('1lll\n5lll\nalllefg', cm.getValue()); + helpers.doKeys('', 'l', 'j', 'r', ''); + eq('1 l\n5 l\nalllefg', cm.getValue()); + cm.setCursor(2, 0); + helpers.doKeys('o'); + helpers.doKeys(''); + cm.replaceRange('\t\t', cm.getCursor()); + helpers.doKeys('', 'h', 'h', 'r', 'r'); + eq('1 l\n5 l\nalllefg\nrrrrrrrr', cm.getValue()); +}, {value: '1234\n5678\nabcdefg'}); +testVim('R', function(cm, vim, helpers) { + cm.setCursor(0, 1); + helpers.doKeys('R'); + helpers.assertCursorAt(0, 1); + eq('vim-replace', cm.getOption('keyMap')); + is(cm.state.overwrite, 'Setting overwrite state failed'); +}); +testVim('mark', function(cm, vim, helpers) { + cm.setCursor(2, 2); + helpers.doKeys('m', 't'); + cm.setCursor(0, 0); + helpers.doKeys('`', 't'); + helpers.assertCursorAt(2, 2); + cm.setCursor(2, 0); + cm.replaceRange(' h', cm.getCursor()); + cm.setCursor(0, 0); + helpers.doKeys('\'', 't'); + helpers.assertCursorAt(2, 3); +}); +testVim('jumpToMark_next', function(cm, vim, helpers) { + cm.setCursor(2, 2); + helpers.doKeys('m', 't'); + cm.setCursor(0, 0); + helpers.doKeys(']', '`'); + helpers.assertCursorAt(2, 2); + cm.setCursor(0, 0); + helpers.doKeys(']', '\''); + helpers.assertCursorAt(2, 0); +}); +testVim('jumpToMark_next_repeat', function(cm, vim, helpers) { + cm.setCursor(2, 2); + helpers.doKeys('m', 'a'); + cm.setCursor(3, 2); + helpers.doKeys('m', 'b'); + cm.setCursor(4, 2); + helpers.doKeys('m', 'c'); + cm.setCursor(0, 0); + helpers.doKeys('2', ']', '`'); + helpers.assertCursorAt(3, 2); + cm.setCursor(0, 0); + helpers.doKeys('2', ']', '\''); + helpers.assertCursorAt(3, 1); +}); +testVim('jumpToMark_next_sameline', function(cm, vim, helpers) { + cm.setCursor(2, 0); + helpers.doKeys('m', 'a'); + cm.setCursor(2, 4); + helpers.doKeys('m', 'b'); + cm.setCursor(2, 2); + helpers.doKeys(']', '`'); + helpers.assertCursorAt(2, 4); +}); +testVim('jumpToMark_next_onlyprev', function(cm, vim, helpers) { + cm.setCursor(2, 0); + helpers.doKeys('m', 'a'); + cm.setCursor(4, 0); + helpers.doKeys(']', '`'); + helpers.assertCursorAt(4, 0); +}); +testVim('jumpToMark_next_nomark', function(cm, vim, helpers) { + cm.setCursor(2, 2); + helpers.doKeys(']', '`'); + helpers.assertCursorAt(2, 2); + helpers.doKeys(']', '\''); + helpers.assertCursorAt(2, 0); +}); +testVim('jumpToMark_next_linewise_over', function(cm, vim, helpers) { + cm.setCursor(2, 2); + helpers.doKeys('m', 'a'); + cm.setCursor(3, 4); + helpers.doKeys('m', 'b'); + cm.setCursor(2, 1); + helpers.doKeys(']', '\''); + helpers.assertCursorAt(3, 1); +}); +testVim('jumpToMark_next_action', function(cm, vim, helpers) { + cm.setCursor(2, 2); + helpers.doKeys('m', 't'); + cm.setCursor(0, 0); + helpers.doKeys('d', ']', '`'); + helpers.assertCursorAt(0, 0); + var actual = cm.getLine(0); + var expected = 'pop pop 0 1 2 3 4'; + eq(actual, expected, "Deleting while jumping to the next mark failed."); +}); +testVim('jumpToMark_next_line_action', function(cm, vim, helpers) { + cm.setCursor(2, 2); + helpers.doKeys('m', 't'); + cm.setCursor(0, 0); + helpers.doKeys('d', ']', '\''); + helpers.assertCursorAt(0, 1); + var actual = cm.getLine(0); + var expected = ' (a) [b] {c} ' + eq(actual, expected, "Deleting while jumping to the next mark line failed."); +}); +testVim('jumpToMark_prev', function(cm, vim, helpers) { + cm.setCursor(2, 2); + helpers.doKeys('m', 't'); + cm.setCursor(4, 0); + helpers.doKeys('[', '`'); + helpers.assertCursorAt(2, 2); + cm.setCursor(4, 0); + helpers.doKeys('[', '\''); + helpers.assertCursorAt(2, 0); +}); +testVim('jumpToMark_prev_repeat', function(cm, vim, helpers) { + cm.setCursor(2, 2); + helpers.doKeys('m', 'a'); + cm.setCursor(3, 2); + helpers.doKeys('m', 'b'); + cm.setCursor(4, 2); + helpers.doKeys('m', 'c'); + cm.setCursor(5, 0); + helpers.doKeys('2', '[', '`'); + helpers.assertCursorAt(3, 2); + cm.setCursor(5, 0); + helpers.doKeys('2', '[', '\''); + helpers.assertCursorAt(3, 1); +}); +testVim('jumpToMark_prev_sameline', function(cm, vim, helpers) { + cm.setCursor(2, 0); + helpers.doKeys('m', 'a'); + cm.setCursor(2, 4); + helpers.doKeys('m', 'b'); + cm.setCursor(2, 2); + helpers.doKeys('[', '`'); + helpers.assertCursorAt(2, 0); +}); +testVim('jumpToMark_prev_onlynext', function(cm, vim, helpers) { + cm.setCursor(4, 4); + helpers.doKeys('m', 'a'); + cm.setCursor(2, 0); + helpers.doKeys('[', '`'); + helpers.assertCursorAt(2, 0); +}); +testVim('jumpToMark_prev_nomark', function(cm, vim, helpers) { + cm.setCursor(2, 2); + helpers.doKeys('[', '`'); + helpers.assertCursorAt(2, 2); + helpers.doKeys('[', '\''); + helpers.assertCursorAt(2, 0); +}); +testVim('jumpToMark_prev_linewise_over', function(cm, vim, helpers) { + cm.setCursor(2, 2); + helpers.doKeys('m', 'a'); + cm.setCursor(3, 4); + helpers.doKeys('m', 'b'); + cm.setCursor(3, 6); + helpers.doKeys('[', '\''); + helpers.assertCursorAt(2, 0); +}); +testVim('delmark_single', function(cm, vim, helpers) { + cm.setCursor(1, 2); + helpers.doKeys('m', 't'); + helpers.doEx('delmarks t'); + cm.setCursor(0, 0); + helpers.doKeys('`', 't'); + helpers.assertCursorAt(0, 0); +}); +testVim('delmark_range', function(cm, vim, helpers) { + cm.setCursor(1, 2); + helpers.doKeys('m', 'a'); + cm.setCursor(2, 2); + helpers.doKeys('m', 'b'); + cm.setCursor(3, 2); + helpers.doKeys('m', 'c'); + cm.setCursor(4, 2); + helpers.doKeys('m', 'd'); + cm.setCursor(5, 2); + helpers.doKeys('m', 'e'); + helpers.doEx('delmarks b-d'); + cm.setCursor(0, 0); + helpers.doKeys('`', 'a'); + helpers.assertCursorAt(1, 2); + helpers.doKeys('`', 'b'); + helpers.assertCursorAt(1, 2); + helpers.doKeys('`', 'c'); + helpers.assertCursorAt(1, 2); + helpers.doKeys('`', 'd'); + helpers.assertCursorAt(1, 2); + helpers.doKeys('`', 'e'); + helpers.assertCursorAt(5, 2); +}); +testVim('delmark_multi', function(cm, vim, helpers) { + cm.setCursor(1, 2); + helpers.doKeys('m', 'a'); + cm.setCursor(2, 2); + helpers.doKeys('m', 'b'); + cm.setCursor(3, 2); + helpers.doKeys('m', 'c'); + cm.setCursor(4, 2); + helpers.doKeys('m', 'd'); + cm.setCursor(5, 2); + helpers.doKeys('m', 'e'); + helpers.doEx('delmarks bcd'); + cm.setCursor(0, 0); + helpers.doKeys('`', 'a'); + helpers.assertCursorAt(1, 2); + helpers.doKeys('`', 'b'); + helpers.assertCursorAt(1, 2); + helpers.doKeys('`', 'c'); + helpers.assertCursorAt(1, 2); + helpers.doKeys('`', 'd'); + helpers.assertCursorAt(1, 2); + helpers.doKeys('`', 'e'); + helpers.assertCursorAt(5, 2); +}); +testVim('delmark_multi_space', function(cm, vim, helpers) { + cm.setCursor(1, 2); + helpers.doKeys('m', 'a'); + cm.setCursor(2, 2); + helpers.doKeys('m', 'b'); + cm.setCursor(3, 2); + helpers.doKeys('m', 'c'); + cm.setCursor(4, 2); + helpers.doKeys('m', 'd'); + cm.setCursor(5, 2); + helpers.doKeys('m', 'e'); + helpers.doEx('delmarks b c d'); + cm.setCursor(0, 0); + helpers.doKeys('`', 'a'); + helpers.assertCursorAt(1, 2); + helpers.doKeys('`', 'b'); + helpers.assertCursorAt(1, 2); + helpers.doKeys('`', 'c'); + helpers.assertCursorAt(1, 2); + helpers.doKeys('`', 'd'); + helpers.assertCursorAt(1, 2); + helpers.doKeys('`', 'e'); + helpers.assertCursorAt(5, 2); +}); +testVim('delmark_all', function(cm, vim, helpers) { + cm.setCursor(1, 2); + helpers.doKeys('m', 'a'); + cm.setCursor(2, 2); + helpers.doKeys('m', 'b'); + cm.setCursor(3, 2); + helpers.doKeys('m', 'c'); + cm.setCursor(4, 2); + helpers.doKeys('m', 'd'); + cm.setCursor(5, 2); + helpers.doKeys('m', 'e'); + helpers.doEx('delmarks a b-de'); + cm.setCursor(0, 0); + helpers.doKeys('`', 'a'); + helpers.assertCursorAt(0, 0); + helpers.doKeys('`', 'b'); + helpers.assertCursorAt(0, 0); + helpers.doKeys('`', 'c'); + helpers.assertCursorAt(0, 0); + helpers.doKeys('`', 'd'); + helpers.assertCursorAt(0, 0); + helpers.doKeys('`', 'e'); + helpers.assertCursorAt(0, 0); +}); +testVim('visual', function(cm, vim, helpers) { + helpers.doKeys('l', 'v', 'l', 'l'); + helpers.assertCursorAt(0, 4); + eqPos(makeCursor(0, 1), cm.getCursor('anchor')); + helpers.doKeys('d'); + eq('15', cm.getValue()); +}, { value: '12345' }); +testVim('visual_yank', function(cm, vim, helpers) { + helpers.doKeys('v', '3', 'l', 'y'); + helpers.assertCursorAt(0, 0); + helpers.doKeys('p'); + eq('aa te test for yank', cm.getValue()); +}, { value: 'a test for yank' }) +testVim('visual_w', function(cm, vim, helpers) { + helpers.doKeys('v', 'w'); + eq(cm.getSelection(), 'motion t'); +}, { value: 'motion test'}); +testVim('visual_initial_selection', function(cm, vim, helpers) { + cm.setCursor(0, 1); + helpers.doKeys('v'); + cm.getSelection('n'); +}, { value: 'init'}); +testVim('visual_crossover_left', function(cm, vim, helpers) { + cm.setCursor(0, 2); + helpers.doKeys('v', 'l', 'h', 'h'); + cm.getSelection('ro'); +}, { value: 'cross'}); +testVim('visual_crossover_left', function(cm, vim, helpers) { + cm.setCursor(0, 2); + helpers.doKeys('v', 'h', 'l', 'l'); + cm.getSelection('os'); +}, { value: 'cross'}); +testVim('visual_crossover_up', function(cm, vim, helpers) { + cm.setCursor(3, 2); + helpers.doKeys('v', 'j', 'k', 'k'); + eqPos(Pos(2, 2), cm.getCursor('head')); + eqPos(Pos(3, 3), cm.getCursor('anchor')); + helpers.doKeys('k'); + eqPos(Pos(1, 2), cm.getCursor('head')); + eqPos(Pos(3, 3), cm.getCursor('anchor')); +}, { value: 'cross\ncross\ncross\ncross\ncross\n'}); +testVim('visual_crossover_down', function(cm, vim, helpers) { + cm.setCursor(1, 2); + helpers.doKeys('v', 'k', 'j', 'j'); + eqPos(Pos(2, 3), cm.getCursor('head')); + eqPos(Pos(1, 2), cm.getCursor('anchor')); + helpers.doKeys('j'); + eqPos(Pos(3, 3), cm.getCursor('head')); + eqPos(Pos(1, 2), cm.getCursor('anchor')); +}, { value: 'cross\ncross\ncross\ncross\ncross\n'}); +testVim('visual_exit', function(cm, vim, helpers) { + helpers.doKeys('', 'l', 'j', 'j', ''); + eqPos(cm.getCursor('anchor'), cm.getCursor('head')); + eq(vim.visualMode, false); +}, { value: 'hello\nworld\nfoo' }); +testVim('visual_line', function(cm, vim, helpers) { + helpers.doKeys('l', 'V', 'l', 'j', 'j', 'd'); + eq(' 4\n 5', cm.getValue()); +}, { value: ' 1\n 2\n 3\n 4\n 5' }); +testVim('visual_block_move_to_eol', function(cm, vim, helpers) { + // moveToEol should move all block cursors to end of line + cm.setCursor(0, 0); + helpers.doKeys('', 'G', '$'); + var selections = cm.getSelections().join(); + console.log(selections); + eq("123,45,6", selections); +}, {value: '123\n45\n6'}); +testVim('visual_block_different_line_lengths', function(cm, vim, helpers) { + // test the block selection with lines of different length + // i.e. extending the selection + // till the end of the longest line. + helpers.doKeys('', 'l', 'j', 'j', '6', 'l', 'd'); + helpers.doKeys('d', 'd', 'd', 'd'); + eq('', cm.getValue()); +}, {value: '1234\n5678\nabcdefg'}); +testVim('visual_block_truncate_on_short_line', function(cm, vim, helpers) { + // check for left side selection in case + // of moving up to a shorter line. + cm.replaceRange('', cm.getCursor()); + cm.setCursor(3, 4); + helpers.doKeys('', 'l', 'k', 'k', 'd'); + eq('hello world\n{\ntis\nsa!', cm.getValue()); +}, {value: 'hello world\n{\nthis is\nsparta!'}); +testVim('visual_block_corners', function(cm, vim, helpers) { + cm.setCursor(1, 2); + helpers.doKeys('', '2', 'l', 'k'); + // circle around the anchor + // and check the selections + var selections = cm.getSelections(); + eq('345891', selections.join('')); + helpers.doKeys('4', 'h'); + selections = cm.getSelections(); + eq('123678', selections.join('')); + helpers.doKeys('j', 'j'); + selections = cm.getSelections(); + eq('678abc', selections.join('')); + helpers.doKeys('4', 'l'); + selections = cm.getSelections(); + eq('891cde', selections.join('')); +}, {value: '12345\n67891\nabcde'}); +testVim('visual_block_mode_switch', function(cm, vim, helpers) { + // switch between visual modes + cm.setCursor(1, 1); + // blockwise to characterwise visual + helpers.doKeys('', 'j', 'l', 'v'); + selections = cm.getSelections(); + eq('7891\nabc', selections.join('')); + // characterwise to blockwise + helpers.doKeys(''); + selections = cm.getSelections(); + eq('78bc', selections.join('')); + // blockwise to linewise visual + helpers.doKeys('V'); + selections = cm.getSelections(); + eq('67891\nabcde', selections.join('')); +}, {value: '12345\n67891\nabcde'}); +testVim('visual_block_crossing_short_line', function(cm, vim, helpers) { + // visual block with long and short lines + cm.setCursor(0, 3); + helpers.doKeys('', 'j', 'j', 'j'); + var selections = cm.getSelections().join(); + eq('4,,d,b', selections); + helpers.doKeys('3', 'k'); + selections = cm.getSelections().join(); + eq('4', selections); + helpers.doKeys('5', 'j', 'k'); + selections = cm.getSelections().join(""); + eq(10, selections.length); +}, {value: '123456\n78\nabcdefg\nfoobar\n}\n'}); +testVim('visual_block_curPos_on_exit', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('', '3' , 'l', ''); + eqPos(makeCursor(0, 3), cm.getCursor()); + helpers.doKeys('h', '', '2' , 'j' ,'3' , 'l'); + eq(cm.getSelections().join(), "3456,,cdef"); + helpers.doKeys('4' , 'h'); + eq(cm.getSelections().join(), "23,8,bc"); + helpers.doKeys('2' , 'l'); + eq(cm.getSelections().join(), "34,,cd"); +}, {value: '123456\n78\nabcdefg\nfoobar'}); + +testVim('visual_marks', function(cm, vim, helpers) { + helpers.doKeys('l', 'v', 'l', 'l', 'j', 'j', 'v'); + // Test visual mode marks + cm.setCursor(2, 1); + helpers.doKeys('\'', '<'); + helpers.assertCursorAt(0, 1); + helpers.doKeys('\'', '>'); + helpers.assertCursorAt(2, 0); +}); +testVim('visual_join', function(cm, vim, helpers) { + helpers.doKeys('l', 'V', 'l', 'j', 'j', 'J'); + eq(' 1 2 3\n 4\n 5', cm.getValue()); + is(!vim.visualMode); +}, { value: ' 1\n 2\n 3\n 4\n 5' }); +testVim('visual_blank', function(cm, vim, helpers) { + helpers.doKeys('v', 'k'); + eq(vim.visualMode, true); +}, { value: '\n' }); +testVim('reselect_visual', function(cm, vim, helpers) { + helpers.doKeys('l', 'v', 'l', 'l', 'l', 'y', 'g', 'v'); + helpers.assertCursorAt(0, 5); + eqPos(makeCursor(0, 1), cm.getCursor('anchor')); + helpers.doKeys('v'); + cm.setCursor(1, 0); + helpers.doKeys('v', 'l', 'l', 'p'); + eq('123456\n2345\nbar', cm.getValue()); + cm.setCursor(0, 0); + helpers.doKeys('g', 'v'); + // here the fake cursor is at (1, 3) + helpers.assertCursorAt(1, 4); + eqPos(makeCursor(1, 0), cm.getCursor('anchor')); + helpers.doKeys('v'); + cm.setCursor(2, 0); + helpers.doKeys('v', 'l', 'l', 'g', 'v'); + helpers.assertCursorAt(1, 4); + eqPos(makeCursor(1, 0), cm.getCursor('anchor')); + helpers.doKeys('g', 'v'); + helpers.assertCursorAt(2, 3); + eqPos(makeCursor(2, 0), cm.getCursor('anchor')); + eq('123456\n2345\nbar', cm.getValue()); +}, { value: '123456\nfoo\nbar' }); +testVim('reselect_visual_line', function(cm, vim, helpers) { + helpers.doKeys('l', 'V', 'j', 'j', 'V', 'g', 'v', 'd'); + eq('foo\nand\nbar', cm.getValue()); + cm.setCursor(1, 0); + helpers.doKeys('V', 'y', 'j'); + helpers.doKeys('V', 'p' , 'g', 'v', 'd'); + eq('foo\nand', cm.getValue()); +}, { value: 'hello\nthis\nis\nfoo\nand\nbar' }); +testVim('reselect_visual_block', function(cm, vim, helpers) { + cm.setCursor(1, 2); + helpers.doKeys('', 'k', 'h', ''); + cm.setCursor(2, 1); + helpers.doKeys('v', 'l', 'g', 'v'); + eqPos(Pos(1, 2), vim.sel.anchor); + eqPos(Pos(0, 1), vim.sel.head); + // Ensure selection is done with visual block mode rather than one + // continuous range. + eq(cm.getSelections().join(''), '23oo') + helpers.doKeys('g', 'v'); + eqPos(Pos(2, 1), vim.sel.anchor); + eqPos(Pos(2, 2), vim.sel.head); + helpers.doKeys(''); + // Ensure selection of deleted range + cm.setCursor(1, 1); + helpers.doKeys('v', '', 'j', 'd', 'g', 'v'); + eq(cm.getSelections().join(''), 'or'); +}, { value: '123456\nfoo\nbar' }); +testVim('s_normal', function(cm, vim, helpers) { + cm.setCursor(0, 1); + helpers.doKeys('s'); + helpers.doKeys(''); + eq('ac', cm.getValue()); +}, { value: 'abc'}); +testVim('s_visual', function(cm, vim, helpers) { + cm.setCursor(0, 1); + helpers.doKeys('v', 's'); + helpers.doKeys(''); + helpers.assertCursorAt(0, 0); + eq('ac', cm.getValue()); +}, { value: 'abc'}); +testVim('o_visual', function(cm, vim, helpers) { + cm.setCursor(0,0); + helpers.doKeys('v','l','l','l','o'); + helpers.assertCursorAt(0,0); + helpers.doKeys('v','v','j','j','j','o'); + helpers.assertCursorAt(0,0); + helpers.doKeys('O'); + helpers.doKeys('l','l') + helpers.assertCursorAt(3, 3); + helpers.doKeys('d'); + eq('p',cm.getValue()); +}, { value: 'abcd\nefgh\nijkl\nmnop'}); +testVim('o_visual_block', function(cm, vim, helpers) { + cm.setCursor(0, 1); + helpers.doKeys('','3','j','l','l', 'o'); + eqPos(Pos(3, 3), vim.sel.anchor); + eqPos(Pos(0, 1), vim.sel.head); + helpers.doKeys('O'); + eqPos(Pos(3, 1), vim.sel.anchor); + eqPos(Pos(0, 3), vim.sel.head); + helpers.doKeys('o'); + eqPos(Pos(0, 3), vim.sel.anchor); + eqPos(Pos(3, 1), vim.sel.head); +}, { value: 'abcd\nefgh\nijkl\nmnop'}); +testVim('changeCase_visual', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('v', 'l', 'l'); + helpers.doKeys('U'); + helpers.assertCursorAt(0, 0); + helpers.doKeys('v', 'l', 'l'); + helpers.doKeys('u'); + helpers.assertCursorAt(0, 0); + helpers.doKeys('l', 'l', 'l', '.'); + helpers.assertCursorAt(0, 3); + cm.setCursor(0, 0); + helpers.doKeys('q', 'a', 'v', 'j', 'U', 'q'); + helpers.assertCursorAt(0, 0); + helpers.doKeys('j', '@', 'a'); + helpers.assertCursorAt(1, 0); + cm.setCursor(3, 0); + helpers.doKeys('V', 'U', 'j', '.'); + eq('ABCDEF\nGHIJKL\nMnopq\nSHORT LINE\nLONG LINE OF TEXT', cm.getValue()); +}, { value: 'abcdef\nghijkl\nmnopq\nshort line\nlong line of text'}); +testVim('changeCase_visual_block', function(cm, vim, helpers) { + cm.setCursor(2, 1); + helpers.doKeys('', 'k', 'k', 'h', 'U'); + eq('ABcdef\nGHijkl\nMNopq\nfoo', cm.getValue()); + cm.setCursor(0, 2); + helpers.doKeys('.'); + eq('ABCDef\nGHIJkl\nMNOPq\nfoo', cm.getValue()); + // check when last line is shorter. + cm.setCursor(2, 2); + helpers.doKeys('.'); + eq('ABCDef\nGHIJkl\nMNOPq\nfoO', cm.getValue()); +}, { value: 'abcdef\nghijkl\nmnopq\nfoo'}); +testVim('visual_paste', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('v', 'l', 'l', 'y'); + helpers.assertCursorAt(0, 0); + helpers.doKeys('3', 'l', 'j', 'v', 'l', 'p'); + helpers.assertCursorAt(1, 5); + eq('this is a\nunithitest for visual paste', cm.getValue()); + cm.setCursor(0, 0); + // in case of pasting whole line + helpers.doKeys('y', 'y'); + cm.setCursor(1, 6); + helpers.doKeys('v', 'l', 'l', 'l', 'p'); + helpers.assertCursorAt(2, 0); + eq('this is a\nunithi\nthis is a\n for visual paste', cm.getValue()); +}, { value: 'this is a\nunit test for visual paste'}); + +// This checks the contents of the register used to paste the text +testVim('v_paste_from_register', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('"', 'a', 'y', 'w'); + cm.setCursor(1, 0); + helpers.doKeys('v', 'p'); + cm.openDialog = helpers.fakeOpenDialog('registers'); + cm.openNotification = helpers.fakeOpenNotification(function(text) { + is(/a\s+register/.test(text)); + }); +}, { value: 'register contents\nare not erased'}); +testVim('S_normal', function(cm, vim, helpers) { + cm.setCursor(0, 1); + helpers.doKeys('j', 'S'); + helpers.doKeys(''); + helpers.assertCursorAt(1, 0); + eq('aa\n\ncc', cm.getValue()); +}, { value: 'aa\nbb\ncc'}); +testVim('blockwise_paste', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('', '3', 'j', 'l', 'y'); + cm.setCursor(0, 2); + // paste one char after the current cursor position + helpers.doKeys('p'); + eq('helhelo\nworwold\nfoofo\nbarba', cm.getValue()); + cm.setCursor(0, 0); + helpers.doKeys('v', '4', 'l', 'y'); + cm.setCursor(0, 0); + helpers.doKeys('', '3', 'j', 'p'); + eq('helheelhelo\norwold\noofo\narba', cm.getValue()); +}, { value: 'hello\nworld\nfoo\nbar'}); +testVim('blockwise_paste_long/short_line', function(cm, vim, helpers) { + // extend short lines in case of different line lengths. + cm.setCursor(0, 0); + helpers.doKeys('', 'j', 'j', 'y'); + cm.setCursor(0, 3); + helpers.doKeys('p'); + eq('hellho\nfoo f\nbar b', cm.getValue()); +}, { value: 'hello\nfoo\nbar'}); +testVim('blockwise_paste_cut_paste', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('', '2', 'j', 'x'); + cm.setCursor(0, 0); + helpers.doKeys('P'); + eq('cut\nand\npaste\nme', cm.getValue()); +}, { value: 'cut\nand\npaste\nme'}); +testVim('blockwise_paste_from_register', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('', '2', 'j', '"', 'a', 'y'); + cm.setCursor(0, 3); + helpers.doKeys('"', 'a', 'p'); + eq('foobfar\nhellho\nworlwd', cm.getValue()); +}, { value: 'foobar\nhello\nworld'}); +testVim('blockwise_paste_last_line', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('', '2', 'j', 'l', 'y'); + cm.setCursor(3, 0); + helpers.doKeys('p'); + eq('cut\nand\npaste\nmcue\n an\n pa', cm.getValue()); +}, { value: 'cut\nand\npaste\nme'}); + +testVim('S_visual', function(cm, vim, helpers) { + cm.setCursor(0, 1); + helpers.doKeys('v', 'j', 'S'); + helpers.doKeys(''); + helpers.assertCursorAt(0, 0); + eq('\ncc', cm.getValue()); +}, { value: 'aa\nbb\ncc'}); + +testVim('/ and n/N', function(cm, vim, helpers) { + cm.openDialog = helpers.fakeOpenDialog('match'); + helpers.doKeys('/'); + helpers.assertCursorAt(0, 11); + helpers.doKeys('n'); + helpers.assertCursorAt(1, 6); + helpers.doKeys('N'); + helpers.assertCursorAt(0, 11); + + cm.setCursor(0, 0); + helpers.doKeys('2', '/'); + helpers.assertCursorAt(1, 6); +}, { value: 'match nope match \n nope Match' }); +testVim('/_case', function(cm, vim, helpers) { + cm.openDialog = helpers.fakeOpenDialog('Match'); + helpers.doKeys('/'); + helpers.assertCursorAt(1, 6); +}, { value: 'match nope match \n nope Match' }); +testVim('/_2_pcre', function(cm, vim, helpers) { + CodeMirror.Vim.setOption('pcre', true); + cm.openDialog = helpers.fakeOpenDialog('(word){2}'); + helpers.doKeys('/'); + helpers.assertCursorAt(1, 9); + helpers.doKeys('n'); + helpers.assertCursorAt(2, 1); +}, { value: 'word\n another wordword\n wordwordword\n' }); +testVim('/_2_nopcre', function(cm, vim, helpers) { + CodeMirror.Vim.setOption('pcre', false); + cm.openDialog = helpers.fakeOpenDialog('\\(word\\)\\{2}'); + helpers.doKeys('/'); + helpers.assertCursorAt(1, 9); + helpers.doKeys('n'); + helpers.assertCursorAt(2, 1); +}, { value: 'word\n another wordword\n wordwordword\n' }); +testVim('/_nongreedy', function(cm, vim, helpers) { + cm.openDialog = helpers.fakeOpenDialog('aa'); + helpers.doKeys('/'); + helpers.assertCursorAt(0, 4); + helpers.doKeys('n'); + helpers.assertCursorAt(1, 3); + helpers.doKeys('n'); + helpers.assertCursorAt(0, 0); +}, { value: 'aaa aa \n a aa'}); +testVim('?_nongreedy', function(cm, vim, helpers) { + cm.openDialog = helpers.fakeOpenDialog('aa'); + helpers.doKeys('?'); + helpers.assertCursorAt(1, 3); + helpers.doKeys('n'); + helpers.assertCursorAt(0, 4); + helpers.doKeys('n'); + helpers.assertCursorAt(0, 0); +}, { value: 'aaa aa \n a aa'}); +testVim('/_greedy', function(cm, vim, helpers) { + cm.openDialog = helpers.fakeOpenDialog('a+'); + helpers.doKeys('/'); + helpers.assertCursorAt(0, 4); + helpers.doKeys('n'); + helpers.assertCursorAt(1, 1); + helpers.doKeys('n'); + helpers.assertCursorAt(1, 3); + helpers.doKeys('n'); + helpers.assertCursorAt(0, 0); +}, { value: 'aaa aa \n a aa'}); +testVim('?_greedy', function(cm, vim, helpers) { + cm.openDialog = helpers.fakeOpenDialog('a+'); + helpers.doKeys('?'); + helpers.assertCursorAt(1, 3); + helpers.doKeys('n'); + helpers.assertCursorAt(1, 1); + helpers.doKeys('n'); + helpers.assertCursorAt(0, 4); + helpers.doKeys('n'); + helpers.assertCursorAt(0, 0); +}, { value: 'aaa aa \n a aa'}); +testVim('/_greedy_0_or_more', function(cm, vim, helpers) { + cm.openDialog = helpers.fakeOpenDialog('a*'); + helpers.doKeys('/'); + helpers.assertCursorAt(0, 3); + helpers.doKeys('n'); + helpers.assertCursorAt(0, 4); + helpers.doKeys('n'); + helpers.assertCursorAt(0, 5); + helpers.doKeys('n'); + helpers.assertCursorAt(1, 0); + helpers.doKeys('n'); + helpers.assertCursorAt(1, 1); + helpers.doKeys('n'); + helpers.assertCursorAt(0, 0); +}, { value: 'aaa aa\n aa'}); +testVim('?_greedy_0_or_more', function(cm, vim, helpers) { + cm.openDialog = helpers.fakeOpenDialog('a*'); + helpers.doKeys('?'); + helpers.assertCursorAt(1, 1); + helpers.doKeys('n'); + helpers.assertCursorAt(1, 0); + helpers.doKeys('n'); + helpers.assertCursorAt(0, 5); + helpers.doKeys('n'); + helpers.assertCursorAt(0, 4); + helpers.doKeys('n'); + helpers.assertCursorAt(0, 3); + helpers.doKeys('n'); + helpers.assertCursorAt(0, 0); +}, { value: 'aaa aa\n aa'}); +testVim('? and n/N', function(cm, vim, helpers) { + cm.openDialog = helpers.fakeOpenDialog('match'); + helpers.doKeys('?'); + helpers.assertCursorAt(1, 6); + helpers.doKeys('n'); + helpers.assertCursorAt(0, 11); + helpers.doKeys('N'); + helpers.assertCursorAt(1, 6); + + cm.setCursor(0, 0); + helpers.doKeys('2', '?'); + helpers.assertCursorAt(0, 11); +}, { value: 'match nope match \n nope Match' }); +testVim('*', function(cm, vim, helpers) { + cm.setCursor(0, 9); + helpers.doKeys('*'); + helpers.assertCursorAt(0, 22); + + cm.setCursor(0, 9); + helpers.doKeys('2', '*'); + helpers.assertCursorAt(1, 8); +}, { value: 'nomatch match nomatch match \nnomatch Match' }); +testVim('*_no_word', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('*'); + helpers.assertCursorAt(0, 0); +}, { value: ' \n match \n' }); +testVim('*_symbol', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('*'); + helpers.assertCursorAt(1, 0); +}, { value: ' /}\n/} match \n' }); +testVim('#', function(cm, vim, helpers) { + cm.setCursor(0, 9); + helpers.doKeys('#'); + helpers.assertCursorAt(1, 8); + + cm.setCursor(0, 9); + helpers.doKeys('2', '#'); + helpers.assertCursorAt(0, 22); +}, { value: 'nomatch match nomatch match \nnomatch Match' }); +testVim('*_seek', function(cm, vim, helpers) { + // Should skip over space and symbols. + cm.setCursor(0, 3); + helpers.doKeys('*'); + helpers.assertCursorAt(0, 22); +}, { value: ' := match nomatch match \nnomatch Match' }); +testVim('#', function(cm, vim, helpers) { + // Should skip over space and symbols. + cm.setCursor(0, 3); + helpers.doKeys('#'); + helpers.assertCursorAt(1, 8); +}, { value: ' := match nomatch match \nnomatch Match' }); +testVim('g*', function(cm, vim, helpers) { + cm.setCursor(0, 8); + helpers.doKeys('g', '*'); + helpers.assertCursorAt(0, 18); + cm.setCursor(0, 8); + helpers.doKeys('3', 'g', '*'); + helpers.assertCursorAt(1, 8); +}, { value: 'matches match alsoMatch\nmatchme matching' }); +testVim('g#', function(cm, vim, helpers) { + cm.setCursor(0, 8); + helpers.doKeys('g', '#'); + helpers.assertCursorAt(0, 0); + cm.setCursor(0, 8); + helpers.doKeys('3', 'g', '#'); + helpers.assertCursorAt(1, 0); +}, { value: 'matches match alsoMatch\nmatchme matching' }); +testVim('macro_insert', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('q', 'a', '0', 'i'); + cm.replaceRange('foo', cm.getCursor()); + helpers.doKeys(''); + helpers.doKeys('q', '@', 'a'); + eq('foofoo', cm.getValue()); +}, { value: ''}); +testVim('macro_insert_repeat', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('q', 'a', '$', 'a'); + cm.replaceRange('larry.', cm.getCursor()); + helpers.doKeys(''); + helpers.doKeys('a'); + cm.replaceRange('curly.', cm.getCursor()); + helpers.doKeys(''); + helpers.doKeys('q'); + helpers.doKeys('a'); + cm.replaceRange('moe.', cm.getCursor()); + helpers.doKeys(''); + helpers.doKeys('@', 'a'); + // At this point, the most recent edit should be the 2nd insert change + // inside the macro, i.e. "curly.". + helpers.doKeys('.'); + eq('larry.curly.moe.larry.curly.curly.', cm.getValue()); +}, { value: ''}); +testVim('macro_space', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('', ''); + helpers.assertCursorAt(0, 2); + helpers.doKeys('q', 'a', '', '', 'q'); + helpers.assertCursorAt(0, 4); + helpers.doKeys('@', 'a'); + helpers.assertCursorAt(0, 6); + helpers.doKeys('@', 'a'); + helpers.assertCursorAt(0, 8); +}, { value: 'one line of text.'}); +testVim('macro_t_search', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('q', 'a', 't', 'e', 'q'); + helpers.assertCursorAt(0, 1); + helpers.doKeys('l', '@', 'a'); + helpers.assertCursorAt(0, 6); + helpers.doKeys('l', ';'); + helpers.assertCursorAt(0, 12); +}, { value: 'one line of text.'}); +testVim('macro_f_search', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('q', 'b', 'f', 'e', 'q'); + helpers.assertCursorAt(0, 2); + helpers.doKeys('@', 'b'); + helpers.assertCursorAt(0, 7); + helpers.doKeys(';'); + helpers.assertCursorAt(0, 13); +}, { value: 'one line of text.'}); +testVim('macro_slash_search', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('q', 'c'); + cm.openDialog = helpers.fakeOpenDialog('e'); + helpers.doKeys('/', 'q'); + helpers.assertCursorAt(0, 2); + helpers.doKeys('@', 'c'); + helpers.assertCursorAt(0, 7); + helpers.doKeys('n'); + helpers.assertCursorAt(0, 13); +}, { value: 'one line of text.'}); +testVim('macro_multislash_search', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('q', 'd'); + cm.openDialog = helpers.fakeOpenDialog('e'); + helpers.doKeys('/'); + cm.openDialog = helpers.fakeOpenDialog('t'); + helpers.doKeys('/', 'q'); + helpers.assertCursorAt(0, 12); + helpers.doKeys('@', 'd'); + helpers.assertCursorAt(0, 15); +}, { value: 'one line of text to rule them all.'}); +testVim('macro_parens', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('q', 'z', 'i'); + cm.replaceRange('(', cm.getCursor()); + helpers.doKeys(''); + helpers.doKeys('e', 'a'); + cm.replaceRange(')', cm.getCursor()); + helpers.doKeys(''); + helpers.doKeys('q'); + helpers.doKeys('w', '@', 'z'); + helpers.doKeys('w', '@', 'z'); + eq('(see) (spot) (run)', cm.getValue()); +}, { value: 'see spot run'}); +testVim('macro_overwrite', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('q', 'z', '0', 'i'); + cm.replaceRange('I ', cm.getCursor()); + helpers.doKeys(''); + helpers.doKeys('q'); + helpers.doKeys('e'); + // Now replace the macro with something else. + helpers.doKeys('q', 'z', 'a'); + cm.replaceRange('.', cm.getCursor()); + helpers.doKeys(''); + helpers.doKeys('q'); + helpers.doKeys('e', '@', 'z'); + helpers.doKeys('e', '@', 'z'); + eq('I see. spot. run.', cm.getValue()); +}, { value: 'see spot run'}); +testVim('macro_search_f', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('q', 'a', 'f', ' '); + helpers.assertCursorAt(0,3); + helpers.doKeys('q', '0'); + helpers.assertCursorAt(0,0); + helpers.doKeys('@', 'a'); + helpers.assertCursorAt(0,3); +}, { value: 'The quick brown fox jumped over the lazy dog.'}); +testVim('macro_search_2f', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('q', 'a', '2', 'f', ' '); + helpers.assertCursorAt(0,9); + helpers.doKeys('q', '0'); + helpers.assertCursorAt(0,0); + helpers.doKeys('@', 'a'); + helpers.assertCursorAt(0,9); +}, { value: 'The quick brown fox jumped over the lazy dog.'}); +testVim('yank_register', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('"', 'a', 'y', 'y'); + helpers.doKeys('j', '"', 'b', 'y', 'y'); + cm.openDialog = helpers.fakeOpenDialog('registers'); + cm.openNotification = helpers.fakeOpenNotification(function(text) { + is(/a\s+foo/.test(text)); + is(/b\s+bar/.test(text)); + }); + helpers.doKeys(':'); +}, { value: 'foo\nbar'}); +testVim('yank_visual_block', function(cm, vim, helpers) { + cm.setCursor(0, 1); + helpers.doKeys('', 'l', 'j', '"', 'a', 'y'); + cm.openNotification = helpers.fakeOpenNotification(function(text) { + is(/a\s+oo\nar/.test(text)); + }); + helpers.doKeys(':'); +}, { value: 'foo\nbar'}); +testVim('yank_append_line_to_line_register', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('"', 'a', 'y', 'y'); + helpers.doKeys('j', '"', 'A', 'y', 'y'); + cm.openDialog = helpers.fakeOpenDialog('registers'); + cm.openNotification = helpers.fakeOpenNotification(function(text) { + is(/a\s+foo\nbar/.test(text)); + is(/"\s+foo\nbar/.test(text)); + }); + helpers.doKeys(':'); +}, { value: 'foo\nbar'}); +testVim('yank_append_word_to_word_register', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('"', 'a', 'y', 'w'); + helpers.doKeys('j', '"', 'A', 'y', 'w'); + cm.openDialog = helpers.fakeOpenDialog('registers'); + cm.openNotification = helpers.fakeOpenNotification(function(text) { + is(/a\s+foobar/.test(text)); + is(/"\s+foobar/.test(text)); + }); + helpers.doKeys(':'); +}, { value: 'foo\nbar'}); +testVim('yank_append_line_to_word_register', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('"', 'a', 'y', 'w'); + helpers.doKeys('j', '"', 'A', 'y', 'y'); + cm.openDialog = helpers.fakeOpenDialog('registers'); + cm.openNotification = helpers.fakeOpenNotification(function(text) { + is(/a\s+foo\nbar/.test(text)); + is(/"\s+foo\nbar/.test(text)); + }); + helpers.doKeys(':'); +}, { value: 'foo\nbar'}); +testVim('yank_append_word_to_line_register', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('"', 'a', 'y', 'y'); + helpers.doKeys('j', '"', 'A', 'y', 'w'); + cm.openDialog = helpers.fakeOpenDialog('registers'); + cm.openNotification = helpers.fakeOpenNotification(function(text) { + is(/a\s+foo\nbar/.test(text)); + is(/"\s+foo\nbar/.test(text)); + }); + helpers.doKeys(':'); +}, { value: 'foo\nbar'}); +testVim('macro_register', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('q', 'a', 'i'); + cm.replaceRange('gangnam', cm.getCursor()); + helpers.doKeys(''); + helpers.doKeys('q'); + helpers.doKeys('q', 'b', 'o'); + cm.replaceRange('style', cm.getCursor()); + helpers.doKeys(''); + helpers.doKeys('q'); + cm.openDialog = helpers.fakeOpenDialog('registers'); + cm.openNotification = helpers.fakeOpenNotification(function(text) { + is(/a\s+i/.test(text)); + is(/b\s+o/.test(text)); + }); + helpers.doKeys(':'); +}, { value: ''}); +testVim('._register', function(cm,vim,helpers) { + cm.setCursor(0,0); + helpers.doKeys('i'); + cm.replaceRange('foo',cm.getCursor()); + helpers.doKeys(''); + cm.openDialog = helpers.fakeOpenDialog('registers'); + cm.openNotification = helpers.fakeOpenNotification(function(text) { + is(/\.\s+foo/.test(text)); + }); + helpers.doKeys(':'); +}, {value: ''}); +testVim(':_register', function(cm,vim,helpers) { + helpers.doEx('bar'); + cm.openDialog = helpers.fakeOpenDialog('registers'); + cm.openNotification = helpers.fakeOpenNotification(function(text) { + is(/:\s+bar/.test(text)); + }); + helpers.doKeys(':'); +}, {value: ''}); +testVim('search_register_escape', function(cm, vim, helpers) { + // Check that the register is restored if the user escapes rather than confirms. + cm.openDialog = helpers.fakeOpenDialog('waldo'); + helpers.doKeys('/'); + var onKeyDown; + var onKeyUp; + var KEYCODES = { + f: 70, + o: 79, + Esc: 27 + }; + cm.openDialog = function(template, callback, options) { + onKeyDown = options.onKeyDown; + onKeyUp = options.onKeyUp; + }; + var close = function() {}; + helpers.doKeys('/'); + // Fake some keyboard events coming in. + onKeyDown({keyCode: KEYCODES.f}, '', close); + onKeyUp({keyCode: KEYCODES.f}, '', close); + onKeyDown({keyCode: KEYCODES.o}, 'f', close); + onKeyUp({keyCode: KEYCODES.o}, 'f', close); + onKeyDown({keyCode: KEYCODES.o}, 'fo', close); + onKeyUp({keyCode: KEYCODES.o}, 'fo', close); + onKeyDown({keyCode: KEYCODES.Esc}, 'foo', close); + cm.openDialog = helpers.fakeOpenDialog('registers'); + cm.openNotification = helpers.fakeOpenNotification(function(text) { + is(/waldo/.test(text)); + is(!/foo/.test(text)); + }); + helpers.doKeys(':'); +}, {value: ''}); +testVim('search_register', function(cm, vim, helpers) { + cm.openDialog = helpers.fakeOpenDialog('foo'); + helpers.doKeys('/'); + cm.openDialog = helpers.fakeOpenDialog('registers'); + cm.openNotification = helpers.fakeOpenNotification(function(text) { + is(/\/\s+foo/.test(text)); + }); + helpers.doKeys(':'); +}, {value: ''}); +testVim('search_history', function(cm, vim, helpers) { + cm.openDialog = helpers.fakeOpenDialog('this'); + helpers.doKeys('/'); + cm.openDialog = helpers.fakeOpenDialog('checks'); + helpers.doKeys('/'); + cm.openDialog = helpers.fakeOpenDialog('search'); + helpers.doKeys('/'); + cm.openDialog = helpers.fakeOpenDialog('history'); + helpers.doKeys('/'); + cm.openDialog = helpers.fakeOpenDialog('checks'); + helpers.doKeys('/'); + var onKeyDown; + var onKeyUp; + var query = ''; + var keyCodes = { + Up: 38, + Down: 40 + }; + cm.openDialog = function(template, callback, options) { + onKeyUp = options.onKeyUp; + onKeyDown = options.onKeyDown; + }; + var close = function(newVal) { + if (typeof newVal == 'string') query = newVal; + } + helpers.doKeys('/'); + onKeyDown({keyCode: keyCodes.Up}, query, close); + onKeyUp({keyCode: keyCodes.Up}, query, close); + eq(query, 'checks'); + onKeyDown({keyCode: keyCodes.Up}, query, close); + onKeyUp({keyCode: keyCodes.Up}, query, close); + eq(query, 'history'); + onKeyDown({keyCode: keyCodes.Up}, query, close); + onKeyUp({keyCode: keyCodes.Up}, query, close); + eq(query, 'search'); + onKeyDown({keyCode: keyCodes.Up}, query, close); + onKeyUp({keyCode: keyCodes.Up}, query, close); + eq(query, 'this'); + onKeyDown({keyCode: keyCodes.Down}, query, close); + onKeyUp({keyCode: keyCodes.Down}, query, close); + eq(query, 'search'); +}, {value: ''}); +testVim('exCommand_history', function(cm, vim, helpers) { + cm.openDialog = helpers.fakeOpenDialog('registers'); + helpers.doKeys(':'); + cm.openDialog = helpers.fakeOpenDialog('sort'); + helpers.doKeys(':'); + cm.openDialog = helpers.fakeOpenDialog('map'); + helpers.doKeys(':'); + cm.openDialog = helpers.fakeOpenDialog('invalid'); + helpers.doKeys(':'); + var onKeyDown; + var onKeyUp; + var input = ''; + var keyCodes = { + Up: 38, + Down: 40, + s: 115 + }; + cm.openDialog = function(template, callback, options) { + onKeyUp = options.onKeyUp; + onKeyDown = options.onKeyDown; + }; + var close = function(newVal) { + if (typeof newVal == 'string') input = newVal; + } + helpers.doKeys(':'); + onKeyDown({keyCode: keyCodes.Up}, input, close); + eq(input, 'invalid'); + onKeyDown({keyCode: keyCodes.Up}, input, close); + eq(input, 'map'); + onKeyDown({keyCode: keyCodes.Up}, input, close); + eq(input, 'sort'); + onKeyDown({keyCode: keyCodes.Up}, input, close); + eq(input, 'registers'); + onKeyDown({keyCode: keyCodes.s}, '', close); + input = 's'; + onKeyDown({keyCode: keyCodes.Up}, input, close); + eq(input, 'sort'); +}, {value: ''}); +testVim('.', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('2', 'd', 'w'); + helpers.doKeys('.'); + eq('5 6', cm.getValue()); +}, { value: '1 2 3 4 5 6'}); +testVim('._repeat', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('2', 'd', 'w'); + helpers.doKeys('3', '.'); + eq('6', cm.getValue()); +}, { value: '1 2 3 4 5 6'}); +testVim('._insert', function(cm, vim, helpers) { + helpers.doKeys('i'); + cm.replaceRange('test', cm.getCursor()); + helpers.doKeys(''); + helpers.doKeys('.'); + eq('testestt', cm.getValue()); + helpers.assertCursorAt(0, 6); +}, { value: ''}); +testVim('._insert_repeat', function(cm, vim, helpers) { + helpers.doKeys('i'); + cm.replaceRange('test', cm.getCursor()); + cm.setCursor(0, 4); + helpers.doKeys(''); + helpers.doKeys('2', '.'); + eq('testesttestt', cm.getValue()); + helpers.assertCursorAt(0, 10); +}, { value: ''}); +testVim('._repeat_insert', function(cm, vim, helpers) { + helpers.doKeys('3', 'i'); + cm.replaceRange('te', cm.getCursor()); + cm.setCursor(0, 2); + helpers.doKeys(''); + helpers.doKeys('.'); + eq('tetettetetee', cm.getValue()); + helpers.assertCursorAt(0, 10); +}, { value: ''}); +testVim('._insert_o', function(cm, vim, helpers) { + helpers.doKeys('o'); + cm.replaceRange('z', cm.getCursor()); + cm.setCursor(1, 1); + helpers.doKeys(''); + helpers.doKeys('.'); + eq('\nz\nz', cm.getValue()); + helpers.assertCursorAt(2, 0); +}, { value: ''}); +testVim('._insert_o_repeat', function(cm, vim, helpers) { + helpers.doKeys('o'); + cm.replaceRange('z', cm.getCursor()); + helpers.doKeys(''); + cm.setCursor(1, 0); + helpers.doKeys('2', '.'); + eq('\nz\nz\nz', cm.getValue()); + helpers.assertCursorAt(3, 0); +}, { value: ''}); +testVim('._insert_o_indent', function(cm, vim, helpers) { + helpers.doKeys('o'); + cm.replaceRange('z', cm.getCursor()); + helpers.doKeys(''); + cm.setCursor(1, 2); + helpers.doKeys('.'); + eq('{\n z\n z', cm.getValue()); + helpers.assertCursorAt(2, 2); +}, { value: '{'}); +testVim('._insert_cw', function(cm, vim, helpers) { + helpers.doKeys('c', 'w'); + cm.replaceRange('test', cm.getCursor()); + helpers.doKeys(''); + cm.setCursor(0, 3); + helpers.doKeys('2', 'l'); + helpers.doKeys('.'); + eq('test test word3', cm.getValue()); + helpers.assertCursorAt(0, 8); +}, { value: 'word1 word2 word3' }); +testVim('._insert_cw_repeat', function(cm, vim, helpers) { + // For some reason, repeat cw in desktop VIM will does not repeat insert mode + // changes. Will conform to that behavior. + helpers.doKeys('c', 'w'); + cm.replaceRange('test', cm.getCursor()); + helpers.doKeys(''); + cm.setCursor(0, 4); + helpers.doKeys('l'); + helpers.doKeys('2', '.'); + eq('test test', cm.getValue()); + helpers.assertCursorAt(0, 8); +}, { value: 'word1 word2 word3' }); +testVim('._delete', function(cm, vim, helpers) { + cm.setCursor(0, 5); + helpers.doKeys('i'); + helpers.doInsertModeKeys('Backspace'); + helpers.doKeys(''); + helpers.doKeys('.'); + eq('zace', cm.getValue()); + helpers.assertCursorAt(0, 1); +}, { value: 'zabcde'}); +testVim('._delete_repeat', function(cm, vim, helpers) { + cm.setCursor(0, 6); + helpers.doKeys('i'); + helpers.doInsertModeKeys('Backspace'); + helpers.doKeys(''); + helpers.doKeys('2', '.'); + eq('zzce', cm.getValue()); + helpers.assertCursorAt(0, 1); +}, { value: 'zzabcde'}); +testVim('._visual_>', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('V', 'j', '>'); + cm.setCursor(2, 0) + helpers.doKeys('.'); + eq(' 1\n 2\n 3\n 4', cm.getValue()); + helpers.assertCursorAt(2, 2); +}, { value: '1\n2\n3\n4'}); +testVim('f;', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('f', 'x'); + helpers.doKeys(';'); + helpers.doKeys('2', ';'); + eq(9, cm.getCursor().ch); +}, { value: '01x3xx678x'}); +testVim('F;', function(cm, vim, helpers) { + cm.setCursor(0, 8); + helpers.doKeys('F', 'x'); + helpers.doKeys(';'); + helpers.doKeys('2', ';'); + eq(2, cm.getCursor().ch); +}, { value: '01x3xx6x8x'}); +testVim('t;', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('t', 'x'); + helpers.doKeys(';'); + helpers.doKeys('2', ';'); + eq(8, cm.getCursor().ch); +}, { value: '01x3xx678x'}); +testVim('T;', function(cm, vim, helpers) { + cm.setCursor(0, 9); + helpers.doKeys('T', 'x'); + helpers.doKeys(';'); + helpers.doKeys('2', ';'); + eq(2, cm.getCursor().ch); +}, { value: '0xx3xx678x'}); +testVim('f,', function(cm, vim, helpers) { + cm.setCursor(0, 6); + helpers.doKeys('f', 'x'); + helpers.doKeys(','); + helpers.doKeys('2', ','); + eq(2, cm.getCursor().ch); +}, { value: '01x3xx678x'}); +testVim('F,', function(cm, vim, helpers) { + cm.setCursor(0, 3); + helpers.doKeys('F', 'x'); + helpers.doKeys(','); + helpers.doKeys('2', ','); + eq(9, cm.getCursor().ch); +}, { value: '01x3xx678x'}); +testVim('t,', function(cm, vim, helpers) { + cm.setCursor(0, 6); + helpers.doKeys('t', 'x'); + helpers.doKeys(','); + helpers.doKeys('2', ','); + eq(3, cm.getCursor().ch); +}, { value: '01x3xx678x'}); +testVim('T,', function(cm, vim, helpers) { + cm.setCursor(0, 4); + helpers.doKeys('T', 'x'); + helpers.doKeys(','); + helpers.doKeys('2', ','); + eq(8, cm.getCursor().ch); +}, { value: '01x3xx67xx'}); +testVim('fd,;', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('f', '4'); + cm.setCursor(0, 0); + helpers.doKeys('d', ';'); + eq('56789', cm.getValue()); + helpers.doKeys('u'); + cm.setCursor(0, 9); + helpers.doKeys('d', ','); + eq('01239', cm.getValue()); +}, { value: '0123456789'}); +testVim('Fd,;', function(cm, vim, helpers) { + cm.setCursor(0, 9); + helpers.doKeys('F', '4'); + cm.setCursor(0, 9); + helpers.doKeys('d', ';'); + eq('01239', cm.getValue()); + helpers.doKeys('u'); + cm.setCursor(0, 0); + helpers.doKeys('d', ','); + eq('56789', cm.getValue()); +}, { value: '0123456789'}); +testVim('td,;', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('t', '4'); + cm.setCursor(0, 0); + helpers.doKeys('d', ';'); + eq('456789', cm.getValue()); + helpers.doKeys('u'); + cm.setCursor(0, 9); + helpers.doKeys('d', ','); + eq('012349', cm.getValue()); +}, { value: '0123456789'}); +testVim('Td,;', function(cm, vim, helpers) { + cm.setCursor(0, 9); + helpers.doKeys('T', '4'); + cm.setCursor(0, 9); + helpers.doKeys('d', ';'); + eq('012349', cm.getValue()); + helpers.doKeys('u'); + cm.setCursor(0, 0); + helpers.doKeys('d', ','); + eq('456789', cm.getValue()); +}, { value: '0123456789'}); +testVim('fc,;', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('f', '4'); + cm.setCursor(0, 0); + helpers.doKeys('c', ';', ''); + eq('56789', cm.getValue()); + helpers.doKeys('u'); + cm.setCursor(0, 9); + helpers.doKeys('c', ','); + eq('01239', cm.getValue()); +}, { value: '0123456789'}); +testVim('Fc,;', function(cm, vim, helpers) { + cm.setCursor(0, 9); + helpers.doKeys('F', '4'); + cm.setCursor(0, 9); + helpers.doKeys('c', ';', ''); + eq('01239', cm.getValue()); + helpers.doKeys('u'); + cm.setCursor(0, 0); + helpers.doKeys('c', ','); + eq('56789', cm.getValue()); +}, { value: '0123456789'}); +testVim('tc,;', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('t', '4'); + cm.setCursor(0, 0); + helpers.doKeys('c', ';', ''); + eq('456789', cm.getValue()); + helpers.doKeys('u'); + cm.setCursor(0, 9); + helpers.doKeys('c', ','); + eq('012349', cm.getValue()); +}, { value: '0123456789'}); +testVim('Tc,;', function(cm, vim, helpers) { + cm.setCursor(0, 9); + helpers.doKeys('T', '4'); + cm.setCursor(0, 9); + helpers.doKeys('c', ';', ''); + eq('012349', cm.getValue()); + helpers.doKeys('u'); + cm.setCursor(0, 0); + helpers.doKeys('c', ','); + eq('456789', cm.getValue()); +}, { value: '0123456789'}); +testVim('fy,;', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('f', '4'); + cm.setCursor(0, 0); + helpers.doKeys('y', ';', 'P'); + eq('012340123456789', cm.getValue()); + helpers.doKeys('u'); + cm.setCursor(0, 9); + helpers.doKeys('y', ',', 'P'); + eq('012345678456789', cm.getValue()); +}, { value: '0123456789'}); +testVim('Fy,;', function(cm, vim, helpers) { + cm.setCursor(0, 9); + helpers.doKeys('F', '4'); + cm.setCursor(0, 9); + helpers.doKeys('y', ';', 'p'); + eq('012345678945678', cm.getValue()); + helpers.doKeys('u'); + cm.setCursor(0, 0); + helpers.doKeys('y', ',', 'P'); + eq('012340123456789', cm.getValue()); +}, { value: '0123456789'}); +testVim('ty,;', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('t', '4'); + cm.setCursor(0, 0); + helpers.doKeys('y', ';', 'P'); + eq('01230123456789', cm.getValue()); + helpers.doKeys('u'); + cm.setCursor(0, 9); + helpers.doKeys('y', ',', 'p'); + eq('01234567895678', cm.getValue()); +}, { value: '0123456789'}); +testVim('Ty,;', function(cm, vim, helpers) { + cm.setCursor(0, 9); + helpers.doKeys('T', '4'); + cm.setCursor(0, 9); + helpers.doKeys('y', ';', 'p'); + eq('01234567895678', cm.getValue()); + helpers.doKeys('u'); + cm.setCursor(0, 0); + helpers.doKeys('y', ',', 'P'); + eq('01230123456789', cm.getValue()); +}, { value: '0123456789'}); +testVim('HML', function(cm, vim, helpers) { + var lines = 35; + var textHeight = cm.defaultTextHeight(); + cm.setSize(600, lines*textHeight); + cm.setCursor(120, 0); + cm.refresh(); //ace! + helpers.doKeys('H'); + helpers.assertCursorAt(86, 2); + helpers.doKeys('L'); + helpers.assertCursorAt(120, 4); + helpers.doKeys('M'); + helpers.assertCursorAt(103,4); +}, { value: (function(){ + var lines = new Array(100); + var upper = ' xx\n'; + var lower = ' xx\n'; + upper = lines.join(upper); + lower = lines.join(lower); + return upper + lower; +})()}); + +var zVals = []; +forEach(['zb','zz','zt','z-','z.','z'], function(e, idx){ + var lineNum = 250; + var lines = 35; + testVim(e, function(cm, vim, helpers) { + var k1 = e[0]; + var k2 = e.substring(1); + var textHeight = cm.defaultTextHeight(); + cm.setSize(600, lines*textHeight); + cm.setCursor(lineNum, 0); + helpers.doKeys(k1, k2); + zVals[idx] = cm.getScrollInfo().top; + }, { value: (function(){ + return new Array(500).join('\n'); + })()}); +}); +testVim('zb', function(cm, vim, helpers){ + eq(zVals[2], zVals[5]); +}); + +var moveTillCharacterSandbox = + 'The quick brown fox \n' + 'jumped over the lazy dog.' +testVim('moveTillCharacter', function(cm, vim, helpers){ + cm.setCursor(0, 0); + // Search for the 'q'. + cm.openDialog = helpers.fakeOpenDialog('q'); + helpers.doKeys('/'); + eq(4, cm.getCursor().ch); + // Jump to just before the first o in the list. + helpers.doKeys('t'); + helpers.doKeys('o'); + eq('The quick brown fox \n', cm.getValue()); + // Delete that one character. + helpers.doKeys('d'); + helpers.doKeys('t'); + helpers.doKeys('o'); + eq('The quick bown fox \n', cm.getValue()); + // Delete everything until the next 'o'. + helpers.doKeys('.'); + eq('The quick box \n', cm.getValue()); + // An unmatched character should have no effect. + helpers.doKeys('d'); + helpers.doKeys('t'); + helpers.doKeys('q'); + eq('The quick box \n', cm.getValue()); + // Matches should only be possible on single lines. + helpers.doKeys('d'); + helpers.doKeys('t'); + helpers.doKeys('z'); + eq('The quick box \n', cm.getValue()); + // After all that, the search for 'q' should still be active, so the 'N' command + // can run it again in reverse. Use that to delete everything back to the 'q'. + helpers.doKeys('d'); + helpers.doKeys('N'); + eq('The ox \n', cm.getValue()); + eq(4, cm.getCursor().ch); +}, { value: moveTillCharacterSandbox}); +testVim('searchForPipe', function(cm, vim, helpers){ + CodeMirror.Vim.setOption('pcre', false); + cm.setCursor(0, 0); + // Search for the '|'. + cm.openDialog = helpers.fakeOpenDialog('|'); + helpers.doKeys('/'); + eq(4, cm.getCursor().ch); +}, { value: 'this|that'}); + + +var scrollMotionSandbox = + '\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n' + '\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n' + '\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n' + '\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n'; +testVim('scrollMotion', function(cm, vim, helpers){ + var prevCursor, prevScrollInfo; + cm.setCursor(0, 0); + // ctrl-y at the top of the file should have no effect. + helpers.doKeys(''); + eq(0, cm.getCursor().line); + prevScrollInfo = cm.getScrollInfo(); + helpers.doKeys(''); + eq(1, cm.getCursor().line); + is(prevScrollInfo.top < cm.getScrollInfo().top); + // Jump to the end of the sandbox. + cm.setCursor(1000, 0); + cm.refresh(); //ace! + prevCursor = cm.getCursor(); + // ctrl-e at the bottom of the file should have no effect. + helpers.doKeys(''); + eq(prevCursor.line, cm.getCursor().line); + cm.refresh(); //ace! + prevScrollInfo = cm.getScrollInfo(); + helpers.doKeys(''); + eq(prevCursor.line - 1, cm.getCursor().line); + is(prevScrollInfo.top > cm.getScrollInfo().top); +}, { value: scrollMotionSandbox}); + +var squareBracketMotionSandbox = ''+ + '({\n'+//0 + ' ({\n'+//11 + ' /*comment {\n'+//2 + ' */(\n'+//3 + '#else \n'+//4 + ' /* )\n'+//5 + '#if }\n'+//6 + ' )}*/\n'+//7 + ')}\n'+//8 + '{}\n'+//9 + '#else {{\n'+//10 + '{}\n'+//11 + '}\n'+//12 + '{\n'+//13 + '#endif\n'+//14 + '}\n'+//15 + '}\n'+//16 + '#else';//17 +testVim('[[, ]]', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys(']', ']'); + helpers.assertCursorAt(9,0); + helpers.doKeys('2', ']', ']'); + helpers.assertCursorAt(13,0); + helpers.doKeys(']', ']'); + helpers.assertCursorAt(17,0); + helpers.doKeys('[', '['); + helpers.assertCursorAt(13,0); + helpers.doKeys('2', '[', '['); + helpers.assertCursorAt(9,0); + helpers.doKeys('[', '['); + helpers.assertCursorAt(0,0); +}, { value: squareBracketMotionSandbox}); +testVim('[], ][', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys(']', '['); + helpers.assertCursorAt(12,0); + helpers.doKeys('2', ']', '['); + helpers.assertCursorAt(16,0); + helpers.doKeys(']', '['); + helpers.assertCursorAt(17,0); + helpers.doKeys('[', ']'); + helpers.assertCursorAt(16,0); + helpers.doKeys('2', '[', ']'); + helpers.assertCursorAt(12,0); + helpers.doKeys('[', ']'); + helpers.assertCursorAt(0,0); +}, { value: squareBracketMotionSandbox}); +testVim('[{, ]}', function(cm, vim, helpers) { + cm.setCursor(4, 10); + helpers.doKeys('[', '{'); + helpers.assertCursorAt(2,12); + helpers.doKeys('2', '[', '{'); + helpers.assertCursorAt(0,1); + cm.setCursor(4, 10); + helpers.doKeys(']', '}'); + helpers.assertCursorAt(6,11); + helpers.doKeys('2', ']', '}'); + helpers.assertCursorAt(8,1); + cm.setCursor(0,1); + helpers.doKeys(']', '}'); + helpers.assertCursorAt(8,1); + helpers.doKeys('[', '{'); + helpers.assertCursorAt(0,1); +}, { value: squareBracketMotionSandbox}); +testVim('[(, ])', function(cm, vim, helpers) { + cm.setCursor(4, 10); + helpers.doKeys('[', '('); + helpers.assertCursorAt(3,14); + helpers.doKeys('2', '[', '('); + helpers.assertCursorAt(0,0); + cm.setCursor(4, 10); + helpers.doKeys(']', ')'); + helpers.assertCursorAt(5,11); + helpers.doKeys('2', ']', ')'); + helpers.assertCursorAt(8,0); + helpers.doKeys('[', '('); + helpers.assertCursorAt(0,0); + helpers.doKeys(']', ')'); + helpers.assertCursorAt(8,0); +}, { value: squareBracketMotionSandbox}); +testVim('[*, ]*, [/, ]/', function(cm, vim, helpers) { + forEach(['*', '/'], function(key){ + cm.setCursor(7, 0); + helpers.doKeys('2', '[', key); + helpers.assertCursorAt(2,2); + helpers.doKeys('2', ']', key); + helpers.assertCursorAt(7,5); + }); +}, { value: squareBracketMotionSandbox}); +testVim('[#, ]#', function(cm, vim, helpers) { + cm.setCursor(10, 3); + helpers.doKeys('2', '[', '#'); + helpers.assertCursorAt(4,0); + helpers.doKeys('5', ']', '#'); + helpers.assertCursorAt(17,0); + cm.setCursor(10, 3); + helpers.doKeys(']', '#'); + helpers.assertCursorAt(14,0); +}, { value: squareBracketMotionSandbox}); +testVim('[m, ]m, [M, ]M', function(cm, vim, helpers) { + cm.setCursor(11, 0); + helpers.doKeys('[', 'm'); + helpers.assertCursorAt(10,7); + helpers.doKeys('4', '[', 'm'); + helpers.assertCursorAt(1,3); + helpers.doKeys('5', ']', 'm'); + helpers.assertCursorAt(11,0); + helpers.doKeys('[', 'M'); + helpers.assertCursorAt(9,1); + helpers.doKeys('3', ']', 'M'); + helpers.assertCursorAt(15,0); + helpers.doKeys('5', '[', 'M'); + helpers.assertCursorAt(7,3); +}, { value: squareBracketMotionSandbox}); + +// Ex mode tests +testVim('ex_go_to_line', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doEx('4'); + helpers.assertCursorAt(3, 0); +}, { value: 'a\nb\nc\nd\ne\n'}); +testVim('ex_write', function(cm, vim, helpers) { + var tmp = CodeMirror.commands.save; + var written; + var actualCm; + CodeMirror.commands.save = function(cm) { + written = true; + actualCm = cm; + }; + // Test that w, wr, wri ... write all trigger :write. + var command = 'write'; + for (var i = 1; i < command.length; i++) { + written = false; + actualCm = null; + helpers.doEx(command.substring(0, i)); + eq(written, true); + eq(actualCm, cm); + } + CodeMirror.commands.save = tmp; +}); +testVim('ex_sort', function(cm, vim, helpers) { + helpers.doEx('sort'); + eq('Z\na\nb\nc\nd', cm.getValue()); +}, { value: 'b\nZ\nd\nc\na'}); +testVim('ex_sort_reverse', function(cm, vim, helpers) { + helpers.doEx('sort!'); + eq('d\nc\nb\na', cm.getValue()); +}, { value: 'b\nd\nc\na'}); +testVim('ex_sort_range', function(cm, vim, helpers) { + helpers.doEx('2,3sort'); + eq('b\nc\nd\na', cm.getValue()); +}, { value: 'b\nd\nc\na'}); +testVim('ex_sort_oneline', function(cm, vim, helpers) { + helpers.doEx('2sort'); + // Expect no change. + eq('b\nd\nc\na', cm.getValue()); +}, { value: 'b\nd\nc\na'}); +testVim('ex_sort_ignoreCase', function(cm, vim, helpers) { + helpers.doEx('sort i'); + eq('a\nb\nc\nd\nZ', cm.getValue()); +}, { value: 'b\nZ\nd\nc\na'}); +testVim('ex_sort_unique', function(cm, vim, helpers) { + helpers.doEx('sort u'); + eq('Z\na\nb\nc\nd', cm.getValue()); +}, { value: 'b\nZ\na\na\nd\na\nc\na'}); +testVim('ex_sort_decimal', function(cm, vim, helpers) { + helpers.doEx('sort d'); + eq('d3\n s5\n6\n.9', cm.getValue()); +}, { value: '6\nd3\n s5\n.9'}); +testVim('ex_sort_decimal_negative', function(cm, vim, helpers) { + helpers.doEx('sort d'); + eq('z-9\nd3\n s5\n6\n.9', cm.getValue()); +}, { value: '6\nd3\n s5\n.9\nz-9'}); +testVim('ex_sort_decimal_reverse', function(cm, vim, helpers) { + helpers.doEx('sort! d'); + eq('.9\n6\n s5\nd3', cm.getValue()); +}, { value: '6\nd3\n s5\n.9'}); +testVim('ex_sort_hex', function(cm, vim, helpers) { + helpers.doEx('sort x'); + eq(' s5\n6\n.9\n&0xB\nd3', cm.getValue()); +}, { value: '6\nd3\n s5\n&0xB\n.9'}); +testVim('ex_sort_octal', function(cm, vim, helpers) { + helpers.doEx('sort o'); + eq('.8\n.9\nd3\n s5\n6', cm.getValue()); +}, { value: '6\nd3\n s5\n.9\n.8'}); +testVim('ex_sort_decimal_mixed', function(cm, vim, helpers) { + helpers.doEx('sort d'); + eq('y\nz\nc1\nb2\na3', cm.getValue()); +}, { value: 'a3\nz\nc1\ny\nb2'}); +testVim('ex_sort_decimal_mixed_reverse', function(cm, vim, helpers) { + helpers.doEx('sort! d'); + eq('a3\nb2\nc1\nz\ny', cm.getValue()); +}, { value: 'a3\nz\nc1\ny\nb2'}); +// test for :global command +testVim('ex_global', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doEx('g/one/s//two'); + eq('two two\n two two\n two two', cm.getValue()); + helpers.doEx('1,2g/two/s//one'); + eq('one one\n one one\n two two', cm.getValue()); +}, {value: 'one one\n one one\n one one'}); +testVim('ex_global_confirm', function(cm, vim, helpers) { + cm.setCursor(0, 0); + var onKeyDown; + var openDialogSave = cm.openDialog; + var KEYCODES = { + a: 65, + n: 78, + q: 81, + y: 89 + }; + // Intercept the ex command, 'global' + cm.openDialog = function(template, callback, options) { + // Intercept the prompt for the embedded ex command, 'substitute' + cm.openDialog = function(template, callback, options) { + onKeyDown = options.onKeyDown; + }; + callback('g/one/s//two/gc'); + }; + helpers.doKeys(':'); + var close = function() {}; + onKeyDown({keyCode: KEYCODES.n}, '', close); + onKeyDown({keyCode: KEYCODES.y}, '', close); + onKeyDown({keyCode: KEYCODES.a}, '', close); + onKeyDown({keyCode: KEYCODES.q}, '', close); + onKeyDown({keyCode: KEYCODES.y}, '', close); + eq('one two\n two two\n one one\n two one\n one one', cm.getValue()); +}, {value: 'one one\n one one\n one one\n one one\n one one'}); +// Basic substitute tests. +testVim('ex_substitute_same_line', function(cm, vim, helpers) { + cm.setCursor(1, 0); + helpers.doEx('s/one/two/g'); + eq('one one\n two two', cm.getValue()); +}, { value: 'one one\n one one'}); +testVim('ex_substitute_full_file', function(cm, vim, helpers) { + cm.setCursor(1, 0); + helpers.doEx('%s/one/two/g'); + eq('two two\n two two', cm.getValue()); +}, { value: 'one one\n one one'}); +testVim('ex_substitute_input_range', function(cm, vim, helpers) { + cm.setCursor(1, 0); + helpers.doEx('1,3s/\\d/0/g'); + eq('0\n0\n0\n4', cm.getValue()); +}, { value: '1\n2\n3\n4' }); +testVim('ex_substitute_visual_range', function(cm, vim, helpers) { + cm.setCursor(1, 0); + // Set last visual mode selection marks '< and '> at lines 2 and 4 + helpers.doKeys('V', '2', 'j', 'v'); + helpers.doEx('\'<,\'>s/\\d/0/g'); + eq('1\n0\n0\n0\n5', cm.getValue()); +}, { value: '1\n2\n3\n4\n5' }); +testVim('ex_substitute_empty_query', function(cm, vim, helpers) { + // If the query is empty, use last query. + cm.setCursor(1, 0); + cm.openDialog = helpers.fakeOpenDialog('1'); + helpers.doKeys('/'); + helpers.doEx('s//b/g'); + eq('abb ab2 ab3', cm.getValue()); +}, { value: 'a11 a12 a13' }); +testVim('ex_substitute_javascript', function(cm, vim, helpers) { + CodeMirror.Vim.setOption('pcre', false); + cm.setCursor(1, 0); + // Throw all the things that javascript likes to treat as special values + // into the replace part. All should be literal (this is VIM). + helpers.doEx('s/\\(\\d+\\)/$$ $\' $` $& \\1/g') + eq('a $$ $\' $` $& 0 b', cm.getValue()); +}, { value: 'a 0 b' }); +testVim('ex_substitute_empty_arguments', function(cm,vim,helpers) { + cm.setCursor(0, 0); + helpers.doEx('s/a/b/g'); + cm.setCursor(1, 0); + helpers.doEx('s'); + eq('b b\nb a', cm.getValue()); +}, {value: 'a a\na a'}); + +// More complex substitute tests that test both pcre and nopcre options. +function testSubstitute(name, options) { + testVim(name + '_pcre', function(cm, vim, helpers) { + cm.setCursor(1, 0); + CodeMirror.Vim.setOption('pcre', true); + helpers.doEx(options.expr); + eq(options.expectedValue, cm.getValue()); + }, options); + // If no noPcreExpr is defined, assume that it's the same as the expr. + var noPcreExpr = options.noPcreExpr ? options.noPcreExpr : options.expr; + testVim(name + '_nopcre', function(cm, vim, helpers) { + cm.setCursor(1, 0); + CodeMirror.Vim.setOption('pcre', false); + helpers.doEx(noPcreExpr); + eq(options.expectedValue, cm.getValue()); + }, options); +} +testSubstitute('ex_substitute_capture', { + value: 'a11 a12 a13', + expectedValue: 'a1111 a1212 a1313', + // $n is a backreference + expr: 's/(\\d+)/$1$1/g', + // \n is a backreference. + noPcreExpr: 's/\\(\\d+\\)/\\1\\1/g'}); +testSubstitute('ex_substitute_capture2', { + value: 'a 0 b', + expectedValue: 'a $00 b', + expr: 's/(\\d+)/$$$1$1/g', + noPcreExpr: 's/\\(\\d+\\)/$\\1\\1/g'}); +testSubstitute('ex_substitute_nocapture', { + value: 'a11 a12 a13', + expectedValue: 'a$1$1 a$1$1 a$1$1', + expr: 's/(\\d+)/$$1$$1/g', + noPcreExpr: 's/\\(\\d+\\)/$1$1/g'}); +testSubstitute('ex_substitute_nocapture2', { + value: 'a 0 b', + expectedValue: 'a $10 b', + expr: 's/(\\d+)/$$1$1/g', + noPcreExpr: 's/\\(\\d+\\)/\\$1\\1/g'}); +testSubstitute('ex_substitute_nocapture', { + value: 'a b c', + expectedValue: 'a $ c', + expr: 's/b/$$/', + noPcreExpr: 's/b/$/'}); +testSubstitute('ex_substitute_slash_regex', { + value: 'one/two \n three/four', + expectedValue: 'one|two \n three|four', + expr: '%s/\\//|'}); +testSubstitute('ex_substitute_pipe_regex', { + value: 'one|two \n three|four', + expectedValue: 'one,two \n three,four', + expr: '%s/\\|/,/', + noPcreExpr: '%s/|/,/'}); +testSubstitute('ex_substitute_or_regex', { + value: 'one|two \n three|four', + expectedValue: 'ana|twa \n thraa|faar', + expr: '%s/o|e|u/a/g', + noPcreExpr: '%s/o\\|e\\|u/a/g'}); +testSubstitute('ex_substitute_or_word_regex', { + value: 'one|two \n three|four', + expectedValue: 'five|five \n three|four', + expr: '%s/(one|two)/five/g', + noPcreExpr: '%s/\\(one\\|two\\)/five/g'}); +testSubstitute('ex_substitute_backslashslash_regex', { + value: 'one\\two \n three\\four', + expectedValue: 'one,two \n three,four', + expr: '%s/\\\\/,'}); +testSubstitute('ex_substitute_slash_replacement', { + value: 'one,two \n three,four', + expectedValue: 'one/two \n three/four', + expr: '%s/,/\\/'}); +testSubstitute('ex_substitute_backslash_replacement', { + value: 'one,two \n three,four', + expectedValue: 'one\\two \n three\\four', + expr: '%s/,/\\\\/g'}); +testSubstitute('ex_substitute_multibackslash_replacement', { + value: 'one,two \n three,four', + expectedValue: 'one\\\\\\\\two \n three\\\\\\\\four', // 2*8 backslashes. + expr: '%s/,/\\\\\\\\\\\\\\\\/g'}); // 16 backslashes. +testSubstitute('ex_substitute_braces_word', { + value: 'ababab abb ab{2}', + expectedValue: 'ab abb ab{2}', + expr: '%s/(ab){2}//g', + noPcreExpr: '%s/\\(ab\\)\\{2\\}//g'}); +testSubstitute('ex_substitute_braces_range', { + value: 'a aa aaa aaaa', + expectedValue: 'a a', + expr: '%s/a{2,3}//g', + noPcreExpr: '%s/a\\{2,3\\}//g'}); +testSubstitute('ex_substitute_braces_literal', { + value: 'ababab abb ab{2}', + expectedValue: 'ababab abb ', + expr: '%s/ab\\{2\\}//g', + noPcreExpr: '%s/ab{2}//g'}); +testSubstitute('ex_substitute_braces_char', { + value: 'ababab abb ab{2}', + expectedValue: 'ababab ab{2}', + expr: '%s/ab{2}//g', + noPcreExpr: '%s/ab\\{2\\}//g'}); +testSubstitute('ex_substitute_braces_no_escape', { + value: 'ababab abb ab{2}', + expectedValue: 'ababab ab{2}', + expr: '%s/ab{2}//g', + noPcreExpr: '%s/ab\\{2}//g'}); +testSubstitute('ex_substitute_count', { + value: '1\n2\n3\n4', + expectedValue: '1\n0\n0\n4', + expr: 's/\\d/0/i 2'}); +testSubstitute('ex_substitute_count_with_range', { + value: '1\n2\n3\n4', + expectedValue: '1\n2\n0\n0', + expr: '1,3s/\\d/0/ 3'}); +testSubstitute('ex_substitute_not_global', { + value: 'aaa\nbaa\ncaa', + expectedValue: 'xaa\nbxa\ncxa', + expr: '%s/a/x/'}); +function testSubstituteConfirm(name, command, initialValue, expectedValue, keys, finalPos) { + testVim(name, function(cm, vim, helpers) { + var savedOpenDialog = cm.openDialog; + var savedKeyName = CodeMirror.keyName; + var onKeyDown; + var recordedCallback; + var closed = true; // Start out closed, set false on second openDialog. + function close() { + closed = true; + } + // First openDialog should save callback. + cm.openDialog = function(template, callback, options) { + recordedCallback = callback; + } + // Do first openDialog. + helpers.doKeys(':'); + // Second openDialog should save keyDown handler. + cm.openDialog = function(template, callback, options) { + onKeyDown = options.onKeyDown; + closed = false; + }; + // Return the command to Vim and trigger second openDialog. + recordedCallback(command); + // The event should really use keyCode, but here just mock it out and use + // key and replace keyName to just return key. + CodeMirror.keyName = function (e) { return e.key; } + keys = keys.toUpperCase(); + for (var i = 0; i < keys.length; i++) { + is(!closed); + onKeyDown({ key: keys.charAt(i) }, '', close); + } + try { + eq(expectedValue, cm.getValue()); + helpers.assertCursorAt(finalPos); + is(closed); + } catch(e) { + throw e + } finally { + // Restore overriden functions. + CodeMirror.keyName = savedKeyName; + cm.openDialog = savedOpenDialog; + } + }, { value: initialValue }); +}; +testSubstituteConfirm('ex_substitute_confirm_emptydoc', + '%s/x/b/c', '', '', '', makeCursor(0, 0)); +testSubstituteConfirm('ex_substitute_confirm_nomatch', + '%s/x/b/c', 'ba a\nbab', 'ba a\nbab', '', makeCursor(0, 0)); +testSubstituteConfirm('ex_substitute_confirm_accept', + '%s/a/b/cg', 'ba a\nbab', 'bb b\nbbb', 'yyy', makeCursor(1, 1)); +testSubstituteConfirm('ex_substitute_confirm_random_keys', + '%s/a/b/cg', 'ba a\nbab', 'bb b\nbbb', 'ysdkywerty', makeCursor(1, 1)); +testSubstituteConfirm('ex_substitute_confirm_some', + '%s/a/b/cg', 'ba a\nbab', 'bb a\nbbb', 'yny', makeCursor(1, 1)); +testSubstituteConfirm('ex_substitute_confirm_all', + '%s/a/b/cg', 'ba a\nbab', 'bb b\nbbb', 'a', makeCursor(1, 1)); +testSubstituteConfirm('ex_substitute_confirm_accept_then_all', + '%s/a/b/cg', 'ba a\nbab', 'bb b\nbbb', 'ya', makeCursor(1, 1)); +testSubstituteConfirm('ex_substitute_confirm_quit', + '%s/a/b/cg', 'ba a\nbab', 'bb a\nbab', 'yq', makeCursor(0, 3)); +testSubstituteConfirm('ex_substitute_confirm_last', + '%s/a/b/cg', 'ba a\nbab', 'bb b\nbab', 'yl', makeCursor(0, 3)); +testSubstituteConfirm('ex_substitute_confirm_oneline', + '1s/a/b/cg', 'ba a\nbab', 'bb b\nbab', 'yl', makeCursor(0, 3)); +testSubstituteConfirm('ex_substitute_confirm_range_accept', + '1,2s/a/b/cg', 'aa\na \na\na', 'bb\nb \na\na', 'yyy', makeCursor(1, 0)); +testSubstituteConfirm('ex_substitute_confirm_range_some', + '1,3s/a/b/cg', 'aa\na \na\na', 'ba\nb \nb\na', 'ynyy', makeCursor(2, 0)); +testSubstituteConfirm('ex_substitute_confirm_range_all', + '1,3s/a/b/cg', 'aa\na \na\na', 'bb\nb \nb\na', 'a', makeCursor(2, 0)); +testSubstituteConfirm('ex_substitute_confirm_range_last', + '1,3s/a/b/cg', 'aa\na \na\na', 'bb\nb \na\na', 'yyl', makeCursor(1, 0)); +//:noh should clear highlighting of search-results but allow to resume search through n +testVim('ex_noh_clearSearchHighlight', function(cm, vim, helpers) { + cm.openDialog = helpers.fakeOpenDialog('match'); + helpers.doKeys('?'); + helpers.doEx('noh'); + eq(vim.searchState_.getOverlay(),null,'match-highlighting wasn\'t cleared'); + helpers.doKeys('n'); + helpers.assertCursorAt(0, 11,'can\'t resume search after clearing highlighting'); +}, { value: 'match nope match \n nope Match' }); +testVim('set_boolean', function(cm, vim, helpers) { + CodeMirror.Vim.defineOption('testoption', true, 'boolean'); + // Test default value is set. + is(CodeMirror.Vim.getOption('testoption')); + try { + // Test fail to set to non-boolean + CodeMirror.Vim.setOption('testoption', '5'); + fail(); + } catch (expected) {}; + // Test setOption + CodeMirror.Vim.setOption('testoption', false); + is(!CodeMirror.Vim.getOption('testoption')); +}); +testVim('ex_set_boolean', function(cm, vim, helpers) { + CodeMirror.Vim.defineOption('testoption', true, 'boolean'); + // Test default value is set. + is(CodeMirror.Vim.getOption('testoption')); + try { + // Test fail to set to non-boolean + helpers.doEx('set testoption=22'); + fail(); + } catch (expected) {}; + // Test setOption + helpers.doEx('set notestoption'); + is(!CodeMirror.Vim.getOption('testoption')); +}); +testVim('set_string', function(cm, vim, helpers) { + CodeMirror.Vim.defineOption('testoption', 'a', 'string'); + // Test default value is set. + eq('a', CodeMirror.Vim.getOption('testoption')); + try { + // Test fail to set non-string. + CodeMirror.Vim.setOption('testoption', true); + fail(); + } catch (expected) {}; + try { + // Test fail to set 'notestoption' + CodeMirror.Vim.setOption('notestoption', 'b'); + fail(); + } catch (expected) {}; + // Test setOption + CodeMirror.Vim.setOption('testoption', 'c'); + eq('c', CodeMirror.Vim.getOption('testoption')); +}); +testVim('ex_set_string', function(cm, vim, helpers) { + CodeMirror.Vim.defineOption('testoption', 'a', 'string'); + // Test default value is set. + eq('a', CodeMirror.Vim.getOption('testoption')); + try { + // Test fail to set 'notestoption' + helpers.doEx('set notestoption=b'); + fail(); + } catch (expected) {}; + // Test setOption + helpers.doEx('set testoption=c') + eq('c', CodeMirror.Vim.getOption('testoption')); +}); +// TODO: Reset key maps after each test. +testVim('ex_map_key2key', function(cm, vim, helpers) { + helpers.doEx('map a x'); + helpers.doKeys('a'); + helpers.assertCursorAt(0, 0); + eq('bc', cm.getValue()); +}, { value: 'abc' }); +testVim('ex_unmap_key2key', function(cm, vim, helpers) { + helpers.doEx('unmap a'); + helpers.doKeys('a'); + eq('vim-insert', cm.getOption('keyMap')); +}, { value: 'abc' }); +testVim('ex_unmap_key2key_does_not_remove_default', function(cm, vim, helpers) { + try { + helpers.doEx('unmap a'); + fail(); + } catch (expected) {} + helpers.doKeys('a'); + eq('vim-insert', cm.getOption('keyMap')); +}, { value: 'abc' }); +testVim('ex_map_key2key_to_colon', function(cm, vim, helpers) { + helpers.doEx('map ; :'); + var dialogOpened = false; + cm.openDialog = function() { + dialogOpened = true; + } + helpers.doKeys(';'); + eq(dialogOpened, true); +}); +testVim('ex_map_ex2key:', function(cm, vim, helpers) { + helpers.doEx('map :del x'); + helpers.doEx('del'); + helpers.assertCursorAt(0, 0); + eq('bc', cm.getValue()); +}, { value: 'abc' }); +testVim('ex_map_ex2ex', function(cm, vim, helpers) { + helpers.doEx('map :del :w'); + var tmp = CodeMirror.commands.save; + var written = false; + var actualCm; + CodeMirror.commands.save = function(cm) { + written = true; + actualCm = cm; + }; + helpers.doEx('del'); + CodeMirror.commands.save = tmp; + eq(written, true); + eq(actualCm, cm); +}); +testVim('ex_map_key2ex', function(cm, vim, helpers) { + helpers.doEx('map a :w'); + var tmp = CodeMirror.commands.save; + var written = false; + var actualCm; + CodeMirror.commands.save = function(cm) { + written = true; + actualCm = cm; + }; + helpers.doKeys('a'); + CodeMirror.commands.save = tmp; + eq(written, true); + eq(actualCm, cm); +}); +testVim('ex_map_key2key_visual_api', function(cm, vim, helpers) { + CodeMirror.Vim.map('b', ':w', 'visual'); + var tmp = CodeMirror.commands.save; + var written = false; + var actualCm; + CodeMirror.commands.save = function(cm) { + written = true; + actualCm = cm; + }; + // Mapping should not work in normal mode. + helpers.doKeys('b'); + eq(written, false); + // Mapping should work in visual mode. + helpers.doKeys('v', 'b'); + eq(written, true); + eq(actualCm, cm); + + CodeMirror.commands.save = tmp; +}); +testVim('ex_imap', function(cm, vim, helpers) { + CodeMirror.Vim.map('jk', '', 'insert'); + helpers.doKeys('i'); + is(vim.insertMode); + helpers.doKeys('j', 'k'); + is(!vim.insertMode); +}) + +// Testing registration of functions as ex-commands and mapping to -keys +testVim('ex_api_test', function(cm, vim, helpers) { + var res=false; + var val='from'; + CodeMirror.Vim.defineEx('extest','ext',function(cm,params){ + if(params.args)val=params.args[0]; + else res=true; + }); + helpers.doEx(':ext to'); + eq(val,'to','Defining ex-command failed'); + CodeMirror.Vim.map('',':ext'); + helpers.doKeys('',''); + is(res,'Mapping to key failed'); +}); +// For now, this test needs to be last because it messes up : for future tests. +testVim('ex_map_key2key_from_colon', function(cm, vim, helpers) { + helpers.doEx('map : x'); + helpers.doKeys(':'); + helpers.assertCursorAt(0, 0); + eq('bc', cm.getValue()); +}, { value: 'abc' }); + +// Test event handlers +testVim('beforeSelectionChange', function(cm, vim, helpers) { + cm.setCursor(0, 100); + eqPos(cm.getCursor('head'), cm.getCursor('anchor')); +}, { value: 'abc' }); + + +}); + + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec(); +} diff --git a/node_modules/ace/lib/ace/layer/cursor.js b/node_modules/ace/lib/ace/layer/cursor.js new file mode 100644 index 00000000..682632e1 --- /dev/null +++ b/node_modules/ace/lib/ace/layer/cursor.js @@ -0,0 +1,240 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var dom = require("../lib/dom"); +var isIE8; + +var Cursor = function(parentEl) { + this.element = dom.createElement("div"); + this.element.className = "ace_layer ace_cursor-layer"; + parentEl.appendChild(this.element); + + if (isIE8 === undefined) + isIE8 = !("opacity" in this.element.style); + + this.isVisible = false; + this.isBlinking = true; + this.blinkInterval = 1000; + this.smoothBlinking = false; + + this.cursors = []; + this.cursor = this.addCursor(); + dom.addCssClass(this.element, "ace_hidden-cursors"); + this.$updateCursors = (isIE8 + ? this.$updateVisibility + : this.$updateOpacity).bind(this); +}; + +(function() { + + this.$updateVisibility = function(val) { + var cursors = this.cursors; + for (var i = cursors.length; i--; ) + cursors[i].style.visibility = val ? "" : "hidden"; + }; + this.$updateOpacity = function(val) { + var cursors = this.cursors; + for (var i = cursors.length; i--; ) + cursors[i].style.opacity = val ? "" : "0"; + }; + + + this.$padding = 0; + this.setPadding = function(padding) { + this.$padding = padding; + }; + + this.setSession = function(session) { + this.session = session; + }; + + this.setBlinking = function(blinking) { + if (blinking != this.isBlinking){ + this.isBlinking = blinking; + this.restartTimer(); + } + }; + + this.setBlinkInterval = function(blinkInterval) { + if (blinkInterval != this.blinkInterval){ + this.blinkInterval = blinkInterval; + this.restartTimer(); + } + }; + + this.setSmoothBlinking = function(smoothBlinking) { + if (smoothBlinking != this.smoothBlinking && !isIE8) { + this.smoothBlinking = smoothBlinking; + dom.setCssClass(this.element, "ace_smooth-blinking", smoothBlinking); + this.$updateCursors(true); + this.$updateCursors = (this.$updateOpacity).bind(this); + this.restartTimer(); + } + }; + + this.addCursor = function() { + var el = dom.createElement("div"); + el.className = "ace_cursor"; + this.element.appendChild(el); + this.cursors.push(el); + return el; + }; + + this.removeCursor = function() { + if (this.cursors.length > 1) { + var el = this.cursors.pop(); + el.parentNode.removeChild(el); + return el; + } + }; + + this.hideCursor = function() { + this.isVisible = false; + dom.addCssClass(this.element, "ace_hidden-cursors"); + this.restartTimer(); + }; + + this.showCursor = function() { + this.isVisible = true; + dom.removeCssClass(this.element, "ace_hidden-cursors"); + this.restartTimer(); + }; + + this.restartTimer = function() { + var update = this.$updateCursors; + clearInterval(this.intervalId); + clearTimeout(this.timeoutId); + if (this.smoothBlinking) { + dom.removeCssClass(this.element, "ace_smooth-blinking"); + } + + update(true); + + if (!this.isBlinking || !this.blinkInterval || !this.isVisible) + return; + + if (this.smoothBlinking) { + setTimeout(function(){ + dom.addCssClass(this.element, "ace_smooth-blinking"); + }.bind(this)); + } + + var blink = function(){ + this.timeoutId = setTimeout(function() { + update(false); + }, 0.6 * this.blinkInterval); + }.bind(this); + + this.intervalId = setInterval(function() { + update(true); + blink(); + }, this.blinkInterval); + + blink(); + }; + + this.getPixelPosition = function(position, onScreen) { + if (!this.config || !this.session) + return {left : 0, top : 0}; + + if (!position) + position = this.session.selection.getCursor(); + var pos = this.session.documentToScreenPosition(position); + var cursorLeft = this.$padding + pos.column * this.config.characterWidth; + var cursorTop = (pos.row - (onScreen ? this.config.firstRowScreen : 0)) * + this.config.lineHeight; + + return {left : cursorLeft, top : cursorTop}; + }; + + this.update = function(config) { + this.config = config; + + var selections = this.session.$selectionMarkers; + var i = 0, cursorIndex = 0; + + if (selections === undefined || selections.length === 0){ + selections = [{cursor: null}]; + } + + for (var i = 0, n = selections.length; i < n; i++) { + var pixelPos = this.getPixelPosition(selections[i].cursor, true); + if ((pixelPos.top > config.height + config.offset || + pixelPos.top < 0) && i > 1) { + continue; + } + + var style = (this.cursors[cursorIndex++] || this.addCursor()).style; + + if (!this.drawCursor) { + style.left = pixelPos.left + "px"; + style.top = pixelPos.top + "px"; + style.width = config.characterWidth + "px"; + style.height = config.lineHeight + "px"; + } else { + this.drawCursor(style, pixelPos, config, selections[i], this.session); + } + } + while (this.cursors.length > cursorIndex) + this.removeCursor(); + + var overwrite = this.session.getOverwrite(); + this.$setOverwrite(overwrite); + + // cache for textarea and gutter highlight + this.$pixelPos = pixelPos; + this.restartTimer(); + }; + + this.drawCursor = null; + + this.$setOverwrite = function(overwrite) { + if (overwrite != this.overwrite) { + this.overwrite = overwrite; + if (overwrite) + dom.addCssClass(this.element, "ace_overwrite-cursors"); + else + dom.removeCssClass(this.element, "ace_overwrite-cursors"); + } + }; + + this.destroy = function() { + clearInterval(this.intervalId); + clearTimeout(this.timeoutId); + }; + +}).call(Cursor.prototype); + +exports.Cursor = Cursor; + +}); diff --git a/node_modules/ace/lib/ace/layer/font_metrics.js b/node_modules/ace/lib/ace/layer/font_metrics.js new file mode 100644 index 00000000..18521489 --- /dev/null +++ b/node_modules/ace/lib/ace/layer/font_metrics.js @@ -0,0 +1,188 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + +var oop = require("../lib/oop"); +var dom = require("../lib/dom"); +var lang = require("../lib/lang"); +var useragent = require("../lib/useragent"); +var EventEmitter = require("../lib/event_emitter").EventEmitter; + +var CHAR_COUNT = 0; + +var ANIMATING = false; + +// transitionend is fired by webkit, but start isn't. The solution is to +// dispatch the start event yourself: +// var ev = new Event({}); +// ev.initEvent("transitionstart", false, false); +// document.dispatchEvent(ev); +document.addEventListener("transitionstart", function(){ ANIMATING = true; }); +document.addEventListener("transitionend", function(){ ANIMATING = false; }); + +var FontMetrics = exports.FontMetrics = function(parentEl, interval) { + this.el = dom.createElement("div"); + this.$setMeasureNodeStyles(this.el.style, true); + + this.$main = dom.createElement("div"); + this.$setMeasureNodeStyles(this.$main.style); + + this.$measureNode = dom.createElement("div"); + this.$setMeasureNodeStyles(this.$measureNode.style); + + + this.el.appendChild(this.$main); + this.el.appendChild(this.$measureNode); + parentEl.appendChild(this.el); + + if (!CHAR_COUNT) + this.$testFractionalRect(); + this.$measureNode.innerHTML = lang.stringRepeat("X", CHAR_COUNT); + + this.$characterSize = {width: 0, height: 0}; + this.checkForSizeChanges(); +}; + +(function() { + + oop.implement(this, EventEmitter); + + this.$characterSize = {width: 0, height: 0}; + + this.$testFractionalRect = function() { + var el = dom.createElement("div"); + this.$setMeasureNodeStyles(el.style); + el.style.width = "0.2px"; + document.documentElement.appendChild(el); + var w = el.getBoundingClientRect().width; + if (w > 0 && w < 1) + CHAR_COUNT = 50; + else + CHAR_COUNT = 100; + el.parentNode.removeChild(el); + }; + + this.$setMeasureNodeStyles = function(style, isRoot) { + style.width = style.height = "auto"; + style.left = style.top = "0px"; + style.visibility = "hidden"; + style.position = "absolute"; + style.whiteSpace = "pre"; + + if (useragent.isIE < 8) { + style["font-family"] = "inherit"; + } else { + style.font = "inherit"; + } + style.overflow = isRoot ? "hidden" : "visible"; + }; + + this.checkForSizeChanges = function() { + if (ANIMATING) + return; + var size = this.$measureSizes(); + if (size && (this.$characterSize.width !== size.width || this.$characterSize.height !== size.height)) { + this.$measureNode.style.fontWeight = "bold"; + var boldSize = this.$measureSizes(); + this.$measureNode.style.fontWeight = ""; + this.$characterSize = size; + this.charSizes = Object.create(null); + this.allowBoldFonts = boldSize && boldSize.width === size.width && boldSize.height === size.height; + this._emit("changeCharacterSize", {data: size}); + } + }; + + this.$pollSizeChanges = function() { + if (this.$pollSizeChangesTimer) + return this.$pollSizeChangesTimer; + var self = this; + return this.$pollSizeChangesTimer = setInterval(function() { + self.checkForSizeChanges(); + }, 500); + }; + + this.setPolling = function(val) { + if (val) { + this.$pollSizeChanges(); + } else { + if (this.$pollSizeChangesTimer) + this.$pollSizeChangesTimer; + } + }; + + this.$measureSizes = function() { + if (CHAR_COUNT === 50) { + var rect = null; + try { + rect = this.$measureNode.getBoundingClientRect(); + } catch(e) { + rect = {width: 0, height:0 }; + }; + var size = { + height: rect.height, + width: rect.width / CHAR_COUNT + }; + } else { + var size = { + height: this.$measureNode.clientHeight, + width: this.$measureNode.clientWidth / CHAR_COUNT + }; + } + // Size and width can be null if the editor is not visible or + // detached from the document + if (size.width === 0 || size.height === 0) + return null; + return size; + }; + + this.$measureCharWidth = function(ch) { + this.$main.innerHTML = lang.stringRepeat(ch, CHAR_COUNT); + var rect = this.$main.getBoundingClientRect(); + return rect.width / CHAR_COUNT; + }; + + this.getCharacterWidth = function(ch) { + var w = this.charSizes[ch]; + if (w === undefined) { + this.charSizes[ch] = this.$measureCharWidth(ch) / this.$characterSize.width; + } + return w; + }; + + this.destroy = function() { + clearInterval(this.$pollSizeChangesTimer); + if (this.el && this.el.parentNode) + this.el.parentNode.removeChild(this.el); + }; + +}).call(FontMetrics.prototype); + +}); diff --git a/node_modules/ace/lib/ace/layer/gutter.js b/node_modules/ace/lib/ace/layer/gutter.js new file mode 100644 index 00000000..dc1055c2 --- /dev/null +++ b/node_modules/ace/lib/ace/layer/gutter.js @@ -0,0 +1,285 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var dom = require("../lib/dom"); +var oop = require("../lib/oop"); +var lang = require("../lib/lang"); +var EventEmitter = require("../lib/event_emitter").EventEmitter; + +var Gutter = function(parentEl) { + this.element = dom.createElement("div"); + this.element.className = "ace_layer ace_gutter-layer"; + parentEl.appendChild(this.element); + this.setShowFoldWidgets(this.$showFoldWidgets); + + this.gutterWidth = 0; + + this.$annotations = []; + this.$updateAnnotations = this.$updateAnnotations.bind(this); + + this.$cells = []; +}; + +(function() { + + oop.implement(this, EventEmitter); + + this.setSession = function(session) { + if (this.session) + this.session.removeEventListener("change", this.$updateAnnotations); + this.session = session; + if (session) + session.on("change", this.$updateAnnotations); + }; + + this.addGutterDecoration = function(row, className){ + if (window.console) + console.warn && console.warn("deprecated use session.addGutterDecoration"); + this.session.addGutterDecoration(row, className); + }; + + this.removeGutterDecoration = function(row, className){ + if (window.console) + console.warn && console.warn("deprecated use session.removeGutterDecoration"); + this.session.removeGutterDecoration(row, className); + }; + + this.setAnnotations = function(annotations) { + // iterate over sparse array + this.$annotations = []; + for (var i = 0; i < annotations.length; i++) { + var annotation = annotations[i]; + var row = annotation.row; + var rowInfo = this.$annotations[row]; + if (!rowInfo) + rowInfo = this.$annotations[row] = {text: []}; + + var annoText = annotation.text; + annoText = annoText ? lang.escapeHTML(annoText) : annotation.html || ""; + + if (rowInfo.text.indexOf(annoText) === -1) + rowInfo.text.push(annoText); + + var type = annotation.type; + if (type == "error") + rowInfo.className = " ace_error"; + else if (type == "warning" && rowInfo.className != " ace_error") + rowInfo.className = " ace_warning"; + else if (type == "info" && (!rowInfo.className)) + rowInfo.className = " ace_info"; + } + }; + + this.$updateAnnotations = function (delta) { + if (!this.$annotations.length) + return; + var firstRow = delta.start.row; + var len = delta.end.row - firstRow; + if (len === 0) { + // do nothing + } else if (delta.action == 'remove') { + this.$annotations.splice(firstRow, len + 1, null); + } else { + var args = new Array(len + 1); + args.unshift(firstRow, 1); + this.$annotations.splice.apply(this.$annotations, args); + } + }; + + this.update = function(config) { + var session = this.session; + var firstRow = config.firstRow; + var lastRow = Math.min(config.lastRow + config.gutterOffset, // needed to compensate for hor scollbar + session.getLength() - 1); + var fold = session.getNextFoldLine(firstRow); + var foldStart = fold ? fold.start.row : Infinity; + var foldWidgets = this.$showFoldWidgets && session.foldWidgets; + var breakpoints = session.$breakpoints; + var decorations = session.$decorations; + var firstLineNumber = session.$firstLineNumber; + var lastLineNumber = 0; + + var gutterRenderer = session.gutterRenderer || this.$renderer; + + var cell = null; + var index = -1; + var row = firstRow; + while (true) { + if (row > foldStart) { + row = fold.end.row + 1; + fold = session.getNextFoldLine(row, fold); + foldStart = fold ? fold.start.row : Infinity; + } + if (row > lastRow) { + while (this.$cells.length > index + 1) { + cell = this.$cells.pop(); + this.element.removeChild(cell.element); + } + break; + } + + cell = this.$cells[++index]; + if (!cell) { + cell = {element: null, textNode: null, foldWidget: null}; + cell.element = dom.createElement("div"); + cell.textNode = document.createTextNode(''); + cell.element.appendChild(cell.textNode); + this.element.appendChild(cell.element); + this.$cells[index] = cell; + } + + var className = "ace_gutter-cell "; + if (breakpoints[row]) + className += breakpoints[row]; + if (decorations[row]) + className += decorations[row]; + if (this.$annotations[row]) + className += this.$annotations[row].className; + if (cell.element.className != className) + cell.element.className = className; + + var height = session.getRowLength(row) * config.lineHeight + "px"; + if (height != cell.element.style.height) + cell.element.style.height = height; + + if (foldWidgets) { + var c = foldWidgets[row]; + // check if cached value is invalidated and we need to recompute + if (c == null) + c = foldWidgets[row] = session.getFoldWidget(row); + } + + if (c) { + if (!cell.foldWidget) { + cell.foldWidget = dom.createElement("span"); + cell.element.appendChild(cell.foldWidget); + } + var className = "ace_fold-widget ace_" + c; + if (c == "start" && row == foldStart && row < fold.end.row) + className += " ace_closed"; + else + className += " ace_open"; + if (cell.foldWidget.className != className) + cell.foldWidget.className = className; + + var height = config.lineHeight + "px"; + if (cell.foldWidget.style.height != height) + cell.foldWidget.style.height = height; + } else { + if (cell.foldWidget) { + cell.element.removeChild(cell.foldWidget); + cell.foldWidget = null; + } + } + + var text = lastLineNumber = gutterRenderer + ? gutterRenderer.getText(session, row) + : row + firstLineNumber; + if (text != cell.textNode.data) + cell.textNode.data = text; + + row++; + } + + this.element.style.height = config.minHeight + "px"; + + if (this.$fixedWidth || session.$useWrapMode) + lastLineNumber = session.getLength() + firstLineNumber; + + var gutterWidth = gutterRenderer + ? gutterRenderer.getWidth(session, lastLineNumber, config) + : lastLineNumber.toString().length * config.characterWidth; + + var padding = this.$padding || this.$computePadding(); + gutterWidth += padding.left + padding.right; + if (gutterWidth !== this.gutterWidth && !isNaN(gutterWidth)) { + this.gutterWidth = gutterWidth; + this.element.style.width = Math.ceil(this.gutterWidth) + "px"; + this._emit("changeGutterWidth", gutterWidth); + } + }; + + this.$fixedWidth = false; + + this.$showLineNumbers = true; + this.$renderer = ""; + this.setShowLineNumbers = function(show) { + this.$renderer = !show && { + getWidth: function() {return ""}, + getText: function() {return ""} + }; + }; + + this.getShowLineNumbers = function() { + return this.$showLineNumbers; + }; + + this.$showFoldWidgets = true; + this.setShowFoldWidgets = function(show) { + if (show) + dom.addCssClass(this.element, "ace_folding-enabled"); + else + dom.removeCssClass(this.element, "ace_folding-enabled"); + + this.$showFoldWidgets = show; + this.$padding = null; + }; + + this.getShowFoldWidgets = function() { + return this.$showFoldWidgets; + }; + + this.$computePadding = function() { + if (!this.element.firstChild) + return {left: 0, right: 0}; + var style = dom.computedStyle(this.element.firstChild); + this.$padding = {}; + this.$padding.left = parseInt(style.paddingLeft) + 1 || 0; + this.$padding.right = parseInt(style.paddingRight) || 0; + return this.$padding; + }; + + this.getRegion = function(point) { + var padding = this.$padding || this.$computePadding(); + var rect = this.element.getBoundingClientRect(); + if (point.x < padding.left + rect.left) + return "markers"; + if (this.$showFoldWidgets && point.x > rect.right - padding.right) + return "foldWidgets"; + }; + +}).call(Gutter.prototype); + +exports.Gutter = Gutter; + +}); diff --git a/node_modules/ace/lib/ace/layer/marker.js b/node_modules/ace/lib/ace/layer/marker.js new file mode 100644 index 00000000..37e038b5 --- /dev/null +++ b/node_modules/ace/lib/ace/layer/marker.js @@ -0,0 +1,218 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var Range = require("../range").Range; +var dom = require("../lib/dom"); + +var Marker = function(parentEl) { + this.element = dom.createElement("div"); + this.element.className = "ace_layer ace_marker-layer"; + parentEl.appendChild(this.element); +}; + +(function() { + + this.$padding = 0; + + this.setPadding = function(padding) { + this.$padding = padding; + }; + this.setSession = function(session) { + this.session = session; + }; + + this.setMarkers = function(markers) { + this.markers = markers; + }; + + this.update = function(config) { + var config = config || this.config; + if (!config) + return; + + this.config = config; + + + var html = []; + for (var key in this.markers) { + var marker = this.markers[key]; + + if (!marker.range) { + marker.update(html, this, this.session, config); + continue; + } + + var range = marker.range.clipRows(config.firstRow, config.lastRow); + if (range.isEmpty()) continue; + + range = range.toScreenRange(this.session); + if (marker.renderer) { + var top = this.$getTop(range.start.row, config); + var left = this.$padding + range.start.column * config.characterWidth; + marker.renderer(html, range, left, top, config); + } else if (marker.type == "fullLine") { + this.drawFullLineMarker(html, range, marker.clazz, config); + } else if (marker.type == "screenLine") { + this.drawScreenLineMarker(html, range, marker.clazz, config); + } else if (range.isMultiLine()) { + if (marker.type == "text") + this.drawTextMarker(html, range, marker.clazz, config); + else + this.drawMultiLineMarker(html, range, marker.clazz, config); + } else { + this.drawSingleLineMarker(html, range, marker.clazz + " ace_start", config); + } + } + this.element.innerHTML = html.join(""); + }; + + this.$getTop = function(row, layerConfig) { + return (row - layerConfig.firstRowScreen) * layerConfig.lineHeight; + }; + + // Draws a marker, which spans a range of text on multiple lines + this.drawTextMarker = function(stringBuilder, range, clazz, layerConfig, extraStyle) { + // selection start + var row = range.start.row; + + var lineRange = new Range( + row, range.start.column, + row, this.session.getScreenLastRowColumn(row) + ); + this.drawSingleLineMarker(stringBuilder, lineRange, clazz + " ace_start", layerConfig, 1, extraStyle); + + // selection end + row = range.end.row; + lineRange = new Range(row, 0, row, range.end.column); + this.drawSingleLineMarker(stringBuilder, lineRange, clazz, layerConfig, 0, extraStyle); + + for (row = range.start.row + 1; row < range.end.row; row++) { + lineRange.start.row = row; + lineRange.end.row = row; + lineRange.end.column = this.session.getScreenLastRowColumn(row); + this.drawSingleLineMarker(stringBuilder, lineRange, clazz, layerConfig, 1, extraStyle); + } + }; + + // Draws a multi line marker, where lines span the full width + this.drawMultiLineMarker = function(stringBuilder, range, clazz, config, extraStyle) { + // from selection start to the end of the line + var padding = this.$padding; + var height = config.lineHeight; + var top = this.$getTop(range.start.row, config); + var left = padding + range.start.column * config.characterWidth; + extraStyle = extraStyle || ""; + + stringBuilder.push( + "
      " + ); + + // from start of the last line to the selection end + top = this.$getTop(range.end.row, config); + var width = range.end.column * config.characterWidth; + + stringBuilder.push( + "
      " + ); + + // all the complete lines + height = (range.end.row - range.start.row - 1) * config.lineHeight; + if (height < 0) + return; + top = this.$getTop(range.start.row + 1, config); + + stringBuilder.push( + "
      " + ); + }; + + // Draws a marker which covers part or whole width of a single screen line + this.drawSingleLineMarker = function(stringBuilder, range, clazz, config, extraLength, extraStyle) { + var height = config.lineHeight; + var width = (range.end.column + (extraLength || 0) - range.start.column) * config.characterWidth; + + var top = this.$getTop(range.start.row, config); + var left = this.$padding + range.start.column * config.characterWidth; + + stringBuilder.push( + "
      " + ); + }; + + this.drawFullLineMarker = function(stringBuilder, range, clazz, config, extraStyle) { + var top = this.$getTop(range.start.row, config); + var height = config.lineHeight; + if (range.start.row != range.end.row) + height += this.$getTop(range.end.row, config) - top; + + stringBuilder.push( + "
      " + ); + }; + + this.drawScreenLineMarker = function(stringBuilder, range, clazz, config, extraStyle) { + var top = this.$getTop(range.start.row, config); + var height = config.lineHeight; + + stringBuilder.push( + "
      " + ); + }; + +}).call(Marker.prototype); + +exports.Marker = Marker; + +}); diff --git a/node_modules/ace/lib/ace/layer/text.js b/node_modules/ace/lib/ace/layer/text.js new file mode 100644 index 00000000..06277ae1 --- /dev/null +++ b/node_modules/ace/lib/ace/layer/text.js @@ -0,0 +1,575 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var dom = require("../lib/dom"); +var lang = require("../lib/lang"); +var useragent = require("../lib/useragent"); +var EventEmitter = require("../lib/event_emitter").EventEmitter; + +var Text = function(parentEl) { + this.element = dom.createElement("div"); + this.element.className = "ace_layer ace_text-layer"; + parentEl.appendChild(this.element); + this.$updateEolChar = this.$updateEolChar.bind(this); +}; + +(function() { + + oop.implement(this, EventEmitter); + + this.EOF_CHAR = "\xB6"; + this.EOL_CHAR_LF = "\xAC"; + this.EOL_CHAR_CRLF = "\xa4"; + this.EOL_CHAR = this.EOL_CHAR_LF; + this.TAB_CHAR = "\u2192"; //"\u21E5"; + this.SPACE_CHAR = "\xB7"; + this.$padding = 0; + + this.$updateEolChar = function() { + var doc = this.session.doc; + var unixMode = doc.getNewLineCharacter() == "\n" && doc.getNewLineMode() != "windows"; + var EOL_CHAR = unixMode ? this.EOL_CHAR_LF : this.EOL_CHAR_CRLF; + if (this.EOL_CHAR != EOL_CHAR) { + this.EOL_CHAR = EOL_CHAR; + return true; + } + }; + + this.setPadding = function(padding) { + this.$padding = padding; + this.element.style.padding = "0 " + padding + "px"; + }; + + this.getLineHeight = function() { + return this.$fontMetrics.$characterSize.height || 0; + }; + + this.getCharacterWidth = function() { + return this.$fontMetrics.$characterSize.width || 0; + }; + + this.$setFontMetrics = function(measure) { + this.$fontMetrics = measure; + this.$fontMetrics.on("changeCharacterSize", function(e) { + this._signal("changeCharacterSize", e); + }.bind(this)); + this.$pollSizeChanges(); + }; + + this.checkForSizeChanges = function() { + this.$fontMetrics.checkForSizeChanges(); + }; + this.$pollSizeChanges = function() { + return this.$pollSizeChangesTimer = this.$fontMetrics.$pollSizeChanges(); + }; + this.setSession = function(session) { + this.session = session; + if (session) + this.$computeTabString(); + }; + + this.showInvisibles = false; + this.setShowInvisibles = function(showInvisibles) { + if (this.showInvisibles == showInvisibles) + return false; + + this.showInvisibles = showInvisibles; + this.$computeTabString(); + return true; + }; + + this.displayIndentGuides = true; + this.setDisplayIndentGuides = function(display) { + if (this.displayIndentGuides == display) + return false; + + this.displayIndentGuides = display; + this.$computeTabString(); + return true; + }; + + this.$tabStrings = []; + this.onChangeTabSize = + this.$computeTabString = function() { + var tabSize = this.session.getTabSize(); + this.tabSize = tabSize; + var tabStr = this.$tabStrings = [0]; + for (var i = 1; i < tabSize + 1; i++) { + if (this.showInvisibles) { + tabStr.push("" + + this.TAB_CHAR + + lang.stringRepeat("\xa0", i - 1) + + ""); + } else { + tabStr.push(lang.stringRepeat("\xa0", i)); + } + } + if (this.displayIndentGuides) { + this.$indentGuideRe = /\s\S| \t|\t |\s$/; + var className = "ace_indent-guide"; + var spaceClass = ""; + var tabClass = ""; + if (this.showInvisibles) { + className += " ace_invisible"; + spaceClass = " ace_invisible_space"; + tabClass = " ace_invisible_tab"; + var spaceContent = lang.stringRepeat(this.SPACE_CHAR, this.tabSize); + var tabContent = this.TAB_CHAR + lang.stringRepeat("\xa0", this.tabSize - 1); + } else{ + var spaceContent = lang.stringRepeat("\xa0", this.tabSize); + var tabContent = spaceContent; + } + + this.$tabStrings[" "] = "" + spaceContent + ""; + this.$tabStrings["\t"] = "" + tabContent + ""; + } + }; + + this.updateLines = function(config, firstRow, lastRow) { + // Due to wrap line changes there can be new lines if e.g. + // the line to updated wrapped in the meantime. + if (this.config.lastRow != config.lastRow || + this.config.firstRow != config.firstRow) { + this.scrollLines(config); + } + this.config = config; + + var first = Math.max(firstRow, config.firstRow); + var last = Math.min(lastRow, config.lastRow); + + var lineElements = this.element.childNodes; + var lineElementsIdx = 0; + + for (var row = config.firstRow; row < first; row++) { + var foldLine = this.session.getFoldLine(row); + if (foldLine) { + if (foldLine.containsRow(first)) { + first = foldLine.start.row; + break; + } else { + row = foldLine.end.row; + } + } + lineElementsIdx ++; + } + + var row = first; + var foldLine = this.session.getNextFoldLine(row); + var foldStart = foldLine ? foldLine.start.row : Infinity; + + while (true) { + if (row > foldStart) { + row = foldLine.end.row+1; + foldLine = this.session.getNextFoldLine(row, foldLine); + foldStart = foldLine ? foldLine.start.row :Infinity; + } + if (row > last) + break; + + var lineElement = lineElements[lineElementsIdx++]; + if (lineElement) { + var html = []; + this.$renderLine( + html, row, !this.$useLineGroups(), row == foldStart ? foldLine : false + ); + lineElement.style.height = config.lineHeight * this.session.getRowLength(row) + "px"; + lineElement.innerHTML = html.join(""); + } + row++; + } + }; + + this.scrollLines = function(config) { + var oldConfig = this.config; + this.config = config; + + if (!oldConfig || oldConfig.lastRow < config.firstRow) + return this.update(config); + + if (config.lastRow < oldConfig.firstRow) + return this.update(config); + + var el = this.element; + if (oldConfig.firstRow < config.firstRow) + for (var row=this.session.getFoldedRowCount(oldConfig.firstRow, config.firstRow - 1); row>0; row--) + el.removeChild(el.firstChild); + + if (oldConfig.lastRow > config.lastRow) + for (var row=this.session.getFoldedRowCount(config.lastRow + 1, oldConfig.lastRow); row>0; row--) + el.removeChild(el.lastChild); + + if (config.firstRow < oldConfig.firstRow) { + var fragment = this.$renderLinesFragment(config, config.firstRow, oldConfig.firstRow - 1); + if (el.firstChild) + el.insertBefore(fragment, el.firstChild); + else + el.appendChild(fragment); + } + + if (config.lastRow > oldConfig.lastRow) { + var fragment = this.$renderLinesFragment(config, oldConfig.lastRow + 1, config.lastRow); + el.appendChild(fragment); + } + }; + + this.$renderLinesFragment = function(config, firstRow, lastRow) { + var fragment = this.element.ownerDocument.createDocumentFragment(); + var row = firstRow; + var foldLine = this.session.getNextFoldLine(row); + var foldStart = foldLine ? foldLine.start.row : Infinity; + + while (true) { + if (row > foldStart) { + row = foldLine.end.row+1; + foldLine = this.session.getNextFoldLine(row, foldLine); + foldStart = foldLine ? foldLine.start.row : Infinity; + } + if (row > lastRow) + break; + + var container = dom.createElement("div"); + + var html = []; + // Get the tokens per line as there might be some lines in between + // beeing folded. + this.$renderLine(html, row, false, row == foldStart ? foldLine : false); + + // don't use setInnerHtml since we are working with an empty DIV + container.innerHTML = html.join(""); + if (this.$useLineGroups()) { + container.className = 'ace_line_group'; + fragment.appendChild(container); + container.style.height = config.lineHeight * this.session.getRowLength(row) + "px"; + + } else { + while(container.firstChild) + fragment.appendChild(container.firstChild); + } + + row++; + } + return fragment; + }; + + this.update = function(config) { + this.config = config; + + var html = []; + var firstRow = config.firstRow, lastRow = config.lastRow; + + var row = firstRow; + var foldLine = this.session.getNextFoldLine(row); + var foldStart = foldLine ? foldLine.start.row : Infinity; + + while (true) { + if (row > foldStart) { + row = foldLine.end.row+1; + foldLine = this.session.getNextFoldLine(row, foldLine); + foldStart = foldLine ? foldLine.start.row :Infinity; + } + if (row > lastRow) + break; + + if (this.$useLineGroups()) + html.push("
      "); + + this.$renderLine(html, row, false, row == foldStart ? foldLine : false); + + if (this.$useLineGroups()) + html.push("
      "); // end the line group + + row++; + } + this.element.innerHTML = html.join(""); + }; + + this.$textToken = { + "text": true, + "rparen": true, + "lparen": true + }; + + this.$renderToken = function(stringBuilder, screenColumn, token, value) { + var self = this; + var replaceReg = /\t|&|<|( +)|([\x00-\x1f\x80-\xa0\xad\u1680\u180E\u2000-\u200f\u2028\u2029\u202F\u205F\u3000\uFEFF])|[\u1100-\u115F\u11A3-\u11A7\u11FA-\u11FF\u2329-\u232A\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u2FF0-\u2FFB\u3000-\u303E\u3041-\u3096\u3099-\u30FF\u3105-\u312D\u3131-\u318E\u3190-\u31BA\u31C0-\u31E3\u31F0-\u321E\u3220-\u3247\u3250-\u32FE\u3300-\u4DBF\u4E00-\uA48C\uA490-\uA4C6\uA960-\uA97C\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFAFF\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE66\uFE68-\uFE6B\uFF01-\uFF60\uFFE0-\uFFE6]/g; + var replaceFunc = function(c, a, b, tabIdx, idx4) { + if (a) { + return self.showInvisibles ? + "" + lang.stringRepeat(self.SPACE_CHAR, c.length) + "" : + lang.stringRepeat("\xa0", c.length); + } else if (c == "&") { + return "&"; + } else if (c == "<") { + return "<"; + } else if (c == "\t") { + var tabSize = self.session.getScreenTabSize(screenColumn + tabIdx); + screenColumn += tabSize - 1; + return self.$tabStrings[tabSize]; + } else if (c == "\u3000") { + // U+3000 is both invisible AND full-width, so must be handled uniquely + var classToUse = self.showInvisibles ? "ace_cjk ace_invisible ace_invisible_space" : "ace_cjk"; + var space = self.showInvisibles ? self.SPACE_CHAR : ""; + screenColumn += 1; + return "" + space + ""; + } else if (b) { + return "" + self.SPACE_CHAR + ""; + } else { + screenColumn += 1; + return "" + c + ""; + } + }; + + var output = value.replace(replaceReg, replaceFunc); + + if (!this.$textToken[token.type]) { + var classes = "ace_" + token.type.replace(/\./g, " ace_"); + var style = ""; + if (token.type == "fold") + style = " style='width:" + (token.value.length * this.config.characterWidth) + "px;' "; + stringBuilder.push("", output, ""); + } + else { + stringBuilder.push(output); + } + return screenColumn + value.length; + }; + + this.renderIndentGuide = function(stringBuilder, value, max) { + var cols = value.search(this.$indentGuideRe); + if (cols <= 0 || cols >= max) + return value; + if (value[0] == " ") { + cols -= cols % this.tabSize; + stringBuilder.push(lang.stringRepeat(this.$tabStrings[" "], cols/this.tabSize)); + return value.substr(cols); + } else if (value[0] == "\t") { + stringBuilder.push(lang.stringRepeat(this.$tabStrings["\t"], cols)); + return value.substr(cols); + } + return value; + }; + + this.$renderWrappedLine = function(stringBuilder, tokens, splits, onlyContents) { + var chars = 0; + var split = 0; + var splitChars = splits[0]; + var screenColumn = 0; + + for (var i = 0; i < tokens.length; i++) { + var token = tokens[i]; + var value = token.value; + if (i == 0 && this.displayIndentGuides) { + chars = value.length; + value = this.renderIndentGuide(stringBuilder, value, splitChars); + if (!value) + continue; + chars -= value.length; + } + + if (chars + value.length < splitChars) { + screenColumn = this.$renderToken(stringBuilder, screenColumn, token, value); + chars += value.length; + } else { + while (chars + value.length >= splitChars) { + screenColumn = this.$renderToken( + stringBuilder, screenColumn, + token, value.substring(0, splitChars - chars) + ); + value = value.substring(splitChars - chars); + chars = splitChars; + + if (!onlyContents) { + stringBuilder.push("
      ", + "
      " + ); + } + + split ++; + screenColumn = 0; + splitChars = splits[split] || Number.MAX_VALUE; + } + if (value.length != 0) { + chars += value.length; + screenColumn = this.$renderToken( + stringBuilder, screenColumn, token, value + ); + } + } + } + }; + + this.$renderSimpleLine = function(stringBuilder, tokens) { + var screenColumn = 0; + var token = tokens[0]; + var value = token.value; + if (this.displayIndentGuides) + value = this.renderIndentGuide(stringBuilder, value); + if (value) + screenColumn = this.$renderToken(stringBuilder, screenColumn, token, value); + for (var i = 1; i < tokens.length; i++) { + token = tokens[i]; + value = token.value; + screenColumn = this.$renderToken(stringBuilder, screenColumn, token, value); + } + }; + + // row is either first row of foldline or not in fold + this.$renderLine = function(stringBuilder, row, onlyContents, foldLine) { + if (!foldLine && foldLine != false) + foldLine = this.session.getFoldLine(row); + + if (foldLine) + var tokens = this.$getFoldLineTokens(row, foldLine); + else + var tokens = this.session.getTokens(row); + + + if (!onlyContents) { + stringBuilder.push( + "
      " + ); + } + + if (tokens.length) { + var splits = this.session.getRowSplitData(row); + if (splits && splits.length) + this.$renderWrappedLine(stringBuilder, tokens, splits, onlyContents); + else + this.$renderSimpleLine(stringBuilder, tokens); + } + + if (this.showInvisibles) { + if (foldLine) + row = foldLine.end.row + + stringBuilder.push( + "", + row == this.session.getLength() - 1 ? this.EOF_CHAR : this.EOL_CHAR, + "" + ); + } + if (!onlyContents) + stringBuilder.push("
      "); + }; + + this.$getFoldLineTokens = function(row, foldLine) { + var session = this.session; + var renderTokens = []; + + function addTokens(tokens, from, to) { + var idx = 0, col = 0; + while ((col + tokens[idx].value.length) < from) { + col += tokens[idx].value.length; + idx++; + + if (idx == tokens.length) + return; + } + if (col != from) { + var value = tokens[idx].value.substring(from - col); + // Check if the token value is longer then the from...to spacing. + if (value.length > (to - from)) + value = value.substring(0, to - from); + + renderTokens.push({ + type: tokens[idx].type, + value: value + }); + + col = from + value.length; + idx += 1; + } + + while (col < to && idx < tokens.length) { + var value = tokens[idx].value; + if (value.length + col > to) { + renderTokens.push({ + type: tokens[idx].type, + value: value.substring(0, to - col) + }); + } else + renderTokens.push(tokens[idx]); + col += value.length; + idx += 1; + } + } + + var tokens = session.getTokens(row); + foldLine.walk(function(placeholder, row, column, lastColumn, isNewRow) { + if (placeholder != null) { + renderTokens.push({ + type: "fold", + value: placeholder + }); + } else { + if (isNewRow) + tokens = session.getTokens(row); + + if (tokens.length) + addTokens(tokens, lastColumn, column); + } + }, foldLine.end.row, this.session.getLine(foldLine.end.row).length); + + return renderTokens; + }; + + this.$useLineGroups = function() { + // For the updateLines function to work correctly, it's important that the + // child nodes of this.element correspond on a 1-to-1 basis to rows in the + // document (as distinct from lines on the screen). For sessions that are + // wrapped, this means we need to add a layer to the node hierarchy (tagged + // with the class name ace_line_group). + return this.session.getUseWrapMode(); + }; + + this.destroy = function() { + clearInterval(this.$pollSizeChangesTimer); + if (this.$measureNode) + this.$measureNode.parentNode.removeChild(this.$measureNode); + delete this.$measureNode; + }; + +}).call(Text.prototype); + +exports.Text = Text; + +}); diff --git a/node_modules/ace/lib/ace/layer/text_test.js b/node_modules/ace/lib/ace/layer/text_test.js new file mode 100644 index 00000000..57601207 --- /dev/null +++ b/node_modules/ace/lib/ace/layer/text_test.js @@ -0,0 +1,126 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +if (typeof process !== "undefined") { + require("amd-loader"); + require("../test/mockdom"); +} + +define(function(require, exports, module) { +"use strict"; + +var assert = require("../test/assertions"); +var EditSession = require("../edit_session").EditSession; +var TextLayer = require("./text").Text; +var JavaScriptMode = require("../mode/javascript").Mode; + +module.exports = { + + setUp: function(next) { + this.session = new EditSession(""); + this.session.setMode(new JavaScriptMode()); + this.textLayer = new TextLayer(document.createElement("div")); + this.textLayer.setSession(this.session); + this.textLayer.config = { + characterWidth: 10, + lineHeight: 20 + }; + next() + }, + + "test: render line with hard tabs should render the same as lines with soft tabs" : function() { + this.session.setValue("a\ta\ta\t\na a a \n"); + this.textLayer.$computeTabString(); + + // row with hard tabs + var stringBuilder = []; + this.textLayer.$renderLine(stringBuilder, 0); + + // row with soft tabs + var stringBuilder2 = []; + this.textLayer.$renderLine(stringBuilder2, 1); + assert.equal(stringBuilder.join(""), stringBuilder2.join("")); + }, + + "test rendering width of ideographic space (U+3000)" : function() { + this.session.setValue("\u3000"); + + var stringBuilder = []; + this.textLayer.$renderLine(stringBuilder, 0, true); + assert.equal(stringBuilder.join(""), ""); + + this.textLayer.setShowInvisibles(true); + var stringBuilder = []; + this.textLayer.$renderLine(stringBuilder, 0, true); + assert.equal( + stringBuilder.join(""), + "" + this.textLayer.SPACE_CHAR + "" + + "\xB6" + ); + }, + + "test rendering of indent guides" : function() { + var textLayer = this.textLayer + var EOL = "" + textLayer.EOL_CHAR + ""; + var SPACE = function(i) {return Array(i+1).join("\xa0")} + var DOT = function(i) {return Array(i+1).join(textLayer.SPACE_CHAR)} + var TAB = function(i) {return textLayer.TAB_CHAR + SPACE(i-1)} + function testRender(results) { + for (var i = results.length; i--; ) { + var stringBuilder = []; + textLayer.$renderLine(stringBuilder, i, true); + assert.equal(stringBuilder.join(""), results[i]); + } + } + + this.session.setValue(" \n\t\tf\n "); + testRender([ + "" + SPACE(4) + "" + SPACE(2), + "" + SPACE(4) + "" + SPACE(4) + "f", + SPACE(3) + ]); + this.textLayer.setShowInvisibles(true); + testRender([ + "" + DOT(4) + "" + DOT(2) + "" + EOL, + "" + TAB(4) + "" + TAB(4) + "f" + EOL, + ]); + this.textLayer.setDisplayIndentGuides(false); + testRender([ + "" + DOT(6) + "" + EOL, + "" + TAB(4) + "" + TAB(4) + "f" + EOL + ]); + } +}; + +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec() +} diff --git a/node_modules/ace/lib/ace/lib/app_config.js b/node_modules/ace/lib/ace/lib/app_config.js new file mode 100644 index 00000000..4fe78a1d --- /dev/null +++ b/node_modules/ace/lib/ace/lib/app_config.js @@ -0,0 +1,157 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"no use strict"; + +var oop = require("./oop"); +var EventEmitter = require("./event_emitter").EventEmitter; + +var optionsProvider = { + setOptions: function(optList) { + Object.keys(optList).forEach(function(key) { + this.setOption(key, optList[key]); + }, this); + }, + getOptions: function(optionNames) { + var result = {}; + if (!optionNames) { + optionNames = Object.keys(this.$options); + } else if (!Array.isArray(optionNames)) { + result = optionNames; + optionNames = Object.keys(result); + } + optionNames.forEach(function(key) { + result[key] = this.getOption(key); + }, this); + return result; + }, + setOption: function(name, value) { + if (this["$" + name] === value) + return; + var opt = this.$options[name]; + if (!opt) { + return warn('misspelled option "' + name + '"'); + } + if (opt.forwardTo) + return this[opt.forwardTo] && this[opt.forwardTo].setOption(name, value); + + if (!opt.handlesSet) + this["$" + name] = value; + if (opt && opt.set) + opt.set.call(this, value); + }, + getOption: function(name) { + var opt = this.$options[name]; + if (!opt) { + return warn('misspelled option "' + name + '"'); + } + if (opt.forwardTo) + return this[opt.forwardTo] && this[opt.forwardTo].getOption(name); + return opt && opt.get ? opt.get.call(this) : this["$" + name]; + } +}; + +function warn(message) { + if (typeof console != "undefined" && console.warn) + console.warn.apply(console, arguments); +} + +function reportError(msg, data) { + var e = new Error(msg); + e.data = data; + if (typeof console == "object" && console.error) + console.error(e); + setTimeout(function() { throw e; }); +} + +var AppConfig = function() { + this.$defaultOptions = {}; +}; + +(function() { + // module loading + oop.implement(this, EventEmitter); + /* + * option {name, value, initialValue, setterName, set, get } + */ + this.defineOptions = function(obj, path, options) { + if (!obj.$options) + this.$defaultOptions[path] = obj.$options = {}; + + Object.keys(options).forEach(function(key) { + var opt = options[key]; + if (typeof opt == "string") + opt = {forwardTo: opt}; + + opt.name || (opt.name = key); + obj.$options[opt.name] = opt; + if ("initialValue" in opt) + obj["$" + opt.name] = opt.initialValue; + }); + + // implement option provider interface + oop.implement(obj, optionsProvider); + + return this; + }; + + this.resetOptions = function(obj) { + Object.keys(obj.$options).forEach(function(key) { + var opt = obj.$options[key]; + if ("value" in opt) + obj.setOption(key, opt.value); + }); + }; + + this.setDefaultValue = function(path, name, value) { + var opts = this.$defaultOptions[path] || (this.$defaultOptions[path] = {}); + if (opts[name]) { + if (opts.forwardTo) + this.setDefaultValue(opts.forwardTo, name, value); + else + opts[name].value = value; + } + }; + + this.setDefaultValues = function(path, optionHash) { + Object.keys(optionHash).forEach(function(key) { + this.setDefaultValue(path, key, optionHash[key]); + }, this); + }; + + this.warn = warn; + this.reportError = reportError; + +}).call(AppConfig.prototype); + +exports.AppConfig = AppConfig; + +}); diff --git a/node_modules/ace/lib/ace/lib/dom.js b/node_modules/ace/lib/ace/lib/dom.js new file mode 100644 index 00000000..ef2f7caa --- /dev/null +++ b/node_modules/ace/lib/ace/lib/dom.js @@ -0,0 +1,284 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var XHTML_NS = "http://www.w3.org/1999/xhtml"; + +exports.getDocumentHead = function(doc) { + if (!doc) + doc = document; + return doc.head || doc.getElementsByTagName("head")[0] || doc.documentElement; +} + +exports.createElement = function(tag, ns) { + return document.createElementNS ? + document.createElementNS(ns || XHTML_NS, tag) : + document.createElement(tag); +}; + +exports.hasCssClass = function(el, name) { + var classes = (el.className || "").split(/\s+/g); + return classes.indexOf(name) !== -1; +}; + +/* +* Add a CSS class to the list of classes on the given node +*/ +exports.addCssClass = function(el, name) { + if (!exports.hasCssClass(el, name)) { + el.className += " " + name; + } +}; + +/* +* Remove a CSS class from the list of classes on the given node +*/ +exports.removeCssClass = function(el, name) { + var classes = el.className.split(/\s+/g); + while (true) { + var index = classes.indexOf(name); + if (index == -1) { + break; + } + classes.splice(index, 1); + } + el.className = classes.join(" "); +}; + +exports.toggleCssClass = function(el, name) { + var classes = el.className.split(/\s+/g), add = true; + while (true) { + var index = classes.indexOf(name); + if (index == -1) { + break; + } + add = false; + classes.splice(index, 1); + } + if(add) + classes.push(name); + + el.className = classes.join(" "); + return add; +}; + +/* + * Add or remove a CSS class from the list of classes on the given node + * depending on the value of include + */ +exports.setCssClass = function(node, className, include) { + if (include) { + exports.addCssClass(node, className); + } else { + exports.removeCssClass(node, className); + } +}; + +exports.hasCssString = function(id, doc) { + var index = 0, sheets; + doc = doc || document; + + if (doc.createStyleSheet && (sheets = doc.styleSheets)) { + while (index < sheets.length) + if (sheets[index++].owningElement.id === id) return true; + } else if ((sheets = doc.getElementsByTagName("style"))) { + while (index < sheets.length) + if (sheets[index++].id === id) return true; + } + + return false; +}; + +exports.importCssString = function importCssString(cssText, id, doc) { + doc = doc || document; + // If style is already imported return immediately. + if (id && exports.hasCssString(id, doc)) + return null; + + var style; + + if (doc.createStyleSheet) { + style = doc.createStyleSheet(); + style.cssText = cssText; + if (id) + style.owningElement.id = id; + } else { + style = doc.createElementNS + ? doc.createElementNS(XHTML_NS, "style") + : doc.createElement("style"); + + style.appendChild(doc.createTextNode(cssText)); + if (id) + style.id = id; + + exports.getDocumentHead(doc).appendChild(style); + } +}; + +exports.importCssStylsheet = function(uri, doc) { + if (doc.createStyleSheet) { + doc.createStyleSheet(uri); + } else { + var link = exports.createElement('link'); + link.rel = 'stylesheet'; + link.href = uri; + + exports.getDocumentHead(doc).appendChild(link); + } +}; + +exports.getInnerWidth = function(element) { + return ( + parseInt(exports.computedStyle(element, "paddingLeft"), 10) + + parseInt(exports.computedStyle(element, "paddingRight"), 10) + + element.clientWidth + ); +}; + +exports.getInnerHeight = function(element) { + return ( + parseInt(exports.computedStyle(element, "paddingTop"), 10) + + parseInt(exports.computedStyle(element, "paddingBottom"), 10) + + element.clientHeight + ); +}; + + +if (typeof document == "undefined") + return; + +if (window.pageYOffset !== undefined) { + exports.getPageScrollTop = function() { + return window.pageYOffset; + }; + + exports.getPageScrollLeft = function() { + return window.pageXOffset; + }; +} +else { + exports.getPageScrollTop = function() { + return document.body.scrollTop; + }; + + exports.getPageScrollLeft = function() { + return document.body.scrollLeft; + }; +} + +if (window.getComputedStyle) + exports.computedStyle = function(element, style) { + if (style) + return (window.getComputedStyle(element, "") || {})[style] || ""; + return window.getComputedStyle(element, "") || {}; + }; +else + exports.computedStyle = function(element, style) { + if (style) + return element.currentStyle[style]; + return element.currentStyle; + }; + +exports.scrollbarWidth = function(document) { + var inner = exports.createElement("ace_inner"); + inner.style.width = "100%"; + inner.style.minWidth = "0px"; + inner.style.height = "200px"; + inner.style.display = "block"; + + var outer = exports.createElement("ace_outer"); + var style = outer.style; + + style.position = "absolute"; + style.left = "-10000px"; + style.overflow = "hidden"; + style.width = "200px"; + style.minWidth = "0px"; + style.height = "150px"; + style.display = "block"; + + outer.appendChild(inner); + + var body = document.documentElement; + body.appendChild(outer); + + var noScrollbar = inner.offsetWidth; + + style.overflow = "scroll"; + var withScrollbar = inner.offsetWidth; + + if (noScrollbar == withScrollbar) { + withScrollbar = outer.clientWidth; + } + + body.removeChild(outer); + + return noScrollbar-withScrollbar; +}; + +/* + * Optimized set innerHTML. This is faster than plain innerHTML if the element + * already contains a lot of child elements. + * + * See http://blog.stevenlevithan.com/archives/faster-than-innerhtml for details + */ +exports.setInnerHtml = function(el, innerHtml) { + var element = el.cloneNode(false);//document.createElement("div"); + element.innerHTML = innerHtml; + el.parentNode.replaceChild(element, el); + return element; +}; + +if ("textContent" in document.documentElement) { + exports.setInnerText = function(el, innerText) { + el.textContent = innerText; + }; + + exports.getInnerText = function(el) { + return el.textContent; + }; +} +else { + exports.setInnerText = function(el, innerText) { + el.innerText = innerText; + }; + + exports.getInnerText = function(el) { + return el.innerText; + }; +} + +exports.getParentWindow = function(document) { + return document.defaultView || document.parentWindow; +}; + +}); diff --git a/node_modules/ace/lib/ace/lib/es5-shim.js b/node_modules/ace/lib/ace/lib/es5-shim.js new file mode 100644 index 00000000..217bdc61 --- /dev/null +++ b/node_modules/ace/lib/ace/lib/es5-shim.js @@ -0,0 +1,1062 @@ +// https://github.com/kriskowal/es5-shim +// Copyright 2009-2012 by contributors, MIT License + +define(function(require, exports, module) { + +/* + * Brings an environment as close to ECMAScript 5 compliance + * as is possible with the facilities of erstwhile engines. + * + * Annotated ES5: http://es5.github.com/ (specific links below) + * ES5 Spec: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf + * Required reading: http://javascriptweblog.wordpress.com/2011/12/05/extending-javascript-natives/ + */ + +// +// Function +// ======== +// + +// ES-5 15.3.4.5 +// http://es5.github.com/#x15.3.4.5 + +function Empty() {} + +if (!Function.prototype.bind) { + Function.prototype.bind = function bind(that) { // .length is 1 + // 1. Let Target be the this value. + var target = this; + // 2. If IsCallable(Target) is false, throw a TypeError exception. + if (typeof target != "function") { + throw new TypeError("Function.prototype.bind called on incompatible " + target); + } + // 3. Let A be a new (possibly empty) internal list of all of the + // argument values provided after thisArg (arg1, arg2 etc), in order. + // XXX slicedArgs will stand in for "A" if used + var args = slice.call(arguments, 1); // for normal call + // 4. Let F be a new native ECMAScript object. + // 11. Set the [[Prototype]] internal property of F to the standard + // built-in Function prototype object as specified in 15.3.3.1. + // 12. Set the [[Call]] internal property of F as described in + // 15.3.4.5.1. + // 13. Set the [[Construct]] internal property of F as described in + // 15.3.4.5.2. + // 14. Set the [[HasInstance]] internal property of F as described in + // 15.3.4.5.3. + var bound = function () { + + if (this instanceof bound) { + // 15.3.4.5.2 [[Construct]] + // When the [[Construct]] internal method of a function object, + // F that was created using the bind function is called with a + // list of arguments ExtraArgs, the following steps are taken: + // 1. Let target be the value of F's [[TargetFunction]] + // internal property. + // 2. If target has no [[Construct]] internal method, a + // TypeError exception is thrown. + // 3. Let boundArgs be the value of F's [[BoundArgs]] internal + // property. + // 4. Let args be a new list containing the same values as the + // list boundArgs in the same order followed by the same + // values as the list ExtraArgs in the same order. + // 5. Return the result of calling the [[Construct]] internal + // method of target providing args as the arguments. + + var result = target.apply( + this, + args.concat(slice.call(arguments)) + ); + if (Object(result) === result) { + return result; + } + return this; + + } else { + // 15.3.4.5.1 [[Call]] + // When the [[Call]] internal method of a function object, F, + // which was created using the bind function is called with a + // this value and a list of arguments ExtraArgs, the following + // steps are taken: + // 1. Let boundArgs be the value of F's [[BoundArgs]] internal + // property. + // 2. Let boundThis be the value of F's [[BoundThis]] internal + // property. + // 3. Let target be the value of F's [[TargetFunction]] internal + // property. + // 4. Let args be a new list containing the same values as the + // list boundArgs in the same order followed by the same + // values as the list ExtraArgs in the same order. + // 5. Return the result of calling the [[Call]] internal method + // of target providing boundThis as the this value and + // providing args as the arguments. + + // equiv: target.call(this, ...boundArgs, ...args) + return target.apply( + that, + args.concat(slice.call(arguments)) + ); + + } + + }; + if(target.prototype) { + Empty.prototype = target.prototype; + bound.prototype = new Empty(); + // Clean up dangling references. + Empty.prototype = null; + } + // XXX bound.length is never writable, so don't even try + // + // 15. If the [[Class]] internal property of Target is "Function", then + // a. Let L be the length property of Target minus the length of A. + // b. Set the length own property of F to either 0 or L, whichever is + // larger. + // 16. Else set the length own property of F to 0. + // 17. Set the attributes of the length own property of F to the values + // specified in 15.3.5.1. + + // TODO + // 18. Set the [[Extensible]] internal property of F to true. + + // TODO + // 19. Let thrower be the [[ThrowTypeError]] function Object (13.2.3). + // 20. Call the [[DefineOwnProperty]] internal method of F with + // arguments "caller", PropertyDescriptor {[[Get]]: thrower, [[Set]]: + // thrower, [[Enumerable]]: false, [[Configurable]]: false}, and + // false. + // 21. Call the [[DefineOwnProperty]] internal method of F with + // arguments "arguments", PropertyDescriptor {[[Get]]: thrower, + // [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false}, + // and false. + + // TODO + // NOTE Function objects created using Function.prototype.bind do not + // have a prototype property or the [[Code]], [[FormalParameters]], and + // [[Scope]] internal properties. + // XXX can't delete prototype in pure-js. + + // 22. Return F. + return bound; + }; +} + +// Shortcut to an often accessed properties, in order to avoid multiple +// dereference that costs universally. +// _Please note: Shortcuts are defined after `Function.prototype.bind` as we +// us it in defining shortcuts. +var call = Function.prototype.call; +var prototypeOfArray = Array.prototype; +var prototypeOfObject = Object.prototype; +var slice = prototypeOfArray.slice; +// Having a toString local variable name breaks in Opera so use _toString. +var _toString = call.bind(prototypeOfObject.toString); +var owns = call.bind(prototypeOfObject.hasOwnProperty); + +// If JS engine supports accessors creating shortcuts. +var defineGetter; +var defineSetter; +var lookupGetter; +var lookupSetter; +var supportsAccessors; +if ((supportsAccessors = owns(prototypeOfObject, "__defineGetter__"))) { + defineGetter = call.bind(prototypeOfObject.__defineGetter__); + defineSetter = call.bind(prototypeOfObject.__defineSetter__); + lookupGetter = call.bind(prototypeOfObject.__lookupGetter__); + lookupSetter = call.bind(prototypeOfObject.__lookupSetter__); +} + +// +// Array +// ===== +// + +// ES5 15.4.4.12 +// http://es5.github.com/#x15.4.4.12 +// Default value for second param +// [bugfix, ielt9, old browsers] +// IE < 9 bug: [1,2].splice(0).join("") == "" but should be "12" +if ([1,2].splice(0).length != 2) { + if(function() { // test IE < 9 to splice bug - see issue #138 + function makeArray(l) { + var a = new Array(l+2); + a[0] = a[1] = 0; + return a; + } + var array = [], lengthBefore; + + array.splice.apply(array, makeArray(20)); + array.splice.apply(array, makeArray(26)); + + lengthBefore = array.length; //46 + array.splice(5, 0, "XXX"); // add one element + + lengthBefore + 1 == array.length + + if (lengthBefore + 1 == array.length) { + return true;// has right splice implementation without bugs + } + // else { + // IE8 bug + // } + }()) {//IE 6/7 + var array_splice = Array.prototype.splice; + Array.prototype.splice = function(start, deleteCount) { + if (!arguments.length) { + return []; + } else { + return array_splice.apply(this, [ + start === void 0 ? 0 : start, + deleteCount === void 0 ? (this.length - start) : deleteCount + ].concat(slice.call(arguments, 2))) + } + }; + } else {//IE8 + // taken from http://docs.sencha.com/ext-js/4-1/source/Array2.html + Array.prototype.splice = function(pos, removeCount){ + var length = this.length; + if (pos > 0) { + if (pos > length) + pos = length; + } else if (pos == void 0) { + pos = 0; + } else if (pos < 0) { + pos = Math.max(length + pos, 0); + } + + if (!(pos+removeCount < length)) + removeCount = length - pos; + + var removed = this.slice(pos, pos+removeCount); + var insert = slice.call(arguments, 2); + var add = insert.length; + + // we try to use Array.push when we can for efficiency... + if (pos === length) { + if (add) { + this.push.apply(this, insert); + } + } else { + var remove = Math.min(removeCount, length - pos); + var tailOldPos = pos + remove; + var tailNewPos = tailOldPos + add - remove; + var tailCount = length - tailOldPos; + var lengthAfterRemove = length - remove; + + if (tailNewPos < tailOldPos) { // case A + for (var i = 0; i < tailCount; ++i) { + this[tailNewPos+i] = this[tailOldPos+i]; + } + } else if (tailNewPos > tailOldPos) { // case B + for (i = tailCount; i--; ) { + this[tailNewPos+i] = this[tailOldPos+i]; + } + } // else, add == remove (nothing to do) + + if (add && pos === lengthAfterRemove) { + this.length = lengthAfterRemove; // truncate array + this.push.apply(this, insert); + } else { + this.length = lengthAfterRemove + add; // reserves space + for (i = 0; i < add; ++i) { + this[pos+i] = insert[i]; + } + } + } + return removed; + }; + } +} + +// ES5 15.4.3.2 +// http://es5.github.com/#x15.4.3.2 +// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/isArray +if (!Array.isArray) { + Array.isArray = function isArray(obj) { + return _toString(obj) == "[object Array]"; + }; +} + +// The IsCallable() check in the Array functions +// has been replaced with a strict check on the +// internal class of the object to trap cases where +// the provided function was actually a regular +// expression literal, which in V8 and +// JavaScriptCore is a typeof "function". Only in +// V8 are regular expression literals permitted as +// reduce parameters, so it is desirable in the +// general case for the shim to match the more +// strict and common behavior of rejecting regular +// expressions. + +// ES5 15.4.4.18 +// http://es5.github.com/#x15.4.4.18 +// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/forEach + +// Check failure of by-index access of string characters (IE < 9) +// and failure of `0 in boxedString` (Rhino) +var boxedString = Object("a"), + splitString = boxedString[0] != "a" || !(0 in boxedString); + +if (!Array.prototype.forEach) { + Array.prototype.forEach = function forEach(fun /*, thisp*/) { + var object = toObject(this), + self = splitString && _toString(this) == "[object String]" ? + this.split("") : + object, + thisp = arguments[1], + i = -1, + length = self.length >>> 0; + + // If no callback function or if callback is not a callable function + if (_toString(fun) != "[object Function]") { + throw new TypeError(); // TODO message + } + + while (++i < length) { + if (i in self) { + // Invoke the callback function with call, passing arguments: + // context, property value, property key, thisArg object + // context + fun.call(thisp, self[i], i, object); + } + } + }; +} + +// ES5 15.4.4.19 +// http://es5.github.com/#x15.4.4.19 +// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/map +if (!Array.prototype.map) { + Array.prototype.map = function map(fun /*, thisp*/) { + var object = toObject(this), + self = splitString && _toString(this) == "[object String]" ? + this.split("") : + object, + length = self.length >>> 0, + result = Array(length), + thisp = arguments[1]; + + // If no callback function or if callback is not a callable function + if (_toString(fun) != "[object Function]") { + throw new TypeError(fun + " is not a function"); + } + + for (var i = 0; i < length; i++) { + if (i in self) + result[i] = fun.call(thisp, self[i], i, object); + } + return result; + }; +} + +// ES5 15.4.4.20 +// http://es5.github.com/#x15.4.4.20 +// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/filter +if (!Array.prototype.filter) { + Array.prototype.filter = function filter(fun /*, thisp */) { + var object = toObject(this), + self = splitString && _toString(this) == "[object String]" ? + this.split("") : + object, + length = self.length >>> 0, + result = [], + value, + thisp = arguments[1]; + + // If no callback function or if callback is not a callable function + if (_toString(fun) != "[object Function]") { + throw new TypeError(fun + " is not a function"); + } + + for (var i = 0; i < length; i++) { + if (i in self) { + value = self[i]; + if (fun.call(thisp, value, i, object)) { + result.push(value); + } + } + } + return result; + }; +} + +// ES5 15.4.4.16 +// http://es5.github.com/#x15.4.4.16 +// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/every +if (!Array.prototype.every) { + Array.prototype.every = function every(fun /*, thisp */) { + var object = toObject(this), + self = splitString && _toString(this) == "[object String]" ? + this.split("") : + object, + length = self.length >>> 0, + thisp = arguments[1]; + + // If no callback function or if callback is not a callable function + if (_toString(fun) != "[object Function]") { + throw new TypeError(fun + " is not a function"); + } + + for (var i = 0; i < length; i++) { + if (i in self && !fun.call(thisp, self[i], i, object)) { + return false; + } + } + return true; + }; +} + +// ES5 15.4.4.17 +// http://es5.github.com/#x15.4.4.17 +// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/some +if (!Array.prototype.some) { + Array.prototype.some = function some(fun /*, thisp */) { + var object = toObject(this), + self = splitString && _toString(this) == "[object String]" ? + this.split("") : + object, + length = self.length >>> 0, + thisp = arguments[1]; + + // If no callback function or if callback is not a callable function + if (_toString(fun) != "[object Function]") { + throw new TypeError(fun + " is not a function"); + } + + for (var i = 0; i < length; i++) { + if (i in self && fun.call(thisp, self[i], i, object)) { + return true; + } + } + return false; + }; +} + +// ES5 15.4.4.21 +// http://es5.github.com/#x15.4.4.21 +// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduce +if (!Array.prototype.reduce) { + Array.prototype.reduce = function reduce(fun /*, initial*/) { + var object = toObject(this), + self = splitString && _toString(this) == "[object String]" ? + this.split("") : + object, + length = self.length >>> 0; + + // If no callback function or if callback is not a callable function + if (_toString(fun) != "[object Function]") { + throw new TypeError(fun + " is not a function"); + } + + // no value to return if no initial value and an empty array + if (!length && arguments.length == 1) { + throw new TypeError("reduce of empty array with no initial value"); + } + + var i = 0; + var result; + if (arguments.length >= 2) { + result = arguments[1]; + } else { + do { + if (i in self) { + result = self[i++]; + break; + } + + // if array contains no values, no initial value to return + if (++i >= length) { + throw new TypeError("reduce of empty array with no initial value"); + } + } while (true); + } + + for (; i < length; i++) { + if (i in self) { + result = fun.call(void 0, result, self[i], i, object); + } + } + + return result; + }; +} + +// ES5 15.4.4.22 +// http://es5.github.com/#x15.4.4.22 +// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduceRight +if (!Array.prototype.reduceRight) { + Array.prototype.reduceRight = function reduceRight(fun /*, initial*/) { + var object = toObject(this), + self = splitString && _toString(this) == "[object String]" ? + this.split("") : + object, + length = self.length >>> 0; + + // If no callback function or if callback is not a callable function + if (_toString(fun) != "[object Function]") { + throw new TypeError(fun + " is not a function"); + } + + // no value to return if no initial value, empty array + if (!length && arguments.length == 1) { + throw new TypeError("reduceRight of empty array with no initial value"); + } + + var result, i = length - 1; + if (arguments.length >= 2) { + result = arguments[1]; + } else { + do { + if (i in self) { + result = self[i--]; + break; + } + + // if array contains no values, no initial value to return + if (--i < 0) { + throw new TypeError("reduceRight of empty array with no initial value"); + } + } while (true); + } + + do { + if (i in this) { + result = fun.call(void 0, result, self[i], i, object); + } + } while (i--); + + return result; + }; +} + +// ES5 15.4.4.14 +// http://es5.github.com/#x15.4.4.14 +// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf +if (!Array.prototype.indexOf || ([0, 1].indexOf(1, 2) != -1)) { + Array.prototype.indexOf = function indexOf(sought /*, fromIndex */ ) { + var self = splitString && _toString(this) == "[object String]" ? + this.split("") : + toObject(this), + length = self.length >>> 0; + + if (!length) { + return -1; + } + + var i = 0; + if (arguments.length > 1) { + i = toInteger(arguments[1]); + } + + // handle negative indices + i = i >= 0 ? i : Math.max(0, length + i); + for (; i < length; i++) { + if (i in self && self[i] === sought) { + return i; + } + } + return -1; + }; +} + +// ES5 15.4.4.15 +// http://es5.github.com/#x15.4.4.15 +// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/lastIndexOf +if (!Array.prototype.lastIndexOf || ([0, 1].lastIndexOf(0, -3) != -1)) { + Array.prototype.lastIndexOf = function lastIndexOf(sought /*, fromIndex */) { + var self = splitString && _toString(this) == "[object String]" ? + this.split("") : + toObject(this), + length = self.length >>> 0; + + if (!length) { + return -1; + } + var i = length - 1; + if (arguments.length > 1) { + i = Math.min(i, toInteger(arguments[1])); + } + // handle negative indices + i = i >= 0 ? i : length - Math.abs(i); + for (; i >= 0; i--) { + if (i in self && sought === self[i]) { + return i; + } + } + return -1; + }; +} + +// +// Object +// ====== +// + +// ES5 15.2.3.2 +// http://es5.github.com/#x15.2.3.2 +if (!Object.getPrototypeOf) { + // https://github.com/kriskowal/es5-shim/issues#issue/2 + // http://ejohn.org/blog/objectgetprototypeof/ + // recommended by fschaefer on github + Object.getPrototypeOf = function getPrototypeOf(object) { + return object.__proto__ || ( + object.constructor ? + object.constructor.prototype : + prototypeOfObject + ); + }; +} + +// ES5 15.2.3.3 +// http://es5.github.com/#x15.2.3.3 +if (!Object.getOwnPropertyDescriptor) { + var ERR_NON_OBJECT = "Object.getOwnPropertyDescriptor called on a " + + "non-object: "; + Object.getOwnPropertyDescriptor = function getOwnPropertyDescriptor(object, property) { + if ((typeof object != "object" && typeof object != "function") || object === null) + throw new TypeError(ERR_NON_OBJECT + object); + // If object does not owns property return undefined immediately. + if (!owns(object, property)) + return; + + var descriptor, getter, setter; + + // If object has a property then it's for sure both `enumerable` and + // `configurable`. + descriptor = { enumerable: true, configurable: true }; + + // If JS engine supports accessor properties then property may be a + // getter or setter. + if (supportsAccessors) { + // Unfortunately `__lookupGetter__` will return a getter even + // if object has own non getter property along with a same named + // inherited getter. To avoid misbehavior we temporary remove + // `__proto__` so that `__lookupGetter__` will return getter only + // if it's owned by an object. + var prototype = object.__proto__; + object.__proto__ = prototypeOfObject; + + var getter = lookupGetter(object, property); + var setter = lookupSetter(object, property); + + // Once we have getter and setter we can put values back. + object.__proto__ = prototype; + + if (getter || setter) { + if (getter) descriptor.get = getter; + if (setter) descriptor.set = setter; + + // If it was accessor property we're done and return here + // in order to avoid adding `value` to the descriptor. + return descriptor; + } + } + + // If we got this far we know that object has an own property that is + // not an accessor so we set it as a value and return descriptor. + descriptor.value = object[property]; + return descriptor; + }; +} + +// ES5 15.2.3.4 +// http://es5.github.com/#x15.2.3.4 +if (!Object.getOwnPropertyNames) { + Object.getOwnPropertyNames = function getOwnPropertyNames(object) { + return Object.keys(object); + }; +} + +// ES5 15.2.3.5 +// http://es5.github.com/#x15.2.3.5 +if (!Object.create) { + var createEmpty; + if (Object.prototype.__proto__ === null) { + createEmpty = function () { + return { "__proto__": null }; + }; + } else { + // In old IE __proto__ can't be used to manually set `null` + createEmpty = function () { + var empty = {}; + for (var i in empty) + empty[i] = null; + empty.constructor = + empty.hasOwnProperty = + empty.propertyIsEnumerable = + empty.isPrototypeOf = + empty.toLocaleString = + empty.toString = + empty.valueOf = + empty.__proto__ = null; + return empty; + } + } + + Object.create = function create(prototype, properties) { + var object; + if (prototype === null) { + object = createEmpty(); + } else { + if (typeof prototype != "object") + throw new TypeError("typeof prototype["+(typeof prototype)+"] != 'object'"); + var Type = function () {}; + Type.prototype = prototype; + object = new Type(); + // IE has no built-in implementation of `Object.getPrototypeOf` + // neither `__proto__`, but this manually setting `__proto__` will + // guarantee that `Object.getPrototypeOf` will work as expected with + // objects created using `Object.create` + object.__proto__ = prototype; + } + if (properties !== void 0) + Object.defineProperties(object, properties); + return object; + }; +} + +// ES5 15.2.3.6 +// http://es5.github.com/#x15.2.3.6 + +// Patch for WebKit and IE8 standard mode +// Designed by hax +// related issue: https://github.com/kriskowal/es5-shim/issues#issue/5 +// IE8 Reference: +// http://msdn.microsoft.com/en-us/library/dd282900.aspx +// http://msdn.microsoft.com/en-us/library/dd229916.aspx +// WebKit Bugs: +// https://bugs.webkit.org/show_bug.cgi?id=36423 + +function doesDefinePropertyWork(object) { + try { + Object.defineProperty(object, "sentinel", {}); + return "sentinel" in object; + } catch (exception) { + // returns falsy + } +} + +// check whether defineProperty works if it's given. Otherwise, +// shim partially. +if (Object.defineProperty) { + var definePropertyWorksOnObject = doesDefinePropertyWork({}); + var definePropertyWorksOnDom = typeof document == "undefined" || + doesDefinePropertyWork(document.createElement("div")); + if (!definePropertyWorksOnObject || !definePropertyWorksOnDom) { + var definePropertyFallback = Object.defineProperty; + } +} + +if (!Object.defineProperty || definePropertyFallback) { + var ERR_NON_OBJECT_DESCRIPTOR = "Property description must be an object: "; + var ERR_NON_OBJECT_TARGET = "Object.defineProperty called on non-object: " + var ERR_ACCESSORS_NOT_SUPPORTED = "getters & setters can not be defined " + + "on this javascript engine"; + + Object.defineProperty = function defineProperty(object, property, descriptor) { + if ((typeof object != "object" && typeof object != "function") || object === null) + throw new TypeError(ERR_NON_OBJECT_TARGET + object); + if ((typeof descriptor != "object" && typeof descriptor != "function") || descriptor === null) + throw new TypeError(ERR_NON_OBJECT_DESCRIPTOR + descriptor); + + // make a valiant attempt to use the real defineProperty + // for I8's DOM elements. + if (definePropertyFallback) { + try { + return definePropertyFallback.call(Object, object, property, descriptor); + } catch (exception) { + // try the shim if the real one doesn't work + } + } + + // If it's a data property. + if (owns(descriptor, "value")) { + // fail silently if "writable", "enumerable", or "configurable" + // are requested but not supported + /* + // alternate approach: + if ( // can't implement these features; allow false but not true + !(owns(descriptor, "writable") ? descriptor.writable : true) || + !(owns(descriptor, "enumerable") ? descriptor.enumerable : true) || + !(owns(descriptor, "configurable") ? descriptor.configurable : true) + ) + throw new RangeError( + "This implementation of Object.defineProperty does not " + + "support configurable, enumerable, or writable." + ); + */ + + if (supportsAccessors && (lookupGetter(object, property) || + lookupSetter(object, property))) + { + // As accessors are supported only on engines implementing + // `__proto__` we can safely override `__proto__` while defining + // a property to make sure that we don't hit an inherited + // accessor. + var prototype = object.__proto__; + object.__proto__ = prototypeOfObject; + // Deleting a property anyway since getter / setter may be + // defined on object itself. + delete object[property]; + object[property] = descriptor.value; + // Setting original `__proto__` back now. + object.__proto__ = prototype; + } else { + object[property] = descriptor.value; + } + } else { + if (!supportsAccessors) + throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED); + // If we got that far then getters and setters can be defined !! + if (owns(descriptor, "get")) + defineGetter(object, property, descriptor.get); + if (owns(descriptor, "set")) + defineSetter(object, property, descriptor.set); + } + + return object; + }; +} + +// ES5 15.2.3.7 +// http://es5.github.com/#x15.2.3.7 +if (!Object.defineProperties) { + Object.defineProperties = function defineProperties(object, properties) { + for (var property in properties) { + if (owns(properties, property)) + Object.defineProperty(object, property, properties[property]); + } + return object; + }; +} + +// ES5 15.2.3.8 +// http://es5.github.com/#x15.2.3.8 +if (!Object.seal) { + Object.seal = function seal(object) { + // this is misleading and breaks feature-detection, but + // allows "securable" code to "gracefully" degrade to working + // but insecure code. + return object; + }; +} + +// ES5 15.2.3.9 +// http://es5.github.com/#x15.2.3.9 +if (!Object.freeze) { + Object.freeze = function freeze(object) { + // this is misleading and breaks feature-detection, but + // allows "securable" code to "gracefully" degrade to working + // but insecure code. + return object; + }; +} + +// detect a Rhino bug and patch it +try { + Object.freeze(function () {}); +} catch (exception) { + Object.freeze = (function freeze(freezeObject) { + return function freeze(object) { + if (typeof object == "function") { + return object; + } else { + return freezeObject(object); + } + }; + })(Object.freeze); +} + +// ES5 15.2.3.10 +// http://es5.github.com/#x15.2.3.10 +if (!Object.preventExtensions) { + Object.preventExtensions = function preventExtensions(object) { + // this is misleading and breaks feature-detection, but + // allows "securable" code to "gracefully" degrade to working + // but insecure code. + return object; + }; +} + +// ES5 15.2.3.11 +// http://es5.github.com/#x15.2.3.11 +if (!Object.isSealed) { + Object.isSealed = function isSealed(object) { + return false; + }; +} + +// ES5 15.2.3.12 +// http://es5.github.com/#x15.2.3.12 +if (!Object.isFrozen) { + Object.isFrozen = function isFrozen(object) { + return false; + }; +} + +// ES5 15.2.3.13 +// http://es5.github.com/#x15.2.3.13 +if (!Object.isExtensible) { + Object.isExtensible = function isExtensible(object) { + // 1. If Type(O) is not Object throw a TypeError exception. + if (Object(object) === object) { + throw new TypeError(); // TODO message + } + // 2. Return the Boolean value of the [[Extensible]] internal property of O. + var name = ''; + while (owns(object, name)) { + name += '?'; + } + object[name] = true; + var returnValue = owns(object, name); + delete object[name]; + return returnValue; + }; +} + +// ES5 15.2.3.14 +// http://es5.github.com/#x15.2.3.14 +if (!Object.keys) { + // http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation + var hasDontEnumBug = true, + dontEnums = [ + "toString", + "toLocaleString", + "valueOf", + "hasOwnProperty", + "isPrototypeOf", + "propertyIsEnumerable", + "constructor" + ], + dontEnumsLength = dontEnums.length; + + for (var key in {"toString": null}) { + hasDontEnumBug = false; + } + + Object.keys = function keys(object) { + + if ( + (typeof object != "object" && typeof object != "function") || + object === null + ) { + throw new TypeError("Object.keys called on a non-object"); + } + + var keys = []; + for (var name in object) { + if (owns(object, name)) { + keys.push(name); + } + } + + if (hasDontEnumBug) { + for (var i = 0, ii = dontEnumsLength; i < ii; i++) { + var dontEnum = dontEnums[i]; + if (owns(object, dontEnum)) { + keys.push(dontEnum); + } + } + } + return keys; + }; + +} + +// +// most of es5-shim Date section is removed since ace doesn't need it, it is too intrusive and it causes problems for users +// ==== +// + +// ES5 15.9.4.4 +// http://es5.github.com/#x15.9.4.4 +if (!Date.now) { + Date.now = function now() { + return new Date().getTime(); + }; +} + + +// +// String +// ====== +// + +// ES5 15.5.4.20 +// http://es5.github.com/#x15.5.4.20 +var ws = "\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003" + + "\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028" + + "\u2029\uFEFF"; +if (!String.prototype.trim || ws.trim()) { + // http://blog.stevenlevithan.com/archives/faster-trim-javascript + // http://perfectionkills.com/whitespace-deviations/ + ws = "[" + ws + "]"; + var trimBeginRegexp = new RegExp("^" + ws + ws + "*"), + trimEndRegexp = new RegExp(ws + ws + "*$"); + String.prototype.trim = function trim() { + return String(this).replace(trimBeginRegexp, "").replace(trimEndRegexp, ""); + }; +} + +// +// Util +// ====== +// + +// ES5 9.4 +// http://es5.github.com/#x9.4 +// http://jsperf.com/to-integer + +function toInteger(n) { + n = +n; + if (n !== n) { // isNaN + n = 0; + } else if (n !== 0 && n !== (1/0) && n !== -(1/0)) { + n = (n > 0 || -1) * Math.floor(Math.abs(n)); + } + return n; +} + +function isPrimitive(input) { + var type = typeof input; + return ( + input === null || + type === "undefined" || + type === "boolean" || + type === "number" || + type === "string" + ); +} + +function toPrimitive(input) { + var val, valueOf, toString; + if (isPrimitive(input)) { + return input; + } + valueOf = input.valueOf; + if (typeof valueOf === "function") { + val = valueOf.call(input); + if (isPrimitive(val)) { + return val; + } + } + toString = input.toString; + if (typeof toString === "function") { + val = toString.call(input); + if (isPrimitive(val)) { + return val; + } + } + throw new TypeError(); +} + +// ES5 9.9 +// http://es5.github.com/#x9.9 +var toObject = function (o) { + if (o == null) { // this matches both null and undefined + throw new TypeError("can't convert "+o+" to object"); + } + return Object(o); +}; + +}); diff --git a/node_modules/ace/lib/ace/lib/event.js b/node_modules/ace/lib/ace/lib/event.js new file mode 100644 index 00000000..b9f3ebe4 --- /dev/null +++ b/node_modules/ace/lib/ace/lib/event.js @@ -0,0 +1,367 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var keys = require("./keys"); +var useragent = require("./useragent"); + +exports.addListener = function(elem, type, callback) { + if (elem.addEventListener) { + return elem.addEventListener(type, callback, false); + } + if (elem.attachEvent) { + var wrapper = function() { + callback.call(elem, window.event); + }; + callback._wrapper = wrapper; + elem.attachEvent("on" + type, wrapper); + } +}; + +exports.removeListener = function(elem, type, callback) { + if (elem.removeEventListener) { + return elem.removeEventListener(type, callback, false); + } + if (elem.detachEvent) { + elem.detachEvent("on" + type, callback._wrapper || callback); + } +}; + +/* +* Prevents propagation and clobbers the default action of the passed event +*/ +exports.stopEvent = function(e) { + exports.stopPropagation(e); + exports.preventDefault(e); + return false; +}; + +exports.stopPropagation = function(e) { + if (e.stopPropagation) + e.stopPropagation(); + else + e.cancelBubble = true; +}; + +exports.preventDefault = function(e) { + if (e.preventDefault) + e.preventDefault(); + else + e.returnValue = false; +}; + +/* + * @return {Number} 0 for left button, 1 for middle button, 2 for right button + */ +exports.getButton = function(e) { + if (e.type == "dblclick") + return 0; + if (e.type == "contextmenu" || (useragent.isMac && (e.ctrlKey && !e.altKey && !e.shiftKey))) + return 2; + + // DOM Event + if (e.preventDefault) { + return e.button; + } + // old IE + else { + return {1:0, 2:2, 4:1}[e.button]; + } +}; + +exports.capture = function(el, eventHandler, releaseCaptureHandler) { + function onMouseUp(e) { + eventHandler && eventHandler(e); + releaseCaptureHandler && releaseCaptureHandler(e); + + exports.removeListener(document, "mousemove", eventHandler, true); + exports.removeListener(document, "mouseup", onMouseUp, true); + exports.removeListener(document, "dragstart", onMouseUp, true); + } + + exports.addListener(document, "mousemove", eventHandler, true); + exports.addListener(document, "mouseup", onMouseUp, true); + exports.addListener(document, "dragstart", onMouseUp, true); + + return onMouseUp; +}; + +exports.addMouseWheelListener = function(el, callback) { + if ("onmousewheel" in el) { + exports.addListener(el, "mousewheel", function(e) { + var factor = 8; + if (e.wheelDeltaX !== undefined) { + e.wheelX = -e.wheelDeltaX / factor; + e.wheelY = -e.wheelDeltaY / factor; + } else { + e.wheelX = 0; + e.wheelY = -e.wheelDelta / factor; + } + callback(e); + }); + } else if ("onwheel" in el) { + exports.addListener(el, "wheel", function(e) { + var factor = 0.35; + switch (e.deltaMode) { + case e.DOM_DELTA_PIXEL: + e.wheelX = e.deltaX * factor || 0; + e.wheelY = e.deltaY * factor || 0; + break; + case e.DOM_DELTA_LINE: + case e.DOM_DELTA_PAGE: + e.wheelX = (e.deltaX || 0) * 5; + e.wheelY = (e.deltaY || 0) * 5; + break; + } + + callback(e); + }); + } else { + exports.addListener(el, "DOMMouseScroll", function(e) { + if (e.axis && e.axis == e.HORIZONTAL_AXIS) { + e.wheelX = (e.detail || 0) * 5; + e.wheelY = 0; + } else { + e.wheelX = 0; + e.wheelY = (e.detail || 0) * 5; + } + callback(e); + }); + } +}; + +exports.addMultiMouseDownListener = function(el, timeouts, eventHandler, callbackName) { + var clicks = 0; + var startX, startY, timer; + var eventNames = { + 2: "dblclick", + 3: "tripleclick", + 4: "quadclick" + }; + + exports.addListener(el, "mousedown", function(e) { + if (exports.getButton(e) !== 0) { + clicks = 0; + } else if (e.detail > 1) { + clicks++; + if (clicks > 4) + clicks = 1; + } else { + clicks = 1; + } + if (useragent.isIE) { + var isNewClick = Math.abs(e.clientX - startX) > 5 || Math.abs(e.clientY - startY) > 5; + if (!timer || isNewClick) + clicks = 1; + if (timer) + clearTimeout(timer); + timer = setTimeout(function() {timer = null}, timeouts[clicks - 1] || 600); + + if (clicks == 1) { + startX = e.clientX; + startY = e.clientY; + } + } + + e._clicks = clicks; + + eventHandler[callbackName]("mousedown", e); + + if (clicks > 4) + clicks = 0; + else if (clicks > 1) + return eventHandler[callbackName](eventNames[clicks], e); + }); + + if (useragent.isOldIE) { + exports.addListener(el, "dblclick", function(e) { + clicks = 2; + if (timer) + clearTimeout(timer); + timer = setTimeout(function() {timer = null}, timeouts[clicks - 1] || 600); + eventHandler[callbackName]("mousedown", e); + eventHandler[callbackName](eventNames[clicks], e); + }); + } +}; + +var getModifierHash = useragent.isMac && useragent.isOpera && !("KeyboardEvent" in window) + ? function(e) { + return 0 | (e.metaKey ? 1 : 0) | (e.altKey ? 2 : 0) | (e.shiftKey ? 4 : 0) | (e.ctrlKey ? 8 : 0); + } + : function(e) { + return 0 | (e.ctrlKey ? 1 : 0) | (e.altKey ? 2 : 0) | (e.shiftKey ? 4 : 0) | (e.metaKey ? 8 : 0); + }; + +exports.getModifierString = function(e) { + return keys.KEY_MODS[getModifierHash(e)]; +}; + +function normalizeCommandKeys(callback, e, keyCode) { + var hashId = getModifierHash(e); + + if (!useragent.isMac && pressedKeys) { + if (pressedKeys[91] || pressedKeys[92]) + hashId |= 8; + if (pressedKeys.altGr) { + if ((3 & hashId) != 3) + pressedKeys.altGr = 0; + else + return; + } + if (keyCode === 18 || keyCode === 17) { + var location = "location" in e ? e.location : e.keyLocation; + if (keyCode === 17 && location === 1) { + ts = e.timeStamp; + } else if (keyCode === 18 && hashId === 3 && location === 2) { + var dt = -ts; + ts = e.timeStamp; + dt += ts; + if (dt < 3) + pressedKeys.altGr = true; + } + } + } + + if (keyCode in keys.MODIFIER_KEYS) { + keyCode = -1; + } + + if (hashId & 8 && (keyCode === 91 || keyCode === 93)) { + keyCode = -1; + } + + if (!hashId && keyCode === 13) { + var location = "location" in e ? e.location : e.keyLocation; + if (location === 3) { + callback(e, hashId, -keyCode); + if (e.defaultPrevented) + return; + } + } + + if (useragent.isChromeOS && hashId & 8) { + callback(e, hashId, keyCode); + if (e.defaultPrevented) + return; + else + hashId &= ~8; + } + + // If there is no hashId and the keyCode is not a function key, then + // we don't call the callback as we don't handle a command key here + // (it's a normal key/character input). + if (!hashId && !(keyCode in keys.FUNCTION_KEYS) && !(keyCode in keys.PRINTABLE_KEYS)) { + return false; + } + + return callback(e, hashId, keyCode); +} + +var pressedKeys = null; +var ts = 0; +exports.addCommandKeyListener = function(el, callback) { + var addListener = exports.addListener; + if (useragent.isOldGecko || (useragent.isOpera && !("KeyboardEvent" in window))) { + // Old versions of Gecko aka. Firefox < 4.0 didn't repeat the keydown + // event if the user pressed the key for a longer time. Instead, the + // keydown event was fired once and later on only the keypress event. + // To emulate the 'right' keydown behavior, the keyCode of the initial + // keyDown event is stored and in the following keypress events the + // stores keyCode is used to emulate a keyDown event. + var lastKeyDownKeyCode = null; + addListener(el, "keydown", function(e) { + lastKeyDownKeyCode = e.keyCode; + }); + addListener(el, "keypress", function(e) { + return normalizeCommandKeys(callback, e, lastKeyDownKeyCode); + }); + } else { + var lastDefaultPrevented = null; + + addListener(el, "keydown", function(e) { + pressedKeys[e.keyCode] = true; + var result = normalizeCommandKeys(callback, e, e.keyCode); + lastDefaultPrevented = e.defaultPrevented; + return result; + }); + + addListener(el, "keypress", function(e) { + if (lastDefaultPrevented && (e.ctrlKey || e.altKey || e.shiftKey || e.metaKey)) { + exports.stopEvent(e); + lastDefaultPrevented = null; + } + }); + + addListener(el, "keyup", function(e) { + pressedKeys[e.keyCode] = null; + }); + + if (!pressedKeys) { + pressedKeys = Object.create(null); + addListener(window, "focus", function(e) { + pressedKeys = Object.create(null); + }); + } + } +}; + +if (window.postMessage && !useragent.isOldIE) { + var postMessageId = 1; + exports.nextTick = function(callback, win) { + win = win || window; + var messageName = "zero-timeout-message-" + postMessageId; + exports.addListener(win, "message", function listener(e) { + if (e.data == messageName) { + exports.stopPropagation(e); + exports.removeListener(win, "message", listener); + callback(); + } + }); + win.postMessage(messageName, "*"); + }; +} + + +exports.nextFrame = window.requestAnimationFrame || + window.mozRequestAnimationFrame || + window.webkitRequestAnimationFrame || + window.msRequestAnimationFrame || + window.oRequestAnimationFrame; + +if (exports.nextFrame) + exports.nextFrame = exports.nextFrame.bind(window); +else + exports.nextFrame = function(callback) { + setTimeout(callback, 17); + }; +}); diff --git a/node_modules/ace/lib/ace/lib/event_emitter.js b/node_modules/ace/lib/ace/lib/event_emitter.js new file mode 100644 index 00000000..b9860145 --- /dev/null +++ b/node_modules/ace/lib/ace/lib/event_emitter.js @@ -0,0 +1,155 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var EventEmitter = {}; +var stopPropagation = function() { this.propagationStopped = true; }; +var preventDefault = function() { this.defaultPrevented = true; }; + +EventEmitter._emit = +EventEmitter._dispatchEvent = function(eventName, e) { + this._eventRegistry || (this._eventRegistry = {}); + this._defaultHandlers || (this._defaultHandlers = {}); + + var listeners = this._eventRegistry[eventName] || []; + var defaultHandler = this._defaultHandlers[eventName]; + if (!listeners.length && !defaultHandler) + return; + + if (typeof e != "object" || !e) + e = {}; + + if (!e.type) + e.type = eventName; + if (!e.stopPropagation) + e.stopPropagation = stopPropagation; + if (!e.preventDefault) + e.preventDefault = preventDefault; + + listeners = listeners.slice(); + for (var i=0; i 0) { + if (count & 1) + result += string; + + if (count >>= 1) + string += string; + } + return result; +}; + +var trimBeginRegexp = /^\s\s*/; +var trimEndRegexp = /\s\s*$/; + +exports.stringTrimLeft = function (string) { + return string.replace(trimBeginRegexp, ''); +}; + +exports.stringTrimRight = function (string) { + return string.replace(trimEndRegexp, ''); +}; + +exports.copyObject = function(obj) { + var copy = {}; + for (var key in obj) { + copy[key] = obj[key]; + } + return copy; +}; + +exports.copyArray = function(array){ + var copy = []; + for (var i=0, l=array.length; i + * Provides an augmented, extensible, cross-browser implementation of regular expressions, + * including support for additional syntax, flags, and methods + */ + +define(function(require, exports, module) { +"use strict"; + + //--------------------------------- + // Private variables + //--------------------------------- + + var real = { + exec: RegExp.prototype.exec, + test: RegExp.prototype.test, + match: String.prototype.match, + replace: String.prototype.replace, + split: String.prototype.split + }, + compliantExecNpcg = real.exec.call(/()??/, "")[1] === undefined, // check `exec` handling of nonparticipating capturing groups + compliantLastIndexIncrement = function () { + var x = /^/g; + real.test.call(x, ""); + return !x.lastIndex; + }(); + + if (compliantLastIndexIncrement && compliantExecNpcg) + return; + + //--------------------------------- + // Overriden native methods + //--------------------------------- + + // Adds named capture support (with backreferences returned as `result.name`), and fixes two + // cross-browser issues per ES3: + // - Captured values for nonparticipating capturing groups should be returned as `undefined`, + // rather than the empty string. + // - `lastIndex` should not be incremented after zero-length matches. + RegExp.prototype.exec = function (str) { + var match = real.exec.apply(this, arguments), + name, r2; + if ( typeof(str) == 'string' && match) { + // Fix browsers whose `exec` methods don't consistently return `undefined` for + // nonparticipating capturing groups + if (!compliantExecNpcg && match.length > 1 && indexOf(match, "") > -1) { + r2 = RegExp(this.source, real.replace.call(getNativeFlags(this), "g", "")); + // Using `str.slice(match.index)` rather than `match[0]` in case lookahead allowed + // matching due to characters outside the match + real.replace.call(str.slice(match.index), r2, function () { + for (var i = 1; i < arguments.length - 2; i++) { + if (arguments[i] === undefined) + match[i] = undefined; + } + }); + } + // Attach named capture properties + if (this._xregexp && this._xregexp.captureNames) { + for (var i = 1; i < match.length; i++) { + name = this._xregexp.captureNames[i - 1]; + if (name) + match[name] = match[i]; + } + } + // Fix browsers that increment `lastIndex` after zero-length matches + if (!compliantLastIndexIncrement && this.global && !match[0].length && (this.lastIndex > match.index)) + this.lastIndex--; + } + return match; + }; + + // Don't override `test` if it won't change anything + if (!compliantLastIndexIncrement) { + // Fix browser bug in native method + RegExp.prototype.test = function (str) { + // Use the native `exec` to skip some processing overhead, even though the overriden + // `exec` would take care of the `lastIndex` fix + var match = real.exec.call(this, str); + // Fix browsers that increment `lastIndex` after zero-length matches + if (match && this.global && !match[0].length && (this.lastIndex > match.index)) + this.lastIndex--; + return !!match; + }; + } + + //--------------------------------- + // Private helper functions + //--------------------------------- + + function getNativeFlags (regex) { + return (regex.global ? "g" : "") + + (regex.ignoreCase ? "i" : "") + + (regex.multiline ? "m" : "") + + (regex.extended ? "x" : "") + // Proposed for ES4; included in AS3 + (regex.sticky ? "y" : ""); + } + + function indexOf (array, item, from) { + if (Array.prototype.indexOf) // Use the native array method if available + return array.indexOf(item, from); + for (var i = from || 0; i < array.length; i++) { + if (array[i] === item) + return i; + } + return -1; + } + +}); diff --git a/node_modules/ace/lib/ace/lib/useragent.js b/node_modules/ace/lib/ace/lib/useragent.js new file mode 100644 index 00000000..0d1d9f4d --- /dev/null +++ b/node_modules/ace/lib/ace/lib/useragent.js @@ -0,0 +1,106 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +/* + * I hate doing this, but we need some way to determine if the user is on a Mac + * The reason is that users have different expectations of their key combinations. + * + * Take copy as an example, Mac people expect to use CMD or APPLE + C + * Windows folks expect to use CTRL + C + */ +exports.OS = { + LINUX: "LINUX", + MAC: "MAC", + WINDOWS: "WINDOWS" +}; + +/* + * Return an exports.OS constant + */ +exports.getOS = function() { + if (exports.isMac) { + return exports.OS.MAC; + } else if (exports.isLinux) { + return exports.OS.LINUX; + } else { + return exports.OS.WINDOWS; + } +}; + +// this can be called in non browser environments (e.g. from ace/requirejs/text) +if (typeof navigator != "object") + return; + +var os = (navigator.platform.match(/mac|win|linux/i) || ["other"])[0].toLowerCase(); +var ua = navigator.userAgent; + +// Is the user using a browser that identifies itself as Windows +exports.isWin = (os == "win"); + +// Is the user using a browser that identifies itself as Mac OS +exports.isMac = (os == "mac"); + +// Is the user using a browser that identifies itself as Linux +exports.isLinux = (os == "linux"); + +// Windows Store JavaScript apps (aka Metro apps written in HTML5 and JavaScript) do not use the "Microsoft Internet Explorer" string in their user agent, but "MSAppHost" instead. +exports.isIE = + (navigator.appName == "Microsoft Internet Explorer" || navigator.appName.indexOf("MSAppHost") >= 0) + ? parseFloat((ua.match(/(?:MSIE |Trident\/[0-9]+[\.0-9]+;.*rv:)([0-9]+[\.0-9]+)/)||[])[1]) + : parseFloat((ua.match(/(?:Trident\/[0-9]+[\.0-9]+;.*rv:)([0-9]+[\.0-9]+)/)||[])[1]); // for ie + +exports.isOldIE = exports.isIE && exports.isIE < 9; + +// Is this Firefox or related? +exports.isGecko = exports.isMozilla = (window.Controllers || window.controllers) && window.navigator.product === "Gecko"; + +// oldGecko == rev < 2.0 +exports.isOldGecko = exports.isGecko && parseInt((ua.match(/rv\:(\d+)/)||[])[1], 10) < 4; + +// Is this Opera +exports.isOpera = window.opera && Object.prototype.toString.call(window.opera) == "[object Opera]"; + +// Is the user using a browser that identifies itself as WebKit +exports.isWebKit = parseFloat(ua.split("WebKit/")[1]) || undefined; + +exports.isChrome = parseFloat(ua.split(" Chrome/")[1]) || undefined; + +exports.isAIR = ua.indexOf("AdobeAIR") >= 0; + +exports.isIPad = ua.indexOf("iPad") >= 0; + +exports.isTouchPad = ua.indexOf("TouchPad") >= 0; + +exports.isChromeOS = ua.indexOf(" CrOS ") >= 0; + +}); diff --git a/node_modules/ace/lib/ace/line_widgets.js b/node_modules/ace/lib/ace/line_widgets.js new file mode 100644 index 00000000..ba87d857 --- /dev/null +++ b/node_modules/ace/lib/ace/line_widgets.js @@ -0,0 +1,295 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("./lib/oop"); +var dom = require("./lib/dom"); +var Range = require("./range").Range; + + +function LineWidgets(session) { + this.session = session; + this.session.widgetManager = this; + this.session.getRowLength = this.getRowLength; + this.session.$getWidgetScreenLength = this.$getWidgetScreenLength; + this.updateOnChange = this.updateOnChange.bind(this); + this.renderWidgets = this.renderWidgets.bind(this); + this.measureWidgets = this.measureWidgets.bind(this); + this.session._changedWidgets = []; + this.$onChangeEditor = this.$onChangeEditor.bind(this); + + this.session.on("change", this.updateOnChange); + this.session.on("changeEditor", this.$onChangeEditor); +} + +(function() { + this.getRowLength = function(row) { + var h; + if (this.lineWidgets) + h = this.lineWidgets[row] && this.lineWidgets[row].rowCount || 0; + else + h = 0; + if (!this.$useWrapMode || !this.$wrapData[row]) { + return 1 + h; + } else { + return this.$wrapData[row].length + 1 + h; + } + }; + + this.$getWidgetScreenLength = function() { + var screenRows = 0; + this.lineWidgets.forEach(function(w){ + if (w && w.rowCount) + screenRows +=w.rowCount; + }); + return screenRows; + }; + + this.$onChangeEditor = function(e) { + this.attach(e.editor); + }; + + this.attach = function(editor) { + if (editor && editor.widgetManager && editor.widgetManager != this) + editor.widgetManager.detach(); + + if (this.editor == editor) + return; + + this.detach(); + this.editor = editor; + + if (editor) { + editor.widgetManager = this; + editor.renderer.on("beforeRender", this.measureWidgets); + editor.renderer.on("afterRender", this.renderWidgets); + } + }; + this.detach = function(e) { + var editor = this.editor; + if (!editor) + return; + + this.editor = null; + editor.widgetManager = null; + + editor.renderer.off("beforeRender", this.measureWidgets); + editor.renderer.off("afterRender", this.renderWidgets); + var lineWidgets = this.session.lineWidgets; + lineWidgets && lineWidgets.forEach(function(w) { + if (w && w.el && w.el.parentNode) { + w._inDocument = false; + w.el.parentNode.removeChild(w.el); + } + }); + }; + + this.updateOnChange = function(delta) { + var lineWidgets = this.session.lineWidgets; + if (!lineWidgets) return; + + var startRow = delta.start.row; + var len = delta.end.row - startRow; + + if (len === 0) { + // return + } else if (delta.action == 'remove') { + var removed = lineWidgets.splice(startRow + 1, len); + removed.forEach(function(w) { + w && this.removeLineWidget(w); + }, this); + this.$updateRows(); + } else { + var args = new Array(len); + args.unshift(startRow, 0); + lineWidgets.splice.apply(lineWidgets, args); + this.$updateRows(); + } + }; + + this.$updateRows = function() { + var lineWidgets = this.session.lineWidgets; + if (!lineWidgets) return; + var noWidgets = true; + lineWidgets.forEach(function(w, i) { + if (w) { + noWidgets = false; + w.row = i; + } + }); + if (noWidgets) + this.session.lineWidgets = null; + }; + + this.addLineWidget = function(w) { + if (!this.session.lineWidgets) + this.session.lineWidgets = new Array(this.session.getLength()); + + this.session.lineWidgets[w.row] = w; + + var renderer = this.editor.renderer; + if (w.html && !w.el) { + w.el = dom.createElement("div"); + w.el.innerHTML = w.html; + } + if (w.el) { + dom.addCssClass(w.el, "ace_lineWidgetContainer"); + w.el.style.position = "absolute"; + w.el.style.zIndex = 5; + renderer.container.appendChild(w.el); + w._inDocument = true; + } + + if (!w.coverGutter) { + w.el.style.zIndex = 3; + } + if (!w.pixelHeight) { + w.pixelHeight = w.el.offsetHeight; + } + if (w.rowCount == null) + w.rowCount = w.pixelHeight / renderer.layerConfig.lineHeight; + + this.session._emit("changeFold", {data:{start:{row: w.row}}}); + + this.$updateRows(); + this.renderWidgets(null, renderer); + return w; + }; + + this.removeLineWidget = function(w) { + w._inDocument = false; + if (w.el && w.el.parentNode) + w.el.parentNode.removeChild(w.el); + if (w.editor && w.editor.destroy) try { + w.editor.destroy(); + } catch(e){} + if (this.session.lineWidgets) + this.session.lineWidgets[w.row] = undefined; + this.session._emit("changeFold", {data:{start:{row: w.row}}}); + this.$updateRows(); + }; + + this.onWidgetChanged = function(w) { + this.session._changedWidgets.push(w); + this.editor && this.editor.renderer.updateFull(); + }; + + this.measureWidgets = function(e, renderer) { + var changedWidgets = this.session._changedWidgets; + var config = renderer.layerConfig; + + if (!changedWidgets || !changedWidgets.length) return; + var min = Infinity; + for (var i = 0; i < changedWidgets.length; i++) { + var w = changedWidgets[i]; + if (!w._inDocument) { + w._inDocument = true; + renderer.container.appendChild(w.el); + } + + w.h = w.el.offsetHeight; + + if (!w.fixedWidth) { + w.w = w.el.offsetWidth; + w.screenWidth = Math.ceil(w.w / config.characterWidth); + } + + var rowCount = w.h / config.lineHeight; + if (w.coverLine) { + rowCount -= this.session.getRowLineCount(w.row); + if (rowCount < 0) + rowCount = 0; + } + if (w.rowCount != rowCount) { + w.rowCount = rowCount; + if (w.row < min) + min = w.row; + } + } + if (min != Infinity) { + this.session._emit("changeFold", {data:{start:{row: min}}}); + this.session.lineWidgetWidth = null; + } + this.session._changedWidgets = []; + }; + + this.renderWidgets = function(e, renderer) { + var config = renderer.layerConfig; + var lineWidgets = this.session.lineWidgets; + if (!lineWidgets) + return; + var first = Math.min(this.firstRow, config.firstRow); + var last = Math.max(this.lastRow, config.lastRow, lineWidgets.length); + + while (first > 0 && !lineWidgets[first]) + first--; + + this.firstRow = config.firstRow; + this.lastRow = config.lastRow; + + renderer.$cursorLayer.config = config; + for (var i = first; i <= last; i++) { + var w = lineWidgets[i]; + if (!w || !w.el) continue; + + if (!w._inDocument) { + w._inDocument = true; + renderer.container.appendChild(w.el); + } + var top = renderer.$cursorLayer.getPixelPosition({row: i, column:0}, true).top; + if (!w.coverLine) + top += config.lineHeight * this.session.getRowLineCount(w.row); + w.el.style.top = top - config.offset + "px"; + + var left = w.coverGutter ? 0 : renderer.gutterWidth; + if (!w.fixedWidth) + left -= renderer.scrollLeft; + w.el.style.left = left + "px"; + + if (w.fixedWidth) { + w.el.style.right = renderer.scrollBar.getWidth() + "px"; + } else { + w.el.style.right = ""; + } + } + }; + +}).call(LineWidgets.prototype); + + +exports.LineWidgets = LineWidgets; + +}); + + + + diff --git a/node_modules/ace/lib/ace/mode/_test/Readme.md b/node_modules/ace/lib/ace/mode/_test/Readme.md new file mode 100644 index 00000000..c2871c0d --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/Readme.md @@ -0,0 +1,9 @@ +`tokens_.json` files keep information about correct tokens and tokenizer states for all modes supported by ace. +They are generated from `text_.txt` or `demo/kitchen-sink/doc/*` with + +```sh +node highlight_rules_test.js -gen +``` + +command. + diff --git a/node_modules/ace/lib/ace/mode/_test/highlight_rules_test.js b/node_modules/ace/lib/ace/mode/_test/highlight_rules_test.js new file mode 100644 index 00000000..c3b877ec --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/highlight_rules_test.js @@ -0,0 +1,210 @@ +var fs = require("fs"); +var path = require("path"); +if (!fs.existsSync) + fs.existsSync = path.existsSync; + +require("amd-loader"); + +var cwd = __dirname + "/"; +var root = path.normalize(cwd + Array(5).join("../")); + +function jsFileList(path, filter) { + if (!filter) filter = /_test/; + return fs.readdirSync(path).map(function(x) { + if (x.slice(-3) == ".js" && !filter.test(x) && !/\s/.test(x)) + return x.slice(0, -3); + }).filter(Boolean); +} + +function modeList() { + return jsFileList(cwd + "../", /_highlight_rules|_test|_worker|xml_util|_outdent|behaviour|completions/); +} + +function checkModes() { + modeList().forEach(function(modeName) { + try { + var Mode = require("../" + modeName).Mode; + } catch(e) { + console.warn("Can't load mode :" + modeName, e); + return; + } + var m = new Mode(); + if (!m.lineCommentStart && !m.blockComment) + console.warn("missing comment in " + modeName); + if (!m.$id) + console.warn("missing id in " + modeName); + var tokenizer = (new Mode).getTokenizer(); + if (m.lineCommentStart) { + if (Array.isArray(m.lineCommentStart)) { + m.lineCommentStart.forEach(function(x) { + testLineComment(tokenizer, x, modeName) + }); + } else { + testLineComment(tokenizer, m.lineCommentStart, modeName) + } + } + // if (m.blockComment) { + // var tokens = tok.getLineTokens(m.lineCommentStart, "start"); + // if (!/comment/.test(tokens[0])) + // console.warn("broken lineCommentStart in " + modeName); + // } + }); + + function testLineComment(tokenizer, commentStart, modeName) { + var tokens = tokenizer.getLineTokens(commentStart + " ", "start").tokens; + if (!/comment/.test(tokens[0].type)) + console.warn("broken lineCommentStart in " + modeName); + } +} + +function generateTestData() { + var docRoot = root + "/demo/kitchen-sink/docs"; + var docs = fs.readdirSync(docRoot); + var specialDocs = fs.readdirSync(cwd); + var modes = modeList(); + + // console.log("Docs:", docs); + // console.log("Modes:", modes); + + docs.forEach(function(docName) { + var p = docName.toLowerCase().split("."); + if (!p[1]) + return; + var modeName; + if (modes.indexOf(p[0]) != -1) + modeName = p[0]; + else if (modes.indexOf(p[1]) != -1) + modeName = p[1]; + else + modeName = {"txt": "text", cpp: "c_cpp"}[p[1]]; + + var filePath = "text_" + modeName + ".txt"; + if (specialDocs.indexOf(filePath) == -1) { + filePath = docRoot + "/" + docName; + } else { + filePath = cwd + filePath; + } + + var text = fs.readFileSync(filePath, "utf8"); + try { + var Mode = require("../" + modeName).Mode; + } catch(e) { + console.warn("Can't load mode :" + modeName, p, e); + return; + } + console.log(modeName); + var tokenizer = new Mode().getTokenizer(); + + var state = "start"; + var data = text.split(/\r\n|\r|\n/).map(function(line) { + var data = tokenizer.getLineTokens(line, state); + var tmp = []; + tmp.push(JSON.stringify(data.state)); + var tokenizedLine = ""; + data.tokens.forEach(function(x) { + tokenizedLine += x.value; + tmp.push(JSON.stringify([x.type, x.value])); + }); + if (tokenizedLine != line) + tmp.push(JSON.stringify(line)); + state = data.state; + return tmp.join(",\n "); + }); + + var jsonStr = "[[\n " + data.join("\n],[\n ") + "\n]]"; + fs.writeFileSync(cwd + "tokens_" + modeName + ".json", jsonStr, "utf8"); + }); +} + +function test(startAt) { + var modes = fs.readdirSync(cwd).map(function(x) { + return (x.match(/tokens_(.*).json/) || {})[1]; + }).filter(function(x){return !!x}); + + for (var i = Math.max(0, startAt||0); i < modes.length; i++) + testMode(modes[i], i); + + console.log("\u001b[32m" + "all ok" + "\u001b[0m"); +} +function testMode(modeName, i) { + console.log(padNumber(i+1, 3) + ") testing: \u001b[33m" + modeName + "\u001b[0m"); + + var text = fs.readFileSync(cwd + "tokens_" + modeName + ".json", "utf8"); + var data = JSON.parse(text); + var Mode = require("../" + modeName).Mode; + var tokenizer = new Mode().getTokenizer(); + + var state = "start"; + data.forEach(function(lineData) { + lineData.values = []; + lineData.types = []; + lineData.state = lineData.shift(); + var line = null; + if (typeof lineData[lineData.length - 1] == "string") + line = lineData.pop(); + lineData.forEach(function(x) { + lineData.types.push(x[0]); + lineData.values.push(x[1]); + }); + if (typeof line != "string") + line = lineData.values.join(""); + + var tokens = tokenizer.getLineTokens(line, state); + var values = tokens.tokens.map(function(x) {return x.value;}); + var types = tokens.tokens.map(function(x) {return x.type;}); + + var err = testEqual([ + JSON.stringify(lineData.state), JSON.stringify(tokens.state), + lineData.types, types, + lineData.values, values]); + + if (err) { + console.log(line); + throw "error"; + } + + state = tokens.state; + }); +} +function testEqual(a) { + var err; + if (a[0] + "" !== a[1] + "") { + console.log(a[0],a[1]); + err = 1; + } + + if ( a[2] + "" !== a[3] + "" || a[4] + "" !== a[5] + "") { + arrayDiff(a[2],a[3]); + arrayDiff(a[4],a[5]); + err = 1; + } + return err; +} +function arrayDiff(a1, a2) { + var l = Math.max(a1.length, a2.length); + var out = []; + for (var i = 0; i < l; i++) { + out.push("\n", padNumber(i+1, 3), ") "); + if (a1[i] !== a2[i]) + out.push("\u001b[31m", a1[i], "\u001b[0m != \u001b[32m", a2[i], "\u001b[0m"); + else + out.push(a1[i]); + } + console.log(out.join("")); +} +function padNumber(num, digits) { + return (" " + num).slice(-digits); +} + +// cli +var arg = process.argv[2]; +if (!arg) + test(); +else if (/--?g(en)?/.test(arg)) + generateTestData(process.argv.splice(3)); +else if (/--?c(heck)?/.test(arg)) + checkModes(process.argv.splice(3)); +else if (/\d+/.test(arg)) + test(parseInt(process.argv[2],10) || 0); +else + testMode(arg, -1); \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/package.json b/node_modules/ace/lib/ace/mode/_test/package.json new file mode 100644 index 00000000..3fdc706d --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/package.json @@ -0,0 +1,8 @@ +{ + "name": "ace-mode-creator", + "version": "0.1.0", + "dependencies": { + "connect": "", + "socket.io": "" + } +} \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/text_asciidoc.txt b/node_modules/ace/lib/ace/mode/_test/text_asciidoc.txt new file mode 100644 index 00000000..af7eaecc --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/text_asciidoc.txt @@ -0,0 +1,111 @@ +------------------------------------ +----------------------------------- +_ita_lic_, *bo*ld*, +mo+no+, normal. +``double quoted'', `single quoted'. + normal, ^super^, ~sub~. + +'''' +Escaped: +\_italic_, +++_italic_+++, +t\__e__st, +++t__e__st+++, ++++bold+++, $$normal$$ +\¶ ¶ +\`not single quoted' +\`\`not double quoted'' + + +[fffff] ++++++++++++++++++++++++++++++++++++++ +(C) {ss} ss ++++++++++++++++++++++++++++++++++++++ + +............. +callout <1> +.............. + +> 1 +1> 2 +<2> 3 + +Escaped: +\_italic_, +t\__e__st, o__ + +.optional title +............. +callout <1> +.............. + + +:macro: dddd + +.lists +. 1 +.. 2 +... d +..... big ++ +continue + +next line +xi) no ++la+tin++ + +xi) la++tin++ +2. num__ber__ [red]#red# +-- + 5. f <> {macro} +-- +image::path[beauty] ->--<= -- replacements + + image::s +sssss +sss +sssss + + +== 1 + heading +=== not a heading +==================================== + +================================== +====4 +NOTE: above + +NOTE: above + +[[x6]] +WARNING: + +[options[]] +--------------------------- +literal +--------------------------- + + += Tables +|==================================== +| _italic_ | *bold* | text | (R) + +|==================================== + + +[more, options] +/////////// +comment +/////////// +// one line comment + + + +[red]#red text# [yellow-background]#on yellow# +[big]#large# [red yellow-background big]*all bold* + + +https://site text callto:ace http://ace.ajaxorg.com[awesome] + .still normal text +.break out thoug should not +--------------------------- +/////////////////////////// +--------------------------- + + diff --git a/node_modules/ace/lib/ace/mode/_test/text_coffee.txt b/node_modules/ace/lib/ace/mode/_test/text_coffee.txt new file mode 100644 index 00000000..2d9ba5ad --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/text_coffee.txt @@ -0,0 +1,57 @@ +#test: tokenize keyword + for (i 1..2) +#test: tokenize regexp +/"[a]/ +#test: tokenize functions +foo = ({args}) -> + foo = ({a1, a2}) -> + foo = ({@a1, a2}) -> + foo : ({args}) -> + foo = ({args}) -> + foo = ({0abc}) -> + foo = ({/abc}) => + foo = ({abc/}) -> + foo = ({#abc}) -> + foo = ({abc#}) -> + foo = ({)abc}) -> + foo = ({abc)}) -> + foo = ({a{bc}) -> + foo = ({}) -> + foo = ({ }) -> + foo : ({}) -> + foo = (args) -> + foo = (arg1, arg2) -> + foo = (arg1 = 1, arg2 = 'name') -> + foo = (@arg1 = /abc/, arg2 = 'name') -> + #test: tokenize function: invalid case: + foo=(/args) -> + foo = () -> + foo = ( ) -> + foo : ( ) -> + window.foo = (args) -> + foo = -> + foo = -> + foo : -> + #test: tokenize callback function + foo bar: 1, (args) -> + foo = (1, 2 (x) -> +#test: tokenize class +class Foo +class Foo extends Bar +#test: tokenize illegal name property +foo.static.function +#!test tokenize string with interpolation +a = "#{ 22 / 7 + {x: "#{a + b}"} + 2}" +" #{ "" + {} } )" +"""heredoc + """ +do -> + ### + herecomment + ### + re = /regex/imgy.test /// + heregex # comment + ///imgy + this isnt: `just + JavaScript` + undefined diff --git a/node_modules/ace/lib/ace/mode/_test/text_curly.txt b/node_modules/ace/lib/ace/mode/_test/text_curly.txt new file mode 100644 index 00000000..1be54b59 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/text_curly.txt @@ -0,0 +1,9 @@ +tokenize Curly template{{test}} +tokenize embedded script +'123' +tokenize multiline attribute value with double quotes + +tokenize multiline attribute value with single quotes + diff --git a/node_modules/ace/lib/ace/mode/_test/text_html.txt b/node_modules/ace/lib/ace/mode/_test/text_html.txt new file mode 100644 index 00000000..d2ce8aaa --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/text_html.txt @@ -0,0 +1,10 @@ + + +'123' + + + + + \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/text_javascript.txt b/node_modules/ace/lib/ace/mode/_test/text_javascript.txt new file mode 100644 index 00000000..48d4af7d --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/text_javascript.txt @@ -0,0 +1,86 @@ +//test: tokenize 'standard' functions +string.charCodeAt(23); document.getElementById('test'); console.log('Here it is');"; +test: /**tokenize doc*/ comment +/**tokenize doc comment with @tag {}*/ +//test: tokenize parens + var line = "[{( )}]"; +//test tokenize arithmetic expression which looks like a regexp +a/b/c +a/=b/c +//test tokenize reg exps +a=/b/g +a+/b/g +a = 1 + /2 + 1/gimyxk +a=/a/ / /a/ +case /a/.test(c) +//test tokenize multi-line comment containing a single line comment +noRegex +/* foo // bar */ +canBeRegex; +/* foo // bar */ +// test tokenize identifier with umlauts +fu?e +// test // is not a regexp +{ // 123 +//test skipping escaped chars +'Meh\\nNeh' +console.log('\\u1232Feh' +"test multiline\ + strings" +a=' +b="\ +still a string + + +function foo(items, nada) { + for (var i=0; ihttp://ace.ajaxorg.com + diff --git a/node_modules/ace/lib/ace/mode/_test/text_php.txt b/node_modules/ace/lib/ace/mode/_test/text_php.txt new file mode 100644 index 00000000..b76aa8a5 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/text_php.txt @@ -0,0 +1,24 @@ + not &js; diff --git a/node_modules/ace/lib/ace/mode/_test/text_ruby.txt b/node_modules/ace/lib/ace/mode/_test/text_ruby.txt new file mode 100644 index 00000000..c16ff7c5 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/text_ruby.txt @@ -0,0 +1,34 @@ + #test: symbol tokenizer + [:@thing, :$thing, :_thing, :thing, :Thing, :thing1, :thing_a, + :THING, :thing!, :thing=, :thing?, :t?, + :, :@, :$, :1, :1thing, :th?ing, :thi=ng, :1thing, + :th!ing, :thing# + ] + + #test: namespaces aren't symbols" : function() { + Namespaced::Class + #test: hex tokenizer + 0x9a, 0XA1, 0x9_a, 0x, 0x_9a, 0x9a_, + #test: float tokenizer + [1, +1, -1, 12_345, 0.000_1, + _, 3_1, 1_2, 1_.0, 0._1]; + +{:id => ?", :key => "value", anotherKey: [x, y?]} + +=begin +=end + +=begin x +=end- +=end x + + herDocs = [<<'FOO', <//Juhu Kinners +test: two tags in the same lines should be in separate tokens" + +test: multiline attributes" + \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_abap.json b/node_modules/ace/lib/ace/mode/_test/tokens_abap.json new file mode 100644 index 00000000..95f2f811 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_abap.json @@ -0,0 +1,189 @@ +[[ + "start", + ["doc.comment","***************************************"] +],[ + "start", + ["doc.comment","** Program: EXAMPLE **"] +],[ + "start", + ["doc.comment","** Author: Joe Byte, 07-Jul-2007 **"] +],[ + "start", + ["doc.comment","***************************************"] +],[ + "start", + ["text"," "] +],[ + "start", + ["keyword","REPORT"], + ["text"," BOOKINGS"], + ["keyword.operator","."] +],[ + "start", + ["text"," "] +],[ + "start", + ["doc.comment","* Read flight bookings from the database"] +],[ + "start", + ["keyword","SELECT"], + ["keyword.operator"," * "], + ["keyword","FROM"], + ["text"," FLIGHTINFO"] +],[ + "start", + ["text"," "], + ["keyword","WHERE"], + ["text"," "], + ["keyword","CLASS"], + ["keyword.operator"," = "], + ["string","'Y'"], + ["text"," "], + ["comment","\"Y = economy"] +],[ + "start", + ["text"," "], + ["keyword","OR"], + ["text"," "], + ["keyword","CLASS"], + ["keyword.operator"," = "], + ["string","'C'"], + ["keyword.operator","."], + ["text"," "], + ["comment","\"C = business"] +],[ + "start", + ["paren.lparen","("], + ["invalid","..."], + ["paren.rparen",")"] +],[ + "start" +],[ + "start", + ["keyword","REPORT"], + ["text"," TEST"], + ["keyword.operator","."] +],[ + "start", + ["keyword","WRITE"], + ["text"," "], + ["string","'Hello World'"], + ["keyword.operator","."] +],[ + "start" +],[ + "start", + ["text","USERPROMPT"], + ["keyword.operator"," = "], + ["string","'Please double-click on a line in the output list '"], + ["text"," "], + ["keyword.operator","&"] +],[ + "start", + ["text"," "], + ["string","'to see the complete details of the transaction.'"], + ["keyword.operator","."] +],[ + "start" +],[ + "start" +],[ + "start", + ["keyword","DATA"], + ["text"," LAST_EOM "], + ["keyword","TYPE"], + ["text"," "], + ["support.type","D"], + ["keyword.operator","."], + ["text"," "], + ["comment","\"last end-of-month date"] +],[ + "start", + ["text"," "] +],[ + "start", + ["doc.comment","* Start from today's date"] +],[ + "start", + ["text"," LAST_EOM"], + ["keyword.operator"," = "], + ["variable.parameter","SY"], + ["keyword.operator","-"], + ["text","DATUM"], + ["keyword.operator","."] +],[ + "start", + ["doc.comment","* Set characters 6 and 7 (0-relative) of the YYYYMMDD string to \"01\","] +],[ + "start", + ["doc.comment","* giving the first day of the current month"] +],[ + "start", + ["text"," LAST_EOM"], + ["constant.numeric","+6"], + ["paren.lparen","("], + ["constant.numeric","2"], + ["paren.rparen",")"], + ["keyword.operator"," = "], + ["string","'01'"], + ["keyword.operator","."] +],[ + "start", + ["doc.comment","* Subtract one day"] +],[ + "start", + ["text"," LAST_EOM"], + ["keyword.operator"," = "], + ["text","LAST_EOM"], + ["keyword.operator"," - "], + ["constant.numeric","1"], + ["keyword.operator","."] +],[ + "start", + ["text"," "] +],[ + "start", + ["text"," "], + ["keyword","WRITE"], + ["keyword.operator",":"], + ["text"," "], + ["string","'Last day of previous month was'"], + ["keyword.operator",","], + ["text"," LAST_EOM"], + ["keyword.operator","."] +],[ + "start", + ["text"," "] +],[ + "start", + ["keyword","DATA"], + ["text"," "], + ["keyword.operator",":"], + ["text"," "], + ["keyword","BEGIN OF"], + ["text"," I_VBRK "], + ["keyword","OCCURS"], + ["text"," "], + ["constant.numeric","0"], + ["keyword.operator",","] +],[ + "start", + ["text"," VBELN "], + ["keyword","LIKE"], + ["text"," "], + ["variable.parameter","VBRK-VBELN"], + ["keyword.operator",","] +],[ + "start", + ["text"," ZUONR "], + ["keyword","LIKE"], + ["text"," "], + ["variable.parameter","VBRK-ZUONR"], + ["keyword.operator",","] +],[ + "start", + ["text"," "], + ["keyword","END OF"], + ["text"," I_VBRK"], + ["keyword.operator","."] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_abc.json b/node_modules/ace/lib/ace/mode/_test/tokens_abc.json new file mode 100644 index 00000000..c65ae2a5 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_abc.json @@ -0,0 +1,2207 @@ +[[ + "start", + ["comment.line.percentage","%abc-2.1"] +],[ + "start", + ["information.keyword","H:"], + ["information.argument.string.unquoted","This file contains some example English tunes"] +],[ + "start", + ["comment.line.percentage","% note that the comments (like this one) are to highlight usages"] +],[ + "start", + ["comment.line.percentage","% and would not normally be included in such detail"] +],[ + "start", + ["information.keyword","O:"], + ["information.argument.string.unquoted","England "], + ["comment.line.percentage","% the origin of all tunes is England"] +],[ + "start" +],[ + "start", + ["information.keyword","X:"], + ["information.argument.string.unquoted","1 "], + ["comment.line.percentage","% tune no 1"] +],[ + "start", + ["information.keyword","T:"], + ["information.argument.string.unquoted","Dusty Miller, The "], + ["comment.line.percentage","% title"] +],[ + "start", + ["information.keyword","T:"], + ["information.argument.string.unquoted","Binny's Jig "], + ["comment.line.percentage","% an alternative title"] +],[ + "start", + ["information.keyword","C:"], + ["information.argument.string.unquoted","Trad. "], + ["comment.line.percentage","% traditional"] +],[ + "start", + ["information.keyword","R:"], + ["information.argument.string.unquoted","DH "], + ["comment.line.percentage","% double hornpipe"] +],[ + "start", + ["information.keyword","M:"], + ["information.argument.string.unquoted","3/4 "], + ["comment.line.percentage","% meter"] +],[ + "start", + ["information.keyword","K:"], + ["information.argument.string.unquoted","G "], + ["comment.line.percentage","% key"] +],[ + "start", + ["pitch.constant.numeric","B"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","c"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","D"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator",":|"] +],[ + "start", + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["pitch.constant.numeric","g"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","c"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["pitch.constant.numeric","a"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator",":|"] +],[ + "start", + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","/2"], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","/2"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","c"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","/2"], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","/2"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","D"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator",":|"] +],[ + "start", + ["information.keyword","W:"], + ["information.argument.string.unquoted","Hey, the dusty miller, and his dusty coat;"] +],[ + "start", + ["information.keyword","W:"], + ["information.argument.string.unquoted","He will win a shilling, or he spend a groat."] +],[ + "start", + ["information.keyword","W:"], + ["information.argument.string.unquoted","Dusty was the coat, dusty was the colour;"] +],[ + "start", + ["information.keyword","W:"], + ["information.argument.string.unquoted","Dusty was the kiss, that I got frae the miller."] +],[ + "start" +],[ + "start", + ["information.keyword","X:"], + ["information.argument.string.unquoted","2"] +],[ + "start", + ["information.keyword","T:"], + ["information.argument.string.unquoted","Old Sir Simon the King"] +],[ + "start", + ["information.keyword","C:"], + ["information.argument.string.unquoted","Trad."] +],[ + "start", + ["information.keyword","S:"], + ["information.argument.string.unquoted","Offord MSS "], + ["comment.line.percentage","% from Offord manuscript"] +],[ + "start", + ["information.keyword","N:"], + ["information.argument.string.unquoted","see also Playford "], + ["comment.line.percentage","% reference note"] +],[ + "start", + ["information.keyword","M:"], + ["information.argument.string.unquoted","9/8"] +],[ + "start", + ["information.keyword","R:"], + ["information.argument.string.unquoted","SJ "], + ["comment.line.percentage","% slip jig"] +],[ + "start", + ["information.keyword","N:"], + ["information.argument.string.unquoted","originally in C "], + ["comment.line.percentage","% transcription note"] +],[ + "start", + ["information.keyword","K:"], + ["information.argument.string.unquoted","G"] +],[ + "start", + ["pitch.constant.numeric","D"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","D"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","F"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","D"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","E"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","E"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","F"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","E"], + ["text"," "], + ["pitch.constant.numeric","D"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator",":|"] +],[ + "start", + ["pitch.constant.numeric","D"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","D"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","D"], + ["barline.keyword.operator","|[1"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","E"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","E"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["text","["], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","G"], + ["text","] "], + ["pitch.constant.numeric","F"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","E"], + ["text"," "], + ["pitch.constant.numeric","D"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator",":|"], + ["text","\\ "], + ["comment.line.percentage","% no line-break in score"] +],[ + "start", + ["information.keyword","M:"], + ["information.argument.string.unquoted","12/8 "], + ["comment.line.percentage","% change of meter"] +],[ + "start", + ["barline.keyword.operator","[2"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","E"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","E"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","E"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["text","\\ "], + ["comment.line.percentage","% no line-break in score"] +],[ + "start", + ["information.keyword","M:"], + ["information.argument.string.unquoted","9/8 "], + ["comment.line.percentage","% change of meter"] +],[ + "start", + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","F"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","E"], + ["text"," "], + ["pitch.constant.numeric","D"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator","|]"] +],[ + "start" +],[ + "start", + ["information.keyword","X:"], + ["information.argument.string.unquoted","3"] +],[ + "start", + ["information.keyword","T:"], + ["information.argument.string.unquoted","William and Nancy"] +],[ + "start", + ["information.keyword","T:"], + ["information.argument.string.unquoted","New Mown Hay"] +],[ + "start", + ["information.keyword","T:"], + ["information.argument.string.unquoted","Legacy, The"] +],[ + "start", + ["information.keyword","C:"], + ["information.argument.string.unquoted","Trad."] +],[ + "start", + ["information.keyword","O:"], + ["information.argument.string.unquoted","England; Gloucs; Bledington "], + ["comment.line.percentage","% place of origin"] +],[ + "start", + ["information.keyword","B:"], + ["information.argument.string.unquoted","Sussex Tune Book "], + ["comment.line.percentage","% can be found in these books"] +],[ + "start", + ["information.keyword","B:"], + ["information.argument.string.unquoted","Mally's Cotswold Morris vol.1 2"] +],[ + "start", + ["information.keyword","D:"], + ["information.argument.string.unquoted","Morris On "], + ["comment.line.percentage","% can be heard on this record"] +],[ + "start", + ["information.keyword","P:"], + ["information.argument.string.unquoted","(AB)2(AC)2A "], + ["comment.line.percentage","% play the parts in this order"] +],[ + "start", + ["information.keyword","M:"], + ["information.argument.string.unquoted","6/8"] +],[ + "start", + ["information.keyword","K:"], + ["information.argument.string.unquoted","G "] +],[ + "start", + ["information.keyword.embedded","[P:"], + ["information.argument.string.unquoted","A]"], + ["text"," "], + ["pitch.constant.numeric","D"], + ["barline.keyword.operator","|"], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["string.quoted","\"C\""], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","e"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["string.quoted","\"D7\""], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["string.quoted","\"C\""], + ["pitch.constant.numeric","E"], + ["duration.constant.numeric","2"], + ["string.quoted","\"D7\""], + ["pitch.constant.numeric","F"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator",":|"] +],[ + "start", + ["information.keyword.embedded","[P:"], + ["information.argument.string.unquoted","B]"], + ["text"," "], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["string.quoted","\"C\""], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["pitch.constant.numeric","e"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["string.quoted","\"C\""], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["pitch.constant.numeric","e"], + ["text"," "], + ["string.quoted","\"D7\""], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","c"], + ["barline.keyword.operator","|"] +],[ + "start", + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["string.quoted","\"C\""], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","e"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["string.quoted","\"D7\""], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["string.quoted","\"C\""], + ["pitch.constant.numeric","E"], + ["duration.constant.numeric","2"], + ["string.quoted","\"D7\""], + ["pitch.constant.numeric","F"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator",":|"] +],[ + "start", + ["comment.line.percentage","% changes of meter, using inline fields"] +],[ + "start", + ["information.keyword.embedded","[T:"], + ["information.argument.string.unquoted","Slows]"], + ["information.keyword.embedded","[M:"], + ["information.argument.string.unquoted","4/4]"], + ["information.keyword.embedded","[L:"], + ["information.argument.string.unquoted","1/4]"], + ["information.keyword.embedded","[P:"], + ["information.argument.string.unquoted","C]"], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator","|"], + ["string.quoted","\"C\""], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","2"], + ["text"," "], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator","|"], + ["string.quoted","\"Em\""], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["text"," "], + ["string.quoted","\"A7\""], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator","|"], + ["string.quoted","\"D7\""], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator","|"], + ["text","\\"] +],[ + "start", + ["text"," "], + ["string.quoted","\"C\""], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator","|"], + ["information.keyword.embedded","[M:"], + ["information.argument.string.unquoted","3/8]"], + ["information.keyword.embedded","[L:"], + ["information.argument.string.unquoted","1/8]"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","2"], + ["text"," "], + ["pitch.constant.numeric","d"], + ["text"," "], + ["barline.keyword.operator","|"], + ["information.keyword.embedded","[M:"], + ["information.argument.string.unquoted","6/8]"], + ["text"," "], + ["string.quoted","\"C\""], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["pitch.constant.numeric","e"], + ["text"," "], + ["string.quoted","\"D7\""], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","c"], + ["barline.keyword.operator","|"] +],[ + "start", + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["string.quoted","\"C\""], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","e"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["string.quoted","\"D7\""], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["string.quoted","\"C\""], + ["pitch.constant.numeric","E"], + ["duration.constant.numeric","2"], + ["string.quoted","\"D7\""], + ["pitch.constant.numeric","F"], + ["text"," "], + ["string.quoted","\"G\""], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator",":|"] +],[ + "start" +],[ + "start", + ["information.keyword","X:"], + ["information.argument.string.unquoted","4"] +],[ + "start", + ["information.keyword","T:"], + ["information.argument.string.unquoted","South Downs Jig"] +],[ + "start", + ["information.keyword","R:"], + ["information.argument.string.unquoted","jig"] +],[ + "start", + ["information.keyword","S:"], + ["information.argument.string.unquoted","Robert Harbron"] +],[ + "start", + ["information.keyword","M:"], + ["information.argument.string.unquoted","6/8"] +],[ + "start", + ["information.keyword","L:"], + ["information.argument.string.unquoted","1/8"] +],[ + "start", + ["information.keyword","K:"], + ["information.argument.string.unquoted","G"] +],[ + "start", + ["barline.keyword.operator","|:"], + ["text"," "], + ["pitch.constant.numeric","d"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text"," "], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","3"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","E"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text"," "], + ["pitch.constant.numeric","D"], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text"," "], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","e"], + ["text"," "], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["barline.keyword.operator","|"] +],[ + "start", + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","3"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","E"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text"," "], + ["pitch.constant.numeric","D"], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text"," "], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","F"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","2"], + ["text"," "], + ["barline.keyword.operator",":|"] +],[ + "start", + ["pitch.constant.numeric","B"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","c"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text"," "], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","c"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text"," "], + ["information.keyword.embedded","[M:"], + ["information.argument.string.unquoted","9/8]"], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","3"], + ["text"," "], + ["barline.keyword.operator","|"] +],[ + "start", + ["information.keyword.embedded","[M:"], + ["information.argument.string.unquoted","6/8]"], + ["pitch.constant.numeric","D"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","F"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["duration.constant.numeric","3"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text"," "], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","D"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text"," "], + ["pitch.constant.numeric","D"], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["barline.keyword.operator","|1"], + ["text"," "], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","F"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","2"], + ["text"," "], + ["barline.keyword.operator",":|2"], + ["text"," "], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","F"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","3"], + ["text"," "], + ["barline.keyword.operator","|]"] +],[ + "start" +],[ + "start", + ["information.keyword","X:"], + ["information.argument.string.unquoted","5"] +],[ + "start", + ["information.keyword","T:"], + ["information.argument.string.unquoted","Atholl Brose"] +],[ + "start", + ["comment.line.percentage","% in this example, which reproduces Highland Bagpipe gracing,"] +],[ + "start", + ["comment.line.percentage","% the large number of grace notes mean that it is more convenient to be specific about"] +],[ + "start", + ["comment.line.percentage","% score line-breaks (using the $ symbol), rather than using code line breaks to indicate them"] +],[ + "start", + ["information.keyword","I:"], + ["information.argument.string.unquoted","linebreak $"] +],[ + "start", + ["information.keyword","K:"], + ["information.argument.string.unquoted","D"] +],[ + "start", + ["text","{"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["text","}"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","<"], + ["text","{"], + ["pitch.constant.numeric","e"], + ["text","}"], + ["pitch.constant.numeric","A"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["text","}"], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","A"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["text","}"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"] +],[ + "start", + ["text","{"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["text","}"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","<"], + ["text","{"], + ["pitch.constant.numeric","e"], + ["text","}"], + ["pitch.constant.numeric","A"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["text","}"], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","a"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","f"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"] +],[ + "start", + ["text","{"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["text","}"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","<"], + ["text","{"], + ["pitch.constant.numeric","e"], + ["text","}"], + ["pitch.constant.numeric","A"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["text","}"], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","A"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["text","}"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"] +],[ + "start", + ["text","{"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","/"], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","/"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric",">"], + ["text","{"], + ["pitch.constant.numeric","d"], + ["text","}"], + ["pitch.constant.numeric","B"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","G"], + ["text"," {"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","c"], + ["text","}"], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","B"], + ["barline.keyword.operator",":|"], + ["text","$"] +],[ + "start", + ["text","{"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","<"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","a"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","e"], + ["barline.keyword.operator","|"] +],[ + "start", + ["text","{"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","<"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","a"], + ["duration.constant.numeric","2"], + ["text"," {"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","G"], + ["text","}"], + ["pitch.constant.numeric","a"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"] +],[ + "start", + ["text","{"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","<"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","a"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","f"], + ["barline.keyword.operator","|"] +],[ + "start", + ["text","{"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","d"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","d"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","d"], + ["text","}"], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","<"], + ["text","{"], + ["pitch.constant.numeric","e"], + ["text","}"], + ["pitch.constant.numeric","G"], + ["text"," {"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","c"], + ["text","}"], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","B"], + ["barline.keyword.operator","|"] +],[ + "start", + ["text","{"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","<"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","a"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","e"], + ["barline.keyword.operator","|"] +],[ + "start", + ["text","{"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","<"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","a"], + ["duration.constant.numeric","2"], + ["text"," {"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","G"], + ["text","}"], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"] +],[ + "start", + ["text","{"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","<"], + ["text","{"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","G"], + ["text","}"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","a"], + ["text"," {"], + ["pitch.constant.numeric","f"], + ["text","}"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","e"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","f"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"] +],[ + "start", + ["text","{"], + ["pitch.constant.numeric","g"], + ["text","}"], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","/"], + ["pitch.constant.numeric","f"], + ["duration.constant.numeric","/"], + ["pitch.constant.numeric","g"], + ["text"," {"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","c"], + ["text","}"], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","c"], + ["text"," {"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","d"], + ["text","}"], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","<"], + ["text","{"], + ["pitch.constant.numeric","e"], + ["text","}"], + ["pitch.constant.numeric","G"], + ["text"," {"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","c"], + ["text","}"], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator","|]"] +],[ + "start" +],[ + "start", + ["information.keyword","X:"], + ["information.argument.string.unquoted","6"] +],[ + "start", + ["information.keyword","T:"], + ["information.argument.string.unquoted","Untitled Reel"] +],[ + "start", + ["information.keyword","C:"], + ["information.argument.string.unquoted","Trad."] +],[ + "start", + ["information.keyword","K:"], + ["information.argument.string.unquoted","D"] +],[ + "start", + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","g"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","a"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","b"], + ["text"," "], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","g"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","b"], + ["pitch.constant.numeric","g"], + ["text"," "], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","f"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric","2"], + ["text"," "], + ["pitch.constant.numeric","f"], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","g"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","f"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["text"," "], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator",":|"], + ["text","\\"] +],[ + "start", + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator",":|"] +],[ + "start", + ["information.keyword","K:"], + ["information.argument.string.unquoted","G"] +],[ + "start", + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","c"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","B"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","F"], + ["text"," "], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","E"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","c"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","B"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator",":|"] +],[ + "start" +],[ + "start", + ["information.keyword","X:"], + ["information.argument.string.unquoted","7"] +],[ + "start", + ["information.keyword","T:"], + ["information.argument.string.unquoted","Kitchen Girl"] +],[ + "start", + ["information.keyword","C:"], + ["information.argument.string.unquoted","Trad."] +],[ + "start", + ["information.keyword","K:"], + ["information.argument.string.unquoted","D"] +],[ + "start", + ["text","["], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","4"], + ["pitch.constant.numeric","a"], + ["duration.constant.numeric","4"], + ["text","] ["], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","4"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric","4"], + ["text","]"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","f"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","f"], + ["duration.constant.numeric","2"], + ["text"," "], + ["pitch.constant.numeric","g"], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","b"], + ["pitch.constant.numeric","a"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["text"," "], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","f"], + ["pitch.constant.numeric","g"], + ["barline.keyword.operator","|"] +],[ + "start", + ["pitch.constant.numeric","a"], + ["duration.constant.numeric","4"], + ["text"," "], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric","4"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","f"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","d"], + ["text"," "], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","f"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["text"," "], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","f"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","4"], + ["barline.keyword.operator",":|"] +],[ + "start", + ["information.keyword","K:"], + ["information.argument.string.unquoted","G"] +],[ + "start", + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","B"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","D"], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["text"," "], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","3"], + ["pitch.constant.numeric","f"], + ["text"," "], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","B"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","B"], + ["barline.keyword.operator","|"] +],[ + "start", + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["text"," "], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","c"], + ["text"," "], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","4"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","4"], + ["barline.keyword.operator",":|"] +],[ + "start" +],[ + "start", + ["comment.line.percentage","%abc-2.1"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","pagewidth 21cm"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","pageheight 29.7cm"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","topspace 0.5cm"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","topmargin 1cm"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","botmargin 0cm"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","leftmargin 1cm"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","rightmargin 1cm"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","titlespace 0cm"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","titlefont Times-Bold 32"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","subtitlefont Times-Bold 24"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","composerfont Times 16"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","vocalfont Times-Roman 14"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","staffsep 60pt"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","sysstaffsep 20pt"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","musicspace 1cm"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","vocalspace 5pt"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","measurenb 0"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","barsperstaff 5"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","scale 0.7"] +],[ + "start", + ["information.keyword","X:"], + ["information.argument.string.unquoted"," 1"] +],[ + "start", + ["information.keyword","T:"], + ["information.argument.string.unquoted"," Canzonetta a tre voci"] +],[ + "start", + ["information.keyword","C:"], + ["information.argument.string.unquoted"," Claudio Monteverdi (1567-1643)"] +],[ + "start", + ["information.keyword","M:"], + ["information.argument.string.unquoted"," C"] +],[ + "start", + ["information.keyword","L:"], + ["information.argument.string.unquoted"," 1/4"] +],[ + "start", + ["information.keyword","Q:"], + ["information.argument.string.unquoted"," \"Andante mosso\" 1/4 = 110"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","score [1 2 3]"] +],[ + "start", + ["information.keyword","V:"], + ["information.argument.string.unquoted"," 1 clef=treble name=\"Soprano\"sname=\"A\""] +],[ + "start", + ["information.keyword","V:"], + ["information.argument.string.unquoted"," 2 clef=treble name=\"Alto\" sname=\"T\""] +],[ + "start", + ["information.keyword","V:"], + ["information.argument.string.unquoted"," 3 clef=bass middle=d name=\"Tenor\" sname=\"B\""] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","MIDI program 1 75 % recorder"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","MIDI program 2 75"] +],[ + "start", + ["information.comment.line.percentage","%%"], + ["information.keyword.embedded","MIDI program 3 75"] +],[ + "start", + ["information.keyword","K:"], + ["information.argument.string.unquoted"," Eb"] +],[ + "start", + ["comment.line.percentage","% 1 - 4"] +],[ + "start", + ["information.keyword.embedded","[V:"], + ["information.argument.string.unquoted"," 1]"], + ["text"," "], + ["barline.keyword.operator","|:"], + ["pitch.constant.numeric","z"], + ["duration.constant.numeric","4"], + ["text"," "], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","z"], + ["duration.constant.numeric","4"], + ["text"," "], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","f"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","c"], + ["text"," "], + ["barline.keyword.operator","|"], + ["accent.constant.language","_"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","c"], + ["text"," "], + ["barline.keyword.operator","|"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," Son que-sti~i cre-spi cri-ni~e"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," Que-sti son gli~oc-chi che mi-"] +],[ + "start", + ["information.keyword.embedded","[V:"], + ["information.argument.string.unquoted"," 2]"], + ["text"," "], + ["barline.keyword.operator","|:"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","G"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","c"], + ["barline.keyword.operator","|"], + ["text","("], + ["pitch.constant.numeric","F"], + ["duration.constant.numeric","/"], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","/"], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","/"], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","/"], + ["text",")"], + ["pitch.constant.numeric","c"], + ["accent.constant.language","="], + ["pitch.constant.numeric","A"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["barline.keyword.operator","|"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," Son que-sti~i cre-spi cri-ni~e que - - - - sto~il vi-so e"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," Que-sti son~gli oc-chi che mi-ran - - - - do fi-so mi-"] +],[ + "start", + ["information.keyword.embedded","[V:"], + ["information.argument.string.unquoted"," 3]"], + ["text"," "], + ["barline.keyword.operator","|:"], + ["pitch.constant.numeric","z"], + ["duration.constant.numeric","4"], + ["text"," "], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","f"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","c"], + ["barline.keyword.operator","|"], + ["accent.constant.language","_"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","f"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text","("], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","/"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","/"], + ["accent.constant.language","_"], + ["pitch.constant.numeric","d"], + ["duration.constant.numeric","/"], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","/"], + ["text",")"], + ["pitch.constant.numeric","f"], + ["pitch.constant.numeric","f"], + ["barline.keyword.operator","|"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," Son que-sti~i cre-spi cri-ni~e que - - - - sto~il"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," Que-sti son~gli oc-chi che mi-ran - - - - do"] +],[ + "start", + ["comment.line.percentage","% 5 - 9"] +],[ + "start", + ["information.keyword.embedded","[V:"], + ["information.argument.string.unquoted"," 1]"], + ["text"," "], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","2"], + ["text"," "], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","3"], + ["pitch.constant.numeric","B"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","2"], + ["string.quoted","!fermata!"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","z"], + ["text"," "], + ["barline.keyword.operator","::"], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","4"], + ["barline.keyword.operator","|"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," que-sto~il vi-so ond' io ri-man-go~uc-ci-so. Deh,"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," ran-do fi-so, tut-to re-stai con-qui-so."] +],[ + "start", + ["information.keyword.embedded","[V:"], + ["information.argument.string.unquoted"," 2]"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","2"], + ["text"," "], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","F"], + ["text"," "], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","3"], + ["pitch.constant.numeric","F"], + ["barline.keyword.operator","|"], + ["accent.constant.language","="], + ["pitch.constant.numeric","E"], + ["duration.constant.numeric","2"], + ["string.quoted","!fermata!"], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","z"], + ["barline.keyword.operator","::"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","4"], + ["barline.keyword.operator","|"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," que-sto~il vi-so ond' io ri-man-go~uc-ci-so. Deh,"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," ran-do fi-so tut-to re-stai con-qui-so."] +],[ + "start", + ["information.keyword.embedded","[V:"], + ["information.argument.string.unquoted"," 3]"], + ["text"," ("], + ["pitch.constant.numeric","a"], + ["pitch.constant.numeric","g"], + ["duration.constant.numeric","/"], + ["pitch.constant.numeric","f"], + ["duration.constant.numeric","/"], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["text",")"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","A"], + ["accent.constant.language","_"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","3"], + ["pitch.constant.numeric","B"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","2"], + ["string.quoted","!fermata!"], + ["pitch.constant.numeric","c"], + ["pitch.constant.numeric","z"], + ["text"," "], + ["barline.keyword.operator","::"], + ["pitch.constant.numeric","A"], + ["duration.constant.numeric","4"], + ["barline.keyword.operator","|"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," vi - - - so ond' io ti-man-go~uc-ci-so. Deh,"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," fi - - - so tut-to re-stai con-qui-so."] +],[ + "start", + ["comment.line.percentage","% 10 - 15"] +],[ + "start", + ["information.keyword.embedded","[V:"], + ["information.argument.string.unquoted"," 1]"], + ["text"," "], + ["pitch.constant.numeric","f"], + ["accent.constant.language","_"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","e"], + ["pitch.constant.numeric","c"], + ["text"," "], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","B"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","z"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","F"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text","\\"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," dim-me-lo ben mi-o, che que-sto"], + ["text","\\"] +],[ + "start", + ["accent.constant.language","="], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","2"], + ["text"," "], + ["barline.keyword.operator","|1"], + ["pitch.constant.numeric","F"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","z"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator",":|2"], + ["pitch.constant.numeric","F"], + ["duration.constant.numeric","8"], + ["barline.keyword.operator","|]"], + ["text"," "], + ["comment.line.percentage","% more notes"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," sol de-si-o_. "], + ["comment.line.percentage","% more lyrics"] +],[ + "start", + ["information.keyword.embedded","[V:"], + ["information.argument.string.unquoted"," 2]"], + ["text"," "], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","A"], + ["text"," "], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","G"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","A"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","F"], + ["accent.constant.language","="], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["text"," "], + ["barline.keyword.operator","|"], + ["text","("], + ["pitch.constant.numeric","G"], + ["pitch.constant.numeric","F"], + ["duration.constant.numeric","3/2"], + ["accent.constant.language","="], + ["pitch.constant.numeric","E"], + ["duration.constant.numeric","//"], + ["pitch.constant.numeric","D"], + ["duration.constant.numeric","//"], + ["pitch.constant.numeric","E"], + ["text",")"], + ["barline.keyword.operator","|1"], + ["pitch.constant.numeric","F"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","z"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator",":|2"], + ["pitch.constant.numeric","F"], + ["duration.constant.numeric","8"], + ["barline.keyword.operator","|]"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," dim-me-lo ben mi-o, che que-sto sol de-si - - - - o_."] +],[ + "start", + ["information.keyword.embedded","[V:"], + ["information.argument.string.unquoted"," 3]"], + ["text"," "], + ["accent.constant.language","_"], + ["pitch.constant.numeric","d"], + ["pitch.constant.numeric","B"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric",">"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","e"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","A"], + ["pitch.constant.numeric","F"], + ["barline.keyword.operator","|"], + ["accent.constant.language","="], + ["pitch.constant.numeric","E"], + ["pitch.constant.numeric","F"], + ["pitch.constant.numeric","c"], + ["accent.constant.language","_"], + ["pitch.constant.numeric","d"], + ["barline.keyword.operator","|"], + ["pitch.constant.numeric","c"], + ["duration.constant.numeric","4"], + ["text"," "], + ["barline.keyword.operator","|1"], + ["pitch.constant.numeric","F"], + ["duration.constant.numeric","2"], + ["pitch.constant.numeric","z"], + ["duration.constant.numeric","2"], + ["barline.keyword.operator",":|2"], + ["pitch.constant.numeric","F"], + ["duration.constant.numeric","8"], + ["barline.keyword.operator","|]"] +],[ + "start", + ["information.keyword","w:"], + ["information.argument.string.unquoted"," dim-me-lo ben mi-o, che que-sto sol de-si-o_."] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_actionscript.json b/node_modules/ace/lib/ace/mode/_test/tokens_actionscript.json new file mode 100644 index 00000000..e3fad38f --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_actionscript.json @@ -0,0 +1,263 @@ +[[ + "start", + ["text","package code"] +],[ + "start", + ["text","{"] +],[ + "punctuation.definition.comment.actionscript.2", + ["text"," "], + ["punctuation.definition.comment.actionscript.2","/*"], + ["comment.block.actionscript.2","****************************************"] +],[ + "punctuation.definition.comment.actionscript.2", + ["comment.block.actionscript.2","\t * based on textmate actionscript bundle"] +],[ + "start", + ["comment.block.actionscript.2","\t ***************************************"], + ["punctuation.definition.comment.actionscript.2","*/"] +],[ + "start", + ["text","\t "] +],[ + "start", + ["text","\t"], + ["keyword.control.actionscript.2","import"], + ["text"," fl.events.SliderEvent;"] +],[ + "start", + ["text","\t"] +],[ + "start", + ["text","\t"], + ["keyword.control.actionscript.2","public"], + ["text"," "], + ["storage.type.class.actionscript.2","class"], + ["meta.class.actionscript.2"," "], + ["entity.name.type.class.actionscript.2","Foo"], + ["meta.class.actionscript.2"," "], + ["storage.modifier.extends.actionscript.2","extends"], + ["meta.class.actionscript.2"," "], + ["entity.other.inherited-class.actionscript.2","MovieClip"] +],[ + "start", + ["text","\t{"] +],[ + "start", + ["text","\t\t"], + ["punctuation.definition.comment.actionscript.2","//*************************"] +],[ + "start", + ["text","\t\t"], + ["punctuation.definition.comment.actionscript.2","// Properties:"] +],[ + "start", + ["text","\t\t"] +],[ + "start", + ["text","\t\t"], + ["keyword.control.actionscript.2","public"], + ["text"," "], + ["keyword.control.actionscript.2","var"], + ["text"," activeSwatch"], + ["keyword.operator.symbolic.actionscript.2",":"], + ["support.class.actionscript.2","MovieClip"], + ["text",";"] +],[ + "start", + ["text","\t\t"] +],[ + "start", + ["text","\t\t"], + ["punctuation.definition.comment.actionscript.2","// Color offsets"] +],[ + "start", + ["text","\t\t"], + ["keyword.control.actionscript.2","public"], + ["text"," "], + ["keyword.control.actionscript.2","var"], + ["text"," c1"], + ["keyword.operator.symbolic.actionscript.2",":"], + ["storage.type.actionscript.2","Number"], + ["text"," "], + ["keyword.operator.symbolic.actionscript.2","="], + ["text"," "], + ["constant.numeric.actionscript.2","0"], + ["text",";\t"], + ["punctuation.definition.comment.actionscript.2","// R"] +],[ + "start", + ["text","\t\t"] +],[ + "start", + ["text","\t\t"], + ["punctuation.definition.comment.actionscript.2","//*************************"] +],[ + "start", + ["text","\t\t"], + ["punctuation.definition.comment.actionscript.2","// Constructor:"] +],[ + "start", + ["text","\t\t"] +],[ + "start", + ["text","\t\t"], + ["keyword.control.actionscript.2","public"], + ["text"," "], + ["storage.type.function.actionscript.2","function"], + ["meta.function.actionscript.2"," "], + ["entity.name.function.actionscript.2","Foo"], + ["punctuation.definition.parameters.begin.actionscript.2","("], + ["punctuation.definition.parameters.end.actionscript.2",")"] +],[ + "start", + ["text","\t\t{"] +],[ + "start", + ["text","\t\t\t"], + ["punctuation.definition.comment.actionscript.2","// Respond to mouse events"] +],[ + "start", + ["text","\t\t\tswatch1_btn."], + ["support.function.actionscript.2","addEventListener"], + ["text","(MouseEvent.CLICK,swatchHandler,"], + ["constant.language.actionscript.2","false"], + ["text",","], + ["constant.numeric.actionscript.2","0"], + ["text",","], + ["constant.language.actionscript.2","false"], + ["text",");"] +],[ + "start", + ["text","\t\t\tpreviewBox_btn."], + ["support.function.actionscript.2","addEventListener"], + ["text","(MouseEvent.MOUSE_DOWN,dragPressHandler);"] +],[ + "start", + ["text","\t\t\t"] +],[ + "start", + ["text","\t\t\t"], + ["punctuation.definition.comment.actionscript.2","// Respond to drag events"] +],[ + "start", + ["text","\t\t\tred_slider."], + ["support.function.actionscript.2","addEventListener"], + ["text","(SliderEvent.THUMB_DRAG,sliderHandler);"] +],[ + "start", + ["text","\t\t\t"] +],[ + "start", + ["text","\t\t\t"], + ["punctuation.definition.comment.actionscript.2","// Draw a frame later"] +],[ + "start", + ["text","\t\t\t"], + ["support.function.actionscript.2","addEventListener"], + ["text","(Event.ENTER_FRAME,"], + ["support.function.actionscript.2","draw"], + ["text",");"] +],[ + "start", + ["text","\t\t}"] +],[ + "start", + ["text"," "] +],[ + "start", + ["text","\t\tprotected "], + ["storage.type.function.actionscript.2","function"], + ["meta.function.actionscript.2"," "], + ["entity.name.function.actionscript.2","clickHandler"], + ["punctuation.definition.parameters.begin.actionscript.2","("], + ["variable.parameter.function.actionscript.2","event:MouseEvent"], + ["punctuation.definition.parameters.end.actionscript.2",")"], + ["keyword.operator.symbolic.actionscript.2",":"], + ["support.function.actionscript.2","void"] +],[ + "start", + ["text","\t\t{"] +],[ + "start", + ["text","\t\t\tcar.transform.colorTransform "], + ["keyword.operator.symbolic.actionscript.2","="], + ["text"," "], + ["keyword.control.actionscript.2","new"], + ["text"," ColorTransform("], + ["constant.numeric.actionscript.2","0"], + ["text",","], + ["constant.numeric.actionscript.2","0"], + ["text",","], + ["constant.numeric.actionscript.2","0"], + ["text",","], + ["constant.numeric.actionscript.2","1"], + ["text",",c1,c2,c3);"] +],[ + "start", + ["text","\t\t}"] +],[ + "start", + ["text","\t\t"] +],[ + "start", + ["text","\t\tprotected "], + ["storage.type.function.actionscript.2","function"], + ["meta.function.actionscript.2"," "], + ["entity.name.function.actionscript.2","changeRGBHandler"], + ["punctuation.definition.parameters.begin.actionscript.2","("], + ["variable.parameter.function.actionscript.2","event:Event"], + ["punctuation.definition.parameters.end.actionscript.2",")"], + ["keyword.operator.symbolic.actionscript.2",":"], + ["support.function.actionscript.2","void"] +],[ + "start", + ["text","\t\t{"] +],[ + "start", + ["text","\t\t\tc1 "], + ["keyword.operator.symbolic.actionscript.2","="], + ["text"," "], + ["storage.type.actionscript.2","Number"], + ["text","(c1_txt."], + ["support.function.actionscript.2","text"], + ["text",");"] +],[ + "start", + ["text"," "] +],[ + "start", + ["text","\t\t\t"], + ["keyword.control.actionscript.2","if"], + ["text","("], + ["keyword.operator.symbolic.actionscript.2","!"], + ["text","(c1>"], + ["keyword.operator.symbolic.actionscript.2","="], + ["constant.numeric.actionscript.2","0"], + ["text",")){"] +],[ + "start", + ["text","\t\t\t\tc1 "], + ["keyword.operator.symbolic.actionscript.2","="], + ["text"," "], + ["constant.numeric.actionscript.2","0"], + ["text",";"] +],[ + "start", + ["text","\t\t\t}\t\t\t"] +],[ + "start", + ["text","\t\t\t"] +],[ + "start", + ["text","\t\t\tupdateSliders();"] +],[ + "start", + ["text","\t\t}"] +],[ + "start", + ["text","\t}"] +],[ + "start", + ["text","}"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_ada.json b/node_modules/ace/lib/ace/mode/_test/tokens_ada.json new file mode 100644 index 00000000..bdef7256 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_ada.json @@ -0,0 +1,39 @@ +[[ + "start", + ["keyword","with"], + ["text"," "], + ["identifier","Ada"], + ["text","."], + ["identifier","Text_IO"], + ["text","; "], + ["keyword","use"], + ["text"," "], + ["identifier","Ada"], + ["text","."], + ["identifier","Text_IO"], + ["text",";"] +],[ + "start", + ["keyword","procedure"], + ["text"," "], + ["identifier","Hello"], + ["text"," "], + ["keyword","is"] +],[ + "start", + ["keyword","begin"] +],[ + "start", + ["text"," "], + ["identifier","Put_Line"], + ["paren.lparen","("], + ["string","\"Hello, world!\""], + ["paren.rparen",")"], + ["text",";"] +],[ + "start", + ["keyword","end"], + ["text"," "], + ["identifier","Hello"], + ["text",";"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_asciidoc.json b/node_modules/ace/lib/ace/mode/_test/tokens_asciidoc.json new file mode 100644 index 00000000..f54c355e --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_asciidoc.json @@ -0,0 +1,422 @@ +[[ + "literalBlock", + ["support.function","------------------------------------"] +],[ + "dissallowDelimitedBlock", + ["support.function","-----------------------------------"] +],[ + "text", + ["string.italic","_ita_lic_"], + ["text",", "], + ["keyword.bold","*bo*ld*"], + ["text",", "], + ["support.function","+mo+no+"], + ["text",", normal. "] +],[ + "text", + ["keyword","``"], + ["text","double quoted"], + ["keyword","''"], + ["text",", `single quoted'."] +],[ + "text", + ["text"," normal, ^super^, "], + ["keyword","~sub~"], + ["text","."] +],[ + "start" +],[ + "text", + ["text","''''"] +],[ + "text", + ["text","Escaped:"] +],[ + "text", + ["constant.language.escape","\\_"], + ["text","italic_, "], + ["support.function","+++"], + ["text","_italic_"], + ["support.function","+++"], + ["text",","] +],[ + "smallPassthrough", + ["text","t"], + ["constant.language.escape","\\_"], + ["text","_e"], + ["string.italic","__st, +++t__"], + ["text","e__st"], + ["support.function","+++"], + ["text",","] +],[ + "smallPassthrough", + ["support.function","+++"], + ["text","bold"], + ["support.function","+++"], + ["text",", $$<"], + ["support.function","b"], + ["text",">"], + ["support.function","normal"], + ["text","$$"] +],[ + "smallPassthrough", + ["text","\\&#"], + ["support.function","182"], + ["text","; &#"], + ["support.function","182"], + ["text",";"] +],[ + "smallPassthrough", + ["text","\\`"], + ["support.function","not"], + ["text"," "], + ["support.function","single"], + ["text"," "], + ["support.function","quoted"], + ["text","'"] +],[ + "smallPassthrough", + ["text","\\`\\`"], + ["support.function","not"], + ["text"," "], + ["support.function","double"], + ["text"," "], + ["support.function","quoted"], + ["text","''"] +],[ + "dissallowDelimitedBlock" +],[ + "text" +],[ + "start", + ["string.regexp","[fffff]"] +],[ + "passthroughBlock", + ["string","+++++++++++++++++++++++++++++++++++++"] +],[ + "passthroughBlock", + ["support.function","(C) "], + ["constant.character","{ss}"], + ["support.function"," ss"] +],[ + "dissallowDelimitedBlock", + ["support.function","+++++++++++++++++++++++++++++++++++++"] +],[ + "text" +],[ + "listingBlock", + ["support.function","............."] +],[ + "listingBlock", + ["support.function","callout "], + ["constant.numeric","<1>"] +],[ + "dissallowDelimitedBlock", + ["support.function",".............."] +],[ + "text" +],[ + "text", + ["text","> 1"] +],[ + "text", + ["text","1> 2"] +],[ + "text", + ["text","<2> 3"] +],[ + "start" +],[ + "text", + ["text","Escaped:"] +],[ + "text", + ["constant.language.escape","\\_"], + ["text","italic_,"] +],[ + "text", + ["text","t"], + ["constant.language.escape","\\_"], + ["text","_e"], + ["string.italic","__st, o__"] +],[ + "start" +],[ + "start", + ["constant.numeric",".optional title"] +],[ + "listingBlock", + ["support.function","............."] +],[ + "listingBlock", + ["support.function","callout "], + ["constant.numeric","<1>"] +],[ + "dissallowDelimitedBlock", + ["support.function",".............."] +],[ + "text" +],[ + "start" +],[ + "text", + ["keyword",":macro:"], + ["text"," dddd"] +],[ + "start" +],[ + "start", + ["constant.numeric",".lists"] +],[ + "listText", + ["keyword",". "], + ["text","1"] +],[ + "listText", + ["keyword",".. "], + ["text","2"] +],[ + "listText", + ["keyword","... "], + ["text","d"] +],[ + "listText", + ["keyword","..... "], + ["text","big"] +],[ + "start", + ["keyword","+"] +],[ + "text", + ["text","continue"], + ["keyword"," +"] +],[ + "text", + ["text","next line"] +],[ + "text", + ["text","xi) no "], + ["support.function","++la+tin++"] +],[ + "start" +],[ + "listText", + ["keyword","xi) "], + ["text","la"], + ["support.function","++tin++"] +],[ + "listText", + ["keyword","2. "], + ["text","num"], + ["string.italic","__ber__"], + ["text"," [red]"], + ["keyword","#"], + ["text","red"], + ["keyword","#"] +],[ + "start", + ["keyword","--"] +],[ + "listText", + ["keyword"," 5. "], + ["text","f "], + ["keyword","<>"], + ["text"," "], + ["constant.character","{macro}"] +],[ + "start", + ["keyword","--"] +],[ + "text", + ["markup.list.macro","image::"], + ["keyword","path"], + ["string","[beauty]"], + ["text"," "], + ["constant.language.escape","->"], + ["text","--"], + ["constant.language.escape","<= --"], + ["text"," replacements"] +],[ + "start" +],[ + "indentedBlock", + ["support.function"," image::s"] +],[ + "indentedBlock", + ["support.function","sssss"] +],[ + "indentedBlock", + ["support.function","sss "] +],[ + "indentedBlock", + ["support.function","sssss"] +],[ + "start" +],[ + "start" +],[ + "start", + ["markup.heading","== 1"] +],[ + "indentedBlock", + ["support.function"," heading"] +],[ + "start", + ["markup.heading","=== not a heading"] +],[ + "start", + ["keyword","===================================="] +],[ + "start" +],[ + "start", + ["keyword","=================================="] +],[ + "text", + ["text","====4 "] +],[ + "text", + ["text","NOTE: above"] +],[ + "start" +],[ + "text", + ["keyword","NOTE:"], + ["text"," above"] +],[ + "start" +],[ + "start", + ["string.regexp","[[x6]]"] +],[ + "text", + ["keyword","WARNING:"], + ["text"," "] +],[ + "start" +],[ + "start", + ["string.regexp","[options[]]"] +],[ + "literalBlock", + ["support.function","---------------------------"] +],[ + "literalBlock", + ["support.function","literal"] +],[ + "dissallowDelimitedBlock", + ["support.function","---------------------------"] +],[ + "text" +],[ + "start" +],[ + "start", + ["markup.heading","= Tables"] +],[ + "tableBlock", + ["doc.comment","|===================================="] +],[ + "tableBlock", + ["doc.comment","|"], + ["text"," "], + ["string.italic","_italic_"], + ["text"," "], + ["doc.comment","|"], + ["text"," "], + ["keyword.bold","*bold*"], + ["text"," "], + ["doc.comment","|"], + ["text"," text "], + ["doc.comment","|"], + ["text"," "], + ["constant.language.escape","(R)"] +],[ + "tableBlock" +],[ + "dissallowDelimitedBlock", + ["doc.comment","|===================================="] +],[ + "text" +],[ + "start" +],[ + "start", + ["string.regexp","[more, options]"] +],[ + "commentBlock", + ["doc.comment","///////////"] +],[ + "commentBlock", + ["doc.comment","comment"] +],[ + "dissallowDelimitedBlock", + ["doc.comment","///////////"] +],[ + "text", + ["comment","// one line comment"] +],[ + "start" +],[ + "start" +],[ + "start" +],[ + "text", + ["text","[red]"], + ["keyword","#"], + ["text","red text"], + ["keyword","#"], + ["text"," [yellow-background]"], + ["keyword","#"], + ["text","on yellow"], + ["keyword","#"] +],[ + "text", + ["text","[big]"], + ["keyword","#"], + ["text","large"], + ["keyword","#"], + ["text"," [red yellow-background big]"], + ["keyword.bold","*all bold*"] +],[ + "start" +],[ + "start", + ["text","\t"] +],[ + "text", + ["markup.underline.list","https://site"], + ["text"," text <"], + ["markup.underline.list","mail@i.am"], + ["text","> "], + ["markup.underline.list","callto:ace"], + ["text"," "], + ["link","http://ace.ajaxorg.com"], + ["variable.language","[awesome]"] +],[ + "text", + ["text"," .still normal text"] +],[ + "start", + ["constant.numeric",".break out thoug should not"] +],[ + "literalBlock", + ["support.function","---------------------------"] +],[ + "literalBlock", + ["support.function","///////////////////////////"] +],[ + "dissallowDelimitedBlock", + ["support.function","---------------------------"] +],[ + "text" +],[ + "start" +],[ + "start" +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_assembly_x86.json b/node_modules/ace/lib/ace/mode/_test/tokens_assembly_x86.json new file mode 100644 index 00000000..5da0470e --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_assembly_x86.json @@ -0,0 +1,114 @@ +[[ + "start", + ["support.function.directive.assembly","section"], + ["text","\t.text"] +],[ + "start", + ["text"," "], + ["support.function.directive.assembly","global"], + ["text"," "], + ["entity.name.function.assembly","main"], + ["text"," "], + ["comment.assembly",";must be declared for using gcc"] +],[ + "start" +],[ + "start", + ["entity.name.function.assembly","main:"], + ["text","\t "], + ["comment.assembly",";tell linker entry point"] +],[ + "start" +],[ + "start", + ["text","\t"], + ["keyword.control.assembly","mov"], + ["text","\t"], + ["variable.parameter.register.assembly","edx"], + ["text",", len\t "], + ["comment.assembly",";message length"] +],[ + "start", + ["text","\t"], + ["keyword.control.assembly","mov"], + ["text","\t"], + ["variable.parameter.register.assembly","ecx"], + ["text",", msg\t "], + ["comment.assembly",";message to write"] +],[ + "start", + ["text","\t"], + ["keyword.control.assembly","mov"], + ["text","\t"], + ["variable.parameter.register.assembly","ebx"], + ["text",", "], + ["constant.character.decimal.assembly","1"], + ["text","\t "], + ["comment.assembly",";file descriptor (stdout)"] +],[ + "start", + ["text","\t"], + ["keyword.control.assembly","mov"], + ["text","\t"], + ["variable.parameter.register.assembly","eax"], + ["text",", "], + ["constant.character.decimal.assembly","4"], + ["text","\t "], + ["comment.assembly",";system call number (sys_write)"] +],[ + "start", + ["text","\t"], + ["keyword.control.assembly","int"], + ["text","\t"], + ["constant.character.hexadecimal.assembly","0x80"], + ["text","\t "], + ["comment.assembly",";call kernel"] +],[ + "start" +],[ + "start", + ["text","\t"], + ["keyword.control.assembly","mov"], + ["text","\t"], + ["variable.parameter.register.assembly","eax"], + ["text",", "], + ["constant.character.decimal.assembly","1"], + ["text","\t "], + ["comment.assembly",";system call number (sys_exit)"] +],[ + "start", + ["text","\t"], + ["keyword.control.assembly","int"], + ["text","\t"], + ["constant.character.hexadecimal.assembly","0x80"], + ["text","\t "], + ["comment.assembly",";call kernel"] +],[ + "start" +],[ + "start", + ["support.function.directive.assembly","section"], + ["text","\t.data"] +],[ + "start" +],[ + "start", + ["entity.name.function.assembly","msg"], + ["text","\t"], + ["support.function.directive.assembly","db"], + ["text","\t"], + ["string.assembly","'Hello, world!'"], + ["text",","], + ["constant.character.hexadecimal.assembly","0xa"], + ["text","\t"], + ["comment.assembly",";our dear string"] +],[ + "start", + ["entity.name.function.assembly","len"], + ["text","\t"], + ["support.function.directive.assembly","equ"], + ["text","\t$ - msg\t\t\t"], + ["comment.assembly",";length of our dear string"] +],[ + "start" +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_autohotkey.json b/node_modules/ace/lib/ace/mode/_test/tokens_autohotkey.json new file mode 100644 index 00000000..374310fb --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_autohotkey.json @@ -0,0 +1,261 @@ +[[ + "start", + ["punctuation.ahk","#"], + ["keyword.command.ahk","NoEnv"] +],[ + "start", + ["keyword.command.ahk","SetBatchLines"], + ["text"," "], + ["constant.numeric","-1"] +],[ + "start" +],[ + "start", + ["keyword.command.ahk","CoordMode"], + ["text"," "], + ["variable.parameter","Mouse"], + ["punctuation.ahk",","], + ["text"," "], + ["variable.parameter","Screen"] +],[ + "start", + ["keyword.command.ahk","OnExit"], + ["text"," "], + ["variable.parameter","GuiClose"] +],[ + "start" +],[ + "start", + ["text","zoom "], + ["keyword.operator.ahk",":="], + ["text"," 9"] +],[ + "start" +],[ + "start", + ["text","computeSize"], + ["punctuation.ahk","(){"] +],[ + "start", + ["text","\t"], + ["keyword.control.ahk","global"], + ["text"," as_x"] +],[ + "start", + ["text","\tas_x "], + ["keyword.operator.ahk",":="], + ["text"," "], + ["support.function.ahk","Round"], + ["punctuation.ahk","("], + ["text","ws_x"], + ["keyword.operator.ahk","/"], + ["text","zoom"], + ["keyword.operator.ahk","/"], + ["text","2 "], + ["keyword.operator.ahk","-"], + ["text"," 0.5"], + ["punctuation.ahk",")"] +],[ + "start", + ["text","\t"], + ["keyword.control.ahk","if"], + ["text"," "], + ["punctuation.ahk","("], + ["text","zoom"], + ["keyword.operator.ahk",">"], + ["text","1"], + ["punctuation.ahk",")"], + ["text"," "], + ["punctuation.ahk","{"] +],[ + "start", + ["text","\t\tpix "], + ["keyword.operator.ahk",":="], + ["text"," "], + ["support.function.ahk","Round"], + ["punctuation.ahk","("], + ["text","zoom"], + ["punctuation.ahk",")"] +],[ + "start", + ["text","\t"], + ["punctuation.ahk","}"], + ["text"," ele "], + ["punctuation.ahk","{"] +],[ + "start", + ["text","\t\tpix "], + ["keyword.operator.ahk",":="], + ["text"," 1"] +],[ + "start", + ["text","\t"], + ["punctuation.ahk","}"] +],[ + "start", + ["text"," "], + ["keyword.command.ahk","ToolTip"], + ["text"," Message "], + ["punctuation.ahk","%"], + ["text","as_x"], + ["punctuation.ahk","%"], + ["text"," "], + ["punctuation.ahk","%"], + ["text","zoom"], + ["punctuation.ahk","%"], + ["text"," "], + ["punctuation.ahk","%"], + ["text","ws_x"], + ["punctuation.ahk","%"], + ["text"," "], + ["punctuation.ahk","%"], + ["text","hws_x"], + ["punctuation.ahk","%"], + ["text"," "] +],[ + "start", + ["punctuation.ahk","}"] +],[ + "start" +],[ + "start", + ["text","hdc_frame "], + ["keyword.operator.ahk",":="], + ["text"," "], + ["support.function.ahk","DllCall"], + ["punctuation.ahk","("], + ["punctuation.quote.double","\""], + ["string.quoted.ahk","GetDC"], + ["punctuation.quote.double","\""], + ["punctuation.ahk",","], + ["text"," UInt"], + ["punctuation.ahk",","], + ["text"," MagnifierID"], + ["punctuation.ahk",")"] +],[ + "start" +],[ + "start", + ["comment.line.ahk","; comment"] +],[ + "start", + ["text","DrawCross"], + ["punctuation.ahk","("], + ["keyword.control.ahk","byRef"], + ["text"," x"], + ["keyword.operator.ahk","="], + ["punctuation.quote.double","\""], + ["punctuation.quote.double","\""], + ["punctuation.ahk",","], + ["text"," rX"], + ["punctuation.ahk",","], + ["text","rY"], + ["punctuation.ahk",","], + ["text","z"], + ["punctuation.ahk",","], + ["text"," dc"], + ["punctuation.ahk","){"] +],[ + "start", + ["text"," "], + ["comment.line.ahk"," ;specify the style, thickness and color of the cross lines"] +],[ + "start", + ["text"," h_pen "], + ["keyword.operator.ahk",":="], + ["text"," "], + ["support.function.ahk","DllCall"], + ["punctuation.ahk","("], + ["text"," "], + ["punctuation.quote.double","\""], + ["string.quoted.ahk","gdi32.dll\\CreatePen"], + ["punctuation.quote.double","\""], + ["punctuation.ahk",","], + ["text"," "], + ["constant.language","Int"], + ["punctuation.ahk",","], + ["text"," 0"], + ["punctuation.ahk",","], + ["text"," "], + ["constant.language","Int"], + ["punctuation.ahk",","], + ["text"," 1"], + ["punctuation.ahk",","], + ["text"," UInt"], + ["punctuation.ahk",","], + ["text"," 0x0000FF"], + ["punctuation.ahk",")"] +],[ + "start", + ["punctuation.ahk","}"] +],[ + "start" +],[ + "start", + ["comment.line.ahk",";Ctrl ^; Shift +; Win #; Alt !"] +],[ + "start", + ["text","^"], + ["support.constant.ahk","NumPadAdd"], + ["keyword.operator.ahk","::"] +],[ + "start", + ["text","^"], + ["support.constant.ahk","WheelUp"], + ["keyword.operator.ahk","::"], + ["text"," "] +],[ + "start", + ["text","^;"], + ["keyword.operator.ahk","::"], + ["text"," "], + ["comment.line.ahk"," ;comment"] +],[ + "start", + ["text"," "], + ["keyword.control.ahk","If"], + ["punctuation.ahk","("], + ["text","zoom "], + ["keyword.operator.ahk","<"], + ["text"," ws_x "], + ["variable.parameter","and"], + ["text"," "], + ["punctuation.ahk","("], + ["text"," "], + ["variable.predefined.ahk","A_ThisHotKey"], + ["text"," "], + ["keyword.operator.ahk","="], + ["text"," "], + ["punctuation.quote.double","\""], + ["string.quoted.ahk","^WheelUp"], + ["punctuation.quote.double","\""], + ["text"," "], + ["variable.parameter","or"], + ["text"," "], + ["variable.predefined.ahk","A_ThisHotKey"], + ["text"," "], + ["keyword.operator.ahk","="], + ["punctuation.quote.double","\""], + ["string.quoted.ahk","^NumPadAdd"], + ["punctuation.quote.double","\""], + ["punctuation.ahk",")"], + ["text"," "], + ["punctuation.ahk",")"] +],[ + "start", + ["text","\t\tzoom "], + ["keyword.operator.ahk","*="], + ["text"," 1.189207115 "], + ["comment.line.ahk"," ; sqrt(sqrt(2))"] +],[ + "start", + ["text","\t"], + ["keyword.command.ahk","Gosub"], + ["punctuation.ahk",","], + ["text","setZoom"] +],[ + "start", + ["keyword.control.ahk","return"] +],[ + "start" +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_batchfile.json b/node_modules/ace/lib/ace/mode/_test/tokens_batchfile.json new file mode 100644 index 00000000..0f1f138c --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_batchfile.json @@ -0,0 +1,70 @@ +[[ + "start", + ["comment.line.colons.dosbatch",":: batch file highlighting in Ace!"] +],[ + "start", + ["text","@"], + ["keyword.command.dosbatch","echo"], + ["text"," off"] +],[ + "start" +],[ + "start", + ["keyword.control.statement.dosbatch","CALL"], + ["text"," "], + ["keyword.command.dosbatch","set"], + ["text"," var1="], + ["constant.numeric","%cd%"] +],[ + "start", + ["keyword.command.dosbatch","echo"], + ["text"," unhide everything in "], + ["constant.numeric","%var1%"], + ["text","!"] +],[ + "start" +],[ + "start", + ["comment.line.colons.dosbatch",":: FOR loop in bat is super strange!"] +],[ + "start", + ["keyword.control.repeat.dosbatch","FOR"], + ["text"," /f "], + ["punctuation.definition.string.begin.shell","\""], + ["string.quoted.double.dosbatch","tokens=*"], + ["punctuation.definition.string.end.shell","\""], + ["text"," "], + ["constant.numeric","%%G"], + ["text"," IN ('"], + ["keyword.command.dosbatch","dir"], + ["text"," /A:D /b') DO ("] +],[ + "start", + ["keyword.command.dosbatch","echo"], + ["text"," "], + ["constant.numeric","%var1%%%G"] +],[ + "start", + ["keyword.command.dosbatch","attrib"], + ["text"," -r -a -h -s "], + ["punctuation.definition.string.begin.shell","\""], + ["constant.numeric","%var1%%%G"], + ["punctuation.definition.string.end.shell","\""], + ["text"," /D /S"] +],[ + "start", + ["text",")"] +],[ + "start" +],[ + "start", + ["keyword.command.dosbatch","pause"] +],[ + "start" +],[ + "start", + ["doc.comment","REM"], + ["comment"," that's all"] +],[ + "start" +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_c9search.json b/node_modules/ace/lib/ace/mode/_test/tokens_c9search.json new file mode 100644 index 00000000..902d8dce --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_c9search.json @@ -0,0 +1,131 @@ +[[ + ["start",{}], + ["text","Searching for '"], + ["text","var"], + ["text","' in"], + ["text"," /.c9/metadata/workspace/plugins "], + ["text","(regexp, case sensitive, whole word)"], + "Searching for \u0001var\u0001 in\u0001/.c9/metadata/workspace/plugins\u0001\u0001regexp, case sensitive, whole word\u0001" +],[ + ["start",{}] +],[ + ["start",{}], + ["string","configs/default.js"], + ["text",":"] +],[ + ["start",{}], + ["c9searchresults.constant.numeric"," 1"], + ["c9searchresults.text",": "], + ["c9searchresults.keyword","var"], + ["c9searchresults.text"," fs = require(\"fs\");"] +],[ + ["start",{}], + ["c9searchresults.constant.numeric","\t2"], + ["c9searchresults.text",": "], + ["c9searchresults.keyword","var"], + ["c9searchresults.text"," argv = require('optimist').argv;"] +],[ + ["start",{}], + ["c9searchresults.constant.numeric","\t3"], + ["c9searchresults.text",": "], + ["c9searchresults.keyword","var"], + ["c9searchresults.text"," path = require(\"path\");"] +],[ + ["start",{}], + ["c9searchresults.constant.numeric","\t5"], + ["c9searchresults.text",": "], + ["c9searchresults.keyword","var"], + ["c9searchresults.text"," clientExtensions = {};"] +],[ + ["start",{}], + ["c9searchresults.constant.numeric","\t6"], + ["c9searchresults.text",": "], + ["c9searchresults.keyword","var"], + ["c9searchresults.text"," clientDirs = fs.readdirSync(__dirname + \"/../plugins-client\");"] +],[ + ["start",{}], + ["c9searchresults.constant.numeric","\t7"], + ["c9searchresults.text",": "], + ["c9searchresults.text","for ("], + ["c9searchresults.keyword","var"], + ["c9searchresults.text"," i = 0; i < clientDirs.length; i++) {"] +],[ + ["start",{}], + ["c9searchresults.constant.numeric","\t8"], + ["c9searchresults.text",": "], + ["c9searchresults.text"," "], + ["c9searchresults.keyword","var"], + ["c9searchresults.text"," dir = clientDirs[i];"] +],[ + ["start",{}], + ["c9searchresults.constant.numeric","\t12"], + ["c9searchresults.text",": "], + ["c9searchresults.text"," "], + ["c9searchresults.keyword","var"], + ["c9searchresults.text"," name = dir.split(\".\")[1];"] +],[ + ["start",{}], + ["c9searchresults.constant.numeric","\t16"], + ["c9searchresults.text",": "], + ["c9searchresults.keyword","var"], + ["c9searchresults.text"," projectDir = (argv.w && path.resolve(process.cwd(), argv.w)) || process.cwd();"] +],[ + ["start",{}], + ["c9searchresults.constant.numeric","\t17"], + ["c9searchresults.text",": "], + ["c9searchresults.keyword","var"], + ["c9searchresults.text"," fsUrl = \"/workspace\";"] +],[ + ["start",{}], + ["c9searchresults.constant.numeric","\t19"], + ["c9searchresults.text",": "], + ["c9searchresults.keyword","var"], + ["c9searchresults.text"," port = argv.p || process.env.PORT || 3131;"] +],[ + ["start",{}], + ["c9searchresults.constant.numeric","\t20"], + ["c9searchresults.text",": "], + ["c9searchresults.keyword","var"], + ["c9searchresults.text"," host = argv.l || \"localhost\";"] +],[ + ["start",{}], + ["c9searchresults.constant.numeric","\t22"], + ["c9searchresults.text",": "], + ["c9searchresults.keyword","var"], + ["c9searchresults.text"," config = {"] +],[ + ["start",{}] +],[ + ["start",{}], + ["string","configs/local.js"], + ["text",":"] +],[ + ["start",{}], + ["c9searchresults.constant.numeric","\t2"], + ["c9searchresults.text",": "], + ["c9searchresults.keyword","var"], + ["c9searchresults.text"," config = require(\"./default\");"] +],[ + ["start",{}] +],[ + ["start",{}], + ["string","configs/packed.js"], + ["text",":"] +],[ + ["start",{}], + ["c9searchresults.constant.numeric","\t1"], + ["c9searchresults.text",": "], + ["c9searchresults.keyword","var"], + ["c9searchresults.text"," config = require(\"./default\");"] +],[ + ["start",{}] +],[ + ["start",{}] +],[ + ["start",{}], + ["text","Found "], + ["constant.numeric","15"], + ["text"," matches in "], + ["constant.numeric","3"], + ["text"," files"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_c_cpp.json b/node_modules/ace/lib/ace/mode/_test/tokens_c_cpp.json new file mode 100644 index 00000000..a8668b0b --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_c_cpp.json @@ -0,0 +1,190 @@ +[[ + "start", + ["comment","// compound assignment operators"] +],[ + "start" +],[ + "start", + ["keyword","#include"], + ["constant.other"," "] +],[ + "start" +],[ + "directive", + ["keyword","#include"], + ["constant.other.multiline"," \\"] +],[ + "start", + ["constant.other"," "] +],[ + "start" +],[ + "directive", + ["keyword","#include"], + ["constant.other.multiline"," \\"] +],[ + "directive", + ["constant.other.multiline"," \\"] +],[ + "start", + ["constant.other"," "] +],[ + "start" +],[ + "directive", + ["keyword","#include"], + ["constant.other.multiline"," \\"] +],[ + "directive", + ["constant.other.multiline"," \\"] +],[ + "start", + ["constant.other"," \"iostream\""] +],[ + "start" +],[ + "start", + ["keyword","#include"], + ["constant.other"," "] +],[ + "start", + ["keyword","#include"], + ["constant.other"," \"boost/asio/io_service.hpp\""] +],[ + "start" +],[ + "directive", + ["keyword","#include"], + ["constant.other.multiline"," \\"] +],[ + "directive", + ["constant.other.multiline"," \\"] +],[ + "directive", + ["constant.other.multiline"," \"iostream\" \\"] +],[ + "directive", + ["constant.other.multiline"," \"string\" \\"] +],[ + "start", + ["constant.other"," "] +],[ + "start", + ["text"," "] +],[ + "start", + ["keyword.control","using"], + ["text"," "], + ["keyword.operator","namespace"], + ["text"," "], + ["identifier","std"], + ["punctuation.operator",";"] +],[ + "start" +],[ + "start", + ["storage.type","int"], + ["text"," "], + ["identifier","main"], + ["text"," "], + ["paren.lparen","("], + ["paren.rparen",")"] +],[ + "start", + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["storage.type","int"], + ["text"," "], + ["identifier","a"], + ["punctuation.operator",","], + ["text"," "], + ["identifier","b"], + ["keyword.operator","="], + ["constant.numeric","3"], + ["punctuation.operator",";"], + ["text"," "], + ["comment","/* foobar */"] +],[ + "start", + ["text"," "], + ["identifier","a"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["identifier","b"], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "], + ["identifier","a"], + ["keyword.operator","+="], + ["constant.numeric","2"], + ["punctuation.operator",";"], + ["text"," "], + ["comment","// equivalent to a=a+2"] +],[ + "start", + ["text"," "], + ["identifier","cout"], + ["text"," "], + ["keyword.operator","<<"], + ["text"," "], + ["identifier","a"], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "], + ["keyword","#if"], + ["text"," "], + ["identifier","VERBOSE"], + ["text"," "], + ["keyword.operator",">="], + ["text"," "], + ["constant.numeric","2"] +],[ + "start", + ["text"," "], + ["identifier","prints"], + ["paren.lparen","("], + ["string","\"trace message\""], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "], + ["keyword","#endif"] +],[ + "start", + ["text"," "], + ["keyword.control","return"], + ["text"," "], + ["constant.numeric","0"], + ["punctuation.operator",";"] +],[ + "start", + ["paren.rparen","}"] +],[ + "start" +],[ + "start", + ["comment","/* Print an error message and get out */"] +],[ + "directive", + ["keyword","#define"], + ["constant.other.multiline"," ABORT \\"] +],[ + "directive", + ["constant.other.multiline"," do { \\"] +],[ + "directive", + ["constant.other.multiline"," print( \"Abort\\n\" ); \\"] +],[ + "directive", + ["constant.other.multiline"," exit(8); \\"] +],[ + "start", + ["constant.other","} while (0) "], + ["comment","/* Note: No semicolon */"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_cirru.json b/node_modules/ace/lib/ace/mode/_test/tokens_cirru.json new file mode 100644 index 00000000..de4852e6 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_cirru.json @@ -0,0 +1,267 @@ +[[ + "start", + ["comment.line.double-dash","-- https://github.com/Cirru/cirru-gopher/blob/master/code/scope.cr,"] +],[ + "start" +],[ + "line", + ["support.function","set"], + ["text"," "], + ["variable.parameter","a"], + ["text"," "], + ["storage.modifier","("], + ["support.function","int"], + ["text"," "], + ["constant.numeric","2"], + ["storage.modifier",")"] +],[ + "start" +],[ + "line", + ["support.function","print"], + ["text"," "], + ["storage.modifier","("], + ["support.function","self"], + ["storage.modifier",")"] +],[ + "start" +],[ + "line", + ["support.function","set"], + ["text"," "], + ["variable.parameter","c"], + ["text"," "], + ["storage.modifier","("], + ["support.function","child"], + ["storage.modifier",")"] +],[ + "start" +],[ + "line", + ["support.function","under"], + ["text"," "], + ["variable.parameter","c"] +],[ + "line", + ["markup.raw"," "], + ["support.function","under"], + ["text"," "], + ["variable.parameter","parent"] +],[ + "line", + ["markup.raw"," "], + ["support.function","print"], + ["text"," "], + ["variable.parameter","a"] +],[ + "start" +],[ + "line", + ["support.function","print"], + ["text"," "], + ["storage.modifier","$"], + ["text"," "], + ["support.function","get"], + ["text"," "], + ["variable.parameter","c"], + ["text"," "], + ["variable.parameter","a"] +],[ + "start" +],[ + "line", + ["support.function","set"], + ["text"," "], + ["variable.parameter","c"], + ["text"," "], + ["variable.parameter","x"], + ["text"," "], + ["storage.modifier","("], + ["support.function","int"], + ["text"," "], + ["constant.numeric","3"], + ["storage.modifier",")"] +],[ + "line", + ["support.function","print"], + ["text"," "], + ["storage.modifier","$"], + ["text"," "], + ["support.function","get"], + ["text"," "], + ["variable.parameter","c"], + ["text"," "], + ["variable.parameter","x"] +],[ + "start" +],[ + "line", + ["support.function","set"], + ["text"," "], + ["variable.parameter","just-print"], + ["text"," "], + ["storage.modifier","$"], + ["text"," "], + ["support.function","code"] +],[ + "line", + ["markup.raw"," "], + ["support.function","print"], + ["text"," "], + ["variable.parameter","a"] +],[ + "start" +],[ + "line", + ["support.function","print"], + ["text"," "], + ["variable.parameter","just-print"] +],[ + "start" +],[ + "line", + ["support.function","eval"], + ["text"," "], + ["storage.modifier","("], + ["support.function","self"], + ["storage.modifier",")"], + ["text"," "], + ["variable.parameter","just-print"] +],[ + "line", + ["support.function","eval"], + ["text"," "], + ["variable.parameter","just-print"] +],[ + "start" +],[ + "line", + ["support.function","print"], + ["text"," "], + ["storage.modifier","("], + ["support.function","string"], + ["text"," "], + ["string.quoted.double","\"string with space\""], + ["storage.modifier",")"] +],[ + "line", + ["support.function","print"], + ["text"," "], + ["storage.modifier","("], + ["support.function","string"], + ["text"," "], + ["string.quoted.double","\"escapes "], + ["constant.character.escape","\\n"], + ["string.quoted.double"," "], + ["constant.character.escape","\\\"\\\\"], + ["string.quoted.double","\""], + ["storage.modifier",")"] +],[ + "start" +],[ + "start", + ["support.function","brackets"], + ["text"," "], + ["storage.modifier","((((()))))"] +],[ + "start" +],[ + "line", + ["string.quoted.double","\"eval\""], + ["text"," "], + ["storage.modifier","$"], + ["text"," "], + ["support.function","string"], + ["text"," "], + ["string.quoted.double","\"eval\""] +],[ + "start" +],[ + "line", + ["support.function","print"], + ["text"," "], + ["storage.modifier","("], + ["support.function","add"], + ["text"," "], + ["storage.modifier","$"], + ["text"," "], + ["storage.modifier","("], + ["support.function","int"], + ["text"," "], + ["constant.numeric","1"], + ["storage.modifier",")"], + ["text"," "], + ["storage.modifier","("], + ["support.function","int"], + ["text"," "], + ["constant.numeric","2"], + ["storage.modifier","))"] +],[ + "start" +],[ + "start", + ["support.function","print"], + ["text"," "], + ["storage.modifier","$"], + ["text"," "], + ["support.function","unwrap"], + ["text"," "], + ["storage.modifier","$"] +],[ + "line", + ["text"," "], + ["support.function","map"], + ["text"," "], + ["storage.modifier","("], + ["support.function","a"], + ["text"," "], + ["storage.modifier","$"], + ["text"," "], + ["support.function","int"], + ["text"," "], + ["constant.numeric","1"], + ["storage.modifier",")"], + ["text"," "], + ["storage.modifier","("], + ["support.function","b"], + ["text"," "], + ["storage.modifier","$"], + ["text"," "], + ["support.function","int"], + ["text"," "], + ["constant.numeric","2"], + ["storage.modifier",")"] +],[ + "start" +],[ + "line", + ["support.function","print"], + ["text"," "], + ["variable.parameter","a"] +],[ + "line", + ["markup.raw"," "], + ["support.function","int"], + ["text"," "], + ["constant.numeric","1"] +],[ + "line", + ["markup.raw"," "], + ["storage.modifier",","], + ["text"," "], + ["variable.parameter","b"], + ["text"," "], + ["variable.parameter","c"] +],[ + "line", + ["markup.raw"," "], + ["support.function","int"], + ["text"," "], + ["constant.numeric","2"] +],[ + "line", + ["markup.raw"," "], + ["storage.modifier",","], + ["text"," "], + ["variable.parameter","d"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_clojure.json b/node_modules/ace/lib/ace/mode/_test/tokens_clojure.json new file mode 100644 index 00000000..824cba59 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_clojure.json @@ -0,0 +1,162 @@ +[[ + "start", + ["keyword","("], + ["support.function","defn"], + ["text"," "], + ["identifier","parting"] +],[ + "start", + ["text"," "], + ["string","\"returns a String parting in a given language\""] +],[ + "start", + ["text"," "], + ["keyword","([]"], + ["text"," "], + ["keyword","("], + ["identifier","parting"], + ["text"," "], + ["string","\"World\""], + ["keyword","))"] +],[ + "start", + ["text"," "], + ["keyword","(["], + ["support.function","name"], + ["keyword","]"], + ["text"," "], + ["keyword","("], + ["identifier","parting"], + ["text"," "], + ["support.function","name"], + ["text"," "], + ["string","\"en\""], + ["keyword","))"] +],[ + "start", + ["text"," "], + ["keyword","(["], + ["support.function","name"], + ["text"," "], + ["identifier","language"], + ["keyword","]"] +],[ + "start", + ["text"," "], + ["comment","; condp is similar to a case statement in other languages."] +],[ + "start", + ["text"," "], + ["comment","; It is described in more detail later."] +],[ + "start", + ["text"," "], + ["comment","; It is used here to take different actions based on whether the"] +],[ + "start", + ["text"," "], + ["comment","; parameter \"language\" is set to \"en\", \"es\" or something else."] +],[ + "start", + ["text"," "], + ["keyword","("], + ["support.function","condp"], + ["text"," "], + ["constant.language","="], + ["text"," "], + ["identifier","language"] +],[ + "start", + ["text"," "], + ["string","\"en\""], + ["text"," "], + ["keyword","("], + ["support.function","str"], + ["text"," "], + ["string","\"Goodbye, \""], + ["text"," "], + ["support.function","name"], + ["keyword",")"] +],[ + "start", + ["text"," "], + ["string","\"es\""], + ["text"," "], + ["keyword","("], + ["support.function","str"], + ["text"," "], + ["string","\"Adios, \""], + ["text"," "], + ["support.function","name"], + ["keyword",")"] +],[ + "start", + ["text"," "], + ["keyword","(throw"], + ["text"," "], + ["keyword","("], + ["identifier","IllegalArgumentException"], + ["text","."] +],[ + "start", + ["text"," "], + ["keyword","("], + ["support.function","str"], + ["text"," "], + ["string","\"unsupported language \""], + ["text"," "], + ["identifier","language"], + ["keyword","))))))"] +],[ + "start" +],[ + "start", + ["keyword","("], + ["support.function","println"], + ["text"," "], + ["keyword","("], + ["identifier","parting"], + ["keyword","))"], + ["text"," "], + ["comment","; -> Goodbye, World"] +],[ + "start", + ["keyword","("], + ["support.function","println"], + ["text"," "], + ["keyword","("], + ["identifier","parting"], + ["text"," "], + ["string","\"Mark\""], + ["keyword","))"], + ["text"," "], + ["comment","; -> Goodbye, Mark"] +],[ + "start", + ["keyword","("], + ["support.function","println"], + ["text"," "], + ["keyword","("], + ["identifier","parting"], + ["text"," "], + ["string","\"Mark\""], + ["text"," "], + ["string","\"es\""], + ["keyword","))"], + ["text"," "], + ["comment","; -> Adios, Mark"] +],[ + "start", + ["keyword","("], + ["support.function","println"], + ["text"," "], + ["keyword","("], + ["identifier","parting"], + ["text"," "], + ["string","\"Mark\""], + ["text",", "], + ["string","\"xy\""], + ["keyword","))"], + ["text"," "], + ["comment","; -> java.lang.IllegalArgumentException: unsupported language xy"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_cobol.json b/node_modules/ace/lib/ace/mode/_test/tokens_cobol.json new file mode 100644 index 00000000..9909eadd --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_cobol.json @@ -0,0 +1,4 @@ +[[ + "start", + ["identifier","TODO"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_coffee.json b/node_modules/ace/lib/ace/mode/_test/tokens_coffee.json new file mode 100644 index 00000000..b0703b37 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_coffee.json @@ -0,0 +1,545 @@ +[[ + "start", + ["comment","#test: tokenize keyword"] +],[ + "start", + ["text"," "], + ["keyword","for"], + ["text"," "], + ["paren.lparen","("], + ["identifier","i"], + ["text"," "], + ["constant.numeric","1"], + ["punctuation.operator","."], + ["constant.numeric",".2"], + ["paren.rparen",")"] +],[ + "start", + ["comment","#test: tokenize regexp"] +],[ + "start", + ["string.regex","/\"[a]/"] +],[ + "start", + ["comment","#test: tokenize functions"] +],[ + "start", + ["entity.name.function","foo"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["paren.lparen","("], + ["variable.parameter","{args}"], + ["paren.rparen",")"], + ["text"," "], + ["storage.type","->"] +],[ + "start", + ["text"," "], + ["entity.name.function","foo"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["paren.lparen","("], + ["variable.parameter","{a1, a2}"], + ["paren.rparen",")"], + ["text"," "], + ["storage.type","->"] +],[ + "start", + ["text"," "], + ["entity.name.function","foo"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["paren.lparen","("], + ["variable.parameter","{@a1, a2}"], + ["paren.rparen",")"], + ["text"," "], + ["storage.type","->"] +],[ + "start", + ["text"," "], + ["entity.name.function","foo"], + ["text"," "], + ["keyword.operator",":"], + ["text"," "], + ["paren.lparen","("], + ["variable.parameter","{args}"], + ["paren.rparen",")"], + ["text"," "], + ["storage.type","->"] +],[ + "start", + ["text"," "], + ["entity.name.function","foo"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["paren.lparen","("], + ["variable.parameter","{args}"], + ["paren.rparen",")"], + ["text"," "], + ["storage.type","->"] +],[ + "start", + ["text"," "], + ["entity.name.function","foo"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["paren.lparen","("], + ["variable.parameter","{0abc}"], + ["paren.rparen",")"], + ["text"," "], + ["storage.type","->"] +],[ + "start", + ["text"," "], + ["identifier","foo"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["paren.lparen","("], + ["paren","{"], + ["keyword.operator","/"], + ["identifier","abc"], + ["paren","}"], + ["paren.rparen",")"], + ["text"," "], + ["storage.type","=>"] +],[ + "start", + ["text"," "], + ["identifier","foo"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["paren.lparen","("], + ["paren","{"], + ["identifier","abc"], + ["keyword.operator","/"], + ["paren","}"], + ["paren.rparen",")"], + ["text"," "], + ["storage.type","->"] +],[ + "start", + ["text"," "], + ["entity.name.function","foo"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["paren.lparen","("], + ["variable.parameter","{#abc}"], + ["paren.rparen",")"], + ["text"," "], + ["storage.type","->"] +],[ + "start", + ["text"," "], + ["entity.name.function","foo"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["paren.lparen","("], + ["variable.parameter","{abc#}"], + ["paren.rparen",")"], + ["text"," "], + ["storage.type","->"] +],[ + "start", + ["text"," "], + ["identifier","foo"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["paren.lparen","("], + ["paren","{"], + ["paren.rparen",")"], + ["identifier","abc"], + ["paren","}"], + ["paren.rparen",")"], + ["text"," "], + ["storage.type","->"] +],[ + "start", + ["text"," "], + ["identifier","foo"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["paren.lparen","("], + ["paren","{"], + ["identifier","abc"], + ["paren.rparen",")"], + ["paren","}"], + ["paren.rparen",")"], + ["text"," "], + ["storage.type","->"] +],[ + "start", + ["text"," "], + ["entity.name.function","foo"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["paren.lparen","("], + ["variable.parameter","{a{bc}"], + ["paren.rparen",")"], + ["text"," "], + ["storage.type","->"] +],[ + "start", + ["text"," "], + ["entity.name.function","foo"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["paren.lparen","("], + ["variable.parameter","{}"], + ["paren.rparen",")"], + ["text"," "], + ["storage.type","->"] +],[ + "start", + ["text"," "], + ["entity.name.function","foo"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["paren.lparen","("], + ["variable.parameter","{ }"], + ["paren.rparen",")"], + ["text"," "], + ["storage.type","->"] +],[ + "start", + ["text"," "], + ["entity.name.function","foo"], + ["text"," "], + ["keyword.operator",":"], + ["text"," "], + ["paren.lparen","("], + ["variable.parameter","{}"], + ["paren.rparen",")"], + ["text"," "], + ["storage.type","->"] +],[ + "start", + ["text"," "], + ["entity.name.function","foo"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["paren.lparen","("], + ["variable.parameter","args"], + ["paren.rparen",")"], + ["text"," "], + ["storage.type","->"] +],[ + "start", + ["text"," "], + ["entity.name.function","foo"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["paren.lparen","("], + ["variable.parameter","arg1, arg2"], + ["paren.rparen",")"], + ["text"," "], + ["storage.type","->"] +],[ + "start", + ["text"," "], + ["entity.name.function","foo"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["paren.lparen","("], + ["variable.parameter","arg1 = 1, arg2 = 'name'"], + ["paren.rparen",")"], + ["text"," "], + ["storage.type","->"] +],[ + "start", + ["text"," "], + ["entity.name.function","foo"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["paren.lparen","("], + ["variable.parameter","@arg1 = /abc/, arg2 = 'name'"], + ["paren.rparen",")"], + ["text"," "], + ["storage.type","->"] +],[ + "start", + ["text"," "], + ["comment","#test: tokenize function: invalid case:"] +],[ + "start", + ["text"," "], + ["identifier","foo"], + ["keyword.operator","="], + ["paren.lparen","("], + ["keyword.operator","/"], + ["identifier","args"], + ["paren.rparen",")"], + ["text"," "], + ["storage.type","->"] +],[ + "start", + ["text"," "], + ["entity.name.function","foo"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["paren.lparen","("], + ["paren.rparen",")"], + ["text"," "], + ["storage.type","->"] +],[ + "start", + ["text"," "], + ["entity.name.function","foo"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["paren.lparen","("], + ["variable.parameter"," "], + ["paren.rparen",")"], + ["text"," "], + ["storage.type","->"] +],[ + "start", + ["text"," "], + ["entity.name.function","foo"], + ["text"," "], + ["keyword.operator",":"], + ["text"," "], + ["paren.lparen","("], + ["variable.parameter"," "], + ["paren.rparen",")"], + ["text"," "], + ["storage.type","->"] +],[ + "start", + ["text"," "], + ["variable.language","window"], + ["punctuation.operator","."], + ["entity.name.function","foo"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["paren.lparen","("], + ["variable.parameter","args"], + ["paren.rparen",")"], + ["text"," "], + ["storage.type","->"] +],[ + "start", + ["text"," "], + ["entity.name.function","foo"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["storage.type","->"] +],[ + "start", + ["text"," "], + ["entity.name.function","foo"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["storage.type","->"] +],[ + "start", + ["text"," "], + ["entity.name.function","foo"], + ["text"," "], + ["keyword.operator",":"], + ["text"," "], + ["storage.type","->"] +],[ + "start", + ["text"," "], + ["comment","#test: tokenize callback function"] +],[ + "start", + ["text"," "], + ["identifier","foo"], + ["text"," "], + ["identifier","bar"], + ["keyword.operator",":"], + ["text"," "], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["text"," "], + ["paren.lparen","("], + ["variable.parameter","args"], + ["paren.rparen",")"], + ["text"," "], + ["storage.type","->"] +],[ + "start", + ["text"," "], + ["identifier","foo"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["paren.lparen","("], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["text"," "], + ["constant.numeric","2"], + ["text"," "], + ["paren.lparen","("], + ["variable.parameter","x"], + ["paren.rparen",")"], + ["text"," "], + ["storage.type","->"] +],[ + "start", + ["comment","#test: tokenize class"] +],[ + "start", + ["keyword","class"], + ["text"," "], + ["language.support.class","Foo"] +],[ + "start", + ["keyword","class"], + ["text"," "], + ["language.support.class","Foo"], + ["text"," "], + ["keyword","extends"], + ["text"," "], + ["language.support.class","Bar"] +],[ + "start", + ["comment","#test: tokenize illegal name property"] +],[ + "start", + ["identifier","foo"], + ["punctuation.operator","."], + ["identifier","static"], + ["punctuation.operator","."], + ["identifier","function"] +],[ + "start", + ["comment","#!test tokenize string with interpolation"] +],[ + "start", + ["identifier","a"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["string.start","\""], + ["paren.string","#{"], + ["text"," "], + ["constant.numeric","22"], + ["text"," "], + ["keyword.operator","/"], + ["text"," "], + ["constant.numeric","7"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["paren","{"], + ["identifier","x"], + ["keyword.operator",":"], + ["text"," "], + ["string.start","\""], + ["paren.string","#{"], + ["identifier","a"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["identifier","b"], + ["paren.string","}"], + ["string.end","\""], + ["paren","}"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["constant.numeric","2"], + ["paren.string","}"], + ["string.end","\""] +],[ + "start", + ["string.start","\""], + ["string"," "], + ["paren.string","#{"], + ["text"," "], + ["string.start","\""], + ["string.end","\""], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["paren","{}"], + ["text"," "], + ["paren.string","}"], + ["string"," )"], + ["string.end","\""], + ["text"," "] +],[ + "qqdoc", + ["string","\"\"\"heredoc"] +],[ + "start", + ["string"," \"\"\""] +],[ + "start", + ["keyword","do"], + ["text"," "], + ["storage.type","->"] +],[ + "comment", + ["text"," "], + ["comment","###"] +],[ + "comment", + ["comment"," herecomment"] +],[ + "start", + ["comment"," ###"] +],[ + "heregex", + ["text"," "], + ["identifier","re"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["string.regex","/regex/imgy"], + ["punctuation.operator","."], + ["identifier","test"], + ["text"," "], + ["string.regex","///"] +],[ + "heregex", + ["comment.regex"," "], + ["string.regex","heregex"], + ["comment.regex"," # comment"] +],[ + "start", + ["string.regex"," ///imgy"] +],[ + "js", + ["text"," "], + ["keyword","this"], + ["text"," "], + ["keyword","isnt"], + ["keyword.operator",":"], + ["text"," "], + ["string","`just "] +],[ + "start", + ["string"," JavaScript`"] +],[ + "start", + ["text"," "], + ["constant.language","undefined"] +],[ + "start" +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_coldfusion.json b/node_modules/ace/lib/ace/mode/_test/tokens_coldfusion.json new file mode 100644 index 00000000..804e647d --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_coldfusion.json @@ -0,0 +1,26 @@ +[[ + "start", + ["comment.xml",""] +],[ + "start" +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","cfset"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","welcome"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"Hello World!\""], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start" +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","cfoutput"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text.xml","#welcome#"], + ["meta.tag.punctuation.end-tag-open.xml",""] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_csharp.json b/node_modules/ace/lib/ace/mode/_test/tokens_csharp.json new file mode 100644 index 00000000..dcc6d0e9 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_csharp.json @@ -0,0 +1,31 @@ +[[ + "start", + ["keyword","public"], + ["text"," "], + ["keyword","void"], + ["text"," "], + ["identifier","HelloWorld"], + ["paren.lparen","("], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["comment","//Say Hello!"] +],[ + "start", + ["text"," "], + ["identifier","Console"], + ["punctuation.operator","."], + ["identifier","WriteLine"], + ["paren.lparen","("], + ["string.start","\""], + ["string","Hello World"], + ["string.end","\""], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + "start", + ["paren.rparen","}"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_css.json b/node_modules/ace/lib/ace/mode/_test/tokens_css.json new file mode 100644 index 00000000..e1a7ba05 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_css.json @@ -0,0 +1,148 @@ +[[ + "ruleset", + ["variable",".text-layer"], + ["text"," "], + ["paren.lparen","{"] +],[ + "ruleset", + ["text"," "], + ["support.type","font-family"], + ["text",": Monaco, "], + ["string","\"Courier New\""], + ["text",", "], + ["support.constant.fonts","monospace"], + ["text",";"] +],[ + "ruleset", + ["text"," "], + ["support.type","font-size"], + ["text",": "], + ["constant.numeric","12"], + ["keyword","pX"], + ["text",";"] +],[ + "ruleset", + ["text"," "], + ["support.type","cursor"], + ["text",": "], + ["support.constant","text"], + ["text",";"] +],[ + "start", + ["paren.rparen","}"] +],[ + "start" +],[ + "ruleset", + ["variable",".blinker"], + ["text"," "], + ["paren.lparen","{"] +],[ + "ruleset", + ["text"," "], + ["support.type","animation-duration"], + ["text",": "], + ["constant.numeric","1"], + ["keyword","s"], + ["text",";"] +],[ + "ruleset", + ["text"," "], + ["support.type","animation-name"], + ["text",": blink;"] +],[ + "ruleset", + ["text"," "], + ["support.type","animation-iteration-count"], + ["text",": infinite;"] +],[ + "ruleset", + ["text"," "], + ["support.type","animation-direction"], + ["text",": alternate;"] +],[ + "ruleset", + ["text"," "], + ["support.type","animation-timing-function"], + ["text",": "], + ["support.constant","linear"], + ["text",";"] +],[ + "start", + ["paren.rparen","}"] +],[ + "start" +],[ + "media", + ["string","@keyframes blink {"] +],[ + ["ruleset","media"], + ["text"," "], + ["constant","0"], + ["text","% "], + ["paren.lparen","{"] +],[ + ["ruleset","media"], + ["text"," "], + ["support.type","opacity"], + ["text",": "], + ["constant.numeric","0"], + ["text",";"] +],[ + "media", + ["text"," "], + ["paren.rparen","}"] +],[ + ["ruleset","media"], + ["text"," "], + ["constant","40"], + ["text","% "], + ["paren.lparen","{"] +],[ + ["ruleset","media"], + ["text"," "], + ["support.type","opacity"], + ["text",": "], + ["constant.numeric","0"], + ["text",";"] +],[ + "media", + ["text"," "], + ["paren.rparen","}"] +],[ + ["ruleset","media"], + ["text"," "], + ["constant","40"], + ["variable",".5"], + ["text","% "], + ["paren.lparen","{"] +],[ + ["ruleset","media"], + ["text"," "], + ["support.type","opacity"], + ["text",": "], + ["constant.numeric","1"] +],[ + "media", + ["text"," "], + ["paren.rparen","}"] +],[ + ["ruleset","media"], + ["text"," "], + ["constant","100"], + ["text","% "], + ["paren.lparen","{"] +],[ + ["ruleset","media"], + ["text"," "], + ["support.type","opacity"], + ["text",": "], + ["constant.numeric","1"] +],[ + "media", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["string","}"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_curly.json b/node_modules/ace/lib/ace/mode/_test/tokens_curly.json new file mode 100644 index 00000000..d87a627a --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_curly.json @@ -0,0 +1,56 @@ +[[ + "start", + ["text.xml","tokenize Curly template"], + ["variable","{{"], + ["text","test"], + ["variable","}}"] +],[ + "start", + ["text.xml","tokenize embedded script"] +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.script.tag-name.xml","script"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","a"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","'a'"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["storage.type","var"], + ["meta.tag.punctuation.end-tag-open.xml",""], + ["text.xml","'123'"] +],[ + "start", + ["text.xml","tokenize multiline attribute value with double quotes"] +],[ + ["string.attribute-value.xml0","tag_stuff"], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.anchor.tag-name.xml","a"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","href"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"abc{{xyz}}"] +],[ + "start", + ["string.attribute-value.xml","def\""], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml","tokenize multiline attribute value with single quotes"] +],[ + ["string.attribute-value.xml","tag_stuff"], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.anchor.tag-name.xml","a"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","href"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","'abc"] +],[ + "start", + ["string.attribute-value.xml","def\\\"'"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start" +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_d.json b/node_modules/ace/lib/ace/mode/_test/tokens_d.json new file mode 100644 index 00000000..85831cc3 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_d.json @@ -0,0 +1,111 @@ +[[ + "start", + ["comment.shebang","#!/usr/bin/env rdmd"] +],[ + "start", + ["comment","// Computes average line length for standard input."] +],[ + "start", + ["keyword","import"], + ["text"," "], + ["variable.module","std.stdio"], + ["punctuation.operator",";"] +],[ + "start" +],[ + "start", + ["keyword.type","void"], + ["text"," "], + ["identifier","main"], + ["paren.lparen","("], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["keyword.type","ulong"], + ["text"," "], + ["identifier","lines"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["constant.numeric","0"], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "], + ["keyword.type","double"], + ["text"," "], + ["identifier","sumLength"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["constant.numeric","0"], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "], + ["keyword.control","foreach"], + ["text"," "], + ["paren.lparen","("], + ["identifier","line"], + ["punctuation.operator",";"], + ["text"," "], + ["identifier","stdin"], + ["punctuation.operator","."], + ["identifier","byLine"], + ["paren.lparen","("], + ["paren.rparen","))"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["keyword.operator","++"], + ["identifier","lines"], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "], + ["identifier","sumLength"], + ["text"," "], + ["keyword.operator","+="], + ["text"," "], + ["identifier","line"], + ["punctuation.operator","."], + ["identifier","length"], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["text"," "], + ["identifier","writeln"], + ["paren.lparen","("], + ["string","\"Average line length: \""], + ["punctuation.operator",","] +],[ + "start", + ["text"," "], + ["identifier","lines"], + ["text"," "], + ["keyword.operator","?"], + ["text"," "], + ["identifier","sumLength"], + ["text"," "], + ["keyword.operator","/"], + ["text"," "], + ["identifier","lines"], + ["text"," "], + ["punctuation.operator",":"], + ["text"," "], + ["constant.numeric","0"], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + "start", + ["paren.rparen","}"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_dart.json b/node_modules/ace/lib/ace/mode/_test/tokens_dart.json new file mode 100644 index 00000000..37cdc323 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_dart.json @@ -0,0 +1,368 @@ +[[ + "start", + ["identifier","main"], + ["text","() {"] +],[ + "start", + ["text"," "], + ["identifier","print"], + ["text","("], + ["string","'Hello World!'"], + ["text",");"] +],[ + "start", + ["text","}"] +],[ + "start" +],[ + "start" +],[ + "start", + ["storage.type.primitive.dart","int"], + ["text"," "], + ["identifier","fib"], + ["text","("], + ["storage.type.primitive.dart","int"], + ["text"," "], + ["identifier","n"], + ["text",") "], + ["keyword.operator.assignment.dart","="], + ["keyword.operator.comparison.dart",">"], + ["text"," ("], + ["identifier","n"], + ["text"," "], + ["keyword.operator.comparison.dart",">"], + ["text"," "], + ["constant.numeric","1"], + ["text",") "], + ["keyword.control.ternary.dart","?"], + ["text"," ("], + ["identifier","fib"], + ["text","("], + ["identifier","n"], + ["text"," "], + ["keyword.operator.arithmetic.dart","-"], + ["text"," "], + ["constant.numeric","1"], + ["text",") "], + ["keyword.operator.arithmetic.dart","+"], + ["text"," "], + ["identifier","fib"], + ["text","("], + ["identifier","n"], + ["text"," "], + ["keyword.operator.arithmetic.dart","-"], + ["text"," "], + ["constant.numeric","2"], + ["text",")) "], + ["keyword.control.ternary.dart",":"], + ["text"," "], + ["identifier","n"], + ["text",";"] +],[ + "start", + ["identifier","main"], + ["text","() {"] +],[ + "start", + ["text"," "], + ["identifier","print"], + ["text","("], + ["string","'fib(20) = ${fib(20)}'"], + ["text",");"] +],[ + "start", + ["text","}"] +],[ + "comment", + ["comment","/*asd"] +],[ + "comment", + ["comment","asdad"] +],[ + "start", + ["comment","*/"] +],[ + "start", + ["constant.numeric","0.67"] +],[ + "start", + ["constant.numeric","77"] +],[ + "start", + ["text","."], + ["constant.numeric","86"] +],[ + "start" +],[ + "start", + ["keyword.other.import.dart","import"], + ["text","("], + ["string","\"http://dartwatch.com/myOtherLibrary.dart\""], + ["text",");"] +],[ + "start", + ["keyword.other.import.dart","import"], + ["text","("], + ["string","\"myOtherLibrary.dart\""], + ["text",", "], + ["keyword.other.import.dart","prefix"], + ["text",":"], + ["string","\"lib1\""], + ["text",");"] +],[ + "start" +],[ + "qqdoc", + ["string","\"\"\"asdasdads"] +],[ + "qqdoc", + ["string","asdadsadsasd"] +],[ + "start", + ["string","asdasdasdad\"\"\""] +],[ + "start", + ["text"," "] +],[ + "start", + ["string","'23424'"] +],[ + "start" +],[ + "start", + ["constant.numeric","0x234"] +],[ + "start" +],[ + "start", + ["identifier","foo"], + ["text"," "], + ["keyword.operator.dart","is"], + ["text"," "], + ["identifier","bar"] +],[ + "start" +],[ + "start", + ["storage.type.primitive.dart","int"], + ["text"," "], + ["identifier","x"], + ["text"," "], + ["keyword.operator.assignment.dart","="], + ["text"," "], + ["constant.numeric","4"], + ["text"," "], + ["keyword.operator.bitwise.dart","<<"], + ["text"," "], + ["constant.numeric","10"], + ["text"," "] +],[ + "start", + ["comment","// Create a class for Point."] +],[ + "start", + ["keyword.declaration.dart","class"], + ["text"," "], + ["identifier","Point"], + ["text"," {"] +],[ + "start", + ["text"," "] +],[ + "start", + ["text"," "], + ["comment","// Final variables cannot be changed once they are assigned."] +],[ + "start", + ["text"," "], + ["comment","// Create two instance variables."] +],[ + "start", + ["text"," "], + ["storage.modifier.dart","final"], + ["text"," "], + ["storage.type.primitive.dart","num"], + ["text"," "], + ["identifier","x"], + ["text",", "], + ["identifier","y"], + ["text",";"] +],[ + "start", + ["text"," "] +],[ + "start", + ["text"," "], + ["comment","// A constructor, with syntactic sugar for setting instance variables."] +],[ + "start", + ["text"," "], + ["identifier","Point"], + ["text","("], + ["variable.language.dart","this"], + ["text","."], + ["identifier","x"], + ["text",", "], + ["variable.language.dart","this"], + ["text","."], + ["identifier","y"], + ["text",");"] +],[ + "start", + ["text"," "] +],[ + "start", + ["text"," "], + ["comment","// A named constructor with an initializer list."] +],[ + "start", + ["text"," "], + ["identifier","Point"], + ["text","."], + ["identifier","origin"], + ["text","() "], + ["keyword.control.ternary.dart",":"], + ["text"," "], + ["identifier","x"], + ["text"," "], + ["keyword.operator.assignment.dart","="], + ["text"," "], + ["constant.numeric","0"], + ["text",", "], + ["identifier","y"], + ["text"," "], + ["keyword.operator.assignment.dart","="], + ["text"," "], + ["constant.numeric","0"], + ["text",";"] +],[ + "start", + ["text"," "] +],[ + "start", + ["text"," "], + ["comment","// A method."] +],[ + "start", + ["text"," "], + ["storage.type.primitive.dart","num"], + ["text"," "], + ["identifier","distanceTo"], + ["text","("], + ["identifier","Point"], + ["text"," "], + ["identifier","other"], + ["text",") {"] +],[ + "start", + ["text"," "], + ["storage.type.primitive.dart","var"], + ["text"," "], + ["identifier","dx"], + ["text"," "], + ["keyword.operator.assignment.dart","="], + ["text"," "], + ["identifier","x"], + ["text"," "], + ["keyword.operator.arithmetic.dart","-"], + ["text"," "], + ["identifier","other"], + ["text","."], + ["identifier","x"], + ["text",";"] +],[ + "start", + ["text"," "], + ["storage.type.primitive.dart","var"], + ["text"," "], + ["identifier","dy"], + ["text"," "], + ["keyword.operator.assignment.dart","="], + ["text"," "], + ["identifier","y"], + ["text"," "], + ["keyword.operator.arithmetic.dart","-"], + ["text"," "], + ["identifier","other"], + ["text","."], + ["identifier","y"], + ["text",";"] +],[ + "start", + ["text"," "], + ["keyword.control.dart","return"], + ["text"," "], + ["identifier","sqrt"], + ["text","("], + ["identifier","dx"], + ["text"," "], + ["keyword.operator.arithmetic.dart","*"], + ["text"," "], + ["identifier","dx"], + ["text"," "], + ["keyword.operator.arithmetic.dart","+"], + ["text"," "], + ["identifier","dy"], + ["text"," "], + ["keyword.operator.arithmetic.dart","*"], + ["text"," "], + ["identifier","dy"], + ["text",");"] +],[ + "start", + ["text"," }"] +],[ + "start", + ["text","}"] +],[ + "start", + ["text"," "] +],[ + "start", + ["text"," "], + ["comment","// Check for null."] +],[ + "start", + ["storage.type.primitive.dart","var"], + ["text"," "], + ["identifier","unicorn"], + ["text",";"] +],[ + "start", + ["keyword.control.dart","assert"], + ["text","("], + ["identifier","unicorn"], + ["text"," "], + ["keyword.operator.comparison.dart","=="], + ["text"," "], + ["constant.language.dart","null"], + ["text",");"] +],[ + "start" +],[ + "start", + ["comment","// Check for NaN."] +],[ + "start", + ["storage.type.primitive.dart","var"], + ["text"," "], + ["identifier","iMeantToDoThis"], + ["text"," "], + ["keyword.operator.assignment.dart","="], + ["text"," "], + ["constant.numeric","0"], + ["keyword.operator.arithmetic.dart","/"], + ["constant.numeric","0"], + ["text",";"] +],[ + "start", + ["keyword.control.dart","assert"], + ["text","("], + ["identifier","iMeantToDoThis"], + ["text","."], + ["identifier","isNaN"], + ["text","());"] +],[ + "start" +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_diff.json b/node_modules/ace/lib/ace/mode/_test/tokens_diff.json new file mode 100644 index 00000000..6c36f5fa --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_diff.json @@ -0,0 +1,262 @@ +[[ + "start", + ["variable","diff"], + ["variable"," --git"], + ["keyword"," a/lib/ace/edit_session.js"], + ["variable"," b/lib/ace/edit_session.js"] +],[ + "start", + ["variable","index 23fc3fc..ed3b273 100644"] +],[ + "start", + ["constant.numeric","---"], + ["meta.tag"," a/lib/ace/edit_session.js"] +],[ + "start", + ["constant.numeric","+++"], + ["meta.tag"," b/lib/ace/edit_session.js"] +],[ + "start", + ["constant","@@"], + ["constant.numeric"," -51,6 +51,7 "], + ["constant","@@"], + ["comment.doc.tag"," var TextMode = require(\"./mode/text\").Mode;"] +],[ + "start", + ["invisible"," var Range = require(\"./range\").Range;"] +],[ + "start", + ["invisible"," var Document = require(\"./document\").Document;"] +],[ + "start", + ["invisible"," var BackgroundTokenizer = require(\"./background_tokenizer\").BackgroundTokenizer;"] +],[ + "start", + ["support.constant","+"], + ["text","var SearchHighlight = require(\"./search_highlight\").SearchHighlight;"] +],[ + "start", + ["text"," "] +],[ + "start", + ["invisible"," /**"] +],[ + "start", + ["invisible"," * class EditSession"] +],[ + "start", + ["constant","@@"], + ["constant.numeric"," -307,6 +308,13 "], + ["constant","@@"], + ["comment.doc.tag"," var EditSession = function(text, mode) {"] +],[ + "start", + ["invisible"," return token;"] +],[ + "start", + ["invisible"," };"] +],[ + "start", + ["text"," "] +],[ + "start", + ["support.constant","+"], + ["text"," this.highlight = function(re) {"] +],[ + "start", + ["support.constant","+"], + ["text"," if (!this.$searchHighlight) {"] +],[ + "start", + ["support.constant","+"], + ["text"," var highlight = new SearchHighlight(null, \"ace_selected-word\", \"text\");"] +],[ + "start", + ["support.constant","+"], + ["text"," this.$searchHighlight = this.addDynamicMarker(highlight);"] +],[ + "start", + ["support.constant","+"], + ["text"," }"] +],[ + "start", + ["support.constant","+"], + ["text"," this.$searchHighlight.setRegexp(re);"] +],[ + "start", + ["support.constant","+"], + ["text"," }"] +],[ + "start", + ["invisible"," /**"] +],[ + "start", + ["invisible"," * EditSession.setUndoManager(undoManager)"] +],[ + "start", + ["invisible"," * - undoManager (UndoManager): The new undo manager"] +],[ + "start", + ["constant","@@"], + ["constant.numeric"," -556,7 +564,8 "], + ["constant","@@"], + ["comment.doc.tag"," var EditSession = function(text, mode) {"] +],[ + "start", + ["invisible"," type : type || \"line\","] +],[ + "start", + ["invisible"," renderer: typeof type == \"function\" ? type : null,"] +],[ + "start", + ["invisible"," clazz : clazz,"] +],[ + "start", + ["support.function","-"], + ["string"," inFront: !!inFront"] +],[ + "start", + ["support.constant","+"], + ["text"," inFront: !!inFront,"] +],[ + "start", + ["support.constant","+"], + ["text"," id: id"] +],[ + "start", + ["invisible"," }"] +],[ + "start", + ["text"," "] +],[ + "start", + ["invisible"," if (inFront) {"] +],[ + "start", + ["variable","diff"], + ["variable"," --git"], + ["keyword"," a/lib/ace/editor.js"], + ["variable"," b/lib/ace/editor.js"] +],[ + "start", + ["variable","index 834e603..b27ec73 100644"] +],[ + "start", + ["constant.numeric","---"], + ["meta.tag"," a/lib/ace/editor.js"] +],[ + "start", + ["constant.numeric","+++"], + ["meta.tag"," b/lib/ace/editor.js"] +],[ + "start", + ["constant","@@"], + ["constant.numeric"," -494,7 +494,7 "], + ["constant","@@"], + ["comment.doc.tag"," var Editor = function(renderer, session) {"] +],[ + "start", + ["invisible"," * Emitted when a selection has changed."] +],[ + "start", + ["invisible"," **/"] +],[ + "start", + ["invisible"," this.onSelectionChange = function(e) {"] +],[ + "start", + ["support.function","-"], + ["string"," var session = this.getSession();"] +],[ + "start", + ["support.constant","+"], + ["text"," var session = this.session;"] +],[ + "start", + ["text"," "] +],[ + "start", + ["invisible"," if (session.$selectionMarker) {"] +],[ + "start", + ["invisible"," session.removeMarker(session.$selectionMarker);"] +],[ + "start", + ["constant","@@"], + ["constant.numeric"," -509,12 +509,40 "], + ["constant","@@"], + ["comment.doc.tag"," var Editor = function(renderer, session) {"] +],[ + "start", + ["invisible"," this.$updateHighlightActiveLine();"] +],[ + "start", + ["invisible"," }"] +],[ + "start", + ["text"," "] +],[ + "start", + ["support.function","-"], + ["string"," var self = this;"] +],[ + "start", + ["support.function","-"], + ["string"," if (this.$highlightSelectedWord && !this.$wordHighlightTimer)"] +],[ + "start", + ["support.function","-"], + ["string"," this.$wordHighlightTimer = setTimeout(function() {"] +],[ + "start", + ["support.function","-"], + ["string"," self.session.$mode.highlightSelection(self);"] +],[ + "start", + ["support.function","-"], + ["string"," self.$wordHighlightTimer = null;"] +],[ + "start", + ["support.function","-"], + ["string"," }, 30, this);"] +],[ + "start", + ["support.constant","+"], + ["text"," var re = this.$highlightSelectedWord && this.$getSelectionHighLightRegexp()"] +],[ + "start", + ["invisible"," };"] +],[ + "start", + ["variable","diff"], + ["variable"," --git"], + ["keyword"," a/lib/ace/search_highlight.js"], + ["variable"," b/lib/ace/search_highlight.js"] +],[ + "start", + ["invisible","new file mode 100644"] +],[ + "start", + ["variable","index 0000000..b2df779"] +],[ + "start", + ["constant.numeric","---"], + ["meta.tag"," /dev/null"] +],[ + "start", + ["constant.numeric","+++"], + ["meta.tag"," b/lib/ace/search_highlight.js"] +],[ + "start", + ["constant","@@"], + ["constant.numeric"," -0,0 +1,3 "], + ["constant","@@"] +],[ + "start", + ["support.constant","+"], + ["text","new"] +],[ + "start", + ["support.constant","+"], + ["text","empty file"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_dot.json b/node_modules/ace/lib/ace/mode/_test/tokens_dot.json new file mode 100644 index 00000000..fec8b969 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_dot.json @@ -0,0 +1,2254 @@ +[[ + "start", + ["comment","// Original source: http://www.graphviz.org/content/lion_share"] +],[ + "start", + ["comment","##\"A few people in the field of genetics are using dot to draw \"marriage node diagram\" pedigree drawings. Here is one I have done of a test pedigree from the FTREE pedigree drawing package (Lion Share was a racehorse).\" Contributed by David Duffy."] +],[ + "start" +],[ + "start", + ["comment","##Command to get the layout: \"dot -Tpng thisfile > thisfile.png\""] +],[ + "start" +],[ + "start", + ["keyword","digraph"], + ["text"," Ped_Lion_Share "], + ["paren.lparen","{"] +],[ + "start", + ["comment","# page = \"8.2677165,11.692913\" ;"] +],[ + "start", + ["variable","ratio"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["string","\"auto\""], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["text","mincross "], + ["keyword.operator","="], + ["text"," "], + ["constant.numeric","2.0"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["variable","label"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["string","\"Pedigree Lion_Share\""], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start" +],[ + "start", + ["string","\"001\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","box "], + ["punctuation.operator",","], + ["text"," "], + ["variable","regular"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","fillcolor"], + ["keyword.operator","="], + ["text","white "], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"002\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","box "], + ["punctuation.operator",","], + ["text"," "], + ["variable","regular"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","fillcolor"], + ["keyword.operator","="], + ["text","white "], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"003\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","circle "], + ["punctuation.operator",","], + ["text"," "], + ["variable","regular"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","fillcolor"], + ["keyword.operator","="], + ["text","white "], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"004\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","box "], + ["punctuation.operator",","], + ["text"," "], + ["variable","regular"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","fillcolor"], + ["keyword.operator","="], + ["text","white "], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"005\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","box "], + ["punctuation.operator",","], + ["text"," "], + ["variable","regular"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","fillcolor"], + ["keyword.operator","="], + ["text","white "], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"006\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","circle "], + ["punctuation.operator",","], + ["text"," "], + ["variable","regular"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","fillcolor"], + ["keyword.operator","="], + ["text","white "], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"007\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","circle "], + ["punctuation.operator",","], + ["text"," "], + ["variable","regular"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","fillcolor"], + ["keyword.operator","="], + ["text","white "], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"009\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","circle "], + ["punctuation.operator",","], + ["text"," "], + ["variable","regular"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","fillcolor"], + ["keyword.operator","="], + ["text","white "], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"014\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","circle "], + ["punctuation.operator",","], + ["text"," "], + ["variable","regular"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","fillcolor"], + ["keyword.operator","="], + ["text","white "], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"015\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","circle "], + ["punctuation.operator",","], + ["text"," "], + ["variable","regular"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","fillcolor"], + ["keyword.operator","="], + ["text","white "], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"016\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","circle "], + ["punctuation.operator",","], + ["text"," "], + ["variable","regular"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","fillcolor"], + ["keyword.operator","="], + ["text","white "], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"ZZ01\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","circle "], + ["punctuation.operator",","], + ["text"," "], + ["variable","regular"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","fillcolor"], + ["keyword.operator","="], + ["text","white "], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"ZZ02\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","circle "], + ["punctuation.operator",","], + ["text"," "], + ["variable","regular"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","fillcolor"], + ["keyword.operator","="], + ["text","white "], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"017\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","circle "], + ["punctuation.operator",","], + ["text"," "], + ["variable","regular"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","fillcolor"], + ["keyword.operator","="], + ["text","white "], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"012\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","circle "], + ["punctuation.operator",","], + ["text"," "], + ["variable","regular"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","fillcolor"], + ["keyword.operator","="], + ["text","white "], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"008\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","box "], + ["punctuation.operator",","], + ["text"," "], + ["variable","regular"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","fillcolor"], + ["keyword.operator","="], + ["text","white "], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"011\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","box "], + ["punctuation.operator",","], + ["text"," "], + ["variable","regular"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","fillcolor"], + ["keyword.operator","="], + ["text","white "], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"013\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","box "], + ["punctuation.operator",","], + ["text"," "], + ["variable","regular"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","fillcolor"], + ["keyword.operator","="], + ["text","white "], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"010\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","box "], + ["punctuation.operator",","], + ["text"," "], + ["variable","regular"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","fillcolor"], + ["keyword.operator","="], + ["text","white "], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"023\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","circle "], + ["punctuation.operator",","], + ["text"," "], + ["variable","regular"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","fillcolor"], + ["keyword.operator","="], + ["text","white "], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"020\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","circle "], + ["punctuation.operator",","], + ["text"," "], + ["variable","regular"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","fillcolor"], + ["keyword.operator","="], + ["text","white "], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"021\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","circle "], + ["punctuation.operator",","], + ["text"," "], + ["variable","regular"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","fillcolor"], + ["keyword.operator","="], + ["text","white "], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"018\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","circle "], + ["punctuation.operator",","], + ["text"," "], + ["variable","regular"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","fillcolor"], + ["keyword.operator","="], + ["text","white "], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"025\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","circle "], + ["punctuation.operator",","], + ["text"," "], + ["variable","regular"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","fillcolor"], + ["keyword.operator","="], + ["text","white "], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"019\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","box "], + ["punctuation.operator",","], + ["text"," "], + ["variable","regular"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","fillcolor"], + ["keyword.operator","="], + ["text","white "], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"022\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","box "], + ["punctuation.operator",","], + ["text"," "], + ["variable","regular"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","fillcolor"], + ["keyword.operator","="], + ["text","white "], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"024\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","box "], + ["punctuation.operator",","], + ["text"," "], + ["variable","regular"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","fillcolor"], + ["keyword.operator","="], + ["text","white "], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"027\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","circle "], + ["punctuation.operator",","], + ["text"," "], + ["variable","regular"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","fillcolor"], + ["keyword.operator","="], + ["text","white "], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"026\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","box "], + ["punctuation.operator",","], + ["text"," "], + ["variable","regular"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","fillcolor"], + ["keyword.operator","="], + ["text","white "], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"028\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","box "], + ["punctuation.operator",","], + ["text"," "], + ["variable","regular"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","fillcolor"], + ["keyword.operator","="], + ["text","grey "], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"marr0001\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","diamond"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","label"], + ["keyword.operator","="], + ["string","\"\""], + ["punctuation.operator",","], + ["variable","height"], + ["keyword.operator","="], + ["text","."], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","width"], + ["keyword.operator","="], + ["text","."], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"001\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"marr0001\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"007\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"marr0001\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"marr0001\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"017\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["text"," "], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","2"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"marr0002\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","diamond"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","label"], + ["keyword.operator","="], + ["string","\"\""], + ["punctuation.operator",","], + ["variable","height"], + ["keyword.operator","="], + ["text","."], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","width"], + ["keyword.operator","="], + ["text","."], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"001\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"marr0002\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"ZZ02\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"marr0002\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"marr0002\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"012\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["text"," "], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","2"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"marr0003\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","diamond"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","label"], + ["keyword.operator","="], + ["string","\"\""], + ["punctuation.operator",","], + ["variable","height"], + ["keyword.operator","="], + ["text","."], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","width"], + ["keyword.operator","="], + ["text","."], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"002\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"marr0003\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"003\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"marr0003\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"marr0003\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"008\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["text"," "], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","2"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"marr0004\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","diamond"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","label"], + ["keyword.operator","="], + ["string","\"\""], + ["punctuation.operator",","], + ["variable","height"], + ["keyword.operator","="], + ["text","."], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","width"], + ["keyword.operator","="], + ["text","."], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"002\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"marr0004\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"006\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"marr0004\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"marr0004\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"011\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["text"," "], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","2"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"marr0005\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","diamond"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","label"], + ["keyword.operator","="], + ["string","\"\""], + ["punctuation.operator",","], + ["variable","height"], + ["keyword.operator","="], + ["text","."], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","width"], + ["keyword.operator","="], + ["text","."], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"002\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"marr0005\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"ZZ01\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"marr0005\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"marr0005\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"013\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["text"," "], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","2"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"marr0006\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","diamond"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","label"], + ["keyword.operator","="], + ["string","\"\""], + ["punctuation.operator",","], + ["variable","height"], + ["keyword.operator","="], + ["text","."], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","width"], + ["keyword.operator","="], + ["text","."], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"004\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"marr0006\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"009\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"marr0006\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"marr0006\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"010\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["text"," "], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","2"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"marr0007\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","diamond"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","label"], + ["keyword.operator","="], + ["string","\"\""], + ["punctuation.operator",","], + ["variable","height"], + ["keyword.operator","="], + ["text","."], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","width"], + ["keyword.operator","="], + ["text","."], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"005\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"marr0007\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"015\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"marr0007\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"marr0007\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"023\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["text"," "], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","2"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"marr0008\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","diamond"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","label"], + ["keyword.operator","="], + ["string","\"\""], + ["punctuation.operator",","], + ["variable","height"], + ["keyword.operator","="], + ["text","."], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","width"], + ["keyword.operator","="], + ["text","."], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"005\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"marr0008\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"016\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"marr0008\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"marr0008\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"020\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["text"," "], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","2"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"marr0009\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","diamond"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","label"], + ["keyword.operator","="], + ["string","\"\""], + ["punctuation.operator",","], + ["variable","height"], + ["keyword.operator","="], + ["text","."], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","width"], + ["keyword.operator","="], + ["text","."], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"005\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"marr0009\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"012\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"marr0009\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"marr0009\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"021\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["text"," "], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","2"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"marr0010\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","diamond"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","label"], + ["keyword.operator","="], + ["string","\"\""], + ["punctuation.operator",","], + ["variable","height"], + ["keyword.operator","="], + ["text","."], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","width"], + ["keyword.operator","="], + ["text","."], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"008\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"marr0010\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"017\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"marr0010\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"marr0010\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"018\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["text"," "], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","2"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"marr0011\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","diamond"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","label"], + ["keyword.operator","="], + ["string","\"\""], + ["punctuation.operator",","], + ["variable","height"], + ["keyword.operator","="], + ["text","."], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","width"], + ["keyword.operator","="], + ["text","."], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"011\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"marr0011\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"023\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"marr0011\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"marr0011\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"025\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["text"," "], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","2"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"marr0012\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","diamond"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","label"], + ["keyword.operator","="], + ["string","\"\""], + ["punctuation.operator",","], + ["variable","height"], + ["keyword.operator","="], + ["text","."], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","width"], + ["keyword.operator","="], + ["text","."], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"013\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"marr0012\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"014\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"marr0012\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"marr0012\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"019\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["text"," "], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","2"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"marr0013\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","diamond"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","label"], + ["keyword.operator","="], + ["string","\"\""], + ["punctuation.operator",","], + ["variable","height"], + ["keyword.operator","="], + ["text","."], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","width"], + ["keyword.operator","="], + ["text","."], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"010\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"marr0013\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"021\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"marr0013\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"marr0013\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"022\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["text"," "], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","2"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"marr0014\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","diamond"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","label"], + ["keyword.operator","="], + ["string","\"\""], + ["punctuation.operator",","], + ["variable","height"], + ["keyword.operator","="], + ["text","."], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","width"], + ["keyword.operator","="], + ["text","."], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"019\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"marr0014\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"020\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"marr0014\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"marr0014\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"024\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["text"," "], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","2"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"marr0015\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","diamond"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","label"], + ["keyword.operator","="], + ["string","\"\""], + ["punctuation.operator",","], + ["variable","height"], + ["keyword.operator","="], + ["text","."], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","width"], + ["keyword.operator","="], + ["text","."], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"022\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"marr0015\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"025\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"marr0015\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"marr0015\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"027\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["text"," "], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","2"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"marr0016\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","diamond"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","label"], + ["keyword.operator","="], + ["string","\"\""], + ["punctuation.operator",","], + ["variable","height"], + ["keyword.operator","="], + ["text","."], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","width"], + ["keyword.operator","="], + ["text","."], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"024\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"marr0016\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"018\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"marr0016\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"marr0016\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"026\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["text"," "], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","2"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"marr0017\""], + ["text"," "], + ["paren.lparen","["], + ["variable","shape"], + ["keyword.operator","="], + ["text","diamond"], + ["punctuation.operator",","], + ["variable","style"], + ["keyword.operator","="], + ["text","filled"], + ["punctuation.operator",","], + ["variable","label"], + ["keyword.operator","="], + ["string","\"\""], + ["punctuation.operator",","], + ["variable","height"], + ["keyword.operator","="], + ["text","."], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["variable","width"], + ["keyword.operator","="], + ["text","."], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"026\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"marr0017\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"027\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"marr0017\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["string","\"marr0017\""], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["string","\"028\""], + ["text"," "], + ["paren.lparen","["], + ["variable","dir"], + ["keyword.operator","="], + ["text","none"], + ["punctuation.operator",","], + ["text"," "], + ["variable","weight"], + ["keyword.operator","="], + ["constant.numeric","2"], + ["paren.rparen","]"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["paren.rparen","}"] +],[ + "start" +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_eiffel.json b/node_modules/ace/lib/ace/mode/_test/tokens_eiffel.json new file mode 100644 index 00000000..344dbc62 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_eiffel.json @@ -0,0 +1,141 @@ +[[ + "start", + ["keyword","note"] +],[ + "start", + ["text","\t"], + ["identifier","description"], + ["keyword.operator",":"], + ["text"," "], + ["string.quoted.double","\"Represents a person.\""] +],[ + "start" +],[ + "start", + ["keyword","class"] +],[ + "start", + ["text","\t"], + ["entity.name.type","PERSON"] +],[ + "start" +],[ + "start", + ["keyword","create"] +],[ + "start", + ["text","\t"], + ["identifier","make"], + ["keyword.operator",","], + ["text"," "], + ["identifier","make_unknown"] +],[ + "start" +],[ + "start", + ["keyword","feature"], + ["text"," "], + ["paren.lparen","{"], + ["entity.name.type","NONE"], + ["paren.rparen","}"], + ["text"," "], + ["comment.line.double-dash","-- Creation"] +],[ + "start" +],[ + "start", + ["text","\t"], + ["identifier","make"], + ["text"," "], + ["paren.lparen","("], + ["identifier","a_name"], + ["keyword.operator",":"], + ["text"," "], + ["keyword","like"], + ["text"," "], + ["identifier","name"], + ["paren.rparen",")"] +],[ + "start", + ["text","\t\t\t"], + ["comment.line.double-dash","-- Create a person with `a_name' as `name'."] +],[ + "start", + ["text","\t\t"], + ["keyword","do"] +],[ + "start", + ["text","\t\t\t"], + ["identifier","name"], + ["text"," "], + ["keyword.operator",":="], + ["text"," "], + ["identifier","a_name"] +],[ + "start", + ["text","\t\t"], + ["keyword","ensure"] +],[ + "start", + ["text","\t\t\t"], + ["identifier","name"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["identifier","a_name"] +],[ + "start", + ["text","\t\t"], + ["keyword","end"] +],[ + "start" +],[ + "start", + ["text","\t"], + ["identifier","make_unknown"] +],[ + "start", + ["text","\t\t"], + ["keyword","do"], + ["text"," "], + ["keyword","ensure"] +],[ + "start", + ["text","\t\t\t"], + ["identifier","name"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["constant.language","Void"] +],[ + "start", + ["text","\t\t"], + ["keyword","end"] +],[ + "start" +],[ + "start", + ["keyword","feature"], + ["text"," "], + ["comment.line.double-dash","-- Access"] +],[ + "start" +],[ + "start", + ["text","\t"], + ["identifier","name"], + ["keyword.operator",":"], + ["text"," "], + ["keyword","detachable"], + ["text"," "], + ["entity.name.type","STRING"] +],[ + "start", + ["text","\t\t\t"], + ["comment.line.double-dash","-- Full name or Void if unknown."] +],[ + "start" +],[ + "start", + ["keyword","end"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_ejs.json b/node_modules/ace/lib/ace/mode/_test/tokens_ejs.json new file mode 100644 index 00000000..7e54af91 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_ejs.json @@ -0,0 +1,296 @@ +[[ + "start", + ["xml-pe.doctype.xml",""] +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","html"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","head"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","title"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text.xml","Cloud9 Rocks!"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","body"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start" +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.table.tag-name.xml","table"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","class"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"table\""], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.table.tag-name.xml","tr"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.table.tag-name.xml","th"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text.xml","Name"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.table.tag-name.xml","th"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text.xml","Size"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "], + ["markup.list.meta.tag","<%"], + ["text"," "], + ["keyword","if"], + ["text"," "], + ["paren.lparen","("], + ["keyword.operator","!"], + ["identifier","isRoot"], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"], + ["text"," "], + ["markup.list.meta.tag","%>"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.table.tag-name.xml","tr"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.table.tag-name.xml","td"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.anchor.tag-name.xml","a"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","href"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"..\""], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text.xml",".."], + ["meta.tag.punctuation.end-tag-open.xml",""], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.table.tag-name.xml","td"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["meta.tag.punctuation.end-tag-open.xml",""], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "], + ["markup.list.meta.tag","<%"], + ["text"," "], + ["paren.rparen","}"], + ["text"," "], + ["markup.list.meta.tag","%>"] +],[ + "start", + ["text.xml"," "], + ["markup.list.meta.tag","<%"], + ["text"," "], + ["identifier","entries"], + ["punctuation.operator","."], + ["identifier","forEach"], + ["paren.lparen","("], + ["storage.type","function"], + ["paren.lparen","("], + ["identifier","entry"], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"], + ["text"," "], + ["markup.list.meta.tag","%>"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.table.tag-name.xml","tr"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.table.tag-name.xml","td"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","span"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","class"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"glyphicon "], + ["markup.list.meta.tag","<%="], + ["text"," "], + ["identifier","entry"], + ["punctuation.operator","."], + ["identifier","mime"], + ["text"," "], + ["keyword.operator","=="], + ["text"," "], + ["string","'directory'"], + ["text"," "], + ["punctuation.operator","?"], + ["text"," "], + ["string","'folder'"], + ["punctuation.operator",":"], + ["text"," "], + ["string","'file'"], + ["markup.list.meta.tag","%>"], + ["string.attribute-value.xml","\""], + ["meta.tag.punctuation.tag-close.xml",">"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.anchor.tag-name.xml","a"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","href"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\""], + ["markup.list.meta.tag","<%="], + ["text"," "], + ["identifier","entry"], + ["punctuation.operator","."], + ["identifier","name"], + ["text"," "], + ["markup.list.meta.tag","%>"], + ["string.attribute-value.xml","\""], + ["meta.tag.punctuation.tag-close.xml",">"], + ["markup.list.meta.tag","<%="], + ["text"," "], + ["identifier","entry"], + ["punctuation.operator","."], + ["identifier","name"], + ["text"," "], + ["markup.list.meta.tag","%>"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.table.tag-name.xml","td"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["markup.list.meta.tag","<%="], + ["text"," "], + ["identifier","entry"], + ["punctuation.operator","."], + ["identifier","size"], + ["text"," "], + ["markup.list.meta.tag","%>"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "], + ["markup.list.meta.tag","<%"], + ["text"," "], + ["paren.rparen","})"], + ["text"," "], + ["markup.list.meta.tag","%>"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["meta.tag.punctuation.end-tag-open.xml",""] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_elixir.json b/node_modules/ace/lib/ace/mode/_test/tokens_elixir.json new file mode 100644 index 00000000..cbbe1fee --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_elixir.json @@ -0,0 +1,196 @@ +[[ + "start", + ["keyword.control.module.elixir","defmodule"], + ["meta.module.elixir"," "], + ["entity.name.type.module.elixir","HelloModule"], + ["text"," "], + ["keyword.control.elixir","do"] +],[ + "comment.documentation.heredoc", + ["text"," "], + ["comment.documentation.heredoc","@moduledoc \"\"\""] +],[ + "comment.documentation.heredoc", + ["comment.documentation.heredoc"," This is supposed to be `markdown`."] +],[ + "comment.documentation.heredoc", + ["comment.documentation.heredoc"," __Yes__ this is [mark](http://down.format)"] +],[ + "comment.documentation.heredoc" +],[ + "comment.documentation.heredoc", + ["comment.documentation.heredoc"," # Truly"] +],[ + "comment.documentation.heredoc" +],[ + "comment.documentation.heredoc", + ["comment.documentation.heredoc"," ## marked"] +],[ + "comment.documentation.heredoc" +],[ + "comment.documentation.heredoc", + ["comment.documentation.heredoc"," * with lists"] +],[ + "comment.documentation.heredoc", + ["comment.documentation.heredoc"," * more"] +],[ + "comment.documentation.heredoc", + ["comment.documentation.heredoc"," * and more"] +],[ + "comment.documentation.heredoc" +],[ + "comment.documentation.heredoc", + ["comment.documentation.heredoc"," Even.with(code)"] +],[ + "comment.documentation.heredoc", + ["comment.documentation.heredoc"," blocks |> with |> samples"] +],[ + "comment.documentation.heredoc" +],[ + "comment.documentation.heredoc", + ["comment.documentation.heredoc"," _Docs are first class citizens in Elixir_ (Jose Valim)"] +],[ + "start", + ["comment.documentation.heredoc"," \"\"\""] +],[ + "start", + ["text"," "] +],[ + "start", + ["text"," "], + ["punctuation.definition.comment.elixir","#"], + ["comment.line.number-sign.elixir"," A \"Hello world\" function"] +],[ + "start", + ["text"," "], + ["keyword.control.elixir","def"], + ["text"," some_fun "], + ["keyword.control.elixir","do"] +],[ + "start", + ["text"," "], + ["variable.other.constant.elixir","IO"], + ["punctuation.separator.method.elixir","."], + ["text","puts "], + ["punctuation.definition.string.begin.elixir","\""], + ["string.quoted.double.elixir","Juhu Kinners!"], + ["punctuation.definition.string.end.elixir","\""] +],[ + "start", + ["text"," "], + ["keyword.control.elixir","end"] +],[ + "start", + ["text"," "], + ["punctuation.definition.comment.elixir","#"], + ["comment.line.number-sign.elixir"," A private function"] +],[ + "start", + ["text"," "], + ["keyword.control.elixir","defp"], + ["text"," priv "], + ["keyword.control.elixir","do"] +],[ + "punctuation.definition.string.begin.elixir7", + ["text"," is_regex "], + ["punctuation.definition.string.begin.elixir","~r\"\"\""] +],[ + "punctuation.definition.string.begin.elixir7", + ["string.quoted.double.heredoc.elixir"," This is a regex"] +],[ + "punctuation.definition.string.begin.elixir7", + ["string.quoted.double.heredoc.elixir"," spanning several"] +],[ + "punctuation.definition.string.begin.elixir7", + ["string.quoted.double.heredoc.elixir"," lines."] +],[ + "start", + ["punctuation.definition.string.end.elixir"," \"\"\""] +],[ + "start", + ["text"," x "], + ["keyword.operator.assignment.elixir","="], + ["text"," elem"], + ["punctuation.section.function.elixir","("], + ["punctuation.section.scope.elixir","{"], + ["text"," "], + ["punctuation.definition.constant.elixir",":"], + ["constant.other.symbol.elixir","a"], + ["punctuation.separator.object.elixir",","], + ["text"," "], + ["punctuation.definition.constant.elixir",":"], + ["constant.other.symbol.elixir","b"], + ["punctuation.separator.object.elixir",","], + ["text"," "], + ["punctuation.definition.constant.elixir",":"], + ["constant.other.symbol.elixir","c"], + ["text"," "], + ["punctuation.section.scope.elixir","}"], + ["punctuation.separator.object.elixir",","], + ["text"," "], + ["constant.numeric.elixir","0"], + ["punctuation.section.function.elixir",")"], + ["text"," "], + ["punctuation.definition.comment.elixir","#"], + ["comment.line.number-sign.elixir","=> :a"] +],[ + "start", + ["text"," "], + ["keyword.control.elixir","end"] +],[ + "start", + ["keyword.control.elixir","end"] +],[ + "start" +],[ + "start", + ["text","test_fun "], + ["keyword.operator.assignment.elixir","="], + ["text"," "], + ["keyword.control.elixir","fn"], + ["punctuation.section.function.elixir","("], + ["text","x"], + ["punctuation.section.function.elixir",")"], + ["text"," "], + ["keyword.operator.arithmetic.elixir","-"], + ["keyword.operator.comparison.elixir",">"] +],[ + "start", + ["text"," "], + ["keyword.control.elixir","cond"], + ["text"," "], + ["keyword.control.elixir","do"] +],[ + "start", + ["text"," x "], + ["keyword.operator.comparison.elixir",">"], + ["text"," "], + ["constant.numeric.elixir","10"], + ["text"," "], + ["keyword.operator.arithmetic.elixir","-"], + ["keyword.operator.comparison.elixir",">"] +],[ + "start", + ["text"," "], + ["punctuation.definition.constant.elixir",":"], + ["constant.other.symbol.elixir","greater_than_ten"] +],[ + "start", + ["text"," "], + ["constant.language.elixir","true"], + ["text"," "], + ["keyword.operator.arithmetic.elixir","-"], + ["keyword.operator.comparison.elixir",">"] +],[ + "start", + ["text"," "], + ["punctuation.definition.constant.elixir",":"], + ["constant.other.symbol.elixir","maybe_ten"] +],[ + "start", + ["text"," "], + ["keyword.control.elixir","end"] +],[ + "start", + ["keyword.control.elixir","end"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_elm.json b/node_modules/ace/lib/ace/mode/_test/tokens_elm.json new file mode 100644 index 00000000..b39de92f --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_elm.json @@ -0,0 +1,198 @@ +[[ + "start", + ["comment.start","{-"], + ["comment"," Ace "], + ["comment.start","{-"], + ["comment"," 4 "], + ["comment.end","-}"], + ["comment"," Elm "], + ["comment.end","-}"] +],[ + "start", + ["constant.language","main"], + ["text"," "], + ["keyword","="], + ["text"," "], + ["identifier","lift"], + ["text"," "], + ["identifier","clock"], + ["text"," "], + ["paren.lparen","("], + ["identifier","every"], + ["text"," "], + ["identifier","second"], + ["paren.rparen",")"] +],[ + "start" +],[ + "start", + ["constant.language","clock"], + ["text"," "], + ["identifier","t"], + ["text"," "], + ["keyword","="], + ["text"," "], + ["identifier","collage"], + ["text"," "], + ["constant.numeric","400"], + ["text"," "], + ["constant.numeric","400"], + ["text"," "], + ["paren.lparen","["], + ["text"," "], + ["identifier","filled"], + ["text"," "], + ["identifier","lightGrey"], + ["text"," "], + ["paren.lparen","("], + ["identifier","ngon"], + ["text"," "], + ["constant.numeric","12"], + ["text"," "], + ["constant.numeric","110"], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["operator.punctuation",","], + ["text"," "], + ["identifier","outlined"], + ["text"," "], + ["paren.lparen","("], + ["identifier","solid"], + ["text"," "], + ["identifier","grey"], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","("], + ["identifier","ngon"], + ["text"," "], + ["constant.numeric","12"], + ["text"," "], + ["constant.numeric","110"], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["operator.punctuation",","], + ["text"," "], + ["identifier","hand"], + ["text"," "], + ["identifier","orange"], + ["text"," "], + ["constant.numeric","100"], + ["text"," "], + ["identifier","t"] +],[ + "start", + ["text"," "], + ["operator.punctuation",","], + ["text"," "], + ["identifier","hand"], + ["text"," "], + ["identifier","charcoal"], + ["text"," "], + ["constant.numeric","100"], + ["text"," "], + ["paren.lparen","("], + ["identifier","t"], + ["keyword.operator","/"], + ["constant.numeric","60"], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["operator.punctuation",","], + ["text"," "], + ["identifier","hand"], + ["text"," "], + ["identifier","charcoal"], + ["text"," "], + ["constant.numeric","60"], + ["text"," "], + ["paren.lparen","("], + ["identifier","t"], + ["keyword.operator","/"], + ["constant.numeric","720"], + ["paren.rparen",")"], + ["text"," "], + ["paren.rparen","]"] +],[ + "start" +],[ + "start", + ["constant.language","hand"], + ["text"," "], + ["identifier","clr"], + ["text"," "], + ["identifier","len"], + ["text"," "], + ["identifier","time"], + ["text"," "], + ["keyword","="] +],[ + "start", + ["text"," "], + ["keyword","let"], + ["text"," "], + ["identifier","angle"], + ["text"," "], + ["keyword","="], + ["text"," "], + ["identifier","degrees"], + ["text"," "], + ["paren.lparen","("], + ["constant.numeric","90"], + ["text"," "], + ["keyword.operator","-"], + ["text"," "], + ["constant.numeric","6"], + ["text"," "], + ["keyword.operator","*"], + ["text"," "], + ["identifier","inSeconds"], + ["text"," "], + ["identifier","time"], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["keyword","in"], + ["text"," "], + ["identifier","traced"], + ["text"," "], + ["paren.lparen","("], + ["identifier","solid"], + ["text"," "], + ["identifier","clr"], + ["paren.rparen",")"], + ["text"," "], + ["keyword.operator","<|"], + ["text"," "], + ["identifier","segment"], + ["text"," "], + ["paren.lparen","("], + ["constant.numeric","0"], + ["operator.punctuation",","], + ["constant.numeric","0"], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","("], + ["identifier","len"], + ["text"," "], + ["keyword.operator","*"], + ["text"," "], + ["identifier","cos"], + ["text"," "], + ["identifier","angle"], + ["operator.punctuation",","], + ["text"," "], + ["identifier","len"], + ["text"," "], + ["keyword.operator","*"], + ["text"," "], + ["identifier","sin"], + ["text"," "], + ["identifier","angle"], + ["paren.rparen",")"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_erlang.json b/node_modules/ace/lib/ace/mode/_test/tokens_erlang.json new file mode 100644 index 00000000..8a828976 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_erlang.json @@ -0,0 +1,166 @@ +[[ + "start", + ["text"," "], + ["punctuation.definition.comment.erlang","%% A process whose only job is to keep a counter."] +],[ + "start", + ["text"," "], + ["punctuation.definition.comment.erlang","%% First version"] +],[ + "start", + ["meta.directive.module.erlang"," "], + ["punctuation.section.directive.begin.erlang","-"], + ["keyword.control.directive.module.erlang","module"], + ["punctuation.definition.parameters.begin.erlang","("], + ["entity.name.type.class.module.definition.erlang","counter"], + ["punctuation.definition.parameters.end.erlang",")"], + ["punctuation.section.directive.end.erlang","."] +],[ + "start", + ["meta.directive.export.erlang"," "], + ["punctuation.section.directive.begin.erlang","-"], + ["keyword.control.directive.export.erlang","export"], + ["punctuation.definition.parameters.begin.erlang","("], + ["punctuation.definition.list.begin.erlang","["], + ["entity.name.function.erlang","start"], + ["punctuation.separator.function-arity.erlang","/"], + ["constant.numeric.integer.decimal.erlang","0"], + ["punctuation.separator.list.erlang",","], + ["meta.structure.list.function.erlang"," "], + ["entity.name.function.erlang","codeswitch"], + ["punctuation.separator.function-arity.erlang","/"], + ["constant.numeric.integer.decimal.erlang","1"], + ["punctuation.definition.list.end.erlang","]"], + ["punctuation.definition.parameters.end.erlang",")"], + ["punctuation.section.directive.end.erlang","."] +],[ + "start", + ["text"," "] +],[ + "start", + ["meta.function.erlang"," "], + ["entity.name.function.definition.erlang","start"], + ["punctuation.section.expression.begin.erlang","("], + ["punctuation.section.expression.end.erlang",")"], + ["text"," "], + ["keyword.operator.symbolic.erlang","->"], + ["text"," "], + ["entity.name.function.erlang","loop"], + ["punctuation.definition.parameters.begin.erlang","("], + ["constant.numeric.integer.decimal.erlang","0"], + ["punctuation.definition.parameters.end.erlang",")"], + ["punctuation.terminator.function.erlang","."] +],[ + "start", + ["text"," "] +],[ + ["text6","meta.function.erlang"], + ["meta.function.erlang"," "], + ["entity.name.function.definition.erlang","loop"], + ["punctuation.section.expression.begin.erlang","("], + ["variable.other.erlang","Sum"], + ["punctuation.section.expression.end.erlang",")"], + ["text"," "], + ["keyword.operator.symbolic.erlang","->"] +],[ + ["keyword.control.receive.erlang","text6","text6","meta.function.erlang"], + ["text"," "], + ["keyword.control.receive.erlang","receive"] +],[ + ["keyword.control.receive.erlang","text6","text6","meta.function.erlang"], + ["meta.expression.receive.erlang"," "], + ["punctuation.definition.tuple.begin.erlang","{"], + ["constant.other.symbol.unquoted.erlang","increment"], + ["punctuation.separator.tuple.erlang",","], + ["meta.structure.tuple.erlang"," "], + ["variable.other.erlang","Count"], + ["punctuation.definition.tuple.end.erlang","}"], + ["meta.expression.receive.erlang"," "], + ["punctuation.separator.clause-head-body.erlang","->"] +],[ + ["keyword.control.receive.erlang","text6","text6","meta.function.erlang"], + ["meta.expression.receive.erlang"," "], + ["entity.name.function.erlang","loop"], + ["punctuation.definition.parameters.begin.erlang","("], + ["variable.other.erlang","Sum"], + ["keyword.operator.symbolic.erlang","+"], + ["variable.other.erlang","Count"], + ["punctuation.definition.parameters.end.erlang",")"], + ["punctuation.separator.clauses.erlang",";"] +],[ + ["keyword.control.receive.erlang","text6","text6","meta.function.erlang"], + ["meta.expression.receive.erlang"," "], + ["punctuation.definition.tuple.begin.erlang","{"], + ["constant.other.symbol.unquoted.erlang","counter"], + ["punctuation.separator.tuple.erlang",","], + ["meta.structure.tuple.erlang"," "], + ["variable.other.erlang","Pid"], + ["punctuation.definition.tuple.end.erlang","}"], + ["meta.expression.receive.erlang"," "], + ["punctuation.separator.clause-head-body.erlang","->"] +],[ + ["keyword.control.receive.erlang","text6","text6","meta.function.erlang"], + ["meta.expression.receive.erlang"," "], + ["variable.other.erlang","Pid"], + ["meta.expression.receive.erlang"," "], + ["keyword.operator.symbolic.erlang","!"], + ["meta.expression.receive.erlang"," "], + ["punctuation.definition.tuple.begin.erlang","{"], + ["constant.other.symbol.unquoted.erlang","counter"], + ["punctuation.separator.tuple.erlang",","], + ["meta.structure.tuple.erlang"," "], + ["variable.other.erlang","Sum"], + ["punctuation.definition.tuple.end.erlang","}"], + ["punctuation.separator.expressions.erlang",","] +],[ + ["keyword.control.receive.erlang","text6","text6","meta.function.erlang"], + ["meta.expression.receive.erlang"," "], + ["entity.name.function.erlang","loop"], + ["punctuation.definition.parameters.begin.erlang","("], + ["variable.other.erlang","Sum"], + ["punctuation.definition.parameters.end.erlang",")"], + ["punctuation.separator.clauses.erlang",";"] +],[ + ["keyword.control.receive.erlang","text6","text6","meta.function.erlang"], + ["meta.expression.receive.erlang"," "], + ["constant.other.symbol.unquoted.erlang","code_switch"], + ["meta.expression.receive.erlang"," "], + ["punctuation.separator.clause-head-body.erlang","->"] +],[ + ["keyword.control.receive.erlang","text6","text6","meta.function.erlang"], + ["meta.expression.receive.erlang"," "], + ["keyword.operator.macro.erlang","?"], + ["entity.name.function.macro.erlang","MODULE"], + ["meta.expression.receive.erlang",":"], + ["entity.name.function.erlang","codeswitch"], + ["punctuation.definition.parameters.begin.erlang","("], + ["variable.other.erlang","Sum"], + ["punctuation.definition.parameters.end.erlang",")"] +],[ + ["keyword.control.receive.erlang","text6","text6","meta.function.erlang"], + ["meta.expression.receive.erlang"," "], + ["punctuation.definition.comment.erlang","% Force the use of 'codeswitch/1' from the latest MODULE version"] +],[ + "start", + ["meta.expression.receive.erlang"," "], + ["keyword.control.end.erlang","end"], + ["punctuation.terminator.function.erlang","."] +],[ + "start", + ["text"," "] +],[ + "start", + ["meta.function.erlang"," "], + ["entity.name.function.definition.erlang","codeswitch"], + ["punctuation.section.expression.begin.erlang","("], + ["variable.other.erlang","Sum"], + ["punctuation.section.expression.end.erlang",")"], + ["text"," "], + ["keyword.operator.symbolic.erlang","->"], + ["text"," "], + ["entity.name.function.erlang","loop"], + ["punctuation.definition.parameters.begin.erlang","("], + ["variable.other.erlang","Sum"], + ["punctuation.definition.parameters.end.erlang",")"], + ["punctuation.terminator.function.erlang","."] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_forth.json b/node_modules/ace/lib/ace/mode/_test/tokens_forth.json new file mode 100644 index 00000000..8c8a007e --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_forth.json @@ -0,0 +1,219 @@ +[[ + "start", + ["keyword.other.compile-only.forth",":"], + ["meta.block.forth"," "], + ["entity.name.function.forth","HELLO"], + ["meta.block.forth"," "], + ["comment.line.parentheses.forth"," ( -- )"], + ["meta.block.forth"," CR "], + ["string.quoted.double.forth",".\" Hello, world!\""], + ["meta.block.forth"," "], + ["keyword.other.compile-only.forth",";"], + ["text"," "] +],[ + "start" +],[ + "start", + ["text","HELLO "] +],[ + "start", + ["text","Hello, world!"] +],[ + "start" +],[ + "start", + ["keyword.other.compile-only.forth",":"], + ["meta.block.forth"," "], + ["entity.name.function.forth","[CHAR]"], + ["meta.block.forth"," "], + ["keyword.other.non-immediate.forth"," CHAR"], + ["meta.block.forth"," "], + ["keyword.other.compile-only.forth"," POSTPONE"], + ["meta.block.forth"," LITERAL "], + ["keyword.other.compile-only.forth",";"], + ["keyword.other.immediate.forth"," IMMEDIATE"] +],[ + "start" +],[ + "start", + ["constant.numeric.forth","0"], + ["storage.type.forth"," value"], + ["text"," ii "], + ["constant.numeric.forth"," 0"], + ["storage.type.forth"," value"], + ["text"," jj"] +],[ + "start", + ["constant.numeric.forth","0"], + ["storage.type.forth"," value"], + ["text"," KeyAddr "], + ["constant.numeric.forth"," 0"], + ["storage.type.forth"," value"], + ["text"," KeyLen"] +],[ + "start", + ["storage.type.forth","create"], + ["text"," SArray "], + ["constant.numeric.forth"," 256"], + ["text"," allot "], + ["comment.line.backslash.forth"," \\ state array of 256 bytes"] +],[ + "start", + ["keyword.other.compile-only.forth",":"], + ["meta.block.forth"," "], + ["entity.name.function.forth","KeyArray"], + ["meta.block.forth"," KeyLen mod KeyAddr "], + ["keyword.other.compile-only.forth",";"] +],[ + "start" +],[ + "start", + ["keyword.other.compile-only.forth",":"], + ["meta.block.forth"," "], + ["entity.name.function.forth","get_byte"], + ["meta.block.forth"," + c@ "], + ["keyword.other.compile-only.forth",";"] +],[ + "start", + ["keyword.other.compile-only.forth",":"], + ["meta.block.forth"," "], + ["entity.name.function.forth","set_byte"], + ["meta.block.forth"," + c! "], + ["keyword.other.compile-only.forth",";"] +],[ + "start", + ["keyword.other.compile-only.forth",":"], + ["meta.block.forth"," "], + ["entity.name.function.forth","as_byte"], + ["meta.block.forth"," "], + ["constant.numeric.forth"," 255"], + ["meta.block.forth"," and "], + ["keyword.other.compile-only.forth",";"] +],[ + "start", + ["keyword.other.compile-only.forth",":"], + ["meta.block.forth"," "], + ["entity.name.function.forth","reset_ij"], + ["meta.block.forth"," "], + ["constant.numeric.forth"," 0"], + ["keyword.other.immediate.forth"," TO"], + ["meta.block.forth"," ii "], + ["constant.numeric.forth"," 0"], + ["keyword.other.immediate.forth"," TO"], + ["meta.block.forth"," jj "], + ["keyword.other.compile-only.forth",";"] +],[ + "start", + ["keyword.other.compile-only.forth",":"], + ["meta.block.forth"," "], + ["entity.name.function.forth","i_update"], + ["meta.block.forth"," "], + ["constant.numeric.forth"," 1"], + ["meta.block.forth"," + as_byte"], + ["keyword.other.immediate.forth"," TO"], + ["meta.block.forth"," ii "], + ["keyword.other.compile-only.forth",";"] +],[ + "start", + ["keyword.other.compile-only.forth",":"], + ["meta.block.forth"," "], + ["entity.name.function.forth","j_update"], + ["meta.block.forth"," ii SArray get_byte + as_byte"], + ["keyword.other.immediate.forth"," TO"], + ["meta.block.forth"," jj "], + ["keyword.other.compile-only.forth",";"] +],[ + "keyword.other.compile-only.forth", + ["keyword.other.compile-only.forth",":"], + ["meta.block.forth"," "], + ["entity.name.function.forth","swap_s_ij"] +],[ + "keyword.other.compile-only.forth", + ["meta.block.forth"," jj SArray get_byte"] +],[ + "keyword.other.compile-only.forth", + ["meta.block.forth"," ii SArray get_byte jj SArray set_byte"] +],[ + "keyword.other.compile-only.forth", + ["meta.block.forth"," ii SArray set_byte"] +],[ + "start", + ["keyword.other.compile-only.forth",";"] +],[ + "start" +],[ + "keyword.other.compile-only.forth", + ["keyword.other.compile-only.forth",":"], + ["meta.block.forth"," "], + ["entity.name.function.forth","rc4_init"], + ["comment.line.parentheses.forth"," ( KeyAddr KeyLen -- )"] +],[ + "keyword.other.compile-only.forth", + ["meta.block.forth"," "], + ["constant.numeric.forth"," 256"], + ["meta.block.forth"," min"], + ["keyword.other.immediate.forth"," TO"], + ["meta.block.forth"," KeyLen "], + ["keyword.other.immediate.forth"," TO"], + ["meta.block.forth"," KeyAddr"] +],[ + "keyword.other.compile-only.forth", + ["meta.block.forth"," "], + ["constant.numeric.forth"," 256 0"], + ["keyword.control.compile-only.forth"," DO"], + ["meta.block.forth"," "], + ["variable.language.forth","i"], + ["meta.block.forth"," "], + ["variable.language.forth","i"], + ["meta.block.forth"," SArray set_byte "], + ["keyword.control.compile-only.forth"," LOOP"] +],[ + "keyword.other.compile-only.forth", + ["meta.block.forth"," reset_ij"] +],[ + "keyword.other.compile-only.forth", + ["meta.block.forth"," "], + ["keyword.control.compile-only.forth"," BEGIN"] +],[ + "keyword.other.compile-only.forth", + ["meta.block.forth"," ii KeyArray get_byte jj + j_update"] +],[ + "keyword.other.compile-only.forth", + ["meta.block.forth"," swap_s_ij"] +],[ + "keyword.other.compile-only.forth", + ["meta.block.forth"," ii"], + ["constant.numeric.forth"," 255"], + ["meta.block.forth"," <"], + ["keyword.control.compile-only.forth"," WHILE"] +],[ + "keyword.other.compile-only.forth", + ["meta.block.forth"," ii i_update"] +],[ + "keyword.other.compile-only.forth", + ["meta.block.forth"," "], + ["keyword.control.compile-only.forth"," REPEAT"] +],[ + "keyword.other.compile-only.forth", + ["meta.block.forth"," reset_ij"] +],[ + "start", + ["keyword.other.compile-only.forth",";"] +],[ + "keyword.other.compile-only.forth", + ["keyword.other.compile-only.forth",":"], + ["meta.block.forth"," "], + ["entity.name.function.forth","rc4_byte"] +],[ + "keyword.other.compile-only.forth", + ["meta.block.forth"," ii i_update jj j_update"] +],[ + "keyword.other.compile-only.forth", + ["meta.block.forth"," swap_s_ij"] +],[ + "keyword.other.compile-only.forth", + ["meta.block.forth"," ii SArray get_byte jj SArray get_byte + as_byte SArray get_byte xor"] +],[ + "start", + ["keyword.other.compile-only.forth",";"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_ftl.json b/node_modules/ace/lib/ace/mode/_test/tokens_ftl.json new file mode 100644 index 00000000..75e7a6f1 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_ftl.json @@ -0,0 +1,341 @@ +[[ + "start", + ["keyword.function","<#ftl"], + ["text"," "], + ["entity.other.attribute-name","encoding"], + ["keyword.operator","="], + ["string","\"utf-8\""], + ["text"," "], + ["keyword","/>"] +],[ + "start", + ["keyword.function","<#setting"], + ["text"," "], + ["entity.other.attribute-name","locale"], + ["keyword.operator","="], + ["string","\"en_US\""], + ["text"," "], + ["keyword","/>"] +],[ + "start", + ["keyword.function","<#import"], + ["text"," "], + ["string","\"library\""], + ["text"," "], + ["keyword.operator","as"], + ["text"," "], + ["variable","lib"], + ["text"," "], + ["keyword","/>"] +],[ + "ftl-dcomment", + ["comment","<#--"] +],[ + "ftl-dcomment", + ["comment"," FreeMarker comment"] +],[ + "ftl-dcomment", + ["comment"," ${abc} <#assign a=12 />"] +],[ + "start", + ["comment","-->"] +],[ + "start" +],[ + "start", + ["xml-pe.doctype.xml",""] +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","html"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","lang"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"en-us\""], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","head"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","meta"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","charset"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"utf-8\""], + ["text.tag-whitespace.xml"," "], + ["meta.tag.punctuation.tag-close.xml","/>"] +],[ + "start", + ["text.xml"," "] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","title"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["string.interpolated","${"], + ["variable","title"], + ["keyword.operator","!"], + ["string","\"FreeMarker\""], + ["string.interpolated","}"], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","title"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","body"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," "] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","h1"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text.xml","Hello "], + ["string.interpolated","${"], + ["variable","name"], + ["keyword.operator","!"], + ["string","\"\""], + ["string.interpolated","}"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","p"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text.xml","Today is: "], + ["string.interpolated","${"], + ["language.variable",".now"], + ["support.function","?date"], + ["string.interpolated","}"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "] +],[ + "start", + ["text.xml"," "], + ["keyword.function","<#assign"], + ["text"," "], + ["variable","x"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["constant.numeric","13"], + ["keyword",">"] +],[ + "start", + ["text.xml"," "], + ["keyword.function","<#if"], + ["text"," "], + ["variable","x"], + ["text"," "], + ["constant.character.entity",">"], + ["text"," "], + ["constant.numeric","12"], + ["text"," "], + ["keyword.operator","&&"], + ["text"," "], + ["variable","x"], + ["text"," "], + ["keyword.operator","lt"], + ["text"," "], + ["constant.numeric","14"], + ["keyword",">"], + ["text.xml","x equals 13: "], + ["string.interpolated","${"], + ["variable","x"], + ["string.interpolated","}"], + ["keyword.function",""] +],[ + "start", + ["text.xml"," "] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","ul"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," "], + ["keyword.function","<#list"], + ["text"," "], + ["variable","items"], + ["text"," "], + ["keyword.operator","as"], + ["text"," "], + ["variable","item"], + ["keyword",">"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","li"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["string.interpolated","${"], + ["variable","item_index"], + ["string.interpolated","}"], + ["text.xml",": "], + ["string.interpolated","${"], + ["variable","item.name"], + ["keyword.operator","!"], + ["support.function","?split"], + ["paren.lparen","("], + ["string","\""], + ["constant.character.escape","\\n"], + ["string","\""], + ["paren.rparen",")"], + ["paren.lparen","["], + ["constant.numeric","0"], + ["paren.rparen","]"], + ["string.interpolated","}"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "], + ["keyword.function",""] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "] +],[ + "start", + ["text.xml"," User directive: "], + ["keyword.other","<@lib.function"], + ["text"," "], + ["variable","attr1"], + ["keyword.operator","="], + ["constant.language","true"], + ["text"," "], + ["variable","attr2"], + ["keyword.operator","="], + ["string","'value'"], + ["text"," "], + ["variable","attr3"], + ["keyword.operator","="], + ["constant.numeric","-42.12"], + ["keyword",">"], + ["text.xml","Test"], + ["keyword.other",""] +],[ + "start", + ["text.xml"," "], + ["keyword.other","<@anotherOne"], + ["text"," "], + ["keyword","/>"] +],[ + "start", + ["text.xml"," "] +],[ + "start", + ["text.xml"," "], + ["keyword.function","<#if"], + ["text"," "], + ["variable","variable"], + ["support.function.deprecated","?exists"], + ["keyword",">"] +],[ + "start", + ["text.xml"," Deprecated"] +],[ + "start", + ["text.xml"," "], + ["keyword.function","<#elseif"], + ["text"," "], + ["variable","variable"], + ["support.function","??"], + ["keyword",">"] +],[ + "start", + ["text.xml"," Better"] +],[ + "start", + ["text.xml"," "], + ["keyword.function","<#else"], + ["keyword",">"] +],[ + "start", + ["text.xml"," Default"] +],[ + "start", + ["text.xml"," "], + ["keyword.function",""] +],[ + "start", + ["text.xml"," "] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.image.tag-name.xml","img"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","src"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"images/"], + ["string.interpolated","${"], + ["variable","user.id"], + ["string.interpolated","}"], + ["string.attribute-value.xml",".png\""], + ["text.tag-whitespace.xml"," "], + ["meta.tag.punctuation.tag-close.xml","/>"] +],[ + "start", + ["text.xml"," "] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start" +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_gcode.json b/node_modules/ace/lib/ace/mode/_test/tokens_gcode.json new file mode 100644 index 00000000..d6227473 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_gcode.json @@ -0,0 +1,296 @@ +[[ + "start", + ["identifier","O"], + ["constant.numeric","003"], + ["text"," "], + ["comment","(DIAMOND SQUARE)"] +],[ + "start", + ["comment","N2"], + ["text"," "], + ["string","G54"], + ["text"," "], + ["string","G90"], + ["text"," "], + ["string","G49"], + ["text"," "], + ["string","G80"] +],[ + "start", + ["comment","N3"], + ["text"," "], + ["string","M6"], + ["text"," "], + ["identifier","T"], + ["constant.numeric","1"], + ["text"," "], + ["comment","(1.ENDMILL)"] +],[ + "start", + ["comment","N4"], + ["text"," "], + ["string","M3"], + ["text"," "], + ["identifier","S"], + ["constant.numeric","1800"] +],[ + "start", + ["comment","N5"], + ["text"," "], + ["string","G0"], + ["text"," "], + ["identifier","X"], + ["constant.numeric","-.6"], + ["text"," "], + ["identifier","Y"], + ["constant.numeric","2.050"] +],[ + "start", + ["comment","N6"], + ["text"," "], + ["string","G43"], + ["text"," "], + ["identifier","H"], + ["constant.numeric","1"], + ["text"," "], + ["identifier","Z"], + ["constant.numeric",".1"] +],[ + "start", + ["comment","N7"], + ["text"," "], + ["string","G1"], + ["text"," "], + ["identifier","Z"], + ["constant.numeric","-.3"], + ["text"," "], + ["identifier","F"], + ["constant.numeric","50."] +],[ + "start", + ["comment","N8"], + ["text"," "], + ["string","G41"], + ["text"," "], + ["identifier","D"], + ["constant.numeric","1"], + ["text"," "], + ["identifier","Y"], + ["constant.numeric","1.45"] +],[ + "start", + ["comment","N9"], + ["text"," "], + ["string","G1"], + ["text"," "], + ["identifier","X"], + ["constant.numeric","0"], + ["text"," "], + ["identifier","F"], + ["constant.numeric","20."] +],[ + "start", + ["comment","N10"], + ["text"," "], + ["string","G2"], + ["text"," "], + ["identifier","J"], + ["constant.numeric","-1.45"] +],[ + "start", + ["comment","(CUTTER COMP CANCEL)"] +],[ + "start", + ["comment","N11"], + ["text"," "], + ["string","G1"], + ["text"," "], + ["identifier","Z"], + ["constant.numeric","-.2"], + ["text"," "], + ["identifier","F"], + ["constant.numeric","50."] +],[ + "start", + ["comment","N12"], + ["text"," "], + ["identifier","Y"], + ["constant.numeric","-.990"] +],[ + "start", + ["comment","N13"], + ["text"," "], + ["string","G40"] +],[ + "start", + ["comment","N14"], + ["text"," "], + ["string","G0"], + ["text"," "], + ["identifier","X"], + ["constant.numeric","-.6"], + ["text"," "], + ["identifier","Y"], + ["constant.numeric","1.590"] +],[ + "start", + ["comment","N15"], + ["text"," "], + ["string","G0"], + ["text"," "], + ["identifier","Z"], + ["constant.numeric",".1"] +],[ + "start", + ["comment","N16"], + ["text"," "], + ["string","M5"], + ["text"," "], + ["string","G49"], + ["text"," "], + ["string","G28"], + ["text"," "], + ["string","G91"], + ["text"," "], + ["identifier","Z"], + ["constant.numeric","0"] +],[ + "start", + ["comment","N17"], + ["text"," "], + ["identifier","CALL"], + ["text"," "], + ["identifier","O"], + ["constant.numeric","9456"] +],[ + "start", + ["comment","N18"], + ["text"," #"], + ["constant.numeric","500"], + ["text","="], + ["constant.numeric","0.004"] +],[ + "start", + ["comment","N19"], + ["text"," #"], + ["constant.numeric","503"], + ["text","="], + ["paren.lparen","["], + ["text","#"], + ["constant.numeric","500"], + ["text","+#"], + ["constant.numeric","501"], + ["paren.rparen","]"] +],[ + "start", + ["comment","N20"], + ["text"," "], + ["identifier","VC"], + ["constant.numeric","45"], + ["text","="], + ["constant.numeric","0.0006"] +],[ + "start", + ["identifier","VS"], + ["constant.numeric","4"], + ["text","="], + ["constant.numeric","0.0007"] +],[ + "start", + ["comment","N21"], + ["text"," "], + ["string","G90"], + ["text"," "], + ["string","G10"], + ["text"," "], + ["identifier","L"], + ["constant.numeric","20"], + ["text"," "], + ["identifier","P"], + ["constant.numeric","3"], + ["text"," "], + ["identifier","X"], + ["constant.numeric","5."], + ["identifier","Y"], + ["constant.numeric","4."], + ["text"," "], + ["identifier","Z"], + ["constant.numeric","6.567"] +],[ + "start", + ["comment","N22"], + ["text"," "], + ["string","G0"], + ["text"," "], + ["identifier","X"], + ["constant.numeric","5000"] +],[ + "start", + ["comment","N23"], + ["text"," "], + ["identifier","IF"], + ["text"," "], + ["paren.lparen","["], + ["text","#"], + ["constant.numeric","1"], + ["text"," "], + ["identifier","LT"], + ["text"," "], + ["constant.numeric","0.370"], + ["paren.rparen","]"], + ["text"," "], + ["identifier","GOTO"], + ["text"," "], + ["constant.numeric","49"] +],[ + "start", + ["comment","N24"], + ["text"," "], + ["identifier","X"], + ["constant.numeric","-0.678"], + ["text"," "], + ["identifier","Y"], + ["constant.numeric","+.990"] +],[ + "start", + ["comment","N25"], + ["text"," "], + ["string","G84.3"], + ["text"," "], + ["identifier","X"], + ["constant.numeric","-0.1"] +],[ + "start", + ["comment","N26"], + ["text"," #"], + ["constant.numeric","4"], + ["text","=#"], + ["constant.numeric","5"], + ["text","*"], + ["identifier","COS"], + ["paren.lparen","["], + ["constant.numeric","45"], + ["paren.rparen","]"] +],[ + "start", + ["comment","N27"], + ["text"," #"], + ["constant.numeric","4"], + ["text","=#"], + ["constant.numeric","5"], + ["text","*"], + ["identifier","SIN"], + ["paren.lparen","["], + ["constant.numeric","45"], + ["paren.rparen","]"] +],[ + "start", + ["comment","N28"], + ["text"," "], + ["identifier","VZOFZ"], + ["text","="], + ["constant.numeric","652.9658"] +],[ + "start", + ["text","%"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_gherkin.json b/node_modules/ace/lib/ace/mode/_test/tokens_gherkin.json new file mode 100644 index 00000000..d16ffc6c --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_gherkin.json @@ -0,0 +1,142 @@ +[[ + "start", + ["comment","@these"], + ["text"," "], + ["comment","@are"], + ["text"," "], + ["comment","@tags"] +],[ + "start", + ["keyword","Feature:"], + ["text"," Serve coffee"] +],[ + "start", + ["text"," Coffee should not be served until paid for"] +],[ + "start", + ["text"," Coffee should not be served until the button has been pressed"] +],[ + "start", + ["text"," If there is no coffee left then money should be refunded"] +],[ + "start", + ["text"," "] +],[ + "start", + ["text"," "], + ["keyword","Scenario Outline:"], + ["text"," Eating"] +],[ + "start", + ["text"," "], + ["keyword","Given"], + ["text"," there are "], + ["comment",""], + ["text"," cucumbers"] +],[ + "start", + ["text"," "], + ["keyword","When"], + ["text"," I eat "], + ["comment",""], + ["text"," cucumbers"] +],[ + "start", + ["text"," "], + ["keyword","Then"], + ["text"," I should have "], + ["comment",""], + ["text"," cucumbers"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword","Examples:"] +],[ + "start", + ["text"," "], + ["comment","| "], + ["string","start "], + ["comment","| "], + ["string","eat "], + ["comment","| "], + ["string","left "], + ["comment","|"] +],[ + "start", + ["text"," "], + ["comment","| "], + ["string"," 12 "], + ["comment","| "], + ["string"," 5 "], + ["comment","| "], + ["string"," 7 "], + ["comment","|"] +],[ + "start", + ["text"," "], + ["comment","| "], + ["string"," 20 "], + ["comment","| "], + ["string"," 5 "], + ["comment","| "], + ["string"," 15 "], + ["comment","| "], + ["string"," "] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword","Scenario:"], + ["text"," Buy last coffee"] +],[ + "start", + ["text"," "], + ["keyword","Given"], + ["text"," there are "], + ["constant.numeric","1"], + ["text"," coffees left in the machine"] +],[ + "start", + ["text"," "], + ["keyword","And"], + ["text"," I have deposited "], + ["constant.numeric","1"], + ["text","$ "] +],[ + "start", + ["text"," "], + ["keyword","When"], + ["text"," I press the coffee button"] +],[ + "start", + ["text"," "], + ["keyword","Then"], + ["text"," I should be served a "], + ["string","\"coffee\""] +],[ + "start", + ["text"," "] +],[ + "start", + ["text"," "], + ["comment","# this a comment"] +],[ + "start", + ["text"," "] +],[ + "qqstring3", + ["text"," "], + ["string","\"\"\""] +],[ + "qqstring3", + ["string"," this is a "] +],[ + "qqstring3", + ["string"," pystring"] +],[ + "start", + ["string"," \"\"\""] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_gitignore.json b/node_modules/ace/lib/ace/mode/_test/tokens_gitignore.json new file mode 100644 index 00000000..8689a724 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_gitignore.json @@ -0,0 +1,33 @@ +[[ + "start", + ["comment","# A sample .gitignore file."] +],[ + "start" +],[ + "start", + ["text",".buildlog"] +],[ + "start", + ["text",".DS_Store"] +],[ + "start", + ["text",".svn"] +],[ + "start" +],[ + "start", + ["comment","# Negated patterns:"] +],[ + "start", + ["keyword","!foo.bar"] +],[ + "start" +],[ + "start", + ["comment","# Also ignore user settings..."] +],[ + "start", + ["text","/.settings"] +],[ + "start" +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_glsl.json b/node_modules/ace/lib/ace/mode/_test/tokens_glsl.json new file mode 100644 index 00000000..ce8a4d16 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_glsl.json @@ -0,0 +1,127 @@ +[[ + "start", + ["keyword","uniform"], + ["text"," "], + ["keyword","float"], + ["text"," "], + ["identifier","amplitude"], + ["punctuation.operator",";"] +],[ + "start", + ["keyword","attribute"], + ["text"," "], + ["keyword","float"], + ["text"," "], + ["identifier","displacement"], + ["punctuation.operator",";"] +],[ + "start", + ["keyword","varying"], + ["text"," "], + ["keyword","vec3"], + ["text"," "], + ["identifier","vNormal"], + ["punctuation.operator",";"] +],[ + "start" +],[ + "start", + ["keyword","void"], + ["text"," "], + ["identifier","main"], + ["paren.lparen","("], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start" +],[ + "start", + ["text"," "], + ["identifier","vNormal"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["identifier","normal"], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "] +],[ + "start", + ["text"," "], + ["comment","// multiply our displacement by the"] +],[ + "start", + ["text"," "], + ["comment","// amplitude. The amp will get animated"] +],[ + "start", + ["text"," "], + ["comment","// so we'll have animated displacement"] +],[ + "start", + ["text"," "], + ["keyword","vec3"], + ["text"," "], + ["identifier","newPosition"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["identifier","position"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "] +],[ + "start", + ["text"," "], + ["identifier","normal"], + ["text"," "], + ["keyword.operator","*"], + ["text"," "] +],[ + "start", + ["text"," "], + ["keyword","vec3"], + ["paren.lparen","("], + ["identifier","displacement"], + ["text"," "], + ["keyword.operator","*"] +],[ + "start", + ["text"," "], + ["identifier","amplitude"], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["constant.language","gl_Position"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["identifier","projectionMatrix"], + ["text"," "], + ["keyword.operator","*"] +],[ + "start", + ["text"," "], + ["identifier","modelViewMatrix"], + ["text"," "], + ["keyword.operator","*"] +],[ + "start", + ["text"," "], + ["keyword","vec4"], + ["paren.lparen","("], + ["identifier","newPosition"], + ["punctuation.operator",","], + ["constant.numeric","1.0"], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + "start", + ["paren.rparen","}"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_golang.json b/node_modules/ace/lib/ace/mode/_test/tokens_golang.json new file mode 100644 index 00000000..070c0a17 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_golang.json @@ -0,0 +1,256 @@ +[[ + "start", + ["comment","// Concurrent computation of pi."] +],[ + "start", + ["comment","// See http://goo.gl/ZuTZM."] +],[ + "start", + ["comment","//"] +],[ + "start", + ["comment","// This demonstrates Go's ability to handle"] +],[ + "start", + ["comment","// large numbers of concurrent processes."] +],[ + "start", + ["comment","// It is an unreasonable way to calculate pi."] +],[ + "start", + ["keyword","package"], + ["text"," "], + ["identifier","main"] +],[ + "start" +],[ + "start", + ["keyword","import"], + ["text"," "], + ["paren.lparen","("] +],[ + "start", + ["text"," "], + ["string","\"fmt\""] +],[ + "start", + ["text"," "], + ["string","\"math\""] +],[ + "start", + ["paren.rparen",")"] +],[ + "start" +],[ + "start", + ["keyword","func"], + ["text"," "], + ["identifier","main"], + ["paren.lparen","("], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["identifier","fmt"], + ["punctuation.operator","."], + ["identifier","Println"], + ["paren.lparen","("], + ["identifier","pi"], + ["paren.lparen","("], + ["constant.numeric","5000"], + ["paren.rparen","))"] +],[ + "start", + ["paren.rparen","}"] +],[ + "start" +],[ + "start", + ["comment","// pi launches n goroutines to compute an"] +],[ + "start", + ["comment","// approximation of pi."] +],[ + "start", + ["keyword","func"], + ["text"," "], + ["identifier","pi"], + ["paren.lparen","("], + ["identifier","n"], + ["text"," "], + ["support.type","int"], + ["paren.rparen",")"], + ["text"," "], + ["support.type","float64"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["identifier","ch"], + ["text"," "], + ["punctuation.operator",":"], + ["keyword.operator","="], + ["text"," "], + ["support.function","make"], + ["paren.lparen","("], + ["keyword","chan"], + ["text"," "], + ["support.type","float64"], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["keyword","for"], + ["text"," "], + ["identifier","k"], + ["text"," "], + ["punctuation.operator",":"], + ["keyword.operator","="], + ["text"," "], + ["constant.numeric","0"], + ["punctuation.operator",";"], + ["text"," "], + ["identifier","k"], + ["text"," "], + ["keyword.operator","<="], + ["text"," "], + ["identifier","n"], + ["punctuation.operator",";"], + ["text"," "], + ["identifier","k"], + ["keyword.operator","++"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["keyword","go"], + ["text"," "], + ["identifier","term"], + ["paren.lparen","("], + ["identifier","ch"], + ["punctuation.operator",","], + ["text"," "], + ["support.type","float64"], + ["paren.lparen","("], + ["identifier","k"], + ["paren.rparen","))"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["text"," "], + ["identifier","f"], + ["text"," "], + ["punctuation.operator",":"], + ["keyword.operator","="], + ["text"," "], + ["constant.numeric","0.0"] +],[ + "start", + ["text"," "], + ["keyword","for"], + ["text"," "], + ["identifier","k"], + ["text"," "], + ["punctuation.operator",":"], + ["keyword.operator","="], + ["text"," "], + ["constant.numeric","0"], + ["punctuation.operator",";"], + ["text"," "], + ["identifier","k"], + ["text"," "], + ["keyword.operator","<="], + ["text"," "], + ["identifier","n"], + ["punctuation.operator",";"], + ["text"," "], + ["identifier","k"], + ["keyword.operator","++"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["identifier","f"], + ["text"," "], + ["keyword.operator","+="], + ["text"," "], + ["keyword.operator","<-"], + ["identifier","ch"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["text"," "], + ["keyword","return"], + ["text"," "], + ["identifier","f"] +],[ + "start", + ["paren.rparen","}"] +],[ + "start" +],[ + "start", + ["keyword","func"], + ["text"," "], + ["identifier","term"], + ["paren.lparen","("], + ["identifier","ch"], + ["text"," "], + ["keyword","chan"], + ["text"," "], + ["support.type","float64"], + ["punctuation.operator",","], + ["text"," "], + ["identifier","k"], + ["text"," "], + ["support.type","float64"], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["identifier","ch"], + ["text"," "], + ["keyword.operator","<-"], + ["text"," "], + ["constant.numeric","4"], + ["text"," "], + ["keyword.operator","*"], + ["text"," "], + ["identifier","math"], + ["punctuation.operator","."], + ["identifier","Pow"], + ["paren.lparen","("], + ["constant.numeric","-1"], + ["punctuation.operator",","], + ["text"," "], + ["identifier","k"], + ["paren.rparen",")"], + ["text"," / "], + ["paren.lparen","("], + ["constant.numeric","2"], + ["keyword.operator","*"], + ["identifier","k"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["constant.numeric","1"], + ["paren.rparen",")"] +],[ + "start", + ["paren.rparen","}"] +],[ + "start" +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_groovy.json b/node_modules/ace/lib/ace/mode/_test/tokens_groovy.json new file mode 100644 index 00000000..c7dae6b1 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_groovy.json @@ -0,0 +1,410 @@ +[[ + "start", + ["comment","//http://groovy.codehaus.org/Martin+Fowler%27s+closure+examples+in+Groovy"] +],[ + "start" +],[ + "start", + ["keyword","class"], + ["text"," "], + ["identifier","Employee"], + ["text"," "], + ["lparen","{"] +],[ + "start", + ["text"," "], + ["keyword","def"], + ["text"," "], + ["identifier","name"], + ["text",", "], + ["identifier","salary"] +],[ + "start", + ["text"," "], + ["keyword","boolean"], + ["text"," "], + ["identifier","manager"] +],[ + "start", + ["text"," "], + ["support.function","String"], + ["text"," "], + ["identifier","toString"], + ["lparen","("], + ["rparen",")"], + ["text"," "], + ["lparen","{"], + ["text"," "], + ["keyword","return"], + ["text"," "], + ["identifier","name"], + ["text"," "], + ["rparen","}"] +],[ + "start", + ["rparen","}"] +],[ + "start" +],[ + "start", + ["keyword","def"], + ["text"," "], + ["identifier","emps"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["lparen","["], + ["keyword","new"], + ["text"," "], + ["identifier","Employee"], + ["lparen","("], + ["identifier","name"], + ["text",":"], + ["string","'Guillaume'"], + ["text",", "], + ["identifier","manager"], + ["text",":"], + ["constant.language.boolean","true"], + ["text",", "], + ["identifier","salary"], + ["text",":"], + ["constant.numeric","200"], + ["rparen",")"], + ["text",","] +],[ + "start", + ["text"," "], + ["keyword","new"], + ["text"," "], + ["identifier","Employee"], + ["lparen","("], + ["identifier","name"], + ["text",":"], + ["string","'Graeme'"], + ["text",", "], + ["identifier","manager"], + ["text",":"], + ["constant.language.boolean","true"], + ["text",", "], + ["identifier","salary"], + ["text",":"], + ["constant.numeric","200"], + ["rparen",")"], + ["text",","] +],[ + "start", + ["text"," "], + ["keyword","new"], + ["text"," "], + ["identifier","Employee"], + ["lparen","("], + ["identifier","name"], + ["text",":"], + ["string","'Dierk'"], + ["text",", "], + ["identifier","manager"], + ["text",":"], + ["constant.language.boolean","false"], + ["text",", "], + ["identifier","salary"], + ["text",":"], + ["constant.numeric","151"], + ["rparen",")"], + ["text",","] +],[ + "start", + ["text"," "], + ["keyword","new"], + ["text"," "], + ["identifier","Employee"], + ["lparen","("], + ["identifier","name"], + ["text",":"], + ["string","'Bernd'"], + ["text",", "], + ["identifier","manager"], + ["text",":"], + ["constant.language.boolean","false"], + ["text",", "], + ["identifier","salary"], + ["text",":"], + ["constant.numeric","50"], + ["rparen",")]"] +],[ + "start" +],[ + "start", + ["keyword","def"], + ["text"," "], + ["identifier","managers"], + ["lparen","("], + ["identifier","emps"], + ["rparen",")"], + ["text"," "], + ["lparen","{"] +],[ + "start", + ["text"," "], + ["identifier","emps"], + ["text","."], + ["identifier","findAll"], + ["text"," "], + ["lparen","{"], + ["text"," "], + ["identifier","e"], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["identifier","e"], + ["text","."], + ["identifier","isManager"], + ["lparen","("], + ["rparen",")"], + ["text"," "], + ["rparen","}"] +],[ + "start", + ["rparen","}"] +],[ + "start" +],[ + "start", + ["keyword","assert"], + ["text"," "], + ["identifier","emps"], + ["lparen","["], + ["constant.numeric","0"], + ["text",".."], + ["constant.numeric","1"], + ["rparen","]"], + ["text"," "], + ["keyword.operator","=="], + ["text"," "], + ["identifier","managers"], + ["lparen","("], + ["identifier","emps"], + ["rparen",")"], + ["text"," "], + ["comment","// [Guillaume, Graeme]"] +],[ + "start" +],[ + "start", + ["keyword","def"], + ["text"," "], + ["identifier","highPaid"], + ["lparen","("], + ["identifier","emps"], + ["rparen",")"], + ["text"," "], + ["lparen","{"] +],[ + "start", + ["text"," "], + ["identifier","threshold"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["constant.numeric","150"] +],[ + "start", + ["text"," "], + ["identifier","emps"], + ["text","."], + ["identifier","findAll"], + ["text"," "], + ["lparen","{"], + ["text"," "], + ["identifier","e"], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["identifier","e"], + ["text","."], + ["identifier","salary"], + ["text"," "], + ["keyword.operator",">"], + ["text"," "], + ["identifier","threshold"], + ["text"," "], + ["rparen","}"] +],[ + "start", + ["rparen","}"] +],[ + "start" +],[ + "start", + ["keyword","assert"], + ["text"," "], + ["identifier","emps"], + ["lparen","["], + ["constant.numeric","0"], + ["text",".."], + ["constant.numeric","2"], + ["rparen","]"], + ["text"," "], + ["keyword.operator","=="], + ["text"," "], + ["identifier","highPaid"], + ["lparen","("], + ["identifier","emps"], + ["rparen",")"], + ["text"," "], + ["comment","// [Guillaume, Graeme, Dierk]"] +],[ + "start" +],[ + "start", + ["keyword","def"], + ["text"," "], + ["identifier","paidMore"], + ["lparen","("], + ["identifier","amount"], + ["rparen",")"], + ["text"," "], + ["lparen","{"] +],[ + "start", + ["text"," "], + ["lparen","{"], + ["text"," "], + ["identifier","e"], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["identifier","e"], + ["text","."], + ["identifier","salary"], + ["text"," "], + ["keyword.operator",">"], + ["text"," "], + ["identifier","amount"], + ["rparen","}"] +],[ + "start", + ["rparen","}"] +],[ + "start", + ["keyword","def"], + ["text"," "], + ["identifier","highPaid"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["identifier","paidMore"], + ["lparen","("], + ["constant.numeric","150"], + ["rparen",")"] +],[ + "start" +],[ + "start", + ["keyword","assert"], + ["text"," "], + ["identifier","highPaid"], + ["lparen","("], + ["identifier","emps"], + ["lparen","["], + ["constant.numeric","0"], + ["rparen","])"], + ["text"," "], + ["comment","// true"] +],[ + "start", + ["keyword","assert"], + ["text"," "], + ["identifier","emps"], + ["lparen","["], + ["constant.numeric","0"], + ["text",".."], + ["constant.numeric","2"], + ["rparen","]"], + ["text"," "], + ["keyword.operator","=="], + ["text"," "], + ["identifier","emps"], + ["text","."], + ["identifier","findAll"], + ["lparen","("], + ["identifier","highPaid"], + ["rparen",")"] +],[ + "start" +],[ + "start", + ["keyword","def"], + ["text"," "], + ["identifier","filename"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["string","'test.txt'"] +],[ + "start", + ["keyword","new"], + ["text"," "], + ["identifier","File"], + ["lparen","("], + ["identifier","filename"], + ["rparen",")"], + ["text","."], + ["identifier","withReader"], + ["lparen","{"], + ["text"," "], + ["identifier","reader"], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["identifier","doSomethingWith"], + ["lparen","("], + ["identifier","reader"], + ["rparen",")"], + ["text"," "], + ["rparen","}"] +],[ + "start" +],[ + "start", + ["keyword","def"], + ["text"," "], + ["identifier","readersText"] +],[ + "start", + ["keyword","def"], + ["text"," "], + ["identifier","doSomethingWith"], + ["lparen","("], + ["identifier","reader"], + ["rparen",")"], + ["text"," "], + ["lparen","{"], + ["text"," "], + ["identifier","readersText"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["identifier","reader"], + ["text","."], + ["identifier","text"], + ["text"," "], + ["rparen","}"] +],[ + "start" +],[ + "start", + ["keyword","assert"], + ["text"," "], + ["keyword","new"], + ["text"," "], + ["identifier","File"], + ["lparen","("], + ["identifier","filename"], + ["rparen",")"], + ["text","."], + ["identifier","text"], + ["text"," "], + ["keyword.operator","=="], + ["text"," "], + ["identifier","readersText"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_haml.json b/node_modules/ace/lib/ace/mode/_test/tokens_haml.json new file mode 100644 index 00000000..423c3bd5 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_haml.json @@ -0,0 +1,174 @@ +[[ + "start", + ["keyword.other.doctype","!!!5"] +],[ + "start" +],[ + "start", + ["punctuation.section.comment","# "] +],[ + "start", + ["punctuation.section.comment","# "] +],[ + "start", + ["punctuation.section.comment","# "] +],[ + "start", + ["punctuation.section.comment","# "] +],[ + "start" +],[ + "start" +],[ + "start", + ["punctuation.section.comment","/adasdasdad"] +],[ + "start", + ["entity.name.tag.haml","%div"], + ["punctuation.section","{"], + ["constant.other.symbol.ruby",":id"], + ["text"," => "], + ["string","\"#{@item.type}_#{@item.number}\""], + ["text",", "], + ["constant.other.symbol.ruby",":class"], + ["text"," => "], + ["string","'#{@item.type} #{@item.urgency}'"], + ["text",", "], + ["constant.other.symbol.ruby",":phoney"], + ["text"," => "], + ["string","`asdasdasd`"], + ["punctuation.section","}"] +],[ + "start", + ["punctuation.section.comment","/ file: app/views/movies/index.html.haml"] +],[ + "start", + ["meta.escape.haml","\\d"] +],[ + "start", + ["entity.name.tag.haml","%ads:"], + ["punctuation.section","{"], + ["constant.other.symbol.ruby",":bleh"], + ["text"," => "], + ["constant.numeric","33"], + ["punctuation.section","}"] +],[ + "embedded_ruby", + ["entity.name.tag.haml","%p"], + ["text","==ddd=="] +],[ + "start", + ["text"," Date/Time:"] +],[ + "embedded_ruby", + ["text"," - "], + ["identifier","now"], + ["text"," = "], + ["support.class","DateTime"], + ["text","."], + ["identifier","now"], + ["text"," "] +],[ + "start", + ["entity.name.tag.haml"," %strong"], + ["text","= now"] +],[ + "embedded_ruby", + ["text"," = "], + ["keyword","if"], + ["text"," "], + ["identifier","now"], + ["text"," "], + ["support.class","DateTime"], + ["text","."], + ["identifier","parse"], + ["text","(\""], + ["support.class","December"], + ["text"," "], + ["constant.numeric","31"], + ["text",", "], + ["constant.numeric","2006"], + ["text","\")"] +],[ + "embedded_ruby", + ["text"," = \""], + ["support.class","Happy"], + ["text"," "], + ["identifier","new"], + ["text"," \" + \""], + ["identifier","year"], + ["text","!\""] +],[ + "start", + ["entity.name.tag.haml","%sfd"], + ["entity.other.attribute-name.class.haml",".dfdfg"] +],[ + "start", + ["punctuation.section.comment","#content"] +],[ + "start", + ["text"," .title"] +],[ + "start", + ["entity.name.tag.haml"," %h1"], + ["text","= @title"] +],[ + "embedded_ruby", + ["text"," = "], + ["support.function","link_to"], + ["text"," '"], + ["support.class","Home"], + ["text","', "], + ["identifier","home_url"] +],[ + "start" +],[ + "start", + ["punctuation.section.comment"," #contents"] +],[ + "start", + ["entity.name.tag.haml","%div"], + ["entity.other.attribute-name.id.haml","#content"] +],[ + "start", + ["entity.name.tag.haml"," %div"], + ["entity.other.attribute-name.class.haml",".articles"] +],[ + "start", + ["entity.name.tag.haml"," %div"], + ["entity.other.attribute-name.class.haml",".article.title"], + ["text"," Blah"] +],[ + "start", + ["entity.name.tag.haml"," %div"], + ["entity.other.attribute-name.class.haml",".article.date"], + ["text"," "], + ["constant.numeric","2006-11-05"] +],[ + "start", + ["entity.name.tag.haml"," %div"], + ["entity.other.attribute-name.class.haml",".article.entry"] +],[ + "start", + ["text"," Neil Patrick Harris "] +],[ + "start" +],[ + "start", + ["entity.name.tag.haml","%div"], + ["text","[@user, "], + ["constant.other.symbol.ruby",":greeting"], + ["text","]"] +],[ + "start", + ["entity.name.tag.haml"," %bar"], + ["text","["], + ["constant.numeric","290"], + ["text","]/"] +],[ + "start", + ["text"," "], + ["string.quoted.double","==Hello!=="] +],[ + "start" +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_handlebars.json b/node_modules/ace/lib/ace/mode/_test/tokens_handlebars.json new file mode 100644 index 00000000..1ec79139 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_handlebars.json @@ -0,0 +1,81 @@ +[[ + "start", + ["comment.start","{{!--"], + ["comment"," Ace + :-}} "], + ["comment.end","--}}"] +],[ + "start" +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","div"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","id"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"comments\""], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," "], + ["storage.type.start","{{#"], + ["variable.parameter","each"], + ["text"," "], + ["variable.parameter","comments"], + ["storage.type.end","}}"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","h2"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.anchor.tag-name.xml","a"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","href"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"/posts/"], + ["storage.type.start","{{"], + ["text","../"], + ["variable.parameter","permalink"], + ["storage.type.end","}}"], + ["string.attribute-value.xml","#"], + ["storage.type.start","{{"], + ["variable.parameter","id"], + ["storage.type.end","}}"], + ["string.attribute-value.xml","\""], + ["meta.tag.punctuation.tag-close.xml",">"], + ["storage.type.start","{{"], + ["variable.parameter","title"], + ["storage.type.end","}}"], + ["meta.tag.punctuation.end-tag-open.xml",""], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","div"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["support.function","{{{"], + ["variable.parameter","body"], + ["support.function","}}}"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "], + ["storage.type.start","{{/"], + ["variable.parameter","each"], + ["storage.type.end","}}"] +],[ + "start", + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start" +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_haskell.json b/node_modules/ace/lib/ace/mode/_test/tokens_haskell.json new file mode 100644 index 00000000..8f9a2b38 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_haskell.json @@ -0,0 +1,156 @@ +[[ + "start", + ["punctuation.definition.comment.haskell","-- Type annotation (optional)"] +],[ + "start", + ["entity.name.function.haskell","fib"], + ["meta.function.type-declaration.haskell"," "], + ["keyword.other.double-colon.haskell","::"], + ["meta.function.type-declaration.haskell"," "], + ["support.type.prelude.haskell","Int"], + ["meta.function.type-declaration.haskell"," "], + ["keyword.other.arrow.haskell","->"], + ["meta.function.type-declaration.haskell"," "], + ["support.type.prelude.haskell","Integer"] +],[ + "start", + ["text"," "] +],[ + "start", + ["punctuation.definition.comment.haskell","-- With self-referencing data"] +],[ + "start", + ["text","fib n "], + ["keyword.operator.haskell","="], + ["text"," fibs "], + ["keyword.operator.haskell","!!"], + ["text"," n"] +],[ + "start", + ["text"," "], + ["keyword.other.haskell","where"], + ["text"," fibs "], + ["keyword.operator.haskell","="], + ["text"," "], + ["constant.numeric.haskell","0"], + ["text"," "], + ["keyword.operator.haskell",":"], + ["text"," "], + ["support.function.prelude.haskell","scanl"], + ["text"," "], + ["entity.name.function.infix.haskell","(+)"], + ["text"," "], + ["constant.numeric.haskell","1"], + ["text"," fibs"] +],[ + "start", + ["text"," "], + ["punctuation.definition.comment.haskell","-- 0,1,1,2,3,5,..."] +],[ + "start", + ["text"," "] +],[ + "start", + ["punctuation.definition.comment.haskell","-- Same, coded directly"] +],[ + "start", + ["text","fib n "], + ["keyword.operator.haskell","="], + ["text"," fibs "], + ["keyword.operator.haskell","!!"], + ["text"," n"] +],[ + "start", + ["text"," "], + ["keyword.other.haskell","where"], + ["text"," fibs "], + ["keyword.operator.haskell","="], + ["text"," "], + ["constant.numeric.haskell","0"], + ["text"," "], + ["keyword.operator.haskell",":"], + ["text"," "], + ["constant.numeric.haskell","1"], + ["text"," "], + ["keyword.operator.haskell",":"], + ["text"," next fibs"] +],[ + "start", + ["text"," next (a "], + ["keyword.operator.haskell",":"], + ["text"," t@(b"], + ["keyword.operator.haskell",":"], + ["text","_)) "], + ["keyword.operator.haskell","="], + ["text"," (a"], + ["keyword.operator.haskell","+"], + ["text","b) "], + ["keyword.operator.haskell",":"], + ["text"," next t"] +],[ + "start", + ["text"," "] +],[ + "start", + ["punctuation.definition.comment.haskell","-- Similar idea, using zipWith"] +],[ + "start", + ["text","fib n "], + ["keyword.operator.haskell","="], + ["text"," fibs "], + ["keyword.operator.haskell","!!"], + ["text"," n"] +],[ + "start", + ["text"," "], + ["keyword.other.haskell","where"], + ["text"," fibs "], + ["keyword.operator.haskell","="], + ["text"," "], + ["constant.numeric.haskell","0"], + ["text"," "], + ["keyword.operator.haskell",":"], + ["text"," "], + ["constant.numeric.haskell","1"], + ["text"," "], + ["keyword.operator.haskell",":"], + ["text"," "], + ["support.function.prelude.haskell","zipWith"], + ["text"," "], + ["entity.name.function.infix.haskell","(+)"], + ["text"," fibs ("], + ["support.function.prelude.haskell","tail"], + ["text"," fibs)"] +],[ + "start", + ["text"," "] +],[ + "start", + ["punctuation.definition.comment.haskell","-- Using a generator function"] +],[ + "start", + ["text","fib n "], + ["keyword.operator.haskell","="], + ["text"," fibs ("], + ["constant.numeric.haskell","0"], + ["punctuation.separator.comma.haskell",","], + ["constant.numeric.haskell","1"], + ["text",") "], + ["keyword.operator.haskell","!!"], + ["text"," n"] +],[ + "start", + ["text"," "], + ["keyword.other.haskell","where"], + ["text"," fibs (a"], + ["punctuation.separator.comma.haskell",","], + ["text","b) "], + ["keyword.operator.haskell","="], + ["text"," a "], + ["keyword.operator.haskell",":"], + ["text"," fibs (b"], + ["punctuation.separator.comma.haskell",","], + ["text","a"], + ["keyword.operator.haskell","+"], + ["text","b)"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_haxe.json b/node_modules/ace/lib/ace/mode/_test/tokens_haxe.json new file mode 100644 index 00000000..f0f79a48 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_haxe.json @@ -0,0 +1,143 @@ +[[ + "start", + ["keyword","class"], + ["text"," "], + ["identifier","Haxe"], + ["text"," "] +],[ + "start", + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["keyword","public"], + ["text"," "], + ["keyword","static"], + ["text"," "], + ["keyword","function"], + ["text"," "], + ["identifier","main"], + ["paren.lparen","("], + ["paren.rparen",")"], + ["text"," "] +],[ + "start", + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["comment","// Say Hello!"] +],[ + "start", + ["text"," "], + ["keyword","var"], + ["text"," "], + ["identifier","greeting"], + ["punctuation.operator",":"], + ["keyword","String"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["string","\"Hello World\""], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "], + ["keyword","trace"], + ["paren.lparen","("], + ["identifier","greeting"], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "] +],[ + "start", + ["text"," "], + ["keyword","var"], + ["text"," "], + ["identifier","targets"], + ["punctuation.operator",":"], + ["keyword","Array"], + ["keyword.operator","<"], + ["keyword","String"], + ["keyword.operator",">"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["paren.lparen","["], + ["string","\"Flash\""], + ["punctuation.operator",","], + ["string","\"Javascript\""], + ["punctuation.operator",","], + ["string","\"PHP\""], + ["punctuation.operator",","], + ["string","\"Neko\""], + ["punctuation.operator",","], + ["string","\"C++\""], + ["punctuation.operator",","], + ["string","\"iOS\""], + ["punctuation.operator",","], + ["string","\"Android\""], + ["punctuation.operator",","], + ["string","\"webOS\""], + ["paren.rparen","]"], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "], + ["keyword","trace"], + ["paren.lparen","("], + ["string","\"Haxe is a great language that can target:\""], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "], + ["keyword","for"], + ["text"," "], + ["paren.lparen","("], + ["identifier","target"], + ["text"," "], + ["keyword","in"], + ["text"," "], + ["identifier","targets"], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["keyword","trace"], + ["text"," "], + ["paren.lparen","("], + ["string","\" - \""], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["identifier","target"], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["text"," "], + ["keyword","trace"], + ["paren.lparen","("], + ["string","\"And many more!\""], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["paren.rparen","}"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_html.json b/node_modules/ace/lib/ace/mode/_test/tokens_html.json new file mode 100644 index 00000000..c5f75eff --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_html.json @@ -0,0 +1,63 @@ +[[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","html"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","scripts"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.script.tag-name.xml","script"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","a"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","'a'"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["storage.type","var"], + ["text"," "], + ["string","\""], + ["meta.tag.punctuation.end-tag-open.xml",""], + ["text.xml","'123'"] +],[ + "start", + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + ["string.attribute-value.xml0","tag_stuff"], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.anchor.tag-name.xml","a"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","href"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"abc"] +],[ + "start", + ["string.attribute-value.xml"," def\""], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + ["string.attribute-value.xml","tag_stuff"], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.anchor.tag-name.xml","a"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","href"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","'abc"] +],[ + "start", + ["string.attribute-value.xml","def\\'"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start" +],[ + "start", + ["meta.tag.punctuation.end-tag-open.xml",""] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_html_ruby.json b/node_modules/ace/lib/ace/mode/_test/tokens_html_ruby.json new file mode 100644 index 00000000..8ff5f6ea --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_html_ruby.json @@ -0,0 +1,257 @@ +[[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","h1"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text.xml","Listing Books"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "] +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.table.tag-name.xml","table"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.table.tag-name.xml","tr"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.table.tag-name.xml","th"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text.xml","Title"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.table.tag-name.xml","th"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text.xml","Summary"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.table.tag-name.xml","th"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.table.tag-name.xml","th"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.table.tag-name.xml","th"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "] +],[ + "start", + ["support.ruby_tag","<%"], + ["text"," "], + ["variable.instance","@books"], + ["text","."], + ["identifier","each"], + ["text"," "], + ["keyword","do"], + ["text"," |"], + ["identifier","book"], + ["text","| "], + ["support.ruby_tag","%>"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.table.tag-name.xml","tr"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," "], + ["comment.start.erb","<%#"], + ["comment"," comment "], + ["comment.end.erb","%>"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.table.tag-name.xml","td"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["support.ruby_tag","<%="], + ["text"," "], + ["identifier","book"], + ["text","."], + ["identifier","title"], + ["text"," "], + ["support.ruby_tag","%>"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.table.tag-name.xml","td"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["support.ruby_tag","<%="], + ["text"," "], + ["identifier","book"], + ["text","."], + ["identifier","content"], + ["text"," "], + ["support.ruby_tag","%>"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.table.tag-name.xml","td"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["support.ruby_tag","<%="], + ["text"," "], + ["support.function","link_to"], + ["text"," "], + ["string.start","'"], + ["string","Show"], + ["string.end","'"], + ["text",", "], + ["identifier","book"], + ["text"," "], + ["support.ruby_tag","%>"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.table.tag-name.xml","td"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["support.ruby_tag","<%="], + ["text"," "], + ["support.function","link_to"], + ["text"," "], + ["string.start","'"], + ["string","Edit"], + ["string.end","'"], + ["text",", "], + ["identifier","edit_book_path"], + ["paren.lparen","("], + ["identifier","book"], + ["paren.rparen",")"], + ["text"," "], + ["support.ruby_tag","%>"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.table.tag-name.xml","td"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["support.ruby_tag","<%="], + ["text"," "], + ["support.function","link_to"], + ["text"," "], + ["string.start","'"], + ["string","Remove"], + ["string.end","'"], + ["text",", "], + ["identifier","book"], + ["text",", "], + ["constant.other.symbol.ruby",":confirm"], + ["text"," "], + ["punctuation.separator.key-value","=>"], + ["text"," "], + ["string.start","'"], + ["string","Are you sure?"], + ["string.end","'"], + ["text",", "], + ["constant.other.symbol.ruby",":method"], + ["text"," "], + ["punctuation.separator.key-value","=>"], + ["text"," "], + ["constant.other.symbol.ruby",":delete"], + ["text"," "], + ["support.ruby_tag","%>"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["support.ruby_tag","<%"], + ["text"," "], + ["keyword","end"], + ["text"," "], + ["support.ruby_tag","%>"] +],[ + "start", + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "] +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","br"], + ["text.tag-whitespace.xml"," "], + ["meta.tag.punctuation.tag-close.xml","/>"] +],[ + "start", + ["text.xml"," "] +],[ + "start", + ["support.ruby_tag","<%="], + ["text"," "], + ["support.function","link_to"], + ["text"," "], + ["string.start","'"], + ["string","New book"], + ["string.end","'"], + ["text",", "], + ["identifier","new_book_path"], + ["text"," "], + ["support.ruby_tag","%>"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_ini.json b/node_modules/ace/lib/ace/mode/_test/tokens_ini.json new file mode 100644 index 00000000..11d28017 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_ini.json @@ -0,0 +1,23 @@ +[[ + "start", + ["punctuation.definition.entity.ini","["], + ["constant.section.group-title.ini",".ShellClassInfo"], + ["punctuation.definition.entity.ini","]"] +],[ + "start", + ["keyword.other.definition.ini","IconResource"], + ["punctuation.separator.key-value.ini","="], + ["text","..\\logo.png"] +],[ + "start", + ["punctuation.definition.entity.ini","["], + ["constant.section.group-title.ini","ViewState"], + ["punctuation.definition.entity.ini","]"] +],[ + "start", + ["keyword.other.definition.ini","FolderType"], + ["punctuation.separator.key-value.ini","="], + ["text","Generic"] +],[ + "start" +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_io.json b/node_modules/ace/lib/ace/mode/_test/tokens_io.json new file mode 100644 index 00000000..b83a675a --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_io.json @@ -0,0 +1,49 @@ +[[ + "start", + ["punctuation.definition.comment.io","//"], + ["comment.line.double-slash.io"," computes factorial of a number"] +],[ + "start", + ["text","factorial "], + ["keyword.operator.io",":="], + ["text"," "], + ["support.function.io","method"], + ["text","(n,"] +],[ + "start", + ["text"," "], + ["keyword.control.io","if"], + ["text","(n "], + ["keyword.operator.io","=="], + ["text"," "], + ["constant.numeric.io","0"], + ["text",", "], + ["keyword.control.io","return"], + ["text"," "], + ["constant.numeric.io","1"], + ["text",")"] +],[ + "start", + ["text"," res "], + ["keyword.operator.io",":="], + ["text"," "], + ["constant.numeric.io","1"] +],[ + "start", + ["text"," "], + ["support.class.io","Range"], + ["text"," "], + ["constant.numeric.io","1"], + ["text"," "], + ["support.function.io","to"], + ["text","(n) "], + ["keyword.control.io","foreach"], + ["text","(i, res "], + ["keyword.operator.io","="], + ["text"," res "], + ["keyword.operator.io","*"], + ["text"," i)"] +],[ + "start", + ["text",")"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_jack.json b/node_modules/ace/lib/ace/mode/_test/tokens_jack.json new file mode 100644 index 00000000..c3d694dd --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_jack.json @@ -0,0 +1,1786 @@ +[[ + "start", + ["keyword","vars"], + ["text"," "], + ["variable","it"], + ["text",", "], + ["variable","p"] +],[ + "start" +],[ + "start", + ["variable","p"], + ["text"," = "], + ["paren.lparen","{"], + ["variable","label"], + ["text",", "], + ["variable","value"], + ["text","|"] +],[ + "start", + ["text"," "], + ["language.builtin","print"], + ["paren.lparen","("], + ["string","\""], + ["constant.language.escape","\\n"], + ["string","\""], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["variable","label"], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["language.builtin","print"], + ["paren.lparen","("], + ["language.builtin","inspect"], + ["paren.lparen","("], + ["variable","value"], + ["paren.rparen","))"] +],[ + "start", + ["paren.rparen","}"] +],[ + "start", + ["comment","-- Create an array from 0 to 15"] +],[ + "start", + ["variable","p"], + ["paren.lparen","("], + ["string","\"range\""], + ["text",", "], + ["language.builtin","i-collect"], + ["paren.lparen","("], + ["language.builtin","range"], + ["paren.lparen","("], + ["constant.numeric","5"], + ["paren.rparen",")))"] +],[ + "start" +],[ + "start", + ["comment","-- Create an array from 0 to 15 and break up in chunks of 4"] +],[ + "start", + ["variable","p"], + ["paren.lparen","("], + ["string","\"chunked range\""], + ["text",", "], + ["language.builtin","i-collect"], + ["paren.lparen","("], + ["language.builtin","i-chunk"], + ["paren.lparen","("], + ["constant.numeric","4"], + ["text",", "], + ["language.builtin","range"], + ["paren.lparen","("], + ["constant.numeric","16"], + ["paren.rparen","))))"] +],[ + "start" +],[ + "start", + ["comment","-- Check if all or none items in stream pass test."] +],[ + "start", + ["variable","p"], + ["paren.lparen","("], + ["string","\"all < 60 in range(60)\""], + ["text",", "], + ["variable","i-all?"], + ["paren.lparen","({"], + ["variable","i"], + ["text","|"], + ["variable","i"], + ["keyword.operator","<"], + ["constant.numeric","60"], + ["paren.rparen","}"], + ["text",", "], + ["language.builtin","range"], + ["paren.lparen","("], + ["constant.numeric","60"], + ["paren.rparen",")))"] +],[ + "start", + ["variable","p"], + ["paren.lparen","("], + ["string","\"any < 60 in range(60)\""], + ["text",", "], + ["variable","i-any?"], + ["paren.lparen","({"], + ["variable","i"], + ["text","|"], + ["variable","i"], + ["keyword.operator",">"], + ["constant.numeric","60"], + ["paren.rparen","}"], + ["text",", "], + ["language.builtin","range"], + ["paren.lparen","("], + ["constant.numeric","60"], + ["paren.rparen",")))"] +],[ + "start", + ["variable","p"], + ["paren.lparen","("], + ["string","\"all < 60 in range(70)\""], + ["text",", "], + ["variable","i-all?"], + ["paren.lparen","({"], + ["variable","i"], + ["text","|"], + ["variable","i"], + ["keyword.operator","<"], + ["constant.numeric","60"], + ["paren.rparen","}"], + ["text",", "], + ["language.builtin","range"], + ["paren.lparen","("], + ["constant.numeric","70"], + ["paren.rparen",")))"] +],[ + "start", + ["variable","p"], + ["paren.lparen","("], + ["string","\"any < 60 in range(70)\""], + ["text",", "], + ["variable","i-any?"], + ["paren.lparen","({"], + ["variable","i"], + ["text","|"], + ["variable","i"], + ["keyword.operator",">"], + ["constant.numeric","60"], + ["paren.rparen","}"], + ["text",", "], + ["language.builtin","range"], + ["paren.lparen","("], + ["constant.numeric","70"], + ["paren.rparen",")))"] +],[ + "start" +],[ + "start", + ["comment","-- Zip three different collections together"] +],[ + "start", + ["variable","p"], + ["paren.lparen","("], + ["string","\"zipped\""], + ["text",", "], + ["language.builtin","i-collect"], + ["paren.lparen","("], + ["language.builtin","i-zip"], + ["paren.lparen","("] +],[ + "start", + ["text"," "], + ["language.builtin","range"], + ["paren.lparen","("], + ["constant.numeric","10"], + ["paren.rparen",")"], + ["text",","] +],[ + "start", + ["text"," "], + ["paren.lparen","["], + ["constant.numeric","1"], + ["text",","], + ["constant.numeric","2"], + ["text",","], + ["constant.numeric","3"], + ["text",","], + ["constant.numeric","4"], + ["text",","], + ["constant.numeric","5"], + ["paren.rparen","]"], + ["text",","] +],[ + "start", + ["text"," "], + ["language.builtin","i-map"], + ["paren.lparen","({"], + ["variable","i"], + ["text","|"], + ["variable","i"], + ["keyword.operator","*"], + ["variable","i"], + ["paren.rparen","}"], + ["text",", "], + ["language.builtin","range"], + ["paren.lparen","("], + ["constant.numeric","10"], + ["paren.rparen","))"] +],[ + "start", + ["paren.rparen",")))"] +],[ + "start" +],[ + "start", + ["keyword","vars"], + ["text"," "], + ["variable","names"], + ["text",", "], + ["variable","person"], + ["text",", "], + ["variable","i"], + ["text",", "], + ["variable","doubles"], + ["text",", "], + ["variable","lengths"], + ["text",", "], + ["variable","cubeRange"] +],[ + "start", + ["variable","names"], + ["text"," = "], + ["paren.lparen","["], + ["string","\"Thorin\""], + ["text",", "], + ["string","\"Dwalin\""], + ["text",", "], + ["string","\"Balin\""], + ["text",", "], + ["string","\"Bifur\""], + ["text",", "], + ["string","\"Bofur\""], + ["text",", "], + ["string","\"Bombur\""], + ["text",", "], + ["string","\"Oin\""], + ["text",","] +],[ + "start", + ["text"," "], + ["string","\"Gloin\""], + ["text",", "], + ["string","\"Ori\""], + ["text",", "], + ["string","\"Nori\""], + ["text",", "], + ["string","\"Dori\""], + ["text",", "], + ["string","\"Fili\""], + ["text",", "], + ["string","\"Kili\""], + ["text",", "], + ["string","\"Bilbo\""], + ["text",", "], + ["string","\"Gandalf\""], + ["paren.rparen","]"] +],[ + "start" +],[ + "start", + ["keyword","for"], + ["text"," "], + ["variable","name"], + ["text"," "], + ["keyword","in"], + ["text"," "], + ["variable","names"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["keyword","if"], + ["text"," "], + ["variable","name"], + ["text"," "], + ["keyword.operator","!="], + ["text"," "], + ["string","\"Bilbo\""], + ["text"," "], + ["keyword.operator","&&"], + ["text"," "], + ["variable","name"], + ["text"," "], + ["keyword.operator","!="], + ["text"," "], + ["string","\"Gandalf\""], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["language.builtin","print"], + ["paren.lparen","("], + ["variable","name"], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["paren.rparen","}"] +],[ + "start" +],[ + "start", + ["variable","person"], + ["text"," = "], + ["paren.lparen","{"], + ["variable","name"], + ["text",": "], + ["string","\"Tim\""], + ["text",", "], + ["variable","age"], + ["text",": "], + ["constant.numeric","30"], + ["paren.rparen","}"] +],[ + "start", + ["keyword","for"], + ["text"," "], + ["variable","key"], + ["text",", "], + ["variable","value"], + ["text"," "], + ["keyword","in"], + ["text"," "], + ["variable","person"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["language.builtin","print"], + ["paren.lparen","("], + ["variable","key"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["string","\" = \""], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["variable","value"], + ["paren.rparen",")"] +],[ + "start", + ["paren.rparen","}"] +],[ + "start" +],[ + "start", + ["variable","i"], + ["text"," = "], + ["constant.numeric","0"] +],[ + "start", + ["keyword","while"], + ["text"," "], + ["variable","i"], + ["text"," "], + ["keyword.operator","<"], + ["text"," "], + ["constant.numeric","10"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["variable","i"], + ["text"," = "], + ["variable","i"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["constant.numeric","1"] +],[ + "start", + ["text"," "], + ["language.builtin","print"], + ["paren.lparen","("], + ["variable","i"], + ["paren.rparen",")"] +],[ + "start", + ["paren.rparen","}"] +],[ + "start" +],[ + "start", + ["language.builtin","print"], + ["paren.lparen","("], + ["string","\"range\""], + ["paren.rparen",")"] +],[ + "start", + ["keyword","for"], + ["text"," "], + ["variable","i"], + ["text"," "], + ["keyword","in"], + ["text"," "], + ["language.builtin","range"], + ["paren.lparen","("], + ["constant.numeric","10"], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["language.builtin","print"], + ["paren.lparen","("], + ["variable","i"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["constant.numeric","1"], + ["paren.rparen",")"] +],[ + "start", + ["paren.rparen","}"] +],[ + "start", + ["keyword","for"], + ["text"," "], + ["variable","i"], + ["text"," "], + ["keyword","in"], + ["text"," "], + ["language.builtin","range"], + ["paren.lparen","("], + ["constant.numeric","10"], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["language.builtin","print"], + ["paren.lparen","("], + ["constant.numeric","10"], + ["text"," "], + ["keyword.operator","-"], + ["text"," "], + ["variable","i"], + ["paren.rparen",")"] +],[ + "start", + ["paren.rparen","}"] +],[ + "start" +],[ + "start", + ["comment","-- Dynamic object that gives the first 10 doubles"] +],[ + "start", + ["variable","doubles"], + ["text"," = "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["storage.form","@len"], + ["text",": "], + ["paren.lparen","{"], + ["text","| "], + ["constant.numeric","10"], + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["text"," "], + ["storage.form","@get"], + ["text",": "], + ["paren.lparen","{"], + ["variable","key"], + ["text","|"] +],[ + "start", + ["text"," "], + ["keyword","if"], + ["text"," "], + ["variable","key"], + ["text"," "], + ["keyword","is"], + ["text"," "], + ["storage.type","Integer"], + ["text"," "], + ["paren.lparen","{"], + ["text"," "], + ["variable","key"], + ["text"," "], + ["keyword.operator","*"], + ["text"," "], + ["variable","key"], + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["paren.rparen","}"] +],[ + "start", + ["language.builtin","print"], + ["paren.lparen","("], + ["string","\"#doubles\""], + ["text",", "], + ["keyword.operator","#"], + ["variable","doubles"], + ["paren.rparen",")"] +],[ + "start" +],[ + "start", + ["language.builtin","print"], + ["paren.lparen","("], + ["string","\"Doubles\""], + ["paren.rparen",")"] +],[ + "start", + ["keyword","for"], + ["text"," "], + ["variable","k"], + ["text",", "], + ["variable","v"], + ["text"," "], + ["keyword","in"], + ["text"," "], + ["variable","doubles"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["language.builtin","print"], + ["paren.lparen","(["], + ["variable","k"], + ["text",", "], + ["variable","v"], + ["paren.rparen","])"] +],[ + "start", + ["paren.rparen","}"] +],[ + "start" +],[ + "start", + ["comment","-- Dynamic object that has names list as keys and string lenth as values"] +],[ + "start", + ["variable","lengths"], + ["text"," = "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["storage.form","@keys"], + ["text",": "], + ["paren.lparen","{"], + ["text","| "], + ["variable","names"], + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["text"," "], + ["storage.form","@get"], + ["text",": "], + ["paren.lparen","{"], + ["variable","key"], + ["text","|"] +],[ + "start", + ["text"," "], + ["keyword","if"], + ["text"," "], + ["variable","key"], + ["text"," "], + ["keyword","is"], + ["text"," "], + ["storage.type","String"], + ["text"," "], + ["paren.lparen","{"], + ["text"," "], + ["keyword.operator","#"], + ["variable","key"], + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["paren.rparen","}"] +],[ + "start" +],[ + "start", + ["language.builtin","print"], + ["text"," "], + ["paren.lparen","("], + ["string","\"Lengths\""], + ["paren.rparen",")"] +],[ + "start", + ["keyword","for"], + ["text"," "], + ["variable","k"], + ["text",", "], + ["variable","v"], + ["text"," "], + ["keyword","in"], + ["text"," "], + ["variable","lengths"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["language.builtin","print"], + ["paren.lparen","(["], + ["variable","k"], + ["text",", "], + ["variable","v"], + ["paren.rparen","])"] +],[ + "start", + ["paren.rparen","}"] +],[ + "start" +],[ + "start" +],[ + "start", + ["variable","cubeRange"], + ["text"," = "], + ["paren.lparen","{"], + ["variable","n"], + ["text","|"] +],[ + "start", + ["text"," "], + ["keyword","vars"], + ["text"," "], + ["variable","i"], + ["text",", "], + ["variable","v"] +],[ + "start", + ["text"," "], + ["variable","i"], + ["text"," = "], + ["constant.numeric","0"] +],[ + "start", + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["storage.form","@call"], + ["text",": "], + ["paren.lparen","{"], + ["text","|"] +],[ + "start", + ["text"," "], + ["variable","v"], + ["text"," = "], + ["variable","i"] +],[ + "start", + ["text"," "], + ["variable","i"], + ["text"," = "], + ["variable","i"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["constant.numeric","1"] +],[ + "start", + ["text"," "], + ["keyword","if"], + ["text"," "], + ["variable","v"], + ["text"," "], + ["keyword.operator","<"], + ["text"," "], + ["variable","n"], + ["text"," "], + ["paren.lparen","{"], + ["text"," "], + ["variable","v"], + ["text"," "], + ["keyword.operator","*"], + ["text"," "], + ["variable","v"], + ["text"," "], + ["keyword.operator","*"], + ["text"," "], + ["variable","v"], + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["paren.rparen","}"] +],[ + "start" +],[ + "start", + ["language.builtin","print"], + ["paren.lparen","("], + ["string","\"Cubes\""], + ["paren.rparen",")"] +],[ + "start", + ["keyword","for"], + ["text"," "], + ["variable","k"], + ["text",", "], + ["variable","v"], + ["text"," "], + ["keyword","in"], + ["text"," "], + ["variable","cubeRange"], + ["paren.lparen","("], + ["constant.numeric","5"], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["language.builtin","print"], + ["paren.lparen","(["], + ["variable","k"], + ["text",", "], + ["variable","v"], + ["paren.rparen","])"] +],[ + "start", + ["paren.rparen","}"] +],[ + "start", + ["language.builtin","print"], + ["paren.lparen","("], + ["string","\"String\""], + ["paren.rparen",")"] +],[ + "start", + ["keyword","for"], + ["text"," "], + ["variable","k"], + ["text",", "], + ["variable","v"], + ["text"," "], + ["keyword","in"], + ["text"," "], + ["string","\"Hello World\""], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["language.builtin","print"], + ["paren.lparen","(["], + ["variable","k"], + ["text",", "], + ["variable","v"], + ["paren.rparen","])"] +],[ + "start", + ["paren.rparen","}"] +],[ + "start" +],[ + "start" +],[ + "start", + ["language.builtin","print"], + ["paren.lparen","(["], + ["variable","i"], + ["text"," "], + ["keyword","for"], + ["text"," "], + ["variable","i"], + ["text"," "], + ["keyword","in"], + ["text"," "], + ["language.builtin","range"], + ["paren.lparen","("], + ["constant.numeric","10"], + ["paren.rparen",")])"] +],[ + "start", + ["language.builtin","print"], + ["paren.lparen","(["], + ["variable","i"], + ["text"," "], + ["keyword","for"], + ["text"," "], + ["variable","i"], + ["text"," "], + ["keyword","in"], + ["text"," "], + ["language.builtin","range"], + ["paren.lparen","("], + ["constant.numeric","20"], + ["paren.rparen",")"], + ["text"," "], + ["keyword","if"], + ["text"," "], + ["variable","i"], + ["text"," "], + ["keyword.operator","%"], + ["text"," "], + ["constant.numeric","3"], + ["paren.rparen","])"] +],[ + "start" +],[ + "start" +],[ + "start" +],[ + "start", + ["comment","-- Example showing how to do parallel work using split..and"] +],[ + "start", + ["variable","base"], + ["text"," = "], + ["paren.lparen","{"], + ["variable","bootstrap"], + ["text",", "], + ["variable","target-dir"], + ["text","|"] +],[ + "start", + ["text"," "], + ["keyword","split"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["variable","copy"], + ["paren.lparen","("], + ["string","\"res\""], + ["text",", "], + ["variable","target-dir"], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"], + ["text"," "], + ["keyword","and"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["keyword","if"], + ["text"," "], + ["variable","newer"], + ["paren.lparen","("], + ["string","\"src/*.less\""], + ["text",", "], + ["variable","target-dir"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["string","\"/style.css\""], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["variable","lessc"], + ["paren.lparen","("], + ["string","\"src/\""], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["variable","bootstrap"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["string","\".less\""], + ["text",", "], + ["variable","target-dir"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["string","\"/style.css\""], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"], + ["text"," "], + ["keyword","and"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["variable","build"], + ["paren.lparen","("], + ["string","\"src/\""], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["variable","bootstrap"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["string","\".js\""], + ["text",", "], + ["variable","target-dir"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["string","\"/app.js\""], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["paren.rparen","}"] +],[ + "start" +],[ + "start" +],[ + "start", + ["keyword","vars"], + ["text"," "], + ["variable","Dragon"], + ["text",", "], + ["variable","pet"] +],[ + "start" +],[ + "start", + ["variable","Dragon"], + ["text"," = "], + ["paren.lparen","{"], + ["variable","name"], + ["text","|"] +],[ + "start", + ["text"," "], + ["keyword","vars"], + ["text"," "], + ["variable","asleep"], + ["text",", "], + ["variable","stuff-in-belly"], + ["text",", "], + ["variable","stuff-in-intestine"], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","feed"], + ["text",", "], + ["variable","walk"], + ["text",", "], + ["variable","put-to-bed"], + ["text",", "], + ["variable","toss"], + ["text",", "], + ["variable","rock"], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","hungry?"], + ["text",", "], + ["variable","poopy?"], + ["text",", "], + ["variable","passage-of-time"] +],[ + "start" +],[ + "start", + ["text"," "], + ["variable","asleep"], + ["text"," = "], + ["constant.language.boolean","false"] +],[ + "start", + ["text"," "], + ["variable","stuff-in-belly"], + ["text"," = "], + ["constant.numeric","10"], + ["text"," "], + ["comment","-- He's full."] +],[ + "start", + ["text"," "], + ["variable","stuff-in-intestine"], + ["text"," = "], + ["constant.numeric","0"], + ["text"," "], + ["comment","-- He doesn't need to go."] +],[ + "start" +],[ + "start", + ["text"," "], + ["language.builtin","print"], + ["paren.lparen","("], + ["variable","name"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["string","' is born.'"], + ["paren.rparen",")"] +],[ + "start" +],[ + "start", + ["text"," "], + ["variable","feed"], + ["text"," = "], + ["paren.lparen","{"], + ["text","|"] +],[ + "start", + ["text"," "], + ["language.builtin","print"], + ["paren.lparen","("], + ["string","'You feed '"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["variable","name"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["string","'.'"], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["variable","stuff-in-belly"], + ["text"," = "], + ["constant.numeric","10"] +],[ + "start", + ["text"," "], + ["variable","passage-of-time"], + ["paren.lparen","("], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start" +],[ + "start", + ["text"," "], + ["variable","walk"], + ["text"," = "], + ["paren.lparen","{"], + ["text","|"] +],[ + "start", + ["text"," "], + ["language.builtin","print"], + ["paren.lparen","("], + ["string","'You walk '"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["variable","name"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["string","\".\""], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["variable","stuff-in-intestine"], + ["text"," = "], + ["constant.numeric","0"] +],[ + "start", + ["text"," "], + ["variable","passage-of-time"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start" +],[ + "start", + ["text"," "], + ["variable","put-to-bed"], + ["text"," = "], + ["paren.lparen","{"], + ["text","|"] +],[ + "start", + ["text"," "], + ["language.builtin","print"], + ["paren.lparen","("], + ["string","'You put '"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["variable","name"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["string","' to bed.'"], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["variable","asleep"], + ["text"," = "], + ["constant.language.boolean","true"] +],[ + "start", + ["text"," "], + ["keyword","for"], + ["text"," "], + ["variable","i"], + ["text"," "], + ["keyword","in"], + ["text"," "], + ["language.builtin","range"], + ["paren.lparen","("], + ["constant.numeric","3"], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["keyword","if"], + ["text"," "], + ["variable","asleep"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["variable","passage-of-time"], + ["paren.lparen","("], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["text"," "], + ["keyword","if"], + ["text"," "], + ["variable","asleep"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["language.builtin","print"], + ["paren.lparen","("], + ["variable","name"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["string","' snores, filling the room with smoke.'"], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["text"," "], + ["keyword","if"], + ["text"," "], + ["variable","asleep"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["variable","asleep"], + ["text"," = "], + ["constant.language.boolean","false"] +],[ + "start", + ["text"," "], + ["language.builtin","print"], + ["paren.lparen","("], + ["variable","name"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["string","' wakes up slowly.'"], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start" +],[ + "start", + ["text"," "], + ["variable","toss"], + ["text"," = "], + ["paren.lparen","{"], + ["text","|"] +],[ + "start", + ["text"," "], + ["language.builtin","print"], + ["paren.lparen","("], + ["string","'You toss '"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["variable","name"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["string","' up into the air.'"], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["language.builtin","print"], + ["paren.lparen","("], + ["string","'He giggles, which singes your eyebrows.'"], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["variable","passage-of-time"], + ["paren.lparen","("], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start" +],[ + "start", + ["text"," "], + ["variable","rock"], + ["text"," = "], + ["paren.lparen","{"], + ["text","|"] +],[ + "start", + ["text"," "], + ["language.builtin","print"], + ["paren.lparen","("], + ["string","'You rock '"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["variable","name"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["string","' gently.'"], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["variable","asleep"], + ["text"," = "], + ["constant.language.boolean","true"] +],[ + "start", + ["text"," "], + ["language.builtin","print"], + ["paren.lparen","("], + ["string","'He briefly dozes off...'"], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["variable","passage-of-time"], + ["paren.lparen","("], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["keyword","if"], + ["text"," "], + ["variable","asleep"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["variable","asleep"], + ["text"," = "], + ["constant.language.boolean","false"] +],[ + "start", + ["text"," "], + ["language.builtin","print"], + ["paren.lparen","("], + ["string","'...but wakes when you stop.'"], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start" +],[ + "start", + ["text"," "], + ["variable","hungry?"], + ["text"," = "], + ["paren.lparen","{"], + ["text","|"] +],[ + "start", + ["text"," "], + ["variable","stuff-in-belly"], + ["text"," "], + ["keyword.operator","<="], + ["text"," "], + ["constant.numeric","2"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start" +],[ + "start", + ["text"," "], + ["variable","poopy?"], + ["text"," = "], + ["paren.lparen","{"], + ["text","|"] +],[ + "start", + ["text"," "], + ["variable","stuff-in-intestine"], + ["text"," "], + ["keyword.operator",">="], + ["text"," "], + ["constant.numeric","8"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start" +],[ + "start", + ["text"," "], + ["variable","passage-of-time"], + ["text"," = "], + ["paren.lparen","{"], + ["text","|"] +],[ + "start", + ["text"," "], + ["keyword","if"], + ["text"," "], + ["variable","stuff-in-belly"], + ["text"," "], + ["keyword.operator",">"], + ["text"," "], + ["constant.numeric","0"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["comment","-- Move food from belly to intestine"] +],[ + "start", + ["text"," "], + ["variable","stuff-in-belly"], + ["text"," = "], + ["variable","stuff-in-belly"], + ["text"," "], + ["keyword.operator","-"], + ["text"," "], + ["constant.numeric","1"] +],[ + "start", + ["text"," "], + ["variable","stuff-in-intestine"], + ["text"," = "], + ["variable","stuff-in-intestine"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["constant.numeric","1"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"], + ["text"," "], + ["keyword","else"], + ["text"," "], + ["paren.lparen","{"], + ["text"," "], + ["comment","-- Our dragon is starving!"] +],[ + "start", + ["text"," "], + ["keyword","if"], + ["text"," "], + ["variable","asleep"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["variable","asleep"], + ["text"," = "], + ["constant.language.boolean","false"] +],[ + "start", + ["text"," "], + ["language.builtin","print"], + ["paren.lparen","("], + ["string","'He wakes up suddenly!'"], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["text"," "], + ["language.builtin","print"], + ["paren.lparen","("], + ["variable","name"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["string","' is starving! In desperation, he ate YOU!'"], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["keyword","abort"], + ["text"," "], + ["string","\"died\""] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword","if"], + ["text"," "], + ["variable","stuff-in-intestine"], + ["text"," "], + ["keyword.operator",">="], + ["text"," "], + ["constant.numeric","10"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["variable","stuff-in-intestine"], + ["text"," = "], + ["constant.numeric","0"] +],[ + "start", + ["text"," "], + ["language.builtin","print"], + ["paren.lparen","("], + ["string","'Whoops! '"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["variable","name"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["string","' had an accident...'"], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword","if"], + ["text"," "], + ["variable","hungry?"], + ["paren.lparen","("], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["keyword","if"], + ["text"," "], + ["variable","asleep"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["variable","asleep"], + ["text"," = "], + ["constant.language.boolean","false"] +],[ + "start", + ["text"," "], + ["language.builtin","print"], + ["paren.lparen","("], + ["string","'He wakes up suddenly!'"], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["text"," "], + ["language.builtin","print"], + ["paren.lparen","("], + ["variable","name"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["string","\"'s stomach grumbles...\""], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword","if"], + ["text"," "], + ["variable","poopy?"], + ["paren.lparen","("], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["keyword","if"], + ["text"," "], + ["variable","asleep"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["variable","asleep"], + ["text"," = "], + ["constant.language.boolean","false"] +],[ + "start", + ["text"," "], + ["language.builtin","print"], + ["paren.lparen","("], + ["string","'He wakes up suddenly!'"], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["text"," "], + ["language.builtin","print"], + ["paren.lparen","("], + ["variable","name"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["string","' does the potty dance...'"], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start" +],[ + "start", + ["text"," "], + ["comment","-- Export the public interface to this closure object."] +],[ + "start", + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["variable","feed"], + ["text",": "], + ["variable","feed"] +],[ + "start", + ["text"," "], + ["variable","walk"], + ["text",": "], + ["variable","walk"] +],[ + "start", + ["text"," "], + ["variable","put-to-bed"], + ["text",": "], + ["variable","put-to-bed"] +],[ + "start", + ["text"," "], + ["variable","toss"], + ["text",": "], + ["variable","toss"] +],[ + "start", + ["text"," "], + ["variable","rock"], + ["text",": "], + ["variable","rock"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start" +],[ + "start", + ["paren.rparen","}"] +],[ + "start" +],[ + "start", + ["variable","pet"], + ["text"," = "], + ["variable","Dragon"], + ["paren.lparen","("], + ["string","'Norbert'"], + ["paren.rparen",")"] +],[ + "start", + ["variable","pet"], + ["text","."], + ["variable","feed"], + ["paren.lparen","("], + ["paren.rparen",")"] +],[ + "start", + ["variable","pet"], + ["text","."], + ["variable","toss"], + ["paren.lparen","("], + ["paren.rparen",")"] +],[ + "start", + ["variable","pet"], + ["text","."], + ["variable","walk"], + ["paren.lparen","("], + ["paren.rparen",")"] +],[ + "start", + ["variable","pet"], + ["text","."], + ["variable","put-to-bed"], + ["paren.lparen","("], + ["paren.rparen",")"] +],[ + "start", + ["variable","pet"], + ["text","."], + ["variable","rock"], + ["paren.lparen","("], + ["paren.rparen",")"] +],[ + "start", + ["variable","pet"], + ["text","."], + ["variable","put-to-bed"], + ["paren.lparen","("], + ["paren.rparen",")"] +],[ + "start", + ["variable","pet"], + ["text","."], + ["variable","put-to-bed"], + ["paren.lparen","("], + ["paren.rparen",")"] +],[ + "start", + ["variable","pet"], + ["text","."], + ["variable","put-to-bed"], + ["paren.lparen","("], + ["paren.rparen",")"] +],[ + "start", + ["variable","pet"], + ["text","."], + ["variable","put-to-bed"], + ["paren.lparen","("], + ["paren.rparen",")"] +],[ + "start" +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_jade.json b/node_modules/ace/lib/ace/mode/_test/tokens_jade.json new file mode 100644 index 00000000..5bf45968 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_jade.json @@ -0,0 +1,188 @@ +[[ + "start", + ["keyword.other.doctype.jade","!!!doctype"] +],[ + "start", + ["keyword.other.doctype.jade","!!!5"] +],[ + "start", + ["keyword.other.doctype.jade","!!!"] +],[ + "start" +],[ + "start", + ["keyword.control.import.include.jade","include"], + ["text"," something"] +],[ + "start" +],[ + "start", + ["keyword.control.import.include.jade"," include"], + ["text"," another_thing"] +],[ + "start" +],[ + "start", + ["punctuation.section.comment"," // let's talk about it"] +],[ + "start" +],[ + ["comment_block",0,"start"], + ["comment","// "] +],[ + ["comment_block",0,"start"], + ["comment"," here it is. a block comment!"] +],[ + ["comment_block",0,"start"], + ["comment"," and another row!"] +],[ + "start", + ["meta.tag.any.jade","but"], + ["text"," not here."] +],[ + "start" +],[ + ["comment_block",5,"start"], + ["comment"," // "] +],[ + ["comment_block",5,"start"], + ["comment"," a far spaced"] +],[ + "start", + ["text"," should be lack of block"] +],[ + "start" +],[ + "start", + ["punctuation.section.comment"," // also not a comment"] +],[ + "start", + ["meta.tag.any.jade"," div"], + ["entity.other.attribute-name.class.jade",".attemptAtBlock"] +],[ + "start", + ["text"," "] +],[ + "start", + ["meta.tag.any.jade"," span"], + ["entity.other.attribute-name.id.jade","#myName"] +],[ + "start" +],[ + "start", + ["text"," "], + ["string.interpolated.jade","#{implicit}"] +],[ + "start", + ["text"," "], + ["string.interpolated.jade","!{more_explicit}"] +],[ + "start" +],[ + "start", + ["text"," "], + ["suport.type.attribute.id.jade","#idDiv"] +],[ + "start" +],[ + "start", + ["text"," "], + ["suport.type.attribute.class.jade",".idDiv"] +],[ + "start" +],[ + "start", + ["meta.tag.any.jade"," test"], + ["punctuation","("], + ["entity.other.attribute-name.jade","id"], + ["text","="], + ["string","\"tag\""], + ["punctuation",")"] +],[ + "start", + ["meta.tag.any.jade"," header"], + ["punctuation","("], + ["entity.other.attribute-name.jade","id"], + ["text","="], + ["string","\"tag\""], + ["text",", "], + ["entity.other.attribute-name.jade","blah"], + ["text","="], + ["string","\"foo\""], + ["text",", "], + ["entity.other.attribute-name.jade","meh"], + ["text","="], + ["string","\"aads\""], + ["punctuation",")"] +],[ + "start", + ["storage.type.function.jade","mixin"], + ["entity.name.function.jade"," article"], + ["punctuation.definition.parameters.begin.jade","("], + ["variable.parameter.function.jade","obj, parents"], + ["punctuation.definition.parameters.end.jade",")"] +],[ + "start" +],[ + "start", + ["storage.type.function.jade"," mixin"], + ["entity.name.function.jade"," bleh"], + ["punctuation.definition.parameters.begin.jade","("], + ["punctuation.definition.parameters.end.jade",")"] +],[ + "start" +],[ + "start", + ["storage.type.function.jade"," mixin"], + ["entity.name.function.jade"," clever-name"] +],[ + "start" +],[ + "start", + ["source.js.embedded.jade"," -"], + ["storage.type","var"], + ["text"," "], + ["identifier","x"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["string","\"0\""], + ["text",";"] +],[ + "start", + ["source.js.embedded.jade"," -"], + ["text"," "], + ["identifier","y"], + ["text"," "], + ["identifier","each"], + ["text"," z"] +],[ + "start" +],[ + "start", + ["source.js.embedded.jade"," -"], + ["text"," "], + ["storage.type","var"], + ["text"," "], + ["identifier","items"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["paren.lparen","["], + ["string","\"one\""], + ["punctuation.operator",","], + ["text"," "], + ["string","\"two\""], + ["punctuation.operator",","], + ["text"," "], + ["string","\"three\""], + ["text","]"] +],[ + "start", + ["meta.tag.any.jade"," each"], + ["text"," item in items"] +],[ + "start", + ["meta.tag.any.jade"," li"], + ["text","= item"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_java.json b/node_modules/ace/lib/ace/mode/_test/tokens_java.json new file mode 100644 index 00000000..799ebdb5 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_java.json @@ -0,0 +1,95 @@ +[[ + "start", + ["keyword","public"], + ["text"," "], + ["keyword","class"], + ["text"," "], + ["identifier","InfiniteLoop"], + ["text"," "], + ["lparen","{"] +],[ + "start" +],[ + "comment", + ["text"," "], + ["comment","/*"] +],[ + "comment", + ["comment"," * This will cause the program to hang..."] +],[ + "comment", + ["comment"," *"] +],[ + "comment", + ["comment"," * Taken from:"] +],[ + "comment", + ["comment"," * http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/"] +],[ + "start", + ["comment"," */"] +],[ + "start", + ["text"," "], + ["keyword","public"], + ["text"," "], + ["keyword","static"], + ["text"," "], + ["keyword","void"], + ["text"," "], + ["identifier","main"], + ["lparen","("], + ["support.function","String"], + ["lparen","["], + ["rparen","]"], + ["text"," "], + ["identifier","args"], + ["rparen",")"], + ["text"," "], + ["lparen","{"] +],[ + "start", + ["text"," "], + ["keyword","double"], + ["text"," "], + ["identifier","d"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["support.function","Double"], + ["text","."], + ["identifier","parseDouble"], + ["lparen","("], + ["string","\"2.2250738585072012e-308\""], + ["rparen",")"], + ["text",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["comment","// unreachable code"] +],[ + "start", + ["text"," "], + ["support.function","System"], + ["text","."], + ["identifier","out"], + ["text","."], + ["identifier","println"], + ["lparen","("], + ["string","\"Value: \""], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["identifier","d"], + ["rparen",")"], + ["text",";"] +],[ + "start", + ["text"," "], + ["rparen","}"] +],[ + "start", + ["rparen","}"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_javascript.json b/node_modules/ace/lib/ace/mode/_test/tokens_javascript.json new file mode 100644 index 00000000..1be3f605 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_javascript.json @@ -0,0 +1,593 @@ +[[ + "start", + ["comment","//test: tokenize 'standard' functions"] +],[ + "no_regex", + ["identifier","string"], + ["punctuation.operator","."], + ["support.function","charCodeAt"], + ["paren.lparen","("], + ["constant.numeric","23"], + ["paren.rparen",")"], + ["punctuation.operator",";"], + ["text"," "], + ["variable.language","document"], + ["punctuation.operator","."], + ["support.function.dom","getElementById"], + ["paren.lparen","("], + ["string","'test'"], + ["paren.rparen",")"], + ["punctuation.operator",";"], + ["text"," "], + ["storage.type","console"], + ["punctuation.operator","."], + ["support.function.firebug","log"], + ["paren.lparen","("], + ["string","'Here it is'"], + ["paren.rparen",")"], + ["punctuation.operator",";"], + ["string","\";"] +],[ + "no_regex", + ["identifier","test"], + ["punctuation.operator",":"], + ["text"," "], + ["comment.doc","/**tokenize doc*/"], + ["text"," "], + ["identifier","comment"] +],[ + "no_regex", + ["comment.doc","/**tokenize doc comment with "], + ["comment.doc.tag","@tag"], + ["comment.doc"," {}*/"] +],[ + "no_regex", + ["comment","//test: tokenize parens"] +],[ + "start", + ["text"," "], + ["storage.type","var"], + ["text"," "], + ["identifier","line"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["string","\"[{( )}]\""], + ["punctuation.operator",";"] +],[ + "start", + ["comment","//test tokenize arithmetic expression which looks like a regexp"] +],[ + "no_regex", + ["identifier","a"], + ["keyword.operator","/"], + ["identifier","b"], + ["keyword.operator","/"], + ["identifier","c"] +],[ + "no_regex", + ["identifier","a"], + ["keyword.operator","/="], + ["identifier","b"], + ["keyword.operator","/"], + ["identifier","c"] +],[ + "no_regex", + ["comment","//test tokenize reg exps"] +],[ + "no_regex", + ["identifier","a"], + ["keyword.operator","="], + ["string.regexp","/b/g"] +],[ + "no_regex", + ["identifier","a"], + ["keyword.operator","+"], + ["string.regexp","/b/g"] +],[ + "no_regex", + ["identifier","a"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["constant.numeric","1"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["string.regexp","/2 "], + ["constant.language.escape","+"], + ["string.regexp"," 1/gimyx"], + ["identifier","k"] +],[ + "no_regex", + ["identifier","a"], + ["keyword.operator","="], + ["string.regexp","/a/"], + ["text"," "], + ["keyword.operator","/"], + ["text"," "], + ["string.regexp","/a/"] +],[ + "no_regex", + ["keyword","case"], + ["text"," "], + ["string.regexp","/a/"], + ["punctuation.operator","."], + ["support.function","test"], + ["paren.lparen","("], + ["identifier","c"], + ["paren.rparen",")"] +],[ + "no_regex", + ["comment","//test tokenize multi-line comment containing a single line comment"] +],[ + "no_regex", + ["identifier","noRegex"] +],[ + "no_regex", + ["comment","/* foo // bar */"] +],[ + "start", + ["identifier","canBeRegex"], + ["punctuation.operator",";"] +],[ + "start", + ["comment","/* foo // bar */"] +],[ + "start", + ["comment","// test tokenize identifier with umlauts"] +],[ + "no_regex", + ["identifier","fu"], + ["punctuation.operator","?"], + ["identifier","e"] +],[ + "no_regex", + ["comment","// test // is not a regexp"] +],[ + "start", + ["paren.lparen","{"], + ["text"," "], + ["comment","// 123"] +],[ + "start", + ["comment","//test skipping escaped chars"] +],[ + "no_regex", + ["string","'Meh"], + ["constant.language.escape","\\\\"], + ["string","nNeh'"] +],[ + "no_regex", + ["storage.type","console"], + ["punctuation.operator","."], + ["support.function.firebug","log"], + ["paren.lparen","("], + ["string","'"], + ["constant.language.escape","\\\\"], + ["string","u1232Feh'"] +],[ + "qqstring", + ["string","\"test multiline\\"] +],[ + "no_regex", + ["string"," strings\""] +],[ + "no_regex", + ["identifier","a"], + ["keyword.operator","="], + ["text","'"] +],[ + "qqstring", + ["identifier","b"], + ["keyword.operator","="], + ["string","\"\\"] +],[ + "no_regex", + ["string","still a string"] +],[ + "no_regex", + ["text"," "] +],[ + "no_regex", + ["text"," "] +],[ + "start", + ["storage.type","function"], + ["text"," "], + ["entity.name.function","foo"], + ["paren.lparen","("], + ["variable.parameter","items"], + ["punctuation.operator",", "], + ["variable.parameter","nada"], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["keyword","for"], + ["text"," "], + ["paren.lparen","("], + ["storage.type","var"], + ["text"," "], + ["identifier","i"], + ["keyword.operator","="], + ["constant.numeric","0"], + ["punctuation.operator",";"], + ["text"," "], + ["identifier","i"], + ["keyword.operator","<"], + ["identifier","items"], + ["punctuation.operator","."], + ["support.constant","length"], + ["punctuation.operator",";"], + ["text"," "], + ["identifier","i"], + ["keyword.operator","++"], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["support.function","alert"], + ["paren.lparen","("], + ["identifier","items"], + ["paren.lparen","["], + ["identifier","i"], + ["paren.rparen","]"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["string","\"juhu"], + ["constant.language.escape","\\n"], + ["string","\""], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + "no_regex", + ["text"," "], + ["paren.rparen","}"], + ["text","\t"], + ["comment","// Real Tab."] +],[ + "no_regex", + ["paren.rparen","}"] +],[ + "no_regex" +],[ + "no_regex", + ["identifier","regexp"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["string.regexp","/p"], + ["constant.language.delimiter","|"], + ["string.regexp","p/"], + ["text"," "], + ["comment","// ends here"] +],[ + "no_regex" +],[ + "no_regex", + ["identifier","r"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["string.regexp","/d"], + ["constant.language.escape","{1,2}?"], + ["string.regexp","f{e}"], + ["invalid","++"], + ["string.regexp","r"], + ["constant.language.escape","*?"], + ["regexp.keyword.operator","\\d"], + ["constant.language.escape","+?[]"], + ["string.regexp","r"], + ["constant.language.escape","[^"], + ["string.regexp.charachterclass","r"], + ["constant.language.escape","-"], + ["string.regexp.charachterclass","o"], + ["regexp.charclass.keyword.operator","\\f\\f"], + ["string.regexp.charachterclass","["], + ["regexp.charclass.keyword.operator","\\f"], + ["constant.language.escape","]?"], + ["string.regexp","r"], + ["invalid","{7}+"], + ["string.regexp","r"], + ["regexp.keyword.operator","\\{"], + ["string.regexp","7}"], + ["constant.language.escape","+"], + ["string.regexp","rr--rr"], + ["constant.language.escape","$^(?:"], + ["string.regexp","d"], + ["constant.language.delimiter","|"], + ["string.regexp","s"], + ["constant.language.escape",")(?="], + ["string.regexp","a"], + ["constant.language.delimiter","|"], + ["constant.language.escape",")(?!"], + ["string.regexp","y"], + ["constant.language.escape",")[]"], + ["constant.language.delimiter","|"], + ["invalid","$?"], + ["constant.language.delimiter","|"], + ["invalid","^*"], + ["string.regexp","/"], + ["text"," "], + ["identifier","o"] +],[ + "no_regex", + ["identifier","a"], + ["keyword.operator","="], + ["string.regexp","/a/"], + ["text"," "], + ["identifier","jk"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["string.regexp","/ /"], + ["text"," "], + ["keyword.operator","/"], + ["text"," "], + ["string.regexp","/ /"] +],[ + "no_regex", + ["text"," "], + ["comment.doc","/************************************/"] +],[ + "no_regex", + ["comment.doc","/** total mess, tricky to highlight**/"] +],[ + "no_regex" +],[ + "start", + ["storage.type","function"], + ["text"," "], + ["paren.lparen","("], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "doc-start", + ["text","\t"], + ["comment.doc","/**"] +],[ + "doc-start", + ["comment.doc","\t * docComment"] +],[ + "no_regex", + ["comment.doc","\t **/"] +],[ + "no_regex", + ["text","\t"], + ["identifier","r"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["string.regexp","/u"], + ["regexp.keyword.operator","\\t"], + ["constant.language.escape","*"], + ["string.regexp","/"] +],[ + "no_regex", + ["text","\t"], + ["identifier","g"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["constant.numeric","1."], + ["text","00"], + ["identifier","E"], + ["keyword.operator","^"], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["text"," "], + ["identifier","y"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["constant.numeric","1.2"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["punctuation.operator","."], + ["constant.numeric","2"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["constant.numeric","052"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["constant.numeric","0x25"] +],[ + "no_regex", + ["text","\t"], + ["identifier","t"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["paren.lparen","["], + ["string","'d'"], + ["punctuation.operator",","], + ["text"," "], + ["string","''"], + ["paren.rparen","]"] +],[ + "no_regex", + ["paren.rparen","}"] +],[ + "start", + ["storage.type","function"], + ["text"," "], + ["paren.lparen","("], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text","\t"], + ["comment","/* eee */"] +],[ + "no_regex", + ["paren.rparen","}"] +],[ + "no_regex" +],[ + "qqstring", + ["string","\"s\\"] +],[ + "no_regex", + ["string","s"], + ["constant.language.escape","\\u7824"], + ["string","sss"], + ["constant.language.escape","\\u"], + ["string","1\""] +],[ + "no_regex" +],[ + "qstring", + ["string","'\\"] +],[ + "no_regex", + ["string","string'"] +],[ + "no_regex" +],[ + "no_regex", + ["text","'"] +],[ + "no_regex", + ["identifier","string"], + ["text","'"] +],[ + "no_regex" +],[ + "no_regex", + ["string","\"trailing space"], + ["constant.language.escape","\\ "], + ["string"," "] +],[ + "no_regex", + ["string","\" \""], + ["text"," "], + ["keyword.operator","/"], + ["identifier","not"], + ["text"," "], + ["identifier","a"], + ["text"," "], + ["identifier","regexp"], + ["keyword.operator","/"], + ["identifier","g"] +],[ + "no_regex" +],[ + "doc-start", + ["comment.doc","/**"] +],[ + "doc-start", + ["comment.doc"," *doc"] +],[ + "no_regex", + ["comment.doc"," */"] +],[ + "no_regex" +],[ + "start", + ["identifier","a"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text","\t"], + ["string","'a'"], + ["punctuation.operator",":"], + ["text"," "], + ["identifier","b"], + ["punctuation.operator",","] +],[ + "no_regex", + ["text","\t"], + ["string","'g'"], + ["text",":"], + ["text"," "], + ["storage.type","function"], + ["paren.lparen","("], + ["variable.parameter","t"], + ["paren.rparen",")"] +],[ + "no_regex", + ["text","\t"], + ["entity.name.function","gta"], + ["punctuation.operator",":"], + ["storage.type","function"], + ["paren.lparen","("], + ["variable.parameter","a"], + ["punctuation.operator",","], + ["variable.parameter","b"], + ["paren.rparen",")"] +],[ + "no_regex", + ["paren.rparen","}"] +],[ + "no_regex" +],[ + "no_regex" +],[ + "function_arguments", + ["identifier","foo"], + ["punctuation.operator","."], + ["storage.type","protoype"], + ["punctuation.operator","."], + ["entity.name.function","d"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["storage.type","function"], + ["paren.lparen","("], + ["variable.parameter","a"], + ["punctuation.operator",", "], + ["variable.parameter","b"], + ["punctuation.operator",","] +],[ + "no_regex", + ["punctuation.operator"," "], + ["variable.parameter","c"], + ["punctuation.operator",", "], + ["variable.parameter","d"], + ["paren.rparen",")"] +],[ + "no_regex", + ["storage.type","foo"], + ["punctuation.operator","."], + ["entity.name.function","d"], + ["text"," "], + ["keyword.operator","="], + ["storage.type","function"], + ["paren.lparen","("], + ["variable.parameter","a"], + ["punctuation.operator",", "], + ["variable.parameter","b"], + ["paren.rparen",")"] +],[ + "no_regex", + ["storage.type","foo"], + ["punctuation.operator","."], + ["entity.name.function","d"], + ["text"," "], + ["keyword.operator","="], + ["storage.type","function"], + ["paren.lparen","("], + ["variable.parameter","a"], + ["punctuation.operator",", "], + ["comment.doc","/*****/"], + ["text"," "], + ["identifier","d"], + ["string","\"string\""], + ["text"," "] +],[ + "no_regex" +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_json.json b/node_modules/ace/lib/ace/mode/_test/tokens_json.json new file mode 100644 index 00000000..4420a740 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_json.json @@ -0,0 +1,412 @@ +[[ + "start", + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["variable","\"query\""], + ["text",": "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["variable","\"count\""], + ["text",": "], + ["constant.numeric","10"], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"created\""], + ["text",": "], + ["string","\"2011-06-21T08:10:46Z\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"lang\""], + ["text",": "], + ["string","\"en-US\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"results\""], + ["text",": "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["variable","\"photo\""], + ["text",": "], + ["paren.lparen","["] +],[ + "start", + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["variable","\"farm\""], + ["text",": "], + ["string","\"6\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"id\""], + ["text",": "], + ["string","\"5855620975\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"isfamily\""], + ["text",": "], + ["string","\"0\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"isfriend\""], + ["text",": "], + ["string","\"0\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"ispublic\""], + ["text",": "], + ["string","\"1\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"owner\""], + ["text",": "], + ["string","\"32021554@N04\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"secret\""], + ["text",": "], + ["string","\"f1f5e8515d\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"server\""], + ["text",": "], + ["string","\"5110\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"title\""], + ["text",": "], + ["string","\"7087 bandit cat\""] +],[ + "start", + ["text"," "], + ["paren.rparen","}"], + ["text",","] +],[ + "start", + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["variable","\"farm\""], + ["text",": "], + ["string","\"4\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"id\""], + ["text",": "], + ["string","\"5856170534\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"isfamily\""], + ["text",": "], + ["string","\"0\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"isfriend\""], + ["text",": "], + ["string","\"0\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"ispublic\""], + ["text",": "], + ["string","\"1\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"owner\""], + ["text",": "], + ["string","\"32021554@N04\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"secret\""], + ["text",": "], + ["string","\"ff1efb2a6f\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"server\""], + ["text",": "], + ["string","\"3217\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"title\""], + ["text",": "], + ["string","\"6975 rusty cat\""] +],[ + "start", + ["text"," "], + ["paren.rparen","}"], + ["text",","] +],[ + "start", + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["variable","\"farm\""], + ["text",": "], + ["string","\"6\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"id\""], + ["text",": "], + ["string","\"5856172972\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"isfamily\""], + ["text",": "], + ["string","\"0\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"isfriend\""], + ["text",": "], + ["string","\"0\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"ispublic\""], + ["text",": "], + ["string","\"1\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"owner\""], + ["text",": "], + ["string","\"51249875@N03\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"secret\""], + ["text",": "], + ["string","\"6c6887347c\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"server\""], + ["text",": "], + ["string","\"5192\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"title\""], + ["text",": "], + ["string","\"watermarked-cats\""] +],[ + "start", + ["text"," "], + ["paren.rparen","}"], + ["text",","] +],[ + "start", + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["variable","\"farm\""], + ["text",": "], + ["string","\"6\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"id\""], + ["text",": "], + ["string","\"5856168328\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"isfamily\""], + ["text",": "], + ["string","\"0\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"isfriend\""], + ["text",": "], + ["string","\"0\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"ispublic\""], + ["text",": "], + ["string","\"1\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"owner\""], + ["text",": "], + ["string","\"32021554@N04\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"secret\""], + ["text",": "], + ["string","\"0c1cfdf64c\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"server\""], + ["text",": "], + ["string","\"5078\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"title\""], + ["text",": "], + ["string","\"7020 mandy cat\""] +],[ + "start", + ["text"," "], + ["paren.rparen","}"], + ["text",","] +],[ + "start", + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["variable","\"farm\""], + ["text",": "], + ["string","\"3\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"id\""], + ["text",": "], + ["string","\"5856171774\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"isfamily\""], + ["text",": "], + ["string","\"0\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"isfriend\""], + ["text",": "], + ["string","\"0\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"ispublic\""], + ["text",": "], + ["string","\"1\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"owner\""], + ["text",": "], + ["string","\"32021554@N04\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"secret\""], + ["text",": "], + ["string","\"7f5a3180ab\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"server\""], + ["text",": "], + ["string","\"2696\""], + ["text",","] +],[ + "start", + ["text"," "], + ["variable","\"title\""], + ["text",": "], + ["string","\"7448 bobby cat\""] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["text"," "], + ["paren.rparen","]"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["paren.rparen","}"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_jsoniq.json b/node_modules/ace/lib/ace/mode/_test/tokens_jsoniq.json new file mode 100644 index 00000000..0f4ee6e9 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_jsoniq.json @@ -0,0 +1,4 @@ +[[ + "[\"start\"]", + ["support.function","TODO"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_jsp.json b/node_modules/ace/lib/ace/mode/_test/tokens_jsp.json new file mode 100644 index 00000000..25d3af4d --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_jsp.json @@ -0,0 +1,435 @@ +[[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","html"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","body"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "js-start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.script.tag-name.xml","script"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "js-start", + ["text"," "], + ["storage.type","var"], + ["text"," "], + ["identifier","x"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["string","\"abc\""], + ["punctuation.operator",";"] +],[ + "js-start", + ["text"," "], + ["storage.type","function"], + ["text"," "], + ["identifier","y"], + ["text"," "], + ["paren.lparen","{"] +],[ + "js-no_regex", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["text"," "], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "css-start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.style.tag-name.xml","style"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + ["css-ruleset","css-start"], + ["text"," "], + ["variable",".class"], + ["text"," "], + ["paren.lparen","{"] +],[ + ["css-ruleset","css-start"], + ["text"," "], + ["support.type","background"], + ["text",": "], + ["constant.numeric","#124356"], + ["text",";"] +],[ + "css-start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["text"," "], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start" +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","p"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," Today's date: "], + ["meta.tag","<%"], + ["keyword.operator","="], + ["text"," "], + ["lparen","("], + ["keyword","new"], + ["text"," "], + ["identifier","java"], + ["text","."], + ["identifier","util"], + ["text","."], + ["identifier","Date"], + ["lparen","("], + ["rparen","))"], + ["text","."], + ["identifier","toLocaleString"], + ["lparen","("], + ["rparen",")"], + ["meta.tag","%>"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "], + ["meta.tag","<%"], + ["keyword.operator","!"], + ["text"," "], + ["keyword","int"], + ["text"," "], + ["identifier","i"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["constant.numeric","0"], + ["text","; "], + ["meta.tag","%>"] +],[ + "jsp-start", + ["text.xml"," "], + ["meta.tag",""] +],[ + "jsp-start", + ["text"," "], + ["keyword","int"], + ["text"," "], + ["identifier","j"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["constant.numeric","10"], + ["text",";"] +],[ + "start", + ["text"," "], + ["meta.tag",""] +],[ + "start" +],[ + "start", + ["text.xml"," "], + ["comment","<%-- This is JSP comment --%>"] +],[ + "start", + ["text.xml"," "], + ["meta.tag","<%@"], + ["text"," "], + ["identifier","directive"], + ["text"," "], + ["identifier","attribute"], + ["keyword.operator","="], + ["string","\"value\""], + ["text"," "], + ["meta.tag","%>"] +],[ + "start" +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","h2"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text.xml","Select Languages:"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start" +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.form.tag-name.xml","form"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","ACTION"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"jspCheckBox.jsp\""], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.form.tag-name.xml","input"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","type"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"checkbox\""], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","name"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"id\""], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","value"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"Java\""], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text.xml"," Java"], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","BR"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.form.tag-name.xml","input"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","type"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"checkbox\""], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","name"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"id\""], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","value"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\".NET\""], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text.xml"," .NET"], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","BR"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.form.tag-name.xml","input"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","type"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"checkbox\""], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","name"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"id\""], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","value"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"PHP\""], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text.xml"," PHP"], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","BR"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.form.tag-name.xml","input"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","type"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"checkbox\""], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","name"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"id\""], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","value"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"C/C++\""], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text.xml"," C/C++"], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","BR"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.form.tag-name.xml","input"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","type"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"checkbox\""], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","name"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"id\""], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","value"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"PERL\""], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text.xml"," PERL "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","BR"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.form.tag-name.xml","input"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","type"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"submit\""], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","value"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"Submit\""], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start" +],[ + "jsp-start", + ["text.xml"," "], + ["meta.tag","<%"] +],[ + "jsp-start", + ["text"," "], + ["support.function","String"], + ["text"," "], + ["identifier","select"], + ["lparen","["], + ["rparen","]"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["variable.language","request"], + ["text","."], + ["identifier","getParameterValues"], + ["lparen","("], + ["string","\"id\""], + ["rparen",")"], + ["text","; "] +],[ + "jsp-start", + ["text"," "], + ["keyword","if"], + ["text"," "], + ["lparen","("], + ["identifier","select"], + ["text"," "], + ["keyword.operator","!="], + ["text"," "], + ["constant.language","null"], + ["text"," "], + ["keyword.operator","&&"], + ["text"," "], + ["identifier","select"], + ["text","."], + ["identifier","length"], + ["text"," "], + ["keyword.operator","!="], + ["text"," "], + ["constant.numeric","0"], + ["rparen",")"], + ["text"," "], + ["lparen","{"] +],[ + "jsp-start", + ["text"," "], + ["variable.language","out"], + ["text","."], + ["identifier","println"], + ["lparen","("], + ["string","\"You have selected: \""], + ["rparen",")"], + ["text",";"] +],[ + "jsp-start", + ["text"," "], + ["keyword","for"], + ["text"," "], + ["lparen","("], + ["keyword","int"], + ["text"," "], + ["identifier","i"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["constant.numeric","0"], + ["text","; "], + ["identifier","i"], + ["text"," "], + ["keyword.operator","<"], + ["text"," "], + ["identifier","select"], + ["text","."], + ["identifier","length"], + ["text","; "], + ["identifier","i"], + ["keyword.operator","++"], + ["rparen",")"], + ["text"," "], + ["lparen","{"] +],[ + "jsp-start", + ["text"," "], + ["variable.language","out"], + ["text","."], + ["identifier","println"], + ["lparen","("], + ["identifier","select"], + ["lparen","["], + ["identifier","i"], + ["rparen","])"], + ["text","; "] +],[ + "jsp-start", + ["text"," "], + ["rparen","}"] +],[ + "jsp-start", + ["text"," "], + ["rparen","}"] +],[ + "start", + ["text"," "], + ["meta.tag","%>"] +],[ + "start", + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["meta.tag.punctuation.end-tag-open.xml",""] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_jsx.json b/node_modules/ace/lib/ace/mode/_test/tokens_jsx.json new file mode 100644 index 00000000..d1a740b0 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_jsx.json @@ -0,0 +1,51 @@ +[[ + "comment", + ["comment","/*EXPECTED"] +],[ + "comment", + ["comment","hello world!"] +],[ + "start", + ["comment","*/"] +],[ + "start", + ["keyword","class"], + ["text"," "], + ["language.support.class","Test"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["keyword","static"], + ["text"," "], + ["storage.type","function"], + ["text"," "], + ["entity.name.function","run"], + ["paren.lparen","("], + ["paren.rparen",")"], + ["text"," "], + ["punctuation.operator",":"], + ["text"," "], + ["keyword","void"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["comment","// console.log(\"hello world!\");"] +],[ + "start", + ["text"," "], + ["keyword","log"], + ["text"," "], + ["string","\"hello world!\""], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["paren.rparen","}"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_julia.json b/node_modules/ace/lib/ace/mode/_test/tokens_julia.json new file mode 100644 index 00000000..5aaef6f9 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_julia.json @@ -0,0 +1,111 @@ +[[ + "start", + ["keyword.control.julia","for"], + ["text"," op "], + ["keyword.operator.update.julia","="], + ["text"," ("], + ["keyword.operator.ternary.julia",":"], + ["keyword.operator.arithmetic.julia","+"], + ["text",", "], + ["keyword.operator.ternary.julia",":"], + ["keyword.operator.arithmetic.julia","*"], + ["text",", "], + ["keyword.operator.ternary.julia",":"], + ["keyword.operator.bitwise.julia","&"], + ["text",", "], + ["keyword.operator.ternary.julia",":"], + ["keyword.operator.bitwise.julia","|"], + ["text",", "], + ["keyword.operator.ternary.julia",":"], + ["keyword.operator.interpolation.julia","$"], + ["text",")"] +],[ + "start", + ["text"," "], + ["variable.macro.julia","@eval"], + ["text"," ("], + ["keyword.operator.interpolation.julia","$"], + ["text","op)(a,b,c) "], + ["keyword.operator.update.julia","="], + ["text"," ("], + ["keyword.operator.interpolation.julia","$"], + ["text","op)(("], + ["keyword.operator.interpolation.julia","$"], + ["text","op)(a,b),c)"] +],[ + "start", + ["keyword.control.julia","end"] +],[ + "start" +],[ + "start", + ["text","v "], + ["keyword.operator.update.julia","="], + ["text"," "], + ["variable","α"], + ["keyword.operator.transposed-variable.julia","'"], + ["text",";"] +],[ + "start", + ["keyword.other.julia","function"], + ["meta.function.julia"," "], + ["entity.name.function.julia","g"], + ["text","("], + ["text","x,y)"] +],[ + "start", + ["text"," "], + ["keyword.control.julia","return"], + ["text"," x "], + ["keyword.operator.arithmetic.julia","*"], + ["text"," y"] +],[ + "start", + ["text"," x "], + ["keyword.operator.arithmetic.julia","+"], + ["text"," y"] +],[ + "start", + ["keyword.control.julia","end"] +],[ + "start" +],[ + "start", + ["support.function.julia","cd"], + ["text","("], + ["punctuation.definition.string.begin.julia","\""], + ["string.quoted.double.julia","data"], + ["punctuation.definition.string.end.julia","\""], + ["text",") "], + ["keyword.control.julia","do"] +],[ + "start", + ["text"," "], + ["support.function.julia","open"], + ["text","("], + ["punctuation.definition.string.begin.julia","\""], + ["string.quoted.double.julia","outfile"], + ["punctuation.definition.string.end.julia","\""], + ["text",", "], + ["punctuation.definition.string.begin.julia","\""], + ["string.quoted.double.julia","w"], + ["punctuation.definition.string.end.julia","\""], + ["text",") "], + ["keyword.control.julia","do"], + ["text"," f"] +],[ + "start", + ["text"," "], + ["support.function.julia","write"], + ["text","("], + ["text","f, data)"] +],[ + "start", + ["text"," "], + ["keyword.control.julia","end"] +],[ + "start", + ["keyword.control.julia","end"] +],[ + "start" +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_latex.json b/node_modules/ace/lib/ace/mode/_test/tokens_latex.json new file mode 100644 index 00000000..52508e0d --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_latex.json @@ -0,0 +1,127 @@ +[[ + "start", + ["keyword","\\usepackage"], + ["lparen","{"], + ["storage.type","amsmath"], + ["rparen","}"] +],[ + "start", + ["storage.type","\\title"], + ["lparen","{"], + ["storage.type","\\LaTeX"], + ["rparen","}"] +],[ + "start", + ["storage.type","\\date"], + ["lparen","{"], + ["rparen","}"] +],[ + "start", + ["storage.type","\\begin"], + ["lparen","{"], + ["variable.parameter","document"], + ["rparen","}"] +],[ + "start", + ["text"," "], + ["storage.type","\\maketitle"] +],[ + "start", + ["text"," "], + ["storage.type","\\LaTeX"], + ["lparen","{"], + ["rparen","}"], + ["text"," is a document preparation system for the "], + ["storage.type","\\TeX"], + ["lparen","{"], + ["rparen","}"] +],[ + "start", + ["text"," typesetting program. It offers programmable desktop publishing"] +],[ + "start", + ["text"," features and extensive facilities for automating most aspects of"] +],[ + "start", + ["text"," typesetting and desktop publishing, including numbering and"] +],[ + "start", + ["text"," cross-referencing, tables and figures, page layout, bibliographies,"] +],[ + "start", + ["text"," and much more. "], + ["storage.type","\\LaTeX"], + ["lparen","{"], + ["rparen","}"], + ["text"," was originally written in 1984 by Leslie"] +],[ + "start", + ["text"," Lamport and has become the dominant method for using "], + ["storage.type","\\TeX"], + ["text","; few"] +],[ + "start", + ["text"," people write in plain "], + ["storage.type","\\TeX"], + ["lparen","{"], + ["rparen","}"], + ["text"," anymore. The current version is"] +],[ + "start", + ["text"," "], + ["storage.type","\\LaTeXe"], + ["text","."] +],[ + "start", + ["text"," "] +],[ + "start", + ["text"," "], + ["comment","% This is a comment; it will not be shown in the final output."] +],[ + "start", + ["text"," "], + ["comment","% The following shows a little of the typesetting power of LaTeX:"] +],[ + "start", + ["text"," "], + ["storage.type","\\begin"], + ["lparen","{"], + ["variable.parameter","align"], + ["rparen","}"] +],[ + "start", + ["text"," E &= mc^2 "], + ["constant.character.escape","\\\\"] +],[ + "start", + ["text"," m &= "], + ["storage.type","\\frac"], + ["lparen","{"], + ["text","m_0"], + ["rparen","}"], + ["lparen","{"], + ["storage.type","\\sqrt"], + ["lparen","{"], + ["text","1-"], + ["storage.type","\\frac"], + ["lparen","{"], + ["text","v^2"], + ["rparen","}"], + ["lparen","{"], + ["text","c^2"], + ["rparen","}}}"] +],[ + "start", + ["text"," "], + ["storage.type","\\end"], + ["lparen","{"], + ["variable.parameter","align"], + ["rparen","}"] +],[ + "start", + ["storage.type","\\end"], + ["lparen","{"], + ["variable.parameter","document"], + ["rparen","}"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_less.json b/node_modules/ace/lib/ace/mode/_test/tokens_less.json new file mode 100644 index 00000000..81fe0c20 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_less.json @@ -0,0 +1,204 @@ +[[ + "start", + ["comment","/* styles.less */"] +],[ + "start" +],[ + "start", + ["variable","@base"], + ["text",": "], + ["constant.numeric","#f938ab"], + ["text",";"] +],[ + "start" +],[ + "start", + ["variable.language",".box-shadow"], + ["paren.lparen","("], + ["variable","@style"], + ["text",", "], + ["variable","@c"], + ["paren.rparen",")"], + ["text"," "], + ["keyword","when"], + ["text"," "], + ["paren.lparen","("], + ["support.function","iscolor"], + ["paren.lparen","("], + ["variable","@c"], + ["paren.rparen","))"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," box-shadow: "], + ["variable","@style"], + ["text"," "], + ["variable","@c"], + ["text",";"] +],[ + "start", + ["text"," -webkit-box-shadow: "], + ["variable","@style"], + ["text"," "], + ["variable","@c"], + ["text",";"] +],[ + "start", + ["text"," -moz-box-shadow: "], + ["variable","@style"], + ["text"," "], + ["variable","@c"], + ["text",";"] +],[ + "start", + ["paren.rparen","}"] +],[ + "start", + ["variable.language",".box-shadow"], + ["paren.lparen","("], + ["variable","@style"], + ["text",", "], + ["variable","@alpha"], + ["text",": "], + ["constant.numeric","50%"], + ["paren.rparen",")"], + ["text"," "], + ["keyword","when"], + ["text"," "], + ["paren.lparen","("], + ["support.function","isnumber"], + ["paren.lparen","("], + ["variable","@alpha"], + ["paren.rparen","))"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["variable.language",".box-shadow"], + ["paren.lparen","("], + ["variable","@style"], + ["text",", "], + ["support.function","rgba"], + ["paren.lparen","("], + ["constant.numeric","0"], + ["text",", "], + ["constant.numeric","0"], + ["text",", "], + ["constant.numeric","0"], + ["text",", "], + ["variable","@alpha"], + ["paren.rparen","))"], + ["text",";"] +],[ + "start", + ["paren.rparen","}"] +],[ + "start" +],[ + "start", + ["comment","// Box styles"] +],[ + "start", + ["variable.language",".box"], + ["text"," "], + ["paren.lparen","{"], + ["text"," "] +],[ + "start", + ["text"," "], + ["support.type","color"], + ["text",": "], + ["support.function","saturate"], + ["paren.lparen","("], + ["variable","@base"], + ["text",", "], + ["constant.numeric","5%"], + ["paren.rparen",")"], + ["text",";"] +],[ + "start", + ["text"," "], + ["support.type","border-color"], + ["text",": "], + ["support.function","lighten"], + ["paren.lparen","("], + ["variable","@base"], + ["text",", "], + ["constant.numeric","30%"], + ["paren.rparen",")"], + ["text",";"] +],[ + "start", + ["text"," "] +],[ + "start", + ["text"," "], + ["variable.language","div"], + ["text"," "], + ["paren.lparen","{"], + ["text"," "], + ["variable.language",".box-shadow"], + ["paren.lparen","("], + ["constant.numeric","0"], + ["text"," "], + ["constant.numeric","0"], + ["text"," "], + ["constant.numeric","5px"], + ["text",", "], + ["constant.numeric","30%"], + ["paren.rparen",")"], + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["text"," "] +],[ + "start", + ["text"," "], + ["variable.language","a"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["support.type","color"], + ["text",": "], + ["variable","@base"], + ["text",";"] +],[ + "start", + ["text"," "] +],[ + "start", + ["text"," &"], + ["variable.language",":hover"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["support.type","color"], + ["text",": "], + ["support.function","lighten"], + ["paren.lparen","("], + ["variable","@base"], + ["text",", "], + ["constant.numeric","50%"], + ["paren.rparen",")"], + ["text",";"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["paren.rparen","}"] +],[ + "start" +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_liquid.json b/node_modules/ace/lib/ace/mode/_test/tokens_liquid.json new file mode 100644 index 00000000..30d003cb --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_liquid.json @@ -0,0 +1,551 @@ +[[ + "start", + ["text.xml","The following examples can be found in full at http://liquidmarkup.org/"] +],[ + "start" +],[ + "start", + ["text.xml","Liquid is an extraction from the e-commerce system Shopify."] +],[ + "start", + ["text.xml","Shopify powers many thousands of e-commerce stores which all call for unique designs."] +],[ + "start", + ["text.xml","For this we developed Liquid which allows our customers complete design freedom while"] +],[ + "start", + ["text.xml","maintaining the integrity of our servers."] +],[ + "start" +],[ + "start", + ["text.xml","Liquid has been in production use since June 2006 and is now used by many other"] +],[ + "start", + ["text.xml","hosted web applications."] +],[ + "start" +],[ + "start", + ["text.xml","It was developed for usage in Ruby on Rails web applications and integrates seamlessly"] +],[ + "start", + ["text.xml","as a plugin but it also works excellently as a stand alone library."] +],[ + "start" +],[ + "start", + ["text.xml","Here's what it looks like:"] +],[ + "start" +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","ul"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","id"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"products\""], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," "], + ["variable","{%"], + ["text"," "], + ["keyword","for"], + ["text"," "], + ["identifier","product"], + ["text"," "], + ["keyword","in"], + ["text"," "], + ["identifier","products"], + ["text"," "], + ["variable","%}"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","li"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","h2"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["variable","{{"], + ["text"," "], + ["identifier","product"], + ["text","."], + ["identifier","title"], + ["text"," "], + ["variable","}}"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," Only "], + ["variable","{{"], + ["text"," "], + ["identifier","product"], + ["text","."], + ["identifier","price"], + ["text"," | "], + ["identifier","format_as_money"], + ["text"," "], + ["variable","}}"] +],[ + "start" +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","p"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["variable","{{"], + ["text"," "], + ["identifier","product"], + ["text","."], + ["identifier","description"], + ["text"," | "], + ["identifier","prettyprint"], + ["text"," | "], + ["support.function","truncate"], + ["text",": "], + ["constant.numeric","200"], + ["text"," "], + ["variable","}}"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start" +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "], + ["variable","{%"], + ["text"," "], + ["keyword","endfor"], + ["text"," "], + ["variable","%}"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start" +],[ + "start" +],[ + "start", + ["text.xml","Some more features include:"] +],[ + "start" +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","h2"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text.xml","Filters"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","p"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text.xml"," The word \"tobi\" in uppercase: "], + ["variable","{{"], + ["text"," "], + ["string","'tobi'"], + ["text"," | "], + ["support.function","upcase"], + ["text"," "], + ["variable","}}"], + ["text.xml"," "], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","p"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text.xml","The word \"tobi\" has "], + ["variable","{{"], + ["text"," "], + ["string","'tobi'"], + ["text"," | "], + ["support.function","size"], + ["text"," "], + ["variable","}}"], + ["text.xml"," letters! "], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","p"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text.xml","Change \"Hello world\" to \"Hi world\": "], + ["variable","{{"], + ["text"," "], + ["string","'Hello world'"], + ["text"," | "], + ["support.function","replace"], + ["text",": "], + ["string","'Hello'"], + ["text",", "], + ["string","'Hi'"], + ["text"," "], + ["variable","}}"], + ["text.xml"," "], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","p"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text.xml","The date today is "], + ["variable","{{"], + ["text"," "], + ["string","'now'"], + ["text"," | "], + ["support.function","date"], + ["text",": "], + ["string","\"%Y %b %d\""], + ["text"," "], + ["variable","}}"], + ["text.xml"," "], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start" +],[ + "start" +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","h2"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text.xml","If"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","p"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," "], + ["variable","{%"], + ["text"," "], + ["keyword","if"], + ["text"," "], + ["identifier","user"], + ["text","."], + ["identifier","name"], + ["text"," "], + ["keyword.operator","=="], + ["text"," "], + ["string","'tobi'"], + ["text"," "], + ["identifier","or"], + ["text"," "], + ["identifier","user"], + ["text","."], + ["identifier","name"], + ["text"," "], + ["keyword.operator","=="], + ["text"," "], + ["string","'marc'"], + ["text"," "], + ["variable","%}"], + ["text.xml"," "] +],[ + "start", + ["text.xml"," hi marc or tobi"] +],[ + "start", + ["text.xml"," "], + ["variable","{%"], + ["text"," "], + ["keyword","endif"], + ["text"," "], + ["variable","%}"] +],[ + "start", + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start" +],[ + "start" +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","h2"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text.xml","Case"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","p"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," "], + ["variable","{%"], + ["text"," "], + ["keyword","case"], + ["text"," "], + ["identifier","template"], + ["text"," "], + ["variable","%}"] +],[ + "start", + ["text.xml"," "], + ["variable","{%"], + ["text"," "], + ["keyword","when"], + ["text"," "], + ["string","'index'"], + ["text"," "], + ["variable","%}"] +],[ + "start", + ["text.xml"," Welcome"] +],[ + "start", + ["text.xml"," "], + ["variable","{%"], + ["text"," "], + ["keyword","when"], + ["text"," "], + ["string","'product'"], + ["text"," "], + ["variable","%}"] +],[ + "start", + ["text.xml"," "], + ["variable","{{"], + ["text"," "], + ["identifier","product"], + ["text","."], + ["identifier","vendor"], + ["text"," | "], + ["identifier","link_to_vendor"], + ["text"," "], + ["variable","}}"], + ["text.xml"," / "], + ["variable","{{"], + ["text"," "], + ["identifier","product"], + ["text","."], + ["identifier","title"], + ["text"," "], + ["variable","}}"] +],[ + "start", + ["text.xml"," "], + ["variable","{%"], + ["text"," "], + ["keyword","else"], + ["text"," "], + ["variable","%}"] +],[ + "start", + ["text.xml"," "], + ["variable","{{"], + ["text"," "], + ["identifier","page_title"], + ["text"," "], + ["variable","}}"] +],[ + "start", + ["text.xml"," "], + ["variable","{%"], + ["text"," "], + ["keyword","endcase"], + ["text"," "], + ["variable","%}"] +],[ + "start", + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start" +],[ + "start" +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","h2"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text.xml","For Loops"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","p"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," "], + ["variable","{%"], + ["text"," "], + ["keyword","for"], + ["text"," "], + ["identifier","item"], + ["text"," "], + ["keyword","in"], + ["text"," "], + ["identifier","array"], + ["text"," "], + ["variable","%}"], + ["text.xml"," "] +],[ + "start", + ["text.xml"," "], + ["variable","{{"], + ["text"," "], + ["identifier","item"], + ["text"," "], + ["variable","}}"] +],[ + "start", + ["text.xml"," "], + ["variable","{%"], + ["text"," "], + ["keyword","endfor"], + ["text"," "], + ["variable","%}"] +],[ + "start", + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start" +],[ + "start" +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","h2"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text.xml","Tables"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","p"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," "], + ["variable","{%"], + ["text"," "], + ["keyword","tablerow"], + ["text"," "], + ["identifier","item"], + ["text"," "], + ["keyword","in"], + ["text"," "], + ["identifier","items"], + ["text"," "], + ["identifier","cols"], + ["text",": "], + ["constant.numeric","3"], + ["text"," "], + ["variable","%}"] +],[ + "start", + ["text.xml"," "], + ["variable","{%"], + ["text"," "], + ["keyword","if"], + ["text"," "], + ["variable.language","tablerowloop"], + ["text","."], + ["identifier","col_first"], + ["text"," "], + ["variable","%}"] +],[ + "start", + ["text.xml"," First column: "], + ["variable","{{"], + ["text"," "], + ["identifier","item"], + ["text","."], + ["identifier","variable"], + ["text"," "], + ["variable","}}"] +],[ + "start", + ["text.xml"," "], + ["variable","{%"], + ["text"," "], + ["keyword","else"], + ["text"," "], + ["variable","%}"] +],[ + "start", + ["text.xml"," Different column: "], + ["variable","{{"], + ["text"," "], + ["identifier","item"], + ["text","."], + ["identifier","variable"], + ["text"," "], + ["variable","}}"] +],[ + "start", + ["text.xml"," "], + ["variable","{%"], + ["text"," "], + ["keyword","endif"], + ["text"," "], + ["variable","%}"] +],[ + "start", + ["text.xml"," "], + ["variable","{%"], + ["text"," "], + ["keyword","endtablerow"], + ["text"," "], + ["variable","%}"] +],[ + "start", + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start" +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_lisp.json b/node_modules/ace/lib/ace/mode/_test/tokens_lisp.json new file mode 100644 index 00000000..2e70a555 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_lisp.json @@ -0,0 +1,248 @@ +[[ + "start", + ["text","("], + ["storage.type.function-type.lisp","defun"], + ["text"," "], + ["entity.name.function.lisp","prompt-for-cd"], + ["text"," ()"] +],[ + "start", + ["text"," "], + ["string","\"Prompts"] +],[ + "start", + ["text"," "], + ["identifier","for"], + ["text"," "], + ["identifier","CD"], + ["text","\""] +],[ + "start", + ["text"," ("], + ["identifier","prompt"], + ["text","-"], + ["identifier","read"], + ["text"," "], + ["string","\"Title\""], + ["text"," "], + ["constant.numeric","1.53"], + ["text"," "], + ["constant.numeric","1"], + ["text"," "], + ["constant.numeric","2"], + ["text","/"], + ["constant.numeric","4"], + ["text"," "], + ["constant.numeric","1.7"], + ["text"," "], + ["constant.numeric","1.7e0"], + ["text"," "], + ["constant.numeric","2.9E-4"], + ["text"," "], + ["constant.numeric","+42"], + ["text"," "], + ["constant.numeric","-7"], + ["text"," "], + ["punctuation.definition.constant.character.lisp","#"], + ["constant.character.lisp","b001"], + ["text"," "], + ["punctuation.definition.constant.character.lisp","#"], + ["constant.character.lisp","b001/100"], + ["text"," "], + ["punctuation.definition.constant.character.lisp","#"], + ["constant.character.lisp","o777"], + ["text"," "], + ["punctuation.definition.constant.character.lisp","#"], + ["constant.character.lisp","O777"], + ["text"," "], + ["punctuation.definition.constant.character.lisp","#"], + ["constant.character.lisp","xabc55"], + ["text"," "], + ["punctuation.definition.constant.character.lisp","#"], + ["constant.character.lisp","c"], + ["text","("], + ["constant.numeric","0"], + ["text"," "], + ["constant.numeric","-5.6"], + ["text","))"] +],[ + "start", + ["text"," ("], + ["identifier","prompt"], + ["text","-"], + ["identifier","read"], + ["text"," "], + ["string","\"Artist\""], + ["text"," &"], + ["identifier","rest"], + ["text",")"] +],[ + "start", + ["text"," ("], + ["keyword.operator","or"], + ["text"," ("], + ["identifier","parse"], + ["text","-"], + ["identifier","integer"], + ["text"," ("], + ["identifier","prompt"], + ["text","-"], + ["identifier","read"], + ["text"," "], + ["string","\"Rating\""], + ["text",") :"], + ["identifier","junk"], + ["text","-"], + ["identifier","allowed"], + ["text"," "], + ["support.function","t"], + ["text",") "], + ["constant.numeric","0"], + ["text",")"] +],[ + "start", + ["text"," ("], + ["keyword.control","if"], + ["text"," "], + ["identifier","x"], + ["text"," ("], + ["support.function","format"], + ["text"," "], + ["support.function","t"], + ["text"," "], + ["string","\"yes\""], + ["text",") ("], + ["support.function","format"], + ["text"," "], + ["support.function","t"], + ["text"," "], + ["string","\"no\""], + ["text"," "], + ["constant.language","nil"], + ["text",") "], + ["comment",";and here comment"] +],[ + "start", + ["text"," ) "], + ["constant.numeric","0xFFLL"], + ["text"," "], + ["constant.numeric","-23ull"] +],[ + "start", + ["text"," "], + ["comment",";; second line comment"] +],[ + "start", + ["text"," '(+ "], + ["constant.numeric","1"], + ["text"," "], + ["constant.numeric","2"], + ["text",")"] +],[ + "start", + ["text"," ("], + ["identifier","defvar"], + ["text"," "], + ["punctuation.definition.variable.lisp","*"], + ["variable.other.global.lisp","lines"], + ["punctuation.definition.variable.lisp","*"], + ["text",") "], + ["comment","; list of all lines"] +],[ + "start", + ["text"," ("], + ["identifier","position"], + ["text","-"], + ["keyword.control","if"], + ["text","-"], + ["identifier","not"], + ["text"," "], + ["punctuation.definition.constant.character.lisp","#"], + ["constant.character.lisp","'sys::whitespacep"], + ["text"," "], + ["identifier","line"], + ["text"," :"], + ["identifier","start"], + ["text"," "], + ["identifier","beg"], + ["text","))"] +],[ + "start", + ["text"," ("], + ["support.function","quote"], + ["text"," ("], + ["identifier","privet"], + ["text"," "], + ["constant.numeric","1"], + ["text"," "], + ["constant.numeric","2"], + ["text"," "], + ["constant.numeric","3"], + ["text","))"] +],[ + "start", + ["text"," '("], + ["identifier","hello"], + ["text"," "], + ["identifier","world"], + ["text",")"] +],[ + "start", + ["text"," (* "], + ["constant.numeric","5"], + ["text"," "], + ["constant.numeric","7"], + ["text",")"] +],[ + "start", + ["text"," ("], + ["constant.numeric","1"], + ["text"," "], + ["constant.numeric","2"], + ["text"," "], + ["constant.numeric","34"], + ["text"," "], + ["constant.numeric","5"], + ["text",")"] +],[ + "start", + ["text"," (:"], + ["identifier","use"], + ["text"," "], + ["string","\"aaaa\""], + ["text",")"] +],[ + "start", + ["text"," ("], + ["keyword.control","let"], + ["text"," (("], + ["identifier","x"], + ["text"," "], + ["constant.numeric","10"], + ["text",") ("], + ["identifier","y"], + ["text"," "], + ["constant.numeric","20"], + ["text","))"] +],[ + "start", + ["text"," ("], + ["identifier","print"], + ["text"," (+ "], + ["identifier","x"], + ["text"," "], + ["identifier","y"], + ["text","))"] +],[ + "start", + ["text"," ) "], + ["support.function","LAmbDa"] +],[ + "start" +],[ + "start", + ["text"," "], + ["string","\"asdad"], + ["constant.character.escape.lisp","\\0"], + ["string","eqweqe\""] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_livescript.json b/node_modules/ace/lib/ace/mode/_test/tokens_livescript.json new file mode 100644 index 00000000..c2bd83df --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_livescript.json @@ -0,0 +1,6 @@ +[[ + "start", + ["comment","# comment"] +],[ + "start" +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_logiql.json b/node_modules/ace/lib/ace/mode/_test/tokens_logiql.json new file mode 100644 index 00000000..5f7eda49 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_logiql.json @@ -0,0 +1,190 @@ +[[ + "start", + ["comment.single","// ancestors"] +],[ + "start", + ["entity.name","parentof"], + ["text","("], + ["string","\"douglas\""], + ["keyword.other",","], + ["text"," "], + ["string","\"john\""], + ["text",")"], + ["keyword.end","."] +],[ + "start", + ["entity.name","parentof"], + ["text","("], + ["string","\"john\""], + ["keyword.other",","], + ["text"," "], + ["string","\"bob\""], + ["text",")"], + ["keyword.end","."] +],[ + "start", + ["entity.name","parentof"], + ["text","("], + ["string","\"bob\""], + ["keyword.other",","], + ["text"," "], + ["string","\"ebbon\""], + ["text",")"], + ["keyword.end","."] +],[ + "start" +],[ + "start", + ["entity.name","parentof"], + ["text","("], + ["string","\"douglas\""], + ["keyword.other",","], + ["text"," "], + ["string","\"jane\""], + ["text",")"], + ["keyword.end","."] +],[ + "start", + ["entity.name","parentof"], + ["text","("], + ["string","\"jane\""], + ["keyword.other",","], + ["text"," "], + ["string","\"jan\""], + ["text",")"], + ["keyword.end","."] +],[ + "start" +],[ + "start", + ["entity.name","ancestorof"], + ["text","("], + ["variable.parameter","A"], + ["keyword.other",","], + ["text"," "], + ["variable.parameter","B"], + ["text",") "], + ["keyword.start","<-"], + ["text"," "], + ["entity.name","parentof"], + ["text","("], + ["variable.parameter","A"], + ["keyword.other",","], + ["text"," "], + ["variable.parameter","B"], + ["text",")"], + ["keyword.end","."] +],[ + "start", + ["entity.name","ancestorof"], + ["text","("], + ["variable.parameter","A"], + ["keyword.other",","], + ["text"," "], + ["variable.parameter","C"], + ["text",") "], + ["keyword.start","<-"], + ["text"," "], + ["entity.name","ancestorof"], + ["text","("], + ["variable.parameter","A"], + ["keyword.other",","], + ["text"," "], + ["variable.parameter","B"], + ["text",")"], + ["keyword.other",","], + ["text"," "], + ["entity.name","parentof"], + ["text","("], + ["variable.parameter","B"], + ["keyword.other",","], + ["variable.parameter","C"], + ["text",")"], + ["keyword.end","."] +],[ + "start" +],[ + "start", + ["entity.name","grandparentof"], + ["text","("], + ["variable.parameter","A"], + ["keyword.other",","], + ["text"," "], + ["variable.parameter","B"], + ["text",") "], + ["keyword.start","<-"], + ["text"," "], + ["entity.name","parentof"], + ["text","("], + ["variable.parameter","A"], + ["keyword.other",","], + ["text"," "], + ["variable.parameter","C"], + ["text",")"], + ["keyword.other",","], + ["text"," "], + ["entity.name","parentof"], + ["text","("], + ["variable.parameter","C"], + ["keyword.other",","], + ["text"," "], + ["variable.parameter","B"], + ["text",")"], + ["keyword.end","."] +],[ + "start" +],[ + "start", + ["entity.name","cousins"], + ["text","("], + ["variable.parameter","A"], + ["keyword.other",","], + ["variable.parameter","B"], + ["text",") "], + ["keyword.start","<-"], + ["text"," "], + ["entity.name","grandparentof"], + ["text","("], + ["variable.parameter","C"], + ["keyword.other",","], + ["variable.parameter","A"], + ["text",")"], + ["keyword.other",","], + ["text"," "], + ["entity.name","grandparentof"], + ["text","("], + ["variable.parameter","C"], + ["keyword.other",","], + ["variable.parameter","B"], + ["text",")"], + ["keyword.end","."] +],[ + "start" +],[ + "start", + ["entity.name","parentof"], + ["text","["], + ["entity.name.type.logicblox","`arg"], + ["text","]("], + ["variable.parameter","A"], + ["keyword.other",","], + ["text"," "], + ["variable.parameter","B"], + ["text",") "], + ["keyword.start","->"], + ["text"," "], + ["entity.name","int"], + ["text","["], + ["constant.numeric","32"], + ["text","]("], + ["variable.parameter","A"], + ["text",")"], + ["keyword.other",","], + ["text"," "], + ["keyword.other","!"], + ["entity.name","string"], + ["text","("], + ["variable.parameter","B"], + ["text",")"], + ["keyword.end","."] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_lsl.json b/node_modules/ace/lib/ace/mode/_test/tokens_lsl.json new file mode 100644 index 00000000..2248a607 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_lsl.json @@ -0,0 +1,503 @@ +[[ + "comment", + ["comment.block.begin.lsl","/*"] +],[ + "comment", + ["comment.block.lsl"," Testing syntax highlighting"] +],[ + "comment", + ["comment.block.lsl"," of Ace Editor"] +],[ + "comment", + ["comment.block.lsl"," for the Linden Scripting Language"] +],[ + "start", + ["comment.block.end.lsl","*/"] +],[ + "start" +],[ + "start", + ["storage.type.lsl","integer"], + ["text.lsl"," "], + ["identifier","someIntNormal"], + ["text.lsl"," "], + ["keyword.operator.lsl","="], + ["text.lsl"," "], + ["constant.numeric.lsl","3672"], + ["punctuation.operator.lsl",";"] +],[ + "start", + ["storage.type.lsl","integer"], + ["text.lsl"," "], + ["identifier","someIntHex"], + ["text.lsl"," "], + ["keyword.operator.lsl","="], + ["text.lsl"," "], + ["constant.numeric.lsl","0x00000000"], + ["punctuation.operator.lsl",";"] +],[ + "start", + ["storage.type.lsl","integer"], + ["text.lsl"," "], + ["identifier","someIntMath"], + ["text.lsl"," "], + ["keyword.operator.lsl","="], + ["text.lsl"," "], + ["constant.language.float.lsl","PI_BY_TWO"], + ["punctuation.operator.lsl",";"] +],[ + "start" +],[ + "start", + ["storage.type.lsl","integer"], + ["text.lsl"," "], + ["invalid.illegal.lsl","event"], + ["text.lsl"," "], + ["keyword.operator.lsl","="], + ["text.lsl"," "], + ["constant.numeric.lsl","5673"], + ["punctuation.operator.lsl",";"], + ["text.lsl"," "], + ["comment.line.double-slash.lsl","// invalid.illegal"] +],[ + "start" +],[ + "start", + ["storage.type.lsl","key"], + ["text.lsl"," "], + ["identifier","someKeyTexture"], + ["text.lsl"," "], + ["keyword.operator.lsl","="], + ["text.lsl"," "], + ["constant.language.string.lsl","TEXTURE_DEFAULT"], + ["punctuation.operator.lsl",";"] +],[ + "start", + ["storage.type.lsl","string"], + ["text.lsl"," "], + ["identifier","someStringSpecial"], + ["text.lsl"," "], + ["keyword.operator.lsl","="], + ["text.lsl"," "], + ["constant.language.string.lsl","EOF"], + ["punctuation.operator.lsl",";"] +],[ + "start" +],[ + "start", + ["identifier","some_user_defined_function_without_return_type"], + ["paren.lparen.lsl","("], + ["storage.type.lsl","string"], + ["text.lsl"," "], + ["identifier","inputAsString"], + ["paren.rparen.lsl",")"] +],[ + "start", + ["paren.lparen.lsl","{"] +],[ + "start", + ["text.lsl"," "], + ["support.function.lsl","llSay"], + ["paren.lparen.lsl","("], + ["constant.language.integer.lsl","PUBLIC_CHANNEL"], + ["punctuation.operator.lsl",","], + ["text.lsl"," "], + ["identifier","inputAsString"], + ["paren.rparen.lsl",")"], + ["punctuation.operator.lsl",";"] +],[ + "start", + ["paren.rparen.lsl","}"] +],[ + "start" +],[ + "start", + ["storage.type.lsl","string"], + ["text.lsl"," "], + ["identifier","user_defined_function_returning_a_string"], + ["paren.lparen.lsl","("], + ["storage.type.lsl","key"], + ["text.lsl"," "], + ["identifier","inputAsKey"], + ["paren.rparen.lsl",")"] +],[ + "start", + ["paren.lparen.lsl","{"] +],[ + "start", + ["text.lsl"," "], + ["keyword.control.lsl","return"], + ["text.lsl"," "], + ["paren.lparen.lsl","("], + ["storage.type.lsl","string"], + ["paren.rparen.lsl",")"], + ["identifier","inputAsKey"], + ["punctuation.operator.lsl",";"] +],[ + "start", + ["paren.rparen.lsl","}"] +],[ + "start" +],[ + "start", + ["entity.name.state.lsl","default"] +],[ + "start", + ["paren.lparen.lsl","{"] +],[ + "start", + ["text.lsl"," "], + ["support.function.event.lsl","state_entry"], + ["paren.lparen.lsl","("], + ["paren.rparen.lsl",")"] +],[ + "start", + ["text.lsl"," "], + ["paren.lparen.lsl","{"] +],[ + "start", + ["text.lsl"," "], + ["storage.type.lsl","key"], + ["text.lsl"," "], + ["identifier","someKey"], + ["text.lsl"," "], + ["keyword.operator.lsl","="], + ["text.lsl"," "], + ["constant.language.string.lsl","NULL_KEY"], + ["punctuation.operator.lsl",";"] +],[ + "start", + ["text.lsl"," "], + ["identifier","someKey"], + ["text.lsl"," "], + ["keyword.operator.lsl","="], + ["text.lsl"," "], + ["support.function.lsl","llGetOwner"], + ["paren.lparen.lsl","("], + ["paren.rparen.lsl",")"], + ["punctuation.operator.lsl",";"] +],[ + "start" +],[ + "start", + ["text.lsl"," "], + ["storage.type.lsl","string"], + ["text.lsl"," "], + ["identifier","someString"], + ["text.lsl"," "], + ["keyword.operator.lsl","="], + ["text.lsl"," "], + ["identifier","user_defined_function_returning_a_string"], + ["paren.lparen.lsl","("], + ["identifier","someKey"], + ["paren.rparen.lsl",")"], + ["punctuation.operator.lsl",";"] +],[ + "start" +],[ + "start", + ["text.lsl"," "], + ["identifier","some_user_defined_function_without_return_type"], + ["paren.lparen.lsl","("], + ["identifier","someString"], + ["paren.rparen.lsl",")"], + ["punctuation.operator.lsl",";"] +],[ + "start", + ["text.lsl"," "], + ["paren.rparen.lsl","}"] +],[ + "start" +],[ + "start", + ["text.lsl"," "], + ["support.function.event.lsl","touch_start"], + ["paren.lparen.lsl","("], + ["storage.type.lsl","integer"], + ["text.lsl"," "], + ["identifier","num_detected"], + ["paren.rparen.lsl",")"] +],[ + "start", + ["text.lsl"," "], + ["paren.lparen.lsl","{"] +],[ + "start", + ["text.lsl"," "], + ["storage.type.lsl","list"], + ["text.lsl"," "], + ["identifier","agentsInRegion"], + ["text.lsl"," "], + ["keyword.operator.lsl","="], + ["text.lsl"," "], + ["support.function.lsl","llGetAgentList"], + ["paren.lparen.lsl","("], + ["constant.language.integer.lsl","AGENT_LIST_REGION"], + ["punctuation.operator.lsl",","], + ["text.lsl"," "], + ["paren.lparen.lsl","["], + ["paren.rparen.lsl","])"], + ["punctuation.operator.lsl",";"] +],[ + "start", + ["text.lsl"," "], + ["storage.type.lsl","integer"], + ["text.lsl"," "], + ["identifier","numOfAgents"], + ["text.lsl"," "], + ["keyword.operator.lsl","="], + ["text.lsl"," "], + ["support.function.lsl","llGetListLength"], + ["paren.lparen.lsl","("], + ["identifier","agentsInRegion"], + ["paren.rparen.lsl",")"], + ["punctuation.operator.lsl",";"] +],[ + "start" +],[ + "start", + ["text.lsl"," "], + ["storage.type.lsl","integer"], + ["text.lsl"," "], + ["identifier","index"], + ["punctuation.operator.lsl",";"], + ["text.lsl"," "], + ["comment.line.double-slash.lsl","// defaults to 0"] +],[ + "start", + ["text.lsl"," "], + ["keyword.control.lsl","for"], + ["text.lsl"," "], + ["paren.lparen.lsl","("], + ["punctuation.operator.lsl",";"], + ["text.lsl"," "], + ["identifier","index"], + ["text.lsl"," "], + ["keyword.operator.lsl","<="], + ["text.lsl"," "], + ["identifier","numOfAgents"], + ["text.lsl"," "], + ["keyword.operator.lsl","-"], + ["text.lsl"," "], + ["constant.numeric.lsl","1"], + ["punctuation.operator.lsl",";"], + ["text.lsl"," "], + ["identifier","index"], + ["keyword.operator.lsl","++"], + ["paren.rparen.lsl",")"], + ["text.lsl"," "], + ["comment.line.double-slash.lsl","// for each agent in region"] +],[ + "start", + ["text.lsl"," "], + ["paren.lparen.lsl","{"] +],[ + "start", + ["text.lsl"," "], + ["support.function.lsl","llRegionSayTo"], + ["paren.lparen.lsl","("], + ["support.function.lsl","llList2Key"], + ["paren.lparen.lsl","("], + ["identifier","agentsInRegion"], + ["punctuation.operator.lsl",","], + ["text.lsl"," "], + ["identifier","index"], + ["paren.rparen.lsl",")"], + ["punctuation.operator.lsl",","], + ["text.lsl"," "], + ["constant.language.integer.lsl","PUBLIC_CHANNEL"], + ["punctuation.operator.lsl",","], + ["text.lsl"," "], + ["string.quoted.double.lsl.start","\""], + ["string.quoted.double.lsl","Hello, Avatar!"], + ["string.quoted.double.lsl.end","\""], + ["paren.rparen.lsl",")"], + ["punctuation.operator.lsl",";"] +],[ + "start", + ["text.lsl"," "], + ["paren.rparen.lsl","}"] +],[ + "start", + ["text.lsl"," "], + ["paren.rparen.lsl","}"] +],[ + "start" +],[ + "start", + ["text.lsl"," "], + ["support.function.event.lsl","touch_end"], + ["paren.lparen.lsl","("], + ["storage.type.lsl","integer"], + ["text.lsl"," "], + ["identifier","num_detected"], + ["paren.rparen.lsl",")"] +],[ + "start", + ["text.lsl"," "], + ["paren.lparen.lsl","{"] +],[ + "start", + ["text.lsl"," "], + ["identifier","someIntNormal"], + ["text.lsl"," "], + ["keyword.operator.lsl","="], + ["text.lsl"," "], + ["constant.numeric.lsl","3672"], + ["punctuation.operator.lsl",";"] +],[ + "start", + ["text.lsl"," "], + ["identifier","someIntHex"], + ["text.lsl"," "], + ["keyword.operator.lsl","="], + ["text.lsl"," "], + ["constant.numeric.lsl","0x00000000"], + ["punctuation.operator.lsl",";"] +],[ + "start", + ["text.lsl"," "], + ["identifier","someIntMath"], + ["text.lsl"," "], + ["keyword.operator.lsl","="], + ["text.lsl"," "], + ["constant.language.float.lsl","PI_BY_TWO"], + ["punctuation.operator.lsl",";"] +],[ + "start" +],[ + "start", + ["text.lsl"," "], + ["invalid.illegal.lsl","event"], + ["text.lsl"," "], + ["keyword.operator.lsl","="], + ["text.lsl"," "], + ["constant.numeric.lsl","5673"], + ["punctuation.operator.lsl",";"], + ["text.lsl"," "], + ["comment.line.double-slash.lsl","// invalid.illegal"] +],[ + "start" +],[ + "start", + ["text.lsl"," "], + ["identifier","someKeyTexture"], + ["text.lsl"," "], + ["keyword.operator.lsl","="], + ["text.lsl"," "], + ["constant.language.string.lsl","TEXTURE_DEFAULT"], + ["punctuation.operator.lsl",";"] +],[ + "start", + ["text.lsl"," "], + ["identifier","someStringSpecial"], + ["text.lsl"," "], + ["keyword.operator.lsl","="], + ["text.lsl"," "], + ["constant.language.string.lsl","EOF"], + ["punctuation.operator.lsl",";"] +],[ + "start" +],[ + "start", + ["text.lsl"," "], + ["reserved.godmode.lsl","llSetInventoryPermMask"], + ["paren.lparen.lsl","("], + ["string.quoted.double.lsl.start","\""], + ["string.quoted.double.lsl","some item"], + ["string.quoted.double.lsl.end","\""], + ["punctuation.operator.lsl",","], + ["text.lsl"," "], + ["constant.language.integer.lsl","MASK_NEXT"], + ["punctuation.operator.lsl",","], + ["text.lsl"," "], + ["constant.language.integer.lsl","PERM_ALL"], + ["paren.rparen.lsl",")"], + ["punctuation.operator.lsl",";"], + ["text.lsl"," "], + ["comment.line.double-slash.lsl","// reserved.godmode"] +],[ + "start" +],[ + "start", + ["text.lsl"," "], + ["support.function.lsl","llWhisper"], + ["paren.lparen.lsl","("], + ["constant.language.integer.lsl","PUBLIC_CHANNEL"], + ["punctuation.operator.lsl",","], + ["text.lsl"," "], + ["string.quoted.double.lsl.start","\""], + ["string.quoted.double.lsl","Leaving "], + ["constant.character.escape.lsl","\\\""], + ["string.quoted.double.lsl","default"], + ["constant.character.escape.lsl","\\\""], + ["string.quoted.double.lsl"," now..."], + ["string.quoted.double.lsl.end","\""], + ["paren.rparen.lsl",")"], + ["punctuation.operator.lsl",";"] +],[ + "start", + ["text.lsl"," "], + ["entity.name.state.lsl","state other"], + ["punctuation.operator.lsl",";"] +],[ + "start", + ["text.lsl"," "], + ["paren.rparen.lsl","}"] +],[ + "start", + ["paren.rparen.lsl","}"] +],[ + "start" +],[ + "start", + ["entity.name.state.lsl","state other"] +],[ + "start", + ["paren.lparen.lsl","{"] +],[ + "start", + ["text.lsl"," "], + ["support.function.event.lsl","state_entry"], + ["paren.lparen.lsl","("], + ["paren.rparen.lsl",")"] +],[ + "start", + ["text.lsl"," "], + ["paren.lparen.lsl","{"] +],[ + "start", + ["text.lsl"," "], + ["support.function.lsl","llWhisper"], + ["paren.lparen.lsl","("], + ["constant.language.integer.lsl","PUBLIC_CHANNEL"], + ["punctuation.operator.lsl",","], + ["text.lsl"," "], + ["string.quoted.double.lsl.start","\""], + ["string.quoted.double.lsl","Entered "], + ["constant.character.escape.lsl","\\\""], + ["string.quoted.double.lsl","state other"], + ["constant.character.escape.lsl","\\\""], + ["string.quoted.double.lsl",", returning to "], + ["constant.character.escape.lsl","\\\""], + ["string.quoted.double.lsl","default"], + ["constant.character.escape.lsl","\\\""], + ["string.quoted.double.lsl"," again..."], + ["string.quoted.double.lsl.end","\""], + ["paren.rparen.lsl",")"], + ["punctuation.operator.lsl",";"] +],[ + "start", + ["text.lsl"," "], + ["entity.name.state.lsl","state default"], + ["punctuation.operator.lsl",";"] +],[ + "start", + ["text.lsl"," "], + ["paren.rparen.lsl","}"] +],[ + "start", + ["paren.rparen.lsl","}"] +],[ + "start" +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_lua.json b/node_modules/ace/lib/ace/mode/_test/tokens_lua.json new file mode 100644 index 00000000..b60c7cb1 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_lua.json @@ -0,0 +1,348 @@ +[[ + ["bracketedComment",2,"start"], + ["comment","--[[--"] +],[ + ["bracketedComment",2,"start"], + ["comment","num_args takes in 5.1 byte code and extracts the number of arguments"] +],[ + ["bracketedComment",2,"start"], + ["comment","from its function header."] +],[ + "start", + ["comment","--]]--"] +],[ + "start" +],[ + "start", + ["keyword","function"], + ["text"," "], + ["identifier","int"], + ["paren.lparen","("], + ["identifier","t"], + ["paren.rparen",")"] +],[ + "start", + ["text","\t"], + ["keyword","return"], + ["text"," "], + ["identifier","t"], + ["keyword.operator",":"], + ["support.function","byte"], + ["paren.lparen","("], + ["constant.numeric","1"], + ["paren.rparen",")"], + ["keyword.operator","+"], + ["identifier","t"], + ["keyword.operator",":"], + ["support.function","byte"], + ["paren.lparen","("], + ["constant.numeric","2"], + ["paren.rparen",")"], + ["keyword.operator","*"], + ["constant.numeric","0x100"], + ["keyword.operator","+"], + ["identifier","t"], + ["keyword.operator",":"], + ["support.function","byte"], + ["paren.lparen","("], + ["constant.numeric","3"], + ["paren.rparen",")"], + ["keyword.operator","*"], + ["constant.numeric","0x10000"], + ["keyword.operator","+"], + ["identifier","t"], + ["keyword.operator",":"], + ["support.function","byte"], + ["paren.lparen","("], + ["constant.numeric","4"], + ["paren.rparen",")"], + ["keyword.operator","*"], + ["constant.numeric","0x1000000"] +],[ + "start", + ["keyword","end"] +],[ + "start" +],[ + "start", + ["keyword","function"], + ["text"," "], + ["identifier","num_args"], + ["paren.lparen","("], + ["identifier","func"], + ["paren.rparen",")"] +],[ + "start", + ["text","\t"], + ["keyword","local"], + ["text"," "], + ["support.function","dump"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["constant.library","string"], + ["text","."], + ["support.function","dump"], + ["paren.lparen","("], + ["identifier","func"], + ["paren.rparen",")"] +],[ + "start", + ["text","\t"], + ["keyword","local"], + ["text"," "], + ["identifier","offset"], + ["text",", "], + ["identifier","cursor"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["identifier","int"], + ["paren.lparen","("], + ["support.function","dump"], + ["keyword.operator",":"], + ["support.function","sub"], + ["paren.lparen","("], + ["constant.numeric","13"], + ["paren.rparen","))"], + ["text",", "], + ["identifier","offset"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["constant.numeric","26"] +],[ + "start", + ["text","\t"], + ["comment","--Get the params and var flag (whether there's a ... in the param)"] +],[ + "start", + ["text","\t"], + ["keyword","return"], + ["text"," "], + ["support.function","dump"], + ["keyword.operator",":"], + ["support.function","sub"], + ["paren.lparen","("], + ["identifier","cursor"], + ["paren.rparen",")"], + ["keyword.operator",":"], + ["support.function","byte"], + ["paren.lparen","("], + ["paren.rparen",")"], + ["text",", "], + ["support.function","dump"], + ["keyword.operator",":"], + ["support.function","sub"], + ["paren.lparen","("], + ["identifier","cursor"], + ["keyword.operator","+"], + ["constant.numeric","1"], + ["paren.rparen",")"], + ["keyword.operator",":"], + ["support.function","byte"], + ["paren.lparen","("], + ["paren.rparen",")"] +],[ + "start", + ["keyword","end"] +],[ + "start" +],[ + "start", + ["comment","-- Usage:"] +],[ + "start", + ["identifier","num_args"], + ["paren.lparen","("], + ["keyword","function"], + ["paren.lparen","("], + ["identifier","a"], + ["text",","], + ["identifier","b"], + ["text",","], + ["identifier","c"], + ["text",","], + ["identifier","d"], + ["text",", "], + ["keyword.operator","..."], + ["paren.rparen",")"], + ["text"," "], + ["keyword","end"], + ["paren.rparen",")"], + ["text"," "], + ["comment","-- return 4, 7"] +],[ + "start" +],[ + "start", + ["comment","-- Python styled string format operator"] +],[ + "start", + ["keyword","local"], + ["text"," "], + ["identifier","gm"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["constant.library","debug"], + ["text","."], + ["support.function","getmetatable"], + ["paren.lparen","("], + ["string","\"\""], + ["paren.rparen",")"] +],[ + "start" +],[ + "start", + ["identifier","gm"], + ["text","."], + ["support.function","__mod"], + ["keyword.operator","="], + ["keyword","function"], + ["paren.lparen","("], + ["variable.language","self"], + ["text",", "], + ["identifier","other"], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["keyword","if"], + ["text"," "], + ["support.function","type"], + ["paren.lparen","("], + ["identifier","other"], + ["paren.rparen",")"], + ["text"," "], + ["keyword.operator","~="], + ["text"," "], + ["string","\"table\""], + ["text"," "], + ["keyword","then"], + ["text"," "], + ["identifier","other"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["paren.lparen","{"], + ["identifier","other"], + ["paren.rparen","}"], + ["text"," "], + ["keyword","end"] +],[ + "start", + ["text"," "], + ["keyword","for"], + ["text"," "], + ["identifier","i"], + ["text",","], + ["identifier","v"], + ["text"," "], + ["keyword","in"], + ["text"," "], + ["support.function","ipairs"], + ["paren.lparen","("], + ["identifier","other"], + ["paren.rparen",")"], + ["text"," "], + ["keyword","do"], + ["text"," "], + ["identifier","other"], + ["paren.lparen","["], + ["identifier","i"], + ["paren.rparen","]"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["support.function","tostring"], + ["paren.lparen","("], + ["identifier","v"], + ["paren.rparen",")"], + ["text"," "], + ["keyword","end"] +],[ + "start", + ["text"," "], + ["keyword","return"], + ["text"," "], + ["variable.language","self"], + ["keyword.operator",":"], + ["support.function","format"], + ["paren.lparen","("], + ["support.function","unpack"], + ["paren.lparen","("], + ["identifier","other"], + ["paren.rparen","))"] +],[ + "start", + ["keyword","end"] +],[ + "start" +],[ + ["bracketedString",5,"start"], + ["support.function","print"], + ["paren.lparen","("], + ["comment","[===["] +],[ + ["bracketedString",5,"start"], + ["comment"," blah blah %s, (%d %d)"] +],[ + "start", + ["comment","]===]"], + ["keyword.operator","%"], + ["paren.lparen","{"], + ["string","\"blah\""], + ["text",", "], + ["identifier","num_args"], + ["paren.lparen","("], + ["identifier","int"], + ["paren.rparen",")})"] +],[ + "start" +],[ + ["bracketedComment",3,"start"], + ["comment","--[=[--"] +],[ + ["bracketedComment",3,"start"], + ["comment","table.maxn is deprecated, use # instead."] +],[ + "start", + ["comment","--]=]--"] +],[ + "start", + ["support.function","print"], + ["paren.lparen","("], + ["constant.library","table"], + ["text","."], + ["invalid.deprecated","maxn"], + ["paren.lparen","{"], + ["constant.numeric","1"], + ["text",","], + ["constant.numeric","2"], + ["text",","], + ["paren.lparen","["], + ["constant.numeric","4"], + ["paren.rparen","]"], + ["keyword.operator","="], + ["constant.numeric","4"], + ["text",","], + ["paren.lparen","["], + ["constant.numeric","8"], + ["paren.rparen","]"], + ["keyword.operator","="], + ["constant.numeric","8"], + ["paren.rparen",")"], + ["text"," "], + ["comment","-- outputs 8 instead of 2"] +],[ + "start" +],[ + "start", + ["support.function","print"], + ["paren.lparen","("], + ["constant.numeric","5"], + ["text"," "], + ["comment","--[[ blah ]]"], + ["paren.rparen",")"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_luapage.json b/node_modules/ace/lib/ace/mode/_test/tokens_luapage.json new file mode 100644 index 00000000..1fa765dd --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_luapage.json @@ -0,0 +1,633 @@ +[[ + "doctype", + ["text.xml",""], + ["xml-pe.doctype.xml",""] +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","html"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + ["lua-bracketedComment",2,"lua-start"], + ["keyword","<%"], + ["text"," "], + ["comment","--[[--"] +],[ + ["lua-bracketedComment",2,"lua-start"], + ["comment"," index.lp from the Kepler Project's LuaDoc HTML doclet."] +],[ + ["lua-bracketedComment",2,"lua-start"], + ["comment"," http://keplerproject.github.com/luadoc/"] +],[ + "start", + ["comment","--]]"], + ["text"," "], + ["keyword","%>"] +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","head"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","title"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text.xml","Reference"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","link"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","rel"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"stylesheet\""], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","href"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\""], + ["keyword","<%="], + ["identifier","luadoc"], + ["text","."], + ["identifier","doclet"], + ["text","."], + ["identifier","html"], + ["text","."], + ["identifier","link"], + ["paren.lparen","("], + ["string","\"luadoc.css\""], + ["paren.rparen",")"], + ["keyword","%>"], + ["string.attribute-value.xml","\""], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","type"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"text/css\""], + ["text.tag-whitespace.xml"," "], + ["meta.tag.punctuation.tag-close.xml","/>"] +],[ + "start", + ["text.xml","\t"], + ["comment.xml",""] +],[ + "start", + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start" +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","body"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","div"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","id"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"container\""], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start" +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","div"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","id"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"product\""], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml","\t"], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","div"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","id"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"product_logo\""], + ["meta.tag.punctuation.tag-close.xml",">"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml","\t"], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","div"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","id"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"product_name\""], + ["meta.tag.punctuation.tag-close.xml",">"], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","big"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","b"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["meta.tag.punctuation.end-tag-open.xml",""], + ["meta.tag.punctuation.end-tag-open.xml",""], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml","\t"], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","div"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","id"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"product_description\""], + ["meta.tag.punctuation.tag-close.xml",">"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["meta.tag.punctuation.end-tag-open.xml",""], + ["text.xml"," "], + ["comment.xml",""] +],[ + "start" +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","div"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","id"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"main\""], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start" +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","div"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","id"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"navigation\""], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["keyword","<%="], + ["identifier","luadoc"], + ["text","."], + ["identifier","doclet"], + ["text","."], + ["identifier","html"], + ["text","."], + ["identifier","include"], + ["paren.lparen","("], + ["string","\"menu.lp\""], + ["text",", "], + ["paren.lparen","{"], + ["text"," "], + ["identifier","doc"], + ["keyword.operator","="], + ["identifier","doc"], + ["text"," "], + ["paren.rparen","})"], + ["keyword","%>"] +],[ + "start" +],[ + "start", + ["meta.tag.punctuation.end-tag-open.xml",""], + ["text.xml"," "], + ["comment.xml",""] +],[ + "start" +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","div"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","id"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"content\""], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start" +],[ + "start" +],[ + "start", + ["keyword","<%if"], + ["text"," "], + ["keyword","not"], + ["text"," "], + ["identifier","options"], + ["text","."], + ["identifier","nomodules"], + ["text"," "], + ["keyword","and"], + ["text"," "], + ["keyword.operator","#"], + ["identifier","doc"], + ["text","."], + ["identifier","modules"], + ["text"," "], + ["keyword.operator",">"], + ["text"," "], + ["constant.numeric","0"], + ["text"," "], + ["keyword","then%>"] +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","h2"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text.xml","Modules"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.table.tag-name.xml","table"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","class"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"module_list\""], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["comment.xml",""] +],[ + "start", + ["keyword","<%for"], + ["text"," "], + ["identifier","_"], + ["text",", "], + ["identifier","modulename"], + ["text"," "], + ["keyword","in"], + ["text"," "], + ["support.function","ipairs"], + ["paren.lparen","("], + ["identifier","doc"], + ["text","."], + ["identifier","modules"], + ["paren.rparen",")"], + ["text"," "], + ["keyword","do%>"] +],[ + "start", + ["text.xml","\t"], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.table.tag-name.xml","tr"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml","\t\t"], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.table.tag-name.xml","td"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","class"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"name\""], + ["meta.tag.punctuation.tag-close.xml",">"], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.anchor.tag-name.xml","a"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","href"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\""], + ["keyword","<%="], + ["identifier","luadoc"], + ["text","."], + ["identifier","doclet"], + ["text","."], + ["identifier","html"], + ["text","."], + ["identifier","module_link"], + ["paren.lparen","("], + ["identifier","modulename"], + ["text",", "], + ["identifier","doc"], + ["paren.rparen",")"], + ["keyword","%>"], + ["string.attribute-value.xml","\""], + ["meta.tag.punctuation.tag-close.xml",">"], + ["keyword","<%="], + ["identifier","modulename"], + ["keyword","%>"], + ["meta.tag.punctuation.end-tag-open.xml",""], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml","\t\t"], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.table.tag-name.xml","td"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","class"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"summary\""], + ["meta.tag.punctuation.tag-close.xml",">"], + ["keyword","<%="], + ["identifier","doc"], + ["text","."], + ["identifier","modules"], + ["paren.lparen","["], + ["identifier","modulename"], + ["paren.rparen","]"], + ["text","."], + ["identifier","summary"], + ["keyword","%>"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml","\t"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["keyword","<%end%>"] +],[ + "start", + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["keyword","<%end%>"] +],[ + "start" +],[ + "start" +],[ + "start" +],[ + "start", + ["keyword","<%if"], + ["text"," "], + ["keyword","not"], + ["text"," "], + ["identifier","options"], + ["text","."], + ["identifier","nofiles"], + ["text"," "], + ["keyword","and"], + ["text"," "], + ["keyword.operator","#"], + ["identifier","doc"], + ["text","."], + ["identifier","files"], + ["text"," "], + ["keyword.operator",">"], + ["text"," "], + ["constant.numeric","0"], + ["text"," "], + ["keyword","then%>"] +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","h2"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text.xml","Files"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.table.tag-name.xml","table"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","class"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"file_list\""], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["comment.xml",""] +],[ + "start", + ["keyword","<%for"], + ["text"," "], + ["identifier","_"], + ["text",", "], + ["identifier","filepath"], + ["text"," "], + ["keyword","in"], + ["text"," "], + ["support.function","ipairs"], + ["paren.lparen","("], + ["identifier","doc"], + ["text","."], + ["identifier","files"], + ["paren.rparen",")"], + ["text"," "], + ["keyword","do%>"] +],[ + "start", + ["text.xml","\t"], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.table.tag-name.xml","tr"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml","\t\t"], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.table.tag-name.xml","td"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","class"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"name\""], + ["meta.tag.punctuation.tag-close.xml",">"], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.anchor.tag-name.xml","a"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","href"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\""], + ["keyword","<%="], + ["identifier","luadoc"], + ["text","."], + ["identifier","doclet"], + ["text","."], + ["identifier","html"], + ["text","."], + ["identifier","file_link"], + ["paren.lparen","("], + ["identifier","filepath"], + ["paren.rparen",")"], + ["keyword","%>"], + ["string.attribute-value.xml","\""], + ["meta.tag.punctuation.tag-close.xml",">"], + ["keyword","<%="], + ["identifier","filepath"], + ["keyword","%>"], + ["meta.tag.punctuation.end-tag-open.xml",""], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml","\t\t"], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.table.tag-name.xml","td"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","class"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"summary\""], + ["meta.tag.punctuation.tag-close.xml",">"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml","\t"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["keyword","<%end%>"] +],[ + "start", + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["keyword","<%end%>"] +],[ + "start" +],[ + "start", + ["meta.tag.punctuation.end-tag-open.xml",""], + ["text.xml"," "], + ["comment.xml",""] +],[ + "start" +],[ + "start", + ["meta.tag.punctuation.end-tag-open.xml",""], + ["text.xml"," "], + ["comment.xml",""] +],[ + "start" +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","div"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","id"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"about\""], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml","\t"], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","p"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.anchor.tag-name.xml","a"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","href"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"http://validator.w3.org/check?uri=referer\""], + ["meta.tag.punctuation.tag-close.xml",">"], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.image.tag-name.xml","img"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","src"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"http://www.w3.org/Icons/valid-xhtml10\""], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","alt"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"Valid XHTML 1.0!\""], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","height"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"31\""], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","width"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"88\""], + ["text.tag-whitespace.xml"," "], + ["meta.tag.punctuation.tag-close.xml","/>"], + ["meta.tag.punctuation.end-tag-open.xml",""], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["meta.tag.punctuation.end-tag-open.xml",""], + ["text.xml"," "], + ["comment.xml",""] +],[ + "start" +],[ + "start", + ["meta.tag.punctuation.end-tag-open.xml",""], + ["text.xml"," "], + ["comment.xml",""], + ["text.xml","\t"] +],[ + "start", + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start" +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_lucene.json b/node_modules/ace/lib/ace/mode/_test/tokens_lucene.json new file mode 100644 index 00000000..1f6d2985 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_lucene.json @@ -0,0 +1,92 @@ +[[ + "start", + ["keyword","test:"], + ["text"," recognises "], + ["keyword.operator","AND"], + ["text"," as keyword"] +],[ + "start", + ["keyword","test:"], + ["text"," recognises "], + ["keyword.operator","OR"], + ["text"," as keyword"] +],[ + "start", + ["keyword","test:"], + ["text"," recognises "], + ["keyword.operator","NOT"], + ["text"," as keyword"] +],[ + "start", + ["keyword","test:"], + ["text"," recognises "], + ["string","\"hello this is dog\""], + ["text"," as string"] +],[ + "start", + ["keyword","test:"], + ["text"," recognises "], + ["constant.character.negation","-"], + ["string","\"hello this is dog\""], + ["text"," as negation with string"] +],[ + "start", + ["keyword","test:"], + ["text"," recognises "], + ["constant.character.proximity","~100"], + ["text"," as text with proximity"] +],[ + "start", + ["keyword","test:"], + ["text"," recognises "], + ["string","\"hello this is dog\""], + ["constant.character.proximity","~100"], + ["text"," as string with proximity"] +],[ + "start", + ["keyword","test:"], + ["text"," recognises "], + ["keyword","raw:"], + ["string","\"hello this is dog\""], + ["text"," as keyword"] +],[ + "start", + ["keyword","test:"], + ["text"," recognises "], + ["keyword","raw:"], + ["text","foo as\"keyword'"] +],[ + "start", + ["keyword","test:"], + ["text"," recognises "], + ["string","\"(\""], + ["text"," as opening parenthesis"] +],[ + "start", + ["keyword","test:"], + ["text"," recognises "], + ["string","\")\""], + ["text"," as closing parenthesis"] +],[ + "start", + ["keyword","test:"], + ["text"," recognises foo"], + ["constant.character.asterisk","*"], + ["text"," as text with asterisk"] +],[ + "start", + ["keyword","test:"], + ["text"," recognises foo"], + ["constant.character.interro","?"], + ["text"," as text with interro"] +],[ + "start", + ["keyword","test:"], + ["text"," recognises single word as text"] +],[ + "start", + ["text"," foo"] +],[ + "start", + ["text"," "] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_markdown.json b/node_modules/ace/lib/ace/mode/_test/tokens_markdown.json new file mode 100644 index 00000000..29e878b2 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_markdown.json @@ -0,0 +1,114 @@ +[[ + "start", + ["text.xml","test: header 1 "] +],[ + "start", + ["markup.heading.1","#"], + ["heading","f"] +],[ + "start", + ["text.xml","test: header 2"] +],[ + "start", + ["markup.heading.2","##"], + ["heading"," foo"] +],[ + "start", + ["text.xml","test: header ends with ' #'"] +],[ + "start", + ["markup.heading.1","#"], + ["heading"," # # "] +],[ + "start", + ["text.xml","test: header ends with '#'"] +],[ + "start", + ["markup.heading.1","#"], + ["heading","foo# "] +],[ + "start", + ["text.xml","test: 6+ #s is not a valid header"] +],[ + "start", + ["text.xml","####### foo"] +],[ + "start", + ["text.xml","test: # followed be only space is not a valid header"] +],[ + "start", + ["text.xml","# "] +],[ + "start", + ["text.xml","test: only space between #s is not a valid header"] +],[ + "start", + ["text.xml","# #"] +],[ + "allowBlock" +],[ + "start", + ["markup.heading.1","#"], + ["heading"," test links "], + ["text","["], + ["string","Cloud9 IDE"], + ["text","]("], + ["markup.underline","http://www.c9.io/"], + ["text",")"], + ["heading"," #"] +],[ + "listblock", + ["markup.list","* "], + ["text","["], + ["string","demo"], + ["text","]("], + ["markup.underline","http://ajaxorg.github.com/ace/"], + ["text",")"], + ["list"," "], + ["text","["], + ["string","+"], + ["text","]("], + ["markup.underline","escape(\\) "], + ["text",")"], + ["list"," "], + ["text","["], + ["string","+"], + ["text","]("], + ["markup.underline","a"], + ["string"," \"title\""], + ["text",")"], + ["list"," "], + ["text","["], + ["string","+"], + ["text","]("], + ["markup.underline","a"], + ["string"," \"space\" "], + ["text",")"] +],[ + "listblock", + ["markup.list","* "], + ["list","usually "], + ["string.emphasis","*work*"], + ["list"," fine ("], + ["string.emphasis","_em_"], + ["list",")"] +],[ + "listblock", + ["list","in lists"] +],[ + "start" +],[ + "start", + ["text.xml","in plain text "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","b"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text.xml","http://ace.ajaxorg.com"], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","b"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "allowBlock" +],[ + "start" +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_mask.json b/node_modules/ace/lib/ace/mode/_test/tokens_mask.json new file mode 100644 index 00000000..5f2b9762 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_mask.json @@ -0,0 +1,302 @@ +[[ + "start", + ["comment","/* Mask Syntax Demo */"] +],[ + "start" +],[ + "start", + ["keyword.support.constant.language","div"], + ["text"," "], + ["paren.lparen",">"], + ["text"," "], + ["string.start","'"], + ["string"," Test "], + ["paren.lparen.markup.italic","~["], + ["identifier","name"], + ["paren.rparen.markup.italic","]"], + ["string.end","'"], + ["paren.rparen",";"] +],[ + "start" +],[ + "start", + ["keyword","define"], + ["text"," :"], + ["support.variable.class","userProfile"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text","\t"], + ["keyword.support.constant.language","header"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text","\t\t"], + ["keyword.support.constant.language","h4"], + ["text"," "], + ["paren.lparen",">"], + ["text"," "], + ["support.function.markup.bold","@title"], + ["paren.lparen",";"] +],[ + "start", + ["text","\t\t"], + ["keyword.support.constant.language","button"], + ["support.variable.class",".close"], + ["paren.lparen",";"] +],[ + "start", + ["text","\t"], + ["paren.rparen","}"] +],[ + "start", + ["paren.rparen","}"] +],[ + "start" +],[ + "start", + ["support.function.markup.bold",":userProfile"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text","\t"], + ["support.function.markup.bold","@title"], + ["text"," "], + ["paren.lparen",">"], + ["text"," "], + ["string.start","'"], + ["string"," Hello "], + ["paren.lparen.markup.italic","~["], + ["keyword.control.markup.italic",":"], + ["text"," "], + ["identifier","username"], + ["punctuation.operator","."], + ["support.function","toUpperCase"], + ["paren.lparen","("], + ["paren.rparen",")"], + ["paren.rparen.markup.italic","]"], + ["string.end","'"] +],[ + "start", + ["paren.rparen","}"] +],[ + "start" +],[ + ["paren.lparen52","constant.language40"], + ["constant.language","style"], + ["text"," "], + ["paren.lparen","{"] +],[ + ["css-block-ruleset","paren.lparen52","paren.lparen52","constant.language40"], + ["text"," "], + ["constant","html"], + ["text",", "], + ["constant","body"], + ["text"," "], + ["paren.lparen","{"] +],[ + ["css-block-ruleset","paren.lparen52","paren.lparen52","constant.language40"], + ["text"," "], + ["support.type","background"], + ["text",": "], + ["support.function","url("], + ["string","'name.png'"], + ["support.function",")"], + ["text"," "], + ["constant.numeric","0"], + ["text"," "], + ["constant.numeric","0"], + ["text"," "], + ["support.constant","no-repeat"], + ["text",";"] +],[ + ["paren.lparen52","constant.language40"], + ["text"," "], + ["paren.rparen","}"] +],[ + ["#tmp","css-block-end","paren.lparen52","constant.language40"], + ["paren.rparen","}"] +],[ + ["#tmp","start","paren.lparen52","constant.language40"] +],[ + ["#tmp","start","paren.lparen52","constant.language40"], + ["keyword.support.constant.language","button"], + ["text"," "], + ["paren.lparen","{"] +],[ + ["paren.lparen39","constant.language27","constant.language27","start","paren.lparen52","constant.language40"], + ["text","\t"], + ["constant.language","event"], + ["text"," "], + ["support.variable.class","click"], + ["text"," "], + ["paren.lparen","("], + ["identifier","e"], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + ["#tmp","js-block-start","paren.lparen39","constant.language27","constant.language27","start","paren.lparen52","constant.language40"], + ["text","\t "], + ["variable.language","this"], + ["punctuation.operator","."], + ["identifier","textContent"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["string.quasi.start","`"], + ["string.quasi","name "], + ["paren.quasi.start","${"], + ["identifier","e"], + ["punctuation.operator","."], + ["identifier","clientX"], + ["paren.quasi.end","}"], + ["string.quasi"," !"], + ["string.quasi.end","`"], + ["punctuation.operator",";"] +],[ + ["#tmp","js-block-end","paren.lparen39","constant.language27","constant.language27","start","paren.lparen52","constant.language40"], + ["text","\t"], + ["paren.rparen","}"] +],[ + ["#tmp","start","paren.lparen39","constant.language27","constant.language27","start","paren.lparen52","constant.language40"], + ["paren.rparen","}"] +],[ + ["#tmp","start","paren.lparen39","constant.language27","constant.language27","start","paren.lparen52","constant.language40"] +],[ + ["paren.lparen13","constant.language","constant.language","start","paren.lparen39","constant.language27","constant.language27","start","paren.lparen52","constant.language40"], + ["constant.language","md"], + ["text"," "], + ["paren.lparen",">"], + ["text"," "], + ["paren.lparen","\"\"\""] +],[ + ["#tmp","md-multiline-allowBlock","paren.lparen13","constant.language","constant.language","start","paren.lparen39","constant.language27","constant.language27","start","paren.lparen52","constant.language40"] +],[ + ["#tmp","md-multiline-listblock","paren.lparen13","constant.language","constant.language","start","paren.lparen39","constant.language27","constant.language27","start","paren.lparen52","constant.language40"], + ["markup.list","- "], + ["list","div"] +],[ + ["#tmp","md-multiline-listblock","paren.lparen13","constant.language","constant.language","start","paren.lparen39","constant.language27","constant.language27","start","paren.lparen52","constant.language40"], + ["markup.list","- "], + ["list","span"] +],[ + ["#tmp","md-multiline-listblock","paren.lparen13","constant.language","constant.language","start","paren.lparen39","constant.language27","constant.language27","start","paren.lparen52","constant.language40"], + ["list"," "] +],[ + ["#tmp","md-multiline-listblock","paren.lparen13","constant.language","constant.language","start","paren.lparen39","constant.language27","constant.language27","start","paren.lparen52","constant.language40"], + ["list","Hello"] +],[ + ["#tmp","md-multiline-start","paren.lparen13","constant.language","constant.language","start","paren.lparen39","constant.language27","constant.language27","start","paren.lparen52","constant.language40"] +],[ + ["#tmp","md-multiline-start","paren.lparen13","constant.language","constant.language","start","paren.lparen39","constant.language27","constant.language27","start","paren.lparen52","constant.language40"], + ["text","["], + ["string","one"], + ["text","]("], + ["markup.underline","http://google.com"], + ["text",")"] +],[ + ["#tmp","md-multiline-allowBlock","paren.lparen13","constant.language","constant.language","start","paren.lparen39","constant.language27","constant.language27","start","paren.lparen52","constant.language40"] +],[ + ["#tmp","start","paren.lparen13","constant.language","constant.language","start","paren.lparen39","constant.language27","constant.language27","start","paren.lparen52","constant.language40"], + ["paren.rparen","\"\"\";"] +],[ + ["#tmp","start","paren.lparen13","constant.language","constant.language","start","paren.lparen39","constant.language27","constant.language27","start","paren.lparen52","constant.language40"] +],[ + ["#tmp","start","paren.lparen13","constant.language","constant.language","start","paren.lparen39","constant.language27","constant.language27","start","paren.lparen52","constant.language40"] +],[ + ["#tmp","start","paren.lparen13","constant.language","constant.language","start","paren.lparen39","constant.language27","constant.language27","start","paren.lparen52","constant.language40"], + ["keyword.support.constant.language","header"], + ["text"," "], + ["support.variable.class",".foo"], + ["text"," "], + ["paren.lparen",">"], + ["text"," "], + ["string.start","'"], + ["string","Heading"], + ["string.end","'"] +],[ + ["#tmp","start","paren.lparen13","constant.language","constant.language","start","paren.lparen39","constant.language27","constant.language27","start","paren.lparen52","constant.language40"] +],[ + ["string.start2","start","paren.lparen13","constant.language","constant.language","start","paren.lparen39","constant.language27","constant.language27","start","paren.lparen52","constant.language40"], + ["keyword.support.constant.language","button"], + ["text"," "], + ["support.variable.class",".baz"], + ["text"," "], + ["support.variable.class.markup.bold","x-signal"], + ["keyword.operator","="], + ["string.start","'"], + ["string","click: test"], + ["string.end","'"], + ["text"," "], + ["support.variable.class","disabled"], + ["text"," "], + ["paren.lparen",">"], + ["text"," "], + ["string.start","\""] +],[ + ["string.start2","start","paren.lparen13","constant.language","constant.language","start","paren.lparen39","constant.language27","constant.language27","start","paren.lparen52","constant.language40"], + ["string","\tHello,"] +],[ + ["string.start2","start","paren.lparen13","constant.language","constant.language","start","paren.lparen39","constant.language27","constant.language27","start","paren.lparen52","constant.language40"], + ["string","\tworld "] +],[ + ["string.start2","start","paren.lparen13","constant.language","constant.language","start","paren.lparen39","constant.language27","constant.language27","start","paren.lparen52","constant.language40"], + ["string","\t"], + ["string.escape","\\\""], + ["string","Buddy"], + ["string.escape","\\\""] +],[ + ["#tmp","start","paren.lparen13","constant.language","constant.language","start","paren.lparen39","constant.language27","constant.language27","start","paren.lparen52","constant.language40"], + ["string.end","\""] +],[ + ["#tmp","start","paren.lparen13","constant.language","constant.language","start","paren.lparen39","constant.language27","constant.language27","start","paren.lparen52","constant.language40"] +],[ + ["#tmp","js-statement-start","start","js-statement-no_regex","constant.language53","start","paren.lparen13","constant.language","constant.language","start","paren.lparen39","constant.language27","constant.language27","start","paren.lparen52","constant.language40"], + ["constant.language","var"], + ["text"," "], + ["identifier","a"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["paren","{"] +],[ + ["#tmp","js-statement-no_regex","start","js-statement-no_regex","constant.language53","start","paren.lparen13","constant.language","constant.language","start","paren.lparen39","constant.language27","constant.language27","start","paren.lparen52","constant.language40"], + ["text"," "], + ["identifier","name"], + ["punctuation.operator",":"], + ["text"," "], + ["string.quasi.start","`"], + ["string.quasi","name "], + ["paren.quasi.start","${"], + ["variable.language","window"], + ["punctuation.operator","."], + ["support.constant","innerWidth"], + ["paren.rparen","}"], + ["string.quasi.end","`"] +],[ + ["#tmp","start","paren.lparen13","constant.language","constant.language","start","paren.lparen39","constant.language27","constant.language27","start","paren.lparen52","constant.language40"], + ["paren.rparen","};"] +],[ + ["#tmp","start","paren.lparen13","constant.language","constant.language","start","paren.lparen39","constant.language27","constant.language27","start","paren.lparen52","constant.language40"] +],[ + ["#tmp","start","paren.lparen13","constant.language","constant.language","start","paren.lparen39","constant.language27","constant.language27","start","paren.lparen52","constant.language40"], + ["keyword.support.constant.language","span"], + ["text"," "], + ["support.variable.class",".foo"], + ["text"," "], + ["paren.lparen",">"], + ["text"," "], + ["string.start","\""], + ["paren.lparen.markup.italic","~["], + ["keyword.control.markup.italic","bind:"], + ["text"," "], + ["identifier","a"], + ["punctuation.operator","."], + ["identifier","name"], + ["paren.rparen.markup.italic","]"], + ["string.end","\""] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_matlab.json b/node_modules/ace/lib/ace/mode/_test/tokens_matlab.json new file mode 100644 index 00000000..6b4a8567 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_matlab.json @@ -0,0 +1,90 @@ +[[ + ["blockComment","noQstring"], + ["comment.start","%{"] +],[ + ["blockComment","blockComment","blockComment","noQstring"], + ["comment.start"," %{"] +],[ + ["blockComment","blockComment","blockComment","noQstring"], + ["comment"," Ace Matlab demo"] +],[ + ["blockComment","noQstring"], + ["comment.end"," %}"] +],[ + "noQstring", + ["comment.end","%}"] +],[ + "start" +],[ + "start", + ["keyword","classdef"], + ["text"," "], + ["identifier","hello"] +],[ + "start", + ["text"," "], + ["support.function","methods"] +],[ + "start", + ["text"," "], + ["keyword","function"], + ["text"," "], + ["identifier","greet"], + ["paren.lparen","("], + ["identifier","this"], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["support.function","disp"], + ["paren.lparen","("], + ["string","'Hello!'"], + ["paren.rparen",")"], + ["text"," "], + ["comment","% say hi"] +],[ + "start", + ["text"," "], + ["keyword","end"] +],[ + "start", + ["text"," "], + ["keyword","end"] +],[ + "start", + ["keyword","end"] +],[ + "noQstring" +],[ + "start", + ["comment","% transpose "] +],[ + "qqstring", + ["identifier","a"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["paren.lparen","["], + ["text"," "], + ["string","'x"], + ["constant.language.escape","''"], + ["string","y'"], + ["punctuation.operator",","], + ["text"," "], + ["string","\"x"], + ["constant.language.escape","\\n"], + ["string","\\"] +],[ + "start", + ["string"," y\""], + ["punctuation.operator",","], + ["text"," "], + ["constant.numeric","1"], + ["text","' "], + ["paren.rparen","]"], + ["text","' "], + ["keyword.operator","+"], + ["text"," "], + ["constant.numeric","2"], + ["text","'"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_mel.json b/node_modules/ace/lib/ace/mode/_test/tokens_mel.json new file mode 100644 index 00000000..a2d618a9 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_mel.json @@ -0,0 +1,257 @@ +[[ + "start", + ["comment.line.double-slash.mel","//"], + ["punctuation.definition.comment.mel"," animated duplicates, instances script"] +],[ + "start", + ["meta.function.mel","proc"], + ["keyword.other.mel"," "], + ["storage.type.mel","animatedDuplication"], + ["entity.name.function.mel"," ("], + ["punctuation.section.function.mel","("], + ["meta.function.mel","int $rangeStart, int $rangeEnd, int $numOfDuplicates, int $duplicateOrInstance"], + ["punctuation.section.function.mel",")"], + "proc animatedDuplication (int $rangeStart, int $rangeEnd, int $numOfDuplicates, int $duplicateOrInstance)" +],[ + "start", + ["text","{"] +],[ + "start", + ["text"," "], + ["storage.type.mel","int"], + ["text"," "], + ["variable.other.mel","$"], + ["punctuation.definition.variable.mel","range_start"], + ["text"," "], + ["keyword.operator.symbolic.mel","="], + ["text"," "], + ["variable.other.mel","$"], + ["punctuation.definition.variable.mel","rangeStart"], + ["text",";"] +],[ + "start", + ["text"," "], + ["storage.type.mel","int"], + ["text"," "], + ["variable.other.mel","$"], + ["punctuation.definition.variable.mel","range_end"], + ["text"," "], + ["keyword.operator.symbolic.mel","="], + ["text"," "], + ["variable.other.mel","$"], + ["punctuation.definition.variable.mel","rangeEnd"], + ["text",";"] +],[ + "start", + ["text"," "], + ["storage.type.mel","int"], + ["text"," "], + ["variable.other.mel","$"], + ["punctuation.definition.variable.mel","num_of_duplicates"], + ["text"," "], + ["keyword.operator.symbolic.mel","="], + ["text"," "], + ["variable.other.mel","$"], + ["punctuation.definition.variable.mel","numOfDuplicates"], + ["text",";"] +],[ + "start", + ["text"," "], + ["storage.type.mel","int"], + ["text"," "], + ["variable.other.mel","$"], + ["punctuation.definition.variable.mel","step_size"], + ["text"," "], + ["keyword.operator.symbolic.mel","="], + ["text"," ("], + ["variable.other.mel","$"], + ["punctuation.definition.variable.mel","range_end"], + ["text"," "], + ["keyword.operator.symbolic.mel","-"], + ["text"," "], + ["variable.other.mel","$"], + ["punctuation.definition.variable.mel","range_start"], + ["text",") "], + ["keyword.operator.symbolic.mel","/"], + ["text"," "], + ["variable.other.mel","$"], + ["punctuation.definition.variable.mel","num_of_duplicates"], + ["text",";"] +],[ + "start", + ["text"," "], + ["storage.type.mel","int"], + ["text"," "], + ["variable.other.mel","$"], + ["punctuation.definition.variable.mel","i"], + ["text"," "], + ["keyword.operator.symbolic.mel","="], + ["text"," "], + ["constant.numeric.mel","0"], + ["text",";"] +],[ + "start", + ["text"," "], + ["storage.type.mel","int"], + ["text"," "], + ["variable.other.mel","$"], + ["punctuation.definition.variable.mel","temp"], + ["text",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["support.function.mel","currentTime"], + ["text"," "], + ["variable.other.mel","$"], + ["punctuation.definition.variable.mel","range_start"], + ["text","; "], + ["comment.line.double-slash.mel","//"], + ["punctuation.definition.comment.mel"," set to range start"] +],[ + "start" +],[ + "start", + ["text"," "], + ["storage.type.mel","string"], + ["text"," "], + ["variable.other.mel","$"], + ["punctuation.definition.variable.mel","selectedObjects"], + ["text","[]; "], + ["comment.line.double-slash.mel","//"], + ["punctuation.definition.comment.mel"," to store selected objects"] +],[ + "start", + ["text"," "], + ["variable.other.mel","$"], + ["punctuation.definition.variable.mel","selectedObjects"], + ["text"," "], + ["keyword.operator.symbolic.mel","="], + ["text"," `"], + ["support.function.mel","ls"], + ["text"," "], + ["keyword.operator.symbolic.mel","-"], + ["text","sl`; "], + ["comment.line.double-slash.mel","//"], + ["punctuation.definition.comment.mel"," store selected objects"] +],[ + "start", + ["text"," "], + ["support.function.mel","select"], + ["text"," "], + ["variable.other.mel","$"], + ["punctuation.definition.variable.mel","selectedObjects"], + ["text",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword.control.mel","while"], + ["text"," ("], + ["variable.other.mel","$"], + ["punctuation.definition.variable.mel","i"], + ["text"," <"], + ["keyword.operator.symbolic.mel","="], + ["text"," "], + ["variable.other.mel","$"], + ["punctuation.definition.variable.mel","num_of_duplicates"], + ["text",")"] +],[ + "start", + ["text"," {"] +],[ + "start", + ["text"," "], + ["variable.other.mel","$"], + ["punctuation.definition.variable.mel","temp"], + ["text"," "], + ["keyword.operator.symbolic.mel","="], + ["text"," "], + ["variable.other.mel","$"], + ["punctuation.definition.variable.mel","range_start"], + ["text"," "], + ["keyword.operator.symbolic.mel","+"], + ["text"," ("], + ["variable.other.mel","$"], + ["punctuation.definition.variable.mel","step_size"], + ["text"," "], + ["keyword.operator.symbolic.mel","*"], + ["text"," "], + ["variable.other.mel","$"], + ["punctuation.definition.variable.mel","i"], + ["text",");"] +],[ + "start", + ["text"," "], + ["support.function.mel","currentTime"], + ["text"," ("], + ["variable.other.mel","$"], + ["punctuation.definition.variable.mel","temp"], + ["text",");"] +],[ + "start", + ["text"," "], + ["comment.line.double-slash.mel","//"], + ["punctuation.definition.comment.mel"," seleced the objects to duplicate or instance"] +],[ + "start", + ["text"," "], + ["support.function.mel","select"], + ["text"," "], + ["variable.other.mel","$"], + ["punctuation.definition.variable.mel","selectedObjects"], + ["text",";"] +],[ + "start", + ["text"," "], + ["keyword.control.mel","if"], + ["text","("], + ["variable.other.mel","$"], + ["punctuation.definition.variable.mel","duplicateOrInstance"], + ["text"," "], + ["keyword.operator.symbolic.mel","=="], + ["text"," "], + ["constant.numeric.mel","0"], + ["text",")"] +],[ + "start", + ["text"," {"] +],[ + "start", + ["text"," "], + ["support.function.mel","duplicate"], + ["text",";"] +],[ + "start", + ["text"," }"] +],[ + "start", + ["text"," "], + ["keyword.control.mel","else"] +],[ + "start", + ["text"," {"] +],[ + "start", + ["text"," "], + ["support.function.mel","instance"], + ["text",";"] +],[ + "start", + ["text"," }"] +],[ + "start", + ["text"," "], + ["variable.other.mel","$"], + ["punctuation.definition.variable.mel","i"], + ["keyword.operator.symbolic.mel","++"], + ["text",";"] +],[ + "start", + ["text"," }"] +],[ + "start", + ["text","}"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_mushcode.json b/node_modules/ace/lib/ace/mode/_test/tokens_mushcode.json new file mode 100644 index 00000000..9f8e7cc2 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_mushcode.json @@ -0,0 +1,790 @@ +[[ + "start", + ["text","@"], + ["support.function","create"], + ["text"," "], + ["identifier","phone"] +],[ + "start", + ["text","&"], + ["identifier","pickup"], + ["text"," "], + ["identifier","phone"], + ["keyword.operator","="], + ["identifier","$pick"], + ["text"," "], + ["identifier","up"], + ["text",":@"], + ["support.function","ifelse"], + ["text"," "], + ["paren.lparen","["], + ["support.function","u"], + ["paren.lparen","("], + ["identifier","is"], + ["text",","], + ["support.function","u"], + ["paren.lparen","("], + ["identifier","mode"], + ["paren.rparen",")"], + ["text",","], + ["identifier","ICC"], + ["paren.rparen",")]"], + ["keyword.operator","="], + ["paren.lparen","{"], + ["text","@"], + ["support.function","pemit"], + ["text"," "], + ["keyword.operator","%#="], + ["identifier","You"], + ["text"," "], + ["support.function","pick"], + ["text"," "], + ["identifier","up"], + ["text"," "], + ["identifier","the"], + ["text"," "], + ["paren.lparen","["], + ["support.function","fullname"], + ["paren.lparen","("], + ["identifier","me"], + ["paren.rparen",")]"], + ["text","."], + ["paren.lparen","["], + ["support.function","set"], + ["paren.lparen","("], + ["identifier","me"], + ["text",","], + ["identifier","PHONER"], + ["text",":"], + ["keyword.operator","%#"], + ["paren.rparen",")]"], + ["paren.lparen","["], + ["support.function","set"], + ["paren.lparen","("], + ["identifier","me"], + ["text",","], + ["identifier","MODE"], + ["text",":"], + ["identifier","CIP"], + ["paren.rparen",")]"], + ["paren.lparen","["], + ["support.function","set"], + ["paren.lparen","(["], + ["support.function","u"], + ["paren.lparen","("], + ["identifier","INCOMING"], + ["paren.rparen",")]"], + ["text",","], + ["identifier","CONNECTED"], + ["text",":"], + ["paren.lparen","["], + ["support.function","num"], + ["paren.lparen","("], + ["identifier","me"], + ["paren.rparen",")])]"], + ["paren.lparen","["], + ["support.function","set"], + ["paren.lparen","("], + ["identifier","me"], + ["text",","], + ["identifier","CONNECTED"], + ["text",":"], + ["paren.lparen","["], + ["support.function","u"], + ["paren.lparen","("], + ["identifier","INCOMING"], + ["paren.rparen",")])]"], + ["variable","%r"], + ["paren.lparen","["], + ["support.function","showpicture"], + ["paren.lparen","("], + ["identifier","PICPICKUP"], + ["paren.rparen",")]"], + ["variable","%r"], + ["identifier","Use"], + ["text"," '"], + ["paren.lparen","["], + ["identifier","color"], + ["paren.lparen","("], + ["identifier","green"], + ["text",","], + ["identifier","black"], + ["text",","], + ["identifier","psay"], + ["text"," "], + ["keyword.operator","<"], + ["identifier","message"], + ["keyword.operator",">"], + ["paren.rparen",")]"], + ["text","' "], + ["paren.lparen","("], + ["support.function","or"], + ["text"," '"], + ["paren.lparen","["], + ["identifier","color"], + ["paren.lparen","("], + ["identifier","green"], + ["text",","], + ["identifier","black"], + ["text",","], + ["identifier","p"], + ["text"," "], + ["keyword.operator","<"], + ["identifier","message"], + ["keyword.operator",">"], + ["paren.rparen",")]"], + ["text","'"], + ["paren.rparen",")"], + ["text"," "], + ["identifier","to"], + ["text"," "], + ["identifier","talk"], + ["text"," "], + ["identifier","into"], + ["text"," "], + ["identifier","the"], + ["text"," "], + ["identifier","phone"], + ["text",".;@"], + ["support.function","oemit"], + ["text"," "], + ["keyword.operator","%#="], + ["variable","%N"], + ["text"," "], + ["identifier","picks"], + ["text"," "], + ["identifier","up"], + ["text"," "], + ["identifier","the"], + ["text"," "], + ["paren.lparen","["], + ["support.function","fullname"], + ["paren.lparen","("], + ["identifier","me"], + ["paren.rparen",")]"], + ["text","."], + ["paren.rparen","}"], + ["text",","], + ["paren.lparen","{"], + ["text","@"], + ["support.function","pemit"], + ["text"," "], + ["keyword.operator","%#="], + ["identifier","You"], + ["text"," "], + ["support.function","pick"], + ["text"," "], + ["identifier","up"], + ["text"," "], + ["identifier","the"], + ["text"," "], + ["identifier","phone"], + ["text"," "], + ["identifier","but"], + ["text"," "], + ["identifier","no"], + ["text"," "], + ["identifier","one"], + ["text"," "], + ["identifier","is"], + ["text"," "], + ["identifier","there"], + ["text",". "], + ["identifier","You"], + ["text"," "], + ["identifier","hear"], + ["text"," "], + ["identifier","a"], + ["text"," "], + ["identifier","dialtone"], + ["text"," "], + ["support.function","and"], + ["text"," "], + ["identifier","then"], + ["text"," "], + ["identifier","hang"], + ["text"," "], + ["identifier","up"], + ["text",". "], + ["paren.lparen","["], + ["support.function","play"], + ["paren.lparen","("], + ["support.function","u"], + ["paren.lparen","("], + ["identifier","DIALTONE"], + ["paren.rparen","))]"], + ["text",";@"], + ["support.function","oemit"], + ["text"," "], + ["keyword.operator","%#="], + ["variable","%N"], + ["text"," "], + ["identifier","picks"], + ["text"," "], + ["identifier","up"], + ["text"," "], + ["identifier","the"], + ["text"," "], + ["identifier","phone"], + ["text",", "], + ["identifier","but"], + ["text"," "], + ["identifier","no"], + ["text"," "], + ["identifier","one"], + ["text"," "], + ["identifier","is"], + ["text"," "], + ["identifier","on"], + ["text"," "], + ["identifier","the"], + ["text"," "], + ["identifier","other"], + ["text"," "], + ["identifier","end"], + ["text","."], + ["paren.rparen","}"] +],[ + "start", + ["text","&"], + ["identifier","ringfun"], + ["text"," "], + ["identifier","phone"], + ["keyword.operator","="], + ["paren.lparen","["], + ["support.function","ifelse"], + ["paren.lparen","("], + ["support.function","eq"], + ["paren.lparen","("], + ["support.function","comp"], + ["paren.lparen","(["], + ["support.function","u"], + ["paren.lparen","("], + ["variable","%0"], + ["keyword.operator","/"], + ["identifier","ringtone"], + ["paren.rparen",")]"], + ["text",","], + ["identifier","off"], + ["paren.rparen",")"], + ["text",","], + ["constant.numeric","0"], + ["paren.rparen",")"], + ["text",","], + ["paren.lparen","["], + ["identifier","color"], + ["paren.lparen","("], + ["identifier","black"], + ["text",","], + ["identifier","cyan"], + ["text",","], + ["identifier","INCOMING"], + ["text"," "], + ["identifier","CALL"], + ["text"," "], + ["identifier","FROM"], + ["text"," "], + ["variable","%1"], + ["paren.rparen",")]"], + ["text",","], + ["paren.lparen","["], + ["support.function","play"], + ["paren.lparen","(["], + ["support.function","switch"], + ["paren.lparen","(["], + ["support.function","u"], + ["paren.lparen","("], + ["variable","%0"], + ["keyword.operator","/"], + ["identifier","ringtone"], + ["paren.rparen",")]"], + ["text",","], + ["constant.numeric","1"], + ["text",","], + ["paren.lparen","["], + ["support.function","u"], + ["paren.lparen","("], + ["variable","%0"], + ["keyword.operator","/"], + ["identifier","ringtone1"], + ["paren.rparen",")]"], + ["text",","], + ["constant.numeric","2"], + ["text",","], + ["paren.lparen","["], + ["support.function","u"], + ["paren.lparen","("], + ["variable","%0"], + ["keyword.operator","/"], + ["identifier","ringtone2"], + ["paren.rparen",")]"], + ["text",","], + ["constant.numeric","3"], + ["text",","], + ["paren.lparen","["], + ["support.function","u"], + ["paren.lparen","("], + ["variable","%0"], + ["keyword.operator","/"], + ["identifier","ringtone3"], + ["paren.rparen",")]"], + ["text",","], + ["constant.numeric","4"], + ["text",","], + ["paren.lparen","["], + ["support.function","u"], + ["paren.lparen","("], + ["variable","%0"], + ["keyword.operator","/"], + ["identifier","ringtone4"], + ["paren.rparen",")]"], + ["text",","], + ["constant.numeric","5"], + ["text",","], + ["paren.lparen","["], + ["support.function","u"], + ["paren.lparen","("], + ["variable","%0"], + ["keyword.operator","/"], + ["identifier","ringtone5"], + ["paren.rparen",")]"], + ["text",","], + ["constant.numeric","6"], + ["text",","], + ["paren.lparen","["], + ["support.function","u"], + ["paren.lparen","("], + ["variable","%0"], + ["keyword.operator","/"], + ["identifier","ringtone6"], + ["paren.rparen",")]"], + ["text",","], + ["constant.numeric","7"], + ["text",","], + ["paren.lparen","["], + ["support.function","u"], + ["paren.lparen","("], + ["variable","%0"], + ["keyword.operator","/"], + ["identifier","ringtone7"], + ["paren.rparen",")]"], + ["text",","], + ["constant.numeric","8"], + ["text",","], + ["paren.lparen","["], + ["support.function","u"], + ["paren.lparen","("], + ["variable","%0"], + ["keyword.operator","/"], + ["identifier","ringtone8"], + ["paren.rparen",")]"], + ["text",","], + ["constant.numeric","9"], + ["text",","], + ["paren.lparen","["], + ["support.function","u"], + ["paren.lparen","("], + ["variable","%0"], + ["keyword.operator","/"], + ["identifier","ringtone9"], + ["paren.rparen",")]"], + ["text",","], + ["identifier","custom"], + ["text",","], + ["paren.lparen","["], + ["support.function","u"], + ["paren.lparen","("], + ["variable","%0"], + ["keyword.operator","/"], + ["identifier","customtone"], + ["paren.rparen",")]"], + ["text",","], + ["identifier","vibrate"], + ["text",","], + ["paren.lparen","["], + ["support.function","u"], + ["paren.lparen","("], + ["variable","%0"], + ["keyword.operator","/"], + ["identifier","vibrate"], + ["paren.rparen",")])])]"] +],[ + "start", + ["text","&"], + ["identifier","ringloop"], + ["text"," "], + ["identifier","phone"], + ["keyword.operator","="], + ["text","@"], + ["support.function","switch"], + ["text"," "], + ["paren.lparen","["], + ["support.function","u"], + ["paren.lparen","("], + ["identifier","ringstate"], + ["paren.rparen",")]"], + ["keyword.operator","="], + ["constant.numeric","1"], + ["text",","], + ["paren.lparen","{"], + ["text","@"], + ["support.function","emit"], + ["text"," "], + ["paren.lparen","["], + ["support.function","setq"], + ["paren.lparen","("], + ["identifier","q"], + ["text",","], + ["paren.lparen","["], + ["support.function","u"], + ["paren.lparen","("], + ["identifier","connecting"], + ["paren.rparen",")])]"], + ["paren.lparen","["], + ["support.function","set"], + ["paren.lparen","("], + ["variable","%qq"], + ["text",","], + ["identifier","rangs"], + ["text",":"], + ["constant.numeric","0"], + ["paren.rparen",")]"], + ["paren.lparen","["], + ["support.function","set"], + ["paren.lparen","("], + ["variable","%qq"], + ["text",","], + ["identifier","mode"], + ["text",":"], + ["identifier","WFC"], + ["paren.rparen",")]"], + ["paren.lparen","["], + ["support.function","set"], + ["paren.lparen","("], + ["variable","%qq"], + ["text",","], + ["identifier","INCOMING"], + ["text",":"], + ["paren.rparen",")]"], + ["text",";@"], + ["support.function","ifelse"], + ["text"," "], + ["paren.lparen","["], + ["support.function","u"], + ["paren.lparen","("], + ["variable","%qq"], + ["keyword.operator","/"], + ["identifier","HASVMB"], + ["paren.rparen",")]"], + ["keyword.operator","="], + ["paren.lparen","{"], + ["text","@"], + ["support.function","tr"], + ["text"," "], + ["identifier","me"], + ["keyword.operator","/"], + ["identifier","ROUTEVMB"], + ["keyword.operator","="], + ["paren.lparen","["], + ["support.function","u"], + ["paren.lparen","("], + ["identifier","connecting"], + ["paren.rparen",")]"], + ["text",";"], + ["paren.rparen","}"], + ["text",","], + ["paren.lparen","{"], + ["text","@"], + ["support.function","pemit"], + ["text"," "], + ["keyword.operator","%#="], + ["paren.lparen","["], + ["support.function","u"], + ["paren.lparen","("], + ["identifier","MSGCNC"], + ["paren.rparen",")]"], + ["text",";"], + ["paren.rparen","}}"], + ["text",","], + ["constant.numeric","2"], + ["text",","], + ["paren.lparen","{"], + ["text","@"], + ["support.function","pemit"], + ["text"," "], + ["keyword.operator","%#="], + ["identifier","The"], + ["text"," "], + ["identifier","call"], + ["text"," "], + ["identifier","is"], + ["text"," "], + ["identifier","connected"], + ["text","."], + ["paren.lparen","["], + ["support.function","setq"], + ["paren.lparen","("], + ["identifier","q"], + ["text",","], + ["paren.lparen","["], + ["support.function","u"], + ["paren.lparen","("], + ["identifier","CONNECTING"], + ["paren.rparen",")])]"], + ["paren.lparen","["], + ["support.function","set"], + ["paren.lparen","("], + ["identifier","me"], + ["text",","], + ["identifier","CONNECTED"], + ["text",":"], + ["variable","%qq"], + ["paren.rparen",")]"], + ["paren.lparen","["], + ["support.function","set"], + ["paren.lparen","("], + ["variable","%qq"], + ["text",","], + ["identifier","CONNECTED"], + ["text",":"], + ["paren.lparen","["], + ["support.function","num"], + ["paren.lparen","("], + ["identifier","me"], + ["paren.rparen",")])]"], + ["paren.lparen","["], + ["support.function","set"], + ["paren.lparen","("], + ["variable","%qq"], + ["text",","], + ["identifier","MODE"], + ["text",":"], + ["identifier","CIP"], + ["paren.rparen",")]"], + ["text",";@"], + ["support.function","tr"], + ["text"," "], + ["identifier","me"], + ["keyword.operator","/"], + ["identifier","ciploop"], + ["text",";@"], + ["support.function","tr"], + ["text"," "], + ["variable","%qq"], + ["keyword.operator","/"], + ["identifier","ciploop"], + ["text",";"], + ["paren.rparen","}"], + ["text",","], + ["constant.numeric","3"], + ["text",","], + ["paren.lparen","{"], + ["text","@"], + ["support.function","emit"], + ["text"," "], + ["identifier","On"], + ["text"," "], + ["paren.lparen","["], + ["support.function","fullname"], + ["paren.lparen","("], + ["identifier","me"], + ["paren.rparen",")]"], + ["text","'"], + ["support.function","s"], + ["text"," "], + ["identifier","earpiece"], + ["text"," "], + ["identifier","you"], + ["text"," "], + ["identifier","hear"], + ["text"," "], + ["identifier","a"], + ["text"," "], + ["identifier","ringing"], + ["text"," "], + ["identifier","sound"], + ["text","."], + ["paren.lparen","["], + ["support.function","play"], + ["paren.lparen","("], + ["support.function","u"], + ["paren.lparen","("], + ["identifier","LINETONE"], + ["paren.rparen","))]"], + ["text",";@"], + ["support.function","tr"], + ["text"," "], + ["identifier","me"], + ["keyword.operator","/"], + ["identifier","ringhere"], + ["text",";@"], + ["identifier","increment"], + ["text"," "], + ["paren.lparen","["], + ["support.function","u"], + ["paren.lparen","("], + ["identifier","connecting"], + ["paren.rparen",")]"], + ["keyword.operator","/"], + ["identifier","RANGS"], + ["text",";@"], + ["identifier","wait"], + ["text"," "], + ["constant.numeric","5"], + ["keyword.operator","="], + ["paren.lparen","{"], + ["text","@"], + ["support.function","tr"], + ["text"," "], + ["identifier","me"], + ["keyword.operator","/"], + ["identifier","ringloop"], + ["paren.rparen","}"], + ["text",";"], + ["paren.rparen","}"], + ["text",","], + ["constant.numeric","4"], + ["text",","], + ["paren.lparen","{"], + ["paren.rparen","}"] +],[ + "start", + ["text","&"], + ["identifier","ringstate"], + ["text"," "], + ["identifier","phone"], + ["keyword.operator","="], + ["paren.lparen","["], + ["support.function","setq"], + ["paren.lparen","("], + ["identifier","q"], + ["text",","], + ["support.function","u"], + ["paren.lparen","("], + ["identifier","connecting"], + ["paren.rparen","))]"], + ["paren.lparen","["], + ["support.function","setq"], + ["paren.lparen","("], + ["constant.numeric","1"], + ["text",","], + ["paren.lparen","["], + ["support.function","gt"], + ["paren.lparen","("], + ["support.function","u"], + ["paren.lparen","("], + ["variable","%qq"], + ["keyword.operator","/"], + ["identifier","rangs"], + ["paren.rparen",")"], + ["text",","], + ["support.function","sub"], + ["paren.lparen","("], + ["support.function","u"], + ["paren.lparen","("], + ["variable","%qq"], + ["keyword.operator","/"], + ["identifier","rings"], + ["paren.rparen",")"], + ["text",","], + ["constant.numeric","1"], + ["paren.rparen","))])]"], + ["paren.lparen","["], + ["support.function","setq"], + ["paren.lparen","("], + ["constant.numeric","2"], + ["text",","], + ["paren.lparen","["], + ["support.function","and"], + ["paren.lparen","("], + ["support.function","u"], + ["paren.lparen","("], + ["identifier","is"], + ["text",","], + ["support.function","u"], + ["paren.lparen","("], + ["variable","%qq"], + ["keyword.operator","/"], + ["identifier","MODE"], + ["paren.rparen",")"], + ["text",","], + ["identifier","CIP"], + ["paren.rparen",")"], + ["text",","], + ["support.function","u"], + ["paren.lparen","("], + ["identifier","is"], + ["text",","], + ["support.function","u"], + ["paren.lparen","("], + ["variable","%qq"], + ["keyword.operator","/"], + ["identifier","INCOMING"], + ["paren.rparen",")"], + ["text",","], + ["paren.lparen","["], + ["support.function","num"], + ["paren.lparen","("], + ["identifier","me"], + ["paren.rparen",")]))]"], + ["paren.lparen","["], + ["support.function","setq"], + ["paren.lparen","("], + ["constant.numeric","3"], + ["text",","], + ["paren.lparen","["], + ["support.function","u"], + ["paren.lparen","("], + ["identifier","is"], + ["text",","], + ["support.function","u"], + ["paren.lparen","("], + ["variable","%qq"], + ["keyword.operator","/"], + ["identifier","MODE"], + ["paren.rparen",")"], + ["text",","], + ["identifier","ICC"], + ["paren.rparen",")])]"], + ["paren.lparen","["], + ["support.function","ifelse"], + ["paren.lparen","("], + ["variable","%q1"], + ["text",","], + ["constant.numeric","1"], + ["text",","], + ["support.function","ifelse"], + ["paren.lparen","("], + ["variable","%q2"], + ["text",","], + ["constant.numeric","2"], + ["text",","], + ["support.function","ifelse"], + ["paren.lparen","("], + ["variable","%q3"], + ["text",","], + ["constant.numeric","3"], + ["text",","], + ["constant.numeric","4"], + ["paren.rparen",")))]"] +],[ + "start", + ["text",";"], + ["identifier","comment"] +],[ + "start", + ["text","@@"], + ["paren.lparen","("], + ["identifier","comment"], + ["paren.rparen",")"] +],[ + "start", + ["keyword","say"], + ["text"," "], + ["paren.lparen","["], + ["support.function","time"], + ["paren.lparen","("], + ["paren.rparen",")]"] +],[ + "start" +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_mysql.json b/node_modules/ace/lib/ace/mode/_test/tokens_mysql.json new file mode 100644 index 00000000..9909eadd --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_mysql.json @@ -0,0 +1,4 @@ +[[ + "start", + ["identifier","TODO"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_nix.json b/node_modules/ace/lib/ace/mode/_test/tokens_nix.json new file mode 100644 index 00000000..b9424456 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_nix.json @@ -0,0 +1,360 @@ +[[ + "start", + ["text","{"] +],[ + "start", + ["text"," "], + ["comment","# Name of our deployment"] +],[ + "start", + ["text"," "], + ["identifier","network"], + ["text","."], + ["identifier","description"], + ["text"," "], + ["keyword.operator.assignment.nix","="], + ["text"," "], + ["string","\"HelloWorld\""], + ["text",";"] +],[ + "start", + ["text"," "], + ["comment","# Enable rolling back to previous versions of our infrastructure"] +],[ + "start", + ["text"," "], + ["identifier","network"], + ["text","."], + ["identifier","enableRollback"], + ["text"," "], + ["keyword.operator.assignment.nix","="], + ["text"," "], + ["constant.language.nix","true"], + ["text",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["comment","# It consists of a single server named 'helloserver'"] +],[ + "start", + ["text"," "], + ["identifier","helloserver"], + ["text"," "], + ["keyword.operator.assignment.nix","="] +],[ + "start", + ["text"," "], + ["comment","# Every server gets passed a few arguments, including a reference"] +],[ + "start", + ["text"," "], + ["comment","# to nixpkgs (pkgs)"] +],[ + "start", + ["text"," { "], + ["identifier","config"], + ["text",", "], + ["identifier","pkgs"], + ["text",", ... }:"] +],[ + "start", + ["text"," "], + ["keyword.declaration.nix","let"] +],[ + "start", + ["text"," "], + ["comment","# We import our custom packages from ./default passing pkgs as argument"] +],[ + "start", + ["text"," "], + ["identifier","packages"], + ["text"," "], + ["keyword.operator.assignment.nix","="], + ["text"," "], + ["keyword.control.nix","import"], + ["text"," ./"], + ["identifier","default"], + ["text","."], + ["identifier","nix"], + ["text"," { "], + ["identifier","pkgs"], + ["text"," "], + ["keyword.operator.assignment.nix","="], + ["text"," "], + ["identifier","pkgs"], + ["text","; };"] +],[ + "start", + ["text"," "], + ["comment","# This is the nodejs version specified in default.nix"] +],[ + "start", + ["text"," "], + ["identifier","nodejs"], + ["text"," "], + ["keyword.operator.assignment.nix","="], + ["text"," "], + ["identifier","packages"], + ["text","."], + ["identifier","nodejs"], + ["text",";"] +],[ + "start", + ["text"," "], + ["comment","# And this is the application we'd like to deploy"] +],[ + "start", + ["text"," "], + ["identifier","app"], + ["text"," "], + ["keyword.operator.assignment.nix","="], + ["text"," "], + ["identifier","packages"], + ["text","."], + ["identifier","app"], + ["text",";"] +],[ + "start", + ["text"," "], + ["keyword.declaration.nix","in"] +],[ + "start", + ["text"," {"] +],[ + "start", + ["text"," "], + ["comment","# We'll be running our application on port 8080, because a regular"] +],[ + "start", + ["text"," "], + ["comment","# user cannot bind to port 80"] +],[ + "start", + ["text"," "], + ["comment","# Then, using some iptables magic we'll forward traffic designated to port 80 to 8080"] +],[ + "start", + ["text"," "], + ["identifier","networking"], + ["text","."], + ["identifier","firewall"], + ["text","."], + ["identifier","enable"], + ["text"," "], + ["keyword.operator.assignment.nix","="], + ["text"," "], + ["constant.language.nix","true"], + ["text",";"] +],[ + "start", + ["text"," "], + ["comment","# We will open up port 22 (SSH) as well otherwise we're locking ourselves out"] +],[ + "start", + ["text"," "], + ["identifier","networking"], + ["text","."], + ["identifier","firewall"], + ["text","."], + ["identifier","allowedTCPPorts"], + ["text"," "], + ["keyword.operator.assignment.nix","="], + ["text"," [ "], + ["constant.numeric","80"], + ["text"," "], + ["constant.numeric","8080"], + ["text"," "], + ["constant.numeric","22"], + ["text"," ];"] +],[ + "start", + ["text"," "], + ["identifier","networking"], + ["text","."], + ["identifier","firewall"], + ["text","."], + ["identifier","allowPing"], + ["text"," "], + ["keyword.operator.assignment.nix","="], + ["text"," "], + ["constant.language.nix","true"], + ["text",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["comment","# Port forwarding using iptables"] +],[ + "qqdoc", + ["text"," "], + ["identifier","networking"], + ["text","."], + ["identifier","firewall"], + ["text","."], + ["identifier","extraCommands"], + ["text"," "], + ["keyword.operator.assignment.nix","="], + ["text"," "], + ["string","''"] +],[ + "qqdoc", + ["string"," iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080"] +],[ + "start", + ["string"," ''"], + ["text",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["comment","# To run our node.js program we're going to use a systemd service"] +],[ + "start", + ["text"," "], + ["comment","# We can configure the service to automatically start on boot and to restart"] +],[ + "start", + ["text"," "], + ["comment","# the process in case it crashes"] +],[ + "start", + ["text"," "], + ["identifier","systemd"], + ["text","."], + ["identifier","services"], + ["text","."], + ["identifier","helloserver"], + ["text"," "], + ["keyword.operator.assignment.nix","="], + ["text"," {"] +],[ + "start", + ["text"," "], + ["identifier","description"], + ["text"," "], + ["keyword.operator.assignment.nix","="], + ["text"," "], + ["string","\"Hello world application\""], + ["text",";"] +],[ + "start", + ["text"," "], + ["comment","# Start the service after the network is available"] +],[ + "start", + ["text"," "], + ["identifier","after"], + ["text"," "], + ["keyword.operator.assignment.nix","="], + ["text"," [ "], + ["string","\"network.target\""], + ["text"," ];"] +],[ + "start", + ["text"," "], + ["comment","# We're going to run it on port 8080 in production"] +],[ + "start", + ["text"," "], + ["identifier","environment"], + ["text"," "], + ["keyword.operator.assignment.nix","="], + ["text"," { "], + ["identifier","PORT"], + ["text"," "], + ["keyword.operator.assignment.nix","="], + ["text"," "], + ["string","\"8080\""], + ["text","; };"] +],[ + "start", + ["text"," "], + ["identifier","serviceConfig"], + ["text"," "], + ["keyword.operator.assignment.nix","="], + ["text"," {"] +],[ + "start", + ["text"," "], + ["comment","# The actual command to run"] +],[ + "start", + ["text"," "], + ["identifier","ExecStart"], + ["text"," "], + ["keyword.operator.assignment.nix","="], + ["text"," "], + ["string","\""], + ["constant.language.escape","${"], + ["identifier","nodejs"], + ["constant.language.escape","}"], + ["string","/bin/node "], + ["constant.language.escape","${"], + ["identifier","app"], + ["constant.language.escape","}"], + ["string","/server.js\""], + ["text",";"] +],[ + "start", + ["text"," "], + ["comment","# For security reasons we'll run this process as a special 'nodejs' user"] +],[ + "start", + ["text"," "], + ["identifier","User"], + ["text"," "], + ["keyword.operator.assignment.nix","="], + ["text"," "], + ["string","\"nodejs\""], + ["text",";"] +],[ + "start", + ["text"," "], + ["identifier","Restart"], + ["text"," "], + ["keyword.operator.assignment.nix","="], + ["text"," "], + ["string","\"always\""], + ["text",";"] +],[ + "start", + ["text"," };"] +],[ + "start", + ["text"," };"] +],[ + "start" +],[ + "start", + ["text"," "], + ["comment","# And lastly we ensure the user we run our application as is created"] +],[ + "start", + ["text"," "], + ["identifier","users"], + ["text","."], + ["identifier","extraUsers"], + ["text"," "], + ["keyword.operator.assignment.nix","="], + ["text"," {"] +],[ + "start", + ["text"," "], + ["identifier","nodejs"], + ["text"," "], + ["keyword.operator.assignment.nix","="], + ["text"," { };"] +],[ + "start", + ["text"," };"] +],[ + "start", + ["text"," };"] +],[ + "start", + ["text","}"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_objectivec.json b/node_modules/ace/lib/ace/mode/_test/tokens_objectivec.json new file mode 100644 index 00000000..cdfd1196 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_objectivec.json @@ -0,0 +1,793 @@ +[[ + "start", + ["storage.type.objc","@"], + ["punctuation.definition.storage.type.objc","protocol"], + ["entity.name.type.objc"," Printing"], + ["text",": "], + ["entity.other.inherited-class.objc","someParent"] +],[ + "start", + ["meta.function.objc","-"], + ["paren.lparen","("], + ["storage.type","void"], + ["paren.rparen",")"], + ["text"," "], + ["identifier","print"], + ["punctuation.operator",";"] +],[ + "start", + ["storage.type.objc","@end"] +],[ + "start" +],[ + "start", + ["storage.type.objc","@"], + ["punctuation.definition.storage.type.objc","interface"], + ["entity.name.type.objc"," Fraction"], + ["text",": "], + ["entity.other.inherited-class.objc","NSObject"], + ["text"," "], + ["keyword.operator","<"], + ["identifier","Printing"], + ["punctuation.operator",","], + ["text"," "], + ["support.class.cocoa","NSCopying"], + ["keyword.operator",">"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["storage.type","int"], + ["text"," "], + ["identifier","numerator"], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "], + ["storage.type","int"], + ["text"," "], + ["identifier","denominator"], + ["punctuation.operator",";"] +],[ + "start", + ["paren.rparen","}"] +],[ + "start", + ["storage.type.objc","@end"] +],[ + "start" +],[ + "start", + ["string.begin.objc","@\""], + ["string","blah"], + ["invalid.illegal.unknown-escape.objc","\\8"], + ["punctuation.definition.string.end","\""], + ["text"," "], + ["string.begin.objc","@\""], + ["string","a"], + ["constant.character.escape.objc","\\222"], + ["string","sd"], + ["invalid.illegal.unknown-escape.objc","\\d"], + ["punctuation.definition.string.end","\""], + ["text"," "], + ["string.begin.objc","@\""], + ["constant.character.escape.objc","\\f"], + ["string","aw"], + ["constant.character.escape.objc","\\\"\\?"], + ["string"," "], + ["constant.character.escape.objc","\\'"], + ["string"," "], + ["constant.character.escape.objc","\\4"], + ["string"," n"], + ["constant.character.escape.objc","\\\\"], + ["punctuation.definition.string.end","\""], + ["text"," "], + ["string.begin.objc","@\""], + ["constant.character.escape.objc","\\56"], + ["punctuation.definition.string.end","\""] +],[ + "start", + ["string.begin.objc","@\""], + ["constant.character.escape.objc","\\xSF42"], + ["punctuation.definition.string.end","\""] +],[ + "start" +],[ + "start", + ["meta.function.objc","-"], + ["paren.lparen","("], + ["support.class.cocoa","NSDecimalNumber"], + ["keyword.operator","*"], + ["paren.rparen",")"], + ["identifier","addCount"], + ["punctuation.operator",":"], + ["paren.lparen","("], + ["storage.type.id.objc","id"], + ["paren.rparen",")"], + ["identifier","addObject"], + ["paren.lparen","{"] +],[ + "start" +],[ + "start", + ["keyword.control","return"], + ["text"," "], + ["punctuation.section.scope.begin.objc","["], + ["identifier","count"], + ["text"," "], + ["support.function.any-method.objc","decimalNumberByAdding:"], + ["identifier","addObject"], + ["punctuation.operator","."], + ["identifier","count"], + ["paren.rparen","]"], + ["punctuation.operator",";"] +],[ + "start" +],[ + "start", + ["paren.rparen","}"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword.control.macro.objc","NS_DURING"], + ["text"," "], + ["keyword.control.macro.objc","NS_HANDLER"], + ["text"," "], + ["keyword.control.macro.objc","NS_ENDHANDLER"] +],[ + "start" +],[ + "start", + ["punctuation.definition.keyword.objc","@"], + ["keyword.control.exception.objc","try"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["keyword.control","if"], + ["text"," "], + ["paren.lparen","("], + ["identifier","argc"], + ["text"," "], + ["keyword.operator",">"], + ["text"," "], + ["constant.numeric","1"], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["punctuation.definition.keyword.objc","@"], + ["keyword.control.exception.objc","throw"], + ["text"," "], + ["punctuation.section.scope.begin.objc","["], + ["support.class.cocoa","NSException"], + ["text"," "], + ["support.function.any-method.objc","exceptionWithName:"], + ["string.begin.objc","@\""], + ["string","Throwing a test exception"], + ["punctuation.definition.string.end","\""], + ["text"," "], + ["identifier","reason"], + ["punctuation.operator",":"], + ["string.begin.objc","@\""], + ["string","Testing the @throw directive."], + ["punctuation.definition.string.end","\""], + ["text"," "], + ["identifier","userInfo"], + ["punctuation.operator",":"], + ["constant.language.objc","nil"], + ["paren.rparen","]"], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["paren.rparen","}"], + ["text"," "] +],[ + "start", + ["punctuation.definition.keyword.objc","@"], + ["keyword.control.exception.objc","catch"], + ["text"," "], + ["paren.lparen","("], + ["storage.type.id.objc","id"], + ["text"," "], + ["identifier","theException"], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["support.function.cocoa","NSLog"], + ["paren.lparen","("], + ["string.begin.objc","@\""], + ["string","%@"], + ["punctuation.definition.string.end","\""], + ["punctuation.operator",","], + ["text"," "], + ["identifier","theException"], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "], + ["identifier","result"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["constant.numeric","1"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["paren.rparen","}"], + ["text"," "] +],[ + "start", + ["punctuation.definition.keyword.objc","@"], + ["keyword.control.exception.objc","finally"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["support.function.cocoa","NSLog"], + ["paren.lparen","("], + ["string.begin.objc","@\""], + ["string","This always happens."], + ["punctuation.definition.string.end","\""], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "], + ["identifier","result"], + ["text"," "], + ["keyword.operator","+="], + ["text"," "], + ["constant.numeric","2"], + ["text"," "], + ["punctuation.operator",";"] +],[ + "start", + ["paren.rparen","}"] +],[ + "start" +],[ + "start", + ["text"," "], + ["punctuation.definition.storage.modifier.objc","@"], + ["storage.modifier.objc","synchronized"], + ["paren.lparen","("], + ["identifier","lock"], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["support.function.cocoa","NSLog"], + ["paren.lparen","("], + ["string.begin.objc","@\""], + ["string","Hello World"], + ["punctuation.definition.string.end","\""], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start" +],[ + "start", + ["storage.type","struct"], + ["text"," "], + ["paren.lparen","{"], + ["text"," "], + ["punctuation.definition.keyword.objc","@"], + ["keyword.other.objc","defs"], + ["paren.lparen","("], + ["text"," "], + ["support.class.cocoa","NSObject"], + ["paren.rparen",")"], + ["text"," "], + ["paren.rparen","}"] +],[ + "start" +],[ + "start", + ["storage.type","char"], + ["text"," "], + ["keyword.operator","*"], + ["identifier","enc1"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["punctuation.definition.keyword.objc","@"], + ["keyword.other.objc","encode"], + ["paren.lparen","("], + ["storage.type","int"], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["storage.type.objc","IBOutlet"], + ["text","|"], + ["storage.type.objc","IBAction"], + ["text","|"], + ["storage.type.objc","BOOL"], + ["text","|"], + ["storage.type.objc","SEL"], + ["text","|"], + ["storage.type.id.objc","id"], + ["text","|"], + ["storage.type.objc","unichar"], + ["text","|"], + ["storage.type.objc","IMP"], + ["text","|"], + ["storage.type.objc","Class"], + ["text"," "] +],[ + "start" +],[ + "start" +],[ + "start", + ["text"," "], + ["punctuation.definition.storage.type.objc","@"], + ["storage.type.objc","class"], + ["text"," "], + ["punctuation.definition.storage.type.objc","@"], + ["storage.type.objc","protocol"] +],[ + "start" +],[ + "start", + ["punctuation.definition.storage.modifier.objc","@"], + ["storage.modifier.objc","public"] +],[ + "start", + ["text"," "], + ["comment","// instance variables"] +],[ + "start", + ["punctuation.definition.storage.modifier.objc","@"], + ["storage.modifier.objc","package"] +],[ + "start", + ["text"," "], + ["comment","// instance variables"] +],[ + "start", + ["punctuation.definition.storage.modifier.objc","@"], + ["storage.modifier.objc","protected"] +],[ + "start", + ["text"," "], + ["comment","// instance variables"] +],[ + "start", + ["punctuation.definition.storage.modifier.objc","@"], + ["storage.modifier.objc","private"] +],[ + "start", + ["text"," "], + ["comment","// instance variables"] +],[ + "start" +],[ + "start", + ["text"," "], + ["constant.language.objc","YES"], + ["text"," "], + ["constant.language.objc","NO"], + ["text"," "], + ["constant.language.objc","Nil"], + ["text"," "], + ["constant.language.objc","nil"] +],[ + "start", + ["support.variable.foundation","NSApp"], + ["paren.lparen","("], + ["paren.rparen",")"] +],[ + "start", + ["support.function.cocoa.leopard","NSRectToCGRect"], + ["text"," "], + ["paren.lparen","("], + ["identifier","Protocol"], + ["text"," "], + ["identifier","ProtocolFromString"], + ["punctuation.operator",":"], + ["string","\"NSTableViewDelegate\""], + ["paren.rparen","))"] +],[ + "start" +],[ + "start", + ["punctuation.section.scope.begin.objc","["], + ["identifier","SPPoint"], + ["text"," "], + ["support.function.any-method.objc","pointFromCGPoint:"], + ["identifier","self"], + ["punctuation.operator","."], + ["identifier","position"], + ["paren.rparen","]"] +],[ + "start" +],[ + "start", + ["support.function.cocoa","NSRoundDownToMultipleOfPageSize"] +],[ + "start" +],[ + "start", + ["keyword","#import"], + ["constant.other"," "] +],[ + "start" +],[ + "start", + ["storage.type","int"], + ["text"," "], + ["identifier","main"], + ["paren.lparen","("], + ["text"," "], + ["storage.type","int"], + ["text"," "], + ["identifier","argc"], + ["punctuation.operator",","], + ["text"," "], + ["storage.modifier","const"], + ["text"," "], + ["storage.type","char"], + ["text"," "], + ["keyword.operator","*"], + ["identifier","argv"], + ["punctuation.section.scope.begin.objc","["], + ["punctuation.section.scope.end.objc","]"], + ["text"," "], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["support.function.C99.c","printf"], + ["paren.lparen","("], + ["text"," "], + ["string","\"hello world\\n\""], + ["text"," "], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "], + ["keyword.control","return"], + ["text"," "], + ["constant.numeric","0"], + ["punctuation.operator",";"] +],[ + "start", + ["paren.rparen","}"] +],[ + "start" +],[ + "start", + ["support.class.cocoa","NSChangeSpelling"] +],[ + "start" +],[ + "start", + ["string.begin.objc","@\""], + ["string","0 != SUBQUERY(image, $x, 0 != SUBQUERY($x.bookmarkItems, $y, $y.@count == 0).@count).@count"], + ["punctuation.definition.string.end","\""] +],[ + "start" +],[ + "start", + ["punctuation.definition.storage.type.objc","@selector"], + ["punctuation","("], + ["support.function.any-method.name-of-parameter.objc","lowercaseString"], + ["punctuation",")"], + ["text"," "], + ["punctuation.definition.storage.type.objc","@selector"], + ["punctuation","("], + ["support.function.any-method.name-of-parameter.objc","uppercaseString:"], + ["punctuation",")"] +],[ + "start" +],[ + "start", + ["identifier","NSFetchRequest"], + ["text"," "], + ["keyword.operator","*"], + ["identifier","localRequest"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["punctuation.section.scope.begin.objc","[["], + ["identifier","NSFetchRequest"], + ["text"," "], + ["support.function.any-method.objc","alloc"], + ["paren.rparen","]"], + ["text"," "], + ["identifier","init"], + ["paren.rparen","]"], + ["punctuation.operator",";"], + ["text"," "] +],[ + "start", + ["identifier","localRequest"], + ["punctuation.operator","."], + ["identifier","entity"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["punctuation.section.scope.begin.objc","["], + ["identifier","NSEntityDescription"], + ["text"," "], + ["support.function.any-method.objc","entityForName:"], + ["string.begin.objc","@\""], + ["string","VNSource"], + ["punctuation.definition.string.end","\""], + ["text"," "], + ["identifier","inManagedObjectContext"], + ["punctuation.operator",":"], + ["identifier","context"], + ["paren.rparen","]"], + ["punctuation.operator",";"], + ["text"," "] +],[ + "start", + ["identifier","localRequest"], + ["punctuation.operator","."], + ["identifier","sortDescriptors"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["punctuation.section.scope.begin.objc","["], + ["support.class.cocoa","NSArray"], + ["text"," "], + ["support.function.any-method.objc","arrayWithObject:"], + ["punctuation.section.scope.begin.objc","["], + ["support.class.cocoa","NSSortDescriptor"], + ["text"," "], + ["support.function.any-method.objc","sortDescriptorWithKey:"], + ["string.begin.objc","@\""], + ["string","resolution"], + ["punctuation.definition.string.end","\""], + ["text"," "], + ["identifier","ascending"], + ["punctuation.operator",":"], + ["constant.language.objc","YES"], + ["paren.rparen","]]"], + ["punctuation.operator",";"], + ["text"," "] +],[ + "start", + ["support.class.cocoa","NSPredicate"], + ["text"," "], + ["keyword.operator","*"], + ["identifier","predicate"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["punctuation.section.scope.begin.objc","["], + ["support.class.cocoa","NSPredicate"], + ["text"," "], + ["support.function.any-method.objc","predicateWithFormat:"], + ["string.begin.objc","@\""], + ["string","0 != SUBQUERY(image, $x, 0 != SUBQUERY($x.bookmarkItems, $y, $y.@count == 0).@count).@count"], + ["punctuation.definition.string.end","\""], + ["paren.rparen","]"], + ["punctuation.operator",";"] +],[ + "start", + ["punctuation.section.scope.begin.objc","["], + ["support.class.cocoa","NSPredicate"], + ["text"," "], + ["support.function.any-method.objc","predicateWithFormat:"], + ["paren.rparen","]"] +],[ + "start", + ["support.class.cocoa","NSString"], + ["text"," "], + ["keyword.operator","*"], + ["identifier","predicateString"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["punctuation.section.scope.begin.objc","["], + ["support.class.cocoa","NSString"], + ["text"," "], + ["support.function.any-method.objc","stringWithFormat:"], + ["string.begin.objc","@\""], + ["string","SELF beginsWith[cd] %@"], + ["punctuation.definition.string.end","\""], + ["punctuation.operator",","], + ["text"," "], + ["identifier","searchString"], + ["paren.rparen","]"], + ["punctuation.operator",";"] +],[ + "start", + ["support.class.cocoa","NSPredicate"], + ["text"," "], + ["keyword.operator","*"], + ["identifier","pred"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["punctuation.section.scope.begin.objc","["], + ["support.class.cocoa","NSPredicate"], + ["text"," "], + ["support.function.any-method.objc","predicateWithFormat:"], + ["identifier","predicateString"], + ["paren.rparen","]"], + ["punctuation.operator",";"] +],[ + "start", + ["support.class.cocoa","NSArray"], + ["text"," "], + ["keyword.operator","*"], + ["identifier","filteredKeys"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["punctuation.section.scope.begin.objc","[["], + ["identifier","myMutableDictionary"], + ["text"," "], + ["support.function.any-method.objc","allKeys"], + ["paren.rparen","]"], + ["text"," "], + ["identifier","filteredArrayUsingPredicate"], + ["punctuation.operator",":"], + ["identifier","pred"], + ["paren.rparen","]"], + ["punctuation.operator",";"], + ["text"," "] +],[ + "start" +],[ + "start", + ["identifier","localRequest"], + ["punctuation.operator","."], + ["identifier","predicate"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["punctuation.section.scope.begin.objc","["], + ["support.class.cocoa","NSPredicate"], + ["text"," "], + ["support.function.any-method.objc","predicateWithFormat:"], + ["string.begin.objc","@\""], + ["string","whichChart = %@"], + ["punctuation.definition.string.end","\""], + ["text"," "], + ["identifier","argumentArray"], + ["punctuation.operator",":"], + ["text"," "], + ["identifier","listChartToDownload"], + ["paren.rparen","]"], + ["punctuation.operator",";"] +],[ + "start", + ["identifier","localRequest"], + ["punctuation.operator","."], + ["identifier","fetchBatchSize"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["constant.numeric","100"], + ["punctuation.operator",";"] +],[ + "start", + ["identifier","arrayRequest"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["punctuation.section.scope.begin.objc","["], + ["identifier","context"], + ["text"," "], + ["support.function.any-method.objc","executeFetchRequest:"], + ["identifier","localRequest"], + ["text"," "], + ["identifier","error"], + ["punctuation.operator",":"], + ["keyword.operator","&"], + ["identifier","error1"], + ["paren.rparen","]"], + ["punctuation.operator",";"] +],[ + "start" +],[ + "start", + ["punctuation.section.scope.begin.objc","["], + ["identifier","localRequest"], + ["text"," "], + ["support.function.any-method.objc","release"], + ["paren.rparen","]"], + ["punctuation.operator",";"] +],[ + "start" +],[ + "start", + ["keyword","#ifndef"], + ["text"," "], + ["constant.language.objc","Nil"] +],[ + "start", + ["keyword","#define"], + ["constant.other"," Nil __DARWIN_NULL "], + ["comment","/* id of Nil class */"] +],[ + "start", + ["keyword","#endif"] +],[ + "start" +],[ + "start", + ["storage.type.objc","@implementation"], + ["entity.name.type.objc"," MyObject"] +],[ + "start", + ["meta.function.objc","- "], + ["paren.lparen","("], + ["storage.type","unsigned"], + ["text"," "], + ["storage.type","int"], + ["paren.rparen",")"], + ["identifier","areaOfWidth"], + ["punctuation.operator",":"], + ["paren.lparen","("], + ["storage.type","unsigned"], + ["text"," "], + ["storage.type","int"], + ["paren.rparen",")"], + ["identifier","width"] +],[ + "start", + ["text"," "], + ["identifier","height"], + ["punctuation.operator",":"], + ["paren.lparen","("], + ["storage.type","unsigned"], + ["text"," "], + ["storage.type","int"], + ["paren.rparen",")"], + ["identifier","height"] +],[ + "start", + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["keyword.control","return"], + ["text"," "], + ["identifier","width"], + ["keyword.operator","*"], + ["identifier","height"], + ["punctuation.operator",";"] +],[ + "start", + ["paren.rparen","}"] +],[ + "start", + ["storage.type.objc","@end"] +],[ + "start" +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_ocaml.json b/node_modules/ace/lib/ace/mode/_test/tokens_ocaml.json new file mode 100644 index 00000000..73e3cfcd --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_ocaml.json @@ -0,0 +1,200 @@ +[[ + "comment", + ["comment","(*"] +],[ + "comment", + ["comment"," * Example of early return implementation taken from"] +],[ + "comment", + ["comment"," * http://ocaml.janestreet.com/?q=node/91"] +],[ + "start", + ["comment"," *)"] +],[ + "start" +],[ + "start", + ["keyword","let"], + ["text"," "], + ["identifier","with_return"], + ["text"," "], + ["paren.lparen","("], + ["keyword","type"], + ["text"," "], + ["identifier","t"], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","("], + ["identifier","f"], + ["text"," : "], + ["identifier","_"], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["identifier","t"], + ["paren.rparen",")"], + ["text"," "], + ["keyword.operator","="] +],[ + "start", + ["text"," "], + ["keyword","let"], + ["text"," "], + ["keyword","module"], + ["text"," "], + ["identifier","M"], + ["text"," "], + ["keyword.operator","="] +],[ + "start", + ["text"," "], + ["keyword","struct"], + ["text"," "], + ["keyword","exception"], + ["text"," "], + ["identifier","Return"], + ["text"," "], + ["keyword","of"], + ["text"," "], + ["identifier","t"], + ["text"," "], + ["keyword","end"] +],[ + "start", + ["text"," "], + ["keyword","in"] +],[ + "start", + ["text"," "], + ["keyword","let"], + ["text"," "], + ["identifier","return"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["paren.lparen","{"], + ["text"," "], + ["identifier","return"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["paren.lparen","("], + ["keyword","fun"], + ["text"," "], + ["identifier","x"], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["support.function","raise"], + ["text"," "], + ["paren.lparen","("], + ["identifier","M"], + ["text","."], + ["identifier","Return"], + ["text"," "], + ["identifier","x"], + ["paren.rparen","))"], + ["text","; "], + ["paren.rparen","}"], + ["text"," "], + ["keyword","in"] +],[ + "start", + ["text"," "], + ["keyword","try"], + ["text"," "], + ["identifier","f"], + ["text"," "], + ["identifier","return"], + ["text"," "], + ["keyword","with"], + ["text"," "], + ["identifier","M"], + ["text","."], + ["identifier","Return"], + ["text"," "], + ["identifier","x"], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["identifier","x"] +],[ + "start" +],[ + "start" +],[ + "start", + ["comment","(* Function that uses the 'early return' functionality provided by `with_return` *)"] +],[ + "start", + ["keyword","let"], + ["text"," "], + ["identifier","sum_until_first_negative"], + ["text"," "], + ["support.function","list"], + ["text"," "], + ["keyword.operator","="] +],[ + "start", + ["text"," "], + ["identifier","with_return"], + ["text"," "], + ["paren.lparen","("], + ["keyword","fun"], + ["text"," "], + ["identifier","r"], + ["text"," "], + ["keyword.operator","->"] +],[ + "start", + ["text"," "], + ["support.function","List"], + ["text","."], + ["support.function","fold"], + ["text"," "], + ["support.function","list"], + ["text"," "], + ["keyword.operator","~"], + ["support.function","init"], + ["text",":"], + ["constant.numeric","0"], + ["text"," "], + ["keyword.operator","~"], + ["identifier","f"], + ["text",":"], + ["paren.lparen","("], + ["keyword","fun"], + ["text"," "], + ["identifier","acc"], + ["text"," "], + ["identifier","x"], + ["text"," "], + ["keyword.operator","->"] +],[ + "start", + ["text"," "], + ["keyword","if"], + ["text"," "], + ["identifier","x"], + ["text"," "], + ["keyword.operator",">="], + ["text"," "], + ["constant.numeric","0"], + ["text"," "], + ["keyword","then"], + ["text"," "], + ["identifier","acc"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["identifier","x"], + ["text"," "], + ["keyword","else"], + ["text"," "], + ["identifier","r"], + ["text","."], + ["identifier","return"], + ["text"," "], + ["identifier","acc"], + ["paren.rparen","))"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_pascal.json b/node_modules/ace/lib/ace/mode/_test/tokens_pascal.json new file mode 100644 index 00000000..22c1f0c4 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_pascal.json @@ -0,0 +1,297 @@ +[[ + "punctuation.definition.comment.pascal", + ["punctuation.definition.comment.pascal","(*"], + ["comment.block.pascal.one","****************************************************************************"] +],[ + "punctuation.definition.comment.pascal", + ["comment.block.pascal.one"," * A simple bubble sort program. Reads integers, one per line, and prints *"] +],[ + "punctuation.definition.comment.pascal", + ["comment.block.pascal.one"," * them out in sorted order. Blows up if there are more than 49. *"] +],[ + "start", + ["comment.block.pascal.one"," ****************************************************************************"], + ["punctuation.definition.comment.pascal","*)"] +],[ + "start", + ["keyword.control.pascal","PROGRAM"], + ["text"," Sort(input"], + ["keyword.operator",","], + ["text"," output)"], + ["keyword.operator",";"] +],[ + "start", + ["text"," "], + ["keyword.control.pascal","CONST"] +],[ + "start", + ["text"," "], + ["punctuation.definition.comment.pascal","(*"], + ["comment.block.pascal.one"," Max array size. "], + ["punctuation.definition.comment.pascal","*)"] +],[ + "start", + ["text"," MaxElts "], + ["keyword.operator","="], + ["text"," "], + ["constant.numeric.pascal","50"], + ["keyword.operator",";"] +],[ + "start", + ["text"," "], + ["keyword.control.pascal","TYPE"], + ["text"," "] +],[ + "start", + ["text"," "], + ["punctuation.definition.comment.pascal","(*"], + ["comment.block.pascal.one"," Type of the element array. "], + ["punctuation.definition.comment.pascal","*)"] +],[ + "start", + ["text"," IntArrType "], + ["keyword.operator","="], + ["text"," "], + ["keyword.control.pascal","ARRAY"], + ["text"," ["], + ["constant.numeric.pascal","1"], + ["text","..MaxElts] "], + ["keyword.control.pascal","OF"], + ["text"," Integer"], + ["keyword.operator",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword.control.pascal","VAR"] +],[ + "start", + ["text"," "], + ["punctuation.definition.comment.pascal","(*"], + ["comment.block.pascal.one"," Indexes, exchange temp, array size. "], + ["punctuation.definition.comment.pascal","*)"] +],[ + "start", + ["text"," i"], + ["keyword.operator",","], + ["text"," j"], + ["keyword.operator",","], + ["text"," tmp"], + ["keyword.operator",","], + ["text"," size: integer"], + ["keyword.operator",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["punctuation.definition.comment.pascal","(*"], + ["comment.block.pascal.one"," Array of ints "], + ["punctuation.definition.comment.pascal","*)"] +],[ + "start", + ["text"," arr: IntArrType"], + ["keyword.operator",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["punctuation.definition.comment.pascal","(*"], + ["comment.block.pascal.one"," Read in the integers. "], + ["punctuation.definition.comment.pascal","*)"] +],[ + "start", + ["text"," "], + ["variable.pascal","PROCEDURE"], + ["text"," "], + ["storage.type.function.pascal","ReadArr"], + ["text","("], + ["keyword.control.pascal","VAR"], + ["text"," size: Integer"], + ["keyword.operator",";"], + ["text"," "], + ["keyword.control.pascal","VAR"], + ["text"," a: IntArrType)"], + ["keyword.operator",";"], + ["text"," "] +],[ + "start", + ["text"," "], + ["keyword.control.pascal","BEGIN"] +],[ + "start", + ["text"," size "], + ["keyword.operator",":="], + ["text"," "], + ["constant.numeric.pascal","1"], + ["keyword.operator",";"] +],[ + "start", + ["text"," "], + ["keyword.control.pascal","WHILE"], + ["text"," "], + ["keyword.control.pascal","NOT"], + ["text"," eof "], + ["keyword.control.pascal","DO"], + ["text"," "], + ["keyword.control.pascal","BEGIN"] +],[ + "start", + ["text"," readln(a[size])"], + ["keyword.operator",";"] +],[ + "start", + ["text"," "], + ["keyword.control.pascal","IF"], + ["text"," "], + ["keyword.control.pascal","NOT"], + ["text"," eof "], + ["keyword.control.pascal","THEN"], + ["text"," "] +],[ + "start", + ["text"," size "], + ["keyword.operator",":="], + ["text"," size "], + ["keyword.operator","+"], + ["text"," "], + ["constant.numeric.pascal","1"] +],[ + "start", + ["text"," "], + ["keyword.control.pascal","END"] +],[ + "start", + ["text"," "], + ["keyword.control.pascal","END"], + ["keyword.operator",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword.control.pascal","BEGIN"] +],[ + "start", + ["text"," "], + ["punctuation.definition.comment.pascal","(*"], + ["comment.block.pascal.one"," Read "], + ["punctuation.definition.comment.pascal","*)"] +],[ + "start", + ["text"," ReadArr(size"], + ["keyword.operator",","], + ["text"," arr)"], + ["keyword.operator",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["punctuation.definition.comment.pascal","(*"], + ["comment.block.pascal.one"," Sort using bubble sort. "], + ["punctuation.definition.comment.pascal","*)"] +],[ + "start", + ["text"," "], + ["keyword.control.pascal","FOR"], + ["text"," i "], + ["keyword.operator",":="], + ["text"," size "], + ["keyword.operator","-"], + ["text"," "], + ["constant.numeric.pascal","1"], + ["text"," DOWNTO "], + ["constant.numeric.pascal","1"], + ["text"," "], + ["keyword.control.pascal","DO"] +],[ + "start", + ["text"," "], + ["keyword.control.pascal","FOR"], + ["text"," j "], + ["keyword.operator",":="], + ["text"," "], + ["constant.numeric.pascal","1"], + ["text"," "], + ["keyword.control.pascal","TO"], + ["text"," i "], + ["keyword.control.pascal","DO"], + ["text"," "] +],[ + "start", + ["text"," "], + ["keyword.control.pascal","IF"], + ["text"," arr[j] > arr[j "], + ["keyword.operator","+"], + ["text"," "], + ["constant.numeric.pascal","1"], + ["text","] "], + ["keyword.control.pascal","THEN"], + ["text"," "], + ["keyword.control.pascal","BEGIN"] +],[ + "start", + ["text"," tmp "], + ["keyword.operator",":="], + ["text"," arr[j]"], + ["keyword.operator",";"] +],[ + "start", + ["text"," arr[j] "], + ["keyword.operator",":="], + ["text"," arr[j "], + ["keyword.operator","+"], + ["text"," "], + ["constant.numeric.pascal","1"], + ["text","]"], + ["keyword.operator",";"] +],[ + "start", + ["text"," arr[j "], + ["keyword.operator","+"], + ["text"," "], + ["constant.numeric.pascal","1"], + ["text","] "], + ["keyword.operator",":="], + ["text"," tmp"], + ["keyword.operator",";"] +],[ + "start", + ["text"," "], + ["keyword.control.pascal","END"], + ["keyword.operator",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["punctuation.definition.comment.pascal","(*"], + ["comment.block.pascal.one"," Print. "], + ["punctuation.definition.comment.pascal","*)"] +],[ + "start", + ["text"," "], + ["keyword.control.pascal","FOR"], + ["text"," i "], + ["keyword.operator",":="], + ["text"," "], + ["constant.numeric.pascal","1"], + ["text"," "], + ["keyword.control.pascal","TO"], + ["text"," size "], + ["keyword.control.pascal","DO"] +],[ + "start", + ["text"," writeln(arr[i])"] +],[ + "start", + ["text"," "], + ["keyword.control.pascal","END"], + ["text","."] +],[ + "start", + ["text"," "] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_perl.json b/node_modules/ace/lib/ace/mode/_test/tokens_perl.json new file mode 100644 index 00000000..30bb39c6 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_perl.json @@ -0,0 +1,227 @@ +[[ + "start", + ["comment","#!/usr/bin/perl"] +],[ + "block_comment", + ["comment.doc","=begin"] +],[ + "block_comment", + ["comment.doc"," perl example code for Ace"] +],[ + "start", + ["comment.doc","=cut"] +],[ + "start" +],[ + "start", + ["keyword","use"], + ["text"," "], + ["identifier","strict"], + ["text",";"] +],[ + "start", + ["keyword","use"], + ["text"," "], + ["identifier","warnings"], + ["text",";"] +],[ + "start", + ["keyword","my"], + ["text"," "], + ["identifier","$num_primes"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["constant.numeric","0"], + ["text",";"] +],[ + "start", + ["keyword","my"], + ["text"," @"], + ["identifier","primes"], + ["text",";"] +],[ + "start" +],[ + "start", + ["comment","# Put 2 as the first prime so we won't have an empty array"] +],[ + "start", + ["identifier","$primes"], + ["lparen","["], + ["identifier","$num_primes"], + ["rparen","]"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["constant.numeric","2"], + ["text",";"] +],[ + "start", + ["identifier","$num_primes"], + ["keyword.operator","++"], + ["text",";"] +],[ + "start" +],[ + "start", + ["identifier","MAIN_LOOP"], + ["text",":"] +],[ + "start", + ["keyword","for"], + ["text"," "], + ["keyword","my"], + ["text"," "], + ["identifier","$number_to_check"], + ["text"," "], + ["lparen","("], + ["constant.numeric","3"], + ["text"," "], + ["keyword.operator",".."], + ["text"," "], + ["constant.numeric","200"], + ["rparen",")"] +],[ + "start", + ["lparen","{"] +],[ + "start", + ["text"," "], + ["keyword","for"], + ["text"," "], + ["keyword","my"], + ["text"," "], + ["identifier","$p"], + ["text"," "], + ["lparen","("], + ["constant.numeric","0"], + ["text"," "], + ["keyword.operator",".."], + ["text"," "], + ["lparen","("], + ["identifier","$num_primes"], + ["constant.numeric","-1"], + ["rparen","))"] +],[ + "start", + ["text"," "], + ["lparen","{"] +],[ + "start", + ["text"," "], + ["keyword","if"], + ["text"," "], + ["lparen","("], + ["identifier","$number_to_check"], + ["text"," "], + ["keyword.operator","%"], + ["text"," "], + ["identifier","$primes"], + ["lparen","["], + ["identifier","$p"], + ["rparen","]"], + ["text"," "], + ["keyword.operator","=="], + ["text"," "], + ["constant.numeric","0"], + ["rparen",")"] +],[ + "start", + ["text"," "], + ["lparen","{"] +],[ + "start", + ["text"," "], + ["keyword","next"], + ["text"," "], + ["identifier","MAIN_LOOP"], + ["text",";"] +],[ + "start", + ["text"," "], + ["rparen","}"] +],[ + "start", + ["text"," "], + ["rparen","}"] +],[ + "start" +],[ + "start", + ["text"," "], + ["comment","# If we reached this point it means $number_to_check is not"] +],[ + "start", + ["text"," "], + ["comment","# divisable by any prime number that came before it."] +],[ + "start", + ["text"," "], + ["identifier","$primes"], + ["lparen","["], + ["identifier","$num_primes"], + ["rparen","]"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["identifier","$number_to_check"], + ["text",";"] +],[ + "start", + ["text"," "], + ["identifier","$num_primes"], + ["keyword.operator","++"], + ["text",";"] +],[ + "start", + ["rparen","}"] +],[ + "start" +],[ + "start", + ["keyword","for"], + ["text"," "], + ["keyword","my"], + ["text"," "], + ["identifier","$p"], + ["text"," "], + ["lparen","("], + ["constant.numeric","0"], + ["text"," "], + ["keyword.operator",".."], + ["text"," "], + ["lparen","("], + ["identifier","$num_primes"], + ["constant.numeric","-1"], + ["rparen","))"] +],[ + "start", + ["lparen","{"] +],[ + "start", + ["text"," "], + ["support.function","print"], + ["text"," "], + ["identifier","$primes"], + ["lparen","["], + ["identifier","$p"], + ["rparen","]"], + ["keyword.operator",","], + ["text"," "], + ["string","\", \""], + ["text",";"] +],[ + "start", + ["rparen","}"] +],[ + "start", + ["support.function","print"], + ["text"," "], + ["string","\"\\n\""], + ["text",";"] +],[ + "start" +],[ + "start" +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_pgsql.json b/node_modules/ace/lib/ace/mode/_test/tokens_pgsql.json new file mode 100644 index 00000000..fef23fd2 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_pgsql.json @@ -0,0 +1,889 @@ +[[ + "start" +],[ + "start", + ["keyword.statementBegin","BEGIN"], + ["statementEnd",";"] +],[ + "start" +],[ + "doc-start", + ["comment.doc","/**"] +],[ + "doc-start", + ["comment.doc","* Samples from PostgreSQL src/tutorial/basics.source"] +],[ + "start", + ["comment.doc","*/"] +],[ + "statement", + ["keyword.statementBegin","CREATE"], + ["text"," "], + ["keyword","TABLE"], + ["text"," "], + ["identifier","weather"], + ["text"," "], + ["paren.lparen","("] +],[ + "statement", + ["text","\t"], + ["identifier","city"], + ["text","\t\t"], + ["keyword","varchar"], + ["paren.lparen","("], + ["constant.numeric","80"], + ["paren.rparen",")"], + ["text",","] +],[ + "statement", + ["text","\t"], + ["identifier","temp_lo"], + ["text","\t\t"], + ["keyword","int"], + ["text",",\t\t"], + ["comment","-- low temperature"] +],[ + "statement", + ["text","\t"], + ["identifier","temp_hi"], + ["text","\t\t"], + ["keyword","int"], + ["text",",\t\t"], + ["comment","-- high temperature"] +],[ + "statement", + ["text","\t"], + ["identifier","prcp"], + ["text","\t\t"], + ["keyword","real"], + ["text",",\t\t"], + ["comment","-- precipitation"] +],[ + "statement", + ["text","\t"], + ["variable.language","\"date\""], + ["text","\t\t"], + ["keyword","date"] +],[ + "start", + ["paren.rparen",")"], + ["statementEnd",";"] +],[ + "start" +],[ + "statement", + ["keyword.statementBegin","CREATE"], + ["text"," "], + ["keyword","TABLE"], + ["text"," "], + ["identifier","cities"], + ["text"," "], + ["paren.lparen","("] +],[ + "statement", + ["text","\t"], + ["keyword","name"], + ["text","\t\t"], + ["keyword","varchar"], + ["paren.lparen","("], + ["constant.numeric","80"], + ["paren.rparen",")"], + ["text",","] +],[ + "statement", + ["text","\t"], + ["keyword","location"], + ["text","\t"], + ["keyword","point"] +],[ + "start", + ["paren.rparen",")"], + ["statementEnd",";"] +],[ + "start" +],[ + "start" +],[ + "statement", + ["keyword.statementBegin","INSERT"], + ["text"," "], + ["keyword","INTO"], + ["text"," "], + ["identifier","weather"] +],[ + "start", + ["text"," "], + ["keyword","VALUES"], + ["text"," "], + ["paren.lparen","("], + ["string","'San Francisco'"], + ["text",", "], + ["constant.numeric","46"], + ["text",", "], + ["constant.numeric","50"], + ["text",", "], + ["constant.numeric","0.25"], + ["text",", "], + ["string","'1994-11-27'"], + ["paren.rparen",")"], + ["statementEnd",";"] +],[ + "start" +],[ + "statement", + ["keyword.statementBegin","INSERT"], + ["text"," "], + ["keyword","INTO"], + ["text"," "], + ["identifier","cities"] +],[ + "start", + ["text"," "], + ["keyword","VALUES"], + ["text"," "], + ["paren.lparen","("], + ["string","'San Francisco'"], + ["text",", "], + ["string","'(-194.0, 53.0)'"], + ["paren.rparen",")"], + ["statementEnd",";"] +],[ + "start" +],[ + "statement", + ["keyword.statementBegin","INSERT"], + ["text"," "], + ["keyword","INTO"], + ["text"," "], + ["identifier","weather"], + ["text"," "], + ["paren.lparen","("], + ["identifier","city"], + ["text",", "], + ["identifier","temp_lo"], + ["text",", "], + ["identifier","temp_hi"], + ["text",", "], + ["identifier","prcp"], + ["text",", "], + ["variable.language","\"date\""], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["keyword","VALUES"], + ["text"," "], + ["paren.lparen","("], + ["string","'San Francisco'"], + ["text",", "], + ["constant.numeric","43"], + ["text",", "], + ["constant.numeric","57"], + ["text",", "], + ["constant.numeric","0.0"], + ["text",", "], + ["string","'1994-11-29'"], + ["paren.rparen",")"], + ["statementEnd",";"] +],[ + "start" +],[ + "statement", + ["keyword.statementBegin","INSERT"], + ["text"," "], + ["keyword","INTO"], + ["text"," "], + ["identifier","weather"], + ["text"," "], + ["paren.lparen","("], + ["keyword","date"], + ["text",", "], + ["identifier","city"], + ["text",", "], + ["identifier","temp_hi"], + ["text",", "], + ["identifier","temp_lo"], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["keyword","VALUES"], + ["text"," "], + ["paren.lparen","("], + ["string","'1994-11-29'"], + ["text",", "], + ["string","'Hayward'"], + ["text",", "], + ["constant.numeric","54"], + ["text",", "], + ["constant.numeric","37"], + ["paren.rparen",")"], + ["statementEnd",";"] +],[ + "start" +],[ + "start" +],[ + "start", + ["keyword.statementBegin","SELECT"], + ["text"," "], + ["identifier","city"], + ["text",", "], + ["paren.lparen","("], + ["identifier","temp_hi"], + ["keyword.operator","+"], + ["identifier","temp_lo"], + ["paren.rparen",")"], + ["keyword.operator","/"], + ["constant.numeric","2"], + ["text"," "], + ["keyword","AS"], + ["text"," "], + ["identifier","temp_avg"], + ["text",", "], + ["variable.language","\"date\""], + ["text"," "], + ["keyword","FROM"], + ["text"," "], + ["identifier","weather"], + ["statementEnd",";"] +],[ + "start" +],[ + "statement", + ["keyword.statementBegin","SELECT"], + ["text"," "], + ["identifier","city"], + ["text",", "], + ["identifier","temp_lo"], + ["text",", "], + ["identifier","temp_hi"], + ["text",", "], + ["identifier","prcp"], + ["text",", "], + ["variable.language","\"date\""], + ["text",", "], + ["keyword","location"] +],[ + "statement", + ["text"," "], + ["keyword","FROM"], + ["text"," "], + ["identifier","weather"], + ["text",", "], + ["identifier","cities"] +],[ + "start", + ["text"," "], + ["keyword","WHERE"], + ["text"," "], + ["identifier","city"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["keyword","name"], + ["statementEnd",";"] +],[ + "start" +],[ + "start" +],[ + "start" +],[ + "doc-start", + ["comment.doc","/**"] +],[ + "doc-start", + ["comment.doc","* Dollar quotes starting at the end of the line are colored as SQL unless"] +],[ + "doc-start", + ["comment.doc","* a special language tag is used. Dollar quote syntax coloring is implemented"] +],[ + "doc-start", + ["comment.doc","* for Perl, Python, JavaScript, and Json."] +],[ + "start", + ["comment.doc","*/"] +],[ + "statement", + ["keyword.statementBegin","create"], + ["text"," "], + ["keyword","or"], + ["text"," "], + ["keyword","replace"], + ["text"," "], + ["keyword","function"], + ["text"," "], + ["identifier","blob_content_chunked"], + ["paren.lparen","("] +],[ + "statement", + ["text"," "], + ["keyword","in"], + ["text"," "], + ["identifier","p_data"], + ["text"," "], + ["keyword","bytea"], + ["text",", "] +],[ + "statement", + ["text"," "], + ["keyword","in"], + ["text"," "], + ["identifier","p_chunk"], + ["text"," "], + ["keyword","integer"], + ["paren.rparen",")"] +],[ + "dollarSql", + ["keyword","returns"], + ["text"," "], + ["keyword","setof"], + ["text"," "], + ["keyword","bytea"], + ["text"," "], + ["keyword","as"], + ["text"," "], + ["string","$$"] +],[ + "dollarSql", + ["comment","-- Still SQL comments"] +],[ + "dollarSql", + ["keyword","declare"] +],[ + "dollarSql", + ["text","\t"], + ["identifier","v_size"], + ["text"," "], + ["keyword","integer"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["support.function","octet_length"], + ["paren.lparen","("], + ["identifier","p_data"], + ["paren.rparen",")"], + ["text",";"] +],[ + "dollarSql", + ["keyword","begin"] +],[ + "dollarSql", + ["text","\t"], + ["keyword","for"], + ["text"," "], + ["identifier","i"], + ["text"," "], + ["keyword","in"], + ["text"," "], + ["constant.numeric","1"], + ["text",".."], + ["identifier","v_size"], + ["text"," "], + ["keyword","by"], + ["text"," "], + ["identifier","p_chunk"], + ["text"," "], + ["identifier","loop"] +],[ + "dollarSql", + ["text","\t\t"], + ["identifier","return"], + ["text"," "], + ["keyword","next"], + ["text"," "], + ["keyword","substring"], + ["paren.lparen","("], + ["identifier","p_data"], + ["text"," "], + ["keyword","from"], + ["text"," "], + ["identifier","i"], + ["text"," "], + ["keyword","for"], + ["text"," "], + ["identifier","p_chunk"], + ["paren.rparen",")"], + ["text",";"] +],[ + "dollarSql", + ["text","\t"], + ["keyword","end"], + ["text"," "], + ["identifier","loop"], + ["text",";"] +],[ + "dollarSql", + ["keyword","end"], + ["text",";"] +],[ + "start", + ["string","$$"], + ["text"," "], + ["keyword","language"], + ["text"," "], + ["identifier","plpgsql"], + ["text"," "], + ["keyword","stable"], + ["statementEnd",";"] +],[ + "start" +],[ + "start" +],[ + "start", + ["comment","-- pl/perl"] +],[ + "perl-start", + ["keyword.statementBegin","CREATE"], + ["text"," "], + ["keyword","FUNCTION"], + ["text"," "], + ["identifier","perl_max"], + ["text"," "], + ["paren.lparen","("], + ["keyword","integer"], + ["text",", "], + ["keyword","integer"], + ["paren.rparen",")"], + ["text"," "], + ["keyword","RETURNS"], + ["text"," "], + ["keyword","integer"], + ["text"," "], + ["keyword","AS"], + ["text"," "], + ["string","$perl$"] +],[ + "perl-start", + ["text"," "], + ["comment","# perl comment..."] +],[ + "perl-start", + ["text"," "], + ["keyword","my"], + ["text"," "], + ["lparen","("], + ["identifier","$x"], + ["keyword.operator",","], + ["identifier","$y"], + ["rparen",")"], + ["text"," "], + ["keyword.operator","="], + ["text"," @"], + ["identifier","_"], + ["text",";"] +],[ + "perl-start", + ["text"," "], + ["keyword","if"], + ["text"," "], + ["lparen","("], + ["keyword.operator","!"], + ["text"," "], + ["support.function","defined"], + ["text"," "], + ["identifier","$x"], + ["rparen",")"], + ["text"," "], + ["lparen","{"] +],[ + "perl-start", + ["text"," "], + ["keyword","if"], + ["text"," "], + ["lparen","("], + ["keyword.operator","!"], + ["text"," "], + ["support.function","defined"], + ["text"," "], + ["identifier","$y"], + ["rparen",")"], + ["text"," "], + ["lparen","{"], + ["text"," "], + ["support.function","return"], + ["text"," "], + ["support.function","undef"], + ["text","; "], + ["rparen","}"] +],[ + "perl-start", + ["text"," "], + ["support.function","return"], + ["text"," "], + ["identifier","$y"], + ["text",";"] +],[ + "perl-start", + ["text"," "], + ["rparen","}"] +],[ + "perl-start", + ["text"," "], + ["keyword","if"], + ["text"," "], + ["lparen","("], + ["keyword.operator","!"], + ["text"," "], + ["support.function","defined"], + ["text"," "], + ["identifier","$y"], + ["rparen",")"], + ["text"," "], + ["lparen","{"], + ["text"," "], + ["support.function","return"], + ["text"," "], + ["identifier","$x"], + ["text","; "], + ["rparen","}"] +],[ + "perl-start", + ["text"," "], + ["keyword","if"], + ["text"," "], + ["lparen","("], + ["identifier","$x"], + ["text"," "], + ["keyword.operator",">"], + ["text"," "], + ["identifier","$y"], + ["rparen",")"], + ["text"," "], + ["lparen","{"], + ["text"," "], + ["support.function","return"], + ["text"," "], + ["identifier","$x"], + ["text","; "], + ["rparen","}"] +],[ + "perl-start", + ["text"," "], + ["support.function","return"], + ["text"," "], + ["identifier","$y"], + ["text",";"] +],[ + "start", + ["string","$perl$"], + ["text"," "], + ["keyword","LANGUAGE"], + ["text"," "], + ["identifier","plperl"], + ["statementEnd",";"] +],[ + "start" +],[ + "start", + ["comment","-- pl/python"] +],[ + "python-start", + ["keyword.statementBegin","CREATE"], + ["text"," "], + ["keyword","FUNCTION"], + ["text"," "], + ["identifier","usesavedplan"], + ["paren.lparen","("], + ["paren.rparen",")"], + ["text"," "], + ["keyword","RETURNS"], + ["text"," "], + ["keyword","trigger"], + ["text"," "], + ["keyword","AS"], + ["text"," "], + ["string","$python$"] +],[ + "python-start", + ["text"," "], + ["comment","# python comment..."] +],[ + "python-start", + ["text"," "], + ["keyword","if"], + ["text"," "], + ["identifier","SD"], + ["text","."], + ["identifier","has_key"], + ["paren.lparen","("], + ["string","\"plan\""], + ["paren.rparen",")"], + ["text",":"] +],[ + "python-start", + ["text"," "], + ["identifier","plan"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["identifier","SD"], + ["paren.lparen","["], + ["string","\"plan\""], + ["paren.rparen","]"] +],[ + "python-start", + ["text"," "], + ["keyword","else"], + ["text",":"] +],[ + "python-start", + ["text"," "], + ["identifier","plan"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["identifier","plpy"], + ["text","."], + ["identifier","prepare"], + ["paren.lparen","("], + ["string","\"SELECT 1\""], + ["paren.rparen",")"] +],[ + "python-start", + ["text"," "], + ["identifier","SD"], + ["paren.lparen","["], + ["string","\"plan\""], + ["paren.rparen","]"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["identifier","plan"] +],[ + "start", + ["string","$python$"], + ["text"," "], + ["keyword","LANGUAGE"], + ["text"," "], + ["identifier","plpythonu"], + ["statementEnd",";"] +],[ + "start" +],[ + "start", + ["comment","-- pl/v8 (javascript)"] +],[ + "javascript-start", + ["keyword.statementBegin","CREATE"], + ["text"," "], + ["keyword","FUNCTION"], + ["text"," "], + ["identifier","plv8_test"], + ["paren.lparen","("], + ["identifier","keys"], + ["text"," "], + ["keyword","text"], + ["text","[], "], + ["identifier","vals"], + ["text"," "], + ["keyword","text"], + ["text","[]"], + ["paren.rparen",")"], + ["text"," "], + ["keyword","RETURNS"], + ["text"," "], + ["keyword","text"], + ["text"," "], + ["keyword","AS"], + ["text"," "], + ["string","$javascript$"] +],[ + "javascript-start", + ["storage.type","var"], + ["text"," "], + ["identifier","o"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["paren.lparen","{"], + ["paren.rparen","}"], + ["punctuation.operator",";"] +],[ + "javascript-start", + ["keyword","for"], + ["paren.lparen","("], + ["storage.type","var"], + ["text"," "], + ["identifier","i"], + ["keyword.operator","="], + ["constant.numeric","0"], + ["punctuation.operator",";"], + ["text"," "], + ["identifier","i"], + ["keyword.operator","<"], + ["identifier","keys"], + ["punctuation.operator","."], + ["support.constant","length"], + ["punctuation.operator",";"], + ["text"," "], + ["identifier","i"], + ["keyword.operator","++"], + ["paren.rparen",")"], + ["paren.lparen","{"] +],[ + "javascript-start", + ["text"," "], + ["identifier","o"], + ["paren.lparen","["], + ["identifier","keys"], + ["paren.lparen","["], + ["identifier","i"], + ["paren.rparen","]]"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["identifier","vals"], + ["paren.lparen","["], + ["identifier","i"], + ["paren.rparen","]"], + ["punctuation.operator",";"] +],[ + "javascript-no_regex", + ["paren.rparen","}"] +],[ + "javascript-start", + ["keyword","return"], + ["text"," "], + ["variable.language","JSON"], + ["punctuation.operator","."], + ["identifier","stringify"], + ["paren.lparen","("], + ["identifier","o"], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + "start", + ["string","$javascript$"], + ["text"," "], + ["keyword","LANGUAGE"], + ["text"," "], + ["identifier","plv8"], + ["text"," "], + ["keyword","IMMUTABLE"], + ["text"," "], + ["keyword","STRICT"], + ["statementEnd",";"] +],[ + "start" +],[ + "start", + ["comment","-- json"] +],[ + "json-start", + ["keyword.statementBegin","select"], + ["text"," "], + ["keyword.operator","*"], + ["text"," "], + ["keyword","from"], + ["text"," "], + ["support.function","json_object_keys"], + ["paren.lparen","("], + ["string","$json$"] +],[ + "json-start", + ["paren.lparen","{"] +],[ + "json-start", + ["text"," "], + ["variable","\"f1\""], + ["text",": "], + ["constant.numeric","5"], + ["text",","] +],[ + "json-start", + ["text"," "], + ["variable","\"f2\""], + ["text",": "], + ["string","\"test\""], + ["text",","] +],[ + "json-start", + ["text"," "], + ["variable","\"f3\""], + ["text",": "], + ["paren.lparen","{"], + ["paren.rparen","}"] +],[ + "json-start", + ["paren.rparen","}"] +],[ + "start", + ["string","$json$"], + ["paren.rparen",")"], + ["statementEnd",";"] +],[ + "start" +],[ + "start" +],[ + "start", + ["comment","-- psql commands"] +],[ + "start", + ["support.buildin","\\df cash*"] +],[ + "start" +],[ + "start" +],[ + "start", + ["comment","-- Some string samples."] +],[ + "start", + ["keyword.statementBegin","select"], + ["text"," "], + ["string","'don''t do it now;'"], + ["text"," "], + ["keyword.operator","||"], + ["text"," "], + ["string","'maybe later'"], + ["statementEnd",";"] +],[ + "start", + ["keyword.statementBegin","select"], + ["text"," "], + ["identifier","E"], + ["string","'dont\\'t do it'"], + ["statementEnd",";"] +],[ + "start", + ["keyword.statementBegin","select"], + ["text"," "], + ["support.function","length"], + ["paren.lparen","("], + ["string","'some other''s stuff'"], + ["text"," "], + ["keyword.operator","||"], + ["text"," "], + ["string","$$cat in hat's stuff $$"], + ["paren.rparen",")"], + ["statementEnd",";"] +],[ + "start" +],[ + "dollarStatementString", + ["keyword.statementBegin","select"], + ["text"," "], + ["string","$$ strings"] +],[ + "dollarStatementString", + ["string","over multiple "] +],[ + "dollarStatementString", + ["string","lines - use dollar quotes"] +],[ + "start", + ["string","$$"], + ["statementEnd",";"] +],[ + "start" +],[ + "start", + ["keyword.statementBegin","END"], + ["statementEnd",";"] +],[ + "start" +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_php.json b/node_modules/ace/lib/ace/mode/_test/tokens_php.json new file mode 100644 index 00000000..2134dccb --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_php.json @@ -0,0 +1,171 @@ +[[ + "php-start", + ["support.php_tag",""], + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.script.tag-name.xml","script"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text"," "], + ["support.php_tag",""] +],[ + "js-comment_regex_allowed", + ["comment","/*this is js "], + ["support.php_tag",""] +],[ + "start", + ["meta.tag.punctuation.end-tag-open.xml",""], + ["text.xml"," not "], + ["constant.language.escape.reference.xml","&js;"] +],[ + "start" +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_powershell.json b/node_modules/ace/lib/ace/mode/_test/tokens_powershell.json new file mode 100644 index 00000000..43b77db4 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_powershell.json @@ -0,0 +1,184 @@ +[[ + "start", + ["comment","# This is a simple comment"] +],[ + "start", + ["keyword","function"], + ["text"," "], + ["identifier","Hello"], + ["lparen","("], + ["variable.instance","$name"], + ["rparen",")"], + ["text"," "], + ["lparen","{"] +],[ + "start", + ["text"," "], + ["identifier","Write-host"], + ["text"," "], + ["string","\"Hello $name\""] +],[ + "start", + ["rparen","}"] +],[ + "start" +],[ + "start", + ["keyword","function"], + ["text"," "], + ["identifier","add"], + ["lparen","("], + ["variable.instance","$left"], + ["text",", "], + ["variable.instance","$right"], + ["keyword.operator","="], + ["constant.numeric","4"], + ["rparen",")"], + ["text"," "], + ["lparen","{"] +],[ + "start", + ["text"," "], + ["keyword","if"], + ["text"," "], + ["lparen","("], + ["variable.instance","$right"], + ["text"," "], + ["keyword.operator","-ne"], + ["text"," "], + ["constant.numeric","4"], + ["rparen",")"], + ["text"," "], + ["lparen","{"] +],[ + "start", + ["text"," "], + ["keyword","return"], + ["text"," "], + ["variable.instance","$left"] +],[ + "start", + ["text"," "], + ["rparen","}"], + ["text"," "], + ["keyword","elseif"], + ["text"," "], + ["lparen","("], + ["variable.instance","$left"], + ["text"," "], + ["keyword.operator","-eq"], + ["text"," "], + ["constant.language","$null"], + ["text"," "], + ["keyword.operator","-and"], + ["text"," "], + ["variable.instance","$right"], + ["text"," "], + ["keyword.operator","-eq"], + ["text"," "], + ["constant.numeric","2"], + ["rparen",")"], + ["text"," "], + ["lparen","{"] +],[ + "start", + ["text"," "], + ["keyword","return"], + ["text"," "], + ["constant.numeric","3"] +],[ + "start", + ["text"," "], + ["rparen","}"], + ["text"," "], + ["keyword","else"], + ["text"," "], + ["lparen","{"] +],[ + "start", + ["text"," "], + ["keyword","return"], + ["text"," "], + ["constant.numeric","2"] +],[ + "start", + ["text"," "], + ["rparen","}"] +],[ + "start", + ["rparen","}"] +],[ + "start" +],[ + "start", + ["variable.instance","$number"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["constant.numeric","1"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["constant.numeric","2"], + ["text",";"] +],[ + "start", + ["variable.instance","$number"], + ["text"," "], + ["keyword.operator","+="], + ["text"," "], + ["constant.numeric","3"] +],[ + "start" +],[ + "start", + ["support.function","Write-Host"], + ["text"," "], + ["identifier","Hello"], + ["text"," "], + ["keyword.operator","-"], + ["identifier","name"], + ["text"," "], + ["string","\"World\""] +],[ + "start" +],[ + "start", + ["variable.instance","$an_array"], + ["text"," "], + ["keyword.operator","="], + ["text"," @"], + ["lparen","("], + ["constant.numeric","1"], + ["text",", "], + ["constant.numeric","2"], + ["text",", "], + ["constant.numeric","3"], + ["rparen",")"] +],[ + "start", + ["variable.instance","$a_hash"], + ["text"," "], + ["keyword.operator","="], + ["text"," @"], + ["lparen","{"], + ["string","\"something\""], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["string","\"something else\""], + ["rparen","}"] +],[ + "start" +],[ + "start", + ["keyword.operator","&"], + ["text"," "], + ["identifier","notepad"], + ["text"," .\\"], + ["identifier","readme"], + ["text","."], + ["identifier","md"] +],[ + "start" +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_prolog.json b/node_modules/ace/lib/ace/mode/_test/tokens_prolog.json new file mode 100644 index 00000000..4c0f5c5c --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_prolog.json @@ -0,0 +1,245 @@ +[[ + "start", + ["entity.name.function.fact.prolog","partition"], + ["punctuation.begin.fact.parameters.prolog","("], + ["punctuation.begin.list.prolog","["], + ["punctuation.end.list.prolog","]"], + ["punctuation.separator.parameters.prolog",","], + ["meta.fact.prolog"," "], + ["variable.language.anonymous.prolog","_"], + ["punctuation.separator.parameters.prolog",","], + ["meta.fact.prolog"," "], + ["punctuation.begin.list.prolog","["], + ["punctuation.end.list.prolog","]"], + ["punctuation.separator.parameters.prolog",","], + ["meta.fact.prolog"," "], + ["punctuation.begin.list.prolog","["], + ["punctuation.end.list.prolog","]"], + ["punctuation.end.fact.parameters.prolog",")"], + ["punctuation.end.fact.prolog","."] +],[ + ["keyword.operator.definition.prolog","meta.rule.prolog"], + ["entity.name.function.rule.prolog","partition"], + ["punctuation.rule.parameters.begin.prolog","("], + ["punctuation.begin.list.prolog","["], + ["variable.other.prolog","X"], + ["punctuation.concat.list.prolog","|"], + ["variable.other.prolog","Xs"], + ["punctuation.end.list.prolog","]"], + ["punctuation.separator.parameters.prolog",","], + ["meta.rule.parameters.prolog"," "], + ["variable.parameter.prolog","Pivot"], + ["punctuation.separator.parameters.prolog",","], + ["meta.rule.parameters.prolog"," "], + ["variable.parameter.prolog","Smalls"], + ["punctuation.separator.parameters.prolog",","], + ["meta.rule.parameters.prolog"," "], + ["variable.parameter.prolog","Bigs"], + ["punctuation.rule.parameters.end.prolog",")"], + ["meta.rule.signature.prolog"," "], + ["keyword.operator.definition.prolog",":-"] +],[ + ["meta.expression.prolog","keyword.operator.definition.prolog","keyword.operator.definition.prolog","meta.rule.prolog"], + ["meta.rule.definition.prolog"," "], + ["meta.expression.prolog","( "], + ["variable.other.prolog","X"], + ["meta.expression.prolog"," @"], + ["keyword.operator.prolog","<"], + ["meta.expression.prolog"," "], + ["variable.other.prolog","Pivot"], + ["meta.expression.prolog"," "], + ["keyword.operator.prolog","->"] +],[ + ["meta.expression.prolog","keyword.operator.definition.prolog","keyword.operator.definition.prolog","meta.rule.prolog"], + ["meta.expression.prolog"," "], + ["variable.other.prolog","Smalls"], + ["meta.expression.prolog"," "], + ["keyword.operator.prolog","="], + ["meta.expression.prolog"," "], + ["punctuation.begin.list.prolog","["], + ["variable.other.prolog","X"], + ["punctuation.concat.list.prolog","|"], + ["variable.other.prolog","Rest"], + ["punctuation.end.list.prolog","]"], + ["punctuation.control.and.prolog",","] +],[ + ["meta.expression.prolog","keyword.operator.definition.prolog","keyword.operator.definition.prolog","meta.rule.prolog"], + ["meta.expression.prolog"," "], + ["constant.other.atom.prolog","partition"], + ["punctuation.begin.statement.parameters.prolog","("], + ["variable.other.prolog","Xs"], + ["punctuation.separator.statement.prolog",","], + ["meta.statement.parameters.prolog"," "], + ["variable.other.prolog","Pivot"], + ["punctuation.separator.statement.prolog",","], + ["meta.statement.parameters.prolog"," "], + ["variable.other.prolog","Rest"], + ["punctuation.separator.statement.prolog",","], + ["meta.statement.parameters.prolog"," "], + ["variable.other.prolog","Bigs"], + ["punctuation.end.statement.parameters.prolog",")"] +],[ + ["meta.expression.prolog","keyword.operator.definition.prolog","keyword.operator.definition.prolog","meta.rule.prolog"], + ["meta.expression.prolog"," "], + ["punctuation.control.or.prolog",";"], + ["meta.expression.prolog"," "], + ["variable.other.prolog","Bigs"], + ["meta.expression.prolog"," "], + ["keyword.operator.prolog","="], + ["meta.expression.prolog"," "], + ["punctuation.begin.list.prolog","["], + ["variable.other.prolog","X"], + ["punctuation.concat.list.prolog","|"], + ["variable.other.prolog","Rest"], + ["punctuation.end.list.prolog","]"], + ["punctuation.control.and.prolog",","] +],[ + ["meta.expression.prolog","keyword.operator.definition.prolog","keyword.operator.definition.prolog","meta.rule.prolog"], + ["meta.expression.prolog"," "], + ["constant.other.atom.prolog","partition"], + ["punctuation.begin.statement.parameters.prolog","("], + ["variable.other.prolog","Xs"], + ["punctuation.separator.statement.prolog",","], + ["meta.statement.parameters.prolog"," "], + ["variable.other.prolog","Pivot"], + ["punctuation.separator.statement.prolog",","], + ["meta.statement.parameters.prolog"," "], + ["variable.other.prolog","Smalls"], + ["punctuation.separator.statement.prolog",","], + ["meta.statement.parameters.prolog"," "], + ["variable.other.prolog","Rest"], + ["punctuation.end.statement.parameters.prolog",")"] +],[ + "start", + ["meta.expression.prolog"," )"], + ["punctuation.rule.end.prolog","."] +],[ + "start", + ["text"," "] +],[ + "start", + ["entity.name.function.fact.prolog","quicksort"], + ["punctuation.begin.fact.parameters.prolog","("], + ["punctuation.begin.list.prolog","["], + ["punctuation.end.list.prolog","]"], + ["punctuation.end.fact.parameters.prolog",")"], + ["text"," --> []."] +],[ + "start", + ["entity.name.function.fact.prolog","quicksort"], + ["punctuation.begin.fact.parameters.prolog","("], + ["punctuation.begin.list.prolog","["], + ["variable.other.prolog","X"], + ["punctuation.concat.list.prolog","|"], + ["variable.other.prolog","Xs"], + ["punctuation.end.list.prolog","]"], + ["punctuation.end.fact.parameters.prolog",")"], + ["text"," -->"] +],[ + "start", + ["text"," { "], + ["entity.name.function.fact.prolog","partition"], + ["punctuation.begin.fact.parameters.prolog","("], + ["variable.parameter.prolog","Xs"], + ["punctuation.separator.parameters.prolog",","], + ["meta.fact.prolog"," "], + ["variable.parameter.prolog","X"], + ["punctuation.separator.parameters.prolog",","], + ["meta.fact.prolog"," "], + ["variable.parameter.prolog","Smaller"], + ["punctuation.separator.parameters.prolog",","], + ["meta.fact.prolog"," "], + ["variable.parameter.prolog","Bigger"], + ["punctuation.end.fact.parameters.prolog",")"], + ["text"," },"] +],[ + "start", + ["text"," "], + ["entity.name.function.fact.prolog","quicksort"], + ["punctuation.begin.fact.parameters.prolog","("], + ["variable.parameter.prolog","Smaller"], + ["punctuation.end.fact.parameters.prolog",")"], + ["text",", [X], "], + ["entity.name.function.fact.prolog","quicksort"], + ["punctuation.begin.fact.parameters.prolog","("], + ["variable.parameter.prolog","Bigger"], + ["punctuation.end.fact.parameters.prolog",")"], + ["punctuation.end.fact.prolog","."] +],[ + "start" +],[ + ["keyword.operator.definition.prolog","meta.rule.prolog"], + ["entity.name.function.rule.prolog","perfect"], + ["punctuation.rule.parameters.begin.prolog","("], + ["variable.parameter.prolog","N"], + ["punctuation.rule.parameters.end.prolog",")"], + ["meta.rule.signature.prolog"," "], + ["keyword.operator.definition.prolog",":-"] +],[ + ["keyword.operator.definition.prolog","meta.rule.prolog"], + ["meta.rule.definition.prolog"," "], + ["constant.other.atom.prolog","between"], + ["punctuation.begin.statement.parameters.prolog","("], + ["constant.numeric.prolog","1"], + ["punctuation.separator.statement.prolog",","], + ["meta.statement.parameters.prolog"," "], + ["constant.other.atom.prolog","inf"], + ["punctuation.separator.statement.prolog",","], + ["meta.statement.parameters.prolog"," "], + ["variable.other.prolog","N"], + ["punctuation.end.statement.parameters.prolog",")"], + ["punctuation.control.and.prolog",","], + ["meta.rule.definition.prolog"," "], + ["variable.other.prolog","U"], + ["meta.rule.definition.prolog"," "], + ["keyword.operator.prolog","is"], + ["meta.rule.definition.prolog"," "], + ["variable.other.prolog","N"], + ["meta.rule.definition.prolog"," // "], + ["constant.numeric.prolog","2"], + ["punctuation.control.and.prolog",","] +],[ + ["keyword.operator.definition.prolog","meta.rule.prolog"], + ["meta.rule.definition.prolog"," "], + ["constant.other.atom.prolog","findall"], + ["punctuation.begin.statement.parameters.prolog","("], + ["variable.other.prolog","D"], + ["punctuation.separator.statement.prolog",","], + ["meta.statement.parameters.prolog"," ("], + ["constant.other.atom.prolog","between"], + ["punctuation.begin.statement.parameters.prolog","("], + ["constant.numeric.prolog","1"], + ["punctuation.separator.statement.prolog",","], + ["variable.other.prolog","U"], + ["punctuation.separator.statement.prolog",","], + ["variable.other.prolog","D"], + ["punctuation.end.statement.parameters.prolog",")"], + ["punctuation.separator.statement.prolog",","], + ["meta.statement.parameters.prolog"," "], + ["variable.other.prolog","N"], + ["meta.statement.parameters.prolog"," "], + ["constant.other.atom.prolog","mod"], + ["meta.statement.parameters.prolog"," "], + ["variable.other.prolog","D"], + ["meta.statement.parameters.prolog"," "], + ["keyword.operator.prolog","=:="], + ["meta.statement.parameters.prolog"," "], + ["constant.numeric.prolog","0"], + ["punctuation.end.statement.parameters.prolog",")"], + ["punctuation.control.and.prolog",","], + ["meta.rule.definition.prolog"," "], + ["variable.other.prolog","Ds"], + ["meta.rule.definition.prolog",")"], + ["punctuation.control.and.prolog",","] +],[ + "start", + ["meta.rule.definition.prolog"," "], + ["constant.other.atom.prolog","sumlist"], + ["punctuation.begin.statement.parameters.prolog","("], + ["variable.other.prolog","Ds"], + ["punctuation.separator.statement.prolog",","], + ["meta.statement.parameters.prolog"," "], + ["variable.other.prolog","N"], + ["punctuation.end.statement.parameters.prolog",")"], + ["punctuation.rule.end.prolog","."] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_properties.json b/node_modules/ace/lib/ace/mode/_test/tokens_properties.json new file mode 100644 index 00000000..8831045e --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_properties.json @@ -0,0 +1,68 @@ +[[ + "start", + ["comment","# You are reading the \".properties\" entry."] +],[ + "start", + ["comment","! The exclamation mark can also mark text as comments."] +],[ + "start", + ["comment","# The key and element characters #, !, =, and : are written with a preceding backslash to ensure that they are properly loaded."] +],[ + "start", + ["variable","website "], + ["keyword","="], + ["string"," http"], + ["constant.language.escape","\\"], + ["string","://en.wikipedia.org/"] +],[ + "start", + ["variable","language "], + ["keyword","="], + ["string"," English"] +],[ + "start", + ["comment","# The backslash below tells the application to continue reading"] +],[ + "start", + ["comment","# the value onto the next line."] +],[ + "value", + ["variable","message "], + ["keyword","="], + ["string"," Welcome to \\"] +],[ + "start", + ["string"," Wikipedia!"] +],[ + "start", + ["comment","# Add spaces to the key"] +],[ + "start", + ["variable","key"], + ["constant.language.escape","\\"], + ["variable"," with"], + ["constant.language.escape","\\"], + ["variable"," spaces "], + ["keyword","="], + ["string"," This is the value that could be looked up with the key \"key with spaces\"."] +],[ + "start", + ["comment","# Unicode"] +],[ + "start", + ["variable","tab "], + ["keyword",":"], + ["string"," "], + ["constant.language.escape","\\u0009"] +],[ + "start", + ["variable","empty-key"], + ["keyword","="] +],[ + "start", + ["variable","last.line"], + ["keyword","="], + ["string","value"] +],[ + "start" +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_protobuf.json b/node_modules/ace/lib/ace/mode/_test/tokens_protobuf.json new file mode 100644 index 00000000..469dba06 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_protobuf.json @@ -0,0 +1,136 @@ +[[ + "start", + ["keyword.declaration.protobuf","message"], + ["text"," "], + ["identifier","Point"], + ["text"," {"] +],[ + "start", + ["text"," "], + ["keyword.declaration.protobuf","required"], + ["text"," "], + ["support.type","int32"], + ["text"," "], + ["identifier","x"], + ["text"," "], + ["keyword.operator.assignment.protobuf","="], + ["text"," "], + ["constant.numeric","1"], + ["text",";"] +],[ + "start", + ["text"," "], + ["keyword.declaration.protobuf","required"], + ["text"," "], + ["support.type","int32"], + ["text"," "], + ["identifier","y"], + ["text"," "], + ["keyword.operator.assignment.protobuf","="], + ["text"," "], + ["constant.numeric","2"], + ["text",";"] +],[ + "start", + ["text"," "], + ["keyword.declaration.protobuf","optional"], + ["text"," "], + ["support.type","string"], + ["text"," "], + ["identifier","label"], + ["text"," "], + ["keyword.operator.assignment.protobuf","="], + ["text"," "], + ["constant.numeric","3"], + ["text",";"] +],[ + "start", + ["text","}"] +],[ + "start" +],[ + "start", + ["keyword.declaration.protobuf","message"], + ["text"," "], + ["identifier","Line"], + ["text"," {"] +],[ + "start", + ["text"," "], + ["keyword.declaration.protobuf","required"], + ["text"," "], + ["identifier","Point"], + ["text"," "], + ["identifier","start"], + ["text"," "], + ["keyword.operator.assignment.protobuf","="], + ["text"," "], + ["constant.numeric","1"], + ["text",";"] +],[ + "start", + ["text"," "], + ["keyword.declaration.protobuf","required"], + ["text"," "], + ["identifier","Point"], + ["text"," "], + ["identifier","end"], + ["text"," "], + ["keyword.operator.assignment.protobuf","="], + ["text"," "], + ["constant.numeric","2"], + ["text",";"] +],[ + "start", + ["text"," "], + ["keyword.declaration.protobuf","optional"], + ["text"," "], + ["support.type","string"], + ["text"," "], + ["identifier","label"], + ["text"," "], + ["keyword.operator.assignment.protobuf","="], + ["text"," "], + ["constant.numeric","3"], + ["text",";"] +],[ + "start", + ["text","}"] +],[ + "start" +],[ + "start", + ["keyword.declaration.protobuf","message"], + ["text"," "], + ["identifier","Polyline"], + ["text"," {"] +],[ + "start", + ["text"," "], + ["keyword.declaration.protobuf","repeated"], + ["text"," "], + ["identifier","Point"], + ["text"," "], + ["identifier","point"], + ["text"," "], + ["keyword.operator.assignment.protobuf","="], + ["text"," "], + ["constant.numeric","1"], + ["text",";"] +],[ + "start", + ["text"," "], + ["keyword.declaration.protobuf","optional"], + ["text"," "], + ["support.type","string"], + ["text"," "], + ["identifier","label"], + ["text"," "], + ["keyword.operator.assignment.protobuf","="], + ["text"," "], + ["constant.numeric","2"], + ["text",";"] +],[ + "start", + ["text","}"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_python.json b/node_modules/ace/lib/ace/mode/_test/tokens_python.json new file mode 100644 index 00000000..293c8ff2 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_python.json @@ -0,0 +1,152 @@ +[[ + "start", + ["comment","#!/usr/local/bin/python"] +],[ + "start" +],[ + "start", + ["keyword","import"], + ["text"," "], + ["identifier","string"], + ["text",", "], + ["identifier","sys"] +],[ + "start" +],[ + "start", + ["comment","# If no arguments were given, print a helpful message"] +],[ + "start", + ["keyword","if"], + ["text"," "], + ["support.function","len"], + ["paren.lparen","("], + ["identifier","sys"], + ["text","."], + ["identifier","argv"], + ["paren.rparen",")"], + ["keyword.operator","=="], + ["constant.numeric","1"], + ["text",":"] +],[ + "qstring3", + ["text"," "], + ["keyword","print"], + ["text"," "], + ["string","'''Usage:"] +],[ + "start", + ["string","celsius temp1 temp2 ...'''"] +],[ + "start", + ["text"," "], + ["identifier","sys"], + ["text","."], + ["identifier","exit"], + ["paren.lparen","("], + ["constant.numeric","0"], + ["paren.rparen",")"] +],[ + "start" +],[ + "start", + ["comment","# Loop over the arguments"] +],[ + "start", + ["keyword","for"], + ["text"," "], + ["identifier","i"], + ["text"," "], + ["keyword","in"], + ["text"," "], + ["identifier","sys"], + ["text","."], + ["identifier","argv"], + ["paren.lparen","["], + ["constant.numeric","1"], + ["text",":"], + ["paren.rparen","]"], + ["text",":"] +],[ + "start", + ["text"," "], + ["keyword","try"], + ["text",":"] +],[ + "start", + ["text"," "], + ["identifier","fahrenheit"], + ["keyword.operator","="], + ["support.function","float"], + ["paren.lparen","("], + ["identifier","string"], + ["text","."], + ["identifier","atoi"], + ["paren.lparen","("], + ["identifier","i"], + ["paren.rparen","))"] +],[ + "start", + ["text"," "], + ["keyword","except"], + ["text"," "], + ["identifier","string"], + ["text","."], + ["identifier","atoi_error"], + ["text",":"] +],[ + "start", + ["text"," "], + ["keyword","print"], + ["text"," "], + ["support.function","repr"], + ["paren.lparen","("], + ["identifier","i"], + ["paren.rparen",")"], + ["text",", "], + ["string","\"not a numeric value\""] +],[ + "start", + ["text"," "], + ["keyword","else"], + ["text",":"] +],[ + "start", + ["text"," "], + ["identifier","celsius"], + ["keyword.operator","="], + ["paren.lparen","("], + ["identifier","fahrenheit"], + ["keyword.operator","-"], + ["constant.numeric","32"], + ["paren.rparen",")"], + ["keyword.operator","*"], + ["constant.numeric","5.0"], + ["keyword.operator","/"], + ["constant.numeric","9.0"] +],[ + "start", + ["text"," "], + ["keyword","print"], + ["text"," "], + ["string","'%i"], + ["constant.language.escape","\\260"], + ["string","F = %i"], + ["constant.language.escape","\\260"], + ["string","C'"], + ["text"," "], + ["keyword.operator","%"], + ["text"," "], + ["paren.lparen","("], + ["support.function","int"], + ["paren.lparen","("], + ["identifier","fahrenheit"], + ["paren.rparen",")"], + ["text",", "], + ["support.function","int"], + ["paren.lparen","("], + ["identifier","celsius"], + ["keyword.operator","+"], + ["constant.numeric",".5"], + ["paren.rparen","))"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_r.json b/node_modules/ace/lib/ace/mode/_test/tokens_r.json new file mode 100644 index 00000000..2d446bce --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_r.json @@ -0,0 +1,235 @@ +[[ + "start", + ["identifier","Call"], + ["keyword.operator",":"] +],[ + "start", + ["identifier","lm"], + ["paren.keyword.operator","("], + ["identifier","formula"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["identifier","y"], + ["text"," "], + ["keyword.operator","~"], + ["text"," "], + ["identifier","x"], + ["paren.keyword.operator",")"] +],[ + "start", + ["text"," "] +],[ + "start", + ["identifier","Residuals"], + ["keyword.operator",":"] +],[ + "start", + ["constant.numeric","1"], + ["text"," "], + ["constant.numeric","2"], + ["text"," "], + ["constant.numeric","3"], + ["text"," "], + ["constant.numeric","4"], + ["text"," "], + ["constant.numeric","5"], + ["text"," "], + ["constant.numeric","6"] +],[ + "start", + ["constant.numeric","3.3333"], + ["text"," "], + ["keyword.operator","-"], + ["constant.numeric","0.6667"], + ["text"," "], + ["keyword.operator","-"], + ["constant.numeric","2.6667"], + ["text"," "], + ["keyword.operator","-"], + ["constant.numeric","2.6667"], + ["text"," "], + ["keyword.operator","-"], + ["constant.numeric","0.6667"], + ["text"," "], + ["constant.numeric","3.3333"] +],[ + "start", + ["text"," "] +],[ + "start", + ["identifier","Coefficients"], + ["keyword.operator",":"] +],[ + "start", + ["text"," "], + ["identifier","Estimate"], + ["text"," "], + ["identifier","Std"], + ["text",". "], + ["identifier","Error"], + ["text"," "], + ["identifier","t"], + ["text"," "], + ["identifier","value"], + ["text"," "], + ["identifier","Pr"], + ["paren.keyword.operator","("], + ["keyword.operator",">|"], + ["identifier","t"], + ["keyword.operator","|"], + ["paren.keyword.operator",")"] +],[ + "start", + ["paren.keyword.operator","("], + ["identifier","Intercept"], + ["paren.keyword.operator",")"], + ["text"," "], + ["keyword.operator","-"], + ["constant.numeric","9.3333"], + ["text"," "], + ["constant.numeric","2.8441"], + ["text"," "], + ["keyword.operator","-"], + ["constant.numeric","3.282"], + ["text"," "], + ["constant.numeric","0.030453"], + ["text"," "], + ["keyword.operator","*"] +],[ + "start", + ["identifier","x"], + ["text"," "], + ["constant.numeric","7.0000"], + ["text"," "], + ["constant.numeric","0.7303"], + ["text"," "], + ["constant.numeric","9.585"], + ["text"," "], + ["constant.numeric","0.000662"], + ["text"," "], + ["keyword.operator","***"] +],[ + "start", + ["keyword.operator","---"] +],[ + "start", + ["identifier","Signif"], + ["text",". "], + ["identifier","codes"], + ["keyword.operator",":"], + ["text"," "], + ["constant.numeric","0"], + ["text"," ‘"], + ["keyword.operator","***"], + ["text","’ "], + ["constant.numeric","0.001"], + ["text"," ‘"], + ["keyword.operator","**"], + ["text","’ "], + ["constant.numeric","0.01"], + ["text"," ‘"], + ["keyword.operator","*"], + ["text","’ "], + ["constant.numeric","0.05"], + ["text"," ‘.’ "], + ["constant.numeric","0.1"], + ["text"," ‘ ’ "], + ["constant.numeric","1"] +],[ + "start", + ["text"," "] +],[ + "start", + ["identifier","Residual"], + ["text"," "], + ["identifier","standard"], + ["text"," "], + ["identifier","error"], + ["keyword.operator",":"], + ["text"," "], + ["constant.numeric","3.055"], + ["text"," "], + ["identifier","on"], + ["text"," "], + ["constant.numeric","4"], + ["text"," "], + ["identifier","degrees"], + ["text"," "], + ["identifier","of"], + ["text"," "], + ["identifier","freedom"] +],[ + "start", + ["identifier","Multiple"], + ["text"," "], + ["identifier","R"], + ["keyword.operator","-"], + ["identifier","squared"], + ["keyword.operator",":"], + ["text"," "], + ["constant.numeric","0.9583"], + ["text",", "], + ["identifier","Adjusted"], + ["text"," "], + ["identifier","R"], + ["keyword.operator","-"], + ["identifier","squared"], + ["keyword.operator",":"], + ["text"," "], + ["constant.numeric","0.9478"] +],[ + "start", + ["constant.language.boolean","F"], + ["keyword.operator","-"], + ["identifier","statistic"], + ["keyword.operator",":"], + ["text"," "], + ["constant.numeric","91.88"], + ["text"," "], + ["identifier","on"], + ["text"," "], + ["constant.numeric","1"], + ["text"," "], + ["identifier","and"], + ["text"," "], + ["constant.numeric","4"], + ["text"," "], + ["identifier","DF"], + ["text",", "], + ["identifier","p"], + ["keyword.operator","-"], + ["identifier","value"], + ["keyword.operator",":"], + ["text"," "], + ["constant.numeric","0.000662"] +],[ + "start", + ["text"," "] +],[ + "start", + ["keyword.operator",">"], + ["text"," "], + ["identifier","par"], + ["paren.keyword.operator","("], + ["identifier","mfrow"], + ["keyword.operator","="], + ["identifier","c"], + ["paren.keyword.operator","("], + ["constant.numeric","2"], + ["text",", "], + ["constant.numeric","2"], + ["paren.keyword.operator","))"], + ["text"," "], + ["comment","# Request 2x2 plot layout"] +],[ + "start", + ["keyword.operator",">"], + ["text"," "], + ["identifier","plot"], + ["paren.keyword.operator","("], + ["identifier","lm_1"], + ["paren.keyword.operator",")"], + ["text"," "], + ["comment","# Diagnostic plot of regression model"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_rdoc.json b/node_modules/ace/lib/ace/mode/_test/tokens_rdoc.json new file mode 100644 index 00000000..0c757438 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_rdoc.json @@ -0,0 +1,441 @@ +[[ + "start", + ["keyword","\\name"], + ["paren.keyword.operator","{"], + ["nospell.text","picker"], + ["paren.keyword.operator","}"] +],[ + "start", + ["keyword","\\alias"], + ["paren.keyword.operator","{"], + ["nospell.text","picker"], + ["paren.keyword.operator","}"] +],[ + "start", + ["keyword","\\title"], + ["paren.keyword.operator","{"], + ["text","Create a picker control"], + ["paren.keyword.operator","}"] +],[ + "start", + ["keyword","\\description"], + ["paren.keyword.operator","{"] +],[ + "start", + ["text"," Create a picker control to enable manipulation of plot variables based on a set of fixed choices."] +],[ + "start", + ["paren.keyword.operator","}"] +],[ + "start" +],[ + "nospell", + ["keyword","\\usage"], + ["paren.keyword.operator","{"] +],[ + "nospell", + ["nospell.text","picker"], + ["paren.keyword.operator","("], + ["text","...,"], + ["nospell.text"," initial "], + ["text","="], + ["nospell.text"," NULL"], + ["text",","], + ["nospell.text"," label "], + ["text","="], + ["nospell.text"," NULL"], + ["paren.keyword.operator",")"] +],[ + "start", + ["paren.keyword.operator","}"] +],[ + "start" +],[ + "start" +],[ + "start", + ["keyword","\\arguments"], + ["paren.keyword.operator","{"] +],[ + "start", + ["text"," "], + ["keyword","\\item"], + ["paren.keyword.operator","{"], + ["keyword","\\dots"], + ["paren.keyword.operator","}{"] +],[ + "start", + ["text"," Arguments containing objects to be presented as choices for the picker "], + ["paren.keyword.operator","("], + ["text","or a list containing the choices"], + ["paren.keyword.operator",")"], + ["text",". If an element is named then the name is used to display it within the picker. If an element is not named then it is displayed within the picker using "], + ["keyword","\\code"], + ["paren.keyword.operator","{"], + ["keyword","\\link"], + ["paren.keyword.operator","{"], + ["nospell.text","as"], + ["text","."], + ["nospell.text","character"], + ["paren.keyword.operator","}}"], + ["text",". "] +],[ + "start", + ["paren.keyword.operator","}"] +],[ + "start", + ["text"," "], + ["keyword","\\item"], + ["paren.keyword.operator","{"], + ["nospell.text","initial"], + ["paren.keyword.operator","}{"] +],[ + "start", + ["text"," Initial value for picker. Value must be present in the list of choices specified. If not specified defaults to the first choice."] +],[ + "start", + ["paren.keyword.operator","}"] +],[ + "start", + ["text"," "], + ["keyword","\\item"], + ["paren.keyword.operator","{"], + ["nospell.text","label"], + ["paren.keyword.operator","}{"] +],[ + "start", + ["text"," Display label for picker. Defaults to the variable name if not specified."] +],[ + "start", + ["paren.keyword.operator","}"] +],[ + "start", + ["paren.keyword.operator","}"] +],[ + "start" +],[ + "start", + ["keyword","\\value"], + ["paren.keyword.operator","{"] +],[ + "start", + ["text"," An object of class \"manipulator.picker\" which can be passed to the "], + ["keyword","\\code"], + ["paren.keyword.operator","{"], + ["keyword","\\link"], + ["paren.keyword.operator","{"], + ["nospell.text","manipulate"], + ["paren.keyword.operator","}}"], + ["text"," function."] +],[ + "start", + ["paren.keyword.operator","}"] +],[ + "start" +],[ + "start", + ["keyword","\\seealso"], + ["paren.keyword.operator","{"] +],[ + "start", + ["keyword","\\code"], + ["paren.keyword.operator","{"], + ["keyword","\\link"], + ["paren.keyword.operator","{"], + ["nospell.text","manipulate"], + ["paren.keyword.operator","}}"], + ["text",", "], + ["keyword","\\code"], + ["paren.keyword.operator","{"], + ["keyword","\\link"], + ["paren.keyword.operator","{"], + ["nospell.text","slider"], + ["paren.keyword.operator","}}"], + ["text",", "], + ["keyword","\\code"], + ["paren.keyword.operator","{"], + ["keyword","\\link"], + ["paren.keyword.operator","{"], + ["nospell.text","checkbox"], + ["paren.keyword.operator","}}"], + ["text",", "], + ["keyword","\\code"], + ["paren.keyword.operator","{"], + ["keyword","\\link"], + ["paren.keyword.operator","{"], + ["nospell.text","button"], + ["paren.keyword.operator","}}"] +],[ + "start", + ["paren.keyword.operator","}"] +],[ + "start" +],[ + "start" +],[ + "nospell", + ["keyword","\\examples"], + ["paren.keyword.operator","{"] +],[ + "nospell", + ["keyword","\\dontrun"], + ["paren.keyword.operator","{"] +],[ + "nospell" +],[ + "nospell", + ["text","##"], + ["nospell.text"," Filtering data with a picker"] +],[ + "nospell", + ["nospell.text","manipulate"], + ["paren.keyword.operator","("] +],[ + "nospell", + ["nospell.text"," barplot"], + ["paren.keyword.operator","("], + ["nospell.text","as"], + ["text","."], + ["nospell.text","matrix"], + ["paren.keyword.operator","("], + ["nospell.text","longley"], + ["paren.keyword.operator","["], + ["text",","], + ["nospell.text","factor"], + ["paren.keyword.operator","])"], + ["text",","], + ["nospell.text"," "] +],[ + "nospell", + ["nospell.text"," beside "], + ["text","="], + ["nospell.text"," TRUE"], + ["text",","], + ["nospell.text"," main "], + ["text","="], + ["nospell.text"," factor"], + ["paren.keyword.operator",")"], + ["text",","] +],[ + "nospell", + ["nospell.text"," factor "], + ["text","="], + ["nospell.text"," picker"], + ["paren.keyword.operator","("], + ["text","\""], + ["nospell.text","GNP"], + ["text","\","], + ["nospell.text"," "], + ["text","\""], + ["nospell.text","Unemployed"], + ["text","\","], + ["nospell.text"," "], + ["text","\""], + ["nospell.text","Employed"], + ["text","\""], + ["paren.keyword.operator","))"] +],[ + "nospell" +],[ + "nospell", + ["text","##"], + ["nospell.text"," Create a picker with labels"] +],[ + "nospell", + ["nospell.text","manipulate"], + ["paren.keyword.operator","("] +],[ + "nospell", + ["nospell.text"," plot"], + ["paren.keyword.operator","("], + ["nospell.text","pressure"], + ["text",","], + ["nospell.text"," type "], + ["text","="], + ["nospell.text"," type"], + ["paren.keyword.operator",")"], + ["text",","], + ["nospell.text"," "] +],[ + "nospell", + ["nospell.text"," type "], + ["text","="], + ["nospell.text"," picker"], + ["paren.keyword.operator","("], + ["text","\""], + ["nospell.text","points"], + ["text","\""], + ["nospell.text"," "], + ["text","="], + ["nospell.text"," "], + ["text","\""], + ["nospell.text","p"], + ["text","\","], + ["nospell.text"," "], + ["text","\""], + ["nospell.text","line"], + ["text","\""], + ["nospell.text"," "], + ["text","="], + ["nospell.text"," "], + ["text","\""], + ["nospell.text","l"], + ["text","\","], + ["nospell.text"," "], + ["text","\""], + ["nospell.text","step"], + ["text","\""], + ["nospell.text"," "], + ["text","="], + ["nospell.text"," "], + ["text","\""], + ["nospell.text","s"], + ["text","\""], + ["paren.keyword.operator","))"] +],[ + "nospell", + ["nospell.text"," "] +],[ + "nospell", + ["text","##"], + ["nospell.text"," Picker with groups"] +],[ + "nospell", + ["nospell.text","manipulate"], + ["paren.keyword.operator","("] +],[ + "nospell", + ["nospell.text"," barplot"], + ["paren.keyword.operator","("], + ["nospell.text","as"], + ["text","."], + ["nospell.text","matrix"], + ["paren.keyword.operator","("], + ["nospell.text","mtcars"], + ["paren.keyword.operator","["], + ["nospell.text","group"], + ["text",",\""], + ["nospell.text","mpg"], + ["text","\""], + ["paren.keyword.operator","])"], + ["text",","], + ["nospell.text"," beside"], + ["text","="], + ["nospell.text","TRUE"], + ["paren.keyword.operator",")"], + ["text",","] +],[ + "nospell", + ["nospell.text"," group "], + ["text","="], + ["nospell.text"," picker"], + ["paren.keyword.operator","("], + ["text","\""], + ["nospell.text","Group 1"], + ["text","\""], + ["nospell.text"," "], + ["text","="], + ["nospell.text"," 1"], + ["text",":"], + ["nospell.text","11"], + ["text",","], + ["nospell.text"," "] +],[ + "nospell", + ["nospell.text"," "], + ["text","\""], + ["nospell.text","Group 2"], + ["text","\""], + ["nospell.text"," "], + ["text","="], + ["nospell.text"," 12"], + ["text",":"], + ["nospell.text","22"], + ["text",","], + ["nospell.text"," "] +],[ + "nospell", + ["nospell.text"," "], + ["text","\""], + ["nospell.text","Group 3"], + ["text","\""], + ["nospell.text"," "], + ["text","="], + ["nospell.text"," 23"], + ["text",":"], + ["nospell.text","32"], + ["paren.keyword.operator","))"] +],[ + "nospell" +],[ + "nospell", + ["text","##"], + ["nospell.text"," Histogram w"], + ["text","/"], + ["nospell.text"," picker to select type"] +],[ + "nospell", + ["nospell.text","require"], + ["paren.keyword.operator","("], + ["nospell.text","lattice"], + ["paren.keyword.operator",")"] +],[ + "nospell", + ["nospell.text","require"], + ["paren.keyword.operator","("], + ["nospell.text","stats"], + ["paren.keyword.operator",")"] +],[ + "nospell", + ["nospell.text","manipulate"], + ["paren.keyword.operator","("] +],[ + "nospell", + ["nospell.text"," histogram"], + ["paren.keyword.operator","("], + ["text","~"], + ["nospell.text"," height "], + ["text","|"], + ["nospell.text"," voice"], + ["text","."], + ["nospell.text","part"], + ["text",","], + ["nospell.text"," "] +],[ + "nospell", + ["nospell.text"," data "], + ["text","="], + ["nospell.text"," singer"], + ["text",","], + ["nospell.text"," type "], + ["text","="], + ["nospell.text"," type"], + ["paren.keyword.operator",")"], + ["text",","] +],[ + "nospell", + ["nospell.text"," type "], + ["text","="], + ["nospell.text"," picker"], + ["paren.keyword.operator","("], + ["text","\""], + ["nospell.text","percent"], + ["text","\","], + ["nospell.text"," "], + ["text","\""], + ["nospell.text","count"], + ["text","\","], + ["nospell.text"," "], + ["text","\""], + ["nospell.text","density"], + ["text","\""], + ["paren.keyword.operator","))"] +],[ + "nospell" +],[ + "start", + ["paren.keyword.operator","}"] +],[ + "start", + ["paren.keyword.operator","}"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_rhtml.json b/node_modules/ace/lib/ace/mode/_test/tokens_rhtml.json new file mode 100644 index 00000000..a536f851 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_rhtml.json @@ -0,0 +1,106 @@ +[[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","html"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start" +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","head"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","title"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text.xml","Title"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start" +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","body"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start" +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","p"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text.xml","This is an R HTML document. When you click the "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","b"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text.xml","Knit HTML"], + ["meta.tag.punctuation.end-tag-open.xml",""], + ["text.xml"," button a web page will be generated that includes both content as well as the output of any embedded R code chunks within the document. You can embed an R code chunk like this:"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start" +],[ + "r-start", + ["support.function.codebegin",""] +],[ + "start" +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","p"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text.xml","You can also embed plots, for example:"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start" +],[ + "r-start", + ["support.function.codebegin",""] +],[ + "start" +],[ + "start", + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start" +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_ruby.json b/node_modules/ace/lib/ace/mode/_test/tokens_ruby.json new file mode 100644 index 00000000..f9991e9c --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_ruby.json @@ -0,0 +1,242 @@ +[[ + "start", + ["text"," "], + ["comment","#test: symbol tokenizer"] +],[ + "start", + ["text"," "], + ["paren.lparen","["], + ["constant.other.symbol.ruby",":@thing"], + ["text",", "], + ["constant.other.symbol.ruby",":$thing"], + ["text",", "], + ["constant.other.symbol.ruby",":_thing"], + ["text",", "], + ["constant.other.symbol.ruby",":thing"], + ["text",", "], + ["constant.other.symbol.ruby",":Thing"], + ["text",", "], + ["constant.other.symbol.ruby",":thing1"], + ["text",", "], + ["constant.other.symbol.ruby",":thing_a"], + ["text",","] +],[ + "start", + ["text"," "], + ["constant.other.symbol.ruby",":THING"], + ["text",", "], + ["constant.other.symbol.ruby",":thing!"], + ["text",", "], + ["constant.other.symbol.ruby",":thing="], + ["text",", "], + ["constant.other.symbol.ruby",":thing?"], + ["text",", "], + ["constant.other.symbol.ruby",":t?"], + ["text",","] +],[ + "start", + ["text"," :, :@, :"], + ["keyword.operator","$"], + ["text",", :"], + ["constant.numeric","1"], + ["text",", :1"], + ["identifier","thing"], + ["text",", "], + ["constant.other.symbol.ruby",":th?"], + ["identifier","ing"], + ["text",", "], + ["constant.other.symbol.ruby",":thi="], + ["identifier","ng"], + ["text",", :1"], + ["identifier","thing"], + ["text",","] +],[ + "start", + ["text"," "], + ["constant.other.symbol.ruby",":th!"], + ["identifier","ing"], + ["text",", "], + ["constant.other.symbol.ruby",":thing"], + ["comment","#"] +],[ + "start", + ["text"," "], + ["paren.rparen","]"] +],[ + "start" +],[ + "start", + ["text"," "], + ["comment","#test: namespaces aren't symbols\" : function() {"] +],[ + "start", + ["text"," "], + ["support.class","Namespaced"], + ["text","::"], + ["support.class","Class"] +],[ + "start", + ["text"," "], + ["comment","#test: hex tokenizer "] +],[ + "start", + ["text"," "], + ["constant.numeric","0x9a"], + ["text",", "], + ["constant.numeric","0XA1"], + ["text",", "], + ["constant.numeric","0x9_a"], + ["text",", 0"], + ["identifier","x"], + ["text",", 0"], + ["identifier","x_9a"], + ["text",", 0"], + ["identifier","x9a_"], + ["text",","] +],[ + "start", + ["text"," "], + ["comment","#test: float tokenizer"] +],[ + "start", + ["text"," "], + ["paren.lparen","["], + ["constant.numeric","1"], + ["text",", "], + ["constant.numeric","+1"], + ["text",", "], + ["constant.numeric","-1"], + ["text",", "], + ["constant.numeric","12_345"], + ["text",", "], + ["constant.numeric","0.000_1"], + ["text",","] +],[ + "start", + ["text"," "], + ["identifier","_"], + ["text",", "], + ["constant.numeric","3_1"], + ["text",", "], + ["constant.numeric","1_2"], + ["text",", 1"], + ["identifier","_"], + ["text","."], + ["constant.numeric","0"], + ["text",", "], + ["constant.numeric","0"], + ["text","."], + ["identifier","_1"], + ["paren.rparen","]"], + ["text",";"] +],[ + "start", + ["text"," "] +],[ + "start", + ["paren.lparen","{"], + ["constant.other.symbol.ruby",":id"], + ["text"," "], + ["punctuation.separator.key-value","=>"], + ["text"," "], + ["string.character","?\""], + ["text",", "], + ["constant.other.symbol.ruby",":key"], + ["text"," "], + ["punctuation.separator.key-value","=>"], + ["text"," "], + ["string.start","\""], + ["string","value"], + ["string.end","\""], + ["text",", "], + ["identifier","anotherKey"], + ["text",": "], + ["paren.lparen","["], + ["identifier","x"], + ["text",", "], + ["identifier","y"], + ["text","?"], + ["paren.rparen","]}"] +],[ + "start" +],[ + "comment", + ["comment","=begin"] +],[ + "start", + ["comment","=end"] +],[ + "start" +],[ + "comment", + ["comment","=begin x"] +],[ + "comment", + ["comment","=end-"] +],[ + "start", + ["comment","=end x"] +],[ + "start" +],[ + ["heredoc","FOO","heredoc","BAR","indentedHeredoc","BAZ","indentedHeredoc","EXEC"], + ["text"," "], + ["identifier","herDocs"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["paren.lparen","["], + ["constant","<<"], + ["string","'"], + ["support.class","FOO"], + ["string","'"], + ["text",", "], + ["constant","<<"], + ["string",""], + ["support.class","BAR"], + ["string",""], + ["text",", "], + ["constant","<<-"], + ["string",""], + ["support.class","BAZ"], + ["string",""], + ["text",", "], + ["constant","<<-"], + ["string","`"], + ["support.class","EXEC"], + ["string","`"], + ["paren.rparen","]"], + ["text"," "], + ["comment","#comment"] +],[ + ["heredoc","FOO","heredoc","BAR","indentedHeredoc","BAZ","indentedHeredoc","EXEC"], + ["string"," FOO #{literal}"] +],[ + ["heredoc","BAR","indentedHeredoc","BAZ","indentedHeredoc","EXEC"], + ["support.class","FOO"] +],[ + ["heredoc","BAR","indentedHeredoc","BAZ","indentedHeredoc","EXEC"], + ["string"," BAR #{fact(10)}"] +],[ + ["indentedHeredoc","BAZ","indentedHeredoc","EXEC"], + ["support.class","BAR"] +],[ + ["indentedHeredoc","BAZ","indentedHeredoc","EXEC"], + ["string"," BAZ indented"] +],[ + ["indentedHeredoc","EXEC"], + ["string"," "], + ["support.class","BAZ"] +],[ + ["indentedHeredoc","EXEC"], + ["string"," echo hi"] +],[ + "start", + ["string"," "], + ["support.class","EXEC"] +],[ + "start", + ["support.function","puts"], + ["text"," "], + ["identifier","herDocs"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_rust.json b/node_modules/ace/lib/ace/mode/_test/tokens_rust.json new file mode 100644 index 00000000..6592575b --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_rust.json @@ -0,0 +1,136 @@ +[[ + "start", + ["keyword.source.rust","use"], + ["text"," "], + ["support.constant","core::rand::"], + ["text","RngUtil"], + ["keyword.operator",";"] +],[ + "start" +],[ + "start", + ["keyword.source.rust","fn"], + ["meta.function.source.rust"," "], + ["entity.name.function.source.rust","main"], + ["meta.function.source.rust","("], + ["text",") {"] +],[ + "start", + ["text"," "], + ["keyword.source.rust","for"], + ["text"," ["], + ["string.quoted.double.source.rust","\"Alice\""], + ["keyword.operator",","], + ["text"," "], + ["string.quoted.double.source.rust","\"Bob\""], + ["keyword.operator",","], + ["text"," "], + ["string.quoted.double.source.rust","\"Carol\""], + ["text","].each |&name| {"] +],[ + "start", + ["text"," "], + ["keyword.source.rust","do"], + ["text"," spawn {"] +],[ + "start", + ["text"," "], + ["keyword.source.rust","let"], + ["text"," v "], + ["keyword.operator","="], + ["text"," "], + ["support.constant","rand::"], + ["text","Rng().shuffle(["], + ["constant.numeric.integer.source.rust","1"], + ["keyword.operator",","], + ["text"," "], + ["constant.numeric.integer.source.rust","2"], + ["keyword.operator",","], + ["text"," "], + ["constant.numeric.integer.source.rust","3"], + ["text","])"], + ["keyword.operator",";"] +],[ + "start", + ["text"," "], + ["keyword.source.rust","for"], + ["text"," v.each |&num| {"] +],[ + "start", + ["text"," print(fmt"], + ["keyword.operator","!"], + ["text","("], + ["string.quoted.double.source.rust","\"%s says: '%d'"], + ["constant.character.escape.source.rust","\\n"], + ["string.quoted.double.source.rust","\""], + ["keyword.operator",","], + ["text"," name"], + ["keyword.operator",","], + ["text"," num "], + ["keyword.operator","+"], + ["text"," "], + ["constant.numeric.integer.source.rust","1"], + ["text","))"] +],[ + "start", + ["text"," }"] +],[ + "start", + ["text"," }"] +],[ + "start", + ["text"," }"] +],[ + "start", + ["text","}"] +],[ + "start" +],[ + "start", + ["keyword.source.rust","fn"], + ["meta.function.source.rust"," "], + ["entity.name.function.source.rust","map"], + ["meta.function.source.rust","("], + ["text","vector: &[T]"], + ["keyword.operator",","], + ["text"," function: &fn(v: &T) "], + ["keyword.operator","->"], + ["text"," U) "], + ["keyword.operator","->"], + ["text"," ~[U] {"] +],[ + "start", + ["text"," "], + ["keyword.source.rust","let"], + ["text"," "], + ["keyword.source.rust","mut"], + ["text"," accumulator "], + ["keyword.operator","="], + ["text"," ~[]"], + ["keyword.operator",";"] +],[ + "start", + ["text"," "], + ["keyword.source.rust","for"], + ["text"," "], + ["support.constant","vec::"], + ["text","each(vector) |element| {"] +],[ + "start", + ["text"," accumulator.push(function(element))"], + ["keyword.operator",";"] +],[ + "start", + ["text"," }"] +],[ + "start", + ["text"," "], + ["keyword.source.rust","return"], + ["text"," accumulator"], + ["keyword.operator",";"] +],[ + "start", + ["text","}"] +],[ + "start" +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_sass.json b/node_modules/ace/lib/ace/mode/_test/tokens_sass.json new file mode 100644 index 00000000..c0b85682 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_sass.json @@ -0,0 +1,229 @@ +[[ + "start", + ["comment","// sass ace mode;"] +],[ + "start" +],[ + "start", + ["keyword","@import"], + ["text"," "], + ["support.function","url("], + ["string","http://fonts.googleapis.com/css?family=Ace:700"], + ["support.function",")"] +],[ + "start" +],[ + "start", + ["variable.language","html"], + ["text",", "], + ["variable.language","body"] +],[ + "start", + ["support.type"," :background-color "], + ["constant.numeric","#ace"] +],[ + "start", + ["text"," "], + ["support.type","text-align"], + ["text",": "], + ["constant.language","center"] +],[ + "start", + ["text"," "], + ["support.type","height"], + ["text",": "], + ["constant.numeric","100%"] +],[ + ["comment",-1,2,"start"], + ["comment"," /*;*********;"] +],[ + ["comment",3,2,"start"], + ["comment"," ;comment ;"] +],[ + ["comment",3,2,"start"], + ["comment"," ;*********;"] +],[ + "start" +],[ + "start", + ["variable.language",".toggle"] +],[ + "start", + ["text"," "], + ["variable","$size"], + ["text",": "], + ["constant.numeric","14px"] +],[ + "start" +],[ + "start", + ["support.type"," :background "], + ["support.function","url("], + ["string","http://subtlepatterns.com/patterns/dark_stripes.png"], + ["support.function",")"] +],[ + "start", + ["text"," "], + ["support.type","border-radius"], + ["text",": "], + ["constant.numeric","8px"] +],[ + "start", + ["text"," "], + ["support.type","height"], + ["text",": "], + ["variable","$size"] +],[ + "start" +],[ + "start", + ["text"," &"], + ["variable.language",":before"] +],[ + "start", + ["text"," "], + ["variable","$radius"], + ["text",": "], + ["variable","$size"], + ["text"," "], + ["keyword.operator","*"], + ["text"," "], + ["constant.numeric","0.845"] +],[ + "start", + ["text"," "], + ["variable","$glow"], + ["text",": "], + ["variable","$size"], + ["text"," "], + ["keyword.operator","*"], + ["text"," "], + ["constant.numeric","0.125"] +],[ + "start" +],[ + "start", + ["text"," "], + ["support.type","box-shadow"], + ["text",": "], + ["constant.numeric","0"], + ["text"," "], + ["constant.numeric","0"], + ["text"," "], + ["variable","$glow"], + ["text"," "], + ["variable","$glow"], + ["text"," / "], + ["constant.numeric","2"], + ["text"," "], + ["constant.numeric","#fff"] +],[ + "start", + ["text"," "], + ["support.type","border-radius"], + ["text",": "], + ["variable","$radius"] +],[ + "start", + ["text"," "] +],[ + "start", + ["text"," &"], + ["variable.language",":active"] +],[ + "start", + ["text"," ~ "], + ["variable.language",".button"] +],[ + "start", + ["text"," "], + ["support.type","box-shadow"], + ["text",": "], + ["constant.numeric","0"], + ["text"," "], + ["constant.numeric","15px"], + ["text"," "], + ["constant.numeric","25px"], + ["text"," "], + ["constant.numeric","-4px"], + ["text"," "], + ["support.function","rgba"], + ["paren.lparen","("], + ["constant.numeric","0"], + ["text",","], + ["constant.numeric","0"], + ["text",","], + ["constant.numeric","0"], + ["text",","], + ["constant.numeric","0.4"], + ["paren.rparen",")"], + ["text"," "] +],[ + "start", + ["text"," ~ "], + ["variable.language",".label"] +],[ + "start", + ["text"," "], + ["support.type","font-size"], + ["text",": "], + ["constant.numeric","40px"] +],[ + "start", + ["text"," "], + ["support.type","color"], + ["text",": "], + ["support.function","rgba"], + ["paren.lparen","("], + ["constant.numeric","0"], + ["text",","], + ["constant.numeric","0"], + ["text",","], + ["constant.numeric","0"], + ["text",","], + ["constant.numeric","0.45"], + ["paren.rparen",")"] +],[ + "start" +],[ + "start", + ["text"," &"], + ["variable.language",":checked"], + ["text"," "] +],[ + "start", + ["text"," ~ "], + ["variable.language",".button"] +],[ + "start", + ["text"," "], + ["support.type","box-shadow"], + ["text",": "], + ["constant.numeric","0"], + ["text"," "], + ["constant.numeric","15px"], + ["text"," "], + ["constant.numeric","25px"], + ["text"," "], + ["constant.numeric","-4px"], + ["text"," "], + ["constant.numeric","#ace"] +],[ + "start", + ["text"," ~ "], + ["variable.language",".label"] +],[ + "start", + ["text"," "], + ["support.type","font-size"], + ["text",": "], + ["constant.numeric","40px"] +],[ + "start", + ["text"," "], + ["support.type","color"], + ["text",": "], + ["constant.numeric","#c9c9c9"] +],[ + "start" +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_scad.json b/node_modules/ace/lib/ace/mode/_test/tokens_scad.json new file mode 100644 index 00000000..8f0ff637 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_scad.json @@ -0,0 +1,194 @@ +[[ + "start", + ["comment","// ace can highlight scad!"] +],[ + "start", + ["keyword","module"], + ["text"," "], + ["identifier","Element"], + ["paren.lparen","("], + ["identifier","xpos"], + ["text",", "], + ["identifier","ypos"], + ["text",", "], + ["identifier","zpos"], + ["paren.rparen",")"], + ["paren.lparen","{"] +],[ + "start", + ["text","\t"], + ["identifier","translate"], + ["paren.lparen","(["], + ["identifier","xpos"], + ["text",","], + ["identifier","ypos"], + ["text",","], + ["identifier","zpos"], + ["paren.rparen","])"], + ["paren.lparen","{"] +],[ + "start", + ["text","\t\t"], + ["identifier","union"], + ["paren.lparen","("], + ["paren.rparen",")"], + ["paren.lparen","{"] +],[ + "start", + ["text","\t\t\t"], + ["identifier","cube"], + ["paren.lparen","(["], + ["constant.numeric","10"], + ["text",","], + ["constant.numeric","10"], + ["text",","], + ["constant.numeric","4"], + ["paren.rparen","]"], + ["text",","], + ["identifier","true"], + ["paren.rparen",")"], + ["text",";"] +],[ + "start", + ["text","\t\t\t"], + ["identifier","cylinder"], + ["paren.lparen","("], + ["constant.numeric","10"], + ["text",","], + ["constant.numeric","15"], + ["text",","], + ["constant.numeric","5"], + ["paren.rparen",")"], + ["text",";"] +],[ + "start", + ["text","\t\t\t"], + ["identifier","translate"], + ["paren.lparen","(["], + ["constant.numeric","0"], + ["text",","], + ["constant.numeric","0"], + ["text",","], + ["constant.numeric","10"], + ["paren.rparen","])"], + ["identifier","sphere"], + ["paren.lparen","("], + ["constant.numeric","5"], + ["paren.rparen",")"], + ["text",";"] +],[ + "start", + ["text","\t\t"], + ["paren.rparen","}"] +],[ + "start", + ["text","\t"], + ["paren.rparen","}"] +],[ + "start", + ["paren.rparen","}"] +],[ + "start" +],[ + "start", + ["identifier","union"], + ["paren.lparen","("], + ["paren.rparen",")"], + ["paren.lparen","{"] +],[ + "start", + ["text","\t"], + ["keyword","for"], + ["paren.lparen","("], + ["identifier","i"], + ["keyword.operator","="], + ["paren.lparen","["], + ["constant.numeric","0"], + ["text",":"], + ["constant.numeric","30"], + ["paren.rparen","])"], + ["paren.lparen","{"] +],[ + "start", + ["text","\t\t# "], + ["identifier","Element"], + ["paren.lparen","("], + ["constant.numeric","0"], + ["text",","], + ["constant.numeric","0"], + ["text",","], + ["constant.numeric","0"], + ["paren.rparen",")"], + ["text",";"] +],[ + "start", + ["text","\t\t"], + ["identifier","Element"], + ["paren.lparen","("], + ["constant.numeric","15"], + ["keyword.operator","*"], + ["identifier","i"], + ["text",","], + ["constant.numeric","0"], + ["text",","], + ["constant.numeric","0"], + ["paren.rparen",")"], + ["text",";"] +],[ + "start", + ["text","\t"], + ["paren.rparen","}"] +],[ + "start", + ["paren.rparen","}"] +],[ + "start" +],[ + "start", + ["keyword","for"], + ["text"," "], + ["paren.lparen","("], + ["identifier","i"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["paren.lparen","["], + ["constant.numeric","3"], + ["text",", "], + ["constant.numeric","5"], + ["text",", "], + ["constant.numeric","7"], + ["text",", "], + ["constant.numeric","11"], + ["paren.rparen","])"], + ["paren.lparen","{"] +],[ + "start", + ["text","\t"], + ["identifier","rotate"], + ["paren.lparen","(["], + ["identifier","i"], + ["keyword.operator","*"], + ["constant.numeric","10"], + ["text",","], + ["constant.numeric","0"], + ["text",","], + ["constant.numeric","0"], + ["paren.rparen","])"], + ["identifier","scale"], + ["paren.lparen","(["], + ["constant.numeric","1"], + ["text",","], + ["constant.numeric","1"], + ["text",","], + ["identifier","i"], + ["paren.rparen","])"], + ["identifier","cube"], + ["paren.lparen","("], + ["constant.numeric","10"], + ["paren.rparen",")"], + ["text",";"] +],[ + "start", + ["paren.rparen","}"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_scala.json b/node_modules/ace/lib/ace/mode/_test/tokens_scala.json new file mode 100644 index 00000000..01dd3ce3 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_scala.json @@ -0,0 +1,542 @@ +[[ + "start", + ["comment","// http://www.scala-lang.org/node/54"] +],[ + "start" +],[ + "start", + ["keyword","package"], + ["text"," "], + ["identifier","examples"], + ["text","."], + ["identifier","actors"] +],[ + "start" +],[ + "start", + ["keyword","import"], + ["text"," "], + ["identifier","scala"], + ["text","."], + ["identifier","actors"], + ["text","."], + ["identifier","Actor"] +],[ + "start", + ["keyword","import"], + ["text"," "], + ["identifier","scala"], + ["text","."], + ["identifier","actors"], + ["text","."], + ["identifier","Actor"], + ["text","."], + ["identifier","_"] +],[ + "start" +],[ + "start", + ["keyword","abstract"], + ["text"," "], + ["keyword","class"], + ["text"," "], + ["identifier","PingMessage"] +],[ + "start", + ["keyword","case"], + ["text"," "], + ["keyword","object"], + ["text"," "], + ["identifier","Start"], + ["text"," "], + ["keyword","extends"], + ["text"," "], + ["identifier","PingMessage"] +],[ + "start", + ["keyword","case"], + ["text"," "], + ["keyword","object"], + ["text"," "], + ["identifier","SendPing"], + ["text"," "], + ["keyword","extends"], + ["text"," "], + ["identifier","PingMessage"] +],[ + "start", + ["keyword","case"], + ["text"," "], + ["keyword","object"], + ["text"," "], + ["identifier","Pong"], + ["text"," "], + ["keyword","extends"], + ["text"," "], + ["identifier","PingMessage"] +],[ + "start" +],[ + "start", + ["keyword","abstract"], + ["text"," "], + ["keyword","class"], + ["text"," "], + ["identifier","PongMessage"] +],[ + "start", + ["keyword","case"], + ["text"," "], + ["keyword","object"], + ["text"," "], + ["identifier","Ping"], + ["text"," "], + ["keyword","extends"], + ["text"," "], + ["identifier","PongMessage"] +],[ + "start", + ["keyword","case"], + ["text"," "], + ["keyword","object"], + ["text"," "], + ["identifier","Stop"], + ["text"," "], + ["keyword","extends"], + ["text"," "], + ["identifier","PongMessage"] +],[ + "start" +],[ + "start", + ["keyword","object"], + ["text"," "], + ["identifier","pingpong"], + ["text"," "], + ["keyword","extends"], + ["text"," "], + ["identifier","Application"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["keyword","val"], + ["text"," "], + ["identifier","pong"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["keyword","new"], + ["text"," "], + ["identifier","Pong"] +],[ + "start", + ["text"," "], + ["keyword","val"], + ["text"," "], + ["identifier","ping"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["keyword","new"], + ["text"," "], + ["identifier","Ping"], + ["paren.lparen","("], + ["constant.numeric","100000"], + ["text",", "], + ["identifier","pong"], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["identifier","ping"], + ["text","."], + ["identifier","start"] +],[ + "start", + ["text"," "], + ["identifier","pong"], + ["text","."], + ["identifier","start"] +],[ + "start", + ["text"," "], + ["identifier","ping"], + ["text"," "], + ["keyword.operator","!"], + ["text"," "], + ["identifier","Start"] +],[ + "start", + ["paren.rparen","}"] +],[ + "start" +],[ + "start", + ["keyword","class"], + ["text"," "], + ["identifier","Ping"], + ["paren.lparen","("], + ["identifier","count"], + ["text",": "], + ["support.function","Int"], + ["text",", "], + ["identifier","pong"], + ["text",": "], + ["identifier","Actor"], + ["paren.rparen",")"], + ["text"," "], + ["keyword","extends"], + ["text"," "], + ["identifier","Actor"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["keyword","def"], + ["text"," "], + ["identifier","act"], + ["paren.lparen","("], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["identifier","println"], + ["paren.lparen","("], + ["string","\"Ping: Initializing with count \""], + ["keyword.operator","+"], + ["identifier","count"], + ["keyword.operator","+"], + ["string","\": \""], + ["keyword.operator","+"], + ["identifier","pong"], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["keyword","var"], + ["text"," "], + ["identifier","pingsLeft"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["identifier","count"] +],[ + "start", + ["text"," "], + ["identifier","loop"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["identifier","react"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["keyword","case"], + ["text"," "], + ["identifier","Start"], + ["text"," "], + ["keyword.operator","=>"] +],[ + "start", + ["text"," "], + ["identifier","println"], + ["paren.lparen","("], + ["string","\"Ping: starting.\""], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["identifier","pong"], + ["text"," "], + ["keyword.operator","!"], + ["text"," "], + ["identifier","Ping"] +],[ + "start", + ["text"," "], + ["identifier","pingsLeft"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["identifier","pingsLeft"], + ["text"," "], + ["keyword.operator","-"], + ["text"," "], + ["constant.numeric","1"] +],[ + "start", + ["text"," "], + ["keyword","case"], + ["text"," "], + ["identifier","SendPing"], + ["text"," "], + ["keyword.operator","=>"] +],[ + "start", + ["text"," "], + ["identifier","pong"], + ["text"," "], + ["keyword.operator","!"], + ["text"," "], + ["identifier","Ping"] +],[ + "start", + ["text"," "], + ["identifier","pingsLeft"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["identifier","pingsLeft"], + ["text"," "], + ["keyword.operator","-"], + ["text"," "], + ["constant.numeric","1"] +],[ + "start", + ["text"," "], + ["keyword","case"], + ["text"," "], + ["identifier","Pong"], + ["text"," "], + ["keyword.operator","=>"] +],[ + "start", + ["text"," "], + ["keyword","if"], + ["text"," "], + ["paren.lparen","("], + ["identifier","pingsLeft"], + ["text"," "], + ["keyword.operator","%"], + ["text"," "], + ["constant.numeric","1000"], + ["text"," "], + ["keyword.operator","=="], + ["text"," "], + ["constant.numeric","0"], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["identifier","println"], + ["paren.lparen","("], + ["string","\"Ping: pong from: \""], + ["keyword.operator","+"], + ["identifier","sender"], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["keyword","if"], + ["text"," "], + ["paren.lparen","("], + ["identifier","pingsLeft"], + ["text"," "], + ["keyword.operator",">"], + ["text"," "], + ["constant.numeric","0"], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["identifier","self"], + ["text"," "], + ["keyword.operator","!"], + ["text"," "], + ["identifier","SendPing"] +],[ + "start", + ["text"," "], + ["keyword","else"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["identifier","println"], + ["paren.lparen","("], + ["string","\"Ping: Stop.\""], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["identifier","pong"], + ["text"," "], + ["keyword.operator","!"], + ["text"," "], + ["identifier","Stop"] +],[ + "start", + ["text"," "], + ["identifier","exit"], + ["paren.lparen","("], + ["symbol.constant","'stop"], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["paren.rparen","}"] +],[ + "start" +],[ + "start", + ["keyword","class"], + ["text"," "], + ["identifier","Pong"], + ["text"," "], + ["keyword","extends"], + ["text"," "], + ["identifier","Actor"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["keyword","def"], + ["text"," "], + ["identifier","act"], + ["paren.lparen","("], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["keyword","var"], + ["text"," "], + ["identifier","pongCount"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["constant.numeric","0"] +],[ + "start", + ["text"," "], + ["identifier","loop"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["identifier","react"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["keyword","case"], + ["text"," "], + ["identifier","Ping"], + ["text"," "], + ["keyword.operator","=>"] +],[ + "start", + ["text"," "], + ["keyword","if"], + ["text"," "], + ["paren.lparen","("], + ["identifier","pongCount"], + ["text"," "], + ["keyword.operator","%"], + ["text"," "], + ["constant.numeric","1000"], + ["text"," "], + ["keyword.operator","=="], + ["text"," "], + ["constant.numeric","0"], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["identifier","println"], + ["paren.lparen","("], + ["string","\"Pong: ping \""], + ["keyword.operator","+"], + ["identifier","pongCount"], + ["keyword.operator","+"], + ["string","\" from \""], + ["keyword.operator","+"], + ["identifier","sender"], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["identifier","sender"], + ["text"," "], + ["keyword.operator","!"], + ["text"," "], + ["identifier","Pong"] +],[ + "start", + ["text"," "], + ["identifier","pongCount"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["identifier","pongCount"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["constant.numeric","1"] +],[ + "start", + ["text"," "], + ["keyword","case"], + ["text"," "], + ["identifier","Stop"], + ["text"," "], + ["keyword.operator","=>"] +],[ + "start", + ["text"," "], + ["identifier","println"], + ["paren.lparen","("], + ["string","\"Pong: Stop.\""], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["identifier","exit"], + ["paren.lparen","("], + ["symbol.constant","'stop"], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["paren.rparen","}"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_scheme.json b/node_modules/ace/lib/ace/mode/_test/tokens_scheme.json new file mode 100644 index 00000000..42f4aa65 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_scheme.json @@ -0,0 +1,216 @@ +[[ + "start", + ["text","("], + ["storage.type.function-type.scheme","define"], + ["text"," "], + ["text","("], + ["identifier","prompt-for-cd"], + ["text",")"] +],[ + "start", + ["text"," "], + ["string","\"Prompts"] +],[ + "start", + ["text"," "], + ["identifier","for"], + ["text"," "], + ["identifier","CD"], + ["text","\""] +],[ + "start", + ["text"," ("], + ["identifier","prompt-read"], + ["text"," "], + ["string","\"Title\""], + ["text"," "], + ["constant.numeric","1.53"], + ["text"," "], + ["constant.numeric","1"], + ["text"," "], + ["constant.numeric","2"], + ["text","/"], + ["constant.numeric","4"], + ["text"," "], + ["constant.numeric","1.7"], + ["text"," "], + ["constant.numeric","1.7e0"], + ["text"," "], + ["constant.numeric","2.9E-4"], + ["text"," "], + ["constant.numeric","+42"], + ["text"," "], + ["constant.numeric","-7"], + ["text"," "], + ["constant.numeric","#b001"], + ["text"," "], + ["constant.numeric","#b001"], + ["text","/"], + ["constant.numeric","100"], + ["text"," "], + ["constant.numeric","#o777"], + ["text"," "], + ["constant.numeric","#O777"], + ["text"," "], + ["constant.numeric","#xabc55"], + ["text"," "], + ["identifier","#c"], + ["text","("], + ["constant.numeric","0"], + ["text"," "], + ["constant.numeric","-5.6"], + ["text","))"] +],[ + "start", + ["text"," ("], + ["identifier","prompt-read"], + ["text"," "], + ["string","\"Artist\""], + ["text",")"] +],[ + "start", + ["text"," ("], + ["keyword.operator","or"], + ["text"," ("], + ["identifier","parse-integer"], + ["text"," ("], + ["identifier","prompt-read"], + ["text"," "], + ["string","\"Rating\""], + ["text",") "], + ["punctuation.definition.constant.character.scheme","#:junk-allowed"], + ["text"," "], + ["constant.language","#t"], + ["text",") "], + ["constant.numeric","0"], + ["text",")"] +],[ + "start", + ["text"," ("], + ["keyword.control","if"], + ["text"," "], + ["identifier","x"], + ["text"," ("], + ["support.function","format"], + ["text"," "], + ["constant.language","#t"], + ["text"," "], + ["string","\"yes\""], + ["text",") ("], + ["support.function","format"], + ["text"," "], + ["constant.language","#f"], + ["text"," "], + ["string","\"no\""], + ["text",") "], + ["comment",";and here comment"] +],[ + "start", + ["text"," ) "] +],[ + "start", + ["text"," "], + ["comment",";; second line comment"] +],[ + "start", + ["text"," '(+ "], + ["constant.numeric","1"], + ["text"," "], + ["constant.numeric","2"], + ["text",")"] +],[ + "start", + ["text"," ("], + ["identifier","position-if-not"], + ["text"," "], + ["identifier","char-set"], + ["text",":"], + ["identifier","whitespace"], + ["text"," "], + ["identifier","line"], + ["text"," "], + ["punctuation.definition.constant.character.scheme","#:start"], + ["text"," "], + ["identifier","beg"], + ["text","))"] +],[ + "start", + ["text"," ("], + ["support.function","quote"], + ["text"," ("], + ["identifier","privet"], + ["text"," "], + ["constant.numeric","1"], + ["text"," "], + ["constant.numeric","2"], + ["text"," "], + ["constant.numeric","3"], + ["text","))"] +],[ + "start", + ["text"," '("], + ["identifier","hello"], + ["text"," "], + ["identifier","world"], + ["text",")"] +],[ + "start", + ["text"," (* "], + ["constant.numeric","5"], + ["text"," "], + ["constant.numeric","7"], + ["text",")"] +],[ + "start", + ["text"," ("], + ["constant.numeric","1"], + ["text"," "], + ["constant.numeric","2"], + ["text"," "], + ["constant.numeric","34"], + ["text"," "], + ["constant.numeric","5"], + ["text",")"] +],[ + "start", + ["text"," ("], + ["punctuation.definition.constant.character.scheme","#:use"], + ["text"," "], + ["string","\"aaaa\""], + ["text",")"] +],[ + "start", + ["text"," ("], + ["keyword.control","let"], + ["text"," (("], + ["identifier","x"], + ["text"," "], + ["constant.numeric","10"], + ["text",") ("], + ["identifier","y"], + ["text"," "], + ["constant.numeric","20"], + ["text","))"] +],[ + "start", + ["text"," ("], + ["identifier","display"], + ["text"," (+ "], + ["identifier","x"], + ["text"," "], + ["identifier","y"], + ["text","))"] +],[ + "start", + ["text"," ) "] +],[ + "start" +],[ + "start", + ["text"," "], + ["string","\"asdad"], + ["constant.character.escape.scheme","\\0"], + ["string","eqweqe\""] +],[ + "start" +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_scss.json b/node_modules/ace/lib/ace/mode/_test/tokens_scss.json new file mode 100644 index 00000000..7e92f153 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_scss.json @@ -0,0 +1,123 @@ +[[ + "start", + ["comment","/* style.scss */"] +],[ + "start" +],[ + "start", + ["variable.language","#navbar"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["variable","$navbar-width"], + ["text",": "], + ["constant.numeric","800px"], + ["text",";"] +],[ + "start", + ["text"," "], + ["variable","$items"], + ["text",": "], + ["constant.numeric","5"], + ["text",";"] +],[ + "start", + ["text"," "], + ["variable","$navbar-color"], + ["text",": "], + ["constant.numeric","#ce4dd6"], + ["text",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["support.type","width"], + ["text",": "], + ["variable","$navbar-width"], + ["text",";"] +],[ + "start", + ["text"," "], + ["support.type","border-bottom"], + ["text",": "], + ["constant.numeric","2px"], + ["text"," "], + ["constant.language","solid"], + ["text"," "], + ["variable","$navbar-color"], + ["text",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["variable.language","li"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["support.type","float"], + ["text",": "], + ["support.type","left"], + ["text",";"] +],[ + "start", + ["text"," "], + ["support.type","width"], + ["text",": "], + ["variable","$navbar-width"], + ["text","/"], + ["variable","$items"], + ["text"," "], + ["constant","-"], + ["text"," "], + ["constant.numeric","10px"], + ["text",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["support.type","background-color"], + ["text",": "], + ["support.function","lighten"], + ["paren.lparen","("], + ["variable","$navbar-color"], + ["text",", "], + ["constant.numeric","20%"], + ["paren.rparen",")"], + ["text",";"] +],[ + "start", + ["text"," &"], + ["variable.language",":hover"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["support.type","background-color"], + ["text",": "], + ["support.function","lighten"], + ["paren.lparen","("], + ["variable","$navbar-color"], + ["text",", "], + ["constant.numeric","10%"], + ["paren.rparen",")"], + ["text",";"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["paren.rparen","}"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_sh.json b/node_modules/ace/lib/ace/mode/_test/tokens_sh.json new file mode 100644 index 00000000..f2c6b276 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_sh.json @@ -0,0 +1,334 @@ +[[ + "start", + ["comment","#!/bin/sh"] +],[ + "start" +],[ + "start", + ["comment","# Script to open a browser to current branch"] +],[ + "start", + ["comment","# Repo formats:"] +],[ + "start", + ["comment","# ssh git@github.com:richo/gh_pr.git"] +],[ + "start", + ["comment","# http https://richoH@github.com/richo/gh_pr.git"] +],[ + "start", + ["comment","# git git://github.com/richo/gh_pr.git"] +],[ + "start" +],[ + "start", + ["variable","username="], + ["text","`"], + ["identifier","git"], + ["text"," "], + ["identifier","config"], + ["text"," "], + ["keyword.operator","--"], + ["identifier","get"], + ["text"," "], + ["identifier","github"], + ["text","."], + ["identifier","user"], + ["text","`"] +],[ + "start" +],[ + "start", + ["support.function","get_repo()"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["identifier","git"], + ["text"," "], + ["identifier","remote"], + ["text"," "], + ["keyword.operator","-"], + ["identifier","v"], + ["text"," | "], + ["identifier","grep"], + ["text"," $"], + ["paren.lparen","{"], + ["text","@:"], + ["keyword.operator","-"], + ["variable","$username"], + ["paren.rparen","}"], + ["text"," | "], + ["keyword","while"], + ["text"," "], + ["keyword","read"], + ["text"," "], + ["identifier","remote"], + ["text","; "], + ["keyword","do"] +],[ + "start", + ["text"," "], + ["keyword","if"], + ["text"," "], + ["variable","repo="], + ["text","`"], + ["support.function.builtin","echo"], + ["text"," "], + ["variable","$remote"], + ["text"," | "], + ["identifier","grep"], + ["text"," "], + ["keyword.operator","-"], + ["identifier","E"], + ["text"," "], + ["keyword.operator","-"], + ["identifier","o"], + ["text"," "], + ["string","\"git@github.com:[^ ]*\""], + ["text","`; "], + ["keyword","then"] +],[ + "start", + ["text"," "], + ["support.function.builtin","echo"], + ["text"," "], + ["variable","$repo"], + ["text"," | "], + ["identifier","sed"], + ["text"," "], + ["keyword.operator","-"], + ["identifier","e"], + ["text"," "], + ["string","\"s/^git@github\\.com://\""], + ["text"," "], + ["keyword.operator","-"], + ["identifier","e"], + ["text"," "], + ["string","\"s/\\.git$//\""] +],[ + "start", + ["text"," "], + ["support.function.builtin","exit"], + ["text"," "], + ["constant.numeric","1"] +],[ + "start", + ["text"," "], + ["keyword","fi"] +],[ + "start", + ["text"," "], + ["keyword","if"], + ["text"," "], + ["variable","repo="], + ["text","`"], + ["support.function.builtin","echo"], + ["text"," "], + ["variable","$remote"], + ["text"," | "], + ["identifier","grep"], + ["text"," "], + ["keyword.operator","-"], + ["identifier","E"], + ["text"," "], + ["keyword.operator","-"], + ["identifier","o"], + ["text"," "], + ["string","\"https?://([^@]*@)?github.com/[^ ]*\\.git\""], + ["text","`; "], + ["keyword","then"] +],[ + "start", + ["text"," "], + ["support.function.builtin","echo"], + ["text"," "], + ["variable","$repo"], + ["text"," | "], + ["identifier","sed"], + ["text"," "], + ["keyword.operator","-"], + ["identifier","e"], + ["text"," "], + ["string","\"s|^https?://||\""], + ["text"," "], + ["keyword.operator","-"], + ["identifier","e"], + ["text"," "], + ["string","\"s/^.*github\\.com\\///\""], + ["text"," "], + ["keyword.operator","-"], + ["identifier","e"], + ["text"," "], + ["string","\"s/\\.git$//\""] +],[ + "start", + ["text"," "], + ["support.function.builtin","exit"], + ["text"," "], + ["constant.numeric","1"] +],[ + "start", + ["text"," "], + ["keyword","fi"] +],[ + "start", + ["text"," "], + ["keyword","if"], + ["text"," "], + ["variable","repo="], + ["text","`"], + ["support.function.builtin","echo"], + ["text"," "], + ["variable","$remote"], + ["text"," | "], + ["identifier","grep"], + ["text"," "], + ["keyword.operator","-"], + ["identifier","E"], + ["text"," "], + ["keyword.operator","-"], + ["identifier","o"], + ["text"," "], + ["string","\"git://github.com/[^ ]*\\.git\""], + ["text","`; "], + ["keyword","then"] +],[ + "start", + ["text"," "], + ["support.function.builtin","echo"], + ["text"," "], + ["variable","$repo"], + ["text"," | "], + ["identifier","sed"], + ["text"," "], + ["keyword.operator","-"], + ["identifier","e"], + ["text"," "], + ["string","\"s|^git://github.com/||\""], + ["text"," "], + ["keyword.operator","-"], + ["identifier","e"], + ["text"," "], + ["string","\"s/\\.git$//\""] +],[ + "start", + ["text"," "], + ["support.function.builtin","exit"], + ["text"," "], + ["constant.numeric","1"] +],[ + "start", + ["text"," "], + ["keyword","fi"] +],[ + "start", + ["text"," "], + ["keyword","done"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword","if"], + ["text"," "], + ["paren.lparen","["], + ["text"," "], + ["variable.language","$?"], + ["text"," "], + ["keyword.operator","-"], + ["identifier","eq"], + ["text"," "], + ["constant.numeric","0"], + ["text"," "], + ["paren.rparen","]"], + ["text","; "], + ["keyword","then"] +],[ + "start", + ["text"," "], + ["support.function.builtin","echo"], + ["text"," "], + ["string","\"Couldn't find a valid remote\""], + ["text"," "], + ["keyword.operator",">"], + ["support.function","&2"] +],[ + "start", + ["text"," "], + ["support.function.builtin","exit"], + ["text"," "], + ["constant.numeric","1"] +],[ + "start", + ["text"," "], + ["keyword","fi"] +],[ + "start", + ["paren.rparen","}"] +],[ + "start" +],[ + "start", + ["support.function.builtin","echo"], + ["text"," $"], + ["paren.lparen","{"], + ["text","#"], + ["identifier","x"], + ["paren.lparen","["], + ["text","@"], + ["paren.rparen","]}"] +],[ + "start" +],[ + "start", + ["keyword","if"], + ["text"," "], + ["variable","repo="], + ["text","`"], + ["identifier","get_repo"], + ["text"," $@`; "], + ["keyword","then"] +],[ + "start", + ["text"," "], + ["variable","branch="], + ["text","`"], + ["identifier","git"], + ["text"," "], + ["identifier","symbolic"], + ["keyword.operator","-"], + ["identifier","ref"], + ["text"," "], + ["identifier","HEAD"], + ["text"," "], + ["constant.numeric","2"], + ["keyword.operator",">/"], + ["identifier","dev"], + ["keyword.operator","/"], + ["identifier","null"], + ["text","`"] +],[ + "start", + ["text"," "], + ["support.function.builtin","echo"], + ["text"," "], + ["string","\"http://github.com/"], + ["constant","$repo"], + ["string","/pull/new/${branch##refs/heads/}\""] +],[ + "start", + ["keyword","else"] +],[ + "start", + ["text"," "], + ["support.function.builtin","exit"], + ["text"," "], + ["constant.numeric","1"] +],[ + "start", + ["keyword","fi"] +],[ + "start" +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_sjs.json b/node_modules/ace/lib/ace/mode/_test/tokens_sjs.json new file mode 100644 index 00000000..5cd96451 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_sjs.json @@ -0,0 +1,276 @@ +[[ + "start", + ["storage.type","var"], + ["text"," "], + ["paren.lparen","{"], + ["text"," "], + ["identifier","each"], + ["punctuation.operator",","], + ["text"," "], + ["identifier","map"], + ["text"," "], + ["paren.rparen","}"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["identifier","require"], + ["paren.lparen","("], + ["string","'sjs:sequence'"], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + "start", + ["storage.type","var"], + ["text"," "], + ["paren.lparen","{"], + ["text"," "], + ["keyword","get"], + ["text"," "], + ["paren.rparen","}"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["identifier","require"], + ["paren.lparen","("], + ["string","'sjs:http'"], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + "start" +],[ + "start", + ["storage.type","function"], + ["text"," "], + ["entity.name.function","foo"], + ["paren.lparen","("], + ["variable.parameter","items"], + ["punctuation.operator",", "], + ["variable.parameter","nada"], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + ["no_regex"], + ["text"," "], + ["storage.type","var"], + ["text"," "], + ["identifier","component"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["paren.lparen","{"], + ["text"," "], + ["identifier","name"], + ["punctuation.operator",":"], + ["text"," "], + ["string","\"Ace\""], + ["punctuation.operator",","], + ["text"," "], + ["identifier","role"], + ["punctuation.operator",":"], + ["text"," "], + ["string","\"Editor\""], + ["text"," "], + ["paren.rparen","}"], + ["punctuation.operator",";"] +],[ + ["qqstring","no_regex"], + ["text"," "], + ["storage.type","console"], + ["punctuation.operator","."], + ["support.function.firebug","log"], + ["paren.lparen","("], + ["string","\""] +],[ + ["qqstring","no_regex"], + ["string"," Welcome, "], + ["paren.lparen","#{"], + ["identifier","component"], + ["text","."], + ["identifier","name"], + ["paren.rparen","}"] +],[ + ["no_regex"], + ["string"," \""], + ["punctuation.operator","."], + ["identifier","trim"], + ["paren.lparen","("], + ["paren.rparen","))"], + ["punctuation.operator",";"] +],[ + ["no_regex"] +],[ + ["no_regex"], + ["text"," "], + ["identifier","logging"], + ["punctuation.operator","."], + ["identifier","debug"], + ["paren.lparen","("], + ["string","`Component added: "], + ["paren.lparen","$"], + ["identifier","String"], + ["paren.lparen","("], + ["identifier","component"], + ["paren.rparen",")"], + ["string"," ("], + ["paren.lparen","${"], + ["identifier","component"], + ["paren.rparen","}"], + ["string",")`"], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + ["no_regex"] +],[ + ["bstring","no_regex"], + ["text"," "], + ["storage.type","console"], + ["punctuation.operator","."], + ["support.function.firebug","log"], + ["paren.lparen","("], + ["string","`"] +],[ + ["string_interp","string_interp","bstring","no_regex"], + ["string"," Welcome, {"], + ["paren.lparen","${"], + ["storage.type","function"], + ["text","() "], + ["paren.lparen","{"] +],[ + ["string_interp","string_interp","bstring","no_regex"], + ["text"," "], + ["keyword","return"], + ["text"," "], + ["paren.lparen","{"], + ["text"," "], + ["identifier","x"], + ["text",": "], + ["constant.numeric","1"], + ["text",", "], + ["identifier","y"], + ["text",": "], + ["string","\"why?}\""], + ["paren.rparen","}"], + ["text",";"] +],[ + ["bstring","no_regex"], + ["text"," "], + ["paren.rparen","}"], + ["text","()"], + ["paren.rparen","}"] +],[ + ["no_regex"], + ["string"," `"], + ["punctuation.operator","."], + ["identifier","trim"], + ["paren.lparen","("], + ["paren.rparen","))"], + ["punctuation.operator",";"] +],[ + ["no_regex"] +],[ + ["no_regex"], + ["text"," "], + ["keyword","waitfor"], + ["text"," "], + ["paren.lparen","{"] +],[ + ["no_regex"], + ["text"," "], + ["identifier","items"], + ["text"," "], + ["keyword.operator",".."], + ["text"," "], + ["identifier","each"], + ["punctuation.operator","."], + ["identifier","par"], + ["text"," "], + ["paren.lparen","{"], + ["text"," "], + ["paren.rparen","|"], + ["variable.parameter","item"], + ["paren.rparen","|"] +],[ + ["no_regex"], + ["text"," "], + ["keyword","get"], + ["paren.lparen","("], + ["identifier","item"], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + ["no_regex"], + ["text"," "], + ["paren.rparen","}"] +],[ + ["no_regex"], + ["text"," "], + ["paren.rparen","}"], + ["text"," "], + ["keyword","and"], + ["text"," "], + ["paren.lparen","{"] +],[ + ["no_regex"], + ["text"," "], + ["storage.type","var"], + ["text"," "], + ["identifier","lengths"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["identifier","items"], + ["text"," "], + ["keyword.operator",".."], + ["text"," "], + ["identifier","map"], + ["paren.lparen","("], + ["identifier","i"], + ["text"," "], + ["keyword.operator","->"], + ["text"," "], + ["identifier","i"], + ["punctuation.operator","."], + ["support.constant","length"], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + ["no_regex"], + ["text"," "], + ["paren.rparen","}"], + ["text"," "], + ["keyword","or"], + ["text"," "], + ["paren.lparen","{"] +],[ + ["no_regex"], + ["text"," "], + ["variable.language","hold"], + ["paren.lparen","("], + ["constant.numeric","1500"], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + ["no_regex"], + ["text"," "], + ["keyword","throw"], + ["text"," "], + ["keyword","new"], + ["text"," "], + ["variable.language","Error"], + ["paren.lparen","("], + ["string","\"timed out\""], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + ["no_regex"], + ["text"," "], + ["paren.rparen","}"] +],[ + ["no_regex"], + ["paren.rparen","}"], + ["text","\t"], + ["comment","// Real Tab."] +],[ + ["no_regex"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_smarty.json b/node_modules/ace/lib/ace/mode/_test/tokens_smarty.json new file mode 100644 index 00000000..0f56985d --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_smarty.json @@ -0,0 +1,98 @@ +[[ + "start", + ["punctuation.section.embedded.begin.smarty","{"], + ["keyword.control.smarty","foreach"], + ["source.smarty"," "], + ["punctuation.definition.variable.smarty","$"], + ["variable.other.smarty","foo"], + ["source.smarty"," as "], + ["punctuation.definition.variable.smarty","$"], + ["variable.other.smarty","bar"], + ["punctuation.section.embedded.end.smarty","}"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.anchor.tag-name.xml","a"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","href"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\""], + ["punctuation.section.embedded.begin.smarty","{"], + ["punctuation.definition.variable.smarty","$"], + ["variable.other.smarty","bar"], + ["source.smarty",".zig"], + ["punctuation.section.embedded.end.smarty","}"], + ["string.attribute-value.xml","\""], + ["meta.tag.punctuation.tag-close.xml",">"], + ["punctuation.section.embedded.begin.smarty","{"], + ["punctuation.definition.variable.smarty","$"], + ["variable.other.smarty","bar"], + ["source.smarty",".zag"], + ["punctuation.section.embedded.end.smarty","}"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.anchor.tag-name.xml","a"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","href"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\""], + ["punctuation.section.embedded.begin.smarty","{"], + ["punctuation.definition.variable.smarty","$"], + ["variable.other.smarty","bar"], + ["source.smarty",".zig2"], + ["punctuation.section.embedded.end.smarty","}"], + ["string.attribute-value.xml","\""], + ["meta.tag.punctuation.tag-close.xml",">"], + ["punctuation.section.embedded.begin.smarty","{"], + ["punctuation.definition.variable.smarty","$"], + ["variable.other.smarty","bar"], + ["source.smarty",".zag2"], + ["punctuation.section.embedded.end.smarty","}"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.anchor.tag-name.xml","a"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","href"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\""], + ["punctuation.section.embedded.begin.smarty","{"], + ["punctuation.definition.variable.smarty","$"], + ["variable.other.smarty","bar"], + ["source.smarty",".zig3"], + ["punctuation.section.embedded.end.smarty","}"], + ["string.attribute-value.xml","\""], + ["meta.tag.punctuation.tag-close.xml",">"], + ["punctuation.section.embedded.begin.smarty","{"], + ["punctuation.definition.variable.smarty","$"], + ["variable.other.smarty","bar"], + ["source.smarty",".zag3"], + ["punctuation.section.embedded.end.smarty","}"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["punctuation.section.embedded.begin.smarty","{"], + ["keyword.control.smarty","foreachelse"], + ["punctuation.section.embedded.end.smarty","}"] +],[ + "start", + ["text.xml"," There were no rows found."] +],[ + "start", + ["punctuation.section.embedded.begin.smarty","{"], + ["source.smarty","/"], + ["keyword.control.smarty","foreach"], + ["punctuation.section.embedded.end.smarty","}"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_snippets.json b/node_modules/ace/lib/ace/mode/_test/tokens_snippets.json new file mode 100644 index 00000000..308683b7 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_snippets.json @@ -0,0 +1,159 @@ +[[ + "start", + ["comment","# Function"] +],[ + "start", + ["constant.language.escape","snippet"], + ["text"," fun"] +],[ + "sn-start", + ["text","\tfunction "], + ["markup.list","${"], + ["constant.numeric","1"], + ["text","?:function_name"], + ["markup.list","}"], + ["text","("], + ["markup.list","${"], + ["constant.numeric","2"], + ["punctuation.operator",":"], + ["text","argument"], + ["markup.list","}"], + ["text",") {"] +],[ + "sn-start", + ["text","\t\t"], + ["markup.list","${"], + ["constant.numeric","3"], + ["punctuation.operator",":"], + ["text","// body..."], + ["markup.list","}"] +],[ + "sn-start", + ["text","\t}"] +],[ + "start", + ["comment","# Anonymous Function"] +],[ + "start", + ["constant.language.escape","regex "], + ["keyword","/"], + ["text","((=)\\s*|(:)\\s*|(\\()|\\b)"], + ["keyword","/"], + ["text","f"], + ["keyword","/"], + ["text","(\\))?"], + ["keyword","/"] +],[ + "start", + ["constant.language.escape","name"], + ["text"," f"] +],[ + "sn-start", + ["text","\tfunction"], + ["markup.list","${"], + ["variable","M1"], + ["text","?: "], + ["markup.list","${"], + ["constant.numeric","1"], + ["punctuation.operator",":"], + ["text","functionName"], + ["markup.list","}}"], + ["text","("], + ["variable","$2"], + ["text",") {"] +],[ + "sn-start", + ["text","\t\t"], + ["markup.list","${"], + ["constant.numeric","0"], + ["punctuation.operator",":"], + ["keyword","$TM_SELECTED_TEXT"], + ["markup.list","}"] +],[ + "sn-start", + ["text","\t}"], + ["markup.list","${"], + ["variable","M2"], + ["text","?;"], + ["markup.list","}${"], + ["variable","M3"], + ["text","?,"], + ["markup.list","}${"], + ["variable","M4"], + ["text","?)"], + ["markup.list","}"] +],[ + "start", + ["comment","# Immediate function"] +],[ + "start", + ["constant.language.escape","trigger"], + ["text"," \\(?f\\("] +],[ + "start", + ["constant.language.escape","endTrigger"], + ["text"," \\)?"] +],[ + "start", + ["constant.language.escape","snippet"], + ["text"," f("] +],[ + "sn-start", + ["text","\t(function("], + ["markup.list","${"], + ["constant.numeric","1"], + ["markup.list","}"], + ["text",") {"] +],[ + "sn-start", + ["text","\t\t"], + ["markup.list","${"], + ["constant.numeric","0"], + ["punctuation.operator",":"], + ["markup.list","${"], + ["keyword","TM_SELECTED_TEXT"], + ["punctuation.operator",":"], + ["text","/* code */"], + ["markup.list","}}"] +],[ + "sn-start", + ["text","\t}("], + ["markup.list","${"], + ["constant.numeric","1"], + ["markup.list","}"], + ["text","));"] +],[ + "start", + ["comment","# if"] +],[ + "start", + ["constant.language.escape","snippet"], + ["text"," if"] +],[ + "sn-start", + ["text","\tif ("], + ["markup.list","${"], + ["constant.numeric","1"], + ["punctuation.operator",":"], + ["text","true"], + ["markup.list","}"], + ["text",") {"] +],[ + "sn-start", + ["text","\t\t"], + ["markup.list","${"], + ["constant.numeric","0"], + ["markup.list","}"] +],[ + "sn-start", + ["text","\t}"] +],[ + "sn-start", + ["text","\t"] +],[ + "sn-start", + ["text","\t"] +],[ + "sn-start", + ["text","\t"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_soy_template.json b/node_modules/ace/lib/ace/mode/_test/tokens_soy_template.json new file mode 100644 index 00000000..9ae7c4ed --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_soy_template.json @@ -0,0 +1,286 @@ +[[ + "punctuation.definition.comment.begin.soy1", + ["punctuation.definition.comment.begin.soy","/**"] +],[ + "punctuation.definition.comment.begin.soy1", + ["comment.block.documentation.soy"," * Greets a person using \"Hello\" by default."] +],[ + "punctuation.definition.comment.begin.soy1", + ["comment.block.documentation.soy"," * "], + ["support.type.soy","@param"], + ["text"," "], + ["variable.parameter.soy","name"], + ["comment.block.documentation.soy"," The name of the person."] +],[ + "punctuation.definition.comment.begin.soy1", + ["comment.block.documentation.soy"," * "], + ["support.type.soy","@param?"], + ["text"," "], + ["variable.parameter.soy","greetingWord"], + ["comment.block.documentation.soy"," Optional greeting word to use instead of \"Hello\"."] +],[ + "start", + ["comment.block.documentation.soy"," "], + ["punctuation.definition.comment.end.soy","*/"] +],[ + "start", + ["punctuation.definition.tag.begin.soy","{"], + ["entity.name.tag.soy","template"], + ["text"," "], + ["entity.name.function.soy",".helloName"], + ["meta.tag.template.soy"," #eee"], + ["punctuation.definition.tag.end.soy","}"] +],[ + "start", + ["text.xml"," "], + ["punctuation.definition.tag.begin.soy","{"], + ["entity.name.tag.soy","if"], + ["meta.tag.if.soy"," "], + ["keyword.operator.soy","not"], + ["meta.tag.if.soy"," "], + ["variable.other.soy","$greetingWord"], + ["punctuation.definition.tag.end.soy","}"] +],[ + "start", + ["text.xml"," Hello "], + ["punctuation.definition.tag.begin.soy","{"], + ["variable.other.soy","$name"], + ["punctuation.definition.tag.end.soy","}"], + ["text.xml","!"] +],[ + "start", + ["text.xml"," "], + ["punctuation.definition.tag.begin.soy","{"], + ["text","else"], + ["punctuation.definition.tag.end.soy","}"] +],[ + "start", + ["text.xml"," "], + ["punctuation.definition.tag.begin.soy","{"], + ["variable.other.soy","$greetingWord"], + ["punctuation.definition.tag.end.soy","}"], + ["text.xml"," "], + ["punctuation.definition.tag.begin.soy","{"], + ["variable.other.soy","$name"], + ["punctuation.definition.tag.end.soy","}"], + ["text.xml","!"] +],[ + "start", + ["text.xml"," "], + ["punctuation.definition.tag.begin.soy","{/"], + ["entity.name.tag.soy","if"], + ["punctuation.definition.tag.end.soy","}"] +],[ + "start", + ["punctuation.definition.tag.begin.soy","{/"], + ["meta.tag.template.soy","template"], + ["punctuation.definition.tag.end.soy","}"] +],[ + "start" +],[ + "punctuation.definition.comment.begin.soy1", + ["punctuation.definition.comment.begin.soy","/**"] +],[ + "punctuation.definition.comment.begin.soy1", + ["comment.block.documentation.soy"," * Greets a person and optionally a list of other people."] +],[ + "punctuation.definition.comment.begin.soy1", + ["comment.block.documentation.soy"," * "], + ["support.type.soy","@param"], + ["text"," "], + ["variable.parameter.soy","name"], + ["comment.block.documentation.soy"," The name of the person."] +],[ + "punctuation.definition.comment.begin.soy1", + ["comment.block.documentation.soy"," * "], + ["support.type.soy","@param"], + ["text"," "], + ["variable.parameter.soy","additionalNames"], + ["comment.block.documentation.soy"," The additional names to greet. May be an empty list."] +],[ + "start", + ["comment.block.documentation.soy"," "], + ["punctuation.definition.comment.end.soy","*/"] +],[ + "start", + ["punctuation.definition.tag.begin.soy","{"], + ["entity.name.tag.soy","template"], + ["text"," "], + ["entity.name.function.soy",".helloNames"], + ["punctuation.definition.tag.end.soy","}"] +],[ + "start", + ["comment.line.double-slash.soy"," "], + ["punctuation.definition.comment.soy","//"], + ["comment.line.double-slash.soy"," Greet the person."] +],[ + "start", + ["text.xml"," "], + ["punctuation.definition.tag.begin.soy","{"], + ["entity.name.tag.soy","call"], + ["variable.parameter.soy"," .helloName"], + ["meta.tag.call.soy"," "], + ["entity.other.attribute-name.soy","data"], + ["keyword.operator.soy","="], + ["string.quoted.double","\"all\""], + ["meta.tag.call.soy"," /"], + ["punctuation.definition.tag.end.soy","}"], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","br"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["comment.line.double-slash.soy"," "], + ["punctuation.definition.comment.soy","//"], + ["comment.line.double-slash.soy"," Greet the additional people."] +],[ + "start", + ["text.xml"," "], + ["punctuation.definition.tag.begin.soy","{"], + ["entity.name.tag.soy","foreach"], + ["meta.tag.foreach.soy"," "], + ["variable.other.soy","$additionalName"], + ["meta.tag.foreach.soy"," "], + ["keyword.operator.soy","in"], + ["meta.tag.foreach.soy"," "], + ["variable.other.soy","$additionalNames"], + ["punctuation.definition.tag.end.soy","}"] +],[ + "start", + ["text.xml"," "], + ["punctuation.definition.tag.begin.soy","{"], + ["entity.name.tag.soy","call"], + ["variable.parameter.soy"," .helloName"], + ["punctuation.definition.tag.end.soy","}"] +],[ + "start", + ["text.xml"," "], + ["punctuation.definition.tag.begin.soy","{"], + ["entity.name.tag.soy","param"], + ["meta.tag.param.soy"," "], + ["entity.other.attribute-name.soy","name"], + ["keyword.operator.soy",":"], + ["meta.tag.param.soy"," "], + ["variable.other.soy","$additionalName"], + ["meta.tag.param.soy"," /"], + ["punctuation.definition.tag.end.soy","}"] +],[ + "start", + ["text.xml"," "], + ["punctuation.definition.tag.begin.soy","{/"], + ["meta.tag.call.soy","call"], + ["punctuation.definition.tag.end.soy","}"] +],[ + "start", + ["text.xml"," "], + ["punctuation.definition.tag.begin.soy","{"], + ["entity.name.tag.soy","if"], + ["meta.tag.if.soy"," "], + ["keyword.operator.soy","not"], + ["meta.tag.if.soy"," "], + ["support.function.soy","isLast"], + ["meta.tag.if.soy","("], + ["variable.other.soy","$additionalName"], + ["meta.tag.if.soy",")"], + ["punctuation.definition.tag.end.soy","}"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","br"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["comment.line.double-slash.soy"," "], + ["punctuation.definition.comment.soy","//"], + ["comment.line.double-slash.soy"," break after every line except the last"] +],[ + "start", + ["text.xml"," "], + ["punctuation.definition.tag.begin.soy","{/"], + ["entity.name.tag.soy","if"], + ["punctuation.definition.tag.end.soy","}"] +],[ + "start", + ["text.xml"," "], + ["punctuation.definition.tag.begin.soy","{"], + ["text","ifempty"], + ["punctuation.definition.tag.end.soy","}"] +],[ + "start", + ["text.xml"," No additional people to greet."] +],[ + "start", + ["text.xml"," "], + ["punctuation.definition.tag.begin.soy","{/"], + ["entity.name.tag.soy","foreach"], + ["punctuation.definition.tag.end.soy","}"] +],[ + "start", + ["punctuation.definition.tag.begin.soy","{/"], + ["meta.tag.template.soy","template"], + ["punctuation.definition.tag.end.soy","}"] +],[ + "start" +],[ + "start" +],[ + "start", + ["punctuation.definition.tag.begin.soy","{/"], + ["entity.name.tag.soy","foreach"], + ["punctuation.definition.tag.end.soy","}"] +],[ + "start", + ["punctuation.definition.tag.begin.soy","{"], + ["entity.name.tag.soy","if"], + ["meta.tag.if.soy"," "], + ["support.function.soy","length"], + ["meta.tag.if.soy","("], + ["variable.other.soy","$items"], + ["meta.tag.if.soy",") > 5"], + ["punctuation.definition.tag.end.soy","}"] +],[ + "start", + ["punctuation.definition.tag.begin.soy","{"], + ["entity.name.tag.soy","msg"], + ["meta.tag.msg.soy"," "], + ["entity.other.attribute-name.soy","desc"], + ["keyword.operator.soy","="], + ["string.quoted.double","\"Says hello to the user.\""], + ["punctuation.definition.tag.end.soy","}"] +],[ + "start" +],[ + "start" +],[ + "start", + ["punctuation.definition.tag.begin.soy","{"], + ["entity.name.tag.soy","namespace"], + ["text"," "], + ["variable.parameter.soy","ns"], + ["text"," autoescape=\"contextual\""], + ["punctuation.definition.tag.end.soy","}"] +],[ + "start" +],[ + "start", + ["punctuation.definition.comment.begin.soy","/**"], + ["comment.block.documentation.soy"," Example. "], + ["punctuation.definition.comment.end.soy","*/"] +],[ + "start", + ["punctuation.definition.tag.begin.soy","{"], + ["entity.name.tag.soy","template"], + ["text"," "], + ["entity.name.function.soy",".example"], + ["punctuation.definition.tag.end.soy","}"] +],[ + "start", + ["text.xml"," foo is "], + ["punctuation.definition.tag.begin.soy","{"], + ["variable.other.soy","$ij.foo"], + ["punctuation.definition.tag.end.soy","}"] +],[ + "start", + ["punctuation.definition.tag.begin.soy","{/"], + ["meta.tag.template.soy","template"], + ["punctuation.definition.tag.end.soy","}"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_space.json b/node_modules/ace/lib/ace/mode/_test/tokens_space.json new file mode 100644 index 00000000..918b9a67 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_space.json @@ -0,0 +1,322 @@ +[[ + "start", + ["variable","query"] +],[ + "start", + ["empty_line"," "], + ["variable","count"], + ["keyword.operator"," "], + ["string","10"] +],[ + "start", + ["empty_line"," "], + ["variable","created"], + ["keyword.operator"," "], + ["string","2011-06-21T08:10:46Z"] +],[ + "start", + ["empty_line"," "], + ["variable","lang"], + ["keyword.operator"," "], + ["string","en-US"] +],[ + "start", + ["empty_line"," "], + ["variable","results"] +],[ + "start", + ["empty_line"," "], + ["variable","photo"] +],[ + "start", + ["empty_line"," "], + ["variable","0"] +],[ + "start", + ["empty_line"," "], + ["variable","farm"], + ["keyword.operator"," "], + ["string","6"] +],[ + "start", + ["empty_line"," "], + ["variable","id"], + ["keyword.operator"," "], + ["string","5855620975"] +],[ + "start", + ["empty_line"," "], + ["variable","isfamily"], + ["keyword.operator"," "], + ["string","0"] +],[ + "start", + ["empty_line"," "], + ["variable","isfriend"], + ["keyword.operator"," "], + ["string","0"] +],[ + "start", + ["empty_line"," "], + ["variable","ispublic"], + ["keyword.operator"," "], + ["string","1"] +],[ + "start", + ["empty_line"," "], + ["variable","owner"], + ["keyword.operator"," "], + ["string","32021554@N04"] +],[ + "start", + ["empty_line"," "], + ["variable","secret"], + ["keyword.operator"," "], + ["string","f1f5e8515d"] +],[ + "start", + ["empty_line"," "], + ["variable","server"], + ["keyword.operator"," "], + ["string","5110"] +],[ + "start", + ["empty_line"," "], + ["variable","title"], + ["keyword.operator"," "], + ["string","7087 bandit cat"] +],[ + "start", + ["empty_line"," "], + ["variable","1"] +],[ + "start", + ["empty_line"," "], + ["variable","farm"], + ["keyword.operator"," "], + ["string","4"] +],[ + "start", + ["empty_line"," "], + ["variable","id"], + ["keyword.operator"," "], + ["string","5856170534"] +],[ + "start", + ["empty_line"," "], + ["variable","isfamily"], + ["keyword.operator"," "], + ["string","0"] +],[ + "start", + ["empty_line"," "], + ["variable","isfriend"], + ["keyword.operator"," "], + ["string","0"] +],[ + "start", + ["empty_line"," "], + ["variable","ispublic"], + ["keyword.operator"," "], + ["string","1"] +],[ + "start", + ["empty_line"," "], + ["variable","owner"], + ["keyword.operator"," "], + ["string","32021554@N04"] +],[ + "start", + ["empty_line"," "], + ["variable","secret"], + ["keyword.operator"," "], + ["string","ff1efb2a6f"] +],[ + "start", + ["empty_line"," "], + ["variable","server"], + ["keyword.operator"," "], + ["string","3217"] +],[ + "start", + ["empty_line"," "], + ["variable","title"], + ["keyword.operator"," "], + ["string","6975 rusty cat"] +],[ + "start", + ["empty_line"," "], + ["variable","2"] +],[ + "start", + ["empty_line"," "], + ["variable","farm"], + ["keyword.operator"," "], + ["string","6"] +],[ + "start", + ["empty_line"," "], + ["variable","id"], + ["keyword.operator"," "], + ["string","5856172972"] +],[ + "start", + ["empty_line"," "], + ["variable","isfamily"], + ["keyword.operator"," "], + ["string","0"] +],[ + "start", + ["empty_line"," "], + ["variable","isfriend"], + ["keyword.operator"," "], + ["string","0"] +],[ + "start", + ["empty_line"," "], + ["variable","ispublic"], + ["keyword.operator"," "], + ["string","1"] +],[ + "start", + ["empty_line"," "], + ["variable","owner"], + ["keyword.operator"," "], + ["string","51249875@N03"] +],[ + "start", + ["empty_line"," "], + ["variable","secret"], + ["keyword.operator"," "], + ["string","6c6887347c"] +],[ + "start", + ["empty_line"," "], + ["variable","server"], + ["keyword.operator"," "], + ["string","5192"] +],[ + "start", + ["empty_line"," "], + ["variable","title"], + ["keyword.operator"," "], + ["string","watermarked-cats"] +],[ + "start", + ["empty_line"," "], + ["variable","3"] +],[ + "start", + ["empty_line"," "], + ["variable","farm"], + ["keyword.operator"," "], + ["string","6"] +],[ + "start", + ["empty_line"," "], + ["variable","id"], + ["keyword.operator"," "], + ["string","5856168328"] +],[ + "start", + ["empty_line"," "], + ["variable","isfamily"], + ["keyword.operator"," "], + ["string","0"] +],[ + "start", + ["empty_line"," "], + ["variable","isfriend"], + ["keyword.operator"," "], + ["string","0"] +],[ + "start", + ["empty_line"," "], + ["variable","ispublic"], + ["keyword.operator"," "], + ["string","1"] +],[ + "start", + ["empty_line"," "], + ["variable","owner"], + ["keyword.operator"," "], + ["string","32021554@N04"] +],[ + "start", + ["empty_line"," "], + ["variable","secret"], + ["keyword.operator"," "], + ["string","0c1cfdf64c"] +],[ + "start", + ["empty_line"," "], + ["variable","server"], + ["keyword.operator"," "], + ["string","5078"] +],[ + "start", + ["empty_line"," "], + ["variable","title"], + ["keyword.operator"," "], + ["string","7020 mandy cat"] +],[ + "start", + ["empty_line"," "], + ["variable","4"] +],[ + "start", + ["empty_line"," "], + ["variable","farm"], + ["keyword.operator"," "], + ["string","3"] +],[ + "start", + ["empty_line"," "], + ["variable","id"], + ["keyword.operator"," "], + ["string","5856171774"] +],[ + "start", + ["empty_line"," "], + ["variable","isfamily"], + ["keyword.operator"," "], + ["string","0"] +],[ + "start", + ["empty_line"," "], + ["variable","isfriend"], + ["keyword.operator"," "], + ["string","0"] +],[ + "start", + ["empty_line"," "], + ["variable","ispublic"], + ["keyword.operator"," "], + ["string","1"] +],[ + "start", + ["empty_line"," "], + ["variable","owner"], + ["keyword.operator"," "], + ["string","32021554@N04"] +],[ + "start", + ["empty_line"," "], + ["variable","secret"], + ["keyword.operator"," "], + ["string","7f5a3180ab"] +],[ + "start", + ["empty_line"," "], + ["variable","server"], + ["keyword.operator"," "], + ["string","2696"] +],[ + "start", + ["empty_line"," "], + ["variable","title"], + ["keyword.operator"," "], + ["string","7448 bobby cat"] +],[ + "key" +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_sql.json b/node_modules/ace/lib/ace/mode/_test/tokens_sql.json new file mode 100644 index 00000000..09a3ef99 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_sql.json @@ -0,0 +1,54 @@ +[[ + "start", + ["keyword","SELECT"], + ["text"," "], + ["identifier","city"], + ["text",", "], + ["support.function","COUNT"], + ["paren.lparen","("], + ["identifier","id"], + ["paren.rparen",")"], + ["text"," "], + ["keyword","AS"], + ["text"," "], + ["identifier","users_count"] +],[ + "start", + ["keyword","FROM"], + ["text"," "], + ["identifier","users"] +],[ + "start", + ["keyword","WHERE"], + ["text"," "], + ["identifier","group_name"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["string","'salesman'"] +],[ + "start", + ["keyword","AND"], + ["text"," "], + ["identifier","created"], + ["text"," "], + ["keyword.operator",">"], + ["text"," "], + ["string","'2011-05-21'"] +],[ + "start", + ["keyword","GROUP"], + ["text"," "], + ["keyword","BY"], + ["text"," "], + ["constant.numeric","1"] +],[ + "start", + ["keyword","ORDER"], + ["text"," "], + ["keyword","BY"], + ["text"," "], + ["constant.numeric","2"], + ["text"," "], + ["keyword","DESC"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_stylus.json b/node_modules/ace/lib/ace/mode/_test/tokens_stylus.json new file mode 100644 index 00000000..f24993f7 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_stylus.json @@ -0,0 +1,271 @@ +[[ + "start", + ["comment","// I'm a comment!"] +],[ + "start" +],[ + "comment", + ["comment","/*"] +],[ + "comment", + ["comment"," * Adds the given numbers together."] +],[ + "start", + ["comment"," */"] +],[ + "start" +],[ + "start" +],[ + "comment", + ["comment","/*!"] +],[ + "comment", + ["comment"," * Adds the given numbers together."] +],[ + "start", + ["comment"," */"] +],[ + "start" +],[ + "start" +],[ + "start", + ["entity.name.function.stylus","asdasdasdad"], + ["text","("], + ["text","df, ad"], + ["keyword.operator.stylus","="], + ["constant.numeric","23"], + ["text",")"] +],[ + "start" +],[ + "start", + ["entity.name.function.stylus","add"], + ["text","("], + ["entity.name.tag.stylus","a"], + ["text",", "], + ["entity.name.tag.stylus","b"], + ["text"," "], + ["keyword.operator.stylus","="], + ["text"," "], + ["entity.name.tag.stylus","a"], + ["text",")"] +],[ + "start", + ["text"," "], + ["entity.name.tag.stylus","a"], + ["text"," "], + ["keyword.operator.stylus","+"], + ["text"," "], + ["entity.name.tag.stylus","b"] +],[ + "start", + ["entity.name.function.stylus","green"], + ["text","("], + ["constant.numeric","#0c0"], + ["text",")"] +],[ + "start", + ["text"," add("], + ["constant.numeric","10"], + ["text",", "], + ["constant.numeric","5"], + ["text",")"] +],[ + "start", + ["text"," "], + ["comment","// => 15"] +],[ + "start" +],[ + "start", + ["text"," add("], + ["constant.numeric","10"], + ["text",")"] +],[ + "start", + ["text"," add("], + ["entity.name.tag.stylus","a"], + ["text",", "], + ["entity.name.tag.stylus","b"], + ["text",")"] +],[ + "start" +],[ + "start", + ["entity.language.stylus"," &"], + ["text","asdasd"] +],[ + "start" +],[ + "start", + ["text"," ("], + ["variable.language.stylus","arguments"], + ["text",")"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword.stylus","@sdfsdf"] +],[ + "start", + ["entity.other.attribute-name.class.stylus",".signatures"] +],[ + "start", + ["text"," "], + ["support.type","background-color"], + ["text"," "], + ["constant.numeric","#e0e8e0"] +],[ + "start", + ["text"," "], + ["support.type","border"], + ["text"," "], + ["constant.numeric","1"], + ["keyword","px"], + ["text"," "], + ["support.constant","solid"], + ["text"," grayLighter"] +],[ + "start", + ["text"," "], + ["support.type","box-shadow"], + ["text"," "], + ["constant.numeric","0"], + ["text"," "], + ["constant.numeric","0"], + ["text"," "], + ["constant.numeric","3"], + ["keyword","px"], + ["text"," grayLightest"] +],[ + "start", + ["text"," "], + ["support.type","border-radius"], + ["text"," "], + ["constant.numeric","3"], + ["keyword","px"] +],[ + "start", + ["text"," "], + ["support.type","padding"], + ["text"," "], + ["constant.numeric","3"], + ["keyword","px"], + ["text"," "], + ["constant.numeric","5"], + ["keyword","px"] +],[ + "start", + ["text"," "], + ["string","\"adsads\""] +],[ + "start", + ["text"," "], + ["support.type","margin-left"], + ["text"," "], + ["constant.numeric","0"] +],[ + "start", + ["text"," "], + ["support.type","list-style"], + ["text"," "], + ["support.constant","none"] +],[ + "start", + ["entity.other.attribute-name.class.stylus",".signature"] +],[ + "start", + ["text"," "], + ["support.type","list-style"], + ["text"," "], + ["support.constant","none"] +],[ + "start", + ["text"," "], + ["support.type","display"], + ["text",": "], + ["support.constant","inline"] +],[ + "start", + ["text"," "], + ["support.type","margin-left"], + ["text"," "], + ["constant.numeric","0"] +],[ + "start", + ["text"," "], + ["keyword.operator.stylus",">"], + ["text"," "], + ["entity.name.tag.stylus","li"] +],[ + "start", + ["text"," "], + ["support.type","display"], + ["text"," "], + ["support.constant","inline"] +],[ + "start", + ["keyword.operator.stylus","is"], + ["text"," "], + ["keyword.operator.stylus","not"] +],[ + "start", + ["entity.other.attribute-name.class.stylus",".signature-values"] +],[ + "start", + ["text"," "], + ["support.type","list-style"], + ["text"," "], + ["support.constant","none"] +],[ + "start", + ["text"," "], + ["support.type","display"], + ["text"," "], + ["support.constant","inline"] +],[ + "start", + ["text"," "], + ["support.type","margin-left"], + ["text"," "], + ["constant.numeric","0"] +],[ + "start", + ["entity.language.stylus"," &"], + ["punctuation",":"], + ["entity.other.attribute-name.pseudo-element.css","before"] +],[ + "start", + ["text"," "], + ["support.type","content"], + ["text"," "], + ["string","'→'"] +],[ + "start", + ["text"," "], + ["support.type","margin"], + ["text"," "], + ["constant.numeric","0"], + ["text"," "], + ["constant.numeric","5"], + ["keyword","px"] +],[ + "start", + ["text"," "], + ["keyword.operator.stylus",">"], + ["text"," "], + ["entity.name.tag.stylus","li"] +],[ + "start", + ["text"," "], + ["keyword.control.stylus","!important"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword.control.stylus","unless"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_svg.json b/node_modules/ace/lib/ace/mode/_test/tokens_svg.json new file mode 100644 index 00000000..66ebae75 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_svg.json @@ -0,0 +1,684 @@ +[[ + "meta.tag.punctuation.tag-open.xml1", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","svg"] +],[ + "meta.tag.punctuation.tag-open.xml1", + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","width"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"800\""], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","height"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"600\""] +],[ + "meta.tag.punctuation.tag-open.xml1", + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","xmlns"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"http://www.w3.org/2000/svg\""] +],[ + "start", + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","onload"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"StartAnimation(evt)\""], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start" +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","title"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text.xml","Test Tube Progress Bar"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","desc"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text.xml","Created for the Web Directions SVG competition"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start" +],[ + "js-no_regex", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.script.tag-name.xml","script"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","type"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"text/ecmascript\""], + ["meta.tag.punctuation.tag-close.xml",">"], + ["string.cdata.xml",""], + ["text"," "], + ["identifier","max_time"], + ["paren.rparen",")"] +],[ + "js-start", + ["text"," "], + ["keyword","return"], + ["punctuation.operator",";"] +],[ + "js-start", + ["text"," "], + ["comment","// Scale the text string gradually until it is 20 times larger"] +],[ + "js-start", + ["text"," "], + ["identifier","scalefactor"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["paren.lparen","("], + ["identifier","timevalue"], + ["text"," "], + ["keyword.operator","*"], + ["text"," "], + ["constant.numeric","650"], + ["paren.rparen",")"], + ["text"," "], + ["keyword.operator","/"], + ["text"," "], + ["identifier","max_time"], + ["punctuation.operator",";"] +],[ + "js-start" +],[ + "js-start", + ["text"," "], + ["keyword","if"], + ["text"," "], + ["paren.lparen","("], + ["identifier","timevalue"], + ["text"," "], + ["keyword.operator","<"], + ["text"," "], + ["constant.numeric","30"], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "js-start", + ["text"," "], + ["identifier","hickory"], + ["punctuation.operator","."], + ["support.function.dom","setAttribute"], + ["paren.lparen","("], + ["string","\"display\""], + ["punctuation.operator",","], + ["text"," "], + ["string","\"\""], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + "js-start", + ["text"," "], + ["identifier","hickory"], + ["punctuation.operator","."], + ["support.function.dom","setAttribute"], + ["paren.lparen","("], + ["string","\"transform\""], + ["punctuation.operator",","], + ["text"," "], + ["string","\"translate(\""], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["paren.lparen","("], + ["constant.numeric","600"], + ["keyword.operator","+"], + ["identifier","scalefactor"], + ["keyword.operator","*"], + ["constant.numeric","3"], + ["keyword.operator","*"], + ["constant.numeric","-1"], + ["text"," "], + ["paren.rparen",")"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["string","\", -144 )\""], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + "js-no_regex", + ["text"," "], + ["paren.rparen","}"] +],[ + "js-no_regex" +],[ + "js-start", + ["text"," "], + ["keyword","if"], + ["text"," "], + ["paren.lparen","("], + ["identifier","timevalue"], + ["text"," "], + ["keyword.operator",">"], + ["text"," "], + ["constant.numeric","30"], + ["text"," "], + ["keyword.operator","&&"], + ["text"," "], + ["identifier","timevalue"], + ["text"," "], + ["keyword.operator","<"], + ["text"," "], + ["constant.numeric","66"], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "js-start", + ["text"," "], + ["identifier","dickory"], + ["punctuation.operator","."], + ["support.function.dom","setAttribute"], + ["paren.lparen","("], + ["string","\"display\""], + ["punctuation.operator",","], + ["text"," "], + ["string","\"\""], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + "js-start", + ["text"," "], + ["identifier","dickory"], + ["punctuation.operator","."], + ["support.function.dom","setAttribute"], + ["paren.lparen","("], + ["string","\"transform\""], + ["punctuation.operator",","], + ["text"," "], + ["string","\"translate(\""], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["paren.lparen","("], + ["constant.numeric","-795"], + ["keyword.operator","+"], + ["identifier","scalefactor"], + ["keyword.operator","*"], + ["constant.numeric","2"], + ["paren.rparen",")"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["string","\", 0 )\""], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + "js-no_regex", + ["text"," "], + ["paren.rparen","}"] +],[ + "js-start", + ["text"," "], + ["keyword","if"], + ["text"," "], + ["paren.lparen","("], + ["identifier","timevalue"], + ["text"," "], + ["keyword.operator",">"], + ["text"," "], + ["constant.numeric","66"], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "js-start", + ["text"," "], + ["identifier","dock"], + ["punctuation.operator","."], + ["support.function.dom","setAttribute"], + ["paren.lparen","("], + ["string","\"display\""], + ["punctuation.operator",","], + ["text"," "], + ["string","\"\""], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + "js-start", + ["text"," "], + ["identifier","dock"], + ["punctuation.operator","."], + ["support.function.dom","setAttribute"], + ["paren.lparen","("], + ["string","\"transform\""], + ["punctuation.operator",","], + ["text"," "], + ["string","\"translate(\""], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["paren.lparen","("], + ["constant.numeric","1450"], + ["keyword.operator","+"], + ["identifier","scalefactor"], + ["keyword.operator","*"], + ["constant.numeric","2"], + ["keyword.operator","*"], + ["constant.numeric","-1"], + ["paren.rparen",")"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["string","\", 144 )\""], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + "js-no_regex", + ["text"," "], + ["paren.rparen","}"] +],[ + "js-no_regex" +],[ + "js-no_regex", + ["text"," "], + ["comment","// Call ShowAndGrowElement again milliseconds later."] +],[ + "js-no_regex", + ["text"," "], + ["identifier","setTimeout"], + ["paren.lparen","("], + ["string","\"ShowAndGrowElement()\""], + ["punctuation.operator",","], + ["text"," "], + ["identifier","timer_increment"], + ["paren.rparen",")"] +],[ + "js-no_regex", + ["text"," "], + ["paren.rparen","}"] +],[ + "js-no_regex", + ["text"," "], + ["variable.language","window"], + ["punctuation.operator","."], + ["identifier","ShowAndGrowElement"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["identifier","ShowAndGrowElement"] +],[ + "start", + ["text"," "], + ["string.cdata.xml","]]>"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start" +],[ + "meta.tag.punctuation.tag-open.xml1", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","rect"] +],[ + "meta.tag.punctuation.tag-open.xml1", + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","fill"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"#2e3436\""] +],[ + "meta.tag.punctuation.tag-open.xml1", + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","fill-rule"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"nonzero\""] +],[ + "meta.tag.punctuation.tag-open.xml1", + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","stroke-width"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"3\""] +],[ + "meta.tag.punctuation.tag-open.xml1", + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","y"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"0\""] +],[ + "meta.tag.punctuation.tag-open.xml1", + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","x"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"0\""] +],[ + "meta.tag.punctuation.tag-open.xml1", + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","height"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"600\""] +],[ + "meta.tag.punctuation.tag-open.xml1", + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","width"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"800\""] +],[ + "start", + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","id"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"rect3590\""], + ["meta.tag.punctuation.tag-close.xml","/>"] +],[ + "start" +],[ + "meta.tag.punctuation.tag-open.xml1", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","text"] +],[ + "meta.tag.punctuation.tag-open.xml1", + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","style"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"font-size:144px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Bold\""] +],[ + "meta.tag.punctuation.tag-open.xml1", + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","x"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"50\""] +],[ + "meta.tag.punctuation.tag-open.xml1", + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","y"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"350\""] +],[ + "meta.tag.punctuation.tag-open.xml1", + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","id"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"hickory\""] +],[ + "start", + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","display"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"none\""], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," Hickory,"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "meta.tag.punctuation.tag-open.xml1", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","text"] +],[ + "meta.tag.punctuation.tag-open.xml1", + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","style"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"font-size:144px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Bold\""] +],[ + "meta.tag.punctuation.tag-open.xml1", + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","x"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"50\""] +],[ + "meta.tag.punctuation.tag-open.xml1", + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","y"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"350\""] +],[ + "meta.tag.punctuation.tag-open.xml1", + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","id"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"dickory\""] +],[ + "start", + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","display"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"none\""], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," dickory,"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "meta.tag.punctuation.tag-open.xml1", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","text"] +],[ + "meta.tag.punctuation.tag-open.xml1", + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","style"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"font-size:144px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Bold\""] +],[ + "meta.tag.punctuation.tag-open.xml1", + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","x"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"50\""] +],[ + "meta.tag.punctuation.tag-open.xml1", + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","y"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"350\""] +],[ + "meta.tag.punctuation.tag-open.xml1", + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","id"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"dock\""] +],[ + "start", + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","display"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"none\""], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," dock!"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["meta.tag.punctuation.end-tag-open.xml",""] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_tcl.json b/node_modules/ace/lib/ace/mode/_test/tokens_tcl.json new file mode 100644 index 00000000..6a032ddc --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_tcl.json @@ -0,0 +1,385 @@ +[[ + "commandItem" +],[ + "commandItem", + ["keyword","proc"], + ["text"," "], + ["identifier","dijkstra"], + ["text"," "], + ["paren.lparen","{"], + ["keyword","graph"], + ["text"," "], + ["identifier","origin"], + ["paren.rparen","}"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["comment","# Initialize"] +],[ + "commandItem", + ["text"," "], + ["keyword","dict"], + ["text"," "], + ["identifier","for"], + ["text"," "], + ["paren.lparen","{"], + ["keyword","vertex"], + ["text"," "], + ["identifier","distmap"], + ["paren.rparen","}"], + ["text"," "], + ["variable.instance","$graph"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text","\t"], + ["keyword","dict"], + ["text"," "], + ["identifier","set"], + ["text"," "], + ["identifier","dist"], + ["text"," "], + ["variable.instance","$vertex"], + ["text"," "], + ["identifier","Inf"] +],[ + "commandItem", + ["text","\t"], + ["keyword","dict"], + ["text"," "], + ["identifier","set"], + ["text"," "], + ["identifier","path"], + ["text"," "], + ["variable.instance","$vertex"], + ["text"," "], + ["paren.lparen","{"], + ["paren.rparen","}"] +],[ + "commandItem", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["text"," "], + ["keyword","dict"], + ["text"," "], + ["identifier","set"], + ["text"," "], + ["identifier","dist"], + ["text"," "], + ["variable.instance","$origin"], + ["text"," 0"] +],[ + "start", + ["text"," "], + ["keyword","dict"], + ["text"," "], + ["identifier","set"], + ["text"," "], + ["identifier","path"], + ["text"," "], + ["variable.instance","$origin"], + ["text"," "], + ["paren.lparen","["], + ["keyword","list"], + ["text"," "], + ["variable.instance","$origin"], + ["paren.rparen","]"] +],[ + "commandItem", + ["text"," "] +],[ + "commandItem", + ["text"," "], + ["keyword","while"], + ["text"," "], + ["paren.lparen","{"], + ["text","["], + ["keyword","dict"], + ["text"," "], + ["identifier","size"], + ["text"," "], + ["variable.instance","$graph"], + ["paren.rparen","]}"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text","\t"], + ["comment","# Find unhandled node with least weight"] +],[ + "start", + ["text","\t"], + ["keyword","set"], + ["text"," "], + ["identifier","d"], + ["text"," "], + ["identifier","Inf"] +],[ + "commandItem", + ["text","\t"], + ["keyword","dict"], + ["text"," "], + ["identifier","for"], + ["text"," "], + ["paren.lparen","{"], + ["keyword","uu"], + ["text"," "], + ["support.function","-"], + ["paren.rparen","}"], + ["text"," "], + ["variable.instance","$graph"], + ["text"," "], + ["paren.lparen","{"] +],[ + "commandItem", + ["text","\t "], + ["keyword","if"], + ["text"," "], + ["paren.lparen","{"], + ["variable.instance","$d"], + ["text"," "], + ["support.function",">"], + ["text"," "], + ["paren.lparen","["], + ["keyword","set"], + ["text"," "], + ["identifier","dd"], + ["text"," "], + ["paren.lparen","["], + ["keyword","dict"], + ["text"," "], + ["identifier","get"], + ["text"," "], + ["variable.instance","$dist"], + ["text"," "], + ["variable.instance","$uu"], + ["paren.rparen","]]}"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text","\t\t"], + ["keyword","set"], + ["text"," "], + ["identifier","u"], + ["text"," "], + ["variable.instance","$uu"] +],[ + "start", + ["text","\t\t"], + ["keyword","set"], + ["text"," "], + ["identifier","d"], + ["text"," "], + ["variable.instance","$dd"] +],[ + "commandItem", + ["text","\t "], + ["paren.rparen","}"] +],[ + "commandItem", + ["text","\t"], + ["paren.rparen","}"] +],[ + "commandItem", + ["text"," "] +],[ + "start", + ["text","\t"], + ["comment","# No such node; graph must be disconnected"] +],[ + "start", + ["text","\t"], + ["keyword","if"], + ["text"," "], + ["paren.lparen","{"], + ["variable.instance","$d"], + ["text"," "], + ["support.function","=="], + ["text"," "], + ["identifier","Inf"], + ["paren.rparen","}"], + ["text"," "], + ["identifier","break"] +],[ + "commandItem", + ["text"," "] +],[ + "commentfollow", + ["text","\t"], + ["comment","# Update the weights for nodes\\"] +],[ + "start", + ["comment","\t lead to by the node we've picked"] +],[ + "commandItem", + ["text","\t"], + ["keyword","dict"], + ["text"," "], + ["identifier","for"], + ["text"," "], + ["paren.lparen","{"], + ["keyword","v"], + ["text"," "], + ["identifier","dd"], + ["paren.rparen","}"], + ["text"," "], + ["paren.lparen","["], + ["keyword","dict"], + ["text"," "], + ["identifier","get"], + ["text"," "], + ["variable.instance","$graph"], + ["text"," "], + ["variable.instance","$u"], + ["paren.rparen","]"], + ["text"," "], + ["paren.lparen","{"] +],[ + "commandItem", + ["text","\t "], + ["keyword","if"], + ["text"," "], + ["paren.lparen","{"], + ["text","["], + ["keyword","dict"], + ["text"," "], + ["identifier","exists"], + ["text"," "], + ["variable.instance","$graph"], + ["text"," "], + ["variable.instance","$v"], + ["paren.rparen","]}"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text","\t\t"], + ["keyword","set"], + ["text"," "], + ["identifier","alt"], + ["text"," "], + ["paren.lparen","["], + ["keyword","expr"], + ["text"," "], + ["paren.lparen","{"], + ["variable.instance","$d"], + ["text"," "], + ["support.function","+"], + ["text"," "], + ["variable.instance","$dd"], + ["paren.rparen","}]"] +],[ + "commandItem", + ["text","\t\t"], + ["keyword","if"], + ["text"," "], + ["paren.lparen","{"], + ["variable.instance","$alt"], + ["text"," "], + ["support.function","<"], + ["text"," "], + ["paren.lparen","["], + ["keyword","dict"], + ["text"," "], + ["identifier","get"], + ["text"," "], + ["variable.instance","$dist"], + ["text"," "], + ["variable.instance","$v"], + ["paren.rparen","]}"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text","\t\t "], + ["keyword","dict"], + ["text"," "], + ["identifier","set"], + ["text"," "], + ["identifier","dist"], + ["text"," "], + ["variable.instance","$v"], + ["text"," "], + ["variable.instance","$alt"] +],[ + "start", + ["text","\t\t "], + ["keyword","dict"], + ["text"," "], + ["identifier","set"], + ["text"," "], + ["identifier","path"], + ["text"," "], + ["variable.instance","$v"], + ["text"," "], + ["paren.lparen","["], + ["keyword","list"], + ["text"," "], + ["support.function","{*}"], + ["paren.lparen","["], + ["keyword","dict"], + ["text"," "], + ["identifier","get"], + ["text"," "], + ["variable.instance","$path"], + ["text"," "], + ["variable.instance","$u"], + ["paren.rparen","]"], + ["text"," "], + ["variable.instance","$v"], + ["paren.rparen","]"] +],[ + "commandItem", + ["text","\t\t"], + ["paren.rparen","}"] +],[ + "commandItem", + ["text","\t "], + ["paren.rparen","}"] +],[ + "commandItem", + ["text","\t"], + ["paren.rparen","}"] +],[ + "commandItem", + ["text"," "] +],[ + "start", + ["text","\t"], + ["comment","# Remove chosen node from graph still to be handled"] +],[ + "start", + ["text","\t"], + ["keyword","dict"], + ["text"," "], + ["identifier","unset"], + ["text"," "], + ["identifier","graph"], + ["text"," "], + ["variable.instance","$u"] +],[ + "commandItem", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["text"," "], + ["keyword","return"], + ["text"," "], + ["paren.lparen","["], + ["keyword","list"], + ["text"," "], + ["variable.instance","$dist"], + ["text"," "], + ["variable.instance","$path"], + ["paren.rparen","]"] +],[ + "commandItem", + ["paren.rparen","}"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_tex.json b/node_modules/ace/lib/ace/mode/_test/tokens_tex.json new file mode 100644 index 00000000..2d023676 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_tex.json @@ -0,0 +1,130 @@ +[[ + "start", + ["text","The quadratic formula is $$-b "], + ["keyword","\\pm"], + ["text"," "], + ["keyword","\\sqrt"], + ["paren.keyword.operator","{"], + ["text","b^2 - 4ac"], + ["paren.keyword.operator","}"], + ["text"," "], + ["keyword","\\over"], + ["text"," 2a$$"] +],[ + "start", + ["keyword","\\bye"] +],[ + "start" +],[ + "start", + ["keyword","\\makeatletter"] +],[ + "start", + ["text"," "], + ["keyword","\\newcommand"], + ["paren.keyword.operator","{"], + ["keyword","\\be"], + ["paren.keyword.operator","}{"], + ["comment","%"] +],[ + "start", + ["text"," "], + ["keyword","\\begingroup"] +],[ + "start", + ["text"," "], + ["comment","% \\setlength{\\arraycolsep}{2pt}"] +],[ + "start", + ["text"," "], + ["keyword","\\eqnarray"], + ["comment","%"] +],[ + "start", + ["text"," "], + ["keyword","\\@"], + ["text","ifstar"], + ["paren.keyword.operator","{"], + ["keyword","\\nonumber"], + ["paren.keyword.operator","}{}"], + ["comment","%"] +],[ + "start", + ["text"," "], + ["paren.keyword.operator","}"] +],[ + "start", + ["text"," "], + ["keyword","\\newcommand"], + ["paren.keyword.operator","{"], + ["keyword","\\ee"], + ["paren.keyword.operator","}{"], + ["keyword","\\endeqnarray\\endgroup"], + ["paren.keyword.operator","}"] +],[ + "start", + ["text"," "], + ["keyword","\\makeatother"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword","\\begin"], + ["paren.keyword.operator","{"], + ["nospell.text","equation"], + ["paren.keyword.operator","}"] +],[ + "start", + ["text"," x="], + ["keyword","\\left\\"], + ["paren.keyword.operator","{"], + ["text"," "], + ["keyword","\\begin"], + ["paren.keyword.operator","{"], + ["nospell.text","array"], + ["paren.keyword.operator","}{"], + ["text","cl"], + ["paren.keyword.operator","}"] +],[ + "start", + ["text"," 0 & "], + ["keyword","\\textrm"], + ["paren.keyword.operator","{"], + ["text","if "], + ["paren.keyword.operator","}"], + ["text","A="], + ["keyword","\\ldots\\\\"] +],[ + "start", + ["text"," 1 & "], + ["keyword","\\textrm"], + ["paren.keyword.operator","{"], + ["text","if "], + ["paren.keyword.operator","}"], + ["text","B="], + ["keyword","\\ldots\\\\"] +],[ + "start", + ["text"," x & "], + ["keyword","\\textrm"], + ["paren.keyword.operator","{"], + ["text","this runs with as much text as you like, but without an raggeright text"] +],[ + "start", + ["text","."], + ["paren.keyword.operator","}"], + ["keyword","\\end"], + ["paren.keyword.operator","{"], + ["nospell.text","array"], + ["paren.keyword.operator","}"], + ["keyword","\\right"], + ["text","."] +],[ + "start", + ["text"," "], + ["keyword","\\end"], + ["paren.keyword.operator","{"], + ["nospell.text","equation"], + ["paren.keyword.operator","}"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_text.json b/node_modules/ace/lib/ace/mode/_test/tokens_text.json new file mode 100644 index 00000000..fff7ef42 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_text.json @@ -0,0 +1,29 @@ +[[ + "start", + ["text","Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet."] +],[ + "start" +],[ + "start", + ["text","Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat."] +],[ + "start" +],[ + "start", + ["text","Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi."] +],[ + "start" +],[ + "start", + ["text","Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat."] +],[ + "start" +],[ + "start", + ["text","Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis."] +],[ + "start" +],[ + "start", + ["text","At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores duo eirmod eos erat, et nonumy sed tempor et et invidunt justo labore Stet clita ea et gubergren, kasd magna no rebum. sanctus sea sed takimata ut vero voluptua. est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_textile.json b/node_modules/ace/lib/ace/mode/_test/tokens_textile.json new file mode 100644 index 00000000..59000ce3 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_textile.json @@ -0,0 +1,113 @@ +[[ + "start", + ["markup.heading.1","h1"], + ["keyword",". "], + ["text","Textile document"] +],[ + "start" +],[ + "start", + ["markup.heading.2","h2"], + ["keyword",". "], + ["text","Heading Two"] +],[ + "start" +],[ + "start", + ["markup.heading.3","h3"], + ["keyword",". "], + ["text","A two-line"] +],[ + "start", + ["text"," header"] +],[ + "start" +],[ + "start", + ["markup.heading.2","h2"], + ["keyword",". "], + ["text","Another two-line"] +],[ + "start", + ["text","header"] +],[ + "start" +],[ + "start", + ["text","Paragraph:"] +],[ + "start", + ["text","one, two,"] +],[ + "start", + ["text","thee lines!"] +],[ + "start" +],[ + "start", + ["markup.heading","p"], + ["keyword","("], + ["string","classone"], + ["text"," "], + ["string","two"], + ["text"," "], + ["string","three"], + ["keyword","). "], + ["text","This is a paragraph with classes"] +],[ + "start" +],[ + "start", + ["markup.heading","p"], + ["keyword","(#"], + ["string","id"], + ["keyword","). "], + ["text","(one with an id)"] +],[ + "start" +],[ + "start", + ["markup.heading","p"], + ["keyword","("], + ["string","one"], + ["text"," "], + ["string","two"], + ["text"," "], + ["string","three"], + ["keyword","#"], + ["string","my_id"], + ["keyword","). "], + ["text","..classes + id"] +],[ + "start" +],[ + "start", + ["keyword","*"], + ["text"," Unordered list"] +],[ + "start", + ["keyword","**"], + ["text"," sublist"] +],[ + "start", + ["keyword","*"], + ["text"," back again!"] +],[ + "start", + ["keyword","**"], + ["text"," sublist again.."] +],[ + "start" +],[ + "start", + ["keyword","#"], + ["text"," ordered"] +],[ + "start" +],[ + "start", + ["text","bg. Blockquote!"] +],[ + "start", + ["text"," This is a two-list blockquote..!"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_toml.json b/node_modules/ace/lib/ace/mode/_test/tokens_toml.json new file mode 100644 index 00000000..ec471f74 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_toml.json @@ -0,0 +1,131 @@ +[[ + "start", + ["comment.toml","# This is a TOML document. Boom."] +],[ + "start" +],[ + "start", + ["identifier","title"], + ["text"," = "], + ["string","\"TOML Example\""] +],[ + "start" +],[ + "start", + ["variable.keygroup.toml","[owner]"] +],[ + "start", + ["identifier","name"], + ["text"," = "], + ["string","\"Tom Preston-Werner\""] +],[ + "start", + ["identifier","organization"], + ["text"," = "], + ["string","\"GitHub\""] +],[ + "start", + ["identifier","bio"], + ["text"," = "], + ["string","\"GitHub Cofounder & CEO"], + ["constant.language.escape","\\n"], + ["string","Likes tater tots and beer.\""] +],[ + "start", + ["identifier","dob"], + ["text"," = "], + ["support.date.toml","1979-05-27T07:32:00Z"], + ["text"," "], + ["comment.toml","# First class dates? Why not?"] +],[ + "start" +],[ + "start", + ["variable.keygroup.toml","[database]"] +],[ + "start", + ["identifier","server"], + ["text"," = "], + ["string","\"192.168.1.1\""] +],[ + "start", + ["identifier","ports"], + ["text"," = [ "], + ["constant.numeric.toml","8001"], + ["text",", "], + ["constant.numeric.toml","8001"], + ["text",", "], + ["constant.numeric.toml","8002"], + ["text"," ]"] +],[ + "start", + ["identifier","connection_max"], + ["text"," = "], + ["constant.numeric.toml","5000"] +],[ + "start", + ["identifier","enabled"], + ["text"," = "], + ["constant.language.boolean","true"] +],[ + "start" +],[ + "start", + ["variable.keygroup.toml","[servers]"] +],[ + "start" +],[ + "start", + ["text"," "], + ["comment.toml","# You can indent as you please. Tabs or spaces. TOML don't care."] +],[ + "start", + ["variable.keygroup.toml"," [servers.alpha]"] +],[ + "start", + ["text"," "], + ["identifier","ip"], + ["text"," = "], + ["string","\"10.0.0.1\""] +],[ + "start", + ["text"," "], + ["identifier","dc"], + ["text"," = "], + ["string","\"eqdc10\""] +],[ + "start" +],[ + "start", + ["variable.keygroup.toml"," [servers.beta]"] +],[ + "start", + ["text"," "], + ["identifier","ip"], + ["text"," = "], + ["string","\"10.0.0.2\""] +],[ + "start", + ["text"," "], + ["identifier","dc"], + ["text"," = "], + ["string","\"eqdc10\""] +],[ + "start" +],[ + "start", + ["variable.keygroup.toml","[clients]"] +],[ + "start", + ["identifier","data"], + ["text"," = [ ["], + ["string","\"gamma\""], + ["text",", "], + ["string","\"delta\""], + ["text","], ["], + ["constant.numeric.toml","1"], + ["text",", "], + ["constant.numeric.toml","2"], + ["text","] ] "], + ["comment.toml","# just an update to make sure parsers support it"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_twig.json b/node_modules/ace/lib/ace/mode/_test/tokens_twig.json new file mode 100644 index 00000000..ada8b4a7 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_twig.json @@ -0,0 +1,288 @@ +[[ + "start", + ["xml-pe.doctype.xml",""] +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","html"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","head"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","title"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text.xml","My Webpage"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","body"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","ul"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","id"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"navigation\""], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.twig","{%"], + ["text"," "], + ["keyword.control.twig","for"], + ["text"," "], + ["identifier","item"], + ["text"," "], + ["keyword.operator.twig","in"], + ["text"," "], + ["identifier","navigation"], + ["text"," "], + ["meta.tag.twig","%}"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","li"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.anchor.tag-name.xml","a"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","href"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\""], + ["variable.other.readwrite.local.twig","{{"], + ["text"," "], + ["identifier","item"], + ["punctuation.operator","."], + ["identifier","href"], + ["keyword.operator.other","|"], + ["support.function.twig","escape"], + ["text"," "], + ["variable.other.readwrite.local.twig","}}"], + ["string.attribute-value.xml","\""], + ["meta.tag.punctuation.tag-close.xml",">"], + ["variable.other.readwrite.local.twig","{{"], + ["text"," "], + ["identifier","item"], + ["punctuation.operator","."], + ["identifier","caption"], + ["text"," "], + ["variable.other.readwrite.local.twig","}}"], + ["meta.tag.punctuation.end-tag-open.xml",""], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "], + ["meta.tag.twig","{%"], + ["text"," "], + ["keyword.control.twig","endfor"], + ["text"," "], + ["meta.tag.twig","%}"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start" +],[ + "start", + ["text.xml"," "], + ["meta.tag.twig","{%"], + ["text"," "], + ["keyword.control.twig","if"], + ["text"," "], + ["constant.numeric","1"], + ["text"," "], + ["keyword.operator.twig","not"], + ["text"," "], + ["keyword.operator.twig","in"], + ["text"," "], + ["paren.lparen","["], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["text"," "], + ["constant.numeric","2"], + ["punctuation.operator",","], + ["text"," "], + ["constant.numeric","3"], + ["paren.rparen","]"], + ["text"," "], + ["meta.tag.twig","%}"] +],[ + "start" +],[ + "start", + ["text.xml"," "], + ["comment.block.twig","{# is equivalent to #}"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.twig","{%"], + ["text"," "], + ["keyword.control.twig","if"], + ["text"," "], + ["keyword.operator.twig","not"], + ["text"," "], + ["paren.lparen","("], + ["constant.numeric","1"], + ["text"," "], + ["keyword.operator.twig","in"], + ["text"," "], + ["paren.lparen","["], + ["constant.numeric","1"], + ["punctuation.operator",","], + ["text"," "], + ["constant.numeric","2"], + ["punctuation.operator",","], + ["text"," "], + ["constant.numeric","3"], + ["paren.rparen","])"], + ["text"," "], + ["meta.tag.twig","%}"] +],[ + "start" +],[ + "start", + ["text.xml"," "], + ["meta.tag.twig","{%"], + ["text"," "], + ["keyword.control.twig","autoescape"], + ["text"," "], + ["constant.language.boolean","true"], + ["text"," "], + ["meta.tag.twig","%}"] +],[ + "start", + ["text.xml"," "], + ["variable.other.readwrite.local.twig","{{"], + ["text"," "], + ["identifier","var"], + ["text"," "], + ["variable.other.readwrite.local.twig","}}"] +],[ + "start", + ["text.xml"," "], + ["variable.other.readwrite.local.twig","{{"], + ["text"," "], + ["identifier","var"], + ["keyword.operator.other","|"], + ["support.function.twig","raw"], + ["text"," "], + ["variable.other.readwrite.local.twig","}}"], + ["text.xml"," "], + ["comment.block.twig","{# var won't be escaped #}"] +],[ + "start", + ["text.xml"," "], + ["variable.other.readwrite.local.twig","{{"], + ["text"," "], + ["identifier","var"], + ["keyword.operator.other","|"], + ["support.function.twig","escape"], + ["text"," "], + ["variable.other.readwrite.local.twig","}}"], + ["text.xml"," "], + ["comment.block.twig","{# var won't be doubled-escaped #}"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.twig","{%"], + ["text"," "], + ["keyword.control.twig","endautoescape"], + ["text"," "], + ["meta.tag.twig","%}"] +],[ + "start" +],[ + "start", + ["text.xml"," "], + ["variable.other.readwrite.local.twig","{{"], + ["text"," "], + ["keyword.control.twig","include"], + ["paren.lparen","("], + ["string","'twig.html'"], + ["punctuation.operator",","], + ["text"," "], + ["identifier","sandboxed"], + ["text"," "], + ["keyword.operator.assignment","="], + ["text"," "], + ["constant.language.boolean","true"], + ["paren.rparen",")"], + ["text"," "], + ["variable.other.readwrite.local.twig","}}"] +],[ + "start" +],[ + "start", + ["text.xml"," "], + ["variable.other.readwrite.local.twig","{{"], + ["string","\"string "], + ["constant.language.escape","#{with}"], + ["string"," "], + ["constant.language.escape","\\\""], + ["string"," escapes\""], + ["text"," "], + ["string","'another#one'"], + ["text"," "], + ["variable.other.readwrite.local.twig","}}"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","h1"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text.xml","My Webpage"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml"," "], + ["variable.other.readwrite.local.twig","{{"], + ["text"," "], + ["identifier","a_variable"], + ["text"," "], + ["variable.other.readwrite.local.twig","}}"] +],[ + "start", + ["text.xml"," "], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["meta.tag.punctuation.end-tag-open.xml",""] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_typescript.json b/node_modules/ace/lib/ace/mode/_test/tokens_typescript.json new file mode 100644 index 00000000..18f2eea6 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_typescript.json @@ -0,0 +1,559 @@ +[[ + "start", + ["keyword.operator.ts","class"], + ["text"," "], + ["identifier","Greeter"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text","\t"], + ["variable.parameter.function.ts","greeting"], + ["text",": "], + ["variable.parameter.function.ts","string"], + ["punctuation.operator",";"] +],[ + "start", + ["text","\t"], + ["keyword.operator.ts","constructor"], + ["text"," "], + ["paren.lparen","("], + ["variable.parameter.function.ts","message"], + ["text",": "], + ["variable.parameter.function.ts","string"], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text","\t\t"], + ["storage.type.variable.ts","this."], + ["identifier","greeting"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["identifier","message"], + ["punctuation.operator",";"] +],[ + "no_regex", + ["text","\t"], + ["paren.rparen","}"] +],[ + "start", + ["text","\t"], + ["identifier","greet"], + ["paren.lparen","("], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text","\t\t"], + ["keyword","return"], + ["text"," "], + ["string","\"Hello, \""], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["storage.type.variable.ts","this."], + ["identifier","greeting"], + ["punctuation.operator",";"] +],[ + "no_regex", + ["text","\t"], + ["paren.rparen","}"] +],[ + "no_regex", + ["paren.rparen","}"], + ["text"," "] +],[ + "no_regex" +],[ + "start", + ["storage.type","var"], + ["text"," "], + ["identifier","greeter"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["keyword","new"], + ["text"," "], + ["identifier","Greeter"], + ["paren.lparen","("], + ["string","\"world\""], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + "start" +],[ + "no_regex", + ["storage.type","var"], + ["text"," "], + ["identifier","button"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["variable.language","document"], + ["punctuation.operator","."], + ["support.function.dom","createElement"], + ["paren.lparen","("], + ["string","'button'"], + ["paren.rparen",")"] +],[ + "no_regex", + ["identifier","button"], + ["punctuation.operator","."], + ["identifier","innerText"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["string","\"Say Hello\""] +],[ + "start", + ["storage.type","button"], + ["punctuation.operator","."], + ["entity.name.function","onclick"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["storage.type","function"], + ["paren.lparen","("], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "no_regex", + ["text","\t"], + ["support.function","alert"], + ["paren.lparen","("], + ["entity.name.function.ts","greeter.greet"], + ["paren.lparen","("], + ["paren.rparen",")"], + ["paren.rparen",")"] +],[ + "no_regex", + ["paren.rparen","}"] +],[ + "no_regex" +],[ + "no_regex", + ["variable.language","document"], + ["punctuation.operator","."], + ["identifier","body"], + ["punctuation.operator","."], + ["support.function.dom","appendChild"], + ["paren.lparen","("], + ["identifier","button"], + ["paren.rparen",")"] +],[ + "no_regex" +],[ + "start", + ["keyword","class"], + ["text"," "], + ["identifier","Snake"], + ["text"," "], + ["keyword","extends"], + ["text"," "], + ["identifier","Animal"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["entity.name.function.ts","move"], + ["paren.lparen","("], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["support.function","alert"], + ["paren.lparen","("], + ["string","\"Slithering...\""], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "], + ["storage.type.variable.ts","super"], + ["text","("], + ["keyword.other.ts","5"], + ["text",")"], + ["punctuation.operator",";"] +],[ + "no_regex", + ["text"," "], + ["paren.rparen","}"] +],[ + "no_regex", + ["paren.rparen","}"] +],[ + "no_regex" +],[ + "start", + ["keyword","class"], + ["text"," "], + ["identifier","Horse"], + ["text"," "], + ["keyword","extends"], + ["text"," "], + ["identifier","Animal"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["entity.name.function.ts","move"], + ["paren.lparen","("], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["support.function","alert"], + ["paren.lparen","("], + ["string","\"Galloping...\""], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "], + ["keyword.operator.ts","super"], + ["punctuation.operator","."], + ["identifier","move"], + ["paren.lparen","("], + ["constant.numeric","45"], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + "no_regex", + ["text"," "], + ["paren.rparen","}"] +],[ + "no_regex", + ["paren.rparen","}"] +],[ + "no_regex" +],[ + "start", + ["identifier","module"], + ["text"," "], + ["identifier","Sayings"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["keyword.operator.ts","export"], + ["text"," "], + ["keyword.operator.ts","class"], + ["text"," "], + ["identifier","Greeter"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["variable.parameter.function.ts","greeting"], + ["text",": "], + ["variable.parameter.function.ts","string"], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "], + ["keyword.operator.ts","constructor"], + ["text"," "], + ["paren.lparen","("], + ["variable.parameter.function.ts","message"], + ["text",": "], + ["variable.parameter.function.ts","string"], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["storage.type.variable.ts","this."], + ["identifier","greeting"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["identifier","message"], + ["punctuation.operator",";"] +],[ + "no_regex", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["text"," "], + ["identifier","greet"], + ["paren.lparen","("], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["keyword","return"], + ["text"," "], + ["string","\"Hello, \""], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["storage.type.variable.ts","this."], + ["identifier","greeting"], + ["punctuation.operator",";"] +],[ + "no_regex", + ["text"," "], + ["paren.rparen","}"] +],[ + "no_regex", + ["text"," "], + ["paren.rparen","}"] +],[ + "no_regex", + ["paren.rparen","}"] +],[ + "start", + ["identifier","module"], + ["text"," "], + ["identifier","Mankala"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["keyword.operator.ts","export"], + ["text"," "], + ["keyword.operator.ts","class"], + ["text"," "], + ["identifier","Features"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["keyword.operator.ts","public"], + ["text"," "], + ["identifier","turnContinues"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["constant.language.boolean","false"], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "], + ["keyword.operator.ts","public"], + ["text"," "], + ["identifier","seedStoredCount"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["constant.numeric","0"], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "], + ["keyword.operator.ts","public"], + ["text"," "], + ["identifier","capturedCount"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["constant.numeric","0"], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "], + ["keyword.operator.ts","public"], + ["text"," "], + ["identifier","spaceCaptured"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["identifier","NoSpace"], + ["punctuation.operator",";"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword.operator.ts","public"], + ["text"," "], + ["entity.name.function.ts","clear"], + ["paren.lparen","("], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["storage.type.variable.ts","this."], + ["identifier","turnContinues"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["constant.language.boolean","false"], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "], + ["storage.type.variable.ts","this."], + ["identifier","seedStoredCount"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["constant.numeric","0"], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "], + ["storage.type.variable.ts","this."], + ["identifier","capturedCount"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["constant.numeric","0"], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "], + ["storage.type.variable.ts","this."], + ["identifier","spaceCaptured"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["identifier","NoSpace"], + ["punctuation.operator",";"] +],[ + "no_regex", + ["text"," "], + ["paren.rparen","}"] +],[ + "no_regex" +],[ + "start", + ["text"," "], + ["keyword","public"], + ["text"," "], + ["identifier","toString"], + ["paren.lparen","("], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["storage.type","var"], + ["text"," "], + ["identifier","stringBuilder"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["string","\"\""], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "], + ["keyword","if"], + ["text"," "], + ["paren.lparen","("], + ["storage.type.variable.ts","this."], + ["identifier","turnContinues"], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["identifier","stringBuilder"], + ["text"," "], + ["keyword.operator","+="], + ["text"," "], + ["string","\" turn continues,\""], + ["punctuation.operator",";"] +],[ + "no_regex", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["text"," "], + ["identifier","stringBuilder"], + ["text"," "], + ["keyword.operator","+="], + ["text"," "], + ["string","\" stores \""], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["storage.type.variable.ts","this."], + ["identifier","seedStoredCount"], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "], + ["keyword","if"], + ["text"," "], + ["paren.lparen","("], + ["storage.type.variable.ts","this."], + ["identifier","capturedCount"], + ["text"," "], + ["keyword.operator",">"], + ["text"," "], + ["constant.numeric","0"], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "start", + ["text"," "], + ["identifier","stringBuilder"], + ["text"," "], + ["keyword.operator","+="], + ["text"," "], + ["string","\" captures \""], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["storage.type.variable.ts","this."], + ["identifier","capturedCount"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["string","\" from space \""], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["storage.type.variable.ts","this."], + ["identifier","spaceCaptured"], + ["punctuation.operator",";"] +],[ + "no_regex", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["text"," "], + ["keyword","return"], + ["text"," "], + ["identifier","stringBuilder"], + ["punctuation.operator",";"] +],[ + "no_regex", + ["text"," "], + ["paren.rparen","}"] +],[ + "no_regex", + ["text"," "], + ["paren.rparen","}"] +],[ + "no_regex", + ["paren.rparen","}"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_vala.json b/node_modules/ace/lib/ace/mode/_test/tokens_vala.json new file mode 100644 index 00000000..efe6e7c8 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_vala.json @@ -0,0 +1,158 @@ +[[ + "start", + ["meta.using.vala",""], + ["keyword.other.using.vala","using"], + ["meta.using.vala"," "], + ["storage.modifier.using.vala","Gtk"], + ["punctuation.terminator.vala",";"] +],[ + "start", + ["text"," "] +],[ + "text0", + ["storage.type.primitive.array.vala","int"], + ["text"," main ("], + ["storage.type.primitive.array.vala","string"], + ["text","[] args) {"] +],[ + "text0", + ["text"," "], + ["storage.type.vala","Gtk"], + ["keyword.operator.dereference.vala","."], + ["text","init ("], + ["storage.modifier.vala","ref"], + ["text"," args)"], + ["punctuation.terminator.vala",";"] +],[ + "text0", + ["text"," "], + ["storage.type.primitive.vala","var"], + ["text"," foo "], + ["keyword.operator.assignment.vala","="], + ["text"," "], + ["keyword.control.new.vala","new"], + ["text"," "], + ["storage.type.generic.vala","MyFoo>"], + ["text","()"], + ["punctuation.terminator.vala",";"] +],[ + "text0" +],[ + "text0", + ["text"," "], + ["storage.type.primitive.vala","var"], + ["text"," window "], + ["keyword.operator.assignment.vala","="], + ["text"," "], + ["keyword.control.new.vala","new"], + ["text"," "], + ["storage.type.vala","Window"], + ["text","()"], + ["punctuation.terminator.vala",";"] +],[ + "text0", + ["text"," window"], + ["keyword.operator.dereference.vala","."], + ["text","title "], + ["keyword.operator.assignment.vala","="], + ["text"," "], + ["punctuation.definition.string.begin.vala","\""], + ["string.quoted.double.vala","Hello, World!"], + ["punctuation.definition.string.end.vala","\""], + ["punctuation.terminator.vala",";"] +],[ + "text0", + ["text"," window"], + ["keyword.operator.dereference.vala","."], + ["text","border_width "], + ["keyword.operator.assignment.vala","="], + ["text"," "], + ["constant.numeric.vala","10"], + ["punctuation.terminator.vala",";"] +],[ + "text0", + ["text"," window"], + ["keyword.operator.dereference.vala","."], + ["text","window_position "], + ["keyword.operator.assignment.vala","="], + ["text"," "], + ["storage.type.vala","WindowPosition"], + ["keyword.operator.dereference.vala","."], + ["constant.other.vala","CENTER"], + ["punctuation.terminator.vala",";"] +],[ + "text0", + ["text"," window"], + ["keyword.operator.dereference.vala","."], + ["text","set_default_size("], + ["constant.numeric.vala","350"], + ["text",", "], + ["constant.numeric.vala","70"], + ["text",")"], + ["punctuation.terminator.vala",";"] +],[ + "text0", + ["text"," window"], + ["keyword.operator.dereference.vala","."], + ["text","destroy"], + ["keyword.operator.dereference.vala","."], + ["text","connect("], + ["storage.type.vala","Gtk"], + ["keyword.operator.dereference.vala","."], + ["text","main_quit)"], + ["punctuation.terminator.vala",";"] +],[ + "text0", + ["text"," "] +],[ + "text0", + ["text"," "], + ["storage.type.primitive.vala","var"], + ["text"," label "], + ["keyword.operator.assignment.vala","="], + ["text"," "], + ["keyword.control.new.vala","new"], + ["text"," "], + ["storage.type.vala","Label"], + ["text","("], + ["punctuation.definition.string.begin.vala","\""], + ["string.quoted.double.vala","Hello, World!"], + ["punctuation.definition.string.end.vala","\""], + ["text",")"], + ["punctuation.terminator.vala",";"] +],[ + "text0", + ["text"," "] +],[ + "text0", + ["text"," window"], + ["keyword.operator.dereference.vala","."], + ["text","add(label)"], + ["punctuation.terminator.vala",";"] +],[ + "text0", + ["text"," window"], + ["keyword.operator.dereference.vala","."], + ["text","show_all()"], + ["punctuation.terminator.vala",";"] +],[ + "text0", + ["text"," "] +],[ + "text0", + ["text"," "], + ["storage.type.vala","Gtk"], + ["keyword.operator.dereference.vala","."], + ["text","main()"], + ["punctuation.terminator.vala",";"] +],[ + "text0", + ["text"," "], + ["keyword.control.vala","return"], + ["text"," "], + ["constant.numeric.vala","0"], + ["punctuation.terminator.vala",";"] +],[ + "start", + ["text","}"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_vbscript.json b/node_modules/ace/lib/ace/mode/_test/tokens_vbscript.json new file mode 100644 index 00000000..a49f976d --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_vbscript.json @@ -0,0 +1,205 @@ +[[ + "start", + ["text","myfilename "], + ["keyword.operator.asp","="], + ["text"," "], + ["punctuation.definition.string.begin.asp","\""], + ["string.quoted.double.asp","C:\\Wikipedia - VBScript - Example - Hello World.txt\""] +],[ + "start", + ["text","MakeHelloWorldFile myfilename"] +],[ + "state_4", + ["meta.leading-space"," "] +],[ + "start", + ["storage.type.function.asp","Sub"], + ["text"," "], + ["entity.name.function.asp","MakeHelloWorldFile"], + ["text"," "], + ["punctuation.definition.parameters.asp","("], + ["variable.parameter.function.asp","FileName"], + ["punctuation.definition.parameters.asp",")"] +],[ + "start", + ["punctuation.definition.comment.asp","'"], + ["comment.line.apostrophe.asp","Create a new file in C: drive or overwrite existing file"] +],[ + "start", + ["meta.odd-tab.spaces"," "], + ["meta.leading-space"," "], + ["storage.type.asp","Set"], + ["text"," FSO "], + ["keyword.operator.asp","="], + ["text"," "], + ["support.function.asp","CreateObject"], + ["text","("], + ["punctuation.definition.string.begin.asp","\""], + ["string.quoted.double.asp","Scripting.FileSystemObject\""], + ["text",")"] +],[ + "start", + ["meta.odd-tab.spaces"," "], + ["meta.leading-space"," "], + ["keyword.control.asp","If"], + ["text"," FSO."], + ["entity.name.function.asp","FileExists"], + ["text","(FileName) "], + ["keyword.control.asp","Then"], + ["text"," "] +],[ + "start", + ["meta.odd-tab.spaces"," "], + ["meta.even-tab.spaces"," "], + ["meta.odd-tab.spaces"," "], + ["text","Answer "], + ["keyword.operator.asp","="], + ["text"," "], + ["support.function.vb.asp","MsgBox"], + ["text"," ("], + ["punctuation.definition.string.begin.asp","\""], + ["string.quoted.double.asp","File \""], + ["text"," "], + ["keyword.operator.asp","&"], + ["text"," FileName "], + ["keyword.operator.asp","&"], + ["text"," "], + ["punctuation.definition.string.begin.asp","\""], + ["string.quoted.double.asp"," exists ... OK to overwrite?\""], + ["text",", vbOKCancel)"] +],[ + "start", + ["meta.odd-tab.spaces"," "], + ["meta.even-tab.spaces"," "], + ["meta.odd-tab.spaces"," "], + ["punctuation.definition.comment.asp","'"], + ["comment.line.apostrophe.asp","If button selected is not OK, then quit now"] +],[ + "start", + ["meta.odd-tab.spaces"," "], + ["meta.even-tab.spaces"," "], + ["meta.odd-tab.spaces"," "], + ["punctuation.definition.comment.asp","'"], + ["comment.line.apostrophe.asp","vbOK is a language constant"] +],[ + "start", + ["meta.odd-tab.spaces"," "], + ["meta.even-tab.spaces"," "], + ["meta.odd-tab.spaces"," "], + ["keyword.control.asp","If"], + ["text"," Answer "], + ["keyword.operator.asp","<>"], + ["text"," vbOK "], + ["keyword.control.asp","Then"], + ["text"," "], + ["keyword.control.asp","Exit Sub"] +],[ + "start", + ["meta.odd-tab.spaces"," "], + ["meta.leading-space"," "], + ["keyword.control.asp","Else"] +],[ + "start", + ["meta.odd-tab.spaces"," "], + ["meta.even-tab.spaces"," "], + ["meta.odd-tab.spaces"," "], + ["punctuation.definition.comment.asp","'"], + ["comment.line.apostrophe.asp","Confirm OK to create"] +],[ + "start", + ["meta.odd-tab.spaces"," "], + ["meta.even-tab.spaces"," "], + ["meta.odd-tab.spaces"," "], + ["text","Answer "], + ["keyword.operator.asp","="], + ["text"," "], + ["support.function.vb.asp","MsgBox"], + ["text"," ("], + ["punctuation.definition.string.begin.asp","\""], + ["string.quoted.double.asp","File \""], + ["text"," "], + ["keyword.operator.asp","&"], + ["text"," FileName "], + ["keyword.operator.asp","&"], + ["text"," "], + ["punctuation.definition.string.begin.asp","\""], + ["string.quoted.double.asp"," ... OK to create?\""], + ["text",", vbOKCancel)"] +],[ + "start", + ["meta.odd-tab.spaces"," "], + ["meta.even-tab.spaces"," "], + ["meta.odd-tab.spaces"," "], + ["keyword.control.asp","If"], + ["text"," Answer "], + ["keyword.operator.asp","<>"], + ["text"," vbOK "], + ["keyword.control.asp","Then"], + ["text"," "], + ["keyword.control.asp","Exit Sub"] +],[ + "start", + ["meta.odd-tab.spaces"," "], + ["meta.leading-space"," "], + ["keyword.control.asp","End If"] +],[ + "start", + ["meta.odd-tab.spaces"," "], + ["meta.leading-space"," "], + ["punctuation.definition.comment.asp","'"], + ["comment.line.apostrophe.asp","Create new file (or replace an existing file)"] +],[ + "start", + ["meta.odd-tab.spaces"," "], + ["meta.leading-space"," "], + ["storage.type.asp","Set"], + ["text"," FileObject "], + ["keyword.operator.asp","="], + ["text"," FSO.CreateTextFile (FileName)"] +],[ + "start", + ["meta.odd-tab.spaces"," "], + ["meta.leading-space"," "], + ["text","FileObject.WriteLine "], + ["punctuation.definition.string.begin.asp","\""], + ["string.quoted.double.asp","Time ... \""], + ["text"," "], + ["keyword.operator.asp","&"], + ["text"," "], + ["support.function.vb.asp","Now"], + ["text","()"] +],[ + "start", + ["meta.odd-tab.spaces"," "], + ["meta.leading-space"," "], + ["text","FileObject.WriteLine "], + ["punctuation.definition.string.begin.asp","\""], + ["string.quoted.double.asp","Hello World\""] +],[ + "start", + ["meta.odd-tab.spaces"," "], + ["meta.leading-space"," "], + ["text","FileObject."], + ["entity.name.function.asp","Close"], + ["text","()"] +],[ + "start", + ["meta.odd-tab.spaces"," "], + ["meta.leading-space"," "], + ["support.function.vb.asp","MsgBox"], + ["text"," "], + ["punctuation.definition.string.begin.asp","\""], + ["string.quoted.double.asp","File \""], + ["text"," "], + ["keyword.operator.asp","&"], + ["text"," FileName "], + ["keyword.operator.asp","&"], + ["text"," "], + ["punctuation.definition.string.begin.asp","\""], + ["string.quoted.double.asp"," ... updated.\""] +],[ + "start", + ["support.function.asp","End"], + ["text"," "], + ["storage.type.asp","Sub"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_velocity.json b/node_modules/ace/lib/ace/mode/_test/tokens_velocity.json new file mode 100644 index 00000000..ee40761c --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_velocity.json @@ -0,0 +1,285 @@ +[[ + "vm_comment", + ["comment.block","#*"] +],[ + "vm_comment", + ["comment"," This is a sample comment block that"] +],[ + "vm_comment", + ["comment"," spans multiple lines."] +],[ + "start", + ["comment","*#"] +],[ + "start" +],[ + "start", + ["keyword","#macro"], + ["text"," "], + ["lparen","("], + ["text"," "], + ["identifier","outputItem"], + ["text"," "], + ["variable","$item"], + ["text"," "], + ["rparen",")"] +],[ + "start", + ["text"," "], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","li"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["variable","${"], + ["identifier","item"], + ["variable","}"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["keyword","#end"] +],[ + "start" +],[ + "start", + ["comment","## Define the items to iterate"] +],[ + "start", + ["keyword","#set"], + ["text"," "], + ["lparen","("], + ["text"," "], + ["variable","$items"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["lparen","["], + ["constant.numeric","1"], + ["text.xml",","], + ["text"," "], + ["constant.numeric","2"], + ["text.xml",","], + ["text"," "], + ["constant.numeric","3"], + ["text.xml",","], + ["text"," "], + ["constant.numeric","4"], + ["rparen","]"], + ["text"," "], + ["rparen",")"] +],[ + "start" +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","ul"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text"," "], + ["comment","## Iterate over the items and output the evens."] +],[ + "start", + ["text"," "], + ["keyword","#foreach"], + ["text"," "], + ["lparen","("], + ["text"," "], + ["variable","$item"], + ["text"," "], + ["identifier","in"], + ["text"," "], + ["variable","$items"], + ["text"," "], + ["rparen",")"] +],[ + "start", + ["text"," "], + ["keyword","#if"], + ["text"," "], + ["lparen","("], + ["text"," "], + ["support.function","$_MathTool"], + ["text.xml","."], + ["identifier","mod"], + ["lparen","("], + ["variable","$item"], + ["text.xml",","], + ["text"," "], + ["constant.numeric","2"], + ["rparen",")"], + ["text"," "], + ["keyword.operator","=="], + ["text"," "], + ["constant.numeric","0"], + ["text"," "], + ["rparen",")"] +],[ + "start", + ["text"," "], + ["identifier","#outputItem"], + ["text"," "], + ["lparen","("], + ["variable","$item"], + ["rparen",")"] +],[ + "start", + ["text"," "], + ["keyword","#end"] +],[ + "start", + ["text"," "], + ["keyword","#end"] +],[ + "start", + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start" +],[ + "js-start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.script.tag-name.xml","script"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "js-comment_regex_allowed", + ["text"," "], + ["comment","/*"] +],[ + "js-comment_regex_allowed", + ["comment"," A sample function to decomstrate"] +],[ + "js-comment_regex_allowed", + ["comment"," JavaScript highlighting and folding."] +],[ + "js-start", + ["comment"," */"] +],[ + "js-start", + ["text"," "], + ["storage.type","function"], + ["text"," "], + ["entity.name.function","foo"], + ["paren.lparen","("], + ["variable.parameter","items"], + ["punctuation.operator",", "], + ["variable.parameter","nada"], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "js-start", + ["text"," "], + ["keyword","for"], + ["text"," "], + ["paren.lparen","("], + ["storage.type","var"], + ["text"," "], + ["identifier","i"], + ["keyword.operator","="], + ["constant.numeric","0"], + ["punctuation.operator",";"], + ["text"," "], + ["identifier","i"], + ["keyword.operator","<"], + ["identifier","items"], + ["punctuation.operator","."], + ["support.constant","length"], + ["punctuation.operator",";"], + ["text"," "], + ["identifier","i"], + ["keyword.operator","++"], + ["paren.rparen",")"], + ["text"," "], + ["paren.lparen","{"] +],[ + "js-start", + ["text"," "], + ["support.function","alert"], + ["paren.lparen","("], + ["identifier","items"], + ["paren.lparen","["], + ["identifier","i"], + ["paren.rparen","]"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["string","\"juhu"], + ["constant.language.escape","\\n"], + ["string","\""], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + "js-no_regex", + ["text"," "], + ["paren.rparen","}"] +],[ + "js-no_regex", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start" +],[ + "css-start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.style.tag-name.xml","style"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + ["css-comment","css-start"], + ["text"," "], + ["comment","/*"] +],[ + ["css-comment","css-start"], + ["comment"," A sample style to decomstrate"] +],[ + ["css-comment","css-start"], + ["comment"," CSS highlighting and folding."] +],[ + "css-start", + ["comment"," */"] +],[ + ["css-ruleset","css-start"], + ["text"," "], + ["variable",".class"], + ["text"," "], + ["paren.lparen","{"] +],[ + ["css-ruleset","css-start"], + ["text"," "], + ["support.type","font-family"], + ["text",": Monaco, "], + ["string","\"Courier New\""], + ["text",", "], + ["support.constant.fonts","monospace"], + ["text",";"] +],[ + ["css-ruleset","css-start"], + ["text"," "], + ["support.type","font-size"], + ["text",": "], + ["constant.numeric","12"], + ["keyword","px"], + ["text",";"] +],[ + ["css-ruleset","css-start"], + ["text"," "], + ["support.type","cursor"], + ["text",": "], + ["support.constant","text"], + ["text",";"] +],[ + "css-start", + ["text"," "], + ["paren.rparen","}"] +],[ + "start", + ["meta.tag.punctuation.end-tag-open.xml",""] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_verilog.json b/node_modules/ace/lib/ace/mode/_test/tokens_verilog.json new file mode 100644 index 00000000..9680a964 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_verilog.json @@ -0,0 +1,113 @@ +[[ + "start", + ["keyword","always"], + ["text"," @"], + ["paren.lparen","("], + ["keyword","negedge"], + ["text"," "], + ["identifier","reset"], + ["text"," "], + ["keyword","or"], + ["text"," "], + ["keyword","posedge"], + ["text"," "], + ["identifier","clk"], + ["paren.rparen",")"], + ["text"," "], + ["keyword","begin"] +],[ + "start", + ["text"," "], + ["keyword","if"], + ["text"," "], + ["paren.lparen","("], + ["identifier","reset"], + ["text"," "], + ["keyword.operator","=="], + ["text"," "], + ["constant.numeric","0"], + ["paren.rparen",")"], + ["text"," "], + ["keyword","begin"] +],[ + "start", + ["text"," "], + ["identifier","d_out"], + ["text"," "], + ["keyword.operator","<="], + ["text"," "], + ["constant.numeric","16"], + ["text","'"], + ["identifier","h0000"], + ["text",";"] +],[ + "start", + ["text"," "], + ["identifier","d_out_mem"], + ["text","["], + ["identifier","resetcount"], + ["text","] "], + ["keyword.operator","<="], + ["text"," "], + ["identifier","d_out"], + ["text",";"] +],[ + "start", + ["text"," "], + ["identifier","laststoredvalue"], + ["text"," "], + ["keyword.operator","<="], + ["text"," "], + ["identifier","d_out"], + ["text",";"] +],[ + "start", + ["text"," "], + ["keyword","end"], + ["text"," "], + ["keyword","else"], + ["text"," "], + ["keyword","begin"] +],[ + "start", + ["text"," "], + ["identifier","d_out"], + ["text"," "], + ["keyword.operator","<="], + ["text"," "], + ["identifier","d_out"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["constant.numeric","1"], + ["text","'"], + ["identifier","b1"], + ["text","; "] +],[ + "start", + ["text"," "], + ["keyword","end"] +],[ + "start", + ["keyword","end"] +],[ + "start" +],[ + "start", + ["keyword","always"], + ["text"," @"], + ["paren.lparen","("], + ["identifier","bufreadaddr"], + ["paren.rparen",")"] +],[ + "start", + ["text"," "], + ["identifier","bufreadval"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["identifier","d_out_mem"], + ["text","["], + ["identifier","bufreadaddr"], + ["text","];"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_vhdl.json b/node_modules/ace/lib/ace/mode/_test/tokens_vhdl.json new file mode 100644 index 00000000..88c6e222 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_vhdl.json @@ -0,0 +1,271 @@ +[[ + "start", + ["keyword","library"], + ["text"," "], + ["identifier","IEEE"] +],[ + "start", + ["identifier","user"], + ["text"," "], + ["identifier","IEEE"], + ["punctuation.operator","."], + ["identifier","std_logic_1164"], + ["punctuation.operator","."], + ["keyword","all"], + ["punctuation.operator",";"] +],[ + "start", + ["keyword","use"], + ["text"," "], + ["identifier","IEEE"], + ["punctuation.operator","."], + ["identifier","numeric_std"], + ["punctuation.operator","."], + ["keyword","all"], + ["punctuation.operator",";"] +],[ + "start" +],[ + "start", + ["keyword","entity"], + ["text"," "], + ["identifier","COUNT16"], + ["text"," "], + ["keyword","is"] +],[ + "start" +],[ + "start", + ["text"," "], + ["keyword","port"], + ["text"," "], + ["paren.lparen","("] +],[ + "start", + ["text"," "], + ["identifier","cOut"], + ["text"," "], + ["punctuation.operator",":"], + ["keyword","out"], + ["text"," "], + ["storage.type","std_logic_vector"], + ["paren.lparen","("], + ["constant.numeric","15"], + ["text"," "], + ["keyword","downto"], + ["text"," "], + ["constant.numeric","0"], + ["paren.rparen",")"], + ["punctuation.operator",";"], + ["text"," "], + ["comment","-- counter output"] +],[ + "start", + ["text"," "], + ["identifier","clkEn"], + ["text"," "], + ["punctuation.operator",":"], + ["keyword","in"], + ["text"," "], + ["storage.type","std_logic"], + ["punctuation.operator",";"], + ["text"," "], + ["comment","-- count enable"] +],[ + "start", + ["text"," "], + ["identifier","clk"], + ["text"," "], + ["punctuation.operator",":"], + ["keyword","in"], + ["text"," "], + ["storage.type","std_logic"], + ["punctuation.operator",";"], + ["text"," "], + ["comment","-- clock input"] +],[ + "start", + ["text"," "], + ["identifier","rst"], + ["text"," "], + ["punctuation.operator",":"], + ["keyword","in"], + ["text"," "], + ["storage.type","std_logic"], + ["text"," "], + ["comment","-- reset input"] +],[ + "start", + ["text"," "], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "] +],[ + "start", + ["keyword","end"], + ["text"," "], + ["keyword","entity"], + ["punctuation.operator",";"] +],[ + "start" +],[ + "start", + ["keyword","architecture"], + ["text"," "], + ["identifier","count_rtl"], + ["text"," "], + ["keyword","of"], + ["text"," "], + ["identifier","COUNT16"], + ["text"," "], + ["keyword","is"] +],[ + "start", + ["text"," "], + ["storage.type","signal"], + ["text"," "], + ["identifier","count"], + ["text"," "], + ["punctuation.operator",":"], + ["storage.type","std_logic_vector"], + ["text"," "], + ["paren.lparen","("], + ["constant.numeric","15"], + ["text"," "], + ["keyword","downto"], + ["text"," "], + ["constant.numeric","0"], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "] +],[ + "start", + ["keyword","begin"] +],[ + "start", + ["text"," "], + ["keyword","process"], + ["text"," "], + ["paren.lparen","("], + ["identifier","clk"], + ["punctuation.operator",","], + ["text"," "], + ["identifier","rst"], + ["paren.rparen",")"], + ["text"," "], + ["keyword","begin"] +],[ + "start", + ["text"," "] +],[ + "start", + ["text"," "], + ["keyword","if"], + ["paren.lparen","("], + ["identifier","rst"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["string","'1'"], + ["paren.rparen",")"], + ["text"," "], + ["keyword","then"] +],[ + "start", + ["text"," "], + ["identifier","count"], + ["text"," "], + ["keyword.operator","<="], + ["text"," "], + ["paren.lparen","("], + ["keyword","others"], + ["keyword.operator","=>"], + ["string","'0'"], + ["paren.rparen",")"], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "], + ["keyword","elsif"], + ["paren.lparen","("], + ["identifier","rising_edge"], + ["paren.lparen","("], + ["identifier","clk"], + ["paren.rparen","))"], + ["text"," "], + ["keyword","then"] +],[ + "start", + ["text"," "], + ["keyword","if"], + ["paren.lparen","("], + ["identifier","clkEn"], + ["text"," "], + ["keyword.operator","="], + ["text"," "], + ["string","'1'"], + ["paren.rparen",")"], + ["text"," "], + ["keyword","then"] +],[ + "start", + ["text"," "], + ["identifier","count"], + ["text"," "], + ["keyword.operator","<="], + ["text"," "], + ["identifier","count"], + ["text"," "], + ["keyword.operator","+"], + ["text"," "], + ["constant.numeric","1"], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "], + ["keyword","end"], + ["text"," "], + ["keyword","if"], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "], + ["keyword","end"], + ["text"," "], + ["keyword","if"], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "] +],[ + "start", + ["text"," "], + ["keyword","end"], + ["text"," "], + ["keyword","process"], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "], + ["identifier","cOut"], + ["text"," "], + ["keyword.operator","<="], + ["text"," "], + ["identifier","count"], + ["punctuation.operator",";"] +],[ + "start" +],[ + "start", + ["keyword","end"], + ["text"," "], + ["keyword","architecture"], + ["punctuation.operator",";"] +],[ + "start", + ["text"," "] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_xml.json b/node_modules/ace/lib/ace/mode/_test/tokens_xml.json new file mode 100644 index 00000000..728be4db --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_xml.json @@ -0,0 +1,43 @@ +[[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","Juhu"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["text.xml","//Juhu Kinners"], + ["meta.tag.punctuation.end-tag-open.xml",""] +],[ + "start", + ["text.xml","test: two tags in the same lines should be in separate tokens\""] +],[ + "start", + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","Juhu"], + ["meta.tag.punctuation.tag-close.xml",">"], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","Kinners"], + ["meta.tag.punctuation.tag-close.xml",">"] +],[ + "start", + ["text.xml","test: multiline attributes\""] +],[ + ["string.attribute-value.xml0","meta.tag.punctuation.tag-open.xml"], + ["meta.tag.punctuation.tag-open.xml","<"], + ["meta.tag.tag-name.xml","copy"], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","set"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"{"] +],[ + ["string.attribute-value.xml0","meta.tag.punctuation.tag-open.xml"], + ["string.attribute-value.xml","}\""], + ["text.tag-whitespace.xml"," "], + ["entity.other.attribute-name.xml","undo"], + ["keyword.operator.attribute-equals.xml","="], + ["string.attribute-value.xml","\"{"] +],[ + "start", + ["string.attribute-value.xml","}\""], + ["meta.tag.punctuation.tag-close.xml","/>"] +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_xquery.json b/node_modules/ace/lib/ace/mode/_test/tokens_xquery.json new file mode 100644 index 00000000..aaf9ab9b --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_xquery.json @@ -0,0 +1,44 @@ +[[ + "[\"start\"]", + ["keyword","xquery"], + ["text"," "], + ["keyword","version"], + ["text"," "], + ["string","\""], + ["string","1.0"], + ["string","\""], + ["text",";"] +],[ + "[\"start\"]" +],[ + "[\"start\"]", + ["keyword","let"], + ["text"," "], + ["variable","$message"], + ["text"," "], + ["keyword.operator",":="], + ["text"," "], + ["string","\""], + ["string","Hello World!"], + ["string","\""] +],[ + "[\"start\",\"StartTag\",\"TagContent\"]", + ["keyword","return"], + ["text"," "], + ["meta.tag",""] +],[ + "[\"start\",\"StartTag\",\"TagContent\"]", + ["text"," "], + ["meta.tag",""], + ["text","{"], + ["variable","$message"], + ["text","}"], + ["meta.tag",""] +],[ + "[\"start\"]", + ["meta.tag",""] +],[ + "[\"start\"]" +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/_test/tokens_yaml.json b/node_modules/ace/lib/ace/mode/_test/tokens_yaml.json new file mode 100644 index 00000000..7c9b45f3 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/_test/tokens_yaml.json @@ -0,0 +1,150 @@ +[[ + "start", + ["comment","# This sample document was taken from wikipedia:"] +],[ + "start", + ["comment","# http://en.wikipedia.org/wiki/YAML#Sample_document"] +],[ + "start", + ["list.markup","---"] +],[ + "start", + ["meta.tag","receipt"], + ["keyword",": "], + ["text","Oz-Ware Purchase Invoice"] +],[ + "start", + ["meta.tag","date"], + ["keyword",": "], + ["constant.numeric","2007-08-06"] +],[ + "start", + ["meta.tag","customer"], + ["keyword",":"] +],[ + "start", + ["meta.tag"," given"], + ["keyword",": "], + ["text","Dorothy"] +],[ + "start", + ["meta.tag"," family"], + ["keyword",": "], + ["text","Gale"] +],[ + "start" +],[ + "start", + ["meta.tag","items"], + ["keyword",":"] +],[ + "start", + ["list.markup"," - "], + ["meta.tag","part_no"], + ["keyword",": "], + ["string","'A4786'"] +],[ + "start", + ["meta.tag"," descrip"], + ["keyword",": "], + ["text","Water Bucket "], + ["paren.lparen","("], + ["text","Filled"], + ["paren.rparen",")"] +],[ + "start", + ["meta.tag"," price"], + ["keyword",": "], + ["constant.numeric","1.47"] +],[ + "start", + ["meta.tag"," quantity"], + ["keyword",": "], + ["constant.numeric","4"] +],[ + "start" +],[ + "start", + ["list.markup"," - "], + ["meta.tag","part_no"], + ["keyword",": "], + ["string","'E1628'"] +],[ + "start", + ["meta.tag"," descrip"], + ["keyword",": "], + ["text","High Heeled "], + ["string","\"Ruby\""], + ["text"," Slippers"] +],[ + "start", + ["meta.tag"," size"], + ["keyword",": "], + ["constant.numeric","8"] +],[ + "start", + ["meta.tag"," price"], + ["keyword",": "], + ["constant.numeric","100.27"] +],[ + "start", + ["meta.tag"," quantity"], + ["keyword",": "], + ["constant.numeric","1"] +],[ + "start" +],[ + "start", + ["meta.tag","bill-to"], + ["keyword",": "], + ["constant.language","&id001"] +],[ + "qqstring", + ["meta.tag"," street"], + ["keyword",": "], + ["string","|"] +],[ + "qqstring", + ["string"," 123 Tornado Alley"] +],[ + "qqstring", + ["string"," Suite 16"] +],[ + "start", + ["meta.tag"," city"], + ["keyword",": "], + ["text","East Centerville"] +],[ + "start", + ["meta.tag"," state"], + ["keyword",": "], + ["text","KS"] +],[ + "start" +],[ + "start", + ["meta.tag","ship-to"], + ["keyword",": "], + ["constant.language","*id001"] +],[ + "start" +],[ + "qqstring", + ["meta.tag","specialDelivery"], + ["keyword",": "], + ["string",">"] +],[ + "qqstring", + ["string"," Follow the Yellow Brick"] +],[ + "qqstring", + ["string"," Road to the Emerald City."] +],[ + "qqstring", + ["string"," Pay no attention to the"] +],[ + "qqstring", + ["string"," man behind the curtain."] +],[ + "qqstring" +]] \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/abap.js b/node_modules/ace/lib/ace/mode/abap.js new file mode 100644 index 00000000..c9d5a991 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/abap.js @@ -0,0 +1,77 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var Rules = require("./abap_highlight_rules").AbapHighlightRules; +var FoldMode = require("./folding/coffee").FoldMode; +var Range = require("../range").Range; +var TextMode = require("./text").Mode; +var oop = require("../lib/oop"); + +function Mode() { + this.HighlightRules = Rules; + this.foldingRules = new FoldMode(); +} + +oop.inherits(Mode, TextMode); + +(function() { + + this.getNextLineIndent = function(state, line, tab) { + var indent = this.$getIndent(line); + return indent; + }; + + this.toggleCommentLines = function(state, doc, startRow, endRow){ + var range = new Range(0, 0, 0, 0); + for (var i = startRow; i <= endRow; ++i) { + var line = doc.getLine(i); + if (hereComment.test(line)) + continue; + + if (commentLine.test(line)) + line = line.replace(commentLine, '$1'); + else + line = line.replace(indentation, '$&#'); + + range.end.row = range.start.row = i; + range.end.column = line.length + 1; + doc.replace(range, line); + } + }; + + this.$id = "ace/mode/abap"; +}).call(Mode.prototype); + +exports.Mode = Mode; + +}); diff --git a/node_modules/ace/lib/ace/mode/abap_highlight_rules.js b/node_modules/ace/lib/ace/mode/abap_highlight_rules.js new file mode 100644 index 00000000..bab1e504 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/abap_highlight_rules.js @@ -0,0 +1,134 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * based on + * " Vim ABAP syntax file + * " Language: SAP - ABAP/R4 + * " Revision: 2.1 + * " Maintainer: Marius Piedallu van Wyk + * " Last Change: 2012 Oct 23 + */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + +var AbapHighlightRules = function() { + + var keywordMapper = this.createKeywordMapper({ + "variable.language": "this", + "keyword": + "ADD ALIAS ALIASES ASSERT ASSIGN ASSIGNING AT BACK" + + " CALL CASE CATCH CHECK CLASS CLEAR CLOSE CNT COLLECT COMMIT COMMUNICATION COMPUTE CONCATENATE CONDENSE CONSTANTS CONTINUE CONTROLS CONVERT CREATE CURRENCY" + + " DATA DEFINE DEFINITION DEFERRED DELETE DESCRIBE DETAIL DIVIDE DO" + + " ELSE ELSEIF ENDAT ENDCASE ENDCLASS ENDDO ENDEXEC ENDFORM ENDFUNCTION ENDIF ENDIFEND ENDINTERFACE ENDLOOP ENDMETHOD ENDMODULE ENDON ENDPROVIDE ENDSELECT ENDTRY ENDWHILE EVENT EVENTS EXEC EXIT EXPORT EXPORTING EXTRACT" + + " FETCH FIELDS FORM FORMAT FREE FROM FUNCTION" + + " GENERATE GET" + + " HIDE" + + " IF IMPORT IMPORTING INDEX INFOTYPES INITIALIZATION INTERFACE INTERFACES INPUT INSERT IMPLEMENTATION" + + " LEAVE LIKE LINE LOAD LOCAL LOOP" + + " MESSAGE METHOD METHODS MODIFY MODULE MOVE MULTIPLY" + + " ON OVERLAY OPTIONAL OTHERS" + + " PACK PARAMETERS PERFORM POSITION PROGRAM PROVIDE PUT" + + " RAISE RANGES READ RECEIVE RECEIVING REDEFINITION REFERENCE REFRESH REJECT REPLACE REPORT RESERVE RESTORE RETURNING ROLLBACK" + + " SCAN SCROLL SEARCH SELECT SET SHIFT SKIP SORT SORTED SPLIT STANDARD STATICS STEP STOP SUBMIT SUBTRACT SUM SUMMARY SUPPRESS" + + " TABLES TIMES TRANSFER TRANSLATE TRY TYPE TYPES" + + " UNASSIGN ULINE UNPACK UPDATE" + + " WHEN WHILE WINDOW WRITE" + + " OCCURS STRUCTURE OBJECT PROPERTY" + + " CASTING APPEND RAISING VALUE COLOR" + + " CHANGING EXCEPTION EXCEPTIONS DEFAULT CHECKBOX COMMENT" + + " ID NUMBER FOR TITLE OUTPUT" + + " WITH EXIT USING" + + " INTO WHERE GROUP BY HAVING ORDER BY SINGLE" + + " APPENDING CORRESPONDING FIELDS OF TABLE" + + " LEFT RIGHT OUTER INNER JOIN AS CLIENT SPECIFIED BYPASSING BUFFER UP TO ROWS CONNECTING" + + " EQ NE LT LE GT GE NOT AND OR XOR IN LIKE BETWEEN", + "constant.language": + "TRUE FALSE NULL SPACE", + "support.type": + "c n i p f d t x string xstring decfloat16 decfloat34", + "keyword.operator": + "abs sign ceil floor trunc frac acos asin atan cos sin tan" + + " abapOperator cosh sinh tanh exp log log10 sqrt" + + " strlen xstrlen charlen numofchar dbmaxlen lines" + }, "text", true, " "); + + var compoundKeywords = "WITH\\W+(?:HEADER\\W+LINE|FRAME|KEY)|NO\\W+STANDARD\\W+PAGE\\W+HEADING|"+ + "EXIT\\W+FROM\\W+STEP\\W+LOOP|BEGIN\\W+OF\\W+(?:BLOCK|LINE)|BEGIN\\W+OF|"+ + "END\\W+OF\\W+(?:BLOCK|LINE)|END\\W+OF|NO\\W+INTERVALS|"+ + "RESPECTING\\W+BLANKS|SEPARATED\\W+BY|USING\\W+(?:EDIT\\W+MASK)|"+ + "WHERE\\W+(?:LINE)|RADIOBUTTON\\W+GROUP|REF\\W+TO|"+ + "(?:PUBLIC|PRIVATE|PROTECTED)(?:\\W+SECTION)?|DELETING\\W+(?:TRAILING|LEADING)"+ + "(?:ALL\\W+OCCURRENCES)|(?:FIRST|LAST)\\W+OCCURRENCE|INHERITING\\W+FROM|"+ + "LINE-COUNT|ADD-CORRESPONDING|AUTHORITY-CHECK|BREAK-POINT|CLASS-DATA|CLASS-METHODS|"+ + "CLASS-METHOD|DIVIDE-CORRESPONDING|EDITOR-CALL|END-OF-DEFINITION|END-OF-PAGE|END-OF-SELECTION|"+ + "FIELD-GROUPS|FIELD-SYMBOLS|FUNCTION-POOL|MOVE-CORRESPONDING|MULTIPLY-CORRESPONDING|NEW-LINE|"+ + "NEW-PAGE|NEW-SECTION|PRINT-CONTROL|RP-PROVIDE-FROM-LAST|SELECT-OPTIONS|SELECTION-SCREEN|"+ + "START-OF-SELECTION|SUBTRACT-CORRESPONDING|SYNTAX-CHECK|SYNTAX-TRACE|TOP-OF-PAGE|TYPE-POOL|"+ + "TYPE-POOLS|LINE-SIZE|LINE-COUNT|MESSAGE-ID|DISPLAY-MODE|READ(?:-ONLY)?|"+ + "IS\\W+(?:NOT\\W+)?(?:ASSIGNED|BOUND|INITIAL|SUPPLIED)"; + + this.$rules = { + "start" : [ + {token : "string", regex : "`", next : "string"}, + {token : "string", regex : "'", next : "qstring"}, + {token : "doc.comment", regex : /^\*.+/}, + {token : "comment", regex : /".+$/}, + {token : "invalid", regex: "\\.{2,}"}, + {token : "keyword.operator", regex: /\W[\-+\%=<>*]\W|\*\*|[~:,\.&$]|->*?|=>/}, + {token : "paren.lparen", regex : "[\\[({]"}, + {token : "paren.rparen", regex : "[\\])}]"}, + {token : "constant.numeric", regex: "[+-]?\\d+\\b"}, + {token : "variable.parameter", regex : /sy|pa?\d\d\d\d\|t\d\d\d\.|innnn/}, + {token : "keyword", regex : compoundKeywords}, + {token : "variable.parameter", regex : /\w+-\w+(?:-\w+)*/}, + {token : keywordMapper, regex : "\\b\\w+\\b"}, + {caseInsensitive: true} + ], + "qstring" : [ + {token : "constant.language.escape", regex : "''"}, + {token : "string", regex : "'", next : "start"}, + {defaultToken : "string"} + ], + "string" : [ + {token : "constant.language.escape", regex : "``"}, + {token : "string", regex : "`", next : "start"}, + {defaultToken : "string"} + ] + }; +}; +oop.inherits(AbapHighlightRules, TextHighlightRules); + +exports.AbapHighlightRules = AbapHighlightRules; +}); diff --git a/node_modules/ace/lib/ace/mode/abc.js b/node_modules/ace/lib/ace/mode/abc.js new file mode 100644 index 00000000..b6eb237a --- /dev/null +++ b/node_modules/ace/lib/ace/mode/abc.js @@ -0,0 +1,58 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +/* + THIS FILE WAS AUTOGENERATED BY mode.tmpl.js + */ + +define(function (require, exports, module) { + "use strict"; + + var oop = require("../lib/oop"); + var TextMode = require("./text").Mode; + var ABCHighlightRules = require("./abc_highlight_rules").ABCHighlightRules; +// TODO: pick appropriate fold mode + var FoldMode = require("./folding/cstyle").FoldMode; + + var Mode = function () { + this.HighlightRules = ABCHighlightRules; + this.foldingRules = new FoldMode(); + }; + oop.inherits(Mode, TextMode); + + (function () { + // this.lineCommentStart = ""%.*""; + // this.blockComment = {start: ""/*"", end: ""*/""}; + // Extra logic goes here. + this.$id = "ace/mode/abc" + }).call(Mode.prototype); + + exports.Mode = Mode; +}); \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/abc_highlight_rules.js b/node_modules/ace/lib/ace/mode/abc_highlight_rules.js new file mode 100644 index 00000000..6ffe9c9b --- /dev/null +++ b/node_modules/ace/lib/ace/mode/abc_highlight_rules.js @@ -0,0 +1,114 @@ +/* This file was partially autogenerated from https://github.com/jimhawkridge/SublimeABC + + Modifications + + - more classes to express the abc semantic + - added syntax highlighting for Zupfnoter conventions (https://github.com/bwl21/zupfnoter) + - separate note pitch and note duration - even if it looks the same + + ***********************************************************************************************/ + + +define(function (require, exports, module) { + "use strict"; + + var oop = require("../lib/oop"); + var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + + var ABCHighlightRules = function () { + // regexp must not have capturing parentheses. Use (?:) instead. + // regexps are ordered -> the first match is used + + this.$rules = { + start: [ + { + token: ['zupfnoter.information.comment.line.percentage', 'information.keyword', 'in formation.keyword.embedded'], + regex: '(%%%%)(hn\\.[a-z]*)(.*)', + comment: 'Instruction Comment' + }, + { + token: ['information.comment.line.percentage', 'information.keyword.embedded'], + regex: '(%%)(.*)', + comment: 'Instruction Comment' + }, + + { + token: 'comment.line.percentage', + regex: '%.*', + comment: 'Comments' + }, + + { + token: 'barline.keyword.operator', + regex: '[\\[:]*[|:][|\\]:]*(?:\\[?[0-9]+)?|\\[[0-9]+', + comment: 'Bar lines' + }, + { + token: ['information.keyword.embedded', 'information.argument.string.unquoted'], + regex: '(\\[[A-Za-z]:)([^\\]]*\\])', + comment: 'embedded Header lines' + }, + { + token: ['information.keyword', 'information.argument.string.unquoted'], + regex: '^([A-Za-z]:)([^%\\\\]*)', + comment: 'Header lines' + }, + { + token: ['text', 'entity.name.function', 'string.unquoted', 'text'], + regex: '(\\[)([A-Z]:)(.*?)(\\])', + comment: 'Inline fields' + }, + { + token: ['accent.constant.language', 'pitch.constant.numeric', 'duration.constant.numeric'], + regex: '([\\^=_]*)([A-Ga-gz][,\']*)([0-9]*/*[><0-9]*)', + comment: 'Notes' + }, + { + token: 'zupfnoter.jumptarget.string.quoted', + regex: '[\\"!]\\^\\:.*?[\\"!]', + comment: 'Zupfnoter jumptarget' + }, { + token: 'zupfnoter.goto.string.quoted', + regex: '[\\"!]\\^\\@.*?[\\"!]', + comment: 'Zupfnoter goto' + }, + { + token: 'zupfnoter.annotation.string.quoted', + regex: '[\\"!]\\^\\!.*?[\\"!]', + comment: 'Zupfnoter annoation' + }, + { + token: 'zupfnoter.annotationref.string.quoted', + regex: '[\\"!]\\^\\#.*?[\\"!]', + comment: 'Zupfnoter annotation reference' + }, + { + token: 'chordname.string.quoted', + regex: '[\\"!]\\^.*?[\\"!]', + comment: 'abc chord' + }, + { + token: 'string.quoted', + regex: '[\\"!].*?[\\"!]', + comment: 'abc annotation' + } + + ] + }; + + // this.embedRules(JsonHighlightRules, "json-") + + this.normalizeRules(); + }; + + ABCHighlightRules.metaData = { + fileTypes: ['abc'], + name: 'ABC', + scopeName: 'text.abcnotation' + }; + + + oop.inherits(ABCHighlightRules, TextHighlightRules); + + exports.ABCHighlightRules = ABCHighlightRules; +}); diff --git a/node_modules/ace/lib/ace/mode/actionscript.js b/node_modules/ace/lib/ace/mode/actionscript.js new file mode 100644 index 00000000..7daf2941 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/actionscript.js @@ -0,0 +1,58 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * + * ***** END LICENSE BLOCK ***** */ + +/* + THIS FILE WAS AUTOGENERATED BY mode.tmpl.js +*/ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextMode = require("./text").Mode; +var ActionScriptHighlightRules = require("./actionscript_highlight_rules").ActionScriptHighlightRules; +// TODO: pick appropriate fold mode +var FoldMode = require("./folding/cstyle").FoldMode; + +var Mode = function() { + this.HighlightRules = ActionScriptHighlightRules; + this.foldingRules = new FoldMode(); +}; +oop.inherits(Mode, TextMode); + +(function() { + this.lineCommentStart = "//"; + this.blockComment = {start: "/*", end: "*/"}; + this.$id = "ace/mode/actionscript"; +}).call(Mode.prototype); + +exports.Mode = Mode; +}); \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/actionscript_highlight_rules.js b/node_modules/ace/lib/ace/mode/actionscript_highlight_rules.js new file mode 100644 index 00000000..1f30d9c2 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/actionscript_highlight_rules.js @@ -0,0 +1,141 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +/* This file was autogenerated from tm bundles\actionscript.tmbundle\Syntaxes\ActionScript.plist (uuid: ) */ +/**************************************************************************************** + * IT MIGHT NOT BE PERFECT ...But it's a good start from an existing *.tmlanguage file. * + * fileTypes * + ****************************************************************************************/ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + +var ActionScriptHighlightRules = function() { + // regexp must not have capturing parentheses. Use (?:) instead. + // regexps are ordered -> the first match is used + + this.$rules = { start: + [ { token: 'support.class.actionscript.2', + regex: '\\b(?:R(?:ecordset|DBMSResolver|adioButton(?:Group)?)|X(?:ML(?:Socket|Node|Connector)?|UpdateResolverDataHolder)|M(?:M(?:Save|Execute)|icrophoneMicrophone|o(?:use|vieClip(?:Loader)?)|e(?:nu(?:Bar)?|dia(?:Controller|Display|Playback))|ath)|B(?:yName|inding|utton)|S(?:haredObject|ystem|crollPane|t(?:yleSheet|age|ream)|ound|e(?:ndEvent|rviceObject)|OAPCall|lide)|N(?:umericStepper|et(?:stream|S(?:tream|ervices)|Connection|Debug(?:Config)?))|C(?:heckBox|o(?:ntextMenu(?:Item)?|okie|lor|m(?:ponentMixins|boBox))|ustomActions|lient|amera)|T(?:ypedValue|ext(?:Snapshot|Input|F(?:ield|ormat)|Area)|ree|AB)|Object|D(?:ownload|elta(?:Item|Packet)?|at(?:e(?:Chooser|Field)?|a(?:G(?:lue|rid)|Set|Type)))|U(?:RL|TC|IScrollBar)|P(?:opUpManager|endingCall|r(?:intJob|o(?:duct|gressBar)))|E(?:ndPoint|rror)|Video|Key|F(?:RadioButton|GridColumn|MessageBox|BarChart|S(?:croll(?:Bar|Pane)|tyleFormat|plitView)|orm|C(?:heckbox|omboBox|alendar)|unction|T(?:icker|ooltip(?:Lite)?|ree(?:Node)?)|IconButton|D(?:ataGrid|raggablePane)|P(?:ieChart|ushButton|ro(?:gressBar|mptBox))|L(?:i(?:stBox|neChart)|oadingBox)|AdvancedMessageBox)|W(?:indow|SDLURL|ebService(?:Connector)?)|L(?:ist|o(?:calConnection|ad(?:er|Vars)|g)|a(?:unch|bel))|A(?:sBroadcaster|cc(?:ordion|essibility)|S(?:Set(?:Native|PropFlags)|N(?:ew|ative)|C(?:onstructor|lamp(?:2)?)|InstanceOf)|pplication|lert|rray))\\b' }, + { token: 'support.function.actionscript.2', + regex: '\\b(?:s(?:h(?:ift|ow(?:GridLines|Menu|Border|Settings|Headers|ColumnHeaders|Today|Preferences)?|ad(?:ow|ePane))|c(?:hema|ale(?:X|Mode|Y|Content)|r(?:oll(?:Track|Drag)?|een(?:Resolution|Color|DPI)))|t(?:yleSheet|op(?:Drag|A(?:nimation|llSounds|gent))?|epSize|a(?:tus|rt(?:Drag|A(?:nimation|gent))?))|i(?:n|ze|lence(?:TimeOut|Level))|o(?:ngname|urce|rt(?:Items(?:By)?|On(?:HeaderRelease)?|able(?:Columns)?)?)|u(?:ppressInvalidCalls|bstr(?:ing)?)|p(?:li(?:ce|t)|aceCol(?:umnsEqually|lumnsEqually))|e(?:nd(?:DefaultPushButtonEvent|AndLoad)?|curity|t(?:R(?:GB|o(?:otNode|w(?:Height|Count))|esizable(?:Columns)?|a(?:nge|te))|G(?:ain|roupName)|X(?:AxisTitle)?|M(?:i(?:n(?:imum|utes)|lliseconds)|o(?:nth(?:Names)?|tionLevel|de)|ultilineMode|e(?:ssage|nu(?:ItemEnabled(?:At)?|EnabledAt)|dia)|a(?:sk|ximum))|B(?:u(?:tton(?:s|Width)|fferTime)|a(?:seTabIndex|ndwidthLimit|ckground))|S(?:howAsDisabled|croll(?:ing|Speed|Content|Target|P(?:osition|roperties)|barState|Location)|t(?:yle(?:Property)?|opOnFocus|at(?:us|e))|i(?:ze|lenceLevel)|ort(?:able(?:Columns)?|Function)|p(?:litterBarPosition|acing)|e(?:conds|lect(?:Multiple|ion(?:Required|Type)?|Style|Color|ed(?:Node(?:s)?|Cell|I(?:nd(?:ices|ex)|tem(?:s)?))?|able))|kin|m(?:oothness|allScroll))|H(?:ighlight(?:s|Color)|Scroll|o(?:urs|rizontal)|eader(?:Symbol|Height|Text|Property|Format|Width|Location)?|as(?:Shader|CloseBox))|Y(?:ear|AxisTitle)?|N(?:ode(?:Properties|ExpansionHandler)|ewTextFormat)|C(?:h(?:ildNodes|a(?:ngeHandler|rt(?:Title|EventHandler)))|o(?:ntent(?:Size)?|okie|lumns)|ell(?:Symbol|Data)|l(?:i(?:ckHandler|pboard)|oseHandler)|redentials)|T(?:ype(?:dVaule)?|i(?:tle(?:barHeight)?|p(?:Target|Offset)?|me(?:out(?:Handler)?)?)|oggle|extFormat|ransform)|I(?:s(?:Branch|Open)|n(?:terval|putProperty)|con(?:SymbolName)?|te(?:rator|m(?:ByKey|Symbol)))|Orientation|D(?:i(?:splay(?:Range|Graphics|Mode|Clip|Text|edMonth)|rection)|uration|e(?:pth(?:Below|To|Above)|fault(?:GatewayURL|Mappings|NodeIconSymbolName)|l(?:iveryMode|ay)|bug(?:ID)?)|a(?:yOfWeekNames|t(?:e(?:Filter)?|a(?:Mapping(?:s)?|Item(?:Text|Property|Format)|Provider|All(?:Height|Property|Format|Width))?))|ra(?:wConnectors|gContent))|U(?:se(?:Shadow|HandCursor|EchoSuppression|rInput|Fade)|TC(?:M(?:i(?:nutes|lliseconds)|onth)|Seconds|Hours|Date|FullYear))|P(?:osition|ercentComplete|an(?:e(?:M(?:inimumSize|aximumSize)|Size|Title))?|ro(?:pert(?:y(?:Data)?|iesAt)|gress))|E(?:nabled|dit(?:Handler|able)|xpand(?:NodeTrigger|erSymbolName))|V(?:Scroll|olume|alue(?:Source)?)|KeyFrameInterval|Quality|F(?:i(?:eld|rst(?:DayOfWeek|VisibleNode))|ocus|ullYear|ps|ade(?:InLength|OutLength)|rame(?:Color|Width))|Width|L(?:ine(?:Color|Weight)|o(?:opback|adTarget)|a(?:rgeScroll|bel(?:Source|Placement)?))|A(?:s(?:Boolean|String|Number)|n(?:yTypedValue|imation)|ctiv(?:e(?:State(?:Handler)?|Handler)|ateHandler)|utoH(?:ideScrollBar|eight)))?|paratorBefore|ek|lect(?:ion(?:Disabled|Unfocused)?|ed(?:Node(?:s)?|Child|I(?:nd(?:ices|ex)|tem(?:s)?)|Dat(?:e|a))?|able(?:Ranges)?)|rver(?:String)?)|kip|qrt|wapDepths|lice|aveToSharedObj|moothing)|h(?:scroll(?:Policy)?|tml(?:Text)?|i(?:t(?:Test(?:TextNearPos)?|Area)|de(?:BuiltInItems|Child)?|ghlight(?:2D|3D)?)|orizontal|e(?:ight|ader(?:Re(?:nderer|lease)|Height|Text))|P(?:osition|ageScrollSize)|a(?:s(?:childNodes|MP3|S(?:creen(?:Broadcast|Playback)|treaming(?:Video|Audio)|ort)|Next|OwnProperty|Pr(?:inting|evious)|EmbeddedVideo|VideoEncoder|A(?:ccesibility|udio(?:Encoder)?))|ndlerName)|LineScrollSize)|ye(?:sLabel|ar)|n(?:o(?:t|de(?:Name|Close|Type|Open|Value)|Label)|u(?:llValue|mChild(?:S(?:creens|lides)|ren|Forms))|e(?:w(?:Item|line|Value|LocationDialog)|xt(?:S(?:cene|ibling|lide)|TabIndex|Value|Frame)?)?|ame(?:s)?)|c(?:h(?:ildNodes|eck|a(?:nge(?:sPending)?|r(?:CodeAt|At))|r)|o(?:s|n(?:st(?:ant|ructor)|nect|c(?:urrency|at)|t(?:ent(?:Type|Path)?|ains|rol(?:Placement|lerPolicy))|denseWhite|version)|py|l(?:or|umn(?:Stretch|Name(?:s)?|Count))|m(?:p(?:onent|lete)|ment))|u(?:stomItems|ePoint(?:s)?|r(?:veTo|Value|rent(?:Slide|ChildSlide|Item|F(?:ocused(?:S(?:creen|lide)|Form)|ps))))|e(?:il|ll(?:Renderer|Press|Edit|Focus(?:In|Out)))|l(?:i(?:ck|ents)|o(?:se(?:Button|Pane)?|ne(?:Node)?)|ear(?:S(?:haredObjects|treams)|Timeout|Interval)?)|a(?:ncelLabel|tch|p(?:tion|abilities)|l(?:cFields|l(?:e(?:e|r))?))|reate(?:GatewayConnection|Menu|Se(?:rver|gment)|C(?:hild(?:AtDepth)?|l(?:ient|ass(?:ChildAtDepth|Object(?:AtDepth)?))|all)|Text(?:Node|Field)|Item|Object(?:AtDepth)?|PopUp|E(?:lement|mptyMovieClip)))|t(?:h(?:is|row)|ype(?:of|Name)?|i(?:tle(?:StyleDeclaration)?|me(?:out)?)|o(?:talTime|String|olTipText|p|UpperCase|ggle(?:HighQuality)?|Lo(?:caleString|werCase))|e(?:st|llTarget|xt(?:RightMargin|Bold|S(?:ize|elected)|Height|Color|I(?:ndent|talic)|Disabled|Underline|F(?:ield|ont)|Width|LeftMargin|Align)?)|a(?:n|rget(?:Path)?|b(?:Stops|Children|Index|Enabled|leName))|r(?:y|igger|ac(?:e|k(?:AsMenu)?)))|i(?:s(?:Running|Branch|NaN|Con(?:soleOpen|nected)|Toggled|Installed|Open|D(?:own|ebugger)|P(?:urchased|ro(?:totypeOf|pertyEnumerable))|Empty|F(?:inite|ullyPopulated)|Local|Active)|n(?:s(?:tall|ertBefore)|cludeDeltaPacketInfo|t|it(?:ialize|Component|Pod|A(?:pplication|gent))?|de(?:nt|terminate|x(?:InParent(?:Slide|Form)?|Of)?)|put|validate|finity|LocalInternetCache)?|con(?:F(?:ield|unction))?|t(?:e(?:ratorScrolled|m(?:s|RollO(?:ut|ver)|ClassName))|alic)|d3|p|fFrameLoaded|gnore(?:Case|White))|o(?:s|n(?:R(?:ollO(?:ut|ver)|e(?:s(?:ize|ult)|l(?:ease(?:Outside)?|aseOutside)))|XML|Mouse(?:Move|Down|Up|Wheel)|S(?:ync|croller|tatus|oundComplete|e(?:tFocus|lect(?:edItem)?))|N(?:oticeEvent|etworkChange)|C(?:hanged|onnect|l(?:ipEvent|ose))|ID3|D(?:isconnect|eactivate|ata|ragO(?:ut|ver))|Un(?:install|load)|P(?:aymentResult|ress)|EnterFrame|K(?:illFocus|ey(?:Down|Up))|Fault|Lo(?:ad|g)|A(?:ctiv(?:ity|ate)|ppSt(?:op|art)))?|pe(?:n|ration)|verLayChildren|kLabel|ldValue|r(?:d)?)|d(?:i(?:s(?:connect|play(?:Normal|ed(?:Month|Year)|Full)|able(?:Shader|d(?:Ranges|Days)|CloseBox|Events))|rection)|o(?:cTypeDecl|tall|Decoding|main|LazyDecoding)|u(?:plicateMovieClip|ration)|e(?:stroy(?:ChildAt|Object)|code|fault(?:PushButton(?:Enabled)?|KeydownHandler)?|l(?:ta(?:Packet(?:Changed)?)?|ete(?:PopUp|All)?)|blocking)|a(?:shBoardSave|yNames|ta(?:Provider)?|rkshadow)|r(?:opdown(?:Width)?|a(?:w|gO(?:ut|ver))))|u(?:se(?:Sort|HandCursor|Codepage|EchoSuppression)|n(?:shift|install|derline|escape|format|watch|lo(?:ck|ad(?:Movie(?:Num)?)?))|pdate(?:Results|Mode|I(?:nputProperties|tem(?:ByIndex)?)|P(?:acket|roperties)|View|AfterEvent)|rl)|join|p(?:ixelAspectRatio|o(?:sition|p|w)|u(?:sh|rge|blish)|ercen(?:tComplete|Loaded)|lay(?:head(?:Change|Time)|ing|Hidden|erType)?|a(?:ssword|use|r(?:se(?:XML|CSS|Int|Float)|ent(?:Node|Is(?:S(?:creen|lide)|Form))|ams))|r(?:int(?:Num|AsBitmap(?:Num)?)?|o(?:to(?:type)?|pert(?:y|ies)|gress)|e(?:ss|v(?:ious(?:S(?:ibling|lide)|Value)?|Scene|Frame)|ferred(?:Height|Width))))|e(?:scape|n(?:code(?:r)?|ter(?:Frame)?|dFill|able(?:Shader|d|CloseBox|Events))|dit(?:able|Field|LocationDialog)|v(?:ent|al(?:uate)?)|q|x(?:tended|p|ec(?:ute)?|actSettings)|m(?:phasized(?:StyleDeclaration)?|bedFonts))|v(?:i(?:sible|ewPod)|ScrollPolicy|o(?:id|lume)|ersion|P(?:osition|ageScrollSize)|a(?:l(?:idat(?:ionError|e(?:Property|ActivationKey)?)|ue(?:Of)?)|riable)|LineScrollSize)|k(?:ind|ey(?:Down|Up|Press|FrameInterval))|q(?:sort|uality)|f(?:scommand|i(?:n(?:d(?:Text|First|Last)?|ally)|eldInfo|lter(?:ed|Func)?|rst(?:Slide|Child|DayOfWeek|VisibleNode)?)|o(?:nt|cus(?:In|edCell|Out|Enabled)|r(?:egroundDisabled|mat(?:ter)?))|unctionName|ps|l(?:oor|ush)|ace|romCharCode)|w(?:i(?:th|dth)|ordWrap|atch|riteAccess)|l(?:t|i(?:st(?:Owner)?|ne(?:Style|To))|o(?:c(?:k|a(?:t(?:ion|eByld)|l(?:ToGlobal|FileReadDisable)))|opback|ad(?:Movie(?:Num)?|S(?:crollContent|ound)|ed|Variables(?:Num)?|Application)?|g(?:Changes)?)|e(?:ngth|ft(?:Margin)?|ading)?|a(?:st(?:Slide|Child|Index(?:Of)?)?|nguage|b(?:el(?:Placement|F(?:ield|unction))?|leField)))|a(?:s(?:scociate(?:Controller|Display)|in|pectRatio|function)|nd|c(?:ceptConnection|tiv(?:ityLevel|ePlayControl)|os)|t(?:t(?:ach(?:Movie|Sound|Video|Audio)|ributes)|an(?:2)?)|dd(?:header|RequestHeader|Menu(?:Item(?:At)?|At)?|Sort|Header|No(?:tice|de(?:At)?)|C(?:olumn(?:At)?|uePoint)|T(?:oLocalInternetCache|reeNode(?:At)?)|I(?:con|tem(?:s(?:At)?|At)?)|DeltaItem|P(?:od|age|roperty)|EventListener|View|FieldInfo|Listener|Animation)?|uto(?:Size|Play|KeyNav|Load)|pp(?:endChild|ly(?:Changes|Updates)?)|vHardwareDisable|fterLoaded|l(?:ternateRowColors|ign|l(?:ow(?:InsecureDomain|Domain)|Transitions(?:InDone|OutDone))|bum)|r(?:tist|row|g(?:uments|List))|gent|bs)|r(?:ight(?:Margin)?|o(?:ot(?:S(?:creen|lide)|Form)|und|w(?:Height|Count)|llO(?:ut|ver))|e(?:s(?:yncDepth|t(?:orePane|artAnimation|rict)|iz(?:e|able(?:Columns)?)|olveDelta|ult(?:s)?|ponse)|c(?:o(?:ncile(?:Results|Updates)|rd)|eive(?:Video|Audio))|draw|jectConnection|place(?:Sel|ItemAt|AllItems)?|ve(?:al(?:Child)?|rse)|quest(?:SizeChange|Payment)?|f(?:errer|resh(?:ScrollContent|Destinations|Pane|FromSources)?)|lease(?:Outside)?|ad(?:Only|Access)|gister(?:SkinElement|C(?:olor(?:Style|Name)|lass)|InheritingStyle|Proxy)|move(?:Range|M(?:ovieClip|enu(?:Item(?:At)?|At))|Background|Sort|No(?:tice|de(?:sAt|At)?)|C(?:olum(?:nAt|At)|uePoints)|T(?:extField|reeNode(?:At)?)|Item(?:At)?|Pod|EventListener|FromLocalInternetCache|Listener|All(?:C(?:olumns|uePoints)|Items)?))|a(?:ndom|te|dioDot))|g(?:t|oto(?:Slide|NextSlide|PreviousSlide|FirstSlide|LastSlide|And(?:Stop|Play))|e(?:nre|t(?:R(?:GB|o(?:otNode|wCount)|e(?:sizable|mote))|X(?:AxisTitle)?|M(?:i(?:n(?:imum(?:Size)?|utes)|lliseconds)|onth(?:Names)?|ultilineMode|e(?:ssage|nu(?:ItemAt|EnabledAt|At))|aximum(?:Size)?)|B(?:ytes(?:Total|Loaded)|ounds|utton(?:s|Width)|eginIndex|a(?:ndwidthLimit|ckground))|S(?:howAsDisabled|croll(?:ing|Speed|Content|Position|barState|Location)|t(?:yle(?:Names)?|opOnFocus|ate)|ize|o(?:urce|rtState)|p(?:litterBarPosition|acing)|e(?:conds|lect(?:Multiple|ion(?:Required|Type)|Style|ed(?:Node(?:s)?|Cell|Text|I(?:nd(?:ices|ex)|tem(?:s)?))?)|rvice)|moothness|WFVersion)|H(?:ighlight(?:s|Color)|ours|e(?:ight|ader(?:Height|Text|Property|Format|Width|Location)?)|as(?:Shader|CloseBox))|Y(?:ear|AxisTitle)?|N(?:o(?:tices|de(?:DisplayedAt|At))|um(?:Children|berAvailable)|e(?:wTextFormat|xtHighestDepth))|C(?:h(?:ild(?:S(?:creen|lide)|Nodes|Form|At)|artTitle)|o(?:n(?:tent|figInfo)|okie|de|unt|lumn(?:Names|Count|Index|At))|uePoint|ellIndex|loseHandler|a(?:ll|retIndex))|T(?:ypedValue|i(?:tle(?:barHeight)?|p(?:Target|Offset)?|me(?:stamp|zoneOffset|out(?:State|Handler)|r)?)|oggle|ext(?:Extent|Format)?|r(?:ee(?:NodeAt|Length)|ans(?:form|actionId)))|I(?:s(?:Branch|Open)|n(?:stanceAtDepth|d(?:icesByKey|exByKey))|con(?:SymbolName)?|te(?:rator|m(?:sByKey|By(?:Name|Key)|id|ID|At))|d)|O(?:utput(?:Parameter(?:s|ByName)?|Value(?:s)?)|peration|ri(?:entation|ginalCellData))|D(?:i(?:s(?:play(?:Range|Mode|Clip|Index|edMonth)|kUsage)|rection)|uration|e(?:pth|faultNodeIconSymbolName|l(?:taPacket|ay)|bug(?:Config|ID)?)|a(?:y(?:OfWeekNames)?|t(?:e|a(?:Mapping(?:s)?|Item(?:Text|Property|Format)|Label|All(?:Height|Property|Format|Width))?))|rawConnectors)|U(?:se(?:Shadow|HandCursor|rInput|Fade)|RL|TC(?:M(?:i(?:nutes|lliseconds)|onth)|Seconds|Hours|Da(?:y|te)|FullYear))|P(?:o(?:sition|ds)|ercentComplete|a(?:n(?:e(?:M(?:inimums|aximums)|Height|Title|Width))?|rentNode)|r(?:operty(?:Name|Data)?|efer(?:ences|red(?:Height|Width))))|E(?:n(?:dIndex|abled)|ditingData|x(?:panderSymbolName|andNodeTrigger))|V(?:iewed(?:Pods|Applications)|olume|ersion|alue(?:Source)?)|F(?:i(?:eld|rst(?:DayOfWeek|VisibleNode))|o(?:ntList|cus)|ullYear|ade(?:InLength|OutLength)|rame(?:Color|Width))|Width|L(?:ine(?:Color|Weight)|o(?:cal|adTarget)|ength|a(?:stTabIndex|bel(?:Source)?))|A(?:s(?:cii|Boolean|String|Number)|n(?:yTypedValue|imation)|ctiv(?:eState(?:Handler)?|ateHandler)|utoH(?:ideScrollBar|eight)|llItems|gent))?)?|lobal(?:StyleFormat|ToLocal)?|ain|roupName)|x(?:updatePackety|mlDecl)?|m(?:y(?:MethodName|Call)|in(?:imum)?|o(?:nthNames|tion(?:TimeOut|Level)|de(?:lChanged)?|use(?:Move|O(?:ut|ver)|Down(?:Somewhere|Outside)?|Up(?:Somewhere)?|WheelEnabled)|ve(?:To)?)|u(?:ted|lti(?:pleS(?:imultaneousAllowed|elections)|line))|e(?:ssage|nu(?:Show|Hide)?|th(?:od)?|diaType)|a(?:nufacturer|tch|x(?:scroll|hscroll|imum|HPosition|Chars|VPosition)?)|b(?:substring|chr|ord|length))|b(?:ytes(?:Total|Loaded)|indFormat(?:Strings|Function)|o(?:ttom(?:Scroll)?|ld|rder(?:Color)?)|u(?:tton(?:Height|Width)|iltInItems|ffer(?:Time|Length)|llet)|e(?:foreApplyUpdates|gin(?:GradientFill|Fill))|lockIndent|a(?:ndwidth|ckground(?:Style|Color|Disabled)?)|roadcastMessage)|onHTTPStatus)\\b' }, + { token: 'support.constant.actionscript.2', + regex: '\\b(?:__proto__|__resolve|_accProps|_alpha|_changed|_currentframe|_droptarget|_flash|_focusrect|_framesloaded|_global|_height|_highquality|_level|_listeners|_lockroot|_name|_parent|_quality|_root|_rotation|_soundbuftime|_target|_totalframes|_url|_visible|_width|_x|_xmouse|_xscale|_y|_ymouse|_yscale)\\b' }, + { token: 'keyword.control.actionscript.2', + regex: '\\b(?:dynamic|extends|import|implements|interface|public|private|new|static|super|var|for|in|break|continue|while|do|return|if|else|case|switch)\\b' }, + { token: 'storage.type.actionscript.2', + regex: '\\b(?:Boolean|Number|String|Void)\\b' }, + { token: 'constant.language.actionscript.2', + regex: '\\b(?:null|undefined|true|false)\\b' }, + { token: 'constant.numeric.actionscript.2', + regex: '\\b(?:0(?:x|X)[0-9a-fA-F]*|(?:[0-9]+\\.?[0-9]*|\\.[0-9]+)(?:(?:e|E)(?:\\+|-)?[0-9]+)?)(?:L|l|UL|ul|u|U|F|f)?\\b' }, + { token: 'punctuation.definition.string.begin.actionscript.2', + regex: '"', + push: + [ { token: 'punctuation.definition.string.end.actionscript.2', + regex: '"', + next: 'pop' }, + { token: 'constant.character.escape.actionscript.2', + regex: '\\\\.' }, + { defaultToken: 'string.quoted.double.actionscript.2' } ] }, + { token: 'punctuation.definition.string.begin.actionscript.2', + regex: '\'', + push: + [ { token: 'punctuation.definition.string.end.actionscript.2', + regex: '\'', + next: 'pop' }, + { token: 'constant.character.escape.actionscript.2', + regex: '\\\\.' }, + { defaultToken: 'string.quoted.single.actionscript.2' } ] }, + { token: 'support.constant.actionscript.2', + regex: '\\b(?:BACKSPACE|CAPSLOCK|CONTROL|DELETEKEY|DOWN|END|ENTER|HOME|INSERT|LEFT|LN10|LN2|LOG10E|LOG2E|MAX_VALUE|MIN_VALUE|NEGATIVE_INFINITY|NaN|PGDN|PGUP|PI|POSITIVE_INFINITY|RIGHT|SPACE|SQRT1_2|SQRT2|UP)\\b' }, + { token: 'punctuation.definition.comment.actionscript.2', + regex: '/\\*', + push: + [ { token: 'punctuation.definition.comment.actionscript.2', + regex: '\\*/', + next: 'pop' }, + { defaultToken: 'comment.block.actionscript.2' } ] }, + { token: 'punctuation.definition.comment.actionscript.2', + regex: '//.*$', + push_: + [ { token: 'comment.line.double-slash.actionscript.2', + regex: '$', + next: 'pop' }, + { defaultToken: 'comment.line.double-slash.actionscript.2' } ] }, + { token: 'keyword.operator.actionscript.2', + regex: '\\binstanceof\\b' }, + { token: 'keyword.operator.symbolic.actionscript.2', + regex: '[-!%&*+=/?:]' }, + { token: + [ 'meta.preprocessor.actionscript.2', + 'punctuation.definition.preprocessor.actionscript.2', + 'meta.preprocessor.actionscript.2' ], + regex: '^([ \\t]*)(#)([a-zA-Z]+)' }, + { token: + [ 'storage.type.function.actionscript.2', + 'meta.function.actionscript.2', + 'entity.name.function.actionscript.2', + 'meta.function.actionscript.2', + 'punctuation.definition.parameters.begin.actionscript.2' ], + regex: '\\b(function)(\\s+)([a-zA-Z_]\\w*)(\\s*)(\\()', + push: + [ { token: 'punctuation.definition.parameters.end.actionscript.2', + regex: '\\)', + next: 'pop' }, + { token: 'variable.parameter.function.actionscript.2', + regex: '[^,)$]+' }, + { defaultToken: 'meta.function.actionscript.2' } ] }, + { token: + [ 'storage.type.class.actionscript.2', + 'meta.class.actionscript.2', + 'entity.name.type.class.actionscript.2', + 'meta.class.actionscript.2', + 'storage.modifier.extends.actionscript.2', + 'meta.class.actionscript.2', + 'entity.other.inherited-class.actionscript.2' ], + regex: '\\b(class)(\\s+)([a-zA-Z_](?:\\w|\\.)*)(?:(\\s+)(extends)(\\s+)([a-zA-Z_](?:\\w|\\.)*))?' } ] } + + this.normalizeRules(); +}; + +ActionScriptHighlightRules.metaData = { fileTypes: [ 'as' ], + keyEquivalent: '^~A', + name: 'ActionScript', + scopeName: 'source.actionscript.2' } + + +oop.inherits(ActionScriptHighlightRules, TextHighlightRules); + +exports.ActionScriptHighlightRules = ActionScriptHighlightRules; +}); \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/ada.js b/node_modules/ace/lib/ace/mode/ada.js new file mode 100644 index 00000000..dc1dfa14 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/ada.js @@ -0,0 +1,54 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextMode = require("./text").Mode; +var AdaHighlightRules = require("./ada_highlight_rules").AdaHighlightRules; +var Range = require("../range").Range; + +var Mode = function() { + this.HighlightRules = AdaHighlightRules; +}; +oop.inherits(Mode, TextMode); + +(function() { + + this.lineCommentStart = "--"; + + this.$id = "ace/mode/ada"; +}).call(Mode.prototype); + +exports.Mode = Mode; + +}); + diff --git a/node_modules/ace/lib/ace/mode/ada_highlight_rules.js b/node_modules/ace/lib/ace/mode/ada_highlight_rules.js new file mode 100644 index 00000000..b345966c --- /dev/null +++ b/node_modules/ace/lib/ace/mode/ada_highlight_rules.js @@ -0,0 +1,93 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + +var AdaHighlightRules = function() { +var keywords = "abort|else|new|return|abs|elsif|not|reverse|abstract|end|null|accept|entry|select|" + +"access|exception|of|separate|aliased|exit|or|some|all|others|subtype|and|for|out|synchronized|" + +"array|function|overriding|at|tagged|generic|package|task|begin|goto|pragma|terminate|" + +"body|private|then|if|procedure|type|case|in|protected|constant|interface|until|" + +"|is|raise|use|declare|range|delay|limited|record|when|delta|loop|rem|while|digits|renames|with|do|mod|requeue|xor"; + + var builtinConstants = ( + "true|false|null" + ); + + var builtinFunctions = ( + "count|min|max|avg|sum|rank|now|coalesce|main" + ); + + var keywordMapper = this.createKeywordMapper({ + "support.function": builtinFunctions, + "keyword": keywords, + "constant.language": builtinConstants + }, "identifier", true); + + this.$rules = { + "start" : [ { + token : "comment", + regex : "--.*$" + }, { + token : "string", // " string + regex : '".*?"' + }, { + token : "string", // ' string + regex : "'.*?'" + }, { + token : "constant.numeric", // float + regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b" + }, { + token : keywordMapper, + regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b" + }, { + token : "keyword.operator", + regex : "\\+|\\-|\\/|\\/\\/|%|<@>|@>|<@|&|\\^|~|<|>|<=|=>|==|!=|<>|=" + }, { + token : "paren.lparen", + regex : "[\\(]" + }, { + token : "paren.rparen", + regex : "[\\)]" + }, { + token : "text", + regex : "\\s+" + } ] + }; +}; + +oop.inherits(AdaHighlightRules, TextHighlightRules); + +exports.AdaHighlightRules = AdaHighlightRules; +}); \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/apache_conf.js b/node_modules/ace/lib/ace/mode/apache_conf.js new file mode 100644 index 00000000..2379b44b --- /dev/null +++ b/node_modules/ace/lib/ace/mode/apache_conf.js @@ -0,0 +1,62 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * + * Contributor(s): + * + * + * + * ***** END LICENSE BLOCK ***** */ + +/* + THIS FILE WAS AUTOGENERATED BY mode.tmpl.js +*/ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextMode = require("./text").Mode; +var ApacheConfHighlightRules = require("./apache_conf_highlight_rules").ApacheConfHighlightRules; +// TODO: pick appropriate fold mode +var FoldMode = require("./folding/cstyle").FoldMode; + +var Mode = function() { + this.HighlightRules = ApacheConfHighlightRules; + this.foldingRules = new FoldMode(); +}; +oop.inherits(Mode, TextMode); + +(function() { + this.lineCommentStart = "#"; + this.$id = "ace/mode/apache_conf"; + // Extra logic goes here. +}).call(Mode.prototype); + +exports.Mode = Mode; +}); \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/apache_conf_highlight_rules.js b/node_modules/ace/lib/ace/mode/apache_conf_highlight_rules.js new file mode 100644 index 00000000..c310612d --- /dev/null +++ b/node_modules/ace/lib/ace/mode/apache_conf_highlight_rules.js @@ -0,0 +1,231 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +/* This file was autogenerated from https://raw.github.com/colinta/ApacheConf.tmLanguage/master/ApacheConf.tmLanguage (uuid: ) */ +/**************************************************************************************** + * IT MIGHT NOT BE PERFECT ...But it's a good start from an existing *.tmlanguage file. * + * fileTypes * + ****************************************************************************************/ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + +var ApacheConfHighlightRules = function() { + // regexp must not have capturing parentheses. Use (?:) instead. + // regexps are ordered -> the first match is used + + this.$rules = { start: + [ { token: + [ 'punctuation.definition.comment.apacheconf', + 'comment.line.hash.ini', + 'comment.line.hash.ini' ], + regex: '^((?:\\s)*)(#)(.*$)' }, + { token: + [ 'punctuation.definition.tag.apacheconf', + 'entity.tag.apacheconf', + 'text', + 'string.value.apacheconf', + 'punctuation.definition.tag.apacheconf' ], + regex: '(<)(Proxy|ProxyMatch|IfVersion|Directory|DirectoryMatch|Files|FilesMatch|IfDefine|IfModule|Limit|LimitExcept|Location|LocationMatch|VirtualHost)(?:(\\s)(.+?))?(>)' }, + { token: + [ 'punctuation.definition.tag.apacheconf', + 'entity.tag.apacheconf', + 'punctuation.definition.tag.apacheconf' ], + regex: '()' }, + { token: + [ 'keyword.alias.apacheconf', 'text', + 'string.regexp.apacheconf', 'text', + 'string.replacement.apacheconf', 'text' ], + regex: '(Rewrite(?:Rule|Cond))(\\s+)(.+?)(\\s+)(.+?)($|\\s)' }, + { token: + [ 'keyword.alias.apacheconf', 'text', + 'entity.status.apacheconf', 'text', + 'string.regexp.apacheconf', 'text', + 'string.path.apacheconf', 'text' ], + regex: '(RedirectMatch)(?:(\\s+)(\\d\\d\\d|permanent|temp|seeother|gone))?(\\s+)(.+?)(\\s+)(?:(.+?)($|\\s))?' }, + { token: + [ 'keyword.alias.apacheconf', 'text', + 'entity.status.apacheconf', 'text', + 'string.path.apacheconf', 'text', + 'string.path.apacheconf', 'text' ], + regex: '(Redirect)(?:(\\s+)(\\d\\d\\d|permanent|temp|seeother|gone))?(\\s+)(.+?)(\\s+)(?:(.+?)($|\\s))?' }, + { token: + [ 'keyword.alias.apacheconf', 'text', + 'string.regexp.apacheconf', 'text', + 'string.path.apacheconf', 'text' ], + regex: '(ScriptAliasMatch|AliasMatch)(\\s+)(.+?)(\\s+)(?:(.+?)(\\s))?' }, + { token: + [ 'keyword.alias.apacheconf', 'text', + 'string.path.apacheconf', 'text', + 'string.path.apacheconf', 'text' ], + regex: '(RedirectPermanent|RedirectTemp|ScriptAlias|Alias)(\\s+)(.+?)(\\s+)(?:(.+?)($|\\s))?' }, + { token: 'keyword.core.apacheconf', + regex: '\\b(?:AcceptPathInfo|AccessFileName|AddDefaultCharset|AddOutputFilterByType|AllowEncodedSlashes|AllowOverride|AuthName|AuthType|CGIMapExtension|ContentDigest|DefaultType|DocumentRoot|EnableMMAP|EnableSendfile|ErrorDocument|ErrorLog|FileETag|ForceType|HostnameLookups|IdentityCheck|Include|KeepAlive|KeepAliveTimeout|LimitInternalRecursion|LimitRequestBody|LimitRequestFields|LimitRequestFieldSize|LimitRequestLine|LimitXMLRequestBody|LogLevel|MaxKeepAliveRequests|NameVirtualHost|Options|Require|RLimitCPU|RLimitMEM|RLimitNPROC|Satisfy|ScriptInterpreterSource|ServerAdmin|ServerAlias|ServerName|ServerPath|ServerRoot|ServerSignature|ServerTokens|SetHandler|SetInputFilter|SetOutputFilter|TimeOut|TraceEnable|UseCanonicalName)\\b' }, + { token: 'keyword.mpm.apacheconf', + regex: '\\b(?:AcceptMutex|AssignUserID|BS2000Account|ChildPerUserID|CoreDumpDirectory|EnableExceptionHook|Group|Listen|ListenBacklog|LockFile|MaxClients|MaxMemFree|MaxRequestsPerChild|MaxRequestsPerThread|MaxSpareServers|MaxSpareThreads|MaxThreads|MaxThreadsPerChild|MinSpareServers|MinSpareThreads|NumServers|PidFile|ReceiveBufferSize|ScoreBoardFile|SendBufferSize|ServerLimit|StartServers|StartThreads|ThreadLimit|ThreadsPerChild|ThreadStackSize|User|Win32DisableAcceptEx)\\b' }, + { token: 'keyword.access.apacheconf', + regex: '\\b(?:Allow|Deny|Order)\\b' }, + { token: 'keyword.actions.apacheconf', + regex: '\\b(?:Action|Script)\\b' }, + { token: 'keyword.alias.apacheconf', + regex: '\\b(?:Alias|AliasMatch|Redirect|RedirectMatch|RedirectPermanent|RedirectTemp|ScriptAlias|ScriptAliasMatch)\\b' }, + { token: 'keyword.auth.apacheconf', + regex: '\\b(?:AuthAuthoritative|AuthGroupFile|AuthUserFile)\\b' }, + { token: 'keyword.auth_anon.apacheconf', + regex: '\\b(?:Anonymous|Anonymous_Authoritative|Anonymous_LogEmail|Anonymous_MustGiveEmail|Anonymous_NoUserID|Anonymous_VerifyEmail)\\b' }, + { token: 'keyword.auth_dbm.apacheconf', + regex: '\\b(?:AuthDBMAuthoritative|AuthDBMGroupFile|AuthDBMType|AuthDBMUserFile)\\b' }, + { token: 'keyword.auth_digest.apacheconf', + regex: '\\b(?:AuthDigestAlgorithm|AuthDigestDomain|AuthDigestFile|AuthDigestGroupFile|AuthDigestNcCheck|AuthDigestNonceFormat|AuthDigestNonceLifetime|AuthDigestQop|AuthDigestShmemSize)\\b' }, + { token: 'keyword.auth_ldap.apacheconf', + regex: '\\b(?:AuthLDAPAuthoritative|AuthLDAPBindDN|AuthLDAPBindPassword|AuthLDAPCharsetConfig|AuthLDAPCompareDNOnServer|AuthLDAPDereferenceAliases|AuthLDAPEnabled|AuthLDAPFrontPageHack|AuthLDAPGroupAttribute|AuthLDAPGroupAttributeIsDN|AuthLDAPRemoteUserIsDN|AuthLDAPUrl)\\b' }, + { token: 'keyword.autoindex.apacheconf', + regex: '\\b(?:AddAlt|AddAltByEncoding|AddAltByType|AddDescription|AddIcon|AddIconByEncoding|AddIconByType|DefaultIcon|HeaderName|IndexIgnore|IndexOptions|IndexOrderDefault|ReadmeName)\\b' }, + { token: 'keyword.cache.apacheconf', + regex: '\\b(?:CacheDefaultExpire|CacheDisable|CacheEnable|CacheForceCompletion|CacheIgnoreCacheControl|CacheIgnoreHeaders|CacheIgnoreNoLastMod|CacheLastModifiedFactor|CacheMaxExpire)\\b' }, + { token: 'keyword.cern_meta.apacheconf', + regex: '\\b(?:MetaDir|MetaFiles|MetaSuffix)\\b' }, + { token: 'keyword.cgi.apacheconf', + regex: '\\b(?:ScriptLog|ScriptLogBuffer|ScriptLogLength)\\b' }, + { token: 'keyword.cgid.apacheconf', + regex: '\\b(?:ScriptLog|ScriptLogBuffer|ScriptLogLength|ScriptSock)\\b' }, + { token: 'keyword.charset_lite.apacheconf', + regex: '\\b(?:CharsetDefault|CharsetOptions|CharsetSourceEnc)\\b' }, + { token: 'keyword.dav.apacheconf', + regex: '\\b(?:Dav|DavDepthInfinity|DavMinTimeout|DavLockDB)\\b' }, + { token: 'keyword.deflate.apacheconf', + regex: '\\b(?:DeflateBufferSize|DeflateCompressionLevel|DeflateFilterNote|DeflateMemLevel|DeflateWindowSize)\\b' }, + { token: 'keyword.dir.apacheconf', + regex: '\\b(?:DirectoryIndex|DirectorySlash)\\b' }, + { token: 'keyword.disk_cache.apacheconf', + regex: '\\b(?:CacheDirLength|CacheDirLevels|CacheExpiryCheck|CacheGcClean|CacheGcDaily|CacheGcInterval|CacheGcMemUsage|CacheGcUnused|CacheMaxFileSize|CacheMinFileSize|CacheRoot|CacheSize|CacheTimeMargin)\\b' }, + { token: 'keyword.dumpio.apacheconf', + regex: '\\b(?:DumpIOInput|DumpIOOutput)\\b' }, + { token: 'keyword.env.apacheconf', + regex: '\\b(?:PassEnv|SetEnv|UnsetEnv)\\b' }, + { token: 'keyword.expires.apacheconf', + regex: '\\b(?:ExpiresActive|ExpiresByType|ExpiresDefault)\\b' }, + { token: 'keyword.ext_filter.apacheconf', + regex: '\\b(?:ExtFilterDefine|ExtFilterOptions)\\b' }, + { token: 'keyword.file_cache.apacheconf', + regex: '\\b(?:CacheFile|MMapFile)\\b' }, + { token: 'keyword.headers.apacheconf', + regex: '\\b(?:Header|RequestHeader)\\b' }, + { token: 'keyword.imap.apacheconf', + regex: '\\b(?:ImapBase|ImapDefault|ImapMenu)\\b' }, + { token: 'keyword.include.apacheconf', + regex: '\\b(?:SSIEndTag|SSIErrorMsg|SSIStartTag|SSITimeFormat|SSIUndefinedEcho|XBitHack)\\b' }, + { token: 'keyword.isapi.apacheconf', + regex: '\\b(?:ISAPIAppendLogToErrors|ISAPIAppendLogToQuery|ISAPICacheFile|ISAPIFakeAsync|ISAPILogNotSupported|ISAPIReadAheadBuffer)\\b' }, + { token: 'keyword.ldap.apacheconf', + regex: '\\b(?:LDAPCacheEntries|LDAPCacheTTL|LDAPConnectionTimeout|LDAPOpCacheEntries|LDAPOpCacheTTL|LDAPSharedCacheFile|LDAPSharedCacheSize|LDAPTrustedCA|LDAPTrustedCAType)\\b' }, + { token: 'keyword.log.apacheconf', + regex: '\\b(?:BufferedLogs|CookieLog|CustomLog|LogFormat|TransferLog|ForensicLog)\\b' }, + { token: 'keyword.mem_cache.apacheconf', + regex: '\\b(?:MCacheMaxObjectCount|MCacheMaxObjectSize|MCacheMaxStreamingBuffer|MCacheMinObjectSize|MCacheRemovalAlgorithm|MCacheSize)\\b' }, + { token: 'keyword.mime.apacheconf', + regex: '\\b(?:AddCharset|AddEncoding|AddHandler|AddInputFilter|AddLanguage|AddOutputFilter|AddType|DefaultLanguage|ModMimeUsePathInfo|MultiviewsMatch|RemoveCharset|RemoveEncoding|RemoveHandler|RemoveInputFilter|RemoveLanguage|RemoveOutputFilter|RemoveType|TypesConfig)\\b' }, + { token: 'keyword.misc.apacheconf', + regex: '\\b(?:ProtocolEcho|Example|AddModuleInfo|MimeMagicFile|CheckSpelling|ExtendedStatus|SuexecUserGroup|UserDir)\\b' }, + { token: 'keyword.negotiation.apacheconf', + regex: '\\b(?:CacheNegotiatedDocs|ForceLanguagePriority|LanguagePriority)\\b' }, + { token: 'keyword.nw_ssl.apacheconf', + regex: '\\b(?:NWSSLTrustedCerts|NWSSLUpgradeable|SecureListen)\\b' }, + { token: 'keyword.proxy.apacheconf', + regex: '\\b(?:AllowCONNECT|NoProxy|ProxyBadHeader|ProxyBlock|ProxyDomain|ProxyErrorOverride|ProxyFtpDirCharset|ProxyIOBufferSize|ProxyMaxForwards|ProxyPass|ProxyPassReverse|ProxyPreserveHost|ProxyReceiveBufferSize|ProxyRemote|ProxyRemoteMatch|ProxyRequests|ProxyTimeout|ProxyVia)\\b' }, + { token: 'keyword.rewrite.apacheconf', + regex: '\\b(?:RewriteBase|RewriteCond|RewriteEngine|RewriteLock|RewriteLog|RewriteLogLevel|RewriteMap|RewriteOptions|RewriteRule)\\b' }, + { token: 'keyword.setenvif.apacheconf', + regex: '\\b(?:BrowserMatch|BrowserMatchNoCase|SetEnvIf|SetEnvIfNoCase)\\b' }, + { token: 'keyword.so.apacheconf', + regex: '\\b(?:LoadFile|LoadModule)\\b' }, + { token: 'keyword.ssl.apacheconf', + regex: '\\b(?:SSLCACertificateFile|SSLCACertificatePath|SSLCARevocationFile|SSLCARevocationPath|SSLCertificateChainFile|SSLCertificateFile|SSLCertificateKeyFile|SSLCipherSuite|SSLEngine|SSLMutex|SSLOptions|SSLPassPhraseDialog|SSLProtocol|SSLProxyCACertificateFile|SSLProxyCACertificatePath|SSLProxyCARevocationFile|SSLProxyCARevocationPath|SSLProxyCipherSuite|SSLProxyEngine|SSLProxyMachineCertificateFile|SSLProxyMachineCertificatePath|SSLProxyProtocol|SSLProxyVerify|SSLProxyVerifyDepth|SSLRandomSeed|SSLRequire|SSLRequireSSL|SSLSessionCache|SSLSessionCacheTimeout|SSLUserName|SSLVerifyClient|SSLVerifyDepth)\\b' }, + { token: 'keyword.usertrack.apacheconf', + regex: '\\b(?:CookieDomain|CookieExpires|CookieName|CookieStyle|CookieTracking)\\b' }, + { token: 'keyword.vhost_alias.apacheconf', + regex: '\\b(?:VirtualDocumentRoot|VirtualDocumentRootIP|VirtualScriptAlias|VirtualScriptAliasIP)\\b' }, + { token: + [ 'keyword.php.apacheconf', + 'text', + 'entity.property.apacheconf', + 'text', + 'string.value.apacheconf', + 'text' ], + regex: '\\b(php_value|php_flag)\\b(?:(\\s+)(.+?)(?:(\\s+)(.+?))?)?(\\s)' }, + { token: + [ 'punctuation.variable.apacheconf', + 'variable.env.apacheconf', + 'variable.misc.apacheconf', + 'punctuation.variable.apacheconf' ], + regex: '(%\\{)(?:(HTTP_USER_AGENT|HTTP_REFERER|HTTP_COOKIE|HTTP_FORWARDED|HTTP_HOST|HTTP_PROXY_CONNECTION|HTTP_ACCEPT|REMOTE_ADDR|REMOTE_HOST|REMOTE_PORT|REMOTE_USER|REMOTE_IDENT|REQUEST_METHOD|SCRIPT_FILENAME|PATH_INFO|QUERY_STRING|AUTH_TYPE|DOCUMENT_ROOT|SERVER_ADMIN|SERVER_NAME|SERVER_ADDR|SERVER_PORT|SERVER_PROTOCOL|SERVER_SOFTWARE|TIME_YEAR|TIME_MON|TIME_DAY|TIME_HOUR|TIME_MIN|TIME_SEC|TIME_WDAY|TIME|API_VERSION|THE_REQUEST|REQUEST_URI|REQUEST_FILENAME|IS_SUBREQ|HTTPS)|(.*?))(\\})' }, + { token: [ 'entity.mime-type.apacheconf', 'text' ], + regex: '\\b((?:text|image|application|video|audio)/.+?)(\\s)' }, + { token: 'entity.helper.apacheconf', + regex: '\\b(?:from|unset|set|on|off)\\b', + caseInsensitive: true }, + { token: 'constant.integer.apacheconf', regex: '\\b\\d+\\b' }, + { token: + [ 'text', + 'punctuation.definition.flag.apacheconf', + 'string.flag.apacheconf', + 'punctuation.definition.flag.apacheconf', + 'text' ], + regex: '(\\s)(\\[)(.*?)(\\])(\\s)' } ] } + + this.normalizeRules(); +}; + +ApacheConfHighlightRules.metaData = { fileTypes: + [ 'conf', + 'CONF', + 'htaccess', + 'HTACCESS', + 'htgroups', + 'HTGROUPS', + 'htpasswd', + 'HTPASSWD', + '.htaccess', + '.HTACCESS', + '.htgroups', + '.HTGROUPS', + '.htpasswd', + '.HTPASSWD' ], + name: 'Apache Conf', + scopeName: 'source.apacheconf' } + + +oop.inherits(ApacheConfHighlightRules, TextHighlightRules); + +exports.ApacheConfHighlightRules = ApacheConfHighlightRules; +}); \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/applescript.js b/node_modules/ace/lib/ace/mode/applescript.js new file mode 100644 index 00000000..81bc3533 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/applescript.js @@ -0,0 +1,55 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextMode = require("./text").Mode; +var Tokenizer = require("../tokenizer").Tokenizer; +var AppleScriptHighlightRules = require("./applescript_highlight_rules").AppleScriptHighlightRules; +// TODO: pick appropriate fold mode +var FoldMode = require("./folding/cstyle").FoldMode; + +var Mode = function() { + this.HighlightRules = AppleScriptHighlightRules; + this.foldingRules = new FoldMode(); +}; +oop.inherits(Mode, TextMode); + +(function() { + this.lineCommentStart = "--"; + this.blockComment = {start: "(*", end: "*)"}; + this.$id = "ace/mode/applescript"; + // Extra logic goes here. +}).call(Mode.prototype); + +exports.Mode = Mode; +}); diff --git a/node_modules/ace/lib/ace/mode/applescript_highlight_rules.js b/node_modules/ace/lib/ace/mode/applescript_highlight_rules.js new file mode 100644 index 00000000..d830d780 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/applescript_highlight_rules.js @@ -0,0 +1,139 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + +var AppleScriptHighlightRules = function() { + // regexp must not have capturing parentheses. Use (?:) instead. + // regexps are ordered -> the first match is used + var keywords = ( + "about|above|after|against|and|around|as|at|back|before|beginning|" + + "behind|below|beneath|beside|between|but|by|considering|" + + "contain|contains|continue|copy|div|does|eighth|else|end|equal|" + + "equals|error|every|exit|fifth|first|for|fourth|from|front|" + + "get|given|global|if|ignoring|in|into|is|it|its|last|local|me|" + + "middle|mod|my|ninth|not|of|on|onto|or|over|prop|property|put|ref|" + + "reference|repeat|returning|script|second|set|seventh|since|" + + "sixth|some|tell|tenth|that|the|then|third|through|thru|" + + "timeout|times|to|transaction|try|until|where|while|whose|with|without" + ); + + var builtinConstants = ( + "AppleScript|false|linefeed|return|pi|quote|result|space|tab|true" + ); + + var builtinFunctions = ( + "activate|beep|count|delay|launch|log|offset|read|round|run|say|" + + "summarize|write" + ); + + var builtinTypes = ( + "alias|application|boolean|class|constant|date|file|integer|list|" + + "number|real|record|string|text|character|characters|contents|day|" + + "frontmost|id|item|length|month|name|paragraph|paragraphs|rest|" + + "reverse|running|time|version|weekday|word|words|year" + ); + + var keywordMapper = this.createKeywordMapper({ + "support.function": builtinFunctions, + "constant.language": builtinConstants, + "support.type": builtinTypes, + "keyword": keywords + }, "identifier"); + + this.$rules = { + "start": [ + { + token: "comment", + regex: "--.*$" + }, + { + token : "comment", // multi line comment + regex : "\\(\\*", + next : "comment" + }, + { + token: "string", // " string + regex: '".*?"' + }, + { + token: "support.type", + regex: '\\b(POSIX file|POSIX path|(date|time) string|quoted form)\\b' + }, + { + token: "support.function", + regex: '\\b(clipboard info|the clipboard|info for|list (disks|folder)|' + + 'mount volume|path to|(close|open for) access|(get|set) eof|' + + 'current date|do shell script|get volume settings|random number|' + + 'set volume|system attribute|system info|time to GMT|' + + '(load|run|store) script|scripting components|' + + 'ASCII (character|number)|localized string|' + + 'choose (application|color|file|file name|' + + 'folder|from list|remote application|URL)|' + + 'display (alert|dialog))\\b|^\\s*return\\b' + }, + { + token: "constant.language", + regex: '\\b(text item delimiters|current application|missing value)\\b' + }, + { + token: "keyword", + regex: '\\b(apart from|aside from|instead of|out of|greater than|' + + "isn't|(doesn't|does not) (equal|come before|come after|contain)|" + + '(greater|less) than( or equal)?|(starts?|ends|begins?) with|' + + 'contained by|comes (before|after)|a (ref|reference))\\b' + }, + { + token: keywordMapper, + regex: "[a-zA-Z][a-zA-Z0-9_]*\\b" + } + ], + "comment": [ + { + token: "comment", // closing comment + regex: "\\*\\)", + next: "start" + }, { + defaultToken: "comment" + } + ] + } + + this.normalizeRules(); +}; + +oop.inherits(AppleScriptHighlightRules, TextHighlightRules); + +exports.AppleScriptHighlightRules = AppleScriptHighlightRules; +}); diff --git a/node_modules/ace/lib/ace/mode/asciidoc.js b/node_modules/ace/lib/ace/mode/asciidoc.js new file mode 100644 index 00000000..894d9763 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/asciidoc.js @@ -0,0 +1,64 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextMode = require("./text").Mode; +var AsciidocHighlightRules = require("./asciidoc_highlight_rules").AsciidocHighlightRules; +var AsciidocFoldMode = require("./folding/asciidoc").FoldMode; + +var Mode = function() { + this.HighlightRules = AsciidocHighlightRules; + + this.foldingRules = new AsciidocFoldMode(); +}; +oop.inherits(Mode, TextMode); + +(function() { + this.type = "text"; + this.getNextLineIndent = function(state, line, tab) { + if (state == "listblock") { + var match = /^((?:.+)?)([-+*][ ]+)/.exec(line); + if (match) { + return new Array(match[1].length + 1).join(" ") + match[2]; + } else { + return ""; + } + } else { + return this.$getIndent(line); + } + }; + this.$id = "ace/mode/asciidoc"; +}).call(Mode.prototype); + +exports.Mode = Mode; +}); diff --git a/node_modules/ace/lib/ace/mode/asciidoc_highlight_rules.js b/node_modules/ace/lib/ace/mode/asciidoc_highlight_rules.js new file mode 100644 index 00000000..c0d1a305 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/asciidoc_highlight_rules.js @@ -0,0 +1,234 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + +var AsciidocHighlightRules = function() { + var identifierRe = "[a-zA-Z\u00a1-\uffff]+\\b"; + + this.$rules = { + "start": [ + {token: "empty", regex: /$/}, + {token: "literal", regex: /^\.{4,}\s*$/, next: "listingBlock"}, + {token: "literal", regex: /^-{4,}\s*$/, next: "literalBlock"}, + {token: "string", regex: /^\+{4,}\s*$/, next: "passthroughBlock"}, + {token: "keyword", regex: /^={4,}\s*$/}, + {token: "text", regex: /^\s*$/}, + // immediately return to the start mode without matching anything + {token: "empty", regex: "", next: "dissallowDelimitedBlock"} + ], + + "dissallowDelimitedBlock": [ + {include: "paragraphEnd"}, + {token: "comment", regex: '^//.+$'}, + {token: "keyword", regex: "^(?:NOTE|TIP|IMPORTANT|WARNING|CAUTION):"}, + + {include: "listStart"}, + {token: "literal", regex: /^\s+.+$/, next: "indentedBlock"}, + {token: "empty", regex: "", next: "text"} + ], + + "paragraphEnd": [ + {token: "doc.comment", regex: /^\/{4,}\s*$/, next: "commentBlock"}, + {token: "tableBlock", regex: /^\s*[|!]=+\s*$/, next: "tableBlock"}, + // open block, ruller + {token: "keyword", regex: /^(?:--|''')\s*$/, next: "start"}, + {token: "option", regex: /^\[.*\]\s*$/, next: "start"}, + {token: "pageBreak", regex: /^>{3,}$/, next: "start"}, + {token: "literal", regex: /^\.{4,}\s*$/, next: "listingBlock"}, + {token: "titleUnderline", regex: /^(?:={2,}|-{2,}|~{2,}|\^{2,}|\+{2,})\s*$/, next: "start"}, + {token: "singleLineTitle", regex: /^={1,5}\s+\S.*$/, next: "start"}, + + {token: "otherBlock", regex: /^(?:\*{2,}|_{2,})\s*$/, next: "start"}, + // .optional title + {token: "optionalTitle", regex: /^\.[^.\s].+$/, next: "start"} + ], + + "listStart": [ + {token: "keyword", regex: /^\s*(?:\d+\.|[a-zA-Z]\.|[ixvmIXVM]+\)|\*{1,5}|-|\.{1,5})\s/, next: "listText"}, + {token: "meta.tag", regex: /^.+(?::{2,4}|;;)(?: |$)/, next: "listText"}, + {token: "support.function.list.callout", regex: /^(?:<\d+>|\d+>|>) /, next: "text"}, + // continuation + {token: "keyword", regex: /^\+\s*$/, next: "start"} + ], + + "text": [ + {token: ["link", "variable.language"], regex: /((?:https?:\/\/|ftp:\/\/|file:\/\/|mailto:|callto:)[^\s\[]+)(\[.*?\])/}, + {token: "link", regex: /(?:https?:\/\/|ftp:\/\/|file:\/\/|mailto:|callto:)[^\s\[]+/}, + {token: "link", regex: /\b[\w\.\/\-]+@[\w\.\/\-]+\b/}, + {include: "macros"}, + {include: "paragraphEnd"}, + {token: "literal", regex:/\+{3,}/, next:"smallPassthrough"}, + {token: "escape", regex: /\((?:C|TM|R)\)|\.{3}|->|<-|=>|<=|&#(?:\d+|x[a-fA-F\d]+);|(?: |^)--(?=\s+\S)/}, + {token: "escape", regex: /\\[_*'`+#]|\\{2}[_*'`+#]{2}/}, + {token: "keyword", regex: /\s\+$/}, + // any word + {token: "text", regex: identifierRe}, + {token: ["keyword", "string", "keyword"], + regex: /(<<[\w\d\-$]+,)(.*?)(>>|$)/}, + {token: "keyword", regex: /<<[\w\d\-$]+,?|>>/}, + {token: "constant.character", regex: /\({2,3}.*?\){2,3}/}, + // Anchor + {token: "keyword", regex: /\[\[.+?\]\]/}, + // bibliography + {token: "support", regex: /^\[{3}[\w\d =\-]+\]{3}/}, + + {include: "quotes"}, + // text block end + {token: "empty", regex: /^\s*$/, next: "start"} + ], + + "listText": [ + {include: "listStart"}, + {include: "text"} + ], + + "indentedBlock": [ + {token: "literal", regex: /^[\s\w].+$/, next: "indentedBlock"}, + {token: "literal", regex: "", next: "start"} + ], + + "listingBlock": [ + {token: "literal", regex: /^\.{4,}\s*$/, next: "dissallowDelimitedBlock"}, + {token: "constant.numeric", regex: '<\\d+>'}, + {token: "literal", regex: '[^<]+'}, + {token: "literal", regex: '<'} + ], + "literalBlock": [ + {token: "literal", regex: /^-{4,}\s*$/, next: "dissallowDelimitedBlock"}, + {token: "constant.numeric", regex: '<\\d+>'}, + {token: "literal", regex: '[^<]+'}, + {token: "literal", regex: '<'} + ], + "passthroughBlock": [ + {token: "literal", regex: /^\+{4,}\s*$/, next: "dissallowDelimitedBlock"}, + {token: "literal", regex: identifierRe + "|\\d+"}, + {include: "macros"}, + {token: "literal", regex: "."} + ], + + "smallPassthrough": [ + {token: "literal", regex: /[+]{3,}/, next: "dissallowDelimitedBlock"}, + {token: "literal", regex: /^\s*$/, next: "dissallowDelimitedBlock"}, + {token: "literal", regex: identifierRe + "|\\d+"}, + {include: "macros"} + ], + + "commentBlock": [ + {token: "doc.comment", regex: /^\/{4,}\s*$/, next: "dissallowDelimitedBlock"}, + {token: "doc.comment", regex: '^.*$'} + ], + "tableBlock": [ + {token: "tableBlock", regex: /^\s*\|={3,}\s*$/, next: "dissallowDelimitedBlock"}, + {token: "tableBlock", regex: /^\s*!={3,}\s*$/, next: "innerTableBlock"}, + {token: "tableBlock", regex: /\|/}, + {include: "text", noEscape: true} + ], + "innerTableBlock": [ + {token: "tableBlock", regex: /^\s*!={3,}\s*$/, next: "tableBlock"}, + {token: "tableBlock", regex: /^\s*|={3,}\s*$/, next: "dissallowDelimitedBlock"}, + {token: "tableBlock", regex: /\!/} + ], + "macros": [ + {token: "macro", regex: /{[\w\-$]+}/}, + {token: ["text", "string", "text", "constant.character", "text"], regex: /({)([\w\-$]+)(:)?(.+)?(})/}, + {token: ["text", "markup.list.macro", "keyword", "string"], regex: /(\w+)(footnote(?:ref)?::?)([^\s\[]+)?(\[.*?\])?/}, + {token: ["markup.list.macro", "keyword", "string"], regex: /([a-zA-Z\-][\w\.\/\-]*::?)([^\s\[]+)(\[.*?\])?/}, + {token: ["markup.list.macro", "keyword"], regex: /([a-zA-Z\-][\w\.\/\-]+::?)(\[.*?\])/}, + {token: "keyword", regex: /^:.+?:(?= |$)/} + ], + + "quotes": [ + {token: "string.italic", regex: /__[^_\s].*?__/}, + {token: "string.italic", regex: quoteRule("_")}, + + {token: "keyword.bold", regex: /\*\*[^*\s].*?\*\*/}, + {token: "keyword.bold", regex: quoteRule("\\*")}, + + {token: "literal", regex: quoteRule("\\+")}, + {token: "literal", regex: /\+\+[^+\s].*?\+\+/}, + {token: "literal", regex: /\$\$.+?\$\$/}, + {token: "literal", regex: quoteRule("`")}, + + {token: "keyword", regex: quoteRule("^")}, + {token: "keyword", regex: quoteRule("~")}, + {token: "keyword", regex: /##?/}, + {token: "keyword", regex: /(?:\B|^)``|\b''/} + ] + + }; + + function quoteRule(ch) { + var prefix = /\w/.test(ch) ? "\\b" : "(?:\\B|^)"; + return prefix + ch + "[^" + ch + "].*?" + ch + "(?![\\w*])"; + } + + //addQuoteBlock("text") + + var tokenMap = { + macro: "constant.character", + tableBlock: "doc.comment", + titleUnderline: "markup.heading", + singleLineTitle: "markup.heading", + pageBreak: "string", + option: "string.regexp", + otherBlock: "markup.list", + literal: "support.function", + optionalTitle: "constant.numeric", + escape: "constant.language.escape", + link: "markup.underline.list" + }; + + for (var state in this.$rules) { + var stateRules = this.$rules[state]; + for (var i = stateRules.length; i--; ) { + var rule = stateRules[i]; + if (rule.include || typeof rule == "string") { + var args = [i, 1].concat(this.$rules[rule.include || rule]); + if (rule.noEscape) { + args = args.filter(function(x) { + return !x.next; + }); + } + stateRules.splice.apply(stateRules, args); + } else if (rule.token in tokenMap) { + rule.token = tokenMap[rule.token]; + } + } + } +}; +oop.inherits(AsciidocHighlightRules, TextHighlightRules); + +exports.AsciidocHighlightRules = AsciidocHighlightRules; +}); diff --git a/node_modules/ace/lib/ace/mode/assembly_x86.js b/node_modules/ace/lib/ace/mode/assembly_x86.js new file mode 100644 index 00000000..d6343e80 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/assembly_x86.js @@ -0,0 +1,56 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * + * ***** END LICENSE BLOCK ***** */ + +/* + THIS FILE WAS AUTOGENERATED BY mode.tmpl.js +*/ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextMode = require("./text").Mode; +var AssemblyX86HighlightRules = require("./assembly_x86_highlight_rules").AssemblyX86HighlightRules; +var FoldMode = require("./folding/coffee").FoldMode; + +var Mode = function() { + this.HighlightRules = AssemblyX86HighlightRules; + this.foldingRules = new FoldMode(); +}; +oop.inherits(Mode, TextMode); + +(function() { + this.lineCommentStart = ";"; + this.$id = "ace/mode/assembly_x86"; +}).call(Mode.prototype); + +exports.Mode = Mode; +}); \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/assembly_x86_highlight_rules.js b/node_modules/ace/lib/ace/mode/assembly_x86_highlight_rules.js new file mode 100644 index 00000000..247d1d0c --- /dev/null +++ b/node_modules/ace/lib/ace/mode/assembly_x86_highlight_rules.js @@ -0,0 +1,114 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +/* This file was autogenerated from Assembly x86.tmLanguage (uuid: ) */ +/**************************************************************************************** + * IT MIGHT NOT BE PERFECT ...But it's a good start from an existing *.tmlanguage file. * + * fileTypes * + ****************************************************************************************/ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + +var AssemblyX86HighlightRules = function() { + // regexp must not have capturing parentheses. Use (?:) instead. + // regexps are ordered -> the first match is used + + this.$rules = { start: + [ { token: 'keyword.control.assembly', + regex: '\\b(?:aaa|aad|aam|aas|adc|add|addpd|addps|addsd|addss|addsubpd|addsubps|aesdec|aesdeclast|aesenc|aesenclast|aesimc|aeskeygenassist|and|andpd|andps|andnpd|andnps|arpl|blendpd|blendps|blendvpd|blendvps|bound|bsf|bsr|bswap|bt|btc|btr|bts|cbw|cwde|cdqe|clc|cld|cflush|clts|cmc|cmov(?:n?e|ge?|ae?|le?|be?|n?o|n?z)|cmp|cmppd|cmpps|cmps|cnpsb|cmpsw|cmpsd|cmpsq|cmpss|cmpxchg|cmpxchg8b|cmpxchg16b|comisd|comiss|cpuid|crc32|cvtdq2pd|cvtdq2ps|cvtpd2dq|cvtpd2pi|cvtpd2ps|cvtpi2pd|cvtpi2ps|cvtps2dq|cvtps2pd|cvtps2pi|cvtsd2si|cvtsd2ss|cvts2sd|cvtsi2ss|cvtss2sd|cvtss2si|cvttpd2dq|cvtpd2pi|cvttps2dq|cvttps2pi|cvttps2dq|cvttps2pi|cvttsd2si|cvttss2si|cwd|cdq|cqo|daa|das|dec|div|divpd|divps|divsd|divss|dppd|dpps|emms|enter|extractps|f2xm1|fabs|fadd|faddp|fiadd|fbld|fbstp|fchs|fclex|fnclex|fcmov(?:n?e|ge?|ae?|le?|be?|n?o|n?z)|fcom|fcmop|fcompp|fcomi|fcomip|fucomi|fucomip|fcos|fdecstp|fdiv|fdivp|fidiv|fdivr|fdivrp|fidivr|ffree|ficom|ficomp|fild|fincstp|finit|fnint|fist|fistp|fisttp|fld|fld1|fldl2t|fldl2e|fldpi|fldlg2|fldln2|fldz|fldcw|fldenv|fmul|fmulp|fimul|fnop|fpatan|fprem|fprem1|fptan|frndint|frstor|fsave|fnsave|fscale|fsin|fsincos|fsqrt|fst|fstp|fstcw|fnstcw|fstenv|fnstenv|fsts|fnstsw|fsub|fsubp|fisub|fsubr|fsubrp|fisubr|ftst|fucom|fucomp|fucompp|fxam|fxch|fxrstor|fxsave|fxtract|fyl2x|fyl2xp1|haddpd|haddps|husbpd|hsubps|idiv|imul|in|inc|ins|insb|insw|insd|insertps|int|into|invd|invplg|invpcid|iret|iretd|iretq|lahf|lar|lddqu|ldmxcsr|lds|les|lfs|lgs|lss|lea|leave|lfence|lgdt|lidt|llgdt|lmsw|lock|lods|lodsb|lodsw|lodsd|lodsq|lsl|ltr|maskmovdqu|maskmovq|maxpd|maxps|maxsd|maxss|mfence|minpd|minps|minsd|minss|monitor|mov|movapd|movaps|movbe|movd|movq|movddup|movdqa|movdqu|movq2q|movhlps|movhpd|movhps|movlhps|movlpd|movlps|movmskpd|movmskps|movntdqa|movntdq|movnti|movntpd|movntps|movntq|movq|movq2dq|movs|movsb|movsw|movsd|movsq|movsd|movshdup|movsldup|movss|movsx|movsxd|movupd|movups|movzx|mpsadbw|mul|mulpd|mulps|mulsd|mulss|mwait|neg|not|or|orpd|orps|out|outs|outsb|outsw|outsd|pabsb|pabsw|pabsd|packsswb|packssdw|packusdw|packuswbpaddb|paddw|paddd|paddq|paddsb|paddsw|paddusb|paddusw|palignr|pand|pandn|pause|pavgb|pavgw|pblendvb|pblendw|pclmulqdq|pcmpeqb|pcmpeqw|pcmpeqd|pcmpeqq|pcmpestri|pcmpestrm|pcmptb|pcmptgw|pcmpgtd|pcmpgtq|pcmpistri|pcmpisrm|pextrb|pextrd|pextrq|pextrw|phaddw|phaddd|phaddsw|phinposuw|phsubw|phsubd|phsubsw|pinsrb|pinsrd|pinsrq|pinsrw|pmaddubsw|pmadddwd|pmaxsb|pmaxsd|pmaxsw|pmaxsw|pmaxub|pmaxud|pmaxuw|pminsb|pminsd|pminsw|pminub|pminud|pminuw|pmovmskb|pmovsx|pmovzx|pmuldq|pmulhrsw|pmulhuw|pmulhw|pmulld|pmullw|pmuludw|pop|popa|popad|popcnt|popf|popfd|popfq|por|prefetch|psadbw|pshufb|pshufd|pshufhw|pshuflw|pshufw|psignb|psignw|psignd|pslldq|psllw|pslld|psllq|psraw|psrad|psrldq|psrlw|psrld|psrlq|psubb|psubw|psubd|psubq|psubsb|psubsw|psubusb|psubusw|test|ptest|punpckhbw|punpckhwd|punpckhdq|punpckhddq|punpcklbw|punpcklwd|punpckldq|punpckldqd|push|pusha|pushad|pushf|pushfd|pxor|prcl|rcr|rol|ror|rcpps|rcpss|rdfsbase|rdgsbase|rdmsr|rdpmc|rdrand|rdtsc|rdtscp|rep|repe|repz|repne|repnz|roundpd|roundps|roundsd|roundss|rsm|rsqrps|rsqrtss|sahf|sal|sar|shl|shr|sbb|scas|scasb|scasw|scasd|set(?:n?e|ge?|ae?|le?|be?|n?o|n?z)|sfence|sgdt|shld|shrd|shufpd|shufps|sidt|sldt|smsw|sqrtpd|sqrtps|sqrtsd|sqrtss|stc|std|stmxcsr|stos|stosb|stosw|stosd|stosq|str|sub|subpd|subps|subsd|subss|swapgs|syscall|sysenter|sysexit|sysret|teset|ucomisd|ucomiss|ud2|unpckhpd|unpckhps|unpcklpd|unpcklps|vbroadcast|vcvtph2ps|vcvtp2sph|verr|verw|vextractf128|vinsertf128|vmaskmov|vpermilpd|vpermilps|vperm2f128|vtestpd|vtestps|vzeroall|vzeroupper|wait|fwait|wbinvd|wrfsbase|wrgsbase|wrmsr|xadd|xchg|xgetbv|xlat|xlatb|xor|xorpd|xorps|xrstor|xsave|xsaveopt|xsetbv|lzcnt|extrq|insertq|movntsd|movntss|vfmaddpd|vfmaddps|vfmaddsd|vfmaddss|vfmaddsubbpd|vfmaddsubps|vfmsubaddpd|vfmsubaddps|vfmsubpd|vfmsubps|vfmsubsd|vfnmaddpd|vfnmaddps|vfnmaddsd|vfnmaddss|vfnmsubpd|vfnmusbps|vfnmusbsd|vfnmusbss|cvt|xor|cli|sti|hlt|nop|lock|wait|enter|leave|ret|loop(?:n?e|n?z)?|call|j(?:mp|n?e|ge?|ae?|le?|be?|n?o|n?z))\\b', + caseInsensitive: true }, + { token: 'variable.parameter.register.assembly', + regex: '\\b(?:CS|DS|ES|FS|GS|SS|RAX|EAX|RBX|EBX|RCX|ECX|RDX|EDX|RCX|RIP|EIP|IP|RSP|ESP|SP|RSI|ESI|SI|RDI|EDI|DI|RFLAGS|EFLAGS|FLAGS|R8-15|(?:Y|X)MM(?:[0-9]|10|11|12|13|14|15)|(?:A|B|C|D)(?:X|H|L)|CR(?:[0-4]|DR(?:[0-7]|TR6|TR7|EFER)))\\b', + caseInsensitive: true }, + { token: 'constant.character.decimal.assembly', + regex: '\\b[0-9]+\\b' }, + { token: 'constant.character.hexadecimal.assembly', + regex: '\\b0x[A-F0-9]+\\b', + caseInsensitive: true }, + { token: 'constant.character.hexadecimal.assembly', + regex: '\\b[A-F0-9]+h\\b', + caseInsensitive: true }, + { token: 'string.assembly', regex: /'([^\\']|\\.)*'/ }, + { token: 'string.assembly', regex: /"([^\\"]|\\.)*"/ }, + { token: 'support.function.directive.assembly', + regex: '^\\[', + push: + [ { token: 'support.function.directive.assembly', + regex: '\\]$', + next: 'pop' }, + { defaultToken: 'support.function.directive.assembly' } ] }, + { token: + [ 'support.function.directive.assembly', + 'support.function.directive.assembly', + 'entity.name.function.assembly' ], + regex: '(^struc)( )([_a-zA-Z][_a-zA-Z0-9]*)' }, + { token: 'support.function.directive.assembly', + regex: '^endstruc\\b' }, + { token: + [ 'support.function.directive.assembly', + 'entity.name.function.assembly', + 'support.function.directive.assembly', + 'constant.character.assembly' ], + regex: '^(%macro )([_a-zA-Z][_a-zA-Z0-9]*)( )([0-9]+)' }, + { token: 'support.function.directive.assembly', + regex: '^%endmacro' }, + { token: + [ 'text', + 'support.function.directive.assembly', + 'text', + 'entity.name.function.assembly' ], + regex: '(\\s*)(%define|%xdefine|%idefine|%undef|%assign|%defstr|%strcat|%strlen|%substr|%00|%0|%rotate|%rep|%endrep|%include|\\$\\$|\\$|%unmacro|%if|%elif|%else|%endif|%(?:el)?ifdef|%(?:el)?ifmacro|%(?:el)?ifctx|%(?:el)?ifidn|%(?:el)?ifidni|%(?:el)?ifid|%(?:el)?ifnum|%(?:el)?ifstr|%(?:el)?iftoken|%(?:el)?ifempty|%(?:el)?ifenv|%pathsearch|%depend|%use|%push|%pop|%repl|%arg|%stacksize|%local|%error|%warning|%fatal|%line|%!|%comment|%endcomment|__NASM_VERSION_ID__|__NASM_VER__|__FILE__|__LINE__|__BITS__|__OUTPUT_FORMAT__|__DATE__|__TIME__|__DATE_NUM__|_TIME__NUM__|__UTC_DATE__|__UTC_TIME__|__UTC_DATE_NUM__|__UTC_TIME_NUM__|__POSIX_TIME__|__PASS__|ISTRUC|AT|IEND|BITS 16|BITS 32|BITS 64|USE16|USE32|__SECT__|ABSOLUTE|EXTERN|GLOBAL|COMMON|CPU|FLOAT)\\b( ?)((?:[_a-zA-Z][_a-zA-Z0-9]*)?)', + caseInsensitive: true }, + { token: 'support.function.directive.assembly', + regex: '\\b(?:d[bwdqtoy]|res[bwdqto]|equ|times|align|alignb|sectalign|section|ptr|byte|word|dword|qword|incbin)\\b', + caseInsensitive: true }, + { token: 'entity.name.function.assembly', regex: '^\\s*%%[\\w.]+?:$' }, + { token: 'entity.name.function.assembly', regex: '^\\s*%\\$[\\w.]+?:$' }, + { token: 'entity.name.function.assembly', regex: '^[\\w.]+?:' }, + { token: 'entity.name.function.assembly', regex: '^[\\w.]+?\\b' }, + { token: 'comment.assembly', regex: ';.*$' } ] + } + + this.normalizeRules(); +}; + +AssemblyX86HighlightRules.metaData = { fileTypes: [ 'asm' ], + name: 'Assembly x86', + scopeName: 'source.assembly' } + + +oop.inherits(AssemblyX86HighlightRules, TextHighlightRules); + +exports.AssemblyX86HighlightRules = AssemblyX86HighlightRules; +}); \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/autohotkey.js b/node_modules/ace/lib/ace/mode/autohotkey.js new file mode 100644 index 00000000..d7093fd5 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/autohotkey.js @@ -0,0 +1,57 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +/* + THIS FILE WAS AUTOGENERATED BY mode.tmpl.js +*/ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextMode = require("./text").Mode; +var AutoHotKeyHighlightRules = require("./autohotkey_highlight_rules").AutoHotKeyHighlightRules; +// TODO: pick appropriate fold mode +var FoldMode = require("./folding/cstyle").FoldMode; + +var Mode = function() { + this.HighlightRules = AutoHotKeyHighlightRules; + this.foldingRules = new FoldMode(); +}; +oop.inherits(Mode, TextMode); + +(function() { + this.lineCommentStart = ";"; + this.blockComment = {start: "/*", end: "*/"}; + this.$id = "ace/mode/autohotkey"; +}).call(Mode.prototype); + +exports.Mode = Mode; +}); \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/autohotkey_highlight_rules.js b/node_modules/ace/lib/ace/mode/autohotkey_highlight_rules.js new file mode 100644 index 00000000..45193996 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/autohotkey_highlight_rules.js @@ -0,0 +1,107 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +/* This file was autogenerated from C:\Users\LED\Desktop\AutoHotKey.tmLanguage (uuid: ) */ +/**************************************************************************************** + * IT MIGHT NOT BE PERFECT ...But it's a good start from an existing *.tmlanguage file. * + * fileTypes * + ****************************************************************************************/ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + +var AutoHotKeyHighlightRules = function() { + var autoItKeywords = 'And|ByRef|Case|Const|ContinueCase|ContinueLoop|Default|Dim|Do|Else|ElseIf|EndFunc|EndIf|EndSelect|EndSwitch|EndWith|Enum|Exit|ExitLoop|False|For|Func|Global|If|In|Local|Next|Not|Or|ReDim|Return|Select|Step|Switch|Then|To|True|Until|WEnd|While|With|' + + 'Abs|ACos|AdlibDisable|AdlibEnable|Asc|AscW|ASin|Assign|ATan|AutoItSetOption|AutoItWinGetTitle|AutoItWinSetTitle|Beep|Binary|BinaryLen|BinaryMid|BinaryToString|BitAND|BitNOT|BitOR|BitRotate|BitShift|BitXOR|BlockInput|Break|Call|CDTray|Ceiling|Chr|ChrW|ClipGet|ClipPut|ConsoleRead|ConsoleWrite|ConsoleWriteError|ControlClick|ControlCommand|ControlDisable|ControlEnable|ControlFocus|ControlGetFocus|ControlGetHandle|ControlGetPos|ControlGetText|ControlHide|ControlListView|ControlMove|ControlSend|ControlSetText|ControlShow|ControlTreeView|Cos|Dec|DirCopy|DirCreate|DirGetSize|DirMove|DirRemove|DllCall|DllCallbackFree|DllCallbackGetPtr|DllCallbackRegister|DllClose|DllOpen|DllStructCreate|DllStructGetData|DllStructGetPtr|DllStructGetSize|DllStructSetData|DriveGetDrive|DriveGetFileSystem|DriveGetLabel|DriveGetSerial|DriveGetType|DriveMapAdd|DriveMapDel|DriveMapGet|DriveSetLabel|DriveSpaceFree|DriveSpaceTotal|DriveStatus|EnvGet|EnvSet|EnvUpdate|Eval|Execute|Exp|FileChangeDir|FileClose|FileCopy|FileCreateNTFSLink|FileCreateShortcut|FileDelete|FileExists|FileFindFirstFile|FileFindNextFile|FileGetAttrib|FileGetLongName|FileGetShortcut|FileGetShortName|FileGetSize|FileGetTime|FileGetVersion|FileInstall|FileMove|FileOpen|FileOpenDialog|FileRead|FileReadLine|FileRecycle|FileRecycleEmpty|FileSaveDialog|FileSelectFolder|FileSetAttrib|FileSetTime|FileWrite|FileWriteLine|Floor|FtpSetProxy|GUICreate|GUICtrlCreateAvi|GUICtrlCreateButton|GUICtrlCreateCheckbox|GUICtrlCreateCombo|GUICtrlCreateContextMenu|GUICtrlCreateDate|GUICtrlCreateDummy|GUICtrlCreateEdit|GUICtrlCreateGraphic|GUICtrlCreateGroup|GUICtrlCreateIcon|GUICtrlCreateInput|GUICtrlCreateLabel|GUICtrlCreateList|GUICtrlCreateListView|GUICtrlCreateListViewItem|GUICtrlCreateMenu|GUICtrlCreateMenuItem|GUICtrlCreateMonthCal|GUICtrlCreateObj|GUICtrlCreatePic|GUICtrlCreateProgress|GUICtrlCreateRadio|GUICtrlCreateSlider|GUICtrlCreateTab|GUICtrlCreateTabItem|GUICtrlCreateTreeView|GUICtrlCreateTreeViewItem|GUICtrlCreateUpdown|GUICtrlDelete|GUICtrlGetHandle|GUICtrlGetState|GUICtrlRead|GUICtrlRecvMsg|GUICtrlRegisterListViewSort|GUICtrlSendMsg|GUICtrlSendToDummy|GUICtrlSetBkColor|GUICtrlSetColor|GUICtrlSetCursor|GUICtrlSetData|GUICtrlSetFont|GUICtrlSetDefColor|GUICtrlSetDefBkColor|GUICtrlSetGraphic|GUICtrlSetImage|GUICtrlSetLimit|GUICtrlSetOnEvent|GUICtrlSetPos|GUICtrlSetResizing|GUICtrlSetState|GUICtrlSetStyle|GUICtrlSetTip|GUIDelete|GUIGetCursorInfo|GUIGetMsg|GUIGetStyle|GUIRegisterMsg|GUISetAccelerators()|GUISetBkColor|GUISetCoord|GUISetCursor|GUISetFont|GUISetHelp|GUISetIcon|GUISetOnEvent|GUISetState|GUISetStyle|GUIStartGroup|GUISwitch|Hex|HotKeySet|HttpSetProxy|HWnd|InetGet|InetGetSize|IniDelete|IniRead|IniReadSection|IniReadSectionNames|IniRenameSection|IniWrite|IniWriteSection|InputBox|Int|IsAdmin|IsArray|IsBinary|IsBool|IsDeclared|IsDllStruct|IsFloat|IsHWnd|IsInt|IsKeyword|IsNumber|IsObj|IsPtr|IsString|Log|MemGetStats|Mod|MouseClick|MouseClickDrag|MouseDown|MouseGetCursor|MouseGetPos|MouseMove|MouseUp|MouseWheel|MsgBox|Number|ObjCreate|ObjEvent|ObjGet|ObjName|Opt|Ping|PixelChecksum|PixelGetColor|PixelSearch|PluginClose|PluginOpen|ProcessClose|ProcessExists|ProcessGetStats|ProcessList|ProcessSetPriority|ProcessWait|ProcessWaitClose|ProgressOff|ProgressOn|ProgressSet|Ptr|Random|RegDelete|RegEnumKey|RegEnumVal|RegRead|RegWrite|Round|Run|RunAs|RunAsWait|RunWait|Send|SendKeepActive|SetError|SetExtended|ShellExecute|ShellExecuteWait|Shutdown|Sin|Sleep|SoundPlay|SoundSetWaveVolume|SplashImageOn|SplashOff|SplashTextOn|Sqrt|SRandom|StatusbarGetText|StderrRead|StdinWrite|StdioClose|StdoutRead|String|StringAddCR|StringCompare|StringFormat|StringInStr|StringIsAlNum|StringIsAlpha|StringIsASCII|StringIsDigit|StringIsFloat|StringIsInt|StringIsLower|StringIsSpace|StringIsUpper|StringIsXDigit|StringLeft|StringLen|StringLower|StringMid|StringRegExp|StringRegExpReplace|StringReplace|StringRight|StringSplit|StringStripCR|StringStripWS|StringToBinary|StringTrimLeft|StringTrimRight|StringUpper|Tan|TCPAccept|TCPCloseSocket|TCPConnect|TCPListen|TCPNameToIP|TCPRecv|TCPSend|TCPShutdown|TCPStartup|TimerDiff|TimerInit|ToolTip|TrayCreateItem|TrayCreateMenu|TrayGetMsg|TrayItemDelete|TrayItemGetHandle|TrayItemGetState|TrayItemGetText|TrayItemSetOnEvent|TrayItemSetState|TrayItemSetText|TraySetClick|TraySetIcon|TraySetOnEvent|TraySetPauseIcon|TraySetState|TraySetToolTip|TrayTip|UBound|UDPBind|UDPCloseSocket|UDPOpen|UDPRecv|UDPSend|UDPShutdown|UDPStartup|VarGetType|WinActivate|WinActive|WinClose|WinExists|WinFlash|WinGetCaretPos|WinGetClassList|WinGetClientSize|WinGetHandle|WinGetPos|WinGetProcess|WinGetState|WinGetText|WinGetTitle|WinKill|WinList|WinMenuSelectItem|WinMinimizeAll|WinMinimizeAllUndo|WinMove|WinSetOnTop|WinSetState|WinSetTitle|WinSetTrans|WinWait|WinWaitActive|WinWaitClose|WinWaitNotActive|' + + 'ArrayAdd|ArrayBinarySearch|ArrayConcatenate|ArrayDelete|ArrayDisplay|ArrayFindAll|ArrayInsert|ArrayMax|ArrayMaxIndex|ArrayMin|ArrayMinIndex|ArrayPop|ArrayPush|ArrayReverse|ArraySearch|ArraySort|ArraySwap|ArrayToClip|ArrayToString|ArrayTrim|ChooseColor|ChooseFont|ClipBoard_ChangeChain|ClipBoard_Close|ClipBoard_CountFormats|ClipBoard_Empty|ClipBoard_EnumFormats|ClipBoard_FormatStr|ClipBoard_GetData|ClipBoard_GetDataEx|ClipBoard_GetFormatName|ClipBoard_GetOpenWindow|ClipBoard_GetOwner|ClipBoard_GetPriorityFormat|ClipBoard_GetSequenceNumber|ClipBoard_GetViewer|ClipBoard_IsFormatAvailable|ClipBoard_Open|ClipBoard_RegisterFormat|ClipBoard_SetData|ClipBoard_SetDataEx|ClipBoard_SetViewer|ClipPutFile|ColorConvertHSLtoRGB|ColorConvertRGBtoHSL|ColorGetBlue|ColorGetGreen|ColorGetRed|Date_Time_CompareFileTime|Date_Time_DOSDateTimeToArray|Date_Time_DOSDateTimeToFileTime|Date_Time_DOSDateTimeToStr|Date_Time_DOSDateToArray|Date_Time_DOSDateToStr|Date_Time_DOSTimeToArray|Date_Time_DOSTimeToStr|Date_Time_EncodeFileTime|Date_Time_EncodeSystemTime|Date_Time_FileTimeToArray|Date_Time_FileTimeToDOSDateTime|Date_Time_FileTimeToLocalFileTime|Date_Time_FileTimeToStr|Date_Time_FileTimeToSystemTime|Date_Time_GetFileTime|Date_Time_GetLocalTime|Date_Time_GetSystemTime|Date_Time_GetSystemTimeAdjustment|Date_Time_GetSystemTimeAsFileTime|Date_Time_GetSystemTimes|Date_Time_GetTickCount|Date_Time_GetTimeZoneInformation|Date_Time_LocalFileTimeToFileTime|Date_Time_SetFileTime|Date_Time_SetLocalTime|Date_Time_SetSystemTime|Date_Time_SetSystemTimeAdjustment|Date_Time_SetTimeZoneInformation|Date_Time_SystemTimeToArray|Date_Time_SystemTimeToDateStr|Date_Time_SystemTimeToDateTimeStr|Date_Time_SystemTimeToFileTime|Date_Time_SystemTimeToTimeStr|Date_Time_SystemTimeToTzSpecificLocalTime|Date_Time_TzSpecificLocalTimeToSystemTime|DateAdd|DateDayOfWeek|DateDaysInMonth|DateDiff|DateIsLeapYear|DateIsValid|DateTimeFormat|DateTimeSplit|DateToDayOfWeek|DateToDayOfWeekISO|DateToDayValue|DateToMonth|DayValueToDate|DebugBugReportEnv|DebugOut|DebugSetup|Degree|EventLog__Backup|EventLog__Clear|EventLog__Close|EventLog__Count|EventLog__DeregisterSource|EventLog__Full|EventLog__Notify|EventLog__Oldest|EventLog__Open|EventLog__OpenBackup|EventLog__Read|EventLog__RegisterSource|EventLog__Report|FileCountLines|FileCreate|FileListToArray|FilePrint|FileReadToArray|FileWriteFromArray|FileWriteLog|FileWriteToLine|GDIPlus_ArrowCapCreate|GDIPlus_ArrowCapDispose|GDIPlus_ArrowCapGetFillState|GDIPlus_ArrowCapGetHeight|GDIPlus_ArrowCapGetMiddleInset|GDIPlus_ArrowCapGetWidth|GDIPlus_ArrowCapSetFillState|GDIPlus_ArrowCapSetHeight|GDIPlus_ArrowCapSetMiddleInset|GDIPlus_ArrowCapSetWidth|GDIPlus_BitmapCloneArea|GDIPlus_BitmapCreateFromFile|GDIPlus_BitmapCreateFromGraphics|GDIPlus_BitmapCreateFromHBITMAP|GDIPlus_BitmapCreateHBITMAPFromBitmap|GDIPlus_BitmapDispose|GDIPlus_BitmapLockBits|GDIPlus_BitmapUnlockBits|GDIPlus_BrushClone|GDIPlus_BrushCreateSolid|GDIPlus_BrushDispose|GDIPlus_BrushGetType|GDIPlus_CustomLineCapDispose|GDIPlus_Decoders|GDIPlus_DecodersGetCount|GDIPlus_DecodersGetSize|GDIPlus_Encoders|GDIPlus_EncodersGetCLSID|GDIPlus_EncodersGetCount|GDIPlus_EncodersGetParamList|GDIPlus_EncodersGetParamListSize|GDIPlus_EncodersGetSize|GDIPlus_FontCreate|GDIPlus_FontDispose|GDIPlus_FontFamilyCreate|GDIPlus_FontFamilyDispose|GDIPlus_GraphicsClear|GDIPlus_GraphicsCreateFromHDC|GDIPlus_GraphicsCreateFromHWND|GDIPlus_GraphicsDispose|GDIPlus_GraphicsDrawArc|GDIPlus_GraphicsDrawBezier|GDIPlus_GraphicsDrawClosedCurve|GDIPlus_GraphicsDrawCurve|GDIPlus_GraphicsDrawEllipse|GDIPlus_GraphicsDrawImage|GDIPlus_GraphicsDrawImageRect|GDIPlus_GraphicsDrawImageRectRect|GDIPlus_GraphicsDrawLine|GDIPlus_GraphicsDrawPie|GDIPlus_GraphicsDrawPolygon|GDIPlus_GraphicsDrawRect|GDIPlus_GraphicsDrawString|GDIPlus_GraphicsDrawStringEx|GDIPlus_GraphicsFillClosedCurve|GDIPlus_GraphicsFillEllipse|GDIPlus_GraphicsFillPie|GDIPlus_GraphicsFillRect|GDIPlus_GraphicsGetDC|GDIPlus_GraphicsGetSmoothingMode|GDIPlus_GraphicsMeasureString|GDIPlus_GraphicsReleaseDC|GDIPlus_GraphicsSetSmoothingMode|GDIPlus_GraphicsSetTransform|GDIPlus_ImageDispose|GDIPlus_ImageGetGraphicsContext|GDIPlus_ImageGetHeight|GDIPlus_ImageGetWidth|GDIPlus_ImageLoadFromFile|GDIPlus_ImageSaveToFile|GDIPlus_ImageSaveToFileEx|GDIPlus_MatrixCreate|GDIPlus_MatrixDispose|GDIPlus_MatrixRotate|GDIPlus_ParamAdd|GDIPlus_ParamInit|GDIPlus_PenCreate|GDIPlus_PenDispose|GDIPlus_PenGetAlignment|GDIPlus_PenGetColor|GDIPlus_PenGetCustomEndCap|GDIPlus_PenGetDashCap|GDIPlus_PenGetDashStyle|GDIPlus_PenGetEndCap|GDIPlus_PenGetWidth|GDIPlus_PenSetAlignment|GDIPlus_PenSetColor|GDIPlus_PenSetCustomEndCap|GDIPlus_PenSetDashCap|GDIPlus_PenSetDashStyle|GDIPlus_PenSetEndCap|GDIPlus_PenSetWidth|GDIPlus_RectFCreate|GDIPlus_Shutdown|GDIPlus_Startup|GDIPlus_StringFormatCreate|GDIPlus_StringFormatDispose|GetIP|GUICtrlAVI_Close|GUICtrlAVI_Create|GUICtrlAVI_Destroy|GUICtrlAVI_Open|GUICtrlAVI_OpenEx|GUICtrlAVI_Play|GUICtrlAVI_Seek|GUICtrlAVI_Show|GUICtrlAVI_Stop|GUICtrlButton_Click|GUICtrlButton_Create|GUICtrlButton_Destroy|GUICtrlButton_Enable|GUICtrlButton_GetCheck|GUICtrlButton_GetFocus|GUICtrlButton_GetIdealSize|GUICtrlButton_GetImage|GUICtrlButton_GetImageList|GUICtrlButton_GetState|GUICtrlButton_GetText|GUICtrlButton_GetTextMargin|GUICtrlButton_SetCheck|GUICtrlButton_SetFocus|GUICtrlButton_SetImage|GUICtrlButton_SetImageList|GUICtrlButton_SetSize|GUICtrlButton_SetState|GUICtrlButton_SetStyle|GUICtrlButton_SetText|GUICtrlButton_SetTextMargin|GUICtrlButton_Show|GUICtrlComboBox_AddDir|GUICtrlComboBox_AddString|GUICtrlComboBox_AutoComplete|GUICtrlComboBox_BeginUpdate|GUICtrlComboBox_Create|GUICtrlComboBox_DeleteString|GUICtrlComboBox_Destroy|GUICtrlComboBox_EndUpdate|GUICtrlComboBox_FindString|GUICtrlComboBox_FindStringExact|GUICtrlComboBox_GetComboBoxInfo|GUICtrlComboBox_GetCount|GUICtrlComboBox_GetCurSel|GUICtrlComboBox_GetDroppedControlRect|GUICtrlComboBox_GetDroppedControlRectEx|GUICtrlComboBox_GetDroppedState|GUICtrlComboBox_GetDroppedWidth|GUICtrlComboBox_GetEditSel|GUICtrlComboBox_GetEditText|GUICtrlComboBox_GetExtendedUI|GUICtrlComboBox_GetHorizontalExtent|GUICtrlComboBox_GetItemHeight|GUICtrlComboBox_GetLBText|GUICtrlComboBox_GetLBTextLen|GUICtrlComboBox_GetList|GUICtrlComboBox_GetListArray|GUICtrlComboBox_GetLocale|GUICtrlComboBox_GetLocaleCountry|GUICtrlComboBox_GetLocaleLang|GUICtrlComboBox_GetLocalePrimLang|GUICtrlComboBox_GetLocaleSubLang|GUICtrlComboBox_GetMinVisible|GUICtrlComboBox_GetTopIndex|GUICtrlComboBox_InitStorage|GUICtrlComboBox_InsertString|GUICtrlComboBox_LimitText|GUICtrlComboBox_ReplaceEditSel|GUICtrlComboBox_ResetContent|GUICtrlComboBox_SelectString|GUICtrlComboBox_SetCurSel|GUICtrlComboBox_SetDroppedWidth|GUICtrlComboBox_SetEditSel|GUICtrlComboBox_SetEditText|GUICtrlComboBox_SetExtendedUI|GUICtrlComboBox_SetHorizontalExtent|GUICtrlComboBox_SetItemHeight|GUICtrlComboBox_SetMinVisible|GUICtrlComboBox_SetTopIndex|GUICtrlComboBox_ShowDropDown|GUICtrlComboBoxEx_AddDir|GUICtrlComboBoxEx_AddString|GUICtrlComboBoxEx_BeginUpdate|GUICtrlComboBoxEx_Create|GUICtrlComboBoxEx_CreateSolidBitMap|GUICtrlComboBoxEx_DeleteString|GUICtrlComboBoxEx_Destroy|GUICtrlComboBoxEx_EndUpdate|GUICtrlComboBoxEx_FindStringExact|GUICtrlComboBoxEx_GetComboBoxInfo|GUICtrlComboBoxEx_GetComboControl|GUICtrlComboBoxEx_GetCount|GUICtrlComboBoxEx_GetCurSel|GUICtrlComboBoxEx_GetDroppedControlRect|GUICtrlComboBoxEx_GetDroppedControlRectEx|GUICtrlComboBoxEx_GetDroppedState|GUICtrlComboBoxEx_GetDroppedWidth|GUICtrlComboBoxEx_GetEditControl|GUICtrlComboBoxEx_GetEditSel|GUICtrlComboBoxEx_GetEditText|GUICtrlComboBoxEx_GetExtendedStyle|GUICtrlComboBoxEx_GetExtendedUI|GUICtrlComboBoxEx_GetImageList|GUICtrlComboBoxEx_GetItem|GUICtrlComboBoxEx_GetItemEx|GUICtrlComboBoxEx_GetItemHeight|GUICtrlComboBoxEx_GetItemImage|GUICtrlComboBoxEx_GetItemIndent|GUICtrlComboBoxEx_GetItemOverlayImage|GUICtrlComboBoxEx_GetItemParam|GUICtrlComboBoxEx_GetItemSelectedImage|GUICtrlComboBoxEx_GetItemText|GUICtrlComboBoxEx_GetItemTextLen|GUICtrlComboBoxEx_GetList|GUICtrlComboBoxEx_GetListArray|GUICtrlComboBoxEx_GetLocale|GUICtrlComboBoxEx_GetLocaleCountry|GUICtrlComboBoxEx_GetLocaleLang|GUICtrlComboBoxEx_GetLocalePrimLang|GUICtrlComboBoxEx_GetLocaleSubLang|GUICtrlComboBoxEx_GetMinVisible|GUICtrlComboBoxEx_GetTopIndex|GUICtrlComboBoxEx_InitStorage|GUICtrlComboBoxEx_InsertString|GUICtrlComboBoxEx_LimitText|GUICtrlComboBoxEx_ReplaceEditSel|GUICtrlComboBoxEx_ResetContent|GUICtrlComboBoxEx_SetCurSel|GUICtrlComboBoxEx_SetDroppedWidth|GUICtrlComboBoxEx_SetEditSel|GUICtrlComboBoxEx_SetEditText|GUICtrlComboBoxEx_SetExtendedStyle|GUICtrlComboBoxEx_SetExtendedUI|GUICtrlComboBoxEx_SetImageList|GUICtrlComboBoxEx_SetItem|GUICtrlComboBoxEx_SetItemEx|GUICtrlComboBoxEx_SetItemHeight|GUICtrlComboBoxEx_SetItemImage|GUICtrlComboBoxEx_SetItemIndent|GUICtrlComboBoxEx_SetItemOverlayImage|GUICtrlComboBoxEx_SetItemParam|GUICtrlComboBoxEx_SetItemSelectedImage|GUICtrlComboBoxEx_SetMinVisible|GUICtrlComboBoxEx_SetTopIndex|GUICtrlComboBoxEx_ShowDropDown|GUICtrlDTP_Create|GUICtrlDTP_Destroy|GUICtrlDTP_GetMCColor|GUICtrlDTP_GetMCFont|GUICtrlDTP_GetMonthCal|GUICtrlDTP_GetRange|GUICtrlDTP_GetRangeEx|GUICtrlDTP_GetSystemTime|GUICtrlDTP_GetSystemTimeEx|GUICtrlDTP_SetFormat|GUICtrlDTP_SetMCColor|GUICtrlDTP_SetMCFont|GUICtrlDTP_SetRange|GUICtrlDTP_SetRangeEx|GUICtrlDTP_SetSystemTime|GUICtrlDTP_SetSystemTimeEx|GUICtrlEdit_AppendText|GUICtrlEdit_BeginUpdate|GUICtrlEdit_CanUndo|GUICtrlEdit_CharFromPos|GUICtrlEdit_Create|GUICtrlEdit_Destroy|GUICtrlEdit_EmptyUndoBuffer|GUICtrlEdit_EndUpdate|GUICtrlEdit_Find|GUICtrlEdit_FmtLines|GUICtrlEdit_GetFirstVisibleLine|GUICtrlEdit_GetLimitText|GUICtrlEdit_GetLine|GUICtrlEdit_GetLineCount|GUICtrlEdit_GetMargins|GUICtrlEdit_GetModify|GUICtrlEdit_GetPasswordChar|GUICtrlEdit_GetRECT|GUICtrlEdit_GetRECTEx|GUICtrlEdit_GetSel|GUICtrlEdit_GetText|GUICtrlEdit_GetTextLen|GUICtrlEdit_HideBalloonTip|GUICtrlEdit_InsertText|GUICtrlEdit_LineFromChar|GUICtrlEdit_LineIndex|GUICtrlEdit_LineLength|GUICtrlEdit_LineScroll|GUICtrlEdit_PosFromChar|GUICtrlEdit_ReplaceSel|GUICtrlEdit_Scroll|GUICtrlEdit_SetLimitText|GUICtrlEdit_SetMargins|GUICtrlEdit_SetModify|GUICtrlEdit_SetPasswordChar|GUICtrlEdit_SetReadOnly|GUICtrlEdit_SetRECT|GUICtrlEdit_SetRECTEx|GUICtrlEdit_SetRECTNP|GUICtrlEdit_SetRectNPEx|GUICtrlEdit_SetSel|GUICtrlEdit_SetTabStops|GUICtrlEdit_SetText|GUICtrlEdit_ShowBalloonTip|GUICtrlEdit_Undo|GUICtrlHeader_AddItem|GUICtrlHeader_ClearFilter|GUICtrlHeader_ClearFilterAll|GUICtrlHeader_Create|GUICtrlHeader_CreateDragImage|GUICtrlHeader_DeleteItem|GUICtrlHeader_Destroy|GUICtrlHeader_EditFilter|GUICtrlHeader_GetBitmapMargin|GUICtrlHeader_GetImageList|GUICtrlHeader_GetItem|GUICtrlHeader_GetItemAlign|GUICtrlHeader_GetItemBitmap|GUICtrlHeader_GetItemCount|GUICtrlHeader_GetItemDisplay|GUICtrlHeader_GetItemFlags|GUICtrlHeader_GetItemFormat|GUICtrlHeader_GetItemImage|GUICtrlHeader_GetItemOrder|GUICtrlHeader_GetItemParam|GUICtrlHeader_GetItemRect|GUICtrlHeader_GetItemRectEx|GUICtrlHeader_GetItemText|GUICtrlHeader_GetItemWidth|GUICtrlHeader_GetOrderArray|GUICtrlHeader_GetUnicodeFormat|GUICtrlHeader_HitTest|GUICtrlHeader_InsertItem|GUICtrlHeader_Layout|GUICtrlHeader_OrderToIndex|GUICtrlHeader_SetBitmapMargin|GUICtrlHeader_SetFilterChangeTimeout|GUICtrlHeader_SetHotDivider|GUICtrlHeader_SetImageList|GUICtrlHeader_SetItem|GUICtrlHeader_SetItemAlign|GUICtrlHeader_SetItemBitmap|GUICtrlHeader_SetItemDisplay|GUICtrlHeader_SetItemFlags|GUICtrlHeader_SetItemFormat|GUICtrlHeader_SetItemImage|GUICtrlHeader_SetItemOrder|GUICtrlHeader_SetItemParam|GUICtrlHeader_SetItemText|GUICtrlHeader_SetItemWidth|GUICtrlHeader_SetOrderArray|GUICtrlHeader_SetUnicodeFormat|GUICtrlIpAddress_ClearAddress|GUICtrlIpAddress_Create|GUICtrlIpAddress_Destroy|GUICtrlIpAddress_Get|GUICtrlIpAddress_GetArray|GUICtrlIpAddress_GetEx|GUICtrlIpAddress_IsBlank|GUICtrlIpAddress_Set|GUICtrlIpAddress_SetArray|GUICtrlIpAddress_SetEx|GUICtrlIpAddress_SetFocus|GUICtrlIpAddress_SetFont|GUICtrlIpAddress_SetRange|GUICtrlIpAddress_ShowHide|GUICtrlListBox_AddFile|GUICtrlListBox_AddString|GUICtrlListBox_BeginUpdate|GUICtrlListBox_Create|GUICtrlListBox_DeleteString|GUICtrlListBox_Destroy|GUICtrlListBox_Dir|GUICtrlListBox_EndUpdate|GUICtrlListBox_FindInText|GUICtrlListBox_FindString|GUICtrlListBox_GetAnchorIndex|GUICtrlListBox_GetCaretIndex|GUICtrlListBox_GetCount|GUICtrlListBox_GetCurSel|GUICtrlListBox_GetHorizontalExtent|GUICtrlListBox_GetItemData|GUICtrlListBox_GetItemHeight|GUICtrlListBox_GetItemRect|GUICtrlListBox_GetItemRectEx|GUICtrlListBox_GetListBoxInfo|GUICtrlListBox_GetLocale|GUICtrlListBox_GetLocaleCountry|GUICtrlListBox_GetLocaleLang|GUICtrlListBox_GetLocalePrimLang|GUICtrlListBox_GetLocaleSubLang|GUICtrlListBox_GetSel|GUICtrlListBox_GetSelCount|GUICtrlListBox_GetSelItems|GUICtrlListBox_GetSelItemsText|GUICtrlListBox_GetText|GUICtrlListBox_GetTextLen|GUICtrlListBox_GetTopIndex|GUICtrlListBox_InitStorage|GUICtrlListBox_InsertString|GUICtrlListBox_ItemFromPoint|GUICtrlListBox_ReplaceString|GUICtrlListBox_ResetContent|GUICtrlListBox_SelectString|GUICtrlListBox_SelItemRange|GUICtrlListBox_SelItemRangeEx|GUICtrlListBox_SetAnchorIndex|GUICtrlListBox_SetCaretIndex|GUICtrlListBox_SetColumnWidth|GUICtrlListBox_SetCurSel|GUICtrlListBox_SetHorizontalExtent|GUICtrlListBox_SetItemData|GUICtrlListBox_SetItemHeight|GUICtrlListBox_SetLocale|GUICtrlListBox_SetSel|GUICtrlListBox_SetTabStops|GUICtrlListBox_SetTopIndex|GUICtrlListBox_Sort|GUICtrlListBox_SwapString|GUICtrlListBox_UpdateHScroll|GUICtrlListView_AddArray|GUICtrlListView_AddColumn|GUICtrlListView_AddItem|GUICtrlListView_AddSubItem|GUICtrlListView_ApproximateViewHeight|GUICtrlListView_ApproximateViewRect|GUICtrlListView_ApproximateViewWidth|GUICtrlListView_Arrange|GUICtrlListView_BeginUpdate|GUICtrlListView_CancelEditLabel|GUICtrlListView_ClickItem|GUICtrlListView_CopyItems|GUICtrlListView_Create|GUICtrlListView_CreateDragImage|GUICtrlListView_CreateSolidBitMap|GUICtrlListView_DeleteAllItems|GUICtrlListView_DeleteColumn|GUICtrlListView_DeleteItem|GUICtrlListView_DeleteItemsSelected|GUICtrlListView_Destroy|GUICtrlListView_DrawDragImage|GUICtrlListView_EditLabel|GUICtrlListView_EnableGroupView|GUICtrlListView_EndUpdate|GUICtrlListView_EnsureVisible|GUICtrlListView_FindInText|GUICtrlListView_FindItem|GUICtrlListView_FindNearest|GUICtrlListView_FindParam|GUICtrlListView_FindText|GUICtrlListView_GetBkColor|GUICtrlListView_GetBkImage|GUICtrlListView_GetCallbackMask|GUICtrlListView_GetColumn|GUICtrlListView_GetColumnCount|GUICtrlListView_GetColumnOrder|GUICtrlListView_GetColumnOrderArray|GUICtrlListView_GetColumnWidth|GUICtrlListView_GetCounterPage|GUICtrlListView_GetEditControl|GUICtrlListView_GetExtendedListViewStyle|GUICtrlListView_GetGroupInfo|GUICtrlListView_GetGroupViewEnabled|GUICtrlListView_GetHeader|GUICtrlListView_GetHotCursor|GUICtrlListView_GetHotItem|GUICtrlListView_GetHoverTime|GUICtrlListView_GetImageList|GUICtrlListView_GetISearchString|GUICtrlListView_GetItem|GUICtrlListView_GetItemChecked|GUICtrlListView_GetItemCount|GUICtrlListView_GetItemCut|GUICtrlListView_GetItemDropHilited|GUICtrlListView_GetItemEx|GUICtrlListView_GetItemFocused|GUICtrlListView_GetItemGroupID|GUICtrlListView_GetItemImage|GUICtrlListView_GetItemIndent|GUICtrlListView_GetItemParam|GUICtrlListView_GetItemPosition|GUICtrlListView_GetItemPositionX|GUICtrlListView_GetItemPositionY|GUICtrlListView_GetItemRect|GUICtrlListView_GetItemRectEx|GUICtrlListView_GetItemSelected|GUICtrlListView_GetItemSpacing|GUICtrlListView_GetItemSpacingX|GUICtrlListView_GetItemSpacingY|GUICtrlListView_GetItemState|GUICtrlListView_GetItemStateImage|GUICtrlListView_GetItemText|GUICtrlListView_GetItemTextArray|GUICtrlListView_GetItemTextString|GUICtrlListView_GetNextItem|GUICtrlListView_GetNumberOfWorkAreas|GUICtrlListView_GetOrigin|GUICtrlListView_GetOriginX|GUICtrlListView_GetOriginY|GUICtrlListView_GetOutlineColor|GUICtrlListView_GetSelectedColumn|GUICtrlListView_GetSelectedCount|GUICtrlListView_GetSelectedIndices|GUICtrlListView_GetSelectionMark|GUICtrlListView_GetStringWidth|GUICtrlListView_GetSubItemRect|GUICtrlListView_GetTextBkColor|GUICtrlListView_GetTextColor|GUICtrlListView_GetToolTips|GUICtrlListView_GetTopIndex|GUICtrlListView_GetUnicodeFormat|GUICtrlListView_GetView|GUICtrlListView_GetViewDetails|GUICtrlListView_GetViewLarge|GUICtrlListView_GetViewList|GUICtrlListView_GetViewRect|GUICtrlListView_GetViewSmall|GUICtrlListView_GetViewTile|GUICtrlListView_HideColumn|GUICtrlListView_HitTest|GUICtrlListView_InsertColumn|GUICtrlListView_InsertGroup|GUICtrlListView_InsertItem|GUICtrlListView_JustifyColumn|GUICtrlListView_MapIDToIndex|GUICtrlListView_MapIndexToID|GUICtrlListView_RedrawItems|GUICtrlListView_RegisterSortCallBack|GUICtrlListView_RemoveAllGroups|GUICtrlListView_RemoveGroup|GUICtrlListView_Scroll|GUICtrlListView_SetBkColor|GUICtrlListView_SetBkImage|GUICtrlListView_SetCallBackMask|GUICtrlListView_SetColumn|GUICtrlListView_SetColumnOrder|GUICtrlListView_SetColumnOrderArray|GUICtrlListView_SetColumnWidth|GUICtrlListView_SetExtendedListViewStyle|GUICtrlListView_SetGroupInfo|GUICtrlListView_SetHotItem|GUICtrlListView_SetHoverTime|GUICtrlListView_SetIconSpacing|GUICtrlListView_SetImageList|GUICtrlListView_SetItem|GUICtrlListView_SetItemChecked|GUICtrlListView_SetItemCount|GUICtrlListView_SetItemCut|GUICtrlListView_SetItemDropHilited|GUICtrlListView_SetItemEx|GUICtrlListView_SetItemFocused|GUICtrlListView_SetItemGroupID|GUICtrlListView_SetItemImage|GUICtrlListView_SetItemIndent|GUICtrlListView_SetItemParam|GUICtrlListView_SetItemPosition|GUICtrlListView_SetItemPosition32|GUICtrlListView_SetItemSelected|GUICtrlListView_SetItemState|GUICtrlListView_SetItemStateImage|GUICtrlListView_SetItemText|GUICtrlListView_SetOutlineColor|GUICtrlListView_SetSelectedColumn|GUICtrlListView_SetSelectionMark|GUICtrlListView_SetTextBkColor|GUICtrlListView_SetTextColor|GUICtrlListView_SetToolTips|GUICtrlListView_SetUnicodeFormat|GUICtrlListView_SetView|GUICtrlListView_SetWorkAreas|GUICtrlListView_SimpleSort|GUICtrlListView_SortItems|GUICtrlListView_SubItemHitTest|GUICtrlListView_UnRegisterSortCallBack|GUICtrlMenu_AddMenuItem|GUICtrlMenu_AppendMenu|GUICtrlMenu_CheckMenuItem|GUICtrlMenu_CheckRadioItem|GUICtrlMenu_CreateMenu|GUICtrlMenu_CreatePopup|GUICtrlMenu_DeleteMenu|GUICtrlMenu_DestroyMenu|GUICtrlMenu_DrawMenuBar|GUICtrlMenu_EnableMenuItem|GUICtrlMenu_FindItem|GUICtrlMenu_FindParent|GUICtrlMenu_GetItemBmp|GUICtrlMenu_GetItemBmpChecked|GUICtrlMenu_GetItemBmpUnchecked|GUICtrlMenu_GetItemChecked|GUICtrlMenu_GetItemCount|GUICtrlMenu_GetItemData|GUICtrlMenu_GetItemDefault|GUICtrlMenu_GetItemDisabled|GUICtrlMenu_GetItemEnabled|GUICtrlMenu_GetItemGrayed|GUICtrlMenu_GetItemHighlighted|GUICtrlMenu_GetItemID|GUICtrlMenu_GetItemInfo|GUICtrlMenu_GetItemRect|GUICtrlMenu_GetItemRectEx|GUICtrlMenu_GetItemState|GUICtrlMenu_GetItemStateEx|GUICtrlMenu_GetItemSubMenu|GUICtrlMenu_GetItemText|GUICtrlMenu_GetItemType|GUICtrlMenu_GetMenu|GUICtrlMenu_GetMenuBackground|GUICtrlMenu_GetMenuBarInfo|GUICtrlMenu_GetMenuContextHelpID|GUICtrlMenu_GetMenuData|GUICtrlMenu_GetMenuDefaultItem|GUICtrlMenu_GetMenuHeight|GUICtrlMenu_GetMenuInfo|GUICtrlMenu_GetMenuStyle|GUICtrlMenu_GetSystemMenu|GUICtrlMenu_InsertMenuItem|GUICtrlMenu_InsertMenuItemEx|GUICtrlMenu_IsMenu|GUICtrlMenu_LoadMenu|GUICtrlMenu_MapAccelerator|GUICtrlMenu_MenuItemFromPoint|GUICtrlMenu_RemoveMenu|GUICtrlMenu_SetItemBitmaps|GUICtrlMenu_SetItemBmp|GUICtrlMenu_SetItemBmpChecked|GUICtrlMenu_SetItemBmpUnchecked|GUICtrlMenu_SetItemChecked|GUICtrlMenu_SetItemData|GUICtrlMenu_SetItemDefault|GUICtrlMenu_SetItemDisabled|GUICtrlMenu_SetItemEnabled|GUICtrlMenu_SetItemGrayed|GUICtrlMenu_SetItemHighlighted|GUICtrlMenu_SetItemID|GUICtrlMenu_SetItemInfo|GUICtrlMenu_SetItemState|GUICtrlMenu_SetItemSubMenu|GUICtrlMenu_SetItemText|GUICtrlMenu_SetItemType|GUICtrlMenu_SetMenu|GUICtrlMenu_SetMenuBackground|GUICtrlMenu_SetMenuContextHelpID|GUICtrlMenu_SetMenuData|GUICtrlMenu_SetMenuDefaultItem|GUICtrlMenu_SetMenuHeight|GUICtrlMenu_SetMenuInfo|GUICtrlMenu_SetMenuStyle|GUICtrlMenu_TrackPopupMenu|GUICtrlMonthCal_Create|GUICtrlMonthCal_Destroy|GUICtrlMonthCal_GetColor|GUICtrlMonthCal_GetColorArray|GUICtrlMonthCal_GetCurSel|GUICtrlMonthCal_GetCurSelStr|GUICtrlMonthCal_GetFirstDOW|GUICtrlMonthCal_GetFirstDOWStr|GUICtrlMonthCal_GetMaxSelCount|GUICtrlMonthCal_GetMaxTodayWidth|GUICtrlMonthCal_GetMinReqHeight|GUICtrlMonthCal_GetMinReqRect|GUICtrlMonthCal_GetMinReqRectArray|GUICtrlMonthCal_GetMinReqWidth|GUICtrlMonthCal_GetMonthDelta|GUICtrlMonthCal_GetMonthRange|GUICtrlMonthCal_GetMonthRangeMax|GUICtrlMonthCal_GetMonthRangeMaxStr|GUICtrlMonthCal_GetMonthRangeMin|GUICtrlMonthCal_GetMonthRangeMinStr|GUICtrlMonthCal_GetMonthRangeSpan|GUICtrlMonthCal_GetRange|GUICtrlMonthCal_GetRangeMax|GUICtrlMonthCal_GetRangeMaxStr|GUICtrlMonthCal_GetRangeMin|GUICtrlMonthCal_GetRangeMinStr|GUICtrlMonthCal_GetSelRange|GUICtrlMonthCal_GetSelRangeMax|GUICtrlMonthCal_GetSelRangeMaxStr|GUICtrlMonthCal_GetSelRangeMin|GUICtrlMonthCal_GetSelRangeMinStr|GUICtrlMonthCal_GetToday|GUICtrlMonthCal_GetTodayStr|GUICtrlMonthCal_GetUnicodeFormat|GUICtrlMonthCal_HitTest|GUICtrlMonthCal_SetColor|GUICtrlMonthCal_SetCurSel|GUICtrlMonthCal_SetDayState|GUICtrlMonthCal_SetFirstDOW|GUICtrlMonthCal_SetMaxSelCount|GUICtrlMonthCal_SetMonthDelta|GUICtrlMonthCal_SetRange|GUICtrlMonthCal_SetSelRange|GUICtrlMonthCal_SetToday|GUICtrlMonthCal_SetUnicodeFormat|GUICtrlRebar_AddBand|GUICtrlRebar_AddToolBarBand|GUICtrlRebar_BeginDrag|GUICtrlRebar_Create|GUICtrlRebar_DeleteBand|GUICtrlRebar_Destroy|GUICtrlRebar_DragMove|GUICtrlRebar_EndDrag|GUICtrlRebar_GetBandBackColor|GUICtrlRebar_GetBandBorders|GUICtrlRebar_GetBandBordersEx|GUICtrlRebar_GetBandChildHandle|GUICtrlRebar_GetBandChildSize|GUICtrlRebar_GetBandCount|GUICtrlRebar_GetBandForeColor|GUICtrlRebar_GetBandHeaderSize|GUICtrlRebar_GetBandID|GUICtrlRebar_GetBandIdealSize|GUICtrlRebar_GetBandLength|GUICtrlRebar_GetBandLParam|GUICtrlRebar_GetBandMargins|GUICtrlRebar_GetBandMarginsEx|GUICtrlRebar_GetBandRect|GUICtrlRebar_GetBandRectEx|GUICtrlRebar_GetBandStyle|GUICtrlRebar_GetBandStyleBreak|GUICtrlRebar_GetBandStyleChildEdge|GUICtrlRebar_GetBandStyleFixedBMP|GUICtrlRebar_GetBandStyleFixedSize|GUICtrlRebar_GetBandStyleGripperAlways|GUICtrlRebar_GetBandStyleHidden|GUICtrlRebar_GetBandStyleHideTitle|GUICtrlRebar_GetBandStyleNoGripper|GUICtrlRebar_GetBandStyleTopAlign|GUICtrlRebar_GetBandStyleUseChevron|GUICtrlRebar_GetBandStyleVariableHeight|GUICtrlRebar_GetBandText|GUICtrlRebar_GetBarHeight|GUICtrlRebar_GetBKColor|GUICtrlRebar_GetColorScheme|GUICtrlRebar_GetRowCount|GUICtrlRebar_GetRowHeight|GUICtrlRebar_GetTextColor|GUICtrlRebar_GetToolTips|GUICtrlRebar_GetUnicodeFormat|GUICtrlRebar_HitTest|GUICtrlRebar_IDToIndex|GUICtrlRebar_MaximizeBand|GUICtrlRebar_MinimizeBand|GUICtrlRebar_MoveBand|GUICtrlRebar_SetBandBackColor|GUICtrlRebar_SetBandForeColor|GUICtrlRebar_SetBandHeaderSize|GUICtrlRebar_SetBandID|GUICtrlRebar_SetBandIdealSize|GUICtrlRebar_SetBandLength|GUICtrlRebar_SetBandLParam|GUICtrlRebar_SetBandStyle|GUICtrlRebar_SetBandStyleBreak|GUICtrlRebar_SetBandStyleChildEdge|GUICtrlRebar_SetBandStyleFixedBMP|GUICtrlRebar_SetBandStyleFixedSize|GUICtrlRebar_SetBandStyleGripperAlways|GUICtrlRebar_SetBandStyleHidden|GUICtrlRebar_SetBandStyleHideTitle|GUICtrlRebar_SetBandStyleNoGripper|GUICtrlRebar_SetBandStyleTopAlign|GUICtrlRebar_SetBandStyleUseChevron|GUICtrlRebar_SetBandStyleVariableHeight|GUICtrlRebar_SetBandText|GUICtrlRebar_SetBKColor|GUICtrlRebar_SetColorScheme|GUICtrlRebar_SetTextColor|GUICtrlRebar_SetToolTips|GUICtrlRebar_SetUnicodeFormat|GUICtrlRebar_ShowBand|GUICtrlSlider_ClearSel|GUICtrlSlider_ClearTics|GUICtrlSlider_Create|GUICtrlSlider_Destroy|GUICtrlSlider_GetBuddy|GUICtrlSlider_GetChannelRect|GUICtrlSlider_GetLineSize|GUICtrlSlider_GetNumTics|GUICtrlSlider_GetPageSize|GUICtrlSlider_GetPos|GUICtrlSlider_GetPTics|GUICtrlSlider_GetRange|GUICtrlSlider_GetRangeMax|GUICtrlSlider_GetRangeMin|GUICtrlSlider_GetSel|GUICtrlSlider_GetSelEnd|GUICtrlSlider_GetSelStart|GUICtrlSlider_GetThumbLength|GUICtrlSlider_GetThumbRect|GUICtrlSlider_GetThumbRectEx|GUICtrlSlider_GetTic|GUICtrlSlider_GetTicPos|GUICtrlSlider_GetToolTips|GUICtrlSlider_GetUnicodeFormat|GUICtrlSlider_SetBuddy|GUICtrlSlider_SetLineSize|GUICtrlSlider_SetPageSize|GUICtrlSlider_SetPos|GUICtrlSlider_SetRange|GUICtrlSlider_SetRangeMax|GUICtrlSlider_SetRangeMin|GUICtrlSlider_SetSel|GUICtrlSlider_SetSelEnd|GUICtrlSlider_SetSelStart|GUICtrlSlider_SetThumbLength|GUICtrlSlider_SetTic|GUICtrlSlider_SetTicFreq|GUICtrlSlider_SetTipSide|GUICtrlSlider_SetToolTips|GUICtrlSlider_SetUnicodeFormat|GUICtrlStatusBar_Create|GUICtrlStatusBar_Destroy|GUICtrlStatusBar_EmbedControl|GUICtrlStatusBar_GetBorders|GUICtrlStatusBar_GetBordersHorz|GUICtrlStatusBar_GetBordersRect|GUICtrlStatusBar_GetBordersVert|GUICtrlStatusBar_GetCount|GUICtrlStatusBar_GetHeight|GUICtrlStatusBar_GetIcon|GUICtrlStatusBar_GetParts|GUICtrlStatusBar_GetRect|GUICtrlStatusBar_GetRectEx|GUICtrlStatusBar_GetText|GUICtrlStatusBar_GetTextFlags|GUICtrlStatusBar_GetTextLength|GUICtrlStatusBar_GetTextLengthEx|GUICtrlStatusBar_GetTipText|GUICtrlStatusBar_GetUnicodeFormat|GUICtrlStatusBar_GetWidth|GUICtrlStatusBar_IsSimple|GUICtrlStatusBar_Resize|GUICtrlStatusBar_SetBkColor|GUICtrlStatusBar_SetIcon|GUICtrlStatusBar_SetMinHeight|GUICtrlStatusBar_SetParts|GUICtrlStatusBar_SetSimple|GUICtrlStatusBar_SetText|GUICtrlStatusBar_SetTipText|GUICtrlStatusBar_SetUnicodeFormat|GUICtrlStatusBar_ShowHide|GUICtrlTab_Create|GUICtrlTab_DeleteAllItems|GUICtrlTab_DeleteItem|GUICtrlTab_DeselectAll|GUICtrlTab_Destroy|GUICtrlTab_FindTab|GUICtrlTab_GetCurFocus|GUICtrlTab_GetCurSel|GUICtrlTab_GetDisplayRect|GUICtrlTab_GetDisplayRectEx|GUICtrlTab_GetExtendedStyle|GUICtrlTab_GetImageList|GUICtrlTab_GetItem|GUICtrlTab_GetItemCount|GUICtrlTab_GetItemImage|GUICtrlTab_GetItemParam|GUICtrlTab_GetItemRect|GUICtrlTab_GetItemRectEx|GUICtrlTab_GetItemState|GUICtrlTab_GetItemText|GUICtrlTab_GetRowCount|GUICtrlTab_GetToolTips|GUICtrlTab_GetUnicodeFormat|GUICtrlTab_HighlightItem|GUICtrlTab_HitTest|GUICtrlTab_InsertItem|GUICtrlTab_RemoveImage|GUICtrlTab_SetCurFocus|GUICtrlTab_SetCurSel|GUICtrlTab_SetExtendedStyle|GUICtrlTab_SetImageList|GUICtrlTab_SetItem|GUICtrlTab_SetItemImage|GUICtrlTab_SetItemParam|GUICtrlTab_SetItemSize|GUICtrlTab_SetItemState|GUICtrlTab_SetItemText|GUICtrlTab_SetMinTabWidth|GUICtrlTab_SetPadding|GUICtrlTab_SetToolTips|GUICtrlTab_SetUnicodeFormat|GUICtrlToolbar_AddBitmap|GUICtrlToolbar_AddButton|GUICtrlToolbar_AddButtonSep|GUICtrlToolbar_AddString|GUICtrlToolbar_ButtonCount|GUICtrlToolbar_CheckButton|GUICtrlToolbar_ClickAccel|GUICtrlToolbar_ClickButton|GUICtrlToolbar_ClickIndex|GUICtrlToolbar_CommandToIndex|GUICtrlToolbar_Create|GUICtrlToolbar_Customize|GUICtrlToolbar_DeleteButton|GUICtrlToolbar_Destroy|GUICtrlToolbar_EnableButton|GUICtrlToolbar_FindToolbar|GUICtrlToolbar_GetAnchorHighlight|GUICtrlToolbar_GetBitmapFlags|GUICtrlToolbar_GetButtonBitmap|GUICtrlToolbar_GetButtonInfo|GUICtrlToolbar_GetButtonInfoEx|GUICtrlToolbar_GetButtonParam|GUICtrlToolbar_GetButtonRect|GUICtrlToolbar_GetButtonRectEx|GUICtrlToolbar_GetButtonSize|GUICtrlToolbar_GetButtonState|GUICtrlToolbar_GetButtonStyle|GUICtrlToolbar_GetButtonText|GUICtrlToolbar_GetColorScheme|GUICtrlToolbar_GetDisabledImageList|GUICtrlToolbar_GetExtendedStyle|GUICtrlToolbar_GetHotImageList|GUICtrlToolbar_GetHotItem|GUICtrlToolbar_GetImageList|GUICtrlToolbar_GetInsertMark|GUICtrlToolbar_GetInsertMarkColor|GUICtrlToolbar_GetMaxSize|GUICtrlToolbar_GetMetrics|GUICtrlToolbar_GetPadding|GUICtrlToolbar_GetRows|GUICtrlToolbar_GetString|GUICtrlToolbar_GetStyle|GUICtrlToolbar_GetStyleAltDrag|GUICtrlToolbar_GetStyleCustomErase|GUICtrlToolbar_GetStyleFlat|GUICtrlToolbar_GetStyleList|GUICtrlToolbar_GetStyleRegisterDrop|GUICtrlToolbar_GetStyleToolTips|GUICtrlToolbar_GetStyleTransparent|GUICtrlToolbar_GetStyleWrapable|GUICtrlToolbar_GetTextRows|GUICtrlToolbar_GetToolTips|GUICtrlToolbar_GetUnicodeFormat|GUICtrlToolbar_HideButton|GUICtrlToolbar_HighlightButton|GUICtrlToolbar_HitTest|GUICtrlToolbar_IndexToCommand|GUICtrlToolbar_InsertButton|GUICtrlToolbar_InsertMarkHitTest|GUICtrlToolbar_IsButtonChecked|GUICtrlToolbar_IsButtonEnabled|GUICtrlToolbar_IsButtonHidden|GUICtrlToolbar_IsButtonHighlighted|GUICtrlToolbar_IsButtonIndeterminate|GUICtrlToolbar_IsButtonPressed|GUICtrlToolbar_LoadBitmap|GUICtrlToolbar_LoadImages|GUICtrlToolbar_MapAccelerator|GUICtrlToolbar_MoveButton|GUICtrlToolbar_PressButton|GUICtrlToolbar_SetAnchorHighlight|GUICtrlToolbar_SetBitmapSize|GUICtrlToolbar_SetButtonBitMap|GUICtrlToolbar_SetButtonInfo|GUICtrlToolbar_SetButtonInfoEx|GUICtrlToolbar_SetButtonParam|GUICtrlToolbar_SetButtonSize|GUICtrlToolbar_SetButtonState|GUICtrlToolbar_SetButtonStyle|GUICtrlToolbar_SetButtonText|GUICtrlToolbar_SetButtonWidth|GUICtrlToolbar_SetCmdID|GUICtrlToolbar_SetColorScheme|GUICtrlToolbar_SetDisabledImageList|GUICtrlToolbar_SetDrawTextFlags|GUICtrlToolbar_SetExtendedStyle|GUICtrlToolbar_SetHotImageList|GUICtrlToolbar_SetHotItem|GUICtrlToolbar_SetImageList|GUICtrlToolbar_SetIndent|GUICtrlToolbar_SetIndeterminate|GUICtrlToolbar_SetInsertMark|GUICtrlToolbar_SetInsertMarkColor|GUICtrlToolbar_SetMaxTextRows|GUICtrlToolbar_SetMetrics|GUICtrlToolbar_SetPadding|GUICtrlToolbar_SetParent|GUICtrlToolbar_SetRows|GUICtrlToolbar_SetStyle|GUICtrlToolbar_SetStyleAltDrag|GUICtrlToolbar_SetStyleCustomErase|GUICtrlToolbar_SetStyleFlat|GUICtrlToolbar_SetStyleList|GUICtrlToolbar_SetStyleRegisterDrop|GUICtrlToolbar_SetStyleToolTips|GUICtrlToolbar_SetStyleTransparent|GUICtrlToolbar_SetStyleWrapable|GUICtrlToolbar_SetToolTips|GUICtrlToolbar_SetUnicodeFormat|GUICtrlToolbar_SetWindowTheme|GUICtrlTreeView_Add|GUICtrlTreeView_AddChild|GUICtrlTreeView_AddChildFirst|GUICtrlTreeView_AddFirst|GUICtrlTreeView_BeginUpdate|GUICtrlTreeView_ClickItem|GUICtrlTreeView_Create|GUICtrlTreeView_CreateDragImage|GUICtrlTreeView_CreateSolidBitMap|GUICtrlTreeView_Delete|GUICtrlTreeView_DeleteAll|GUICtrlTreeView_DeleteChildren|GUICtrlTreeView_Destroy|GUICtrlTreeView_DisplayRect|GUICtrlTreeView_DisplayRectEx|GUICtrlTreeView_EditText|GUICtrlTreeView_EndEdit|GUICtrlTreeView_EndUpdate|GUICtrlTreeView_EnsureVisible|GUICtrlTreeView_Expand|GUICtrlTreeView_ExpandedOnce|GUICtrlTreeView_FindItem|GUICtrlTreeView_FindItemEx|GUICtrlTreeView_GetBkColor|GUICtrlTreeView_GetBold|GUICtrlTreeView_GetChecked|GUICtrlTreeView_GetChildCount|GUICtrlTreeView_GetChildren|GUICtrlTreeView_GetCount|GUICtrlTreeView_GetCut|GUICtrlTreeView_GetDropTarget|GUICtrlTreeView_GetEditControl|GUICtrlTreeView_GetExpanded|GUICtrlTreeView_GetFirstChild|GUICtrlTreeView_GetFirstItem|GUICtrlTreeView_GetFirstVisible|GUICtrlTreeView_GetFocused|GUICtrlTreeView_GetHeight|GUICtrlTreeView_GetImageIndex|GUICtrlTreeView_GetImageListIconHandle|GUICtrlTreeView_GetIndent|GUICtrlTreeView_GetInsertMarkColor|GUICtrlTreeView_GetISearchString|GUICtrlTreeView_GetItemByIndex|GUICtrlTreeView_GetItemHandle|GUICtrlTreeView_GetItemParam|GUICtrlTreeView_GetLastChild|GUICtrlTreeView_GetLineColor|GUICtrlTreeView_GetNext|GUICtrlTreeView_GetNextChild|GUICtrlTreeView_GetNextSibling|GUICtrlTreeView_GetNextVisible|GUICtrlTreeView_GetNormalImageList|GUICtrlTreeView_GetParentHandle|GUICtrlTreeView_GetParentParam|GUICtrlTreeView_GetPrev|GUICtrlTreeView_GetPrevChild|GUICtrlTreeView_GetPrevSibling|GUICtrlTreeView_GetPrevVisible|GUICtrlTreeView_GetScrollTime|GUICtrlTreeView_GetSelected|GUICtrlTreeView_GetSelectedImageIndex|GUICtrlTreeView_GetSelection|GUICtrlTreeView_GetSiblingCount|GUICtrlTreeView_GetState|GUICtrlTreeView_GetStateImageIndex|GUICtrlTreeView_GetStateImageList|GUICtrlTreeView_GetText|GUICtrlTreeView_GetTextColor|GUICtrlTreeView_GetToolTips|GUICtrlTreeView_GetTree|GUICtrlTreeView_GetUnicodeFormat|GUICtrlTreeView_GetVisible|GUICtrlTreeView_GetVisibleCount|GUICtrlTreeView_HitTest|GUICtrlTreeView_HitTestEx|GUICtrlTreeView_HitTestItem|GUICtrlTreeView_Index|GUICtrlTreeView_InsertItem|GUICtrlTreeView_IsFirstItem|GUICtrlTreeView_IsParent|GUICtrlTreeView_Level|GUICtrlTreeView_SelectItem|GUICtrlTreeView_SelectItemByIndex|GUICtrlTreeView_SetBkColor|GUICtrlTreeView_SetBold|GUICtrlTreeView_SetChecked|GUICtrlTreeView_SetCheckedByIndex|GUICtrlTreeView_SetChildren|GUICtrlTreeView_SetCut|GUICtrlTreeView_SetDropTarget|GUICtrlTreeView_SetFocused|GUICtrlTreeView_SetHeight|GUICtrlTreeView_SetIcon|GUICtrlTreeView_SetImageIndex|GUICtrlTreeView_SetIndent|GUICtrlTreeView_SetInsertMark|GUICtrlTreeView_SetInsertMarkColor|GUICtrlTreeView_SetItemHeight|GUICtrlTreeView_SetItemParam|GUICtrlTreeView_SetLineColor|GUICtrlTreeView_SetNormalImageList|GUICtrlTreeView_SetScrollTime|GUICtrlTreeView_SetSelected|GUICtrlTreeView_SetSelectedImageIndex|GUICtrlTreeView_SetState|GUICtrlTreeView_SetStateImageIndex|GUICtrlTreeView_SetStateImageList|GUICtrlTreeView_SetText|GUICtrlTreeView_SetTextColor|GUICtrlTreeView_SetToolTips|GUICtrlTreeView_SetUnicodeFormat|GUICtrlTreeView_Sort|GUIImageList_Add|GUIImageList_AddBitmap|GUIImageList_AddIcon|GUIImageList_AddMasked|GUIImageList_BeginDrag|GUIImageList_Copy|GUIImageList_Create|GUIImageList_Destroy|GUIImageList_DestroyIcon|GUIImageList_DragEnter|GUIImageList_DragLeave|GUIImageList_DragMove|GUIImageList_Draw|GUIImageList_DrawEx|GUIImageList_Duplicate|GUIImageList_EndDrag|GUIImageList_GetBkColor|GUIImageList_GetIcon|GUIImageList_GetIconHeight|GUIImageList_GetIconSize|GUIImageList_GetIconSizeEx|GUIImageList_GetIconWidth|GUIImageList_GetImageCount|GUIImageList_GetImageInfoEx|GUIImageList_Remove|GUIImageList_ReplaceIcon|GUIImageList_SetBkColor|GUIImageList_SetIconSize|GUIImageList_SetImageCount|GUIImageList_Swap|GUIScrollBars_EnableScrollBar|GUIScrollBars_GetScrollBarInfoEx|GUIScrollBars_GetScrollBarRect|GUIScrollBars_GetScrollBarRGState|GUIScrollBars_GetScrollBarXYLineButton|GUIScrollBars_GetScrollBarXYThumbBottom|GUIScrollBars_GetScrollBarXYThumbTop|GUIScrollBars_GetScrollInfo|GUIScrollBars_GetScrollInfoEx|GUIScrollBars_GetScrollInfoMax|GUIScrollBars_GetScrollInfoMin|GUIScrollBars_GetScrollInfoPage|GUIScrollBars_GetScrollInfoPos|GUIScrollBars_GetScrollInfoTrackPos|GUIScrollBars_GetScrollPos|GUIScrollBars_GetScrollRange|GUIScrollBars_Init|GUIScrollBars_ScrollWindow|GUIScrollBars_SetScrollInfo|GUIScrollBars_SetScrollInfoMax|GUIScrollBars_SetScrollInfoMin|GUIScrollBars_SetScrollInfoPage|GUIScrollBars_SetScrollInfoPos|GUIScrollBars_SetScrollRange|GUIScrollBars_ShowScrollBar|GUIToolTip_Activate|GUIToolTip_AddTool|GUIToolTip_AdjustRect|GUIToolTip_BitsToTTF|GUIToolTip_Create|GUIToolTip_DelTool|GUIToolTip_Destroy|GUIToolTip_EnumTools|GUIToolTip_GetBubbleHeight|GUIToolTip_GetBubbleSize|GUIToolTip_GetBubbleWidth|GUIToolTip_GetCurrentTool|GUIToolTip_GetDelayTime|GUIToolTip_GetMargin|GUIToolTip_GetMarginEx|GUIToolTip_GetMaxTipWidth|GUIToolTip_GetText|GUIToolTip_GetTipBkColor|GUIToolTip_GetTipTextColor|GUIToolTip_GetTitleBitMap|GUIToolTip_GetTitleText|GUIToolTip_GetToolCount|GUIToolTip_GetToolInfo|GUIToolTip_HitTest|GUIToolTip_NewToolRect|GUIToolTip_Pop|GUIToolTip_PopUp|GUIToolTip_SetDelayTime|GUIToolTip_SetMargin|GUIToolTip_SetMaxTipWidth|GUIToolTip_SetTipBkColor|GUIToolTip_SetTipTextColor|GUIToolTip_SetTitle|GUIToolTip_SetToolInfo|GUIToolTip_SetWindowTheme|GUIToolTip_ToolExists|GUIToolTip_ToolToArray|GUIToolTip_TrackActivate|GUIToolTip_TrackPosition|GUIToolTip_TTFToBits|GUIToolTip_Update|GUIToolTip_UpdateTipText|HexToString|IE_Example|IE_Introduction|IE_VersionInfo|IEAction|IEAttach|IEBodyReadHTML|IEBodyReadText|IEBodyWriteHTML|IECreate|IECreateEmbedded|IEDocGetObj|IEDocInsertHTML|IEDocInsertText|IEDocReadHTML|IEDocWriteHTML|IEErrorHandlerDeRegister|IEErrorHandlerRegister|IEErrorNotify|IEFormElementCheckBoxSelect|IEFormElementGetCollection|IEFormElementGetObjByName|IEFormElementGetValue|IEFormElementOptionSelect|IEFormElementRadioSelect|IEFormElementSetValue|IEFormGetCollection|IEFormGetObjByName|IEFormImageClick|IEFormReset|IEFormSubmit|IEFrameGetCollection|IEFrameGetObjByName|IEGetObjById|IEGetObjByName|IEHeadInsertEventScript|IEImgClick|IEImgGetCollection|IEIsFrameSet|IELinkClickByIndex|IELinkClickByText|IELinkGetCollection|IELoadWait|IELoadWaitTimeout|IENavigate|IEPropertyGet|IEPropertySet|IEQuit|IETableGetCollection|IETableWriteToArray|IETagNameAllGetCollection|IETagNameGetCollection|Iif|INetExplorerCapable|INetGetSource|INetMail|INetSmtpMail|IsPressed|MathCheckDiv|Max|MemGlobalAlloc|MemGlobalFree|MemGlobalLock|MemGlobalSize|MemGlobalUnlock|MemMoveMemory|MemMsgBox|MemShowError|MemVirtualAlloc|MemVirtualAllocEx|MemVirtualFree|MemVirtualFreeEx|Min|MouseTrap|NamedPipes_CallNamedPipe|NamedPipes_ConnectNamedPipe|NamedPipes_CreateNamedPipe|NamedPipes_CreatePipe|NamedPipes_DisconnectNamedPipe|NamedPipes_GetNamedPipeHandleState|NamedPipes_GetNamedPipeInfo|NamedPipes_PeekNamedPipe|NamedPipes_SetNamedPipeHandleState|NamedPipes_TransactNamedPipe|NamedPipes_WaitNamedPipe|Net_Share_ConnectionEnum|Net_Share_FileClose|Net_Share_FileEnum|Net_Share_FileGetInfo|Net_Share_PermStr|Net_Share_ResourceStr|Net_Share_SessionDel|Net_Share_SessionEnum|Net_Share_SessionGetInfo|Net_Share_ShareAdd|Net_Share_ShareCheck|Net_Share_ShareDel|Net_Share_ShareEnum|Net_Share_ShareGetInfo|Net_Share_ShareSetInfo|Net_Share_StatisticsGetSvr|Net_Share_StatisticsGetWrk|Now|NowCalc|NowCalcDate|NowDate|NowTime|PathFull|PathMake|PathSplit|ProcessGetName|ProcessGetPriority|Radian|ReplaceStringInFile|RunDOS|ScreenCapture_Capture|ScreenCapture_CaptureWnd|ScreenCapture_SaveImage|ScreenCapture_SetBMPFormat|ScreenCapture_SetJPGQuality|ScreenCapture_SetTIFColorDepth|ScreenCapture_SetTIFCompression|Security__AdjustTokenPrivileges|Security__GetAccountSid|Security__GetLengthSid|Security__GetTokenInformation|Security__ImpersonateSelf|Security__IsValidSid|Security__LookupAccountName|Security__LookupAccountSid|Security__LookupPrivilegeValue|Security__OpenProcessToken|Security__OpenThreadToken|Security__OpenThreadTokenEx|Security__SetPrivilege|Security__SidToStringSid|Security__SidTypeStr|Security__StringSidToSid|SendMessage|SendMessageA|SetDate|SetTime|Singleton|SoundClose|SoundLength|SoundOpen|SoundPause|SoundPlay|SoundPos|SoundResume|SoundSeek|SoundStatus|SoundStop|SQLite_Changes|SQLite_Close|SQLite_Display2DResult|SQLite_Encode|SQLite_ErrCode|SQLite_ErrMsg|SQLite_Escape|SQLite_Exec|SQLite_FetchData|SQLite_FetchNames|SQLite_GetTable|SQLite_GetTable2d|SQLite_LastInsertRowID|SQLite_LibVersion|SQLite_Open|SQLite_Query|SQLite_QueryFinalize|SQLite_QueryReset|SQLite_QuerySingleRow|SQLite_SaveMode|SQLite_SetTimeout|SQLite_Shutdown|SQLite_SQLiteExe|SQLite_Startup|SQLite_TotalChanges|StringAddComma|StringBetween|StringEncrypt|StringInsert|StringProper|StringRepeat|StringReverse|StringSplit|StringToHex|TCPIpToName|TempFile|TicksToTime|Timer_Diff|Timer_GetTimerID|Timer_Init|Timer_KillAllTimers|Timer_KillTimer|Timer_SetTimer|TimeToTicks|VersionCompare|viClose|viExecCommand|viFindGpib|viGpibBusReset|viGTL|viOpen|viSetAttribute|viSetTimeout|WeekNumberISO|WinAPI_AttachConsole|WinAPI_AttachThreadInput|WinAPI_Beep|WinAPI_BitBlt|WinAPI_CallNextHookEx|WinAPI_Check|WinAPI_ClientToScreen|WinAPI_CloseHandle|WinAPI_CommDlgExtendedError|WinAPI_CopyIcon|WinAPI_CreateBitmap|WinAPI_CreateCompatibleBitmap|WinAPI_CreateCompatibleDC|WinAPI_CreateEvent|WinAPI_CreateFile|WinAPI_CreateFont|WinAPI_CreateFontIndirect|WinAPI_CreateProcess|WinAPI_CreateSolidBitmap|WinAPI_CreateSolidBrush|WinAPI_CreateWindowEx|WinAPI_DefWindowProc|WinAPI_DeleteDC|WinAPI_DeleteObject|WinAPI_DestroyIcon|WinAPI_DestroyWindow|WinAPI_DrawEdge|WinAPI_DrawFrameControl|WinAPI_DrawIcon|WinAPI_DrawIconEx|WinAPI_DrawText|WinAPI_EnableWindow|WinAPI_EnumDisplayDevices|WinAPI_EnumWindows|WinAPI_EnumWindowsPopup|WinAPI_EnumWindowsTop|WinAPI_ExpandEnvironmentStrings|WinAPI_ExtractIconEx|WinAPI_FatalAppExit|WinAPI_FillRect|WinAPI_FindExecutable|WinAPI_FindWindow|WinAPI_FlashWindow|WinAPI_FlashWindowEx|WinAPI_FloatToInt|WinAPI_FlushFileBuffers|WinAPI_FormatMessage|WinAPI_FrameRect|WinAPI_FreeLibrary|WinAPI_GetAncestor|WinAPI_GetAsyncKeyState|WinAPI_GetClassName|WinAPI_GetClientHeight|WinAPI_GetClientRect|WinAPI_GetClientWidth|WinAPI_GetCurrentProcess|WinAPI_GetCurrentProcessID|WinAPI_GetCurrentThread|WinAPI_GetCurrentThreadId|WinAPI_GetCursorInfo|WinAPI_GetDC|WinAPI_GetDesktopWindow|WinAPI_GetDeviceCaps|WinAPI_GetDIBits|WinAPI_GetDlgCtrlID|WinAPI_GetDlgItem|WinAPI_GetFileSizeEx|WinAPI_GetFocus|WinAPI_GetForegroundWindow|WinAPI_GetIconInfo|WinAPI_GetLastError|WinAPI_GetLastErrorMessage|WinAPI_GetModuleHandle|WinAPI_GetMousePos|WinAPI_GetMousePosX|WinAPI_GetMousePosY|WinAPI_GetObject|WinAPI_GetOpenFileName|WinAPI_GetOverlappedResult|WinAPI_GetParent|WinAPI_GetProcessAffinityMask|WinAPI_GetSaveFileName|WinAPI_GetStdHandle|WinAPI_GetStockObject|WinAPI_GetSysColor|WinAPI_GetSysColorBrush|WinAPI_GetSystemMetrics|WinAPI_GetTextExtentPoint32|WinAPI_GetWindow|WinAPI_GetWindowDC|WinAPI_GetWindowHeight|WinAPI_GetWindowLong|WinAPI_GetWindowRect|WinAPI_GetWindowText|WinAPI_GetWindowThreadProcessId|WinAPI_GetWindowWidth|WinAPI_GetXYFromPoint|WinAPI_GlobalMemStatus|WinAPI_GUIDFromString|WinAPI_GUIDFromStringEx|WinAPI_HiWord|WinAPI_InProcess|WinAPI_IntToFloat|WinAPI_InvalidateRect|WinAPI_IsClassName|WinAPI_IsWindow|WinAPI_IsWindowVisible|WinAPI_LoadBitmap|WinAPI_LoadImage|WinAPI_LoadLibrary|WinAPI_LoadLibraryEx|WinAPI_LoadShell32Icon|WinAPI_LoadString|WinAPI_LocalFree|WinAPI_LoWord|WinAPI_MakeDWord|WinAPI_MAKELANGID|WinAPI_MAKELCID|WinAPI_MakeLong|WinAPI_MessageBeep|WinAPI_Mouse_Event|WinAPI_MoveWindow|WinAPI_MsgBox|WinAPI_MulDiv|WinAPI_MultiByteToWideChar|WinAPI_MultiByteToWideCharEx|WinAPI_OpenProcess|WinAPI_PointFromRect|WinAPI_PostMessage|WinAPI_PrimaryLangId|WinAPI_PtInRect|WinAPI_ReadFile|WinAPI_ReadProcessMemory|WinAPI_RectIsEmpty|WinAPI_RedrawWindow|WinAPI_RegisterWindowMessage|WinAPI_ReleaseCapture|WinAPI_ReleaseDC|WinAPI_ScreenToClient|WinAPI_SelectObject|WinAPI_SetBkColor|WinAPI_SetCapture|WinAPI_SetCursor|WinAPI_SetDefaultPrinter|WinAPI_SetDIBits|WinAPI_SetEvent|WinAPI_SetFocus|WinAPI_SetFont|WinAPI_SetHandleInformation|WinAPI_SetLastError|WinAPI_SetParent|WinAPI_SetProcessAffinityMask|WinAPI_SetSysColors|WinAPI_SetTextColor|WinAPI_SetWindowLong|WinAPI_SetWindowPos|WinAPI_SetWindowsHookEx|WinAPI_SetWindowText|WinAPI_ShowCursor|WinAPI_ShowError|WinAPI_ShowMsg|WinAPI_ShowWindow|WinAPI_StringFromGUID|WinAPI_SubLangId|WinAPI_SystemParametersInfo|WinAPI_TwipsPerPixelX|WinAPI_TwipsPerPixelY|WinAPI_UnhookWindowsHookEx|WinAPI_UpdateLayeredWindow|WinAPI_UpdateWindow|WinAPI_ValidateClassName|WinAPI_WaitForInputIdle|WinAPI_WaitForMultipleObjects|WinAPI_WaitForSingleObject|WinAPI_WideCharToMultiByte|WinAPI_WindowFromPoint|WinAPI_WriteConsole|WinAPI_WriteFile|WinAPI_WriteProcessMemory|WinNet_AddConnection|WinNet_AddConnection2|WinNet_AddConnection3|WinNet_CancelConnection|WinNet_CancelConnection2|WinNet_CloseEnum|WinNet_ConnectionDialog|WinNet_ConnectionDialog1|WinNet_DisconnectDialog|WinNet_DisconnectDialog1|WinNet_EnumResource|WinNet_GetConnection|WinNet_GetConnectionPerformance|WinNet_GetLastError|WinNet_GetNetworkInformation|WinNet_GetProviderName|WinNet_GetResourceInformation|WinNet_GetResourceParent|WinNet_GetUniversalName|WinNet_GetUser|WinNet_OpenEnum|WinNet_RestoreConnection|WinNet_UseConnection|Word_VersionInfo|WordAttach|WordCreate|WordDocAdd|WordDocAddLink|WordDocAddPicture|WordDocClose|WordDocFindReplace|WordDocGetCollection|WordDocLinkGetCollection|WordDocOpen|WordDocPrint|WordDocPropertyGet|WordDocPropertySet|WordDocSave|WordDocSaveAs|WordErrorHandlerDeRegister|WordErrorHandlerRegister|WordErrorNotify|WordMacroRun|WordPropertyGet|WordPropertySet|WordQuit|' + + 'ce|comments-end|comments-start|cs|include|include-once|NoTrayIcon|RequireAdmin|' + + 'AutoIt3Wrapper_Au3Check_Parameters|AutoIt3Wrapper_Au3Check_Stop_OnWarning|AutoIt3Wrapper_Change2CUI|AutoIt3Wrapper_Compression|AutoIt3Wrapper_cvsWrapper_Parameters|AutoIt3Wrapper_Icon|AutoIt3Wrapper_Outfile|AutoIt3Wrapper_Outfile_Type|AutoIt3Wrapper_Plugin_Funcs|AutoIt3Wrapper_Res_Comment|AutoIt3Wrapper_Res_Description|AutoIt3Wrapper_Res_Field|AutoIt3Wrapper_Res_File_Add|AutoIt3Wrapper_Res_Fileversion|AutoIt3Wrapper_Res_FileVersion_AutoIncrement|AutoIt3Wrapper_Res_Icon_Add|AutoIt3Wrapper_Res_Language|AutoIt3Wrapper_Res_LegalCopyright|AutoIt3Wrapper_res_requestedExecutionLevel|AutoIt3Wrapper_Res_SaveSource|AutoIt3Wrapper_Run_After|AutoIt3Wrapper_Run_Au3check|AutoIt3Wrapper_Run_Before|AutoIt3Wrapper_Run_cvsWrapper|AutoIt3Wrapper_Run_Debug_Mode|AutoIt3Wrapper_Run_Obfuscator|AutoIt3Wrapper_Run_Tidy|AutoIt3Wrapper_Tidy_Stop_OnError|AutoIt3Wrapper_UseAnsi|AutoIt3Wrapper_UseUpx|AutoIt3Wrapper_UseX64|AutoIt3Wrapper_Version|EndRegion|forceref|Obfuscator_Ignore_Funcs|Obfuscator_Ignore_Variables|Obfuscator_Parameters|Region|Tidy_Parameters' + var atKeywords = 'AppDataCommonDir|AppDataDir|AutoItExe|AutoItPID|AutoItUnicode|AutoItVersion|AutoItX64|COM_EventObj|CommonFilesDir|Compiled|ComputerName|ComSpec|CR|CRLF|DesktopCommonDir|DesktopDepth|DesktopDir|DesktopHeight|DesktopRefresh|DesktopWidth|DocumentsCommonDir|error|exitCode|exitMethod|extended|FavoritesCommonDir|FavoritesDir|GUI_CtrlHandle|GUI_CtrlId|GUI_DragFile|GUI_DragId|GUI_DropId|GUI_WinHandle|HomeDrive|HomePath|HomeShare|HotKeyPressed|HOUR|InetGetActive|InetGetBytesRead|IPAddress1|IPAddress2|IPAddress3|IPAddress4|KBLayout|LF|LogonDNSDomain|LogonDomain|LogonServer|MDAY|MIN|MON|MyDocumentsDir|NumParams|OSBuild|OSLang|OSServicePack|OSTYPE|OSVersion|ProcessorArch|ProgramFilesDir|ProgramsCommonDir|ProgramsDir|ScriptDir|ScriptFullPath|ScriptLineNumber|ScriptName|SEC|StartMenuCommonDir|StartMenuDir|StartupCommonDir|StartupDir|SW_DISABLE|SW_ENABLE|SW_HIDE|SW_LOCK|SW_MAXIMIZE|SW_MINIMIZE|SW_RESTORE|SW_SHOW|SW_SHOWDEFAULT|SW_SHOWMAXIMIZED|SW_SHOWMINIMIZED|SW_SHOWMINNOACTIVE|SW_SHOWNA|SW_SHOWNOACTIVATE|SW_SHOWNORMAL|SW_UNLOCK|SystemDir|TAB|TempDir|TRAY_ID|TrayIconFlashing|TrayIconVisible|UserName|UserProfileDir|WDAY|WindowsDir|WorkingDir|YDAY|YEAR' + + this.$rules = { start: + [ { token: 'comment.line.ahk', regex: '(?:^| );.*$' }, + { token: 'comment.block.ahk', + regex: '/\\*', push: + [ { token: 'comment.block.ahk', regex: '\\*/', next: 'pop' }, + { defaultToken: 'comment.block.ahk' } ] }, + { token: 'doc.comment.ahk', + regex: '#cs', push: + [ { token: 'doc.comment.ahk', regex: '#ce', next: 'pop' }, + { defaultToken: 'doc.comment.ahk' } ] }, + { token: 'keyword.command.ahk', + regex: '(?:\\b|^)(?:allowsamelinecomments|clipboardtimeout|commentflag|errorstdout|escapechar|hotkeyinterval|hotkeymodifiertimeout|hotstring|include|includeagain|installkeybdhook|installmousehook|keyhistory|ltrim|maxhotkeysperinterval|maxmem|maxthreads|maxthreadsbuffer|maxthreadsperhotkey|noenv|notrayicon|persistent|singleinstance|usehook|winactivateforce|autotrim|blockinput|click|clipwait|continue|control|controlclick|controlfocus|controlget|controlgetfocus|controlgetpos|controlgettext|controlmove|controlsend|controlsendraw|controlsettext|coordmode|critical|detecthiddentext|detecthiddenwindows|drive|driveget|drivespacefree|edit|endrepeat|envadd|envdiv|envget|envmult|envset|envsub|envupdate|exit|exitapp|fileappend|filecopy|filecopydir|filecreatedir|filecreateshortcut|filedelete|filegetattrib|filegetshortcut|filegetsize|filegettime|filegetversion|fileinstall|filemove|filemovedir|fileread|filereadline|filerecycle|filerecycleempty|fileremovedir|fileselectfile|fileselectfolder|filesetattrib|filesettime|formattime|getkeystate|gosub|goto|groupactivate|groupadd|groupclose|groupdeactivate|gui|guicontrol|guicontrolget|hideautoitwin|hotkey|ifequal|ifexist|ifgreater|ifgreaterorequal|ifinstring|ifless|iflessorequal|ifmsgbox|ifnotequal|ifnotexist|ifnotinstring|ifwinactive|ifwinexist|ifwinnotactive|ifwinnotexist|imagesearch|inidelete|iniread|iniwrite|input|inputbox|keyhistory|keywait|listhotkeys|listlines|listvars|menu|mouseclick|mouseclickdrag|mousegetpos|mousemove|msgbox|onexit|outputdebug|pause|pixelgetcolor|pixelsearch|postmessage|process|progress|random|regdelete|regread|regwrite|reload|repeat|run|runas|runwait|send|sendevent|sendinput|sendmode|sendplay|sendmessage|sendraw|setbatchlines|setcapslockstate|setcontroldelay|setdefaultmousespeed|setenv|setformat|setkeydelay|setmousedelay|setnumlockstate|setscrolllockstate|setstorecapslockmode|settimer|settitlematchmode|setwindelay|setworkingdir|shutdown|sleep|sort|soundbeep|soundget|soundgetwavevolume|soundplay|soundset|soundsetwavevolume|splashimage|splashtextoff|splashtexton|splitpath|statusbargettext|statusbarwait|stringcasesense|stringgetpos|stringleft|stringlen|stringlower|stringmid|stringreplace|stringright|stringsplit|stringtrimleft|stringtrimright|stringupper|suspend|sysget|thread|tooltip|transform|traytip|urldownloadtofile|while|winactivate|winactivatebottom|winclose|winget|wingetactivestats|wingetactivetitle|wingetclass|wingetpos|wingettext|wingettitle|winhide|winkill|winmaximize|winmenuselectitem|winminimize|winminimizeall|winminimizeallundo|winmove|winrestore|winset|winsettitle|winshow|winwait|winwaitactive|winwaitclose|winwaitnotactive)\\b', + caseInsensitive: true }, + { token: 'keyword.control.ahk', + regex: '(?:\\b|^)(?:if|else|return|loop|break|for|while|global|local|byref)\\b', + caseInsensitive: true }, + { token: 'support.function.ahk', + regex: '(?:\\b|^)(?:abs|acos|asc|asin|atan|ceil|chr|cos|dllcall|exp|fileexist|floor|getkeystate|il_add|il_create|il_destroy|instr|substr|isfunc|islabel|ln|log|lv_add|lv_delete|lv_deletecol|lv_getcount|lv_getnext|lv_gettext|lv_insert|lv_insertcol|lv_modify|lv_modifycol|lv_setimagelist|mod|onmessage|numget|numput|registercallback|regexmatch|regexreplace|round|sin|tan|sqrt|strlen|sb_seticon|sb_setparts|sb_settext|tv_add|tv_delete|tv_getchild|tv_getcount|tv_getnext|tv_get|tv_getparent|tv_getprev|tv_getselection|tv_gettext|tv_modify|varsetcapacity|winactive|winexist)\\b', + caseInsensitive: true }, + { token: 'variable.predefined.ahk', + regex: '(?:\\b|^)(?:a_ahkpath|a_ahkversion|a_appdata|a_appdatacommon|a_autotrim|a_batchlines|a_caretx|a_carety|a_computername|a_controldelay|a_cursor|a_dd|a_ddd|a_dddd|a_defaultmousespeed|a_desktop|a_desktopcommon|a_detecthiddentext|a_detecthiddenwindows|a_endchar|a_eventinfo|a_exitreason|a_formatfloat|a_formatinteger|a_gui|a_guievent|a_guicontrol|a_guicontrolevent|a_guiheight|a_guiwidth|a_guix|a_guiy|a_hour|a_iconfile|a_iconhidden|a_iconnumber|a_icontip|a_index|a_ipaddress1|a_ipaddress2|a_ipaddress3|a_ipaddress4|a_isadmin|a_iscompiled|a_iscritical|a_ispaused|a_issuspended|a_keydelay|a_language|a_lasterror|a_linefile|a_linenumber|a_loopfield|a_loopfileattrib|a_loopfiledir|a_loopfileext|a_loopfilefullpath|a_loopfilelongpath|a_loopfilename|a_loopfileshortname|a_loopfileshortpath|a_loopfilesize|a_loopfilesizekb|a_loopfilesizemb|a_loopfiletimeaccessed|a_loopfiletimecreated|a_loopfiletimemodified|a_loopreadline|a_loopregkey|a_loopregname|a_loopregsubkey|a_loopregtimemodified|a_loopregtype|a_mday|a_min|a_mm|a_mmm|a_mmmm|a_mon|a_mousedelay|a_msec|a_mydocuments|a_now|a_nowutc|a_numbatchlines|a_ostype|a_osversion|a_priorhotkey|programfiles|a_programfiles|a_programs|a_programscommon|a_screenheight|a_screenwidth|a_scriptdir|a_scriptfullpath|a_scriptname|a_sec|a_space|a_startmenu|a_startmenucommon|a_startup|a_startupcommon|a_stringcasesense|a_tab|a_temp|a_thisfunc|a_thishotkey|a_thislabel|a_thismenu|a_thismenuitem|a_thismenuitempos|a_tickcount|a_timeidle|a_timeidlephysical|a_timesincepriorhotkey|a_timesincethishotkey|a_titlematchmode|a_titlematchmodespeed|a_username|a_wday|a_windelay|a_windir|a_workingdir|a_yday|a_year|a_yweek|a_yyyy|clipboard|clipboardall|comspec|errorlevel)\\b', + caseInsensitive: true }, + { token: 'support.constant.ahk', + regex: '(?:\\b|^)(?:shift|lshift|rshift|alt|lalt|ralt|control|lcontrol|rcontrol|ctrl|lctrl|rctrl|lwin|rwin|appskey|altdown|altup|shiftdown|shiftup|ctrldown|ctrlup|lwindown|lwinup|rwindown|rwinup|lbutton|rbutton|mbutton|wheelup|wheelleft|wheelright|wheeldown|xbutton1|xbutton2|joy1|joy2|joy3|joy4|joy5|joy6|joy7|joy8|joy9|joy10|joy11|joy12|joy13|joy14|joy15|joy16|joy17|joy18|joy19|joy20|joy21|joy22|joy23|joy24|joy25|joy26|joy27|joy28|joy29|joy30|joy31|joy32|joyx|joyy|joyz|joyr|joyu|joyv|joypov|joyname|joybuttons|joyaxes|joyinfo|space|tab|enter|escape|esc|backspace|bs|delete|del|insert|ins|pgup|pgdn|home|end|up|down|left|right|printscreen|ctrlbreak|pause|scrolllock|capslock|numlock|numpad0|numpad1|numpad2|numpad3|numpad4|numpad5|numpad6|numpad7|numpad8|numpad9|numpadmult|numpadadd|numpadsub|numpaddiv|numpaddot|numpaddel|numpadins|numpadclear|numpadup|numpaddown|numpadleft|numpadright|numpadhome|numpadend|numpadpgup|numpadpgdn|numpadenter|f1|f2|f3|f4|f5|f6|f7|f8|f9|f10|f11|f12|f13|f14|f15|f16|f17|f18|f19|f20|f21|f22|f23|f24|browser_back|browser_forward|browser_refresh|browser_stop|browser_search|browser_favorites|browser_home|volume_mute|volume_down|volume_up|media_next|media_prev|media_stop|media_play_pause|launch_mail|launch_media|launch_app1|launch_app2)\\b', + caseInsensitive: true }, + { token: 'variable.parameter', + regex: '(?:\\b|^)(?:pixel|mouse|screen|relative|rgb|ltrim|rtrim|join|low|belownormal|normal|abovenormal|high|realtime|ahk_id|ahk_pid|ahk_class|ahk_group|between|contains|in|is|integer|float|integerfast|floatfast|number|digit|xdigit|alpha|upper|lower|alnum|time|date|not|or|and|alwaysontop|topmost|top|bottom|transparent|transcolor|redraw|region|id|idlast|processname|minmax|controllist|count|list|capacity|statuscd|eject|lock|unlock|label|filesystem|label|setlabel|serial|type|status|static|seconds|minutes|hours|days|read|parse|logoff|close|error|single|tray|add|rename|check|uncheck|togglecheck|enable|disable|toggleenable|default|nodefault|standard|nostandard|color|delete|deleteall|icon|noicon|tip|click|show|mainwindow|nomainwindow|useerrorlevel|text|picture|pic|groupbox|button|checkbox|radio|dropdownlist|ddl|combobox|listbox|listview|datetime|monthcal|updown|slider|tab|tab2|statusbar|treeview|iconsmall|tile|report|sortdesc|nosort|nosorthdr|grid|hdr|autosize|range|xm|ym|ys|xs|xp|yp|font|resize|owner|submit|nohide|minimize|maximize|restore|noactivate|na|cancel|destroy|center|margin|maxsize|minsize|owndialogs|guiescape|guiclose|guisize|guicontextmenu|guidropfiles|tabstop|section|altsubmit|wrap|hscroll|vscroll|border|top|bottom|buttons|expand|first|imagelist|lines|wantctrla|wantf2|vis|visfirst|number|uppercase|lowercase|limit|password|multi|wantreturn|group|background|bold|italic|strike|underline|norm|backgroundtrans|theme|caption|delimiter|minimizebox|maximizebox|sysmenu|toolwindow|flash|style|exstyle|check3|checked|checkedgray|readonly|password|hidden|left|right|center|notab|section|move|focus|hide|choose|choosestring|text|pos|enabled|disabled|visible|lastfound|lastfoundexist|alttab|shiftalttab|alttabmenu|alttabandmenu|alttabmenudismiss|notimers|interrupt|priority|waitclose|blind|raw|unicode|deref|pow|bitnot|bitand|bitor|bitxor|bitshiftleft|bitshiftright|yes|no|ok|cancel|abort|retry|ignore|tryagain|on|off|all|hkey_local_machine|hkey_users|hkey_current_user|hkey_classes_root|hkey_current_config|hklm|hku|hkcu|hkcr|hkcc|reg_sz|reg_expand_sz|reg_multi_sz|reg_dword|reg_qword|reg_binary|reg_link|reg_resource_list|reg_full_resource_descriptor|reg_resource_requirements_list|reg_dword_big_endian)\\b', + caseInsensitive: true }, + { keywordMap: {"constant.language": autoItKeywords}, regex: '\\w+\\b'}, + { keywordMap: {"variable.function": atKeywords}, regex: '@\\w+\\b'}, + { token : "constant.numeric", regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"}, + { token: 'keyword.operator.ahk', + regex: '=|==|<>|:=|<|>|\\*|\\/|\\+|:|\\?|\\-' }, + { token: 'punctuation.ahk', + regex: '#|`|::|,|\\{|\\}|\\(|\\)|\\%' }, + { token: + [ 'punctuation.quote.double', + 'string.quoted.ahk', + 'punctuation.quote.double' ], + regex: '(")((?:[^"]|"")*)(")' }, + { token: [ 'label.ahk', 'punctuation.definition.label.ahk' ], + regex: '^([^: ]+)(:)(?!:)' } ] } + + this.normalizeRules(); +}; + +AutoHotKeyHighlightRules.metaData = { name: 'AutoHotKey', + scopeName: 'source.ahk', + fileTypes: [ 'ahk' ], + foldingStartMarker: '^\\s*/\\*|^(?![^{]*?;|[^{]*?/\\*(?!.*?\\*/.*?\\{)).*?\\{\\s*($|;|/\\*(?!.*?\\*/.*\\S))', + foldingStopMarker: '^\\s*\\*/|^\\s*\\}' } + + +oop.inherits(AutoHotKeyHighlightRules, TextHighlightRules); + +exports.AutoHotKeyHighlightRules = AutoHotKeyHighlightRules; +}); \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/batchfile.js b/node_modules/ace/lib/ace/mode/batchfile.js new file mode 100644 index 00000000..e080464c --- /dev/null +++ b/node_modules/ace/lib/ace/mode/batchfile.js @@ -0,0 +1,61 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * + * Contributor(s): + * + * + * + * ***** END LICENSE BLOCK ***** */ + +/* + THIS FILE WAS AUTOGENERATED BY mode.tmpl.js +*/ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextMode = require("./text").Mode; +var BatchFileHighlightRules = require("./batchfile_highlight_rules").BatchFileHighlightRules; +var FoldMode = require("./folding/cstyle").FoldMode; + +var Mode = function() { + this.HighlightRules = BatchFileHighlightRules; + this.foldingRules = new FoldMode(); +}; +oop.inherits(Mode, TextMode); + +(function() { + this.lineCommentStart = "::"; + this.blockComment = ""; + this.$id = "ace/mode/batchfile"; +}).call(Mode.prototype); + +exports.Mode = Mode; +}); \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/batchfile_highlight_rules.js b/node_modules/ace/lib/ace/mode/batchfile_highlight_rules.js new file mode 100644 index 00000000..be0380d8 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/batchfile_highlight_rules.js @@ -0,0 +1,97 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +/* This file was autogenerated from C:\Users\LED\AppData\Roaming\Sublime Text 2\Packages\Batch File\Batch File.tmLanguage (uuid: ) */ +/**************************************************************************************** + * IT MIGHT NOT BE PERFECT ...But it's a good start from an existing *.tmlanguage file. * + * fileTypes * + ****************************************************************************************/ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + +var BatchFileHighlightRules = function() { + // regexp must not have capturing parentheses. Use (?:) instead. + // regexps are ordered -> the first match is used + + this.$rules = { start: + [ { token: 'keyword.command.dosbatch', + regex: '\\b(?:append|assoc|at|attrib|break|cacls|cd|chcp|chdir|chkdsk|chkntfs|cls|cmd|color|comp|compact|convert|copy|date|del|dir|diskcomp|diskcopy|doskey|echo|endlocal|erase|fc|find|findstr|format|ftype|graftabl|help|keyb|label|md|mkdir|mode|more|move|path|pause|popd|print|prompt|pushd|rd|recover|ren|rename|replace|restore|rmdir|set|setlocal|shift|sort|start|subst|time|title|tree|type|ver|verify|vol|xcopy)\\b', + caseInsensitive: true }, + { token: 'keyword.control.statement.dosbatch', + regex: '\\b(?:goto|call|exit)\\b', + caseInsensitive: true }, + { token: 'keyword.control.conditional.if.dosbatch', + regex: '\\bif\\s+not\\s+(?:exist|defined|errorlevel|cmdextversion)\\b', + caseInsensitive: true }, + { token: 'keyword.control.conditional.dosbatch', + regex: '\\b(?:if|else)\\b', + caseInsensitive: true }, + { token: 'keyword.control.repeat.dosbatch', + regex: '\\bfor\\b', + caseInsensitive: true }, + { token: 'keyword.operator.dosbatch', + regex: '\\b(?:EQU|NEQ|LSS|LEQ|GTR|GEQ)\\b' }, + { token: ['doc.comment', 'comment'], + regex: '(?:^|\\b)(rem)($|\\s.*$)', + caseInsensitive: true }, + { token: 'comment.line.colons.dosbatch', + regex: '::.*$' }, + { include: 'variable' }, + { token: 'punctuation.definition.string.begin.shell', + regex: '"', + push: [ + { token: 'punctuation.definition.string.end.shell', regex: '"', next: 'pop' }, + { include: 'variable' }, + { defaultToken: 'string.quoted.double.dosbatch' } ] }, + { token: 'keyword.operator.pipe.dosbatch', regex: '[|]' }, + { token: 'keyword.operator.redirect.shell', + regex: '&>|\\d*>&\\d*|\\d*(?:>>|>|<)|\\d*<&|\\d*<>' } ], + variable: [ + { token: 'constant.numeric', regex: '%%\\w+|%[*\\d]|%\\w+%'}, + { token: 'constant.numeric', regex: '%~\\d+'}, + { token: ['markup.list', 'constant.other', 'markup.list'], + regex: '(%)(\\w+)(%?)' }]} + + this.normalizeRules(); +}; + +BatchFileHighlightRules.metaData = { name: 'Batch File', + scopeName: 'source.dosbatch', + fileTypes: [ 'bat' ] } + + +oop.inherits(BatchFileHighlightRules, TextHighlightRules); + +exports.BatchFileHighlightRules = BatchFileHighlightRules; +}); \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/behaviour.js b/node_modules/ace/lib/ace/mode/behaviour.js new file mode 100644 index 00000000..c1c6cb15 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/behaviour.js @@ -0,0 +1,90 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var Behaviour = function() { + this.$behaviours = {}; +}; + +(function () { + + this.add = function (name, action, callback) { + switch (undefined) { + case this.$behaviours: + this.$behaviours = {}; + case this.$behaviours[name]: + this.$behaviours[name] = {}; + } + this.$behaviours[name][action] = callback; + } + + this.addBehaviours = function (behaviours) { + for (var key in behaviours) { + for (var action in behaviours[key]) { + this.add(key, action, behaviours[key][action]); + } + } + } + + this.remove = function (name) { + if (this.$behaviours && this.$behaviours[name]) { + delete this.$behaviours[name]; + } + } + + this.inherit = function (mode, filter) { + if (typeof mode === "function") { + var behaviours = new mode().getBehaviours(filter); + } else { + var behaviours = mode.getBehaviours(filter); + } + this.addBehaviours(behaviours); + } + + this.getBehaviours = function (filter) { + if (!filter) { + return this.$behaviours; + } else { + var ret = {} + for (var i = 0; i < filter.length; i++) { + if (this.$behaviours[filter[i]]) { + ret[filter[i]] = this.$behaviours[filter[i]]; + } + } + return ret; + } + } + +}).call(Behaviour.prototype); + +exports.Behaviour = Behaviour; +}); diff --git a/node_modules/ace/lib/ace/mode/behaviour/behaviour_test.js b/node_modules/ace/lib/ace/mode/behaviour/behaviour_test.js new file mode 100644 index 00000000..ba0a5041 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/behaviour/behaviour_test.js @@ -0,0 +1,139 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +if (typeof process !== "undefined") { + require("amd-loader"); +} + +define(function(require, exports, module) { +"use strict"; + +require("../../multi_select"); +var assert = require("../../test/assertions"); +var Range = require("../../range").Range; +var Editor = require("../../editor").Editor; +var EditSession = require("../../edit_session").EditSession; +var MockRenderer = require("../../test/mockrenderer").MockRenderer; +var JavaScriptMode = require("../javascript").Mode; +var editor; +var exec = function(name, times, args) { + do { + editor.commands.exec(name, editor, args); + } while(times --> 1); +}; +var testRanges = function(str) { + assert.equal(editor.selection.getAllRanges() + "", str + ""); +}; + +module.exports = { + "test: cstyle": function() { + function testValue(line) { + assert.equal(editor.getValue(), Array(4).join(line + "\n")); + } + function testSelection(line, col, inc) { + editor.selection.rangeList.ranges.forEach(function(r) { + assert.range(r, line, col, line, col); + line += (inc || 1); + }); + } + var doc = new EditSession([ + "", + "", + "", + "" + ], new JavaScriptMode()); + editor = new Editor(new MockRenderer(), doc); + editor.setOption("behavioursEnabled", true); + + editor.navigateFileStart(); + exec("addCursorBelow", 2); + + exec("insertstring", 1, "if "); + + // pairing ( + exec("insertstring", 1, "("); + testValue("if ()"); + testSelection(0, 4); + exec("insertstring", 1, ")"); + testValue("if ()"); + testSelection(0, 5); + + // pairing [ + exec("gotoleft", 1); + exec("insertstring", 1, "["); + testValue("if ([])"); + testSelection(0, 5); + + exec("insertstring", 1, "]"); + testValue("if ([])"); + testSelection(0, 6); + + // test deletion + exec("gotoleft", 1); + exec("backspace", 1); + testValue("if ()"); + testSelection(0, 4); + + exec("gotolineend", 1); + exec("insertstring", 1, "{"); + testValue("if (){}"); + testSelection(0, 6); + + exec("insertstring", 1, "}"); + testValue("if (){}"); + testSelection(0, 7); + + exec("gotolinestart", 1); + exec("insertstring", 1, "("); + testValue("(if (){}"); + exec("backspace", 1); + + editor.setValue(""); + exec("insertstring", 1, "{"); + assert.equal(editor.getValue(), "{") + exec("insertstring", 1, "\n"); + assert.equal(editor.getValue(), "{\n \n}") + + editor.setValue(""); + exec("insertstring", 1, "("); + exec("insertstring", 1, '"'); + exec("insertstring", 1, '"'); + assert.equal(editor.getValue(), '("")'); + exec("backspace", 1); + exec("insertstring", 1, '"'); + assert.equal(editor.getValue(), '("")'); + } +}; + +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec(); +} diff --git a/node_modules/ace/lib/ace/mode/behaviour/css.js b/node_modules/ace/lib/ace/mode/behaviour/css.js new file mode 100644 index 00000000..1c35f744 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/behaviour/css.js @@ -0,0 +1,108 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../../lib/oop"); +var Behaviour = require("../behaviour").Behaviour; +var CstyleBehaviour = require("./cstyle").CstyleBehaviour; +var TokenIterator = require("../../token_iterator").TokenIterator; + +var CssBehaviour = function () { + + this.inherit(CstyleBehaviour); + + this.add("colon", "insertion", function (state, action, editor, session, text) { + if (text === ':') { + var cursor = editor.getCursorPosition(); + var iterator = new TokenIterator(session, cursor.row, cursor.column); + var token = iterator.getCurrentToken(); + if (token && token.value.match(/\s+/)) { + token = iterator.stepBackward(); + } + if (token && token.type === 'support.type') { + var line = session.doc.getLine(cursor.row); + var rightChar = line.substring(cursor.column, cursor.column + 1); + if (rightChar === ':') { + return { + text: '', + selection: [1, 1] + } + } + if (!line.substring(cursor.column).match(/^\s*;/)) { + return { + text: ':;', + selection: [1, 1] + } + } + } + } + }); + + this.add("colon", "deletion", function (state, action, editor, session, range) { + var selected = session.doc.getTextRange(range); + if (!range.isMultiLine() && selected === ':') { + var cursor = editor.getCursorPosition(); + var iterator = new TokenIterator(session, cursor.row, cursor.column); + var token = iterator.getCurrentToken(); + if (token && token.value.match(/\s+/)) { + token = iterator.stepBackward(); + } + if (token && token.type === 'support.type') { + var line = session.doc.getLine(range.start.row); + var rightChar = line.substring(range.end.column, range.end.column + 1); + if (rightChar === ';') { + range.end.column ++; + return range; + } + } + } + }); + + this.add("semicolon", "insertion", function (state, action, editor, session, text) { + if (text === ';') { + var cursor = editor.getCursorPosition(); + var line = session.doc.getLine(cursor.row); + var rightChar = line.substring(cursor.column, cursor.column + 1); + if (rightChar === ';') { + return { + text: '', + selection: [1, 1] + } + } + } + }); + +} +oop.inherits(CssBehaviour, CstyleBehaviour); + +exports.CssBehaviour = CssBehaviour; +}); diff --git a/node_modules/ace/lib/ace/mode/behaviour/cstyle.js b/node_modules/ace/lib/ace/mode/behaviour/cstyle.js new file mode 100644 index 00000000..be1a4a46 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/behaviour/cstyle.js @@ -0,0 +1,392 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../../lib/oop"); +var Behaviour = require("../behaviour").Behaviour; +var TokenIterator = require("../../token_iterator").TokenIterator; +var lang = require("../../lib/lang"); + +var SAFE_INSERT_IN_TOKENS = + ["text", "paren.rparen", "punctuation.operator"]; +var SAFE_INSERT_BEFORE_TOKENS = + ["text", "paren.rparen", "punctuation.operator", "comment"]; + +var context; +var contextCache = {}; +var initContext = function(editor) { + var id = -1; + if (editor.multiSelect) { + id = editor.selection.index; + if (contextCache.rangeCount != editor.multiSelect.rangeCount) + contextCache = {rangeCount: editor.multiSelect.rangeCount}; + } + if (contextCache[id]) + return context = contextCache[id]; + context = contextCache[id] = { + autoInsertedBrackets: 0, + autoInsertedRow: -1, + autoInsertedLineEnd: "", + maybeInsertedBrackets: 0, + maybeInsertedRow: -1, + maybeInsertedLineStart: "", + maybeInsertedLineEnd: "" + }; +}; + +var CstyleBehaviour = function() { + this.add("braces", "insertion", function(state, action, editor, session, text) { + var cursor = editor.getCursorPosition(); + var line = session.doc.getLine(cursor.row); + if (text == '{') { + initContext(editor); + var selection = editor.getSelectionRange(); + var selected = session.doc.getTextRange(selection); + if (selected !== "" && selected !== "{" && editor.getWrapBehavioursEnabled()) { + return { + text: '{' + selected + '}', + selection: false + }; + } else if (CstyleBehaviour.isSaneInsertion(editor, session)) { + if (/[\]\}\)]/.test(line[cursor.column]) || editor.inMultiSelectMode) { + CstyleBehaviour.recordAutoInsert(editor, session, "}"); + return { + text: '{}', + selection: [1, 1] + }; + } else { + CstyleBehaviour.recordMaybeInsert(editor, session, "{"); + return { + text: '{', + selection: [1, 1] + }; + } + } + } else if (text == '}') { + initContext(editor); + var rightChar = line.substring(cursor.column, cursor.column + 1); + if (rightChar == '}') { + var matching = session.$findOpeningBracket('}', {column: cursor.column + 1, row: cursor.row}); + if (matching !== null && CstyleBehaviour.isAutoInsertedClosing(cursor, line, text)) { + CstyleBehaviour.popAutoInsertedClosing(); + return { + text: '', + selection: [1, 1] + }; + } + } + } else if (text == "\n" || text == "\r\n") { + initContext(editor); + var closing = ""; + if (CstyleBehaviour.isMaybeInsertedClosing(cursor, line)) { + closing = lang.stringRepeat("}", context.maybeInsertedBrackets); + CstyleBehaviour.clearMaybeInsertedClosing(); + } + var rightChar = line.substring(cursor.column, cursor.column + 1); + if (rightChar === '}') { + var openBracePos = session.findMatchingBracket({row: cursor.row, column: cursor.column+1}, '}'); + if (!openBracePos) + return null; + var next_indent = this.$getIndent(session.getLine(openBracePos.row)); + } else if (closing) { + var next_indent = this.$getIndent(line); + } else { + CstyleBehaviour.clearMaybeInsertedClosing(); + return; + } + var indent = next_indent + session.getTabString(); + + return { + text: '\n' + indent + '\n' + next_indent + closing, + selection: [1, indent.length, 1, indent.length] + }; + } else { + CstyleBehaviour.clearMaybeInsertedClosing(); + } + }); + + this.add("braces", "deletion", function(state, action, editor, session, range) { + var selected = session.doc.getTextRange(range); + if (!range.isMultiLine() && selected == '{') { + initContext(editor); + var line = session.doc.getLine(range.start.row); + var rightChar = line.substring(range.end.column, range.end.column + 1); + if (rightChar == '}') { + range.end.column++; + return range; + } else { + context.maybeInsertedBrackets--; + } + } + }); + + this.add("parens", "insertion", function(state, action, editor, session, text) { + if (text == '(') { + initContext(editor); + var selection = editor.getSelectionRange(); + var selected = session.doc.getTextRange(selection); + if (selected !== "" && editor.getWrapBehavioursEnabled()) { + return { + text: '(' + selected + ')', + selection: false + }; + } else if (CstyleBehaviour.isSaneInsertion(editor, session)) { + CstyleBehaviour.recordAutoInsert(editor, session, ")"); + return { + text: '()', + selection: [1, 1] + }; + } + } else if (text == ')') { + initContext(editor); + var cursor = editor.getCursorPosition(); + var line = session.doc.getLine(cursor.row); + var rightChar = line.substring(cursor.column, cursor.column + 1); + if (rightChar == ')') { + var matching = session.$findOpeningBracket(')', {column: cursor.column + 1, row: cursor.row}); + if (matching !== null && CstyleBehaviour.isAutoInsertedClosing(cursor, line, text)) { + CstyleBehaviour.popAutoInsertedClosing(); + return { + text: '', + selection: [1, 1] + }; + } + } + } + }); + + this.add("parens", "deletion", function(state, action, editor, session, range) { + var selected = session.doc.getTextRange(range); + if (!range.isMultiLine() && selected == '(') { + initContext(editor); + var line = session.doc.getLine(range.start.row); + var rightChar = line.substring(range.start.column + 1, range.start.column + 2); + if (rightChar == ')') { + range.end.column++; + return range; + } + } + }); + + this.add("brackets", "insertion", function(state, action, editor, session, text) { + if (text == '[') { + initContext(editor); + var selection = editor.getSelectionRange(); + var selected = session.doc.getTextRange(selection); + if (selected !== "" && editor.getWrapBehavioursEnabled()) { + return { + text: '[' + selected + ']', + selection: false + }; + } else if (CstyleBehaviour.isSaneInsertion(editor, session)) { + CstyleBehaviour.recordAutoInsert(editor, session, "]"); + return { + text: '[]', + selection: [1, 1] + }; + } + } else if (text == ']') { + initContext(editor); + var cursor = editor.getCursorPosition(); + var line = session.doc.getLine(cursor.row); + var rightChar = line.substring(cursor.column, cursor.column + 1); + if (rightChar == ']') { + var matching = session.$findOpeningBracket(']', {column: cursor.column + 1, row: cursor.row}); + if (matching !== null && CstyleBehaviour.isAutoInsertedClosing(cursor, line, text)) { + CstyleBehaviour.popAutoInsertedClosing(); + return { + text: '', + selection: [1, 1] + }; + } + } + } + }); + + this.add("brackets", "deletion", function(state, action, editor, session, range) { + var selected = session.doc.getTextRange(range); + if (!range.isMultiLine() && selected == '[') { + initContext(editor); + var line = session.doc.getLine(range.start.row); + var rightChar = line.substring(range.start.column + 1, range.start.column + 2); + if (rightChar == ']') { + range.end.column++; + return range; + } + } + }); + + this.add("string_dquotes", "insertion", function(state, action, editor, session, text) { + if (text == '"' || text == "'") { + initContext(editor); + var quote = text; + var selection = editor.getSelectionRange(); + var selected = session.doc.getTextRange(selection); + if (selected !== "" && selected !== "'" && selected != '"' && editor.getWrapBehavioursEnabled()) { + return { + text: quote + selected + quote, + selection: false + }; + } else { + var cursor = editor.getCursorPosition(); + var line = session.doc.getLine(cursor.row); + var leftChar = line.substring(cursor.column-1, cursor.column); + var rightChar = line.substring(cursor.column, cursor.column + 1); + + var token = session.getTokenAt(cursor.row, cursor.column); + var rightToken = session.getTokenAt(cursor.row, cursor.column + 1); + // We're escaped. + if (leftChar == "\\" && token && /escape/.test(token.type)) + return null; + + var stringBefore = token && /string/.test(token.type); + var stringAfter = !rightToken || /string/.test(rightToken.type); + + var pair; + if (rightChar == quote) { + pair = stringBefore !== stringAfter; + } else { + if (stringBefore && !stringAfter) + return null; // wrap string with different quote + if (stringBefore && stringAfter) + return null; // do not pair quotes inside strings + var wordRe = session.$mode.tokenRe; + wordRe.lastIndex = 0; + var isWordBefore = wordRe.test(leftChar); + wordRe.lastIndex = 0; + var isWordAfter = wordRe.test(leftChar); + if (isWordBefore || isWordAfter) + return null; // before or after alphanumeric + if (rightChar && !/[\s;,.})\]\\]/.test(rightChar)) + return null; // there is rightChar and it isn't closing + pair = true; + } + return { + text: pair ? quote + quote : "", + selection: [1,1] + }; + } + } + }); + + this.add("string_dquotes", "deletion", function(state, action, editor, session, range) { + var selected = session.doc.getTextRange(range); + if (!range.isMultiLine() && (selected == '"' || selected == "'")) { + initContext(editor); + var line = session.doc.getLine(range.start.row); + var rightChar = line.substring(range.start.column + 1, range.start.column + 2); + if (rightChar == selected) { + range.end.column++; + return range; + } + } + }); + +}; + + +CstyleBehaviour.isSaneInsertion = function(editor, session) { + var cursor = editor.getCursorPosition(); + var iterator = new TokenIterator(session, cursor.row, cursor.column); + + // Don't insert in the middle of a keyword/identifier/lexical + if (!this.$matchTokenType(iterator.getCurrentToken() || "text", SAFE_INSERT_IN_TOKENS)) { + // Look ahead in case we're at the end of a token + var iterator2 = new TokenIterator(session, cursor.row, cursor.column + 1); + if (!this.$matchTokenType(iterator2.getCurrentToken() || "text", SAFE_INSERT_IN_TOKENS)) + return false; + } + + // Only insert in front of whitespace/comments + iterator.stepForward(); + return iterator.getCurrentTokenRow() !== cursor.row || + this.$matchTokenType(iterator.getCurrentToken() || "text", SAFE_INSERT_BEFORE_TOKENS); +}; + +CstyleBehaviour.$matchTokenType = function(token, types) { + return types.indexOf(token.type || token) > -1; +}; + +CstyleBehaviour.recordAutoInsert = function(editor, session, bracket) { + var cursor = editor.getCursorPosition(); + var line = session.doc.getLine(cursor.row); + // Reset previous state if text or context changed too much + if (!this.isAutoInsertedClosing(cursor, line, context.autoInsertedLineEnd[0])) + context.autoInsertedBrackets = 0; + context.autoInsertedRow = cursor.row; + context.autoInsertedLineEnd = bracket + line.substr(cursor.column); + context.autoInsertedBrackets++; +}; + +CstyleBehaviour.recordMaybeInsert = function(editor, session, bracket) { + var cursor = editor.getCursorPosition(); + var line = session.doc.getLine(cursor.row); + if (!this.isMaybeInsertedClosing(cursor, line)) + context.maybeInsertedBrackets = 0; + context.maybeInsertedRow = cursor.row; + context.maybeInsertedLineStart = line.substr(0, cursor.column) + bracket; + context.maybeInsertedLineEnd = line.substr(cursor.column); + context.maybeInsertedBrackets++; +}; + +CstyleBehaviour.isAutoInsertedClosing = function(cursor, line, bracket) { + return context.autoInsertedBrackets > 0 && + cursor.row === context.autoInsertedRow && + bracket === context.autoInsertedLineEnd[0] && + line.substr(cursor.column) === context.autoInsertedLineEnd; +}; + +CstyleBehaviour.isMaybeInsertedClosing = function(cursor, line) { + return context.maybeInsertedBrackets > 0 && + cursor.row === context.maybeInsertedRow && + line.substr(cursor.column) === context.maybeInsertedLineEnd && + line.substr(0, cursor.column) == context.maybeInsertedLineStart; +}; + +CstyleBehaviour.popAutoInsertedClosing = function() { + context.autoInsertedLineEnd = context.autoInsertedLineEnd.substr(1); + context.autoInsertedBrackets--; +}; + +CstyleBehaviour.clearMaybeInsertedClosing = function() { + if (context) { + context.maybeInsertedBrackets = 0; + context.maybeInsertedRow = -1; + } +}; + + + +oop.inherits(CstyleBehaviour, Behaviour); + +exports.CstyleBehaviour = CstyleBehaviour; +}); diff --git a/node_modules/ace/lib/ace/mode/behaviour/html.js b/node_modules/ace/lib/ace/mode/behaviour/html.js new file mode 100644 index 00000000..181655c0 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/behaviour/html.js @@ -0,0 +1,46 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../../lib/oop"); +var XmlBehaviour = require("../behaviour/xml").XmlBehaviour; + +var HtmlBehaviour = function () { + + XmlBehaviour.call(this); + +}; + +oop.inherits(HtmlBehaviour, XmlBehaviour); + +exports.HtmlBehaviour = HtmlBehaviour; +}); diff --git a/node_modules/ace/lib/ace/mode/behaviour/xml.js b/node_modules/ace/lib/ace/mode/behaviour/xml.js new file mode 100644 index 00000000..fc46a240 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/behaviour/xml.js @@ -0,0 +1,202 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../../lib/oop"); +var Behaviour = require("../behaviour").Behaviour; +var TokenIterator = require("../../token_iterator").TokenIterator; +var lang = require("../../lib/lang"); + +function is(token, type) { + return token.type.lastIndexOf(type + ".xml") > -1; +} + +var XmlBehaviour = function () { + + this.add("string_dquotes", "insertion", function (state, action, editor, session, text) { + if (text == '"' || text == "'") { + var quote = text; + var selected = session.doc.getTextRange(editor.getSelectionRange()); + if (selected !== "" && selected !== "'" && selected != '"' && editor.getWrapBehavioursEnabled()) { + return { + text: quote + selected + quote, + selection: false + }; + } + + var cursor = editor.getCursorPosition(); + var line = session.doc.getLine(cursor.row); + var rightChar = line.substring(cursor.column, cursor.column + 1); + var iterator = new TokenIterator(session, cursor.row, cursor.column); + var token = iterator.getCurrentToken(); + + if (rightChar == quote && (is(token, "attribute-value") || is(token, "string"))) { + // Ignore input and move right one if we're typing over the closing quote. + return { + text: "", + selection: [1, 1] + }; + } + + if (!token) + token = iterator.stepBackward(); + + if (!token) + return; + + while (is(token, "tag-whitespace") || is(token, "whitespace")) { + token = iterator.stepBackward(); + } + var rightSpace = !rightChar || rightChar.match(/\s/); + if (is(token, "attribute-equals") && (rightSpace || rightChar == '>') || (is(token, "decl-attribute-equals") && (rightSpace || rightChar == '?'))) { + return { + text: quote + quote, + selection: [1, 1] + }; + } + } + }); + + this.add("string_dquotes", "deletion", function(state, action, editor, session, range) { + var selected = session.doc.getTextRange(range); + if (!range.isMultiLine() && (selected == '"' || selected == "'")) { + var line = session.doc.getLine(range.start.row); + var rightChar = line.substring(range.start.column + 1, range.start.column + 2); + if (rightChar == selected) { + range.end.column++; + return range; + } + } + }); + + this.add("autoclosing", "insertion", function (state, action, editor, session, text) { + if (text == '>') { + var position = editor.getCursorPosition(); + var iterator = new TokenIterator(session, position.row, position.column); + var token = iterator.getCurrentToken() || iterator.stepBackward(); + + // exit if we're not in a tag + if (!token || !(is(token, "tag-name") || is(token, "tag-whitespace") || is(token, "attribute-name") || is(token, "attribute-equals") || is(token, "attribute-value"))) + return; + + // exit if we're inside of a quoted attribute value + if (is(token, "reference.attribute-value")) + return; + if (is(token, "attribute-value")) { + var firstChar = token.value.charAt(0); + if (firstChar == '"' || firstChar == "'") { + var lastChar = token.value.charAt(token.value.length - 1); + var tokenEnd = iterator.getCurrentTokenColumn() + token.value.length; + if (tokenEnd > position.column || tokenEnd == position.column && firstChar != lastChar) + return; + } + } + + // find tag name + while (!is(token, "tag-name")) { + token = iterator.stepBackward(); + } + + var tokenRow = iterator.getCurrentTokenRow(); + var tokenColumn = iterator.getCurrentTokenColumn(); + + // exit if the tag is ending + if (is(iterator.stepBackward(), "end-tag-open")) + return; + + var element = token.value; + if (tokenRow == position.row) + element = element.substring(0, position.column - tokenColumn); + + if (this.voidElements.hasOwnProperty(element.toLowerCase())) + return; + + return { + text: ">" + "", + selection: [1, 1] + }; + } + }); + + this.add("autoindent", "insertion", function (state, action, editor, session, text) { + if (text == "\n") { + var cursor = editor.getCursorPosition(); + var line = session.getLine(cursor.row); + var iterator = new TokenIterator(session, cursor.row, cursor.column); + var token = iterator.getCurrentToken(); + + if (token && token.type.indexOf("tag-close") !== -1) { + //get tag name + while (token && token.type.indexOf("tag-name") === -1) { + token = iterator.stepBackward(); + } + + if (!token) { + return; + } + + var tag = token.value; + var row = iterator.getCurrentTokenRow(); + + //don't indent after closing tag + token = iterator.stepBackward(); + if (!token || token.type.indexOf("end-tag") !== -1) { + return; + } + + if (this.voidElements && !this.voidElements[tag]) { + var nextToken = session.getTokenAt(cursor.row, cursor.column+1); + var line = session.getLine(row); + var nextIndent = this.$getIndent(line); + var indent = nextIndent + session.getTabString(); + + if (nextToken && nextToken.value === "') { + var position = editor.getCursorPosition(); + var iterator = new TokenIterator(session, position.row, position.column); + var token = iterator.getCurrentToken(); + var atCursor = false; + var state = JSON.parse(state).pop(); + if ((token && token.value === '>') || state !== "StartTag") return; + if (!token || !hasType(token, 'meta.tag') && !(hasType(token, 'text') && token.value.match('/'))){ + do { + token = iterator.stepBackward(); + } while (token && (hasType(token, 'string') || hasType(token, 'keyword.operator') || hasType(token, 'entity.attribute-name') || hasType(token, 'text'))); + } else { + atCursor = true; + } + var previous = iterator.stepBackward(); + if (!token || !hasType(token, 'meta.tag') || (previous !== null && previous.value.match('/'))) { + return + } + var tag = token.value.substring(1); + if (atCursor){ + var tag = tag.substring(0, position.column - token.start); + } + + return { + text: '>' + '', + selection: [1, 1] + } + } + }); + + } + oop.inherits(XQueryBehaviour, Behaviour); + + exports.XQueryBehaviour = XQueryBehaviour; +}); diff --git a/node_modules/ace/lib/ace/mode/c9search.js b/node_modules/ace/lib/ace/mode/c9search.js new file mode 100644 index 00000000..3286456a --- /dev/null +++ b/node_modules/ace/lib/ace/mode/c9search.js @@ -0,0 +1,67 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextMode = require("./text").Mode; +var C9SearchHighlightRules = require("./c9search_highlight_rules").C9SearchHighlightRules; +var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent; +var C9StyleFoldMode = require("./folding/c9search").FoldMode; + +var Mode = function() { + this.HighlightRules = C9SearchHighlightRules; + this.$outdent = new MatchingBraceOutdent(); + this.foldingRules = new C9StyleFoldMode(); +}; +oop.inherits(Mode, TextMode); + +(function() { + + this.getNextLineIndent = function(state, line, tab) { + var indent = this.$getIndent(line); + return indent; + }; + + this.checkOutdent = function(state, line, input) { + return this.$outdent.checkOutdent(line, input); + }; + + this.autoOutdent = function(state, doc, row) { + this.$outdent.autoOutdent(doc, row); + }; + + this.$id = "ace/mode/c9search"; +}).call(Mode.prototype); + +exports.Mode = Mode; + +}); diff --git a/node_modules/ace/lib/ace/mode/c9search_highlight_rules.js b/node_modules/ace/lib/ace/mode/c9search_highlight_rules.js new file mode 100644 index 00000000..43ec4bf8 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/c9search_highlight_rules.js @@ -0,0 +1,182 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var lang = require("../lib/lang"); +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + +function safeCreateRegexp(source, flag) { + try { + return new RegExp(source, flag); + } catch(e) {} +} + +var C9SearchHighlightRules = function() { + + // regexp must not have capturing parentheses. Use (?:) instead. + // regexps are ordered -> the first match is used + this.$rules = { + "start" : [ + { + tokenNames : ["c9searchresults.constant.numeric", "c9searchresults.text", "c9searchresults.text", "c9searchresults.keyword"], + regex : "(^\\s+[0-9]+)(:\\s)(.+)", + onMatch : function(val, state, stack) { + var values = this.splitRegex.exec(val); + var types = this.tokenNames; + var tokens = [{ + type: types[0], + value: values[1] + },{ + type: types[1], + value: values[2] + }]; + + var regex = stack[1]; + var str = values[3]; + + var m; + var last = 0; + if (regex && regex.exec) { + regex.lastIndex = 0; + while (m = regex.exec(str)) { + var skipped = str.substring(last, m.index); + last = regex.lastIndex; + if (skipped) + tokens.push({type: types[2], value: skipped}); + if (m[0]) + tokens.push({type: types[3], value: m[0]}); + else if (!skipped) + break; + } + } + if (last < str.length) + tokens.push({type: types[2], value: str.substr(last)}); + return tokens; + } + }, + { + token : ["string", "text"], // single line + regex : "(\\S.*)(:$)" + }, + { + regex : "Searching for .*$", + onMatch: function(val, state, stack) { + var parts = val.split("\x01"); + if (parts.length < 3) + return "text"; + + var options, search, replace; + + var i = 0; + var tokens = [{ + value: parts[i++] + "'", + type: "text" + }, { + value: search = parts[i++], + type: "text" // "c9searchresults.keyword" + }, { + value: "'" + parts[i++], + type: "text" + }]; + + // replaced + if (parts[2] !== " in") { + replace = parts[i]; + tokens.push({ + value: "'" + parts[i++] + "'", + type: "text" + }, { + value: parts[i++], + type: "text" + }); + } + // path + tokens.push({ + value: " " + parts[i++] + " ", + type: "text" + }); + // options + if (parts[i+1]) { + options = parts[i+1]; + tokens.push({ + value: "(" + parts[i+1] + ")", + type: "text" + }); + i += 1; + } else { + i -= 1; + } + while (i++ < parts.length) { + parts[i] && tokens.push({ + value: parts[i], + type: "text" + }); + } + + if (replace) { + search = replace; + options = ""; + } + + if (search) { + if (!/regex/.test(options)) + search = lang.escapeRegExp(search); + if (/whole/.test(options)) + search = "\\b" + search + "\\b"; + } + + var regex = search && safeCreateRegexp( + "(" + search + ")", + / sensitive/.test(options) ? "g" : "ig" + ); + if (regex) { + stack[0] = state; + stack[1] = regex; + } + + return tokens; + } + }, + { + regex : "\\d+", + token: "constant.numeric" + } + ] + }; +}; + +oop.inherits(C9SearchHighlightRules, TextHighlightRules); + +exports.C9SearchHighlightRules = C9SearchHighlightRules; + +}); \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/c_cpp.js b/node_modules/ace/lib/ace/mode/c_cpp.js new file mode 100644 index 00000000..a2dc133f --- /dev/null +++ b/node_modules/ace/lib/ace/mode/c_cpp.js @@ -0,0 +1,101 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextMode = require("./text").Mode; +var c_cppHighlightRules = require("./c_cpp_highlight_rules").c_cppHighlightRules; +var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent; +var Range = require("../range").Range; +var CstyleBehaviour = require("./behaviour/cstyle").CstyleBehaviour; +var CStyleFoldMode = require("./folding/cstyle").FoldMode; + +var Mode = function() { + this.HighlightRules = c_cppHighlightRules; + + this.$outdent = new MatchingBraceOutdent(); + this.$behaviour = new CstyleBehaviour(); + + this.foldingRules = new CStyleFoldMode(); +}; +oop.inherits(Mode, TextMode); + +(function() { + + this.lineCommentStart = "//"; + this.blockComment = {start: "/*", end: "*/"}; + + this.getNextLineIndent = function(state, line, tab) { + var indent = this.$getIndent(line); + + var tokenizedLine = this.getTokenizer().getLineTokens(line, state); + var tokens = tokenizedLine.tokens; + var endState = tokenizedLine.state; + + if (tokens.length && tokens[tokens.length-1].type == "comment") { + return indent; + } + + if (state == "start") { + var match = line.match(/^.*[\{\(\[]\s*$/); + if (match) { + indent += tab; + } + } else if (state == "doc-start") { + if (endState == "start") { + return ""; + } + var match = line.match(/^\s*(\/?)\*/); + if (match) { + if (match[1]) { + indent += " "; + } + indent += "* "; + } + } + + return indent; + }; + + this.checkOutdent = function(state, line, input) { + return this.$outdent.checkOutdent(line, input); + }; + + this.autoOutdent = function(state, doc, row) { + this.$outdent.autoOutdent(doc, row); + }; + + this.$id = "ace/mode/c_cpp"; +}).call(Mode.prototype); + +exports.Mode = Mode; +}); diff --git a/node_modules/ace/lib/ace/mode/c_cpp_highlight_rules.js b/node_modules/ace/lib/ace/mode/c_cpp_highlight_rules.js new file mode 100644 index 00000000..b5a29799 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/c_cpp_highlight_rules.js @@ -0,0 +1,196 @@ +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var DocCommentHighlightRules = require("./doc_comment_highlight_rules").DocCommentHighlightRules; +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + +// used by objective-c +var cFunctions = exports.cFunctions = "\\b(?:hypot(?:f|l)?|s(?:scanf|ystem|nprintf|ca(?:nf|lb(?:n(?:f|l)?|ln(?:f|l)?))|i(?:n(?:h(?:f|l)?|f|l)?|gn(?:al|bit))|tr(?:s(?:tr|pn)|nc(?:py|at|mp)|c(?:spn|hr|oll|py|at|mp)|to(?:imax|d|u(?:l(?:l)?|max)|k|f|l(?:d|l)?)|error|pbrk|ftime|len|rchr|xfrm)|printf|et(?:jmp|vbuf|locale|buf)|qrt(?:f|l)?|w(?:scanf|printf)|rand)|n(?:e(?:arbyint(?:f|l)?|xt(?:toward(?:f|l)?|after(?:f|l)?))|an(?:f|l)?)|c(?:s(?:in(?:h(?:f|l)?|f|l)?|qrt(?:f|l)?)|cos(?:h(?:f)?|f|l)?|imag(?:f|l)?|t(?:ime|an(?:h(?:f|l)?|f|l)?)|o(?:s(?:h(?:f|l)?|f|l)?|nj(?:f|l)?|pysign(?:f|l)?)|p(?:ow(?:f|l)?|roj(?:f|l)?)|e(?:il(?:f|l)?|xp(?:f|l)?)|l(?:o(?:ck|g(?:f|l)?)|earerr)|a(?:sin(?:h(?:f|l)?|f|l)?|cos(?:h(?:f|l)?|f|l)?|tan(?:h(?:f|l)?|f|l)?|lloc|rg(?:f|l)?|bs(?:f|l)?)|real(?:f|l)?|brt(?:f|l)?)|t(?:ime|o(?:upper|lower)|an(?:h(?:f|l)?|f|l)?|runc(?:f|l)?|gamma(?:f|l)?|mp(?:nam|file))|i(?:s(?:space|n(?:ormal|an)|cntrl|inf|digit|u(?:nordered|pper)|p(?:unct|rint)|finite|w(?:space|c(?:ntrl|type)|digit|upper|p(?:unct|rint)|lower|al(?:num|pha)|graph|xdigit|blank)|l(?:ower|ess(?:equal|greater)?)|al(?:num|pha)|gr(?:eater(?:equal)?|aph)|xdigit|blank)|logb(?:f|l)?|max(?:div|abs))|di(?:v|fftime)|_Exit|unget(?:c|wc)|p(?:ow(?:f|l)?|ut(?:s|c(?:har)?|wc(?:har)?)|error|rintf)|e(?:rf(?:c(?:f|l)?|f|l)?|x(?:it|p(?:2(?:f|l)?|f|l|m1(?:f|l)?)?))|v(?:s(?:scanf|nprintf|canf|printf|w(?:scanf|printf))|printf|f(?:scanf|printf|w(?:scanf|printf))|w(?:scanf|printf)|a_(?:start|copy|end|arg))|qsort|f(?:s(?:canf|e(?:tpos|ek))|close|tell|open|dim(?:f|l)?|p(?:classify|ut(?:s|c|w(?:s|c))|rintf)|e(?:holdexcept|set(?:e(?:nv|xceptflag)|round)|clearexcept|testexcept|of|updateenv|r(?:aiseexcept|ror)|get(?:e(?:nv|xceptflag)|round))|flush|w(?:scanf|ide|printf|rite)|loor(?:f|l)?|abs(?:f|l)?|get(?:s|c|pos|w(?:s|c))|re(?:open|e|ad|xp(?:f|l)?)|m(?:in(?:f|l)?|od(?:f|l)?|a(?:f|l|x(?:f|l)?)?))|l(?:d(?:iv|exp(?:f|l)?)|o(?:ngjmp|cal(?:time|econv)|g(?:1(?:p(?:f|l)?|0(?:f|l)?)|2(?:f|l)?|f|l|b(?:f|l)?)?)|abs|l(?:div|abs|r(?:int(?:f|l)?|ound(?:f|l)?))|r(?:int(?:f|l)?|ound(?:f|l)?)|gamma(?:f|l)?)|w(?:scanf|c(?:s(?:s(?:tr|pn)|nc(?:py|at|mp)|c(?:spn|hr|oll|py|at|mp)|to(?:imax|d|u(?:l(?:l)?|max)|k|f|l(?:d|l)?|mbs)|pbrk|ftime|len|r(?:chr|tombs)|xfrm)|to(?:b|mb)|rtomb)|printf|mem(?:set|c(?:hr|py|mp)|move))|a(?:s(?:sert|ctime|in(?:h(?:f|l)?|f|l)?)|cos(?:h(?:f|l)?|f|l)?|t(?:o(?:i|f|l(?:l)?)|exit|an(?:h(?:f|l)?|2(?:f|l)?|f|l)?)|b(?:s|ort))|g(?:et(?:s|c(?:har)?|env|wc(?:har)?)|mtime)|r(?:int(?:f|l)?|ound(?:f|l)?|e(?:name|alloc|wind|m(?:ove|quo(?:f|l)?|ainder(?:f|l)?))|a(?:nd|ise))|b(?:search|towc)|m(?:odf(?:f|l)?|em(?:set|c(?:hr|py|mp)|move)|ktime|alloc|b(?:s(?:init|towcs|rtowcs)|towc|len|r(?:towc|len))))\\b" + +var c_cppHighlightRules = function() { + + var keywordControls = ( + "break|case|continue|default|do|else|for|goto|if|_Pragma|" + + "return|switch|while|catch|operator|try|throw|using" + ); + + var storageType = ( + "asm|__asm__|auto|bool|_Bool|char|_Complex|double|enum|float|" + + "_Imaginary|int|long|short|signed|struct|typedef|union|unsigned|void|" + + "class|wchar_t|template" + ); + + var storageModifiers = ( + "const|extern|register|restrict|static|volatile|inline|private|" + + "protected|public|friend|explicit|virtual|export|mutable|typename|" + + "constexpr|new|delete" + ); + + var keywordOperators = ( + "and|and_eq|bitand|bitor|compl|not|not_eq|or|or_eq|typeid|xor|xor_eq" + + "const_cast|dynamic_cast|reinterpret_cast|static_cast|sizeof|namespace" + ); + + var builtinConstants = ( + "NULL|true|false|TRUE|FALSE" + ); + + var keywordMapper = this.$keywords = this.createKeywordMapper({ + "keyword.control" : keywordControls, + "storage.type" : storageType, + "storage.modifier" : storageModifiers, + "keyword.operator" : keywordOperators, + "variable.language": "this", + "constant.language": builtinConstants + }, "identifier"); + + var identifierRe = "[a-zA-Z\\$_\u00a1-\uffff][a-zA-Z\d\\$_\u00a1-\uffff]*\\b"; + + // regexp must not have capturing parentheses. Use (?:) instead. + // regexps are ordered -> the first match is used + + this.$rules = { + "start" : [ + { + token : "comment", + regex : "//", + next : "singleLineComment" + }, + DocCommentHighlightRules.getStartRule("doc-start"), + { + token : "comment", // multi line comment + regex : "\\/\\*", + next : "comment" + }, { + token : "string", // single line + regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]' + }, { + token : "string", // multi line string start + regex : '["].*\\\\$', + next : "qqstring" + }, { + token : "string", // single line + regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']" + }, { + token : "string", // multi line string start + regex : "['].*\\\\$", + next : "qstring" + }, { + token : "constant.numeric", // hex + regex : "0[xX][0-9a-fA-F]+(L|l|UL|ul|u|U|F|f|ll|LL|ull|ULL)?\\b" + }, { + token : "constant.numeric", // float + regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?(L|l|UL|ul|u|U|F|f|ll|LL|ull|ULL)?\\b" + }, { + token : "keyword", // pre-compiler directives + regex : "#\\s*(?:include|import|pragma|line|define|undef)\\b", + next : "directive" + }, { + token : "keyword", // special case pre-compiler directive + regex : "#\\s*(?:endif|if|ifdef|else|elif|ifndef)\\b" + }, { + token : "support.function.C99.c", + regex : cFunctions + }, { + token : keywordMapper, + regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b" + }, { + token : "keyword.operator", + regex : "!|\\$|%|&|\\*|\\-\\-|\\-|\\+\\+|\\+|~|==|=|!=|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\\|\\||\\?\\:|\\*=|%=|\\+=|\\-=|&=|\\^=|\\b(?:in|new|delete|typeof|void)" + }, { + token : "punctuation.operator", + regex : "\\?|\\:|\\,|\\;|\\." + }, { + token : "paren.lparen", + regex : "[[({]" + }, { + token : "paren.rparen", + regex : "[\\])}]" + }, { + token : "text", + regex : "\\s+" + } + ], + "comment" : [ + { + token : "comment", // closing comment + regex : ".*?\\*\\/", + next : "start" + }, { + token : "comment", // comment spanning whole line + regex : ".+" + } + ], + "singleLineComment" : [ + { + token : "comment", + regex : /\\$/, + next : "singleLineComment" + }, { + token : "comment", + regex : /$/, + next : "start" + }, { + defaultToken: "comment" + } + ], + "qqstring" : [ + { + token : "string", + regex : '(?:(?:\\\\.)|(?:[^"\\\\]))*?"', + next : "start" + }, { + defaultToken : "string" + } + ], + "qstring" : [ + { + token : "string", + regex : "(?:(?:\\\\.)|(?:[^'\\\\]))*?'", + next : "start" + }, { + defaultToken : "string" + } + ], + "directive" : [ + { + token : "constant.other.multiline", + regex : /\\/ + }, + { + token : "constant.other.multiline", + regex : /.*\\/ + }, + { + token : "constant.other", + regex : "\\s*<.+?>", + next : "start" + }, + { + token : "constant.other", // single line + regex : '\\s*["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]', + next : "start" + }, + { + token : "constant.other", // single line + regex : "\\s*['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']", + next : "start" + }, + // "\" implies multiline, while "/" implies comment + { + token : "constant.other", + regex : /[^\\\/]+/, + next : "start" + } + ] + }; + + this.embedRules(DocCommentHighlightRules, "doc-", + [ DocCommentHighlightRules.getEndRule("start") ]); +}; + +oop.inherits(c_cppHighlightRules, TextHighlightRules); + +exports.c_cppHighlightRules = c_cppHighlightRules; +}); diff --git a/node_modules/ace/lib/ace/mode/cirru.js b/node_modules/ace/lib/ace/mode/cirru.js new file mode 100644 index 00000000..5f1c4d9e --- /dev/null +++ b/node_modules/ace/lib/ace/mode/cirru.js @@ -0,0 +1,51 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2014, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextMode = require("./text").Mode; +var CirruHighlightRules = require("./cirru_highlight_rules").CirruHighlightRules; +var CoffeeFoldMode = require("./folding/coffee").FoldMode; + +var Mode = function() { + this.HighlightRules = CirruHighlightRules; + this.foldingRules = new CoffeeFoldMode(); +}; +oop.inherits(Mode, TextMode); + +(function() { + this.lineCommentStart = "--"; + this.$id = "ace/mode/cirru"; +}).call(Mode.prototype); + +exports.Mode = Mode; +}); diff --git a/node_modules/ace/lib/ace/mode/cirru_highlight_rules.js b/node_modules/ace/lib/ace/mode/cirru_highlight_rules.js new file mode 100644 index 00000000..737ec0be --- /dev/null +++ b/node_modules/ace/lib/ace/mode/cirru_highlight_rules.js @@ -0,0 +1,125 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2014, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + +// see http://cirru.org for more about this language +var CirruHighlightRules = function() { + this.$rules = { + start: [{ + token: 'constant.numeric', + regex: /[\d\.]+/ + }, { + token: 'comment.line.double-dash', + regex: /--/, + next: 'comment', + }, { + token: 'storage.modifier', + regex: /\(/, + }, { + token: 'storage.modifier', + regex: /\,/, + next: 'line', + }, { + token: 'support.function', + regex: /[^\(\)\"\s]+/, + next: 'line' + }, { + token: 'string.quoted.double', + regex: /"/, + next: 'string', + }, { + token: 'storage.modifier', + regex: /\)/, + }], + comment: [{ + token: 'comment.line.double-dash', + regex: /\ +[^\n]+/, + next: 'start', + }], + string: [{ + token: 'string.quoted.double', + regex: /"/, + next: 'line', + }, { + token: 'constant.character.escape', + regex: /\\/, + next: 'escape', + }, { + token: 'string.quoted.double', + regex: /[^\\\"]+/, + }], + escape: [{ + token: 'constant.character.escape', + regex: /./, + next: 'string', + }], + line: [{ + token: 'constant.numeric', + regex: /[\d\.]+/ + }, { + token: 'markup.raw', + regex: /^\s*/, + next: 'start', + }, { + token: 'storage.modifier', + regex: /\$/, + next: 'start', + }, { + token: 'variable.parameter', + regex: /[^\(\)\"\s]+/ + }, { + token: 'storage.modifier', + regex: /\(/, + next: 'start' + }, { + token: 'storage.modifier', + regex: /\)/, + }, { + token: 'markup.raw', + regex: /^\ */, + next: 'start', + }, { + token: 'string.quoted.double', + regex: /"/, + next: 'string', + }] + } + +}; + +oop.inherits(CirruHighlightRules, TextHighlightRules); + +exports.CirruHighlightRules = CirruHighlightRules; +}); diff --git a/node_modules/ace/lib/ace/mode/clojure.js b/node_modules/ace/lib/ace/mode/clojure.js new file mode 100644 index 00000000..ee44ac3e --- /dev/null +++ b/node_modules/ace/lib/ace/mode/clojure.js @@ -0,0 +1,128 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextMode = require("./text").Mode; +var ClojureHighlightRules = require("./clojure_highlight_rules").ClojureHighlightRules; +var MatchingParensOutdent = require("./matching_parens_outdent").MatchingParensOutdent; + +var Mode = function() { + this.HighlightRules = ClojureHighlightRules; + this.$outdent = new MatchingParensOutdent(); +}; +oop.inherits(Mode, TextMode); + +(function() { + + this.lineCommentStart = ";"; + this.minorIndentFunctions = ["defn", "defn-", "defmacro", "def", "deftest", "testing"]; + + this.$toIndent = function(str) { + return str.split('').map(function(ch) { + if (/\s/.exec(ch)) { + return ch; + } else { + return ' '; + } + }).join(''); + }; + + this.$calculateIndent = function(line, tab) { + var baseIndent = this.$getIndent(line); + var delta = 0; + var isParen, ch; + // Walk back from end of line, find matching braces + for (var i = line.length - 1; i >= 0; i--) { + ch = line[i]; + if (ch === '(') { + delta--; + isParen = true; + } else if (ch === '(' || ch === '[' || ch === '{') { + delta--; + isParen = false; + } else if (ch === ')' || ch === ']' || ch === '}') { + delta++; + } + if (delta < 0) { + break; + } + } + if (delta < 0 && isParen) { + // Were more brackets opened than closed and was a ( left open? + i += 1; + var iBefore = i; + var fn = ''; + while (true) { + ch = line[i]; + if (ch === ' ' || ch === '\t') { + if(this.minorIndentFunctions.indexOf(fn) !== -1) { + return this.$toIndent(line.substring(0, iBefore - 1) + tab); + } else { + return this.$toIndent(line.substring(0, i + 1)); + } + } else if (ch === undefined) { + return this.$toIndent(line.substring(0, iBefore - 1) + tab); + } + fn += line[i]; + i++; + } + } else if(delta < 0 && !isParen) { + // Were more brackets openend than closed and was it not a (? + return this.$toIndent(line.substring(0, i+1)); + } else if(delta > 0) { + // Mere more brackets closed than opened? Outdent. + baseIndent = baseIndent.substring(0, baseIndent.length - tab.length); + return baseIndent; + } else { + // Were they nicely matched? Just indent like line before. + return baseIndent; + } + }; + + this.getNextLineIndent = function(state, line, tab) { + return this.$calculateIndent(line, tab); + }; + + this.checkOutdent = function(state, line, input) { + return this.$outdent.checkOutdent(line, input); + }; + + this.autoOutdent = function(state, doc, row) { + this.$outdent.autoOutdent(doc, row); + }; + + this.$id = "ace/mode/clojure"; +}).call(Mode.prototype); + +exports.Mode = Mode; +}); diff --git a/node_modules/ace/lib/ace/mode/clojure_highlight_rules.js b/node_modules/ace/lib/ace/mode/clojure_highlight_rules.js new file mode 100644 index 00000000..f7e28d87 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/clojure_highlight_rules.js @@ -0,0 +1,200 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + + + +var ClojureHighlightRules = function() { + + var builtinFunctions = ( + '* *1 *2 *3 *agent* *allow-unresolved-vars* *assert* *clojure-version* ' + + '*command-line-args* *compile-files* *compile-path* *e *err* *file* ' + + '*flush-on-newline* *in* *macro-meta* *math-context* *ns* *out* ' + + '*print-dup* *print-length* *print-level* *print-meta* *print-readably* ' + + '*read-eval* *source-path* *use-context-classloader* ' + + '*warn-on-reflection* + - -> ->> .. / < <= = ' + + '== > > >= >= accessor aclone ' + + 'add-classpath add-watch agent agent-errors aget alength alias all-ns ' + + 'alter alter-meta! alter-var-root amap ancestors and apply areduce ' + + 'array-map aset aset-boolean aset-byte aset-char aset-double aset-float ' + + 'aset-int aset-long aset-short assert assoc assoc! assoc-in associative? ' + + 'atom await await-for await1 bases bean bigdec bigint binding bit-and ' + + 'bit-and-not bit-clear bit-flip bit-not bit-or bit-set bit-shift-left ' + + 'bit-shift-right bit-test bit-xor boolean boolean-array booleans ' + + 'bound-fn bound-fn* butlast byte byte-array bytes cast char char-array ' + + 'char-escape-string char-name-string char? chars chunk chunk-append ' + + 'chunk-buffer chunk-cons chunk-first chunk-next chunk-rest chunked-seq? ' + + 'class class? clear-agent-errors clojure-version coll? comment commute ' + + 'comp comparator compare compare-and-set! compile complement concat cond ' + + 'condp conj conj! cons constantly construct-proxy contains? count ' + + 'counted? create-ns create-struct cycle dec decimal? declare definline ' + + 'defmacro defmethod defmulti defn defn- defonce defstruct delay delay? ' + + 'deliver deref derive descendants destructure disj disj! dissoc dissoc! ' + + 'distinct distinct? doall doc dorun doseq dosync dotimes doto double ' + + 'double-array doubles drop drop-last drop-while empty empty? ensure ' + + 'enumeration-seq eval even? every? false? ffirst file-seq filter find ' + + 'find-doc find-ns find-var first float float-array float? floats flush ' + + 'fn fn? fnext for force format future future-call future-cancel ' + + 'future-cancelled? future-done? future? gen-class gen-interface gensym ' + + 'get get-in get-method get-proxy-class get-thread-bindings get-validator ' + + 'hash hash-map hash-set identical? identity if-let if-not ifn? import ' + + 'in-ns inc init-proxy instance? int int-array integer? interleave intern ' + + 'interpose into into-array ints io! isa? iterate iterator-seq juxt key ' + + 'keys keyword keyword? last lazy-cat lazy-seq let letfn line-seq list ' + + 'list* list? load load-file load-reader load-string loaded-libs locking ' + + 'long long-array longs loop macroexpand macroexpand-1 make-array ' + + 'make-hierarchy map map? mapcat max max-key memfn memoize merge ' + + 'merge-with meta method-sig methods min min-key mod name namespace neg? ' + + 'newline next nfirst nil? nnext not not-any? not-empty not-every? not= ' + + 'ns ns-aliases ns-imports ns-interns ns-map ns-name ns-publics ' + + 'ns-refers ns-resolve ns-unalias ns-unmap nth nthnext num number? odd? ' + + 'or parents partial partition pcalls peek persistent! pmap pop pop! ' + + 'pop-thread-bindings pos? pr pr-str prefer-method prefers ' + + 'primitives-classnames print print-ctor print-doc print-dup print-method ' + + 'print-namespace-doc print-simple print-special-doc print-str printf ' + + 'println println-str prn prn-str promise proxy proxy-call-with-super ' + + 'proxy-mappings proxy-name proxy-super push-thread-bindings pvalues quot ' + + 'rand rand-int range ratio? rational? rationalize re-find re-groups ' + + 're-matcher re-matches re-pattern re-seq read read-line read-string ' + + 'reduce ref ref-history-count ref-max-history ref-min-history ref-set ' + + 'refer refer-clojure release-pending-sends rem remove remove-method ' + + 'remove-ns remove-watch repeat repeatedly replace replicate require ' + + 'reset! reset-meta! resolve rest resultset-seq reverse reversible? rseq ' + + 'rsubseq second select-keys send send-off seq seq? seque sequence ' + + 'sequential? set set-validator! set? short short-array shorts ' + + 'shutdown-agents slurp some sort sort-by sorted-map sorted-map-by ' + + 'sorted-set sorted-set-by sorted? special-form-anchor special-symbol? ' + + 'split-at split-with str stream? string? struct struct-map subs subseq ' + + 'subvec supers swap! symbol symbol? sync syntax-symbol-anchor take ' + + 'take-last take-nth take-while test the-ns time to-array to-array-2d ' + + 'trampoline transient tree-seq true? type unchecked-add unchecked-dec ' + + 'unchecked-divide unchecked-inc unchecked-multiply unchecked-negate ' + + 'unchecked-remainder unchecked-subtract underive unquote ' + + 'unquote-splicing update-in update-proxy use val vals var-get var-set ' + + 'var? vary-meta vec vector vector? when when-first when-let when-not ' + + 'while with-bindings with-bindings* with-in-str with-loading-context ' + + 'with-local-vars with-meta with-open with-out-str with-precision xml-seq ' + + 'zero? zipmap' + ); + + var keywords = ('throw try var ' + + 'def do fn if let loop monitor-enter monitor-exit new quote recur set!' + ); + + var buildinConstants = ("true false nil"); + + var keywordMapper = this.createKeywordMapper({ + "keyword": keywords, + "constant.language": buildinConstants, + "support.function": builtinFunctions + }, "identifier", false, " "); + + // regexp must not have capturing parentheses. Use (?:) instead. + // regexps are ordered -> the first match is used + + this.$rules = { + "start" : [ + { + token : "comment", + regex : ";.*$" + }, { + token : "keyword", //parens + regex : "[\\(|\\)]" + }, { + token : "keyword", //lists + regex : "[\\'\\(]" + }, { + token : "keyword", //vectors + regex : "[\\[|\\]]" + }, { + token : "keyword", //sets and maps + regex : "[\\{|\\}|\\#\\{|\\#\\}]" + }, { + token : "keyword", // ampersands + regex : '[\\&]' + }, { + token : "keyword", // metadata + regex : '[\\#\\^\\{]' + }, { + token : "keyword", // anonymous fn syntactic sugar + regex : '[\\%]' + }, { + token : "keyword", // deref reader macro + regex : '[@]' + }, { + token : "constant.numeric", // hex + regex : "0[xX][0-9a-fA-F]+\\b" + }, { + token : "constant.numeric", // float + regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b" + }, { + token : "constant.language", + regex : '[!|\\$|%|&|\\*|\\-\\-|\\-|\\+\\+|\\+||=|!=|<=|>=|<>|<|>|!|&&]' + }, { + token : keywordMapper, + regex : "[a-zA-Z_$][a-zA-Z0-9_$\\-]*\\b" + }, { + token : "string", // single line + regex : '"', + next: "string" + }, { + token : "constant", // symbol + regex : /:[^()\[\]{}'"\^%`,;\s]+/ + }, { + token : "string.regexp", //Regular Expressions + regex : '/#"(?:\\.|(?:\\\")|[^\""\n])*"/g' + } + + ], + "string" : [ + { + token : "constant.language.escape", + regex : "\\\\.|\\\\$" + }, { + token : "string", + regex : '[^"\\\\]+' + }, { + token : "string", + regex : '"', + next : "start" + } + ] + }; +}; + +oop.inherits(ClojureHighlightRules, TextHighlightRules); + +exports.ClojureHighlightRules = ClojureHighlightRules; +}); diff --git a/node_modules/ace/lib/ace/mode/cobol.js b/node_modules/ace/lib/ace/mode/cobol.js new file mode 100644 index 00000000..91713bd0 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/cobol.js @@ -0,0 +1,53 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextMode = require("./text").Mode; +var CobolHighlightRules = require("./cobol_highlight_rules").CobolHighlightRules; +var Range = require("../range").Range; + +var Mode = function() { + this.HighlightRules = CobolHighlightRules; +}; +oop.inherits(Mode, TextMode); + +(function() { + + this.lineCommentStart = "*"; + + this.$id = "ace/mode/cobol"; +}).call(Mode.prototype); + +exports.Mode = Mode; + +}); diff --git a/node_modules/ace/lib/ace/mode/cobol_highlight_rules.js b/node_modules/ace/lib/ace/mode/cobol_highlight_rules.js new file mode 100644 index 00000000..36335c93 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/cobol_highlight_rules.js @@ -0,0 +1,100 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + +var CobolHighlightRules = function() { +var keywords = "ACCEPT|MERGE|SUM|ADD||MESSAGE|TABLE|ADVANCING|MODE|TAPE|" + +"AFTER|MULTIPLY|TEST|ALL|NEGATIVE|TEXT|ALPHABET|NEXT|THAN|" + +"ALSO|NO|THEN|ALTERNATE|NOT|THROUGH|AND|NUMBER|THRU|ANY|OCCURS|" + +"TIME|ARE|OF|TO|AREA|OFF|TOP||ASCENDING|OMITTED|TRUE|ASSIGN|ON|TYPE|AT|OPEN|" + +"UNIT|AUTHOR|OR|UNTIL|BEFORE|OTHER|UP|BLANK|OUTPUT|USE|BLOCK|PAGE|USING|BOTTOM|" + +"PERFORM|VALUE|BY|PIC|VALUES|CALL|PICTURE|WHEN|CANCEL|PLUS|WITH|CD|POINTER|WRITE|" + +"CHARACTER|POSITION||ZERO|CLOSE|POSITIVE|ZEROS|COLUMN|PROCEDURE|ZEROES|COMMA|PROGRAM|" + +"COMMON|PROGRAM-ID|COMMUNICATION|QUOTE|COMP|RANDOM|COMPUTE|READ|CONTAINS|RECEIVE|CONFIGURATION|" + +"RECORD|CONTINUE|REDEFINES|CONTROL|REFERENCE|COPY|REMAINDER|COUNT|REPLACE|DATA|REPORT|DATE|RESERVE|" + +"DAY|RESET|DELETE|RETURN|DESTINATION|REWIND|DISABLE|REWRITE|DISPLAY|RIGHT|DIVIDE|RUN|DOWN|SAME|" + +"ELSE|SEARCH|ENABLE|SECTION|END|SELECT|ENVIRONMENT|SENTENCE|EQUAL|SET|ERROR|SIGN|EXIT|SEQUENTIAL|" + +"EXTERNAL|SIZE|FLASE|SORT|FILE|SOURCE|LENGTH|SPACE|LESS|STANDARD|LIMIT|START|LINE|STOP|LOCK|STRING|LOW-VALUE|SUBTRACT"; + + var builtinConstants = ( + "true|false|null" + ); + + var builtinFunctions = ( + "count|min|max|avg|sum|rank|now|coalesce|main" + ); + + var keywordMapper = this.createKeywordMapper({ + "support.function": builtinFunctions, + "keyword": keywords, + "constant.language": builtinConstants + }, "identifier", true); + + this.$rules = { + "start" : [ { + token : "comment", + regex : "\\*.*$" + }, { + token : "string", // " string + regex : '".*?"' + }, { + token : "string", // ' string + regex : "'.*?'" + }, { + token : "constant.numeric", // float + regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b" + }, { + token : keywordMapper, + regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b" + }, { + token : "keyword.operator", + regex : "\\+|\\-|\\/|\\/\\/|%|<@>|@>|<@|&|\\^|~|<|>|<=|=>|==|!=|<>|=" + }, { + token : "paren.lparen", + regex : "[\\(]" + }, { + token : "paren.rparen", + regex : "[\\)]" + }, { + token : "text", + regex : "\\s+" + } ] + }; +}; + +oop.inherits(CobolHighlightRules, TextHighlightRules); + +exports.CobolHighlightRules = CobolHighlightRules; +}); \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/coffee.js b/node_modules/ace/lib/ace/mode/coffee.js new file mode 100644 index 00000000..e866f2b0 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/coffee.js @@ -0,0 +1,135 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var Rules = require("./coffee_highlight_rules").CoffeeHighlightRules; +var Outdent = require("./matching_brace_outdent").MatchingBraceOutdent; +var FoldMode = require("./folding/coffee").FoldMode; +var Range = require("../range").Range; +var TextMode = require("./text").Mode; +var WorkerClient = require("../worker/worker_client").WorkerClient; +var oop = require("../lib/oop"); + +function Mode() { + this.HighlightRules = Rules; + this.$outdent = new Outdent(); + this.foldingRules = new FoldMode(); +} + +oop.inherits(Mode, TextMode); + +(function() { + + /*: + [({[=:] # Opening parentheses or brackets + |[-=]> # OR single or double arrow + |\b(?: # OR one of these words: + else # else + |try # OR try + |(?:swi|ca)tch # OR catch, optionally followed by: + (?:\s*[$A-Za-z_\x7f-\uffff][$\w\x7f-\uffff]*)? # a variable + |finally # OR finally + ))\s*$ # all as the last thing on a line (allowing trailing space) + | # ---- OR ---- : + ^\s* # a line starting with optional space + (else\b\s*)? # followed by an optional "else" + (?: # followed by one of the following: + if # if + |for # OR for + |while # OR while + |loop # OR loop + )\b # (as a word) + (?!.*\bthen\b) # ... but NOT followed by "then" on the line + */ + var indenter = /(?:[({[=:]|[-=]>|\b(?:else|try|(?:swi|ca)tch(?:\s+[$A-Za-z_\x7f-\uffff][$\w\x7f-\uffff]*)?|finally))\s*$|^\s*(else\b\s*)?(?:if|for|while|loop)\b(?!.*\bthen\b)/; + var commentLine = /^(\s*)#/; + var hereComment = /^\s*###(?!#)/; + var indentation = /^\s*/; + + this.getNextLineIndent = function(state, line, tab) { + var indent = this.$getIndent(line); + var tokens = this.getTokenizer().getLineTokens(line, state).tokens; + + if (!(tokens.length && tokens[tokens.length - 1].type === 'comment') && + state === 'start' && indenter.test(line)) + indent += tab; + return indent; + }; + + this.toggleCommentLines = function(state, doc, startRow, endRow){ + console.log("toggle"); + var range = new Range(0, 0, 0, 0); + for (var i = startRow; i <= endRow; ++i) { + var line = doc.getLine(i); + if (hereComment.test(line)) + continue; + + if (commentLine.test(line)) + line = line.replace(commentLine, '$1'); + else + line = line.replace(indentation, '$&#'); + + range.end.row = range.start.row = i; + range.end.column = line.length + 1; + doc.replace(range, line); + } + }; + + this.checkOutdent = function(state, line, input) { + return this.$outdent.checkOutdent(line, input); + }; + + this.autoOutdent = function(state, doc, row) { + this.$outdent.autoOutdent(doc, row); + }; + + this.createWorker = function(session) { + var worker = new WorkerClient(["ace"], "ace/mode/coffee_worker", "Worker"); + worker.attachToDocument(session.getDocument()); + + worker.on("annotate", function(e) { + session.setAnnotations(e.data); + }); + + worker.on("terminate", function() { + session.clearAnnotations(); + }); + + return worker; + }; + + this.$id = "ace/mode/coffee"; +}).call(Mode.prototype); + +exports.Mode = Mode; + +}); diff --git a/node_modules/ace/lib/ace/mode/coffee/coffee-script.js b/node_modules/ace/lib/ace/mode/coffee/coffee-script.js new file mode 100644 index 00000000..9e9719f7 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/coffee/coffee-script.js @@ -0,0 +1,62 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + + var Lexer = require("./lexer").Lexer; + var parser = require("./parser"); + + var lexer = new Lexer(); + parser.lexer = { + lex: function() { + var tag, token; + token = this.tokens[this.pos++]; + if (token) { + tag = token[0], this.yytext = token[1], this.yylloc = token[2]; + this.yylineno = this.yylloc.first_line; + } else { + tag = ''; + } + return tag; + }, + setInput: function(tokens) { + this.tokens = tokens; + return this.pos = 0; + }, + upcomingInput: function() { + return ""; + } + }; + parser.yy = require('./nodes'); + + exports.parse = function(code) { + return parser.parse(lexer.tokenize(code)); + }; +}); diff --git a/node_modules/ace/lib/ace/mode/coffee/helpers.js b/node_modules/ace/lib/ace/mode/coffee/helpers.js new file mode 100644 index 00000000..60412fc6 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/coffee/helpers.js @@ -0,0 +1,271 @@ +/** + * Copyright (c) 2009-2013 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. + * + */ + +define(function(require, exports, module) { +// Generated by CoffeeScript 1.6.3 + + var buildLocationData, extend, flatten, last, repeat, syntaxErrorToString, _ref; + + 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.repeat = repeat = function(str, n) { + var res; + res = ''; + while (n > 0) { + if (n & 1) { + res += str; + } + n >>>= 1; + str += str; + } + return res; + }; + + 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 = last = function(array, back) { + return array[array.length - (back || 0) - 1]; + }; + + exports.some = (_ref = Array.prototype.some) != null ? _ref : function(fn) { + var e, _i, _len; + for (_i = 0, _len = this.length; _i < _len; _i++) { + e = this[_i]; + if (fn(e)) { + return true; + } + } + return false; + }; + + exports.invertLiterate = function(code) { + var line, lines, maybe_code; + maybe_code = true; + lines = (function() { + var _i, _len, _ref1, _results; + _ref1 = code.split('\n'); + _results = []; + for (_i = 0, _len = _ref1.length; _i < _len; _i++) { + line = _ref1[_i]; + if (maybe_code && /^([ ]{4}|[ ]{0,3}\t)/.test(line)) { + _results.push(line); + } else if (maybe_code = /^\s*$/.test(line)) { + _results.push(line); + } else { + _results.push('# ' + line); + } + } + return _results; + })(); + return lines.join('\n'); + }; + + buildLocationData = function(first, last) { + if (!last) { + return first; + } else { + return { + first_line: first.first_line, + first_column: first.first_column, + last_line: last.last_line, + last_column: last.last_column + }; + } + }; + + exports.addLocationDataFn = function(first, last) { + return function(obj) { + if (((typeof obj) === 'object') && (!!obj['updateLocationDataIfMissing'])) { + obj.updateLocationDataIfMissing(buildLocationData(first, last)); + } + return obj; + }; + }; + + exports.locationDataToString = function(obj) { + var locationData; + if (("2" in obj) && ("first_line" in obj[2])) { + locationData = obj[2]; + } else if ("first_line" in obj) { + locationData = obj; + } + if (locationData) { + return ("" + (locationData.first_line + 1) + ":" + (locationData.first_column + 1) + "-") + ("" + (locationData.last_line + 1) + ":" + (locationData.last_column + 1)); + } else { + return "No location data"; + } + }; + + exports.baseFileName = function(file, stripExt, useWinPathSep) { + var parts, pathSep; + if (stripExt == null) { + stripExt = false; + } + if (useWinPathSep == null) { + useWinPathSep = false; + } + pathSep = useWinPathSep ? /\\|\// : /\//; + parts = file.split(pathSep); + file = parts[parts.length - 1]; + if (!(stripExt && file.indexOf('.') >= 0)) { + return file; + } + parts = file.split('.'); + parts.pop(); + if (parts[parts.length - 1] === 'coffee' && parts.length > 1) { + parts.pop(); + } + return parts.join('.'); + }; + + exports.isCoffee = function(file) { + return /\.((lit)?coffee|coffee\.md)$/.test(file); + }; + + exports.isLiterate = function(file) { + return /\.(litcoffee|coffee\.md)$/.test(file); + }; + + exports.throwSyntaxError = function(message, location) { + var error; + if (location.last_line == null) { + location.last_line = location.first_line; + } + if (location.last_column == null) { + location.last_column = location.first_column; + } + error = new SyntaxError(message); + error.location = location; + error.toString = syntaxErrorToString; + error.stack = error.toString(); + throw error; + }; + + exports.updateSyntaxError = function(error, code, filename) { + if (error.toString === syntaxErrorToString) { + error.code || (error.code = code); + error.filename || (error.filename = filename); + error.stack = error.toString(); + } + return error; + }; + + syntaxErrorToString = function() { + var codeLine, colorize, colorsEnabled, end, filename, first_column, first_line, last_column, last_line, marker, start, _ref1, _ref2; + if (!(this.code && this.location)) { + return Error.prototype.toString.call(this); + } + _ref1 = this.location, first_line = _ref1.first_line, first_column = _ref1.first_column, last_line = _ref1.last_line, last_column = _ref1.last_column; + if (last_line == null) { + last_line = first_line; + } + if (last_column == null) { + last_column = first_column; + } + filename = this.filename || '[stdin]'; + codeLine = this.code.split('\n')[first_line]; + start = first_column; + end = first_line === last_line ? last_column + 1 : codeLine.length; + marker = repeat(' ', start) + repeat('^', end - start); + if (typeof process !== "undefined" && process !== null) { + colorsEnabled = process.stdout.isTTY && !process.env.NODE_DISABLE_COLORS; + } + if ((_ref2 = this.colorful) != null ? _ref2 : colorsEnabled) { + colorize = function(str) { + return "\x1B[1;31m" + str + "\x1B[0m"; + }; + codeLine = codeLine.slice(0, start) + colorize(codeLine.slice(start, end)) + codeLine.slice(end); + marker = colorize(marker); + } + return "" + filename + ":" + (first_line + 1) + ":" + (first_column + 1) + ": error: " + this.message + "\n" + codeLine + "\n" + marker; + }; + + +}); \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/coffee/lexer.js b/node_modules/ace/lib/ace/mode/coffee/lexer.js new file mode 100644 index 00000000..05d85236 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/coffee/lexer.js @@ -0,0 +1,935 @@ +/** + * Copyright (c) 2009-2013 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. + * + */ + +define(function(require, exports, module) { +// Generated by CoffeeScript 1.6.3 + + var BOM, 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, invertLiterate, key, last, locationDataToString, repeat, starts, throwSyntaxError, _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, repeat = _ref1.repeat, invertLiterate = _ref1.invertLiterate, locationDataToString = _ref1.locationDataToString, throwSyntaxError = _ref1.throwSyntaxError; + + exports.Lexer = Lexer = (function() { + function Lexer() {} + + Lexer.prototype.tokenize = function(code, opts) { + var consumed, i, tag, _ref2; + if (opts == null) { + opts = {}; + } + this.literate = opts.literate; + this.indent = 0; + this.baseIndent = 0; + this.indebt = 0; + this.outdebt = 0; + this.indents = []; + this.ends = []; + this.tokens = []; + this.chunkLine = opts.line || 0; + this.chunkColumn = opts.column || 0; + code = this.clean(code); + i = 0; + while (this.chunk = code.slice(i)) { + consumed = this.identifierToken() || this.commentToken() || this.whitespaceToken() || this.lineToken() || this.heredocToken() || this.stringToken() || this.numberToken() || this.regexToken() || this.jsToken() || this.literalToken(); + _ref2 = this.getLineAndColumnFromChunk(consumed), this.chunkLine = _ref2[0], this.chunkColumn = _ref2[1]; + i += consumed; + } + 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.clean = function(code) { + if (code.charCodeAt(0) === BOM) { + code = code.slice(1); + } + code = code.replace(/\r/g, '').replace(TRAILING_SPACES, ''); + if (WHITESPACE.test(code)) { + code = "\n" + code; + this.chunkLine--; + } + if (this.literate) { + code = invertLiterate(code); + } + return code; + }; + + Lexer.prototype.identifierToken = function() { + var colon, colonOffset, forcedIdentifier, id, idLength, input, match, poppedToken, prev, tag, tagToken, _ref2, _ref3, _ref4; + if (!(match = IDENTIFIER.exec(this.chunk))) { + return 0; + } + input = match[0], id = match[1], colon = match[2]; + idLength = id.length; + poppedToken = void 0; + if (id === 'own' && this.tag() === 'FOR') { + this.token('OWN', id); + return id.length; + } + forcedIdentifier = colon || (prev = last(this.tokens)) && (((_ref2 = prev[0]) === '.' || _ref2 === '?.' || _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() === '!') { + poppedToken = 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; + } + })(); + } + tagToken = this.token(tag, id, 0, idLength); + if (poppedToken) { + _ref4 = [poppedToken[2].first_line, poppedToken[2].first_column], tagToken[2].first_line = _ref4[0], tagToken[2].first_column = _ref4[1]; + } + if (colon) { + colonOffset = input.lastIndexOf(':'); + this.token(':', ':', colonOffset, colon.length); + } + 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, 0, lexedLength); + return lexedLength; + }; + + Lexer.prototype.stringToken = function() { + var octalEsc, quote, string, trimmed; + switch (quote = this.chunk.charAt(0)) { + case "'": + string = SIMPLESTR.exec(this.chunk)[0]; + break; + case '"': + string = this.balancedString(this.chunk, '"'); + } + if (!string) { + return 0; + } + trimmed = this.removeNewlines(string.slice(1, -1)); + if (quote === '"' && 0 < string.indexOf('#{', 1)) { + this.interpolateString(trimmed, { + strOffset: 1, + lexedLength: string.length + }); + } else { + this.token('STRING', quote + this.escapeLines(trimmed) + quote, 0, string.length); + } + if (octalEsc = /^(?:\\.|[^\\])*\\(?:0[0-7]|[1-7])/.test(string)) { + this.error("octal escape sequences " + string + " are not allowed"); + } + 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, + strOffset: 3, + lexedLength: heredoc.length + }); + } else { + this.token('STRING', this.makeString(doc, quote, true), 0, heredoc.length); + } + 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: repeat(' ', this.indent) + }), 0, comment.length); + } + 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), 0, script.length); + 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); + 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, 0, match.length); + return match.length; + }; + + Lexer.prototype.heregexToken = function(match) { + var body, flags, flagsOffset, heregex, plusToken, prev, re, tag, token, tokens, value, _i, _len, _ref2, _ref3, _ref4; + heregex = match[0], body = match[1], flags = match[2]; + if (0 > body.indexOf('#{')) { + re = this.escapeLines(body.replace(HEREGEX_OMIT, '$1$2').replace(/\//g, '\\/'), true); + if (re.match(/^\*/)) { + this.error('regular expressions cannot begin with `*`'); + } + this.token('REGEX', "/" + (re || '(?:)') + "/" + flags, 0, heregex.length); + return heregex.length; + } + this.token('IDENTIFIER', 'RegExp', 0, 0); + this.token('CALL_START', '(', 0, 0); + tokens = []; + _ref2 = this.interpolateString(body, { + regex: true + }); + for (_i = 0, _len = _ref2.length; _i < _len; _i++) { + token = _ref2[_i]; + tag = token[0], value = token[1]; + if (tag === 'TOKENS') { + tokens.push.apply(tokens, value); + } else if (tag === 'NEOSTRING') { + if (!(value = value.replace(HEREGEX_OMIT, '$1$2'))) { + continue; + } + value = value.replace(/\\/g, '\\\\'); + token[0] = 'STRING'; + token[1] = this.makeString(value, '"', true); + tokens.push(token); + } else { + this.error("Unexpected " + tag); + } + prev = last(this.tokens); + plusToken = ['+', '+']; + plusToken[2] = prev[2]; + tokens.push(plusToken); + } + tokens.pop(); + if (((_ref3 = tokens[0]) != null ? _ref3[0] : void 0) !== 'STRING') { + this.token('STRING', '""', 0, 0); + this.token('+', '+', 0, 0); + } + (_ref4 = this.tokens).push.apply(_ref4, tokens); + if (flags) { + flagsOffset = heregex.lastIndexOf(flags); + this.token(',', ',', flagsOffset, 0); + this.token('STRING', '"' + flags + '"', flagsOffset, flags.length); + } + this.token(')', ')', heregex.length - 1, 0); + return heregex.length; + }; + + Lexer.prototype.lineToken = function() { + var diff, indent, match, noNewlines, size; + if (!(match = MULTI_DENT.exec(this.chunk))) { + return 0; + } + indent = match[0]; + this.seenFor = false; + size = indent.length - 1 - indent.lastIndexOf('\n'); + noNewlines = this.unfinished(); + if (size - this.indebt === this.indent) { + if (noNewlines) { + this.suppressNewlines(); + } else { + this.newlineToken(0); + } + return indent.length; + } + if (size > this.indent) { + if (noNewlines) { + this.indebt = size - this.indent; + this.suppressNewlines(); + return indent.length; + } + if (!this.tokens.length) { + this.baseIndent = this.indent = size; + return indent.length; + } + diff = size - this.indent + this.outdebt; + this.token('INDENT', diff, indent.length - size, size); + this.indents.push(diff); + this.ends.push('OUTDENT'); + this.outdebt = this.indebt = 0; + } else if (size < this.baseIndent) { + this.error('missing indentation', indent.length); + } else { + this.indebt = 0; + this.outdentToken(this.indent - size, noNewlines, indent.length); + } + this.indent = size; + return indent.length; + }; + + Lexer.prototype.outdentToken = function(moveOut, noNewlines, outdentLength) { + 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, 0, outdentLength); + } + } + if (dent) { + this.outdebt -= moveOut; + } + while (this.value() === ';') { + this.tokens.pop(); + } + if (!(this.tag() === 'TERMINATOR' || noNewlines)) { + this.token('TERMINATOR', '\n', outdentLength, 0); + } + 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(offset) { + while (this.value() === ';') { + this.tokens.pop(); + } + if (this.tag() !== 'TERMINATOR') { + this.token('TERMINATOR', '\n', offset, 0); + } + 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 column, expr, heredoc, i, inner, interpolated, len, letter, lexedLength, line, locationToken, nested, offsetInChunk, pi, plusToken, popped, regex, rparen, strOffset, tag, token, tokens, value, _i, _len, _ref2, _ref3, _ref4; + if (options == null) { + options = {}; + } + heredoc = options.heredoc, regex = options.regex, offsetInChunk = options.offsetInChunk, strOffset = options.strOffset, lexedLength = options.lexedLength; + offsetInChunk = offsetInChunk || 0; + strOffset = strOffset || 0; + lexedLength = lexedLength || str.length; + 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(this.makeToken('NEOSTRING', str.slice(pi, i), strOffset + pi)); + } + inner = expr.slice(1, -1); + if (inner.length) { + _ref2 = this.getLineAndColumnFromChunk(strOffset + i + 1), line = _ref2[0], column = _ref2[1]; + nested = new Lexer().tokenize(inner, { + line: line, + column: column, + rewrite: false + }); + popped = nested.pop(); + if (((_ref3 = nested[0]) != null ? _ref3[0] : void 0) === 'TERMINATOR') { + popped = nested.shift(); + } + if (len = nested.length) { + if (len > 1) { + nested.unshift(this.makeToken('(', '(', strOffset + i + 1, 0)); + nested.push(this.makeToken(')', ')', strOffset + i + 1 + inner.length, 0)); + } + tokens.push(['TOKENS', nested]); + } + } + i += expr.length; + pi = i + 1; + } + if ((i > pi && pi < str.length)) { + tokens.push(this.makeToken('NEOSTRING', str.slice(pi), strOffset + pi)); + } + if (regex) { + return tokens; + } + if (!tokens.length) { + return this.token('STRING', '""', offsetInChunk, lexedLength); + } + if (tokens[0][0] !== 'NEOSTRING') { + tokens.unshift(this.makeToken('NEOSTRING', '', offsetInChunk)); + } + if (interpolated = tokens.length > 1) { + this.token('(', '(', offsetInChunk, 0); + } + for (i = _i = 0, _len = tokens.length; _i < _len; i = ++_i) { + token = tokens[i]; + tag = token[0], value = token[1]; + if (i) { + if (i) { + plusToken = this.token('+', '+'); + } + locationToken = tag === 'TOKENS' ? value[0] : token; + plusToken[2] = { + first_line: locationToken[2].first_line, + first_column: locationToken[2].first_column, + last_line: locationToken[2].first_line, + last_column: locationToken[2].first_column + }; + } + if (tag === 'TOKENS') { + (_ref4 = this.tokens).push.apply(_ref4, value); + } else if (tag === 'NEOSTRING') { + token[0] = 'STRING'; + token[1] = this.makeString(value, '"', heredoc); + this.tokens.push(token); + } else { + this.error("Unexpected " + tag); + } + } + if (interpolated) { + rparen = this.makeToken(')', ')', offsetInChunk + lexedLength, 0); + rparen.stringEnd = true; + this.tokens.push(rparen); + } + 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.getLineAndColumnFromChunk = function(offset) { + var column, lineCount, lines, string; + if (offset === 0) { + return [this.chunkLine, this.chunkColumn]; + } + if (offset >= this.chunk.length) { + string = this.chunk; + } else { + string = this.chunk.slice(0, +(offset - 1) + 1 || 9e9); + } + lineCount = count(string, '\n'); + column = this.chunkColumn; + if (lineCount > 0) { + lines = string.split('\n'); + column = last(lines).length; + } else { + column += string.length; + } + return [this.chunkLine + lineCount, column]; + }; + + Lexer.prototype.makeToken = function(tag, value, offsetInChunk, length) { + var lastCharacter, locationData, token, _ref2, _ref3; + if (offsetInChunk == null) { + offsetInChunk = 0; + } + if (length == null) { + length = value.length; + } + locationData = {}; + _ref2 = this.getLineAndColumnFromChunk(offsetInChunk), locationData.first_line = _ref2[0], locationData.first_column = _ref2[1]; + lastCharacter = Math.max(0, length - 1); + _ref3 = this.getLineAndColumnFromChunk(offsetInChunk + lastCharacter), locationData.last_line = _ref3[0], locationData.last_column = _ref3[1]; + token = [tag, value, locationData]; + return token; + }; + + Lexer.prototype.token = function(tag, value, offsetInChunk, length) { + var token; + token = this.makeToken(tag, value, offsetInChunk, length); + this.tokens.push(token); + return token; + }; + + 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 === '?::' || _ref2 === 'UNARY' || _ref2 === 'MATH' || _ref2 === '+' || _ref2 === '-' || _ref2 === 'SHIFT' || _ref2 === 'RELATION' || _ref2 === 'COMPARE' || _ref2 === 'LOGIC' || _ref2 === 'THROW' || _ref2 === 'EXTENDS'); + }; + + Lexer.prototype.removeNewlines = function(str) { + return str.replace(/^\s*\n\s*/, '').replace(/([^\\]|\\\\)\s*\n\s*$/, '$1'); + }; + + Lexer.prototype.escapeLines = function(str, heredoc) { + str = str.replace(/\\[^\S\n]*(\n|\\)\s*/g, function(escaped, character) { + if (character === '\n') { + return ''; + } else { + return escaped; + } + }); + if (heredoc) { + return str.replace(MULTILINER, '\\n'); + } else { + return str.replace(/\s*\n\s*/g, ' '); + } + }; + + Lexer.prototype.makeString = function(body, quote, heredoc) { + if (!body) { + return quote + quote; + } + body = body.replace(RegExp("\\\\(" + quote + "|\\\\)", "g"), function(match, contents) { + if (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, offset) { + var first_column, first_line, _ref2; + if (offset == null) { + offset = 0; + } + _ref2 = this.getLineAndColumnFromChunk(offset), first_line = _ref2[0], first_column = _ref2[1]; + return throwSyntaxError(message, { + first_line: first_line, + first_column: first_column + }); + }; + + 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', '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; + + BOM = 65279; + + 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 = /^'[^\\']*(?:\\[\s\S][^\\']*)*'/; + + 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|\/)|\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']; + + +}); \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/coffee/nodes.js b/node_modules/ace/lib/ace/mode/coffee/nodes.js new file mode 100644 index 00000000..52afdf2c --- /dev/null +++ b/node_modules/ace/lib/ace/mode/coffee/nodes.js @@ -0,0 +1,3106 @@ +/** + * Copyright (c) 2009-2013 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. + * + */ + +define(function(require, exports, module) { +// Generated by CoffeeScript 1.6.3 + + var Access, Arr, Assign, Base, Block, Call, Class, Code, CodeFragment, Comment, Existence, Extends, For, HEXNUM, IDENTIFIER, IDENTIFIER_STR, IS_REGEX, IS_STRING, If, In, Index, LEVEL_ACCESS, LEVEL_COND, LEVEL_LIST, LEVEL_OP, LEVEL_PAREN, LEVEL_TOP, Literal, METHOD_DEF, NEGATE, NO, NUMBER, Obj, Op, Param, Parens, RESERVED, Range, Return, SIMPLENUM, STRICT_PROSCRIBED, Scope, Slice, Splat, Switch, TAB, THIS, Throw, Try, UTILITIES, Value, While, YES, addLocationDataFn, compact, del, ends, extend, flatten, fragmentsToText, isLiteralArguments, isLiteralThis, last, locationDataToString, merge, multident, parseNum, some, starts, throwSyntaxError, unfoldSoak, utility, _ref, _ref1, + __hasProp = {}.hasOwnProperty, + __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + __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; + + Error.stackTraceLimit = Infinity; + + Scope = require('./scope').Scope; + + _ref = require('./lexer'), RESERVED = _ref.RESERVED, STRICT_PROSCRIBED = _ref.STRICT_PROSCRIBED; + + _ref1 = require('./helpers'), compact = _ref1.compact, flatten = _ref1.flatten, extend = _ref1.extend, merge = _ref1.merge, del = _ref1.del, starts = _ref1.starts, ends = _ref1.ends, last = _ref1.last, some = _ref1.some, addLocationDataFn = _ref1.addLocationDataFn, locationDataToString = _ref1.locationDataToString, throwSyntaxError = _ref1.throwSyntaxError; + + exports.extend = extend; + + exports.addLocationDataFn = addLocationDataFn; + + YES = function() { + return true; + }; + + NO = function() { + return false; + }; + + THIS = function() { + return this; + }; + + NEGATE = function() { + this.negated = !this.negated; + return this; + }; + + exports.CodeFragment = CodeFragment = (function() { + function CodeFragment(parent, code) { + var _ref2; + this.code = "" + code; + this.locationData = parent != null ? parent.locationData : void 0; + this.type = (parent != null ? (_ref2 = parent.constructor) != null ? _ref2.name : void 0 : void 0) || 'unknown'; + } + + CodeFragment.prototype.toString = function() { + return "" + this.code + (this.locationData ? ": " + locationDataToString(this.locationData) : ''); + }; + + return CodeFragment; + + })(); + + fragmentsToText = function(fragments) { + var fragment; + return ((function() { + var _i, _len, _results; + _results = []; + for (_i = 0, _len = fragments.length; _i < _len; _i++) { + fragment = fragments[_i]; + _results.push(fragment.code); + } + return _results; + })()).join(''); + }; + + exports.Base = Base = (function() { + function Base() {} + + Base.prototype.compile = function(o, lvl) { + return fragmentsToText(this.compileToFragments(o, lvl)); + }; + + Base.prototype.compileToFragments = function(o, lvl) { + var node; + o = extend({}, o); + if (lvl) { + o.level = lvl; + } + node = this.unfoldSoak(o) || this; + node.tab = o.indent; + if (o.level === LEVEL_TOP || !node.isStatement(o)) { + return node.compileNode(o); + } else { + return node.compileClosure(o); + } + }; + + Base.prototype.compileClosure = function(o) { + var args, argumentsNode, func, jumpNode, meth; + if (jumpNode = this.jumps()) { + jumpNode.error('cannot use a pure statement in an expression'); + } + o.sharedScope = true; + func = new Code([], Block.wrap([this])); + args = []; + if ((argumentsNode = this.contains(isLiteralArguments)) || this.contains(isLiteralThis)) { + args = [new Literal('this')]; + if (argumentsNode) { + meth = 'apply'; + args.push(new Literal('arguments')); + } else { + meth = 'call'; + } + func = new Value(func, [new Access(new Literal(meth))]); + } + return (new Call(func, args)).compileNode(o); + }; + + Base.prototype.cache = function(o, level, reused) { + var ref, sub; + if (!this.isComplex()) { + ref = level ? this.compileToFragments(o, level) : this; + return [ref, ref]; + } else { + ref = new Literal(reused || o.scope.freeVariable('ref')); + sub = new Assign(ref, this); + if (level) { + return [sub.compileToFragments(o, level), [this.makeCode(ref.value)]]; + } else { + return [sub, ref]; + } + } + }; + + Base.prototype.cacheToCodeFragments = function(cacheValues) { + return [fragmentsToText(cacheValues[0]), fragmentsToText(cacheValues[1])]; + }; + + Base.prototype.makeReturn = function(res) { + var me; + me = this.unwrapAll(); + if (res) { + return new Call(new Literal("" + res + ".push"), [me]); + } else { + return new Return(me); + } + }; + + Base.prototype.contains = function(pred) { + var node; + node = void 0; + this.traverseChildren(false, function(n) { + if (pred(n)) { + node = n; + return false; + } + }); + return node; + }; + + Base.prototype.lastNonComment = function(list) { + var i; + i = list.length; + while (i--) { + if (!(list[i] instanceof Comment)) { + return list[i]; + } + } + return null; + }; + + Base.prototype.toString = function(idt, name) { + var tree; + if (idt == null) { + idt = ''; + } + if (name == null) { + name = this.constructor.name; + } + tree = '\n' + idt + name; + if (this.soak) { + tree += '?'; + } + this.eachChild(function(node) { + return tree += node.toString(idt + TAB); + }); + return tree; + }; + + Base.prototype.eachChild = function(func) { + var attr, child, _i, _j, _len, _len1, _ref2, _ref3; + if (!this.children) { + return this; + } + _ref2 = this.children; + for (_i = 0, _len = _ref2.length; _i < _len; _i++) { + attr = _ref2[_i]; + if (this[attr]) { + _ref3 = flatten([this[attr]]); + for (_j = 0, _len1 = _ref3.length; _j < _len1; _j++) { + child = _ref3[_j]; + if (func(child) === false) { + return this; + } + } + } + } + return this; + }; + + Base.prototype.traverseChildren = function(crossScope, func) { + return this.eachChild(function(child) { + var recur; + recur = func(child); + if (recur !== false) { + return child.traverseChildren(crossScope, func); + } + }); + }; + + Base.prototype.invert = function() { + return new Op('!', this); + }; + + Base.prototype.unwrapAll = function() { + var node; + node = this; + while (node !== (node = node.unwrap())) { + continue; + } + return node; + }; + + Base.prototype.children = []; + + Base.prototype.isStatement = NO; + + Base.prototype.jumps = NO; + + Base.prototype.isComplex = YES; + + Base.prototype.isChainable = NO; + + Base.prototype.isAssignable = NO; + + Base.prototype.unwrap = THIS; + + Base.prototype.unfoldSoak = NO; + + Base.prototype.assigns = NO; + + Base.prototype.updateLocationDataIfMissing = function(locationData) { + if (this.locationData) { + return this; + } + this.locationData = locationData; + return this.eachChild(function(child) { + return child.updateLocationDataIfMissing(locationData); + }); + }; + + Base.prototype.error = function(message) { + return throwSyntaxError(message, this.locationData); + }; + + Base.prototype.makeCode = function(code) { + return new CodeFragment(this, code); + }; + + Base.prototype.wrapInBraces = function(fragments) { + return [].concat(this.makeCode('('), fragments, this.makeCode(')')); + }; + + Base.prototype.joinFragmentArrays = function(fragmentsList, joinStr) { + var answer, fragments, i, _i, _len; + answer = []; + for (i = _i = 0, _len = fragmentsList.length; _i < _len; i = ++_i) { + fragments = fragmentsList[i]; + if (i) { + answer.push(this.makeCode(joinStr)); + } + answer = answer.concat(fragments); + } + return answer; + }; + + return Base; + + })(); + + exports.Block = Block = (function(_super) { + __extends(Block, _super); + + function Block(nodes) { + this.expressions = compact(flatten(nodes || [])); + } + + Block.prototype.children = ['expressions']; + + Block.prototype.push = function(node) { + this.expressions.push(node); + return this; + }; + + Block.prototype.pop = function() { + return this.expressions.pop(); + }; + + Block.prototype.unshift = function(node) { + this.expressions.unshift(node); + return this; + }; + + Block.prototype.unwrap = function() { + if (this.expressions.length === 1) { + return this.expressions[0]; + } else { + return this; + } + }; + + Block.prototype.isEmpty = function() { + return !this.expressions.length; + }; + + Block.prototype.isStatement = function(o) { + var exp, _i, _len, _ref2; + _ref2 = this.expressions; + for (_i = 0, _len = _ref2.length; _i < _len; _i++) { + exp = _ref2[_i]; + if (exp.isStatement(o)) { + return true; + } + } + return false; + }; + + Block.prototype.jumps = function(o) { + var exp, jumpNode, _i, _len, _ref2; + _ref2 = this.expressions; + for (_i = 0, _len = _ref2.length; _i < _len; _i++) { + exp = _ref2[_i]; + if (jumpNode = exp.jumps(o)) { + return jumpNode; + } + } + }; + + Block.prototype.makeReturn = function(res) { + var expr, len; + len = this.expressions.length; + while (len--) { + expr = this.expressions[len]; + if (!(expr instanceof Comment)) { + this.expressions[len] = expr.makeReturn(res); + if (expr instanceof Return && !expr.expression) { + this.expressions.splice(len, 1); + } + break; + } + } + return this; + }; + + Block.prototype.compileToFragments = function(o, level) { + if (o == null) { + o = {}; + } + if (o.scope) { + return Block.__super__.compileToFragments.call(this, o, level); + } else { + return this.compileRoot(o); + } + }; + + Block.prototype.compileNode = function(o) { + var answer, compiledNodes, fragments, index, node, top, _i, _len, _ref2; + this.tab = o.indent; + top = o.level === LEVEL_TOP; + compiledNodes = []; + _ref2 = this.expressions; + for (index = _i = 0, _len = _ref2.length; _i < _len; index = ++_i) { + node = _ref2[index]; + node = node.unwrapAll(); + node = node.unfoldSoak(o) || node; + if (node instanceof Block) { + compiledNodes.push(node.compileNode(o)); + } else if (top) { + node.front = true; + fragments = node.compileToFragments(o); + if (!node.isStatement(o)) { + fragments.unshift(this.makeCode("" + this.tab)); + fragments.push(this.makeCode(";")); + } + compiledNodes.push(fragments); + } else { + compiledNodes.push(node.compileToFragments(o, LEVEL_LIST)); + } + } + if (top) { + if (this.spaced) { + return [].concat(this.joinFragmentArrays(compiledNodes, '\n\n'), this.makeCode("\n")); + } else { + return this.joinFragmentArrays(compiledNodes, '\n'); + } + } + if (compiledNodes.length) { + answer = this.joinFragmentArrays(compiledNodes, ', '); + } else { + answer = [this.makeCode("void 0")]; + } + if (compiledNodes.length > 1 && o.level >= LEVEL_LIST) { + return this.wrapInBraces(answer); + } else { + return answer; + } + }; + + Block.prototype.compileRoot = function(o) { + var exp, fragments, i, name, prelude, preludeExps, rest, _i, _len, _ref2; + o.indent = o.bare ? '' : TAB; + o.level = LEVEL_TOP; + this.spaced = true; + o.scope = new Scope(null, this, null); + _ref2 = o.locals || []; + for (_i = 0, _len = _ref2.length; _i < _len; _i++) { + name = _ref2[_i]; + o.scope.parameter(name); + } + prelude = []; + if (!o.bare) { + preludeExps = (function() { + var _j, _len1, _ref3, _results; + _ref3 = this.expressions; + _results = []; + for (i = _j = 0, _len1 = _ref3.length; _j < _len1; i = ++_j) { + exp = _ref3[i]; + if (!(exp.unwrap() instanceof Comment)) { + break; + } + _results.push(exp); + } + return _results; + }).call(this); + rest = this.expressions.slice(preludeExps.length); + this.expressions = preludeExps; + if (preludeExps.length) { + prelude = this.compileNode(merge(o, { + indent: '' + })); + prelude.push(this.makeCode("\n")); + } + this.expressions = rest; + } + fragments = this.compileWithDeclarations(o); + if (o.bare) { + return fragments; + } + return [].concat(prelude, this.makeCode("(function() {\n"), fragments, this.makeCode("\n}).call(this);\n")); + }; + + Block.prototype.compileWithDeclarations = function(o) { + var assigns, declars, exp, fragments, i, post, rest, scope, spaced, _i, _len, _ref2, _ref3, _ref4; + fragments = []; + post = []; + _ref2 = this.expressions; + for (i = _i = 0, _len = _ref2.length; _i < _len; i = ++_i) { + exp = _ref2[i]; + exp = exp.unwrap(); + if (!(exp instanceof Comment || exp instanceof Literal)) { + break; + } + } + o = merge(o, { + level: LEVEL_TOP + }); + if (i) { + rest = this.expressions.splice(i, 9e9); + _ref3 = [this.spaced, false], spaced = _ref3[0], this.spaced = _ref3[1]; + _ref4 = [this.compileNode(o), spaced], fragments = _ref4[0], this.spaced = _ref4[1]; + this.expressions = rest; + } + post = this.compileNode(o); + scope = o.scope; + if (scope.expressions === this) { + declars = o.scope.hasDeclarations(); + assigns = scope.hasAssignments; + if (declars || assigns) { + if (i) { + fragments.push(this.makeCode('\n')); + } + fragments.push(this.makeCode("" + this.tab + "var ")); + if (declars) { + fragments.push(this.makeCode(scope.declaredVariables().join(', '))); + } + if (assigns) { + if (declars) { + fragments.push(this.makeCode(",\n" + (this.tab + TAB))); + } + fragments.push(this.makeCode(scope.assignedVariables().join(",\n" + (this.tab + TAB)))); + } + fragments.push(this.makeCode(";\n" + (this.spaced ? '\n' : ''))); + } else if (fragments.length && post.length) { + fragments.push(this.makeCode("\n")); + } + } + return fragments.concat(post); + }; + + Block.wrap = function(nodes) { + if (nodes.length === 1 && nodes[0] instanceof Block) { + return nodes[0]; + } + return new Block(nodes); + }; + + return Block; + + })(Base); + + exports.Literal = Literal = (function(_super) { + __extends(Literal, _super); + + function Literal(value) { + this.value = value; + } + + Literal.prototype.makeReturn = function() { + if (this.isStatement()) { + return this; + } else { + return Literal.__super__.makeReturn.apply(this, arguments); + } + }; + + Literal.prototype.isAssignable = function() { + return IDENTIFIER.test(this.value); + }; + + Literal.prototype.isStatement = function() { + var _ref2; + return (_ref2 = this.value) === 'break' || _ref2 === 'continue' || _ref2 === 'debugger'; + }; + + Literal.prototype.isComplex = NO; + + Literal.prototype.assigns = function(name) { + return name === this.value; + }; + + Literal.prototype.jumps = function(o) { + if (this.value === 'break' && !((o != null ? o.loop : void 0) || (o != null ? o.block : void 0))) { + return this; + } + if (this.value === 'continue' && !(o != null ? o.loop : void 0)) { + return this; + } + }; + + Literal.prototype.compileNode = function(o) { + var answer, code, _ref2; + code = this.value === 'this' ? ((_ref2 = o.scope.method) != null ? _ref2.bound : void 0) ? o.scope.method.context : this.value : this.value.reserved ? "\"" + this.value + "\"" : this.value; + answer = this.isStatement() ? "" + this.tab + code + ";" : code; + return [this.makeCode(answer)]; + }; + + Literal.prototype.toString = function() { + return ' "' + this.value + '"'; + }; + + return Literal; + + })(Base); + + exports.Undefined = (function(_super) { + __extends(Undefined, _super); + + function Undefined() { + return Undefined.__super__.constructor.apply(this, arguments); + } + + Undefined.prototype.isAssignable = NO; + + Undefined.prototype.isComplex = NO; + + Undefined.prototype.compileNode = function(o) { + return [this.makeCode(o.level >= LEVEL_ACCESS ? '(void 0)' : 'void 0')]; + }; + + return Undefined; + + })(Base); + + exports.Null = (function(_super) { + __extends(Null, _super); + + function Null() { + return Null.__super__.constructor.apply(this, arguments); + } + + Null.prototype.isAssignable = NO; + + Null.prototype.isComplex = NO; + + Null.prototype.compileNode = function() { + return [this.makeCode("null")]; + }; + + return Null; + + })(Base); + + exports.Bool = (function(_super) { + __extends(Bool, _super); + + Bool.prototype.isAssignable = NO; + + Bool.prototype.isComplex = NO; + + Bool.prototype.compileNode = function() { + return [this.makeCode(this.val)]; + }; + + function Bool(val) { + this.val = val; + } + + return Bool; + + })(Base); + + exports.Return = Return = (function(_super) { + __extends(Return, _super); + + function Return(expr) { + if (expr && !expr.unwrap().isUndefined) { + this.expression = expr; + } + } + + Return.prototype.children = ['expression']; + + Return.prototype.isStatement = YES; + + Return.prototype.makeReturn = THIS; + + Return.prototype.jumps = THIS; + + Return.prototype.compileToFragments = function(o, level) { + var expr, _ref2; + expr = (_ref2 = this.expression) != null ? _ref2.makeReturn() : void 0; + if (expr && !(expr instanceof Return)) { + return expr.compileToFragments(o, level); + } else { + return Return.__super__.compileToFragments.call(this, o, level); + } + }; + + Return.prototype.compileNode = function(o) { + var answer; + answer = []; + answer.push(this.makeCode(this.tab + ("return" + (this.expression ? " " : "")))); + if (this.expression) { + answer = answer.concat(this.expression.compileToFragments(o, LEVEL_PAREN)); + } + answer.push(this.makeCode(";")); + return answer; + }; + + return Return; + + })(Base); + + exports.Value = Value = (function(_super) { + __extends(Value, _super); + + function Value(base, props, tag) { + if (!props && base instanceof Value) { + return base; + } + this.base = base; + this.properties = props || []; + if (tag) { + this[tag] = true; + } + return this; + } + + Value.prototype.children = ['base', 'properties']; + + Value.prototype.add = function(props) { + this.properties = this.properties.concat(props); + return this; + }; + + Value.prototype.hasProperties = function() { + return !!this.properties.length; + }; + + Value.prototype.bareLiteral = function(type) { + return !this.properties.length && this.base instanceof type; + }; + + Value.prototype.isArray = function() { + return this.bareLiteral(Arr); + }; + + Value.prototype.isRange = function() { + return this.bareLiteral(Range); + }; + + Value.prototype.isComplex = function() { + return this.hasProperties() || this.base.isComplex(); + }; + + Value.prototype.isAssignable = function() { + return this.hasProperties() || this.base.isAssignable(); + }; + + Value.prototype.isSimpleNumber = function() { + return this.bareLiteral(Literal) && SIMPLENUM.test(this.base.value); + }; + + Value.prototype.isString = function() { + return this.bareLiteral(Literal) && IS_STRING.test(this.base.value); + }; + + Value.prototype.isRegex = function() { + return this.bareLiteral(Literal) && IS_REGEX.test(this.base.value); + }; + + Value.prototype.isAtomic = function() { + var node, _i, _len, _ref2; + _ref2 = this.properties.concat(this.base); + for (_i = 0, _len = _ref2.length; _i < _len; _i++) { + node = _ref2[_i]; + if (node.soak || node instanceof Call) { + return false; + } + } + return true; + }; + + Value.prototype.isNotCallable = function() { + return this.isSimpleNumber() || this.isString() || this.isRegex() || this.isArray() || this.isRange() || this.isSplice() || this.isObject(); + }; + + Value.prototype.isStatement = function(o) { + return !this.properties.length && this.base.isStatement(o); + }; + + Value.prototype.assigns = function(name) { + return !this.properties.length && this.base.assigns(name); + }; + + Value.prototype.jumps = function(o) { + return !this.properties.length && this.base.jumps(o); + }; + + Value.prototype.isObject = function(onlyGenerated) { + if (this.properties.length) { + return false; + } + return (this.base instanceof Obj) && (!onlyGenerated || this.base.generated); + }; + + Value.prototype.isSplice = function() { + return last(this.properties) instanceof Slice; + }; + + Value.prototype.looksStatic = function(className) { + var _ref2; + return this.base.value === className && this.properties.length && ((_ref2 = this.properties[0].name) != null ? _ref2.value : void 0) !== 'prototype'; + }; + + Value.prototype.unwrap = function() { + if (this.properties.length) { + return this; + } else { + return this.base; + } + }; + + Value.prototype.cacheReference = function(o) { + var base, bref, name, nref; + name = last(this.properties); + if (this.properties.length < 2 && !this.base.isComplex() && !(name != null ? name.isComplex() : void 0)) { + return [this, this]; + } + base = new Value(this.base, this.properties.slice(0, -1)); + if (base.isComplex()) { + bref = new Literal(o.scope.freeVariable('base')); + base = new Value(new Parens(new Assign(bref, base))); + } + if (!name) { + return [base, bref]; + } + if (name.isComplex()) { + nref = new Literal(o.scope.freeVariable('name')); + name = new Index(new Assign(nref, name.index)); + nref = new Index(nref); + } + return [base.add(name), new Value(bref || base.base, [nref || name])]; + }; + + Value.prototype.compileNode = function(o) { + var fragments, prop, props, _i, _len; + this.base.front = this.front; + props = this.properties; + fragments = this.base.compileToFragments(o, (props.length ? LEVEL_ACCESS : null)); + if ((this.base instanceof Parens || props.length) && SIMPLENUM.test(fragmentsToText(fragments))) { + fragments.push(this.makeCode('.')); + } + for (_i = 0, _len = props.length; _i < _len; _i++) { + prop = props[_i]; + fragments.push.apply(fragments, prop.compileToFragments(o)); + } + return fragments; + }; + + Value.prototype.unfoldSoak = function(o) { + return this.unfoldedSoak != null ? this.unfoldedSoak : this.unfoldedSoak = (function(_this) { + return function() { + var fst, i, ifn, prop, ref, snd, _i, _len, _ref2, _ref3; + if (ifn = _this.base.unfoldSoak(o)) { + (_ref2 = ifn.body.properties).push.apply(_ref2, _this.properties); + return ifn; + } + _ref3 = _this.properties; + for (i = _i = 0, _len = _ref3.length; _i < _len; i = ++_i) { + prop = _ref3[i]; + if (!prop.soak) { + continue; + } + prop.soak = false; + fst = new Value(_this.base, _this.properties.slice(0, i)); + snd = new Value(_this.base, _this.properties.slice(i)); + if (fst.isComplex()) { + ref = new Literal(o.scope.freeVariable('ref')); + fst = new Parens(new Assign(ref, fst)); + snd.base = ref; + } + return new If(new Existence(fst), snd, { + soak: true + }); + } + return false; + }; + })(this)(); + }; + + return Value; + + })(Base); + + exports.Comment = Comment = (function(_super) { + __extends(Comment, _super); + + function Comment(comment) { + this.comment = comment; + } + + Comment.prototype.isStatement = YES; + + Comment.prototype.makeReturn = THIS; + + Comment.prototype.compileNode = function(o, level) { + var code, comment; + comment = this.comment.replace(/^(\s*)#/gm, "$1 *"); + code = "/*" + (multident(comment, this.tab)) + (__indexOf.call(comment, '\n') >= 0 ? "\n" + this.tab : '') + " */"; + if ((level || o.level) === LEVEL_TOP) { + code = o.indent + code; + } + return [this.makeCode("\n"), this.makeCode(code)]; + }; + + return Comment; + + })(Base); + + exports.Call = Call = (function(_super) { + __extends(Call, _super); + + function Call(variable, args, soak) { + this.args = args != null ? args : []; + this.soak = soak; + this.isNew = false; + this.isSuper = variable === 'super'; + this.variable = this.isSuper ? null : variable; + if (variable instanceof Value && variable.isNotCallable()) { + variable.error("literal is not a function"); + } + } + + Call.prototype.children = ['variable', 'args']; + + Call.prototype.newInstance = function() { + var base, _ref2; + base = ((_ref2 = this.variable) != null ? _ref2.base : void 0) || this.variable; + if (base instanceof Call && !base.isNew) { + base.newInstance(); + } else { + this.isNew = true; + } + return this; + }; + + Call.prototype.superReference = function(o) { + var accesses, method; + method = o.scope.namedMethod(); + if (method != null ? method.klass : void 0) { + accesses = [new Access(new Literal('__super__'))]; + if (method["static"]) { + accesses.push(new Access(new Literal('constructor'))); + } + accesses.push(new Access(new Literal(method.name))); + return (new Value(new Literal(method.klass), accesses)).compile(o); + } else if (method != null ? method.ctor : void 0) { + return "" + method.name + ".__super__.constructor"; + } else { + return this.error('cannot call super outside of an instance method.'); + } + }; + + Call.prototype.superThis = function(o) { + var method; + method = o.scope.method; + return (method && !method.klass && method.context) || "this"; + }; + + Call.prototype.unfoldSoak = function(o) { + var call, ifn, left, list, rite, _i, _len, _ref2, _ref3; + if (this.soak) { + if (this.variable) { + if (ifn = unfoldSoak(o, this, 'variable')) { + return ifn; + } + _ref2 = new Value(this.variable).cacheReference(o), left = _ref2[0], rite = _ref2[1]; + } else { + left = new Literal(this.superReference(o)); + rite = new Value(left); + } + rite = new Call(rite, this.args); + rite.isNew = this.isNew; + left = new Literal("typeof " + (left.compile(o)) + " === \"function\""); + return new If(left, new Value(rite), { + soak: true + }); + } + call = this; + list = []; + while (true) { + if (call.variable instanceof Call) { + list.push(call); + call = call.variable; + continue; + } + if (!(call.variable instanceof Value)) { + break; + } + list.push(call); + if (!((call = call.variable.base) instanceof Call)) { + break; + } + } + _ref3 = list.reverse(); + for (_i = 0, _len = _ref3.length; _i < _len; _i++) { + call = _ref3[_i]; + if (ifn) { + if (call.variable instanceof Call) { + call.variable = ifn; + } else { + call.variable.base = ifn; + } + } + ifn = unfoldSoak(o, call, 'variable'); + } + return ifn; + }; + + Call.prototype.compileNode = function(o) { + var arg, argIndex, compiledArgs, compiledArray, fragments, preface, _i, _len, _ref2, _ref3; + if ((_ref2 = this.variable) != null) { + _ref2.front = this.front; + } + compiledArray = Splat.compileSplattedArray(o, this.args, true); + if (compiledArray.length) { + return this.compileSplat(o, compiledArray); + } + compiledArgs = []; + _ref3 = this.args; + for (argIndex = _i = 0, _len = _ref3.length; _i < _len; argIndex = ++_i) { + arg = _ref3[argIndex]; + if (argIndex) { + compiledArgs.push(this.makeCode(", ")); + } + compiledArgs.push.apply(compiledArgs, arg.compileToFragments(o, LEVEL_LIST)); + } + fragments = []; + if (this.isSuper) { + preface = this.superReference(o) + (".call(" + (this.superThis(o))); + if (compiledArgs.length) { + preface += ", "; + } + fragments.push(this.makeCode(preface)); + } else { + if (this.isNew) { + fragments.push(this.makeCode('new ')); + } + fragments.push.apply(fragments, this.variable.compileToFragments(o, LEVEL_ACCESS)); + fragments.push(this.makeCode("(")); + } + fragments.push.apply(fragments, compiledArgs); + fragments.push(this.makeCode(")")); + return fragments; + }; + + Call.prototype.compileSplat = function(o, splatArgs) { + var answer, base, fun, idt, name, ref; + if (this.isSuper) { + return [].concat(this.makeCode("" + (this.superReference(o)) + ".apply(" + (this.superThis(o)) + ", "), splatArgs, this.makeCode(")")); + } + if (this.isNew) { + idt = this.tab + TAB; + return [].concat(this.makeCode("(function(func, args, ctor) {\n" + idt + "ctor.prototype = func.prototype;\n" + idt + "var child = new ctor, result = func.apply(child, args);\n" + idt + "return Object(result) === result ? result : child;\n" + this.tab + "})("), this.variable.compileToFragments(o, LEVEL_LIST), this.makeCode(", "), splatArgs, this.makeCode(", function(){})")); + } + answer = []; + base = new Value(this.variable); + if ((name = base.properties.pop()) && base.isComplex()) { + ref = o.scope.freeVariable('ref'); + answer = answer.concat(this.makeCode("(" + ref + " = "), base.compileToFragments(o, LEVEL_LIST), this.makeCode(")"), name.compileToFragments(o)); + } else { + fun = base.compileToFragments(o, LEVEL_ACCESS); + if (SIMPLENUM.test(fragmentsToText(fun))) { + fun = this.wrapInBraces(fun); + } + if (name) { + ref = fragmentsToText(fun); + fun.push.apply(fun, name.compileToFragments(o)); + } else { + ref = 'null'; + } + answer = answer.concat(fun); + } + return answer = answer.concat(this.makeCode(".apply(" + ref + ", "), splatArgs, this.makeCode(")")); + }; + + return Call; + + })(Base); + + exports.Extends = Extends = (function(_super) { + __extends(Extends, _super); + + function Extends(child, parent) { + this.child = child; + this.parent = parent; + } + + Extends.prototype.children = ['child', 'parent']; + + Extends.prototype.compileToFragments = function(o) { + return new Call(new Value(new Literal(utility('extends'))), [this.child, this.parent]).compileToFragments(o); + }; + + return Extends; + + })(Base); + + exports.Access = Access = (function(_super) { + __extends(Access, _super); + + function Access(name, tag) { + this.name = name; + this.name.asKey = true; + this.soak = tag === 'soak'; + } + + Access.prototype.children = ['name']; + + Access.prototype.compileToFragments = function(o) { + var name; + name = this.name.compileToFragments(o); + if (IDENTIFIER.test(fragmentsToText(name))) { + name.unshift(this.makeCode(".")); + } else { + name.unshift(this.makeCode("[")); + name.push(this.makeCode("]")); + } + return name; + }; + + Access.prototype.isComplex = NO; + + return Access; + + })(Base); + + exports.Index = Index = (function(_super) { + __extends(Index, _super); + + function Index(index) { + this.index = index; + } + + Index.prototype.children = ['index']; + + Index.prototype.compileToFragments = function(o) { + return [].concat(this.makeCode("["), this.index.compileToFragments(o, LEVEL_PAREN), this.makeCode("]")); + }; + + Index.prototype.isComplex = function() { + return this.index.isComplex(); + }; + + return Index; + + })(Base); + + exports.Range = Range = (function(_super) { + __extends(Range, _super); + + Range.prototype.children = ['from', 'to']; + + function Range(from, to, tag) { + this.from = from; + this.to = to; + this.exclusive = tag === 'exclusive'; + this.equals = this.exclusive ? '' : '='; + } + + Range.prototype.compileVariables = function(o) { + var step, _ref2, _ref3, _ref4, _ref5; + o = merge(o, { + top: true + }); + _ref2 = this.cacheToCodeFragments(this.from.cache(o, LEVEL_LIST)), this.fromC = _ref2[0], this.fromVar = _ref2[1]; + _ref3 = this.cacheToCodeFragments(this.to.cache(o, LEVEL_LIST)), this.toC = _ref3[0], this.toVar = _ref3[1]; + if (step = del(o, 'step')) { + _ref4 = this.cacheToCodeFragments(step.cache(o, LEVEL_LIST)), this.step = _ref4[0], this.stepVar = _ref4[1]; + } + _ref5 = [this.fromVar.match(NUMBER), this.toVar.match(NUMBER)], this.fromNum = _ref5[0], this.toNum = _ref5[1]; + if (this.stepVar) { + return this.stepNum = this.stepVar.match(NUMBER); + } + }; + + Range.prototype.compileNode = function(o) { + var cond, condPart, from, gt, idx, idxName, known, lt, namedIndex, stepPart, to, varPart, _ref2, _ref3; + if (!this.fromVar) { + this.compileVariables(o); + } + if (!o.index) { + return this.compileArray(o); + } + known = this.fromNum && this.toNum; + idx = del(o, 'index'); + idxName = del(o, 'name'); + namedIndex = idxName && idxName !== idx; + varPart = "" + idx + " = " + this.fromC; + if (this.toC !== this.toVar) { + varPart += ", " + this.toC; + } + if (this.step !== this.stepVar) { + varPart += ", " + this.step; + } + _ref2 = ["" + idx + " <" + this.equals, "" + idx + " >" + this.equals], lt = _ref2[0], gt = _ref2[1]; + condPart = this.stepNum ? parseNum(this.stepNum[0]) > 0 ? "" + lt + " " + this.toVar : "" + gt + " " + this.toVar : known ? ((_ref3 = [parseNum(this.fromNum[0]), parseNum(this.toNum[0])], from = _ref3[0], to = _ref3[1], _ref3), from <= to ? "" + lt + " " + to : "" + gt + " " + to) : (cond = this.stepVar ? "" + this.stepVar + " > 0" : "" + this.fromVar + " <= " + this.toVar, "" + cond + " ? " + lt + " " + this.toVar + " : " + gt + " " + this.toVar); + stepPart = this.stepVar ? "" + idx + " += " + this.stepVar : known ? namedIndex ? from <= to ? "++" + idx : "--" + idx : from <= to ? "" + idx + "++" : "" + idx + "--" : namedIndex ? "" + cond + " ? ++" + idx + " : --" + idx : "" + cond + " ? " + idx + "++ : " + idx + "--"; + if (namedIndex) { + varPart = "" + idxName + " = " + varPart; + } + if (namedIndex) { + stepPart = "" + idxName + " = " + stepPart; + } + return [this.makeCode("" + varPart + "; " + condPart + "; " + stepPart)]; + }; + + Range.prototype.compileArray = function(o) { + var args, body, cond, hasArgs, i, idt, post, pre, range, result, vars, _i, _ref2, _ref3, _results; + if (this.fromNum && this.toNum && Math.abs(this.fromNum - this.toNum) <= 20) { + range = (function() { + _results = []; + for (var _i = _ref2 = +this.fromNum, _ref3 = +this.toNum; _ref2 <= _ref3 ? _i <= _ref3 : _i >= _ref3; _ref2 <= _ref3 ? _i++ : _i--){ _results.push(_i); } + return _results; + }).apply(this); + if (this.exclusive) { + range.pop(); + } + return [this.makeCode("[" + (range.join(', ')) + "]")]; + } + idt = this.tab + TAB; + i = o.scope.freeVariable('i'); + result = o.scope.freeVariable('results'); + pre = "\n" + idt + result + " = [];"; + if (this.fromNum && this.toNum) { + o.index = i; + body = fragmentsToText(this.compileNode(o)); + } else { + vars = ("" + i + " = " + this.fromC) + (this.toC !== this.toVar ? ", " + this.toC : ''); + cond = "" + this.fromVar + " <= " + this.toVar; + body = "var " + vars + "; " + cond + " ? " + i + " <" + this.equals + " " + this.toVar + " : " + i + " >" + this.equals + " " + this.toVar + "; " + cond + " ? " + i + "++ : " + i + "--"; + } + post = "{ " + result + ".push(" + i + "); }\n" + idt + "return " + result + ";\n" + o.indent; + hasArgs = function(node) { + return node != null ? node.contains(isLiteralArguments) : void 0; + }; + if (hasArgs(this.from) || hasArgs(this.to)) { + args = ', arguments'; + } + return [this.makeCode("(function() {" + pre + "\n" + idt + "for (" + body + ")" + post + "}).apply(this" + (args != null ? args : '') + ")")]; + }; + + return Range; + + })(Base); + + exports.Slice = Slice = (function(_super) { + __extends(Slice, _super); + + Slice.prototype.children = ['range']; + + function Slice(range) { + this.range = range; + Slice.__super__.constructor.call(this); + } + + Slice.prototype.compileNode = function(o) { + var compiled, compiledText, from, fromCompiled, to, toStr, _ref2; + _ref2 = this.range, to = _ref2.to, from = _ref2.from; + fromCompiled = from && from.compileToFragments(o, LEVEL_PAREN) || [this.makeCode('0')]; + if (to) { + compiled = to.compileToFragments(o, LEVEL_PAREN); + compiledText = fragmentsToText(compiled); + if (!(!this.range.exclusive && +compiledText === -1)) { + toStr = ', ' + (this.range.exclusive ? compiledText : SIMPLENUM.test(compiledText) ? "" + (+compiledText + 1) : (compiled = to.compileToFragments(o, LEVEL_ACCESS), "+" + (fragmentsToText(compiled)) + " + 1 || 9e9")); + } + } + return [this.makeCode(".slice(" + (fragmentsToText(fromCompiled)) + (toStr || '') + ")")]; + }; + + return Slice; + + })(Base); + + exports.Obj = Obj = (function(_super) { + __extends(Obj, _super); + + function Obj(props, generated) { + this.generated = generated != null ? generated : false; + this.objects = this.properties = props || []; + } + + Obj.prototype.children = ['properties']; + + Obj.prototype.compileNode = function(o) { + var answer, i, idt, indent, join, lastNoncom, node, prop, props, _i, _j, _len, _len1; + props = this.properties; + if (!props.length) { + return [this.makeCode(this.front ? '({})' : '{}')]; + } + if (this.generated) { + for (_i = 0, _len = props.length; _i < _len; _i++) { + node = props[_i]; + if (node instanceof Value) { + node.error('cannot have an implicit value in an implicit object'); + } + } + } + idt = o.indent += TAB; + lastNoncom = this.lastNonComment(this.properties); + answer = []; + for (i = _j = 0, _len1 = props.length; _j < _len1; i = ++_j) { + prop = props[i]; + join = i === props.length - 1 ? '' : prop === lastNoncom || prop instanceof Comment ? '\n' : ',\n'; + indent = prop instanceof Comment ? '' : idt; + if (prop instanceof Assign && prop.variable instanceof Value && prop.variable.hasProperties()) { + prop.variable.error('Invalid object key'); + } + if (prop instanceof Value && prop["this"]) { + prop = new Assign(prop.properties[0].name, prop, 'object'); + } + if (!(prop instanceof Comment)) { + if (!(prop instanceof Assign)) { + prop = new Assign(prop, prop, 'object'); + } + (prop.variable.base || prop.variable).asKey = true; + } + if (indent) { + answer.push(this.makeCode(indent)); + } + answer.push.apply(answer, prop.compileToFragments(o, LEVEL_TOP)); + if (join) { + answer.push(this.makeCode(join)); + } + } + answer.unshift(this.makeCode("{" + (props.length && '\n'))); + answer.push(this.makeCode("" + (props.length && '\n' + this.tab) + "}")); + if (this.front) { + return this.wrapInBraces(answer); + } else { + return answer; + } + }; + + Obj.prototype.assigns = function(name) { + var prop, _i, _len, _ref2; + _ref2 = this.properties; + for (_i = 0, _len = _ref2.length; _i < _len; _i++) { + prop = _ref2[_i]; + if (prop.assigns(name)) { + return true; + } + } + return false; + }; + + return Obj; + + })(Base); + + exports.Arr = Arr = (function(_super) { + __extends(Arr, _super); + + function Arr(objs) { + this.objects = objs || []; + } + + Arr.prototype.children = ['objects']; + + Arr.prototype.compileNode = function(o) { + var answer, compiledObjs, fragments, index, obj, _i, _len; + if (!this.objects.length) { + return [this.makeCode('[]')]; + } + o.indent += TAB; + answer = Splat.compileSplattedArray(o, this.objects); + if (answer.length) { + return answer; + } + answer = []; + compiledObjs = (function() { + var _i, _len, _ref2, _results; + _ref2 = this.objects; + _results = []; + for (_i = 0, _len = _ref2.length; _i < _len; _i++) { + obj = _ref2[_i]; + _results.push(obj.compileToFragments(o, LEVEL_LIST)); + } + return _results; + }).call(this); + for (index = _i = 0, _len = compiledObjs.length; _i < _len; index = ++_i) { + fragments = compiledObjs[index]; + if (index) { + answer.push(this.makeCode(", ")); + } + answer.push.apply(answer, fragments); + } + if (fragmentsToText(answer).indexOf('\n') >= 0) { + answer.unshift(this.makeCode("[\n" + o.indent)); + answer.push(this.makeCode("\n" + this.tab + "]")); + } else { + answer.unshift(this.makeCode("[")); + answer.push(this.makeCode("]")); + } + return answer; + }; + + Arr.prototype.assigns = function(name) { + var obj, _i, _len, _ref2; + _ref2 = this.objects; + for (_i = 0, _len = _ref2.length; _i < _len; _i++) { + obj = _ref2[_i]; + if (obj.assigns(name)) { + return true; + } + } + return false; + }; + + return Arr; + + })(Base); + + exports.Class = Class = (function(_super) { + __extends(Class, _super); + + function Class(variable, parent, body) { + this.variable = variable; + this.parent = parent; + this.body = body != null ? body : new Block; + this.boundFuncs = []; + this.body.classBody = true; + } + + Class.prototype.children = ['variable', 'parent', 'body']; + + Class.prototype.determineName = function() { + var decl, tail; + if (!this.variable) { + return null; + } + decl = (tail = last(this.variable.properties)) ? tail instanceof Access && tail.name.value : this.variable.base.value; + if (__indexOf.call(STRICT_PROSCRIBED, decl) >= 0) { + this.variable.error("class variable name may not be " + decl); + } + return decl && (decl = IDENTIFIER.test(decl) && decl); + }; + + Class.prototype.setContext = function(name) { + return this.body.traverseChildren(false, function(node) { + if (node.classBody) { + return false; + } + if (node instanceof Literal && node.value === 'this') { + return node.value = name; + } else if (node instanceof Code) { + node.klass = name; + if (node.bound) { + return node.context = name; + } + } + }); + }; + + Class.prototype.addBoundFunctions = function(o) { + var bvar, lhs, _i, _len, _ref2; + _ref2 = this.boundFuncs; + for (_i = 0, _len = _ref2.length; _i < _len; _i++) { + bvar = _ref2[_i]; + lhs = (new Value(new Literal("this"), [new Access(bvar)])).compile(o); + this.ctor.body.unshift(new Literal("" + lhs + " = " + (utility('bind')) + "(" + lhs + ", this)")); + } + }; + + Class.prototype.addProperties = function(node, name, o) { + var assign, base, exprs, func, props; + props = node.base.properties.slice(0); + exprs = (function() { + var _results; + _results = []; + while (assign = props.shift()) { + if (assign instanceof Assign) { + base = assign.variable.base; + delete assign.context; + func = assign.value; + if (base.value === 'constructor') { + if (this.ctor) { + assign.error('cannot define more than one constructor in a class'); + } + if (func.bound) { + assign.error('cannot define a constructor as a bound function'); + } + if (func instanceof Code) { + assign = this.ctor = func; + } else { + this.externalCtor = o.classScope.freeVariable('class'); + assign = new Assign(new Literal(this.externalCtor), func); + } + } else { + if (assign.variable["this"]) { + func["static"] = true; + } else { + assign.variable = new Value(new Literal(name), [new Access(new Literal('prototype')), new Access(base)]); + if (func instanceof Code && func.bound) { + this.boundFuncs.push(base); + func.bound = false; + } + } + } + } + _results.push(assign); + } + return _results; + }).call(this); + return compact(exprs); + }; + + Class.prototype.walkBody = function(name, o) { + return this.traverseChildren(false, (function(_this) { + return function(child) { + var cont, exps, i, node, _i, _len, _ref2; + cont = true; + if (child instanceof Class) { + return false; + } + if (child instanceof Block) { + _ref2 = exps = child.expressions; + for (i = _i = 0, _len = _ref2.length; _i < _len; i = ++_i) { + node = _ref2[i]; + if (node instanceof Assign && node.variable.looksStatic(name)) { + node.value["static"] = true; + } else if (node instanceof Value && node.isObject(true)) { + cont = false; + exps[i] = _this.addProperties(node, name, o); + } + } + child.expressions = exps = flatten(exps); + } + return cont && !(child instanceof Class); + }; + })(this)); + }; + + Class.prototype.hoistDirectivePrologue = function() { + var expressions, index, node; + index = 0; + expressions = this.body.expressions; + while ((node = expressions[index]) && node instanceof Comment || node instanceof Value && node.isString()) { + ++index; + } + return this.directives = expressions.splice(0, index); + }; + + Class.prototype.ensureConstructor = function(name) { + if (!this.ctor) { + this.ctor = new Code; + if (this.externalCtor) { + this.ctor.body.push(new Literal("" + this.externalCtor + ".apply(this, arguments)")); + } else if (this.parent) { + this.ctor.body.push(new Literal("" + name + ".__super__.constructor.apply(this, arguments)")); + } + this.ctor.body.makeReturn(); + this.body.expressions.unshift(this.ctor); + } + this.ctor.ctor = this.ctor.name = name; + this.ctor.klass = null; + return this.ctor.noReturn = true; + }; + + Class.prototype.compileNode = function(o) { + var args, argumentsNode, func, jumpNode, klass, lname, name, superClass, _ref2; + if (jumpNode = this.body.jumps()) { + jumpNode.error('Class bodies cannot contain pure statements'); + } + if (argumentsNode = this.body.contains(isLiteralArguments)) { + argumentsNode.error("Class bodies shouldn't reference arguments"); + } + name = this.determineName() || '_Class'; + if (name.reserved) { + name = "_" + name; + } + lname = new Literal(name); + func = new Code([], Block.wrap([this.body])); + args = []; + o.classScope = func.makeScope(o.scope); + this.hoistDirectivePrologue(); + this.setContext(name); + this.walkBody(name, o); + this.ensureConstructor(name); + this.addBoundFunctions(o); + this.body.spaced = true; + this.body.expressions.push(lname); + if (this.parent) { + superClass = new Literal(o.classScope.freeVariable('super', false)); + this.body.expressions.unshift(new Extends(lname, superClass)); + func.params.push(new Param(superClass)); + args.push(this.parent); + } + (_ref2 = this.body.expressions).unshift.apply(_ref2, this.directives); + klass = new Parens(new Call(func, args)); + if (this.variable) { + klass = new Assign(this.variable, klass); + } + return klass.compileToFragments(o); + }; + + return Class; + + })(Base); + + exports.Assign = Assign = (function(_super) { + __extends(Assign, _super); + + function Assign(variable, value, context, options) { + var forbidden, name, _ref2; + this.variable = variable; + this.value = value; + this.context = context; + this.param = options && options.param; + this.subpattern = options && options.subpattern; + forbidden = (_ref2 = (name = this.variable.unwrapAll().value), __indexOf.call(STRICT_PROSCRIBED, _ref2) >= 0); + if (forbidden && this.context !== 'object') { + this.variable.error("variable name may not be \"" + name + "\""); + } + } + + Assign.prototype.children = ['variable', 'value']; + + Assign.prototype.isStatement = function(o) { + return (o != null ? o.level : void 0) === LEVEL_TOP && (this.context != null) && __indexOf.call(this.context, "?") >= 0; + }; + + Assign.prototype.assigns = function(name) { + return this[this.context === 'object' ? 'value' : 'variable'].assigns(name); + }; + + Assign.prototype.unfoldSoak = function(o) { + return unfoldSoak(o, this, 'variable'); + }; + + Assign.prototype.compileNode = function(o) { + var answer, compiledName, isValue, match, name, val, varBase, _ref2, _ref3, _ref4; + if (isValue = this.variable instanceof Value) { + if (this.variable.isArray() || this.variable.isObject()) { + return this.compilePatternMatch(o); + } + if (this.variable.isSplice()) { + return this.compileSplice(o); + } + if ((_ref2 = this.context) === '||=' || _ref2 === '&&=' || _ref2 === '?=') { + return this.compileConditional(o); + } + } + compiledName = this.variable.compileToFragments(o, LEVEL_LIST); + name = fragmentsToText(compiledName); + if (!this.context) { + varBase = this.variable.unwrapAll(); + if (!varBase.isAssignable()) { + this.variable.error("\"" + (this.variable.compile(o)) + "\" cannot be assigned"); + } + if (!(typeof varBase.hasProperties === "function" ? varBase.hasProperties() : void 0)) { + if (this.param) { + o.scope.add(name, 'var'); + } else { + o.scope.find(name); + } + } + } + if (this.value instanceof Code && (match = METHOD_DEF.exec(name))) { + if (match[2]) { + this.value.klass = match[1]; + } + this.value.name = (_ref3 = (_ref4 = match[3]) != null ? _ref4 : match[4]) != null ? _ref3 : match[5]; + } + val = this.value.compileToFragments(o, LEVEL_LIST); + if (this.context === 'object') { + return compiledName.concat(this.makeCode(": "), val); + } + answer = compiledName.concat(this.makeCode(" " + (this.context || '=') + " "), val); + if (o.level <= LEVEL_LIST) { + return answer; + } else { + return this.wrapInBraces(answer); + } + }; + + Assign.prototype.compilePatternMatch = function(o) { + var acc, assigns, code, fragments, i, idx, isObject, ivar, name, obj, objects, olen, ref, rest, splat, top, val, value, vvar, vvarText, _i, _len, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7; + top = o.level === LEVEL_TOP; + value = this.value; + objects = this.variable.base.objects; + if (!(olen = objects.length)) { + code = value.compileToFragments(o); + if (o.level >= LEVEL_OP) { + return this.wrapInBraces(code); + } else { + return code; + } + } + isObject = this.variable.isObject(); + if (top && olen === 1 && !((obj = objects[0]) instanceof Splat)) { + if (obj instanceof Assign) { + _ref2 = obj, (_ref3 = _ref2.variable, idx = _ref3.base), obj = _ref2.value; + } else { + idx = isObject ? obj["this"] ? obj.properties[0].name : obj : new Literal(0); + } + acc = IDENTIFIER.test(idx.unwrap().value || 0); + value = new Value(value); + value.properties.push(new (acc ? Access : Index)(idx)); + if (_ref4 = obj.unwrap().value, __indexOf.call(RESERVED, _ref4) >= 0) { + obj.error("assignment to a reserved word: " + (obj.compile(o))); + } + return new Assign(obj, value, null, { + param: this.param + }).compileToFragments(o, LEVEL_TOP); + } + vvar = value.compileToFragments(o, LEVEL_LIST); + vvarText = fragmentsToText(vvar); + assigns = []; + splat = false; + if (!IDENTIFIER.test(vvarText) || this.variable.assigns(vvarText)) { + assigns.push([this.makeCode("" + (ref = o.scope.freeVariable('ref')) + " = ")].concat(__slice.call(vvar))); + vvar = [this.makeCode(ref)]; + vvarText = ref; + } + for (i = _i = 0, _len = objects.length; _i < _len; i = ++_i) { + obj = objects[i]; + idx = i; + if (isObject) { + if (obj instanceof Assign) { + _ref5 = obj, (_ref6 = _ref5.variable, idx = _ref6.base), obj = _ref5.value; + } else { + if (obj.base instanceof Parens) { + _ref7 = new Value(obj.unwrapAll()).cacheReference(o), obj = _ref7[0], idx = _ref7[1]; + } else { + idx = obj["this"] ? obj.properties[0].name : obj; + } + } + } + if (!splat && obj instanceof Splat) { + name = obj.name.unwrap().value; + obj = obj.unwrap(); + val = "" + olen + " <= " + vvarText + ".length ? " + (utility('slice')) + ".call(" + vvarText + ", " + i; + if (rest = olen - i - 1) { + ivar = o.scope.freeVariable('i'); + val += ", " + ivar + " = " + vvarText + ".length - " + rest + ") : (" + ivar + " = " + i + ", [])"; + } else { + val += ") : []"; + } + val = new Literal(val); + splat = "" + ivar + "++"; + } else { + name = obj.unwrap().value; + if (obj instanceof Splat) { + obj.error("multiple splats are disallowed in an assignment"); + } + if (typeof idx === 'number') { + idx = new Literal(splat || idx); + acc = false; + } else { + acc = isObject && IDENTIFIER.test(idx.unwrap().value || 0); + } + val = new Value(new Literal(vvarText), [new (acc ? Access : Index)(idx)]); + } + if ((name != null) && __indexOf.call(RESERVED, name) >= 0) { + obj.error("assignment to a reserved word: " + (obj.compile(o))); + } + assigns.push(new Assign(obj, val, null, { + param: this.param, + subpattern: true + }).compileToFragments(o, LEVEL_LIST)); + } + if (!(top || this.subpattern)) { + assigns.push(vvar); + } + fragments = this.joinFragmentArrays(assigns, ', '); + if (o.level < LEVEL_LIST) { + return fragments; + } else { + return this.wrapInBraces(fragments); + } + }; + + Assign.prototype.compileConditional = function(o) { + var fragments, left, right, _ref2; + _ref2 = this.variable.cacheReference(o), left = _ref2[0], right = _ref2[1]; + if (!left.properties.length && left.base instanceof Literal && left.base.value !== "this" && !o.scope.check(left.base.value)) { + this.variable.error("the variable \"" + left.base.value + "\" can't be assigned with " + this.context + " because it has not been declared before"); + } + if (__indexOf.call(this.context, "?") >= 0) { + o.isExistentialEquals = true; + return new If(new Existence(left), right, { + type: 'if' + }).addElse(new Assign(right, this.value, '=')).compileToFragments(o); + } else { + fragments = new Op(this.context.slice(0, -1), left, new Assign(right, this.value, '=')).compileToFragments(o); + if (o.level <= LEVEL_LIST) { + return fragments; + } else { + return this.wrapInBraces(fragments); + } + } + }; + + Assign.prototype.compileSplice = function(o) { + var answer, exclusive, from, fromDecl, fromRef, name, to, valDef, valRef, _ref2, _ref3, _ref4; + _ref2 = this.variable.properties.pop().range, from = _ref2.from, to = _ref2.to, exclusive = _ref2.exclusive; + name = this.variable.compile(o); + if (from) { + _ref3 = this.cacheToCodeFragments(from.cache(o, LEVEL_OP)), fromDecl = _ref3[0], fromRef = _ref3[1]; + } else { + fromDecl = fromRef = '0'; + } + if (to) { + if (from instanceof Value && from.isSimpleNumber() && to instanceof Value && to.isSimpleNumber()) { + to = to.compile(o) - fromRef; + if (!exclusive) { + to += 1; + } + } else { + to = to.compile(o, LEVEL_ACCESS) + ' - ' + fromRef; + if (!exclusive) { + to += ' + 1'; + } + } + } else { + to = "9e9"; + } + _ref4 = this.value.cache(o, LEVEL_LIST), valDef = _ref4[0], valRef = _ref4[1]; + answer = [].concat(this.makeCode("[].splice.apply(" + name + ", [" + fromDecl + ", " + to + "].concat("), valDef, this.makeCode(")), "), valRef); + if (o.level > LEVEL_TOP) { + return this.wrapInBraces(answer); + } else { + return answer; + } + }; + + return Assign; + + })(Base); + + exports.Code = Code = (function(_super) { + __extends(Code, _super); + + function Code(params, body, tag) { + this.params = params || []; + this.body = body || new Block; + this.bound = tag === 'boundfunc'; + } + + Code.prototype.children = ['params', 'body']; + + Code.prototype.isStatement = function() { + return !!this.ctor; + }; + + Code.prototype.jumps = NO; + + Code.prototype.makeScope = function(parentScope) { + return new Scope(parentScope, this.body, this); + }; + + Code.prototype.compileNode = function(o) { + var answer, boundfunc, code, exprs, i, lit, p, param, params, ref, splats, uniqs, val, wasEmpty, wrapper, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _len5, _m, _n, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7; + if (this.bound && ((_ref2 = o.scope.method) != null ? _ref2.bound : void 0)) { + this.context = o.scope.method.context; + } + if (this.bound && !this.context) { + this.context = '_this'; + wrapper = new Code([new Param(new Literal(this.context))], new Block([this])); + boundfunc = new Call(wrapper, [new Literal('this')]); + boundfunc.updateLocationDataIfMissing(this.locationData); + return boundfunc.compileNode(o); + } + o.scope = del(o, 'classScope') || this.makeScope(o.scope); + o.scope.shared = del(o, 'sharedScope'); + o.indent += TAB; + delete o.bare; + delete o.isExistentialEquals; + params = []; + exprs = []; + _ref3 = this.params; + for (_i = 0, _len = _ref3.length; _i < _len; _i++) { + param = _ref3[_i]; + o.scope.parameter(param.asReference(o)); + } + _ref4 = this.params; + for (_j = 0, _len1 = _ref4.length; _j < _len1; _j++) { + param = _ref4[_j]; + if (!param.splat) { + continue; + } + _ref5 = this.params; + for (_k = 0, _len2 = _ref5.length; _k < _len2; _k++) { + p = _ref5[_k].name; + if (p["this"]) { + p = p.properties[0].name; + } + if (p.value) { + o.scope.add(p.value, 'var', true); + } + } + splats = new Assign(new Value(new Arr((function() { + var _l, _len3, _ref6, _results; + _ref6 = this.params; + _results = []; + for (_l = 0, _len3 = _ref6.length; _l < _len3; _l++) { + p = _ref6[_l]; + _results.push(p.asReference(o)); + } + return _results; + }).call(this))), new Value(new Literal('arguments'))); + break; + } + _ref6 = this.params; + for (_l = 0, _len3 = _ref6.length; _l < _len3; _l++) { + param = _ref6[_l]; + if (param.isComplex()) { + val = ref = param.asReference(o); + if (param.value) { + val = new Op('?', ref, param.value); + } + exprs.push(new Assign(new Value(param.name), val, '=', { + param: true + })); + } else { + ref = param; + if (param.value) { + lit = new Literal(ref.name.value + ' == null'); + val = new Assign(new Value(param.name), param.value, '='); + exprs.push(new If(lit, val)); + } + } + if (!splats) { + params.push(ref); + } + } + wasEmpty = this.body.isEmpty(); + if (splats) { + exprs.unshift(splats); + } + if (exprs.length) { + (_ref7 = this.body.expressions).unshift.apply(_ref7, exprs); + } + for (i = _m = 0, _len4 = params.length; _m < _len4; i = ++_m) { + p = params[i]; + params[i] = p.compileToFragments(o); + o.scope.parameter(fragmentsToText(params[i])); + } + uniqs = []; + this.eachParamName(function(name, node) { + if (__indexOf.call(uniqs, name) >= 0) { + node.error("multiple parameters named '" + name + "'"); + } + return uniqs.push(name); + }); + if (!(wasEmpty || this.noReturn)) { + this.body.makeReturn(); + } + code = 'function'; + if (this.ctor) { + code += ' ' + this.name; + } + code += '('; + answer = [this.makeCode(code)]; + for (i = _n = 0, _len5 = params.length; _n < _len5; i = ++_n) { + p = params[i]; + if (i) { + answer.push(this.makeCode(", ")); + } + answer.push.apply(answer, p); + } + answer.push(this.makeCode(') {')); + if (!this.body.isEmpty()) { + answer = answer.concat(this.makeCode("\n"), this.body.compileWithDeclarations(o), this.makeCode("\n" + this.tab)); + } + answer.push(this.makeCode('}')); + if (this.ctor) { + return [this.makeCode(this.tab)].concat(__slice.call(answer)); + } + if (this.front || (o.level >= LEVEL_ACCESS)) { + return this.wrapInBraces(answer); + } else { + return answer; + } + }; + + Code.prototype.eachParamName = function(iterator) { + var param, _i, _len, _ref2, _results; + _ref2 = this.params; + _results = []; + for (_i = 0, _len = _ref2.length; _i < _len; _i++) { + param = _ref2[_i]; + _results.push(param.eachName(iterator)); + } + return _results; + }; + + Code.prototype.traverseChildren = function(crossScope, func) { + if (crossScope) { + return Code.__super__.traverseChildren.call(this, crossScope, func); + } + }; + + return Code; + + })(Base); + + exports.Param = Param = (function(_super) { + __extends(Param, _super); + + function Param(name, value, splat) { + var _ref2; + this.name = name; + this.value = value; + this.splat = splat; + if (_ref2 = (name = this.name.unwrapAll().value), __indexOf.call(STRICT_PROSCRIBED, _ref2) >= 0) { + this.name.error("parameter name \"" + name + "\" is not allowed"); + } + } + + Param.prototype.children = ['name', 'value']; + + Param.prototype.compileToFragments = function(o) { + return this.name.compileToFragments(o, LEVEL_LIST); + }; + + Param.prototype.asReference = function(o) { + var node; + if (this.reference) { + return this.reference; + } + node = this.name; + if (node["this"]) { + node = node.properties[0].name; + if (node.value.reserved) { + node = new Literal(o.scope.freeVariable(node.value)); + } + } else if (node.isComplex()) { + node = new Literal(o.scope.freeVariable('arg')); + } + node = new Value(node); + if (this.splat) { + node = new Splat(node); + } + node.updateLocationDataIfMissing(this.locationData); + return this.reference = node; + }; + + Param.prototype.isComplex = function() { + return this.name.isComplex(); + }; + + Param.prototype.eachName = function(iterator, name) { + var atParam, node, obj, _i, _len, _ref2; + if (name == null) { + name = this.name; + } + atParam = function(obj) { + var node; + node = obj.properties[0].name; + if (!node.value.reserved) { + return iterator(node.value, node); + } + }; + if (name instanceof Literal) { + return iterator(name.value, name); + } + if (name instanceof Value) { + return atParam(name); + } + _ref2 = name.objects; + for (_i = 0, _len = _ref2.length; _i < _len; _i++) { + obj = _ref2[_i]; + if (obj instanceof Assign) { + this.eachName(iterator, obj.value.unwrap()); + } else if (obj instanceof Splat) { + node = obj.name.unwrap(); + iterator(node.value, node); + } else if (obj instanceof Value) { + if (obj.isArray() || obj.isObject()) { + this.eachName(iterator, obj.base); + } else if (obj["this"]) { + atParam(obj); + } else { + iterator(obj.base.value, obj.base); + } + } else { + obj.error("illegal parameter " + (obj.compile())); + } + } + }; + + return Param; + + })(Base); + + exports.Splat = Splat = (function(_super) { + __extends(Splat, _super); + + Splat.prototype.children = ['name']; + + Splat.prototype.isAssignable = YES; + + function Splat(name) { + this.name = name.compile ? name : new Literal(name); + } + + Splat.prototype.assigns = function(name) { + return this.name.assigns(name); + }; + + Splat.prototype.compileToFragments = function(o) { + return this.name.compileToFragments(o); + }; + + Splat.prototype.unwrap = function() { + return this.name; + }; + + Splat.compileSplattedArray = function(o, list, apply) { + var args, base, compiledNode, concatPart, fragments, i, index, node, _i, _len; + index = -1; + while ((node = list[++index]) && !(node instanceof Splat)) { + continue; + } + if (index >= list.length) { + return []; + } + if (list.length === 1) { + node = list[0]; + fragments = node.compileToFragments(o, LEVEL_LIST); + if (apply) { + return fragments; + } + return [].concat(node.makeCode("" + (utility('slice')) + ".call("), fragments, node.makeCode(")")); + } + args = list.slice(index); + for (i = _i = 0, _len = args.length; _i < _len; i = ++_i) { + node = args[i]; + compiledNode = node.compileToFragments(o, LEVEL_LIST); + args[i] = node instanceof Splat ? [].concat(node.makeCode("" + (utility('slice')) + ".call("), compiledNode, node.makeCode(")")) : [].concat(node.makeCode("["), compiledNode, node.makeCode("]")); + } + if (index === 0) { + node = list[0]; + concatPart = node.joinFragmentArrays(args.slice(1), ', '); + return args[0].concat(node.makeCode(".concat("), concatPart, node.makeCode(")")); + } + base = (function() { + var _j, _len1, _ref2, _results; + _ref2 = list.slice(0, index); + _results = []; + for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) { + node = _ref2[_j]; + _results.push(node.compileToFragments(o, LEVEL_LIST)); + } + return _results; + })(); + base = list[0].joinFragmentArrays(base, ', '); + concatPart = list[index].joinFragmentArrays(args, ', '); + return [].concat(list[0].makeCode("["), base, list[index].makeCode("].concat("), concatPart, (last(list)).makeCode(")")); + }; + + return Splat; + + })(Base); + + exports.While = While = (function(_super) { + __extends(While, _super); + + function While(condition, options) { + this.condition = (options != null ? options.invert : void 0) ? condition.invert() : condition; + this.guard = options != null ? options.guard : void 0; + } + + While.prototype.children = ['condition', 'guard', 'body']; + + While.prototype.isStatement = YES; + + While.prototype.makeReturn = function(res) { + if (res) { + return While.__super__.makeReturn.apply(this, arguments); + } else { + this.returns = !this.jumps({ + loop: true + }); + return this; + } + }; + + While.prototype.addBody = function(body) { + this.body = body; + return this; + }; + + While.prototype.jumps = function() { + var expressions, jumpNode, node, _i, _len; + expressions = this.body.expressions; + if (!expressions.length) { + return false; + } + for (_i = 0, _len = expressions.length; _i < _len; _i++) { + node = expressions[_i]; + if (jumpNode = node.jumps({ + loop: true + })) { + return jumpNode; + } + } + return false; + }; + + While.prototype.compileNode = function(o) { + var answer, body, rvar, set; + o.indent += TAB; + set = ''; + body = this.body; + if (body.isEmpty()) { + body = this.makeCode(''); + } else { + if (this.returns) { + body.makeReturn(rvar = o.scope.freeVariable('results')); + set = "" + this.tab + rvar + " = [];\n"; + } + if (this.guard) { + if (body.expressions.length > 1) { + body.expressions.unshift(new If((new Parens(this.guard)).invert(), new Literal("continue"))); + } else { + if (this.guard) { + body = Block.wrap([new If(this.guard, body)]); + } + } + } + body = [].concat(this.makeCode("\n"), body.compileToFragments(o, LEVEL_TOP), this.makeCode("\n" + this.tab)); + } + answer = [].concat(this.makeCode(set + this.tab + "while ("), this.condition.compileToFragments(o, LEVEL_PAREN), this.makeCode(") {"), body, this.makeCode("}")); + if (this.returns) { + answer.push(this.makeCode("\n" + this.tab + "return " + rvar + ";")); + } + return answer; + }; + + return While; + + })(Base); + + exports.Op = Op = (function(_super) { + var CONVERSIONS, INVERSIONS; + + __extends(Op, _super); + + function Op(op, first, second, flip) { + if (op === 'in') { + return new In(first, second); + } + if (op === 'do') { + return this.generateDo(first); + } + if (op === 'new') { + if (first instanceof Call && !first["do"] && !first.isNew) { + return first.newInstance(); + } + if (first instanceof Code && first.bound || first["do"]) { + first = new Parens(first); + } + } + this.operator = CONVERSIONS[op] || op; + this.first = first; + this.second = second; + this.flip = !!flip; + return this; + } + + CONVERSIONS = { + '==': '===', + '!=': '!==', + 'of': 'in' + }; + + INVERSIONS = { + '!==': '===', + '===': '!==' + }; + + Op.prototype.children = ['first', 'second']; + + Op.prototype.isSimpleNumber = NO; + + Op.prototype.isUnary = function() { + return !this.second; + }; + + Op.prototype.isComplex = function() { + var _ref2; + return !(this.isUnary() && ((_ref2 = this.operator) === '+' || _ref2 === '-')) || this.first.isComplex(); + }; + + Op.prototype.isChainable = function() { + var _ref2; + return (_ref2 = this.operator) === '<' || _ref2 === '>' || _ref2 === '>=' || _ref2 === '<=' || _ref2 === '===' || _ref2 === '!=='; + }; + + Op.prototype.invert = function() { + var allInvertable, curr, fst, op, _ref2; + if (this.isChainable() && this.first.isChainable()) { + allInvertable = true; + curr = this; + while (curr && curr.operator) { + allInvertable && (allInvertable = curr.operator in INVERSIONS); + curr = curr.first; + } + if (!allInvertable) { + return new Parens(this).invert(); + } + curr = this; + while (curr && curr.operator) { + curr.invert = !curr.invert; + curr.operator = INVERSIONS[curr.operator]; + curr = curr.first; + } + return this; + } else if (op = INVERSIONS[this.operator]) { + this.operator = op; + if (this.first.unwrap() instanceof Op) { + this.first.invert(); + } + return this; + } else if (this.second) { + return new Parens(this).invert(); + } else if (this.operator === '!' && (fst = this.first.unwrap()) instanceof Op && ((_ref2 = fst.operator) === '!' || _ref2 === 'in' || _ref2 === 'instanceof')) { + return fst; + } else { + return new Op('!', this); + } + }; + + Op.prototype.unfoldSoak = function(o) { + var _ref2; + return ((_ref2 = this.operator) === '++' || _ref2 === '--' || _ref2 === 'delete') && unfoldSoak(o, this, 'first'); + }; + + Op.prototype.generateDo = function(exp) { + var call, func, param, passedParams, ref, _i, _len, _ref2; + passedParams = []; + func = exp instanceof Assign && (ref = exp.value.unwrap()) instanceof Code ? ref : exp; + _ref2 = func.params || []; + for (_i = 0, _len = _ref2.length; _i < _len; _i++) { + param = _ref2[_i]; + if (param.value) { + passedParams.push(param.value); + delete param.value; + } else { + passedParams.push(param); + } + } + call = new Call(exp, passedParams); + call["do"] = true; + return call; + }; + + Op.prototype.compileNode = function(o) { + var answer, isChain, _ref2, _ref3; + isChain = this.isChainable() && this.first.isChainable(); + if (!isChain) { + this.first.front = this.front; + } + if (this.operator === 'delete' && o.scope.check(this.first.unwrapAll().value)) { + this.error('delete operand may not be argument or var'); + } + if (((_ref2 = this.operator) === '--' || _ref2 === '++') && (_ref3 = this.first.unwrapAll().value, __indexOf.call(STRICT_PROSCRIBED, _ref3) >= 0)) { + this.error("cannot increment/decrement \"" + (this.first.unwrapAll().value) + "\""); + } + if (this.isUnary()) { + return this.compileUnary(o); + } + if (isChain) { + return this.compileChain(o); + } + if (this.operator === '?') { + return this.compileExistence(o); + } + answer = [].concat(this.first.compileToFragments(o, LEVEL_OP), this.makeCode(' ' + this.operator + ' '), this.second.compileToFragments(o, LEVEL_OP)); + if (o.level <= LEVEL_OP) { + return answer; + } else { + return this.wrapInBraces(answer); + } + }; + + Op.prototype.compileChain = function(o) { + var fragments, fst, shared, _ref2; + _ref2 = this.first.second.cache(o), this.first.second = _ref2[0], shared = _ref2[1]; + fst = this.first.compileToFragments(o, LEVEL_OP); + fragments = fst.concat(this.makeCode(" " + (this.invert ? '&&' : '||') + " "), shared.compileToFragments(o), this.makeCode(" " + this.operator + " "), this.second.compileToFragments(o, LEVEL_OP)); + return this.wrapInBraces(fragments); + }; + + Op.prototype.compileExistence = function(o) { + var fst, ref; + if (this.first.isComplex()) { + ref = new Literal(o.scope.freeVariable('ref')); + fst = new Parens(new Assign(ref, this.first)); + } else { + fst = this.first; + ref = fst; + } + return new If(new Existence(fst), ref, { + type: 'if' + }).addElse(this.second).compileToFragments(o); + }; + + Op.prototype.compileUnary = function(o) { + var op, parts, plusMinus; + parts = []; + op = this.operator; + parts.push([this.makeCode(op)]); + if (op === '!' && this.first instanceof Existence) { + this.first.negated = !this.first.negated; + return this.first.compileToFragments(o); + } + if (o.level >= LEVEL_ACCESS) { + return (new Parens(this)).compileToFragments(o); + } + plusMinus = op === '+' || op === '-'; + if ((op === 'new' || op === 'typeof' || op === 'delete') || plusMinus && this.first instanceof Op && this.first.operator === op) { + parts.push([this.makeCode(' ')]); + } + if ((plusMinus && this.first instanceof Op) || (op === 'new' && this.first.isStatement(o))) { + this.first = new Parens(this.first); + } + parts.push(this.first.compileToFragments(o, LEVEL_OP)); + if (this.flip) { + parts.reverse(); + } + return this.joinFragmentArrays(parts, ''); + }; + + Op.prototype.toString = function(idt) { + return Op.__super__.toString.call(this, idt, this.constructor.name + ' ' + this.operator); + }; + + return Op; + + })(Base); + + exports.In = In = (function(_super) { + __extends(In, _super); + + function In(object, array) { + this.object = object; + this.array = array; + } + + In.prototype.children = ['object', 'array']; + + In.prototype.invert = NEGATE; + + In.prototype.compileNode = function(o) { + var hasSplat, obj, _i, _len, _ref2; + if (this.array instanceof Value && this.array.isArray()) { + _ref2 = this.array.base.objects; + for (_i = 0, _len = _ref2.length; _i < _len; _i++) { + obj = _ref2[_i]; + if (!(obj instanceof Splat)) { + continue; + } + hasSplat = true; + break; + } + if (!hasSplat) { + return this.compileOrTest(o); + } + } + return this.compileLoopTest(o); + }; + + In.prototype.compileOrTest = function(o) { + var cmp, cnj, i, item, ref, sub, tests, _i, _len, _ref2, _ref3, _ref4; + if (this.array.base.objects.length === 0) { + return [this.makeCode("" + (!!this.negated))]; + } + _ref2 = this.object.cache(o, LEVEL_OP), sub = _ref2[0], ref = _ref2[1]; + _ref3 = this.negated ? [' !== ', ' && '] : [' === ', ' || '], cmp = _ref3[0], cnj = _ref3[1]; + tests = []; + _ref4 = this.array.base.objects; + for (i = _i = 0, _len = _ref4.length; _i < _len; i = ++_i) { + item = _ref4[i]; + if (i) { + tests.push(this.makeCode(cnj)); + } + tests = tests.concat((i ? ref : sub), this.makeCode(cmp), item.compileToFragments(o, LEVEL_ACCESS)); + } + if (o.level < LEVEL_OP) { + return tests; + } else { + return this.wrapInBraces(tests); + } + }; + + In.prototype.compileLoopTest = function(o) { + var fragments, ref, sub, _ref2; + _ref2 = this.object.cache(o, LEVEL_LIST), sub = _ref2[0], ref = _ref2[1]; + fragments = [].concat(this.makeCode(utility('indexOf') + ".call("), this.array.compileToFragments(o, LEVEL_LIST), this.makeCode(", "), ref, this.makeCode(") " + (this.negated ? '< 0' : '>= 0'))); + if (fragmentsToText(sub) === fragmentsToText(ref)) { + return fragments; + } + fragments = sub.concat(this.makeCode(', '), fragments); + if (o.level < LEVEL_LIST) { + return fragments; + } else { + return this.wrapInBraces(fragments); + } + }; + + In.prototype.toString = function(idt) { + return In.__super__.toString.call(this, idt, this.constructor.name + (this.negated ? '!' : '')); + }; + + return In; + + })(Base); + + exports.Try = Try = (function(_super) { + __extends(Try, _super); + + function Try(attempt, errorVariable, recovery, ensure) { + this.attempt = attempt; + this.errorVariable = errorVariable; + this.recovery = recovery; + this.ensure = ensure; + } + + Try.prototype.children = ['attempt', 'recovery', 'ensure']; + + Try.prototype.isStatement = YES; + + Try.prototype.jumps = function(o) { + var _ref2; + return this.attempt.jumps(o) || ((_ref2 = this.recovery) != null ? _ref2.jumps(o) : void 0); + }; + + Try.prototype.makeReturn = function(res) { + if (this.attempt) { + this.attempt = this.attempt.makeReturn(res); + } + if (this.recovery) { + this.recovery = this.recovery.makeReturn(res); + } + return this; + }; + + Try.prototype.compileNode = function(o) { + var catchPart, ensurePart, placeholder, tryPart; + o.indent += TAB; + tryPart = this.attempt.compileToFragments(o, LEVEL_TOP); + catchPart = this.recovery ? (placeholder = new Literal('_error'), this.errorVariable ? this.recovery.unshift(new Assign(this.errorVariable, placeholder)) : void 0, [].concat(this.makeCode(" catch ("), placeholder.compileToFragments(o), this.makeCode(") {\n"), this.recovery.compileToFragments(o, LEVEL_TOP), this.makeCode("\n" + this.tab + "}"))) : !(this.ensure || this.recovery) ? [this.makeCode(' catch (_error) {}')] : []; + ensurePart = this.ensure ? [].concat(this.makeCode(" finally {\n"), this.ensure.compileToFragments(o, LEVEL_TOP), this.makeCode("\n" + this.tab + "}")) : []; + return [].concat(this.makeCode("" + this.tab + "try {\n"), tryPart, this.makeCode("\n" + this.tab + "}"), catchPart, ensurePart); + }; + + return Try; + + })(Base); + + exports.Throw = Throw = (function(_super) { + __extends(Throw, _super); + + function Throw(expression) { + this.expression = expression; + } + + Throw.prototype.children = ['expression']; + + Throw.prototype.isStatement = YES; + + Throw.prototype.jumps = NO; + + Throw.prototype.makeReturn = THIS; + + Throw.prototype.compileNode = function(o) { + return [].concat(this.makeCode(this.tab + "throw "), this.expression.compileToFragments(o), this.makeCode(";")); + }; + + return Throw; + + })(Base); + + exports.Existence = Existence = (function(_super) { + __extends(Existence, _super); + + function Existence(expression) { + this.expression = expression; + } + + Existence.prototype.children = ['expression']; + + Existence.prototype.invert = NEGATE; + + Existence.prototype.compileNode = function(o) { + var cmp, cnj, code, _ref2; + this.expression.front = this.front; + code = this.expression.compile(o, LEVEL_OP); + if (IDENTIFIER.test(code) && !o.scope.check(code)) { + _ref2 = this.negated ? ['===', '||'] : ['!==', '&&'], cmp = _ref2[0], cnj = _ref2[1]; + code = "typeof " + code + " " + cmp + " \"undefined\" " + cnj + " " + code + " " + cmp + " null"; + } else { + code = "" + code + " " + (this.negated ? '==' : '!=') + " null"; + } + return [this.makeCode(o.level <= LEVEL_COND ? code : "(" + code + ")")]; + }; + + return Existence; + + })(Base); + + exports.Parens = Parens = (function(_super) { + __extends(Parens, _super); + + function Parens(body) { + this.body = body; + } + + Parens.prototype.children = ['body']; + + Parens.prototype.unwrap = function() { + return this.body; + }; + + Parens.prototype.isComplex = function() { + return this.body.isComplex(); + }; + + Parens.prototype.compileNode = function(o) { + var bare, expr, fragments; + expr = this.body.unwrap(); + if (expr instanceof Value && expr.isAtomic()) { + expr.front = this.front; + return expr.compileToFragments(o); + } + fragments = expr.compileToFragments(o, LEVEL_PAREN); + bare = o.level < LEVEL_OP && (expr instanceof Op || expr instanceof Call || (expr instanceof For && expr.returns)); + if (bare) { + return fragments; + } else { + return this.wrapInBraces(fragments); + } + }; + + return Parens; + + })(Base); + + exports.For = For = (function(_super) { + __extends(For, _super); + + function For(body, source) { + var _ref2; + this.source = source.source, this.guard = source.guard, this.step = source.step, this.name = source.name, this.index = source.index; + this.body = Block.wrap([body]); + this.own = !!source.own; + this.object = !!source.object; + if (this.object) { + _ref2 = [this.index, this.name], this.name = _ref2[0], this.index = _ref2[1]; + } + if (this.index instanceof Value) { + this.index.error('index cannot be a pattern matching expression'); + } + this.range = this.source instanceof Value && this.source.base instanceof Range && !this.source.properties.length; + this.pattern = this.name instanceof Value; + if (this.range && this.index) { + this.index.error('indexes do not apply to range loops'); + } + if (this.range && this.pattern) { + this.name.error('cannot pattern match over range loops'); + } + if (this.own && !this.object) { + this.name.error('cannot use own with for-in'); + } + this.returns = false; + } + + For.prototype.children = ['body', 'source', 'guard', 'step']; + + For.prototype.compileNode = function(o) { + var body, bodyFragments, compare, compareDown, declare, declareDown, defPart, defPartFragments, down, forPartFragments, guardPart, idt1, increment, index, ivar, kvar, kvarAssign, lastJumps, lvar, name, namePart, ref, resultPart, returnResult, rvar, scope, source, step, stepNum, stepVar, svar, varPart, _ref2, _ref3; + body = Block.wrap([this.body]); + lastJumps = (_ref2 = last(body.expressions)) != null ? _ref2.jumps() : void 0; + if (lastJumps && lastJumps instanceof Return) { + this.returns = false; + } + source = this.range ? this.source.base : this.source; + scope = o.scope; + name = this.name && (this.name.compile(o, LEVEL_LIST)); + index = this.index && (this.index.compile(o, LEVEL_LIST)); + if (name && !this.pattern) { + scope.find(name); + } + if (index) { + scope.find(index); + } + if (this.returns) { + rvar = scope.freeVariable('results'); + } + ivar = (this.object && index) || scope.freeVariable('i'); + kvar = (this.range && name) || index || ivar; + kvarAssign = kvar !== ivar ? "" + kvar + " = " : ""; + if (this.step && !this.range) { + _ref3 = this.cacheToCodeFragments(this.step.cache(o, LEVEL_LIST)), step = _ref3[0], stepVar = _ref3[1]; + stepNum = stepVar.match(NUMBER); + } + if (this.pattern) { + name = ivar; + } + varPart = ''; + guardPart = ''; + defPart = ''; + idt1 = this.tab + TAB; + if (this.range) { + forPartFragments = source.compileToFragments(merge(o, { + index: ivar, + name: name, + step: this.step + })); + } else { + svar = this.source.compile(o, LEVEL_LIST); + if ((name || this.own) && !IDENTIFIER.test(svar)) { + defPart += "" + this.tab + (ref = scope.freeVariable('ref')) + " = " + svar + ";\n"; + svar = ref; + } + if (name && !this.pattern) { + namePart = "" + name + " = " + svar + "[" + kvar + "]"; + } + if (!this.object) { + if (step !== stepVar) { + defPart += "" + this.tab + step + ";\n"; + } + if (!(this.step && stepNum && (down = parseNum(stepNum[0]) < 0))) { + lvar = scope.freeVariable('len'); + } + declare = "" + kvarAssign + ivar + " = 0, " + lvar + " = " + svar + ".length"; + declareDown = "" + kvarAssign + ivar + " = " + svar + ".length - 1"; + compare = "" + ivar + " < " + lvar; + compareDown = "" + ivar + " >= 0"; + if (this.step) { + if (stepNum) { + if (down) { + compare = compareDown; + declare = declareDown; + } + } else { + compare = "" + stepVar + " > 0 ? " + compare + " : " + compareDown; + declare = "(" + stepVar + " > 0 ? (" + declare + ") : " + declareDown + ")"; + } + increment = "" + ivar + " += " + stepVar; + } else { + increment = "" + (kvar !== ivar ? "++" + ivar : "" + ivar + "++"); + } + forPartFragments = [this.makeCode("" + declare + "; " + compare + "; " + kvarAssign + increment)]; + } + } + if (this.returns) { + resultPart = "" + this.tab + rvar + " = [];\n"; + returnResult = "\n" + this.tab + "return " + rvar + ";"; + body.makeReturn(rvar); + } + if (this.guard) { + if (body.expressions.length > 1) { + body.expressions.unshift(new If((new Parens(this.guard)).invert(), new Literal("continue"))); + } else { + if (this.guard) { + body = Block.wrap([new If(this.guard, body)]); + } + } + } + if (this.pattern) { + body.expressions.unshift(new Assign(this.name, new Literal("" + svar + "[" + kvar + "]"))); + } + defPartFragments = [].concat(this.makeCode(defPart), this.pluckDirectCall(o, body)); + if (namePart) { + varPart = "\n" + idt1 + namePart + ";"; + } + if (this.object) { + forPartFragments = [this.makeCode("" + kvar + " in " + svar)]; + if (this.own) { + guardPart = "\n" + idt1 + "if (!" + (utility('hasProp')) + ".call(" + svar + ", " + kvar + ")) continue;"; + } + } + bodyFragments = body.compileToFragments(merge(o, { + indent: idt1 + }), LEVEL_TOP); + if (bodyFragments && (bodyFragments.length > 0)) { + bodyFragments = [].concat(this.makeCode("\n"), bodyFragments, this.makeCode("\n")); + } + return [].concat(defPartFragments, this.makeCode("" + (resultPart || '') + this.tab + "for ("), forPartFragments, this.makeCode(") {" + guardPart + varPart), bodyFragments, this.makeCode("" + this.tab + "}" + (returnResult || ''))); + }; + + For.prototype.pluckDirectCall = function(o, body) { + var base, defs, expr, fn, idx, ref, val, _i, _len, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7, _ref8; + defs = []; + _ref2 = body.expressions; + for (idx = _i = 0, _len = _ref2.length; _i < _len; idx = ++_i) { + expr = _ref2[idx]; + expr = expr.unwrapAll(); + if (!(expr instanceof Call)) { + continue; + } + val = (_ref3 = expr.variable) != null ? _ref3.unwrapAll() : void 0; + if (!((val instanceof Code) || (val instanceof Value && ((_ref4 = val.base) != null ? _ref4.unwrapAll() : void 0) instanceof Code && val.properties.length === 1 && ((_ref5 = (_ref6 = val.properties[0].name) != null ? _ref6.value : void 0) === 'call' || _ref5 === 'apply')))) { + continue; + } + fn = ((_ref7 = val.base) != null ? _ref7.unwrapAll() : void 0) || val; + ref = new Literal(o.scope.freeVariable('fn')); + base = new Value(ref); + if (val.base) { + _ref8 = [base, val], val.base = _ref8[0], base = _ref8[1]; + } + body.expressions[idx] = new Call(base, expr.args); + defs = defs.concat(this.makeCode(this.tab), new Assign(ref, fn).compileToFragments(o, LEVEL_TOP), this.makeCode(';\n')); + } + return defs; + }; + + return For; + + })(While); + + exports.Switch = Switch = (function(_super) { + __extends(Switch, _super); + + function Switch(subject, cases, otherwise) { + this.subject = subject; + this.cases = cases; + this.otherwise = otherwise; + } + + Switch.prototype.children = ['subject', 'cases', 'otherwise']; + + Switch.prototype.isStatement = YES; + + Switch.prototype.jumps = function(o) { + var block, conds, jumpNode, _i, _len, _ref2, _ref3, _ref4; + if (o == null) { + o = { + block: true + }; + } + _ref2 = this.cases; + for (_i = 0, _len = _ref2.length; _i < _len; _i++) { + _ref3 = _ref2[_i], conds = _ref3[0], block = _ref3[1]; + if (jumpNode = block.jumps(o)) { + return jumpNode; + } + } + return (_ref4 = this.otherwise) != null ? _ref4.jumps(o) : void 0; + }; + + Switch.prototype.makeReturn = function(res) { + var pair, _i, _len, _ref2, _ref3; + _ref2 = this.cases; + for (_i = 0, _len = _ref2.length; _i < _len; _i++) { + pair = _ref2[_i]; + pair[1].makeReturn(res); + } + if (res) { + this.otherwise || (this.otherwise = new Block([new Literal('void 0')])); + } + if ((_ref3 = this.otherwise) != null) { + _ref3.makeReturn(res); + } + return this; + }; + + Switch.prototype.compileNode = function(o) { + var block, body, cond, conditions, expr, fragments, i, idt1, idt2, _i, _j, _len, _len1, _ref2, _ref3, _ref4; + idt1 = o.indent + TAB; + idt2 = o.indent = idt1 + TAB; + fragments = [].concat(this.makeCode(this.tab + "switch ("), (this.subject ? this.subject.compileToFragments(o, LEVEL_PAREN) : this.makeCode("false")), this.makeCode(") {\n")); + _ref2 = this.cases; + for (i = _i = 0, _len = _ref2.length; _i < _len; i = ++_i) { + _ref3 = _ref2[i], conditions = _ref3[0], block = _ref3[1]; + _ref4 = flatten([conditions]); + for (_j = 0, _len1 = _ref4.length; _j < _len1; _j++) { + cond = _ref4[_j]; + if (!this.subject) { + cond = cond.invert(); + } + fragments = fragments.concat(this.makeCode(idt1 + "case "), cond.compileToFragments(o, LEVEL_PAREN), this.makeCode(":\n")); + } + if ((body = block.compileToFragments(o, LEVEL_TOP)).length > 0) { + fragments = fragments.concat(body, this.makeCode('\n')); + } + if (i === this.cases.length - 1 && !this.otherwise) { + break; + } + expr = this.lastNonComment(block.expressions); + if (expr instanceof Return || (expr instanceof Literal && expr.jumps() && expr.value !== 'debugger')) { + continue; + } + fragments.push(cond.makeCode(idt2 + 'break;\n')); + } + if (this.otherwise && this.otherwise.expressions.length) { + fragments.push.apply(fragments, [this.makeCode(idt1 + "default:\n")].concat(__slice.call(this.otherwise.compileToFragments(o, LEVEL_TOP)), [this.makeCode("\n")])); + } + fragments.push(this.makeCode(this.tab + '}')); + return fragments; + }; + + return Switch; + + })(Base); + + exports.If = If = (function(_super) { + __extends(If, _super); + + function If(condition, body, options) { + this.body = body; + if (options == null) { + options = {}; + } + this.condition = options.type === 'unless' ? condition.invert() : condition; + this.elseBody = null; + this.isChain = false; + this.soak = options.soak; + } + + If.prototype.children = ['condition', 'body', 'elseBody']; + + If.prototype.bodyNode = function() { + var _ref2; + return (_ref2 = this.body) != null ? _ref2.unwrap() : void 0; + }; + + If.prototype.elseBodyNode = function() { + var _ref2; + return (_ref2 = this.elseBody) != null ? _ref2.unwrap() : void 0; + }; + + If.prototype.addElse = function(elseBody) { + if (this.isChain) { + this.elseBodyNode().addElse(elseBody); + } else { + this.isChain = elseBody instanceof If; + this.elseBody = this.ensureBlock(elseBody); + this.elseBody.updateLocationDataIfMissing(elseBody.locationData); + } + return this; + }; + + If.prototype.isStatement = function(o) { + var _ref2; + return (o != null ? o.level : void 0) === LEVEL_TOP || this.bodyNode().isStatement(o) || ((_ref2 = this.elseBodyNode()) != null ? _ref2.isStatement(o) : void 0); + }; + + If.prototype.jumps = function(o) { + var _ref2; + return this.body.jumps(o) || ((_ref2 = this.elseBody) != null ? _ref2.jumps(o) : void 0); + }; + + If.prototype.compileNode = function(o) { + if (this.isStatement(o)) { + return this.compileStatement(o); + } else { + return this.compileExpression(o); + } + }; + + If.prototype.makeReturn = function(res) { + if (res) { + this.elseBody || (this.elseBody = new Block([new Literal('void 0')])); + } + this.body && (this.body = new Block([this.body.makeReturn(res)])); + this.elseBody && (this.elseBody = new Block([this.elseBody.makeReturn(res)])); + return this; + }; + + If.prototype.ensureBlock = function(node) { + if (node instanceof Block) { + return node; + } else { + return new Block([node]); + } + }; + + If.prototype.compileStatement = function(o) { + var answer, body, child, cond, exeq, ifPart, indent; + child = del(o, 'chainChild'); + exeq = del(o, 'isExistentialEquals'); + if (exeq) { + return new If(this.condition.invert(), this.elseBodyNode(), { + type: 'if' + }).compileToFragments(o); + } + indent = o.indent + TAB; + cond = this.condition.compileToFragments(o, LEVEL_PAREN); + body = this.ensureBlock(this.body).compileToFragments(merge(o, { + indent: indent + })); + ifPart = [].concat(this.makeCode("if ("), cond, this.makeCode(") {\n"), body, this.makeCode("\n" + this.tab + "}")); + if (!child) { + ifPart.unshift(this.makeCode(this.tab)); + } + if (!this.elseBody) { + return ifPart; + } + answer = ifPart.concat(this.makeCode(' else ')); + if (this.isChain) { + o.chainChild = true; + answer = answer.concat(this.elseBody.unwrap().compileToFragments(o, LEVEL_TOP)); + } else { + answer = answer.concat(this.makeCode("{\n"), this.elseBody.compileToFragments(merge(o, { + indent: indent + }), LEVEL_TOP), this.makeCode("\n" + this.tab + "}")); + } + return answer; + }; + + If.prototype.compileExpression = function(o) { + var alt, body, cond, fragments; + cond = this.condition.compileToFragments(o, LEVEL_COND); + body = this.bodyNode().compileToFragments(o, LEVEL_LIST); + alt = this.elseBodyNode() ? this.elseBodyNode().compileToFragments(o, LEVEL_LIST) : [this.makeCode('void 0')]; + fragments = cond.concat(this.makeCode(" ? "), body, this.makeCode(" : "), alt); + if (o.level >= LEVEL_COND) { + return this.wrapInBraces(fragments); + } else { + return fragments; + } + }; + + If.prototype.unfoldSoak = function() { + return this.soak && this; + }; + + return If; + + })(Base); + + UTILITIES = { + "extends": function() { + return "function(child, parent) { for (var key in parent) { if (" + (utility('hasProp')) + ".call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }"; + }, + bind: function() { + return 'function(fn, me){ return function(){ return fn.apply(me, arguments); }; }'; + }, + indexOf: function() { + return "[].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }"; + }, + hasProp: function() { + return '{}.hasOwnProperty'; + }, + slice: function() { + return '[].slice'; + } + }; + + LEVEL_TOP = 1; + + LEVEL_PAREN = 2; + + LEVEL_LIST = 3; + + LEVEL_COND = 4; + + LEVEL_OP = 5; + + LEVEL_ACCESS = 6; + + TAB = ' '; + + IDENTIFIER_STR = "[$A-Za-z_\\x7f-\\uffff][$\\w\\x7f-\\uffff]*"; + + IDENTIFIER = RegExp("^" + IDENTIFIER_STR + "$"); + + SIMPLENUM = /^[+-]?\d+$/; + + HEXNUM = /^[+-]?0x[\da-f]+/i; + + NUMBER = /^[+-]?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)$/i; + + METHOD_DEF = RegExp("^(" + IDENTIFIER_STR + ")(\\.prototype)?(?:\\.(" + IDENTIFIER_STR + ")|\\[(\"(?:[^\\\\\"\\r\\n]|\\\\.)*\"|'(?:[^\\\\'\\r\\n]|\\\\.)*')\\]|\\[(0x[\\da-fA-F]+|\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\])$"); + + IS_STRING = /^['"]/; + + IS_REGEX = /^\//; + + utility = function(name) { + var ref; + ref = "__" + name; + Scope.root.assign(ref, UTILITIES[name]()); + return ref; + }; + + multident = function(code, tab) { + code = code.replace(/\n/g, '$&' + tab); + return code.replace(/\s+$/, ''); + }; + + parseNum = function(x) { + if (x == null) { + return 0; + } else if (x.match(HEXNUM)) { + return parseInt(x, 16); + } else { + return parseFloat(x); + } + }; + + isLiteralArguments = function(node) { + return node instanceof Literal && node.value === 'arguments' && !node.asKey; + }; + + isLiteralThis = function(node) { + return (node instanceof Literal && node.value === 'this' && !node.asKey) || (node instanceof Code && node.bound) || (node instanceof Call && node.isSuper); + }; + + unfoldSoak = function(o, parent, name) { + var ifn; + if (!(ifn = parent[name].unfoldSoak(o))) { + return; + } + parent[name] = ifn.body; + ifn.body = new Value(parent); + return ifn; + }; + + +}); \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/coffee/parser.js b/node_modules/ace/lib/ace/mode/coffee/parser.js new file mode 100644 index 00000000..00d1b723 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/coffee/parser.js @@ -0,0 +1,724 @@ +/** + * Copyright (c) 2009-2013 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. + * + */ + +define(function(require, exports, module) { +/* parser generated by jison 0.4.4 */ +/* + Returns a Parser object of the following structure: + + Parser: { + yy: {} + } + + Parser.prototype: { + yy: {}, + trace: function(), + symbols_: {associative list: name ==> number}, + terminals_: {associative list: number ==> name}, + productions_: [...], + performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$), + table: [...], + defaultActions: {...}, + parseError: function(str, hash), + parse: function(input), + + lexer: { + EOF: 1, + parseError: function(str, hash), + setInput: function(input), + input: function(), + unput: function(str), + more: function(), + less: function(n), + pastInput: function(), + upcomingInput: function(), + showPosition: function(), + test_match: function(regex_match_array, rule_index), + next: function(), + lex: function(), + begin: function(condition), + popState: function(), + _currentRules: function(), + topState: function(), + pushState: function(condition), + + options: { + ranges: boolean (optional: true ==> token location info will include a .range[] member) + flex: boolean (optional: true ==> flex-like lexing behaviour where the rules are tested exhaustively to find the longest match) + backtrack_lexer: boolean (optional: true ==> lexer regexes are tested in order and for each matching regex the action code is invoked; the lexer terminates the scan when a token is returned by the action code) + }, + + performAction: function(yy, yy_, $avoiding_name_collisions, YY_START), + rules: [...], + conditions: {associative list: name ==> set}, + } + } + + + token location info (@$, _$, etc.): { + first_line: n, + last_line: n, + first_column: n, + last_column: n, + range: [start_number, end_number] (where the numbers are indexes into the input string, regular zero-based) + } + + + the parseError function receives a 'hash' object with these members for lexer and parser errors: { + text: (matched text) + token: (the produced terminal token, if any) + line: (yylineno) + } + while parser (grammar) errors will also provide these members, i.e. parser errors deliver a superset of attributes: { + loc: (yylloc) + expected: (string describing the set of expected tokens) + recoverable: (boolean: TRUE when the parser has a error recovery rule available for this particular error) + } +*/ + +var parser = {trace: function trace() { }, +yy: {}, +symbols_: {"error":2,"Root":3,"Body":4,"Line":5,"TERMINATOR":6,"Expression":7,"Statement":8,"Return":9,"Comment":10,"STATEMENT":11,"Value":12,"Invocation":13,"Code":14,"Operation":15,"Assign":16,"If":17,"Try":18,"While":19,"For":20,"Switch":21,"Class":22,"Throw":23,"Block":24,"INDENT":25,"OUTDENT":26,"Identifier":27,"IDENTIFIER":28,"AlphaNumeric":29,"NUMBER":30,"STRING":31,"Literal":32,"JS":33,"REGEX":34,"DEBUGGER":35,"UNDEFINED":36,"NULL":37,"BOOL":38,"Assignable":39,"=":40,"AssignObj":41,"ObjAssignable":42,":":43,"ThisProperty":44,"RETURN":45,"HERECOMMENT":46,"PARAM_START":47,"ParamList":48,"PARAM_END":49,"FuncGlyph":50,"->":51,"=>":52,"OptComma":53,",":54,"Param":55,"ParamVar":56,"...":57,"Array":58,"Object":59,"Splat":60,"SimpleAssignable":61,"Accessor":62,"Parenthetical":63,"Range":64,"This":65,".":66,"?.":67,"::":68,"?::":69,"Index":70,"INDEX_START":71,"IndexValue":72,"INDEX_END":73,"INDEX_SOAK":74,"Slice":75,"{":76,"AssignList":77,"}":78,"CLASS":79,"EXTENDS":80,"OptFuncExist":81,"Arguments":82,"SUPER":83,"FUNC_EXIST":84,"CALL_START":85,"CALL_END":86,"ArgList":87,"THIS":88,"@":89,"[":90,"]":91,"RangeDots":92,"..":93,"Arg":94,"SimpleArgs":95,"TRY":96,"Catch":97,"FINALLY":98,"CATCH":99,"THROW":100,"(":101,")":102,"WhileSource":103,"WHILE":104,"WHEN":105,"UNTIL":106,"Loop":107,"LOOP":108,"ForBody":109,"FOR":110,"ForStart":111,"ForSource":112,"ForVariables":113,"OWN":114,"ForValue":115,"FORIN":116,"FOROF":117,"BY":118,"SWITCH":119,"Whens":120,"ELSE":121,"When":122,"LEADING_WHEN":123,"IfBlock":124,"IF":125,"POST_IF":126,"UNARY":127,"-":128,"+":129,"--":130,"++":131,"?":132,"MATH":133,"SHIFT":134,"COMPARE":135,"LOGIC":136,"RELATION":137,"COMPOUND_ASSIGN":138,"$accept":0,"$end":1}, +terminals_: {2:"error",6:"TERMINATOR",11:"STATEMENT",25:"INDENT",26:"OUTDENT",28:"IDENTIFIER",30:"NUMBER",31:"STRING",33:"JS",34:"REGEX",35:"DEBUGGER",36:"UNDEFINED",37:"NULL",38:"BOOL",40:"=",43:":",45:"RETURN",46:"HERECOMMENT",47:"PARAM_START",49:"PARAM_END",51:"->",52:"=>",54:",",57:"...",66:".",67:"?.",68:"::",69:"?::",71:"INDEX_START",73:"INDEX_END",74:"INDEX_SOAK",76:"{",78:"}",79:"CLASS",80:"EXTENDS",83:"SUPER",84:"FUNC_EXIST",85:"CALL_START",86:"CALL_END",88:"THIS",89:"@",90:"[",91:"]",93:"..",96:"TRY",98:"FINALLY",99:"CATCH",100:"THROW",101:"(",102:")",104:"WHILE",105:"WHEN",106:"UNTIL",108:"LOOP",110:"FOR",114:"OWN",116:"FORIN",117:"FOROF",118:"BY",119:"SWITCH",121:"ELSE",123:"LEADING_WHEN",125:"IF",126:"POST_IF",127:"UNARY",128:"-",129:"+",130:"--",131:"++",132:"?",133:"MATH",134:"SHIFT",135:"COMPARE",136:"LOGIC",137:"RELATION",138:"COMPOUND_ASSIGN"}, +productions_: [0,[3,0],[3,1],[4,1],[4,3],[4,2],[5,1],[5,1],[8,1],[8,1],[8,1],[7,1],[7,1],[7,1],[7,1],[7,1],[7,1],[7,1],[7,1],[7,1],[7,1],[7,1],[7,1],[24,2],[24,3],[27,1],[29,1],[29,1],[32,1],[32,1],[32,1],[32,1],[32,1],[32,1],[32,1],[16,3],[16,4],[16,5],[41,1],[41,3],[41,5],[41,1],[42,1],[42,1],[42,1],[9,2],[9,1],[10,1],[14,5],[14,2],[50,1],[50,1],[53,0],[53,1],[48,0],[48,1],[48,3],[48,4],[48,6],[55,1],[55,2],[55,3],[56,1],[56,1],[56,1],[56,1],[60,2],[61,1],[61,2],[61,2],[61,1],[39,1],[39,1],[39,1],[12,1],[12,1],[12,1],[12,1],[12,1],[62,2],[62,2],[62,2],[62,2],[62,1],[62,1],[70,3],[70,2],[72,1],[72,1],[59,4],[77,0],[77,1],[77,3],[77,4],[77,6],[22,1],[22,2],[22,3],[22,4],[22,2],[22,3],[22,4],[22,5],[13,3],[13,3],[13,1],[13,2],[81,0],[81,1],[82,2],[82,4],[65,1],[65,1],[44,2],[58,2],[58,4],[92,1],[92,1],[64,5],[75,3],[75,2],[75,2],[75,1],[87,1],[87,3],[87,4],[87,4],[87,6],[94,1],[94,1],[95,1],[95,3],[18,2],[18,3],[18,4],[18,5],[97,3],[97,3],[97,2],[23,2],[63,3],[63,5],[103,2],[103,4],[103,2],[103,4],[19,2],[19,2],[19,2],[19,1],[107,2],[107,2],[20,2],[20,2],[20,2],[109,2],[109,2],[111,2],[111,3],[115,1],[115,1],[115,1],[115,1],[113,1],[113,3],[112,2],[112,2],[112,4],[112,4],[112,4],[112,6],[112,6],[21,5],[21,7],[21,4],[21,6],[120,1],[120,2],[122,3],[122,4],[124,3],[124,5],[17,1],[17,3],[17,3],[17,3],[15,2],[15,2],[15,2],[15,2],[15,2],[15,2],[15,2],[15,2],[15,3],[15,3],[15,3],[15,3],[15,3],[15,3],[15,3],[15,3],[15,5],[15,4],[15,3]], +performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) { +/* this == yyval */ + +var $0 = $$.length - 1; +switch (yystate) { +case 1:return this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Block); +break; +case 2:return this.$ = $$[$0]; +break; +case 3:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(yy.Block.wrap([$$[$0]])); +break; +case 4:this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])($$[$0-2].push($$[$0])); +break; +case 5:this.$ = $$[$0-1]; +break; +case 6:this.$ = $$[$0]; +break; +case 7:this.$ = $$[$0]; +break; +case 8:this.$ = $$[$0]; +break; +case 9:this.$ = $$[$0]; +break; +case 10:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Literal($$[$0])); +break; +case 11:this.$ = $$[$0]; +break; +case 12:this.$ = $$[$0]; +break; +case 13:this.$ = $$[$0]; +break; +case 14:this.$ = $$[$0]; +break; +case 15:this.$ = $$[$0]; +break; +case 16:this.$ = $$[$0]; +break; +case 17:this.$ = $$[$0]; +break; +case 18:this.$ = $$[$0]; +break; +case 19:this.$ = $$[$0]; +break; +case 20:this.$ = $$[$0]; +break; +case 21:this.$ = $$[$0]; +break; +case 22:this.$ = $$[$0]; +break; +case 23:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Block); +break; +case 24:this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])($$[$0-1]); +break; +case 25:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Literal($$[$0])); +break; +case 26:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Literal($$[$0])); +break; +case 27:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Literal($$[$0])); +break; +case 28:this.$ = $$[$0]; +break; +case 29:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Literal($$[$0])); +break; +case 30:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Literal($$[$0])); +break; +case 31:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Literal($$[$0])); +break; +case 32:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Undefined); +break; +case 33:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Null); +break; +case 34:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Bool($$[$0])); +break; +case 35:this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.Assign($$[$0-2], $$[$0])); +break; +case 36:this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])(new yy.Assign($$[$0-3], $$[$0])); +break; +case 37:this.$ = yy.addLocationDataFn(_$[$0-4], _$[$0])(new yy.Assign($$[$0-4], $$[$0-1])); +break; +case 38:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Value($$[$0])); +break; +case 39:this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.Assign(yy.addLocationDataFn(_$[$0-2])(new yy.Value($$[$0-2])), $$[$0], 'object')); +break; +case 40:this.$ = yy.addLocationDataFn(_$[$0-4], _$[$0])(new yy.Assign(yy.addLocationDataFn(_$[$0-4])(new yy.Value($$[$0-4])), $$[$0-1], 'object')); +break; +case 41:this.$ = $$[$0]; +break; +case 42:this.$ = $$[$0]; +break; +case 43:this.$ = $$[$0]; +break; +case 44:this.$ = $$[$0]; +break; +case 45:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Return($$[$0])); +break; +case 46:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Return); +break; +case 47:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Comment($$[$0])); +break; +case 48:this.$ = yy.addLocationDataFn(_$[$0-4], _$[$0])(new yy.Code($$[$0-3], $$[$0], $$[$0-1])); +break; +case 49:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Code([], $$[$0], $$[$0-1])); +break; +case 50:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])('func'); +break; +case 51:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])('boundfunc'); +break; +case 52:this.$ = $$[$0]; +break; +case 53:this.$ = $$[$0]; +break; +case 54:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])([]); +break; +case 55:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])([$$[$0]]); +break; +case 56:this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])($$[$0-2].concat($$[$0])); +break; +case 57:this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])($$[$0-3].concat($$[$0])); +break; +case 58:this.$ = yy.addLocationDataFn(_$[$0-5], _$[$0])($$[$0-5].concat($$[$0-2])); +break; +case 59:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Param($$[$0])); +break; +case 60:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Param($$[$0-1], null, true)); +break; +case 61:this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.Param($$[$0-2], $$[$0])); +break; +case 62:this.$ = $$[$0]; +break; +case 63:this.$ = $$[$0]; +break; +case 64:this.$ = $$[$0]; +break; +case 65:this.$ = $$[$0]; +break; +case 66:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Splat($$[$0-1])); +break; +case 67:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Value($$[$0])); +break; +case 68:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])($$[$0-1].add($$[$0])); +break; +case 69:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Value($$[$0-1], [].concat($$[$0]))); +break; +case 70:this.$ = $$[$0]; +break; +case 71:this.$ = $$[$0]; +break; +case 72:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Value($$[$0])); +break; +case 73:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Value($$[$0])); +break; +case 74:this.$ = $$[$0]; +break; +case 75:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Value($$[$0])); +break; +case 76:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Value($$[$0])); +break; +case 77:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Value($$[$0])); +break; +case 78:this.$ = $$[$0]; +break; +case 79:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Access($$[$0])); +break; +case 80:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Access($$[$0], 'soak')); +break; +case 81:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])([yy.addLocationDataFn(_$[$0-1])(new yy.Access(new yy.Literal('prototype'))), yy.addLocationDataFn(_$[$0])(new yy.Access($$[$0]))]); +break; +case 82:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])([yy.addLocationDataFn(_$[$0-1])(new yy.Access(new yy.Literal('prototype'), 'soak')), yy.addLocationDataFn(_$[$0])(new yy.Access($$[$0]))]); +break; +case 83:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Access(new yy.Literal('prototype'))); +break; +case 84:this.$ = $$[$0]; +break; +case 85:this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])($$[$0-1]); +break; +case 86:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(yy.extend($$[$0], { + soak: true + })); +break; +case 87:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Index($$[$0])); +break; +case 88:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Slice($$[$0])); +break; +case 89:this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])(new yy.Obj($$[$0-2], $$[$0-3].generated)); +break; +case 90:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])([]); +break; +case 91:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])([$$[$0]]); +break; +case 92:this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])($$[$0-2].concat($$[$0])); +break; +case 93:this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])($$[$0-3].concat($$[$0])); +break; +case 94:this.$ = yy.addLocationDataFn(_$[$0-5], _$[$0])($$[$0-5].concat($$[$0-2])); +break; +case 95:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Class); +break; +case 96:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Class(null, null, $$[$0])); +break; +case 97:this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.Class(null, $$[$0])); +break; +case 98:this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])(new yy.Class(null, $$[$0-1], $$[$0])); +break; +case 99:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Class($$[$0])); +break; +case 100:this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.Class($$[$0-1], null, $$[$0])); +break; +case 101:this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])(new yy.Class($$[$0-2], $$[$0])); +break; +case 102:this.$ = yy.addLocationDataFn(_$[$0-4], _$[$0])(new yy.Class($$[$0-3], $$[$0-1], $$[$0])); +break; +case 103:this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.Call($$[$0-2], $$[$0], $$[$0-1])); +break; +case 104:this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.Call($$[$0-2], $$[$0], $$[$0-1])); +break; +case 105:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Call('super', [new yy.Splat(new yy.Literal('arguments'))])); +break; +case 106:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Call('super', $$[$0])); +break; +case 107:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(false); +break; +case 108:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(true); +break; +case 109:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])([]); +break; +case 110:this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])($$[$0-2]); +break; +case 111:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Value(new yy.Literal('this'))); +break; +case 112:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Value(new yy.Literal('this'))); +break; +case 113:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Value(yy.addLocationDataFn(_$[$0-1])(new yy.Literal('this')), [yy.addLocationDataFn(_$[$0])(new yy.Access($$[$0]))], 'this')); +break; +case 114:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Arr([])); +break; +case 115:this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])(new yy.Arr($$[$0-2])); +break; +case 116:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])('inclusive'); +break; +case 117:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])('exclusive'); +break; +case 118:this.$ = yy.addLocationDataFn(_$[$0-4], _$[$0])(new yy.Range($$[$0-3], $$[$0-1], $$[$0-2])); +break; +case 119:this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.Range($$[$0-2], $$[$0], $$[$0-1])); +break; +case 120:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Range($$[$0-1], null, $$[$0])); +break; +case 121:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Range(null, $$[$0], $$[$0-1])); +break; +case 122:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Range(null, null, $$[$0])); +break; +case 123:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])([$$[$0]]); +break; +case 124:this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])($$[$0-2].concat($$[$0])); +break; +case 125:this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])($$[$0-3].concat($$[$0])); +break; +case 126:this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])($$[$0-2]); +break; +case 127:this.$ = yy.addLocationDataFn(_$[$0-5], _$[$0])($$[$0-5].concat($$[$0-2])); +break; +case 128:this.$ = $$[$0]; +break; +case 129:this.$ = $$[$0]; +break; +case 130:this.$ = $$[$0]; +break; +case 131:this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])([].concat($$[$0-2], $$[$0])); +break; +case 132:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Try($$[$0])); +break; +case 133:this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.Try($$[$0-1], $$[$0][0], $$[$0][1])); +break; +case 134:this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])(new yy.Try($$[$0-2], null, null, $$[$0])); +break; +case 135:this.$ = yy.addLocationDataFn(_$[$0-4], _$[$0])(new yy.Try($$[$0-3], $$[$0-2][0], $$[$0-2][1], $$[$0])); +break; +case 136:this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])([$$[$0-1], $$[$0]]); +break; +case 137:this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])([yy.addLocationDataFn(_$[$0-1])(new yy.Value($$[$0-1])), $$[$0]]); +break; +case 138:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])([null, $$[$0]]); +break; +case 139:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Throw($$[$0])); +break; +case 140:this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.Parens($$[$0-1])); +break; +case 141:this.$ = yy.addLocationDataFn(_$[$0-4], _$[$0])(new yy.Parens($$[$0-2])); +break; +case 142:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.While($$[$0])); +break; +case 143:this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])(new yy.While($$[$0-2], { + guard: $$[$0] + })); +break; +case 144:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.While($$[$0], { + invert: true + })); +break; +case 145:this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])(new yy.While($$[$0-2], { + invert: true, + guard: $$[$0] + })); +break; +case 146:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])($$[$0-1].addBody($$[$0])); +break; +case 147:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])($$[$0].addBody(yy.addLocationDataFn(_$[$0-1])(yy.Block.wrap([$$[$0-1]])))); +break; +case 148:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])($$[$0].addBody(yy.addLocationDataFn(_$[$0-1])(yy.Block.wrap([$$[$0-1]])))); +break; +case 149:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])($$[$0]); +break; +case 150:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.While(yy.addLocationDataFn(_$[$0-1])(new yy.Literal('true'))).addBody($$[$0])); +break; +case 151:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.While(yy.addLocationDataFn(_$[$0-1])(new yy.Literal('true'))).addBody(yy.addLocationDataFn(_$[$0])(yy.Block.wrap([$$[$0]])))); +break; +case 152:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.For($$[$0-1], $$[$0])); +break; +case 153:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.For($$[$0-1], $$[$0])); +break; +case 154:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.For($$[$0], $$[$0-1])); +break; +case 155:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])({ + source: yy.addLocationDataFn(_$[$0])(new yy.Value($$[$0])) + }); +break; +case 156:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])((function () { + $$[$0].own = $$[$0-1].own; + $$[$0].name = $$[$0-1][0]; + $$[$0].index = $$[$0-1][1]; + return $$[$0]; + }())); +break; +case 157:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])($$[$0]); +break; +case 158:this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])((function () { + $$[$0].own = true; + return $$[$0]; + }())); +break; +case 159:this.$ = $$[$0]; +break; +case 160:this.$ = $$[$0]; +break; +case 161:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Value($$[$0])); +break; +case 162:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])(new yy.Value($$[$0])); +break; +case 163:this.$ = yy.addLocationDataFn(_$[$0], _$[$0])([$$[$0]]); +break; +case 164:this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])([$$[$0-2], $$[$0]]); +break; +case 165:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])({ + source: $$[$0] + }); +break; +case 166:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])({ + source: $$[$0], + object: true + }); +break; +case 167:this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])({ + source: $$[$0-2], + guard: $$[$0] + }); +break; +case 168:this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])({ + source: $$[$0-2], + guard: $$[$0], + object: true + }); +break; +case 169:this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])({ + source: $$[$0-2], + step: $$[$0] + }); +break; +case 170:this.$ = yy.addLocationDataFn(_$[$0-5], _$[$0])({ + source: $$[$0-4], + guard: $$[$0-2], + step: $$[$0] + }); +break; +case 171:this.$ = yy.addLocationDataFn(_$[$0-5], _$[$0])({ + source: $$[$0-4], + step: $$[$0-2], + guard: $$[$0] + }); +break; +case 172:this.$ = yy.addLocationDataFn(_$[$0-4], _$[$0])(new yy.Switch($$[$0-3], $$[$0-1])); +break; +case 173:this.$ = yy.addLocationDataFn(_$[$0-6], _$[$0])(new yy.Switch($$[$0-5], $$[$0-3], $$[$0-1])); +break; +case 174:this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])(new yy.Switch(null, $$[$0-1])); +break; +case 175:this.$ = yy.addLocationDataFn(_$[$0-5], _$[$0])(new yy.Switch(null, $$[$0-3], $$[$0-1])); +break; +case 176:this.$ = $$[$0]; +break; +case 177:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])($$[$0-1].concat($$[$0])); +break; +case 178:this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])([[$$[$0-1], $$[$0]]]); +break; +case 179:this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])([[$$[$0-2], $$[$0-1]]]); +break; +case 180:this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.If($$[$0-1], $$[$0], { + type: $$[$0-2] + })); +break; +case 181:this.$ = yy.addLocationDataFn(_$[$0-4], _$[$0])($$[$0-4].addElse(yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.If($$[$0-1], $$[$0], { + type: $$[$0-2] + })))); +break; +case 182:this.$ = $$[$0]; +break; +case 183:this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])($$[$0-2].addElse($$[$0])); +break; +case 184:this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.If($$[$0], yy.addLocationDataFn(_$[$0-2])(yy.Block.wrap([$$[$0-2]])), { + type: $$[$0-1], + statement: true + })); +break; +case 185:this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.If($$[$0], yy.addLocationDataFn(_$[$0-2])(yy.Block.wrap([$$[$0-2]])), { + type: $$[$0-1], + statement: true + })); +break; +case 186:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Op($$[$0-1], $$[$0])); +break; +case 187:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Op('-', $$[$0])); +break; +case 188:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Op('+', $$[$0])); +break; +case 189:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Op('--', $$[$0])); +break; +case 190:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Op('++', $$[$0])); +break; +case 191:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Op('--', $$[$0-1], null, true)); +break; +case 192:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Op('++', $$[$0-1], null, true)); +break; +case 193:this.$ = yy.addLocationDataFn(_$[$0-1], _$[$0])(new yy.Existence($$[$0-1])); +break; +case 194:this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.Op('+', $$[$0-2], $$[$0])); +break; +case 195:this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.Op('-', $$[$0-2], $$[$0])); +break; +case 196:this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.Op($$[$0-1], $$[$0-2], $$[$0])); +break; +case 197:this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.Op($$[$0-1], $$[$0-2], $$[$0])); +break; +case 198:this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.Op($$[$0-1], $$[$0-2], $$[$0])); +break; +case 199:this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.Op($$[$0-1], $$[$0-2], $$[$0])); +break; +case 200:this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])((function () { + if ($$[$0-1].charAt(0) === '!') { + return new yy.Op($$[$0-1].slice(1), $$[$0-2], $$[$0]).invert(); + } else { + return new yy.Op($$[$0-1], $$[$0-2], $$[$0]); + } + }())); +break; +case 201:this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.Assign($$[$0-2], $$[$0], $$[$0-1])); +break; +case 202:this.$ = yy.addLocationDataFn(_$[$0-4], _$[$0])(new yy.Assign($$[$0-4], $$[$0-1], $$[$0-3])); +break; +case 203:this.$ = yy.addLocationDataFn(_$[$0-3], _$[$0])(new yy.Assign($$[$0-3], $$[$0], $$[$0-2])); +break; +case 204:this.$ = yy.addLocationDataFn(_$[$0-2], _$[$0])(new yy.Extends($$[$0-2], $$[$0])); +break; +} +}, +table: [{1:[2,1],3:1,4:2,5:3,7:4,8:5,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{1:[3]},{1:[2,2],6:[1,72]},{1:[2,3],6:[2,3],26:[2,3],102:[2,3]},{1:[2,6],6:[2,6],26:[2,6],102:[2,6],103:82,104:[1,63],106:[1,64],109:83,110:[1,66],111:67,126:[1,81],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[1,78],136:[1,79],137:[1,80]},{1:[2,7],6:[2,7],26:[2,7],102:[2,7],103:85,104:[1,63],106:[1,64],109:86,110:[1,66],111:67,126:[1,84]},{1:[2,11],6:[2,11],25:[2,11],26:[2,11],49:[2,11],54:[2,11],57:[2,11],62:88,66:[1,90],67:[1,91],68:[1,92],69:[1,93],70:94,71:[1,95],73:[2,11],74:[1,96],78:[2,11],81:87,84:[1,89],85:[2,107],86:[2,11],91:[2,11],93:[2,11],102:[2,11],104:[2,11],105:[2,11],106:[2,11],110:[2,11],118:[2,11],126:[2,11],128:[2,11],129:[2,11],132:[2,11],133:[2,11],134:[2,11],135:[2,11],136:[2,11],137:[2,11]},{1:[2,12],6:[2,12],25:[2,12],26:[2,12],49:[2,12],54:[2,12],57:[2,12],62:98,66:[1,90],67:[1,91],68:[1,92],69:[1,93],70:94,71:[1,95],73:[2,12],74:[1,96],78:[2,12],81:97,84:[1,89],85:[2,107],86:[2,12],91:[2,12],93:[2,12],102:[2,12],104:[2,12],105:[2,12],106:[2,12],110:[2,12],118:[2,12],126:[2,12],128:[2,12],129:[2,12],132:[2,12],133:[2,12],134:[2,12],135:[2,12],136:[2,12],137:[2,12]},{1:[2,13],6:[2,13],25:[2,13],26:[2,13],49:[2,13],54:[2,13],57:[2,13],73:[2,13],78:[2,13],86:[2,13],91:[2,13],93:[2,13],102:[2,13],104:[2,13],105:[2,13],106:[2,13],110:[2,13],118:[2,13],126:[2,13],128:[2,13],129:[2,13],132:[2,13],133:[2,13],134:[2,13],135:[2,13],136:[2,13],137:[2,13]},{1:[2,14],6:[2,14],25:[2,14],26:[2,14],49:[2,14],54:[2,14],57:[2,14],73:[2,14],78:[2,14],86:[2,14],91:[2,14],93:[2,14],102:[2,14],104:[2,14],105:[2,14],106:[2,14],110:[2,14],118:[2,14],126:[2,14],128:[2,14],129:[2,14],132:[2,14],133:[2,14],134:[2,14],135:[2,14],136:[2,14],137:[2,14]},{1:[2,15],6:[2,15],25:[2,15],26:[2,15],49:[2,15],54:[2,15],57:[2,15],73:[2,15],78:[2,15],86:[2,15],91:[2,15],93:[2,15],102:[2,15],104:[2,15],105:[2,15],106:[2,15],110:[2,15],118:[2,15],126:[2,15],128:[2,15],129:[2,15],132:[2,15],133:[2,15],134:[2,15],135:[2,15],136:[2,15],137:[2,15]},{1:[2,16],6:[2,16],25:[2,16],26:[2,16],49:[2,16],54:[2,16],57:[2,16],73:[2,16],78:[2,16],86:[2,16],91:[2,16],93:[2,16],102:[2,16],104:[2,16],105:[2,16],106:[2,16],110:[2,16],118:[2,16],126:[2,16],128:[2,16],129:[2,16],132:[2,16],133:[2,16],134:[2,16],135:[2,16],136:[2,16],137:[2,16]},{1:[2,17],6:[2,17],25:[2,17],26:[2,17],49:[2,17],54:[2,17],57:[2,17],73:[2,17],78:[2,17],86:[2,17],91:[2,17],93:[2,17],102:[2,17],104:[2,17],105:[2,17],106:[2,17],110:[2,17],118:[2,17],126:[2,17],128:[2,17],129:[2,17],132:[2,17],133:[2,17],134:[2,17],135:[2,17],136:[2,17],137:[2,17]},{1:[2,18],6:[2,18],25:[2,18],26:[2,18],49:[2,18],54:[2,18],57:[2,18],73:[2,18],78:[2,18],86:[2,18],91:[2,18],93:[2,18],102:[2,18],104:[2,18],105:[2,18],106:[2,18],110:[2,18],118:[2,18],126:[2,18],128:[2,18],129:[2,18],132:[2,18],133:[2,18],134:[2,18],135:[2,18],136:[2,18],137:[2,18]},{1:[2,19],6:[2,19],25:[2,19],26:[2,19],49:[2,19],54:[2,19],57:[2,19],73:[2,19],78:[2,19],86:[2,19],91:[2,19],93:[2,19],102:[2,19],104:[2,19],105:[2,19],106:[2,19],110:[2,19],118:[2,19],126:[2,19],128:[2,19],129:[2,19],132:[2,19],133:[2,19],134:[2,19],135:[2,19],136:[2,19],137:[2,19]},{1:[2,20],6:[2,20],25:[2,20],26:[2,20],49:[2,20],54:[2,20],57:[2,20],73:[2,20],78:[2,20],86:[2,20],91:[2,20],93:[2,20],102:[2,20],104:[2,20],105:[2,20],106:[2,20],110:[2,20],118:[2,20],126:[2,20],128:[2,20],129:[2,20],132:[2,20],133:[2,20],134:[2,20],135:[2,20],136:[2,20],137:[2,20]},{1:[2,21],6:[2,21],25:[2,21],26:[2,21],49:[2,21],54:[2,21],57:[2,21],73:[2,21],78:[2,21],86:[2,21],91:[2,21],93:[2,21],102:[2,21],104:[2,21],105:[2,21],106:[2,21],110:[2,21],118:[2,21],126:[2,21],128:[2,21],129:[2,21],132:[2,21],133:[2,21],134:[2,21],135:[2,21],136:[2,21],137:[2,21]},{1:[2,22],6:[2,22],25:[2,22],26:[2,22],49:[2,22],54:[2,22],57:[2,22],73:[2,22],78:[2,22],86:[2,22],91:[2,22],93:[2,22],102:[2,22],104:[2,22],105:[2,22],106:[2,22],110:[2,22],118:[2,22],126:[2,22],128:[2,22],129:[2,22],132:[2,22],133:[2,22],134:[2,22],135:[2,22],136:[2,22],137:[2,22]},{1:[2,8],6:[2,8],26:[2,8],102:[2,8],104:[2,8],106:[2,8],110:[2,8],126:[2,8]},{1:[2,9],6:[2,9],26:[2,9],102:[2,9],104:[2,9],106:[2,9],110:[2,9],126:[2,9]},{1:[2,10],6:[2,10],26:[2,10],102:[2,10],104:[2,10],106:[2,10],110:[2,10],126:[2,10]},{1:[2,74],6:[2,74],25:[2,74],26:[2,74],40:[1,99],49:[2,74],54:[2,74],57:[2,74],66:[2,74],67:[2,74],68:[2,74],69:[2,74],71:[2,74],73:[2,74],74:[2,74],78:[2,74],84:[2,74],85:[2,74],86:[2,74],91:[2,74],93:[2,74],102:[2,74],104:[2,74],105:[2,74],106:[2,74],110:[2,74],118:[2,74],126:[2,74],128:[2,74],129:[2,74],132:[2,74],133:[2,74],134:[2,74],135:[2,74],136:[2,74],137:[2,74]},{1:[2,75],6:[2,75],25:[2,75],26:[2,75],49:[2,75],54:[2,75],57:[2,75],66:[2,75],67:[2,75],68:[2,75],69:[2,75],71:[2,75],73:[2,75],74:[2,75],78:[2,75],84:[2,75],85:[2,75],86:[2,75],91:[2,75],93:[2,75],102:[2,75],104:[2,75],105:[2,75],106:[2,75],110:[2,75],118:[2,75],126:[2,75],128:[2,75],129:[2,75],132:[2,75],133:[2,75],134:[2,75],135:[2,75],136:[2,75],137:[2,75]},{1:[2,76],6:[2,76],25:[2,76],26:[2,76],49:[2,76],54:[2,76],57:[2,76],66:[2,76],67:[2,76],68:[2,76],69:[2,76],71:[2,76],73:[2,76],74:[2,76],78:[2,76],84:[2,76],85:[2,76],86:[2,76],91:[2,76],93:[2,76],102:[2,76],104:[2,76],105:[2,76],106:[2,76],110:[2,76],118:[2,76],126:[2,76],128:[2,76],129:[2,76],132:[2,76],133:[2,76],134:[2,76],135:[2,76],136:[2,76],137:[2,76]},{1:[2,77],6:[2,77],25:[2,77],26:[2,77],49:[2,77],54:[2,77],57:[2,77],66:[2,77],67:[2,77],68:[2,77],69:[2,77],71:[2,77],73:[2,77],74:[2,77],78:[2,77],84:[2,77],85:[2,77],86:[2,77],91:[2,77],93:[2,77],102:[2,77],104:[2,77],105:[2,77],106:[2,77],110:[2,77],118:[2,77],126:[2,77],128:[2,77],129:[2,77],132:[2,77],133:[2,77],134:[2,77],135:[2,77],136:[2,77],137:[2,77]},{1:[2,78],6:[2,78],25:[2,78],26:[2,78],49:[2,78],54:[2,78],57:[2,78],66:[2,78],67:[2,78],68:[2,78],69:[2,78],71:[2,78],73:[2,78],74:[2,78],78:[2,78],84:[2,78],85:[2,78],86:[2,78],91:[2,78],93:[2,78],102:[2,78],104:[2,78],105:[2,78],106:[2,78],110:[2,78],118:[2,78],126:[2,78],128:[2,78],129:[2,78],132:[2,78],133:[2,78],134:[2,78],135:[2,78],136:[2,78],137:[2,78]},{1:[2,105],6:[2,105],25:[2,105],26:[2,105],49:[2,105],54:[2,105],57:[2,105],66:[2,105],67:[2,105],68:[2,105],69:[2,105],71:[2,105],73:[2,105],74:[2,105],78:[2,105],82:100,84:[2,105],85:[1,101],86:[2,105],91:[2,105],93:[2,105],102:[2,105],104:[2,105],105:[2,105],106:[2,105],110:[2,105],118:[2,105],126:[2,105],128:[2,105],129:[2,105],132:[2,105],133:[2,105],134:[2,105],135:[2,105],136:[2,105],137:[2,105]},{6:[2,54],25:[2,54],27:105,28:[1,71],44:106,48:102,49:[2,54],54:[2,54],55:103,56:104,58:107,59:108,76:[1,68],89:[1,109],90:[1,110]},{24:111,25:[1,112]},{7:113,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{7:115,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{7:116,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{12:118,13:119,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:120,44:61,58:45,59:46,61:117,63:23,64:24,65:25,76:[1,68],83:[1,26],88:[1,56],89:[1,57],90:[1,55],101:[1,54]},{12:118,13:119,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:120,44:61,58:45,59:46,61:121,63:23,64:24,65:25,76:[1,68],83:[1,26],88:[1,56],89:[1,57],90:[1,55],101:[1,54]},{1:[2,71],6:[2,71],25:[2,71],26:[2,71],40:[2,71],49:[2,71],54:[2,71],57:[2,71],66:[2,71],67:[2,71],68:[2,71],69:[2,71],71:[2,71],73:[2,71],74:[2,71],78:[2,71],80:[1,125],84:[2,71],85:[2,71],86:[2,71],91:[2,71],93:[2,71],102:[2,71],104:[2,71],105:[2,71],106:[2,71],110:[2,71],118:[2,71],126:[2,71],128:[2,71],129:[2,71],130:[1,122],131:[1,123],132:[2,71],133:[2,71],134:[2,71],135:[2,71],136:[2,71],137:[2,71],138:[1,124]},{1:[2,182],6:[2,182],25:[2,182],26:[2,182],49:[2,182],54:[2,182],57:[2,182],73:[2,182],78:[2,182],86:[2,182],91:[2,182],93:[2,182],102:[2,182],104:[2,182],105:[2,182],106:[2,182],110:[2,182],118:[2,182],121:[1,126],126:[2,182],128:[2,182],129:[2,182],132:[2,182],133:[2,182],134:[2,182],135:[2,182],136:[2,182],137:[2,182]},{24:127,25:[1,112]},{24:128,25:[1,112]},{1:[2,149],6:[2,149],25:[2,149],26:[2,149],49:[2,149],54:[2,149],57:[2,149],73:[2,149],78:[2,149],86:[2,149],91:[2,149],93:[2,149],102:[2,149],104:[2,149],105:[2,149],106:[2,149],110:[2,149],118:[2,149],126:[2,149],128:[2,149],129:[2,149],132:[2,149],133:[2,149],134:[2,149],135:[2,149],136:[2,149],137:[2,149]},{24:129,25:[1,112]},{7:130,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,25:[1,131],27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{1:[2,95],6:[2,95],12:118,13:119,24:132,25:[1,112],26:[2,95],27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:120,44:61,49:[2,95],54:[2,95],57:[2,95],58:45,59:46,61:134,63:23,64:24,65:25,73:[2,95],76:[1,68],78:[2,95],80:[1,133],83:[1,26],86:[2,95],88:[1,56],89:[1,57],90:[1,55],91:[2,95],93:[2,95],101:[1,54],102:[2,95],104:[2,95],105:[2,95],106:[2,95],110:[2,95],118:[2,95],126:[2,95],128:[2,95],129:[2,95],132:[2,95],133:[2,95],134:[2,95],135:[2,95],136:[2,95],137:[2,95]},{7:135,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{1:[2,46],6:[2,46],7:136,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,26:[2,46],27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],102:[2,46],103:37,104:[2,46],106:[2,46],107:38,108:[1,65],109:39,110:[2,46],111:67,119:[1,40],124:35,125:[1,62],126:[2,46],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{1:[2,47],6:[2,47],25:[2,47],26:[2,47],54:[2,47],78:[2,47],102:[2,47],104:[2,47],106:[2,47],110:[2,47],126:[2,47]},{1:[2,72],6:[2,72],25:[2,72],26:[2,72],40:[2,72],49:[2,72],54:[2,72],57:[2,72],66:[2,72],67:[2,72],68:[2,72],69:[2,72],71:[2,72],73:[2,72],74:[2,72],78:[2,72],84:[2,72],85:[2,72],86:[2,72],91:[2,72],93:[2,72],102:[2,72],104:[2,72],105:[2,72],106:[2,72],110:[2,72],118:[2,72],126:[2,72],128:[2,72],129:[2,72],132:[2,72],133:[2,72],134:[2,72],135:[2,72],136:[2,72],137:[2,72]},{1:[2,73],6:[2,73],25:[2,73],26:[2,73],40:[2,73],49:[2,73],54:[2,73],57:[2,73],66:[2,73],67:[2,73],68:[2,73],69:[2,73],71:[2,73],73:[2,73],74:[2,73],78:[2,73],84:[2,73],85:[2,73],86:[2,73],91:[2,73],93:[2,73],102:[2,73],104:[2,73],105:[2,73],106:[2,73],110:[2,73],118:[2,73],126:[2,73],128:[2,73],129:[2,73],132:[2,73],133:[2,73],134:[2,73],135:[2,73],136:[2,73],137:[2,73]},{1:[2,28],6:[2,28],25:[2,28],26:[2,28],49:[2,28],54:[2,28],57:[2,28],66:[2,28],67:[2,28],68:[2,28],69:[2,28],71:[2,28],73:[2,28],74:[2,28],78:[2,28],84:[2,28],85:[2,28],86:[2,28],91:[2,28],93:[2,28],102:[2,28],104:[2,28],105:[2,28],106:[2,28],110:[2,28],118:[2,28],126:[2,28],128:[2,28],129:[2,28],132:[2,28],133:[2,28],134:[2,28],135:[2,28],136:[2,28],137:[2,28]},{1:[2,29],6:[2,29],25:[2,29],26:[2,29],49:[2,29],54:[2,29],57:[2,29],66:[2,29],67:[2,29],68:[2,29],69:[2,29],71:[2,29],73:[2,29],74:[2,29],78:[2,29],84:[2,29],85:[2,29],86:[2,29],91:[2,29],93:[2,29],102:[2,29],104:[2,29],105:[2,29],106:[2,29],110:[2,29],118:[2,29],126:[2,29],128:[2,29],129:[2,29],132:[2,29],133:[2,29],134:[2,29],135:[2,29],136:[2,29],137:[2,29]},{1:[2,30],6:[2,30],25:[2,30],26:[2,30],49:[2,30],54:[2,30],57:[2,30],66:[2,30],67:[2,30],68:[2,30],69:[2,30],71:[2,30],73:[2,30],74:[2,30],78:[2,30],84:[2,30],85:[2,30],86:[2,30],91:[2,30],93:[2,30],102:[2,30],104:[2,30],105:[2,30],106:[2,30],110:[2,30],118:[2,30],126:[2,30],128:[2,30],129:[2,30],132:[2,30],133:[2,30],134:[2,30],135:[2,30],136:[2,30],137:[2,30]},{1:[2,31],6:[2,31],25:[2,31],26:[2,31],49:[2,31],54:[2,31],57:[2,31],66:[2,31],67:[2,31],68:[2,31],69:[2,31],71:[2,31],73:[2,31],74:[2,31],78:[2,31],84:[2,31],85:[2,31],86:[2,31],91:[2,31],93:[2,31],102:[2,31],104:[2,31],105:[2,31],106:[2,31],110:[2,31],118:[2,31],126:[2,31],128:[2,31],129:[2,31],132:[2,31],133:[2,31],134:[2,31],135:[2,31],136:[2,31],137:[2,31]},{1:[2,32],6:[2,32],25:[2,32],26:[2,32],49:[2,32],54:[2,32],57:[2,32],66:[2,32],67:[2,32],68:[2,32],69:[2,32],71:[2,32],73:[2,32],74:[2,32],78:[2,32],84:[2,32],85:[2,32],86:[2,32],91:[2,32],93:[2,32],102:[2,32],104:[2,32],105:[2,32],106:[2,32],110:[2,32],118:[2,32],126:[2,32],128:[2,32],129:[2,32],132:[2,32],133:[2,32],134:[2,32],135:[2,32],136:[2,32],137:[2,32]},{1:[2,33],6:[2,33],25:[2,33],26:[2,33],49:[2,33],54:[2,33],57:[2,33],66:[2,33],67:[2,33],68:[2,33],69:[2,33],71:[2,33],73:[2,33],74:[2,33],78:[2,33],84:[2,33],85:[2,33],86:[2,33],91:[2,33],93:[2,33],102:[2,33],104:[2,33],105:[2,33],106:[2,33],110:[2,33],118:[2,33],126:[2,33],128:[2,33],129:[2,33],132:[2,33],133:[2,33],134:[2,33],135:[2,33],136:[2,33],137:[2,33]},{1:[2,34],6:[2,34],25:[2,34],26:[2,34],49:[2,34],54:[2,34],57:[2,34],66:[2,34],67:[2,34],68:[2,34],69:[2,34],71:[2,34],73:[2,34],74:[2,34],78:[2,34],84:[2,34],85:[2,34],86:[2,34],91:[2,34],93:[2,34],102:[2,34],104:[2,34],105:[2,34],106:[2,34],110:[2,34],118:[2,34],126:[2,34],128:[2,34],129:[2,34],132:[2,34],133:[2,34],134:[2,34],135:[2,34],136:[2,34],137:[2,34]},{4:137,5:3,7:4,8:5,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,25:[1,138],27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{7:139,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,25:[1,143],27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,60:144,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],87:141,88:[1,56],89:[1,57],90:[1,55],91:[1,140],94:142,96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{1:[2,111],6:[2,111],25:[2,111],26:[2,111],49:[2,111],54:[2,111],57:[2,111],66:[2,111],67:[2,111],68:[2,111],69:[2,111],71:[2,111],73:[2,111],74:[2,111],78:[2,111],84:[2,111],85:[2,111],86:[2,111],91:[2,111],93:[2,111],102:[2,111],104:[2,111],105:[2,111],106:[2,111],110:[2,111],118:[2,111],126:[2,111],128:[2,111],129:[2,111],132:[2,111],133:[2,111],134:[2,111],135:[2,111],136:[2,111],137:[2,111]},{1:[2,112],6:[2,112],25:[2,112],26:[2,112],27:145,28:[1,71],49:[2,112],54:[2,112],57:[2,112],66:[2,112],67:[2,112],68:[2,112],69:[2,112],71:[2,112],73:[2,112],74:[2,112],78:[2,112],84:[2,112],85:[2,112],86:[2,112],91:[2,112],93:[2,112],102:[2,112],104:[2,112],105:[2,112],106:[2,112],110:[2,112],118:[2,112],126:[2,112],128:[2,112],129:[2,112],132:[2,112],133:[2,112],134:[2,112],135:[2,112],136:[2,112],137:[2,112]},{25:[2,50]},{25:[2,51]},{1:[2,67],6:[2,67],25:[2,67],26:[2,67],40:[2,67],49:[2,67],54:[2,67],57:[2,67],66:[2,67],67:[2,67],68:[2,67],69:[2,67],71:[2,67],73:[2,67],74:[2,67],78:[2,67],80:[2,67],84:[2,67],85:[2,67],86:[2,67],91:[2,67],93:[2,67],102:[2,67],104:[2,67],105:[2,67],106:[2,67],110:[2,67],118:[2,67],126:[2,67],128:[2,67],129:[2,67],130:[2,67],131:[2,67],132:[2,67],133:[2,67],134:[2,67],135:[2,67],136:[2,67],137:[2,67],138:[2,67]},{1:[2,70],6:[2,70],25:[2,70],26:[2,70],40:[2,70],49:[2,70],54:[2,70],57:[2,70],66:[2,70],67:[2,70],68:[2,70],69:[2,70],71:[2,70],73:[2,70],74:[2,70],78:[2,70],80:[2,70],84:[2,70],85:[2,70],86:[2,70],91:[2,70],93:[2,70],102:[2,70],104:[2,70],105:[2,70],106:[2,70],110:[2,70],118:[2,70],126:[2,70],128:[2,70],129:[2,70],130:[2,70],131:[2,70],132:[2,70],133:[2,70],134:[2,70],135:[2,70],136:[2,70],137:[2,70],138:[2,70]},{7:146,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{7:147,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{7:148,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{7:150,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,24:149,25:[1,112],27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{27:155,28:[1,71],44:156,58:157,59:158,64:151,76:[1,68],89:[1,109],90:[1,55],113:152,114:[1,153],115:154},{112:159,116:[1,160],117:[1,161]},{6:[2,90],10:165,25:[2,90],27:166,28:[1,71],29:167,30:[1,69],31:[1,70],41:163,42:164,44:168,46:[1,44],54:[2,90],77:162,78:[2,90],89:[1,109]},{1:[2,26],6:[2,26],25:[2,26],26:[2,26],43:[2,26],49:[2,26],54:[2,26],57:[2,26],66:[2,26],67:[2,26],68:[2,26],69:[2,26],71:[2,26],73:[2,26],74:[2,26],78:[2,26],84:[2,26],85:[2,26],86:[2,26],91:[2,26],93:[2,26],102:[2,26],104:[2,26],105:[2,26],106:[2,26],110:[2,26],118:[2,26],126:[2,26],128:[2,26],129:[2,26],132:[2,26],133:[2,26],134:[2,26],135:[2,26],136:[2,26],137:[2,26]},{1:[2,27],6:[2,27],25:[2,27],26:[2,27],43:[2,27],49:[2,27],54:[2,27],57:[2,27],66:[2,27],67:[2,27],68:[2,27],69:[2,27],71:[2,27],73:[2,27],74:[2,27],78:[2,27],84:[2,27],85:[2,27],86:[2,27],91:[2,27],93:[2,27],102:[2,27],104:[2,27],105:[2,27],106:[2,27],110:[2,27],118:[2,27],126:[2,27],128:[2,27],129:[2,27],132:[2,27],133:[2,27],134:[2,27],135:[2,27],136:[2,27],137:[2,27]},{1:[2,25],6:[2,25],25:[2,25],26:[2,25],40:[2,25],43:[2,25],49:[2,25],54:[2,25],57:[2,25],66:[2,25],67:[2,25],68:[2,25],69:[2,25],71:[2,25],73:[2,25],74:[2,25],78:[2,25],80:[2,25],84:[2,25],85:[2,25],86:[2,25],91:[2,25],93:[2,25],102:[2,25],104:[2,25],105:[2,25],106:[2,25],110:[2,25],116:[2,25],117:[2,25],118:[2,25],126:[2,25],128:[2,25],129:[2,25],130:[2,25],131:[2,25],132:[2,25],133:[2,25],134:[2,25],135:[2,25],136:[2,25],137:[2,25],138:[2,25]},{1:[2,5],5:169,6:[2,5],7:4,8:5,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,26:[2,5],27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],102:[2,5],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{1:[2,193],6:[2,193],25:[2,193],26:[2,193],49:[2,193],54:[2,193],57:[2,193],73:[2,193],78:[2,193],86:[2,193],91:[2,193],93:[2,193],102:[2,193],104:[2,193],105:[2,193],106:[2,193],110:[2,193],118:[2,193],126:[2,193],128:[2,193],129:[2,193],132:[2,193],133:[2,193],134:[2,193],135:[2,193],136:[2,193],137:[2,193]},{7:170,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{7:171,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{7:172,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{7:173,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{7:174,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{7:175,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{7:176,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{7:177,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{1:[2,148],6:[2,148],25:[2,148],26:[2,148],49:[2,148],54:[2,148],57:[2,148],73:[2,148],78:[2,148],86:[2,148],91:[2,148],93:[2,148],102:[2,148],104:[2,148],105:[2,148],106:[2,148],110:[2,148],118:[2,148],126:[2,148],128:[2,148],129:[2,148],132:[2,148],133:[2,148],134:[2,148],135:[2,148],136:[2,148],137:[2,148]},{1:[2,153],6:[2,153],25:[2,153],26:[2,153],49:[2,153],54:[2,153],57:[2,153],73:[2,153],78:[2,153],86:[2,153],91:[2,153],93:[2,153],102:[2,153],104:[2,153],105:[2,153],106:[2,153],110:[2,153],118:[2,153],126:[2,153],128:[2,153],129:[2,153],132:[2,153],133:[2,153],134:[2,153],135:[2,153],136:[2,153],137:[2,153]},{7:178,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{1:[2,147],6:[2,147],25:[2,147],26:[2,147],49:[2,147],54:[2,147],57:[2,147],73:[2,147],78:[2,147],86:[2,147],91:[2,147],93:[2,147],102:[2,147],104:[2,147],105:[2,147],106:[2,147],110:[2,147],118:[2,147],126:[2,147],128:[2,147],129:[2,147],132:[2,147],133:[2,147],134:[2,147],135:[2,147],136:[2,147],137:[2,147]},{1:[2,152],6:[2,152],25:[2,152],26:[2,152],49:[2,152],54:[2,152],57:[2,152],73:[2,152],78:[2,152],86:[2,152],91:[2,152],93:[2,152],102:[2,152],104:[2,152],105:[2,152],106:[2,152],110:[2,152],118:[2,152],126:[2,152],128:[2,152],129:[2,152],132:[2,152],133:[2,152],134:[2,152],135:[2,152],136:[2,152],137:[2,152]},{82:179,85:[1,101]},{1:[2,68],6:[2,68],25:[2,68],26:[2,68],40:[2,68],49:[2,68],54:[2,68],57:[2,68],66:[2,68],67:[2,68],68:[2,68],69:[2,68],71:[2,68],73:[2,68],74:[2,68],78:[2,68],80:[2,68],84:[2,68],85:[2,68],86:[2,68],91:[2,68],93:[2,68],102:[2,68],104:[2,68],105:[2,68],106:[2,68],110:[2,68],118:[2,68],126:[2,68],128:[2,68],129:[2,68],130:[2,68],131:[2,68],132:[2,68],133:[2,68],134:[2,68],135:[2,68],136:[2,68],137:[2,68],138:[2,68]},{85:[2,108]},{27:180,28:[1,71]},{27:181,28:[1,71]},{1:[2,83],6:[2,83],25:[2,83],26:[2,83],27:182,28:[1,71],40:[2,83],49:[2,83],54:[2,83],57:[2,83],66:[2,83],67:[2,83],68:[2,83],69:[2,83],71:[2,83],73:[2,83],74:[2,83],78:[2,83],80:[2,83],84:[2,83],85:[2,83],86:[2,83],91:[2,83],93:[2,83],102:[2,83],104:[2,83],105:[2,83],106:[2,83],110:[2,83],118:[2,83],126:[2,83],128:[2,83],129:[2,83],130:[2,83],131:[2,83],132:[2,83],133:[2,83],134:[2,83],135:[2,83],136:[2,83],137:[2,83],138:[2,83]},{27:183,28:[1,71]},{1:[2,84],6:[2,84],25:[2,84],26:[2,84],40:[2,84],49:[2,84],54:[2,84],57:[2,84],66:[2,84],67:[2,84],68:[2,84],69:[2,84],71:[2,84],73:[2,84],74:[2,84],78:[2,84],80:[2,84],84:[2,84],85:[2,84],86:[2,84],91:[2,84],93:[2,84],102:[2,84],104:[2,84],105:[2,84],106:[2,84],110:[2,84],118:[2,84],126:[2,84],128:[2,84],129:[2,84],130:[2,84],131:[2,84],132:[2,84],133:[2,84],134:[2,84],135:[2,84],136:[2,84],137:[2,84],138:[2,84]},{7:185,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],57:[1,189],58:45,59:46,61:34,63:23,64:24,65:25,72:184,75:186,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],92:187,93:[1,188],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{70:190,71:[1,95],74:[1,96]},{82:191,85:[1,101]},{1:[2,69],6:[2,69],25:[2,69],26:[2,69],40:[2,69],49:[2,69],54:[2,69],57:[2,69],66:[2,69],67:[2,69],68:[2,69],69:[2,69],71:[2,69],73:[2,69],74:[2,69],78:[2,69],80:[2,69],84:[2,69],85:[2,69],86:[2,69],91:[2,69],93:[2,69],102:[2,69],104:[2,69],105:[2,69],106:[2,69],110:[2,69],118:[2,69],126:[2,69],128:[2,69],129:[2,69],130:[2,69],131:[2,69],132:[2,69],133:[2,69],134:[2,69],135:[2,69],136:[2,69],137:[2,69],138:[2,69]},{6:[1,193],7:192,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,25:[1,194],27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{1:[2,106],6:[2,106],25:[2,106],26:[2,106],49:[2,106],54:[2,106],57:[2,106],66:[2,106],67:[2,106],68:[2,106],69:[2,106],71:[2,106],73:[2,106],74:[2,106],78:[2,106],84:[2,106],85:[2,106],86:[2,106],91:[2,106],93:[2,106],102:[2,106],104:[2,106],105:[2,106],106:[2,106],110:[2,106],118:[2,106],126:[2,106],128:[2,106],129:[2,106],132:[2,106],133:[2,106],134:[2,106],135:[2,106],136:[2,106],137:[2,106]},{7:197,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,25:[1,143],27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,60:144,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],86:[1,195],87:196,88:[1,56],89:[1,57],90:[1,55],94:142,96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{6:[2,52],25:[2,52],49:[1,198],53:200,54:[1,199]},{6:[2,55],25:[2,55],26:[2,55],49:[2,55],54:[2,55]},{6:[2,59],25:[2,59],26:[2,59],40:[1,202],49:[2,59],54:[2,59],57:[1,201]},{6:[2,62],25:[2,62],26:[2,62],40:[2,62],49:[2,62],54:[2,62],57:[2,62]},{6:[2,63],25:[2,63],26:[2,63],40:[2,63],49:[2,63],54:[2,63],57:[2,63]},{6:[2,64],25:[2,64],26:[2,64],40:[2,64],49:[2,64],54:[2,64],57:[2,64]},{6:[2,65],25:[2,65],26:[2,65],40:[2,65],49:[2,65],54:[2,65],57:[2,65]},{27:145,28:[1,71]},{7:197,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,25:[1,143],27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,60:144,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],87:141,88:[1,56],89:[1,57],90:[1,55],91:[1,140],94:142,96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{1:[2,49],6:[2,49],25:[2,49],26:[2,49],49:[2,49],54:[2,49],57:[2,49],73:[2,49],78:[2,49],86:[2,49],91:[2,49],93:[2,49],102:[2,49],104:[2,49],105:[2,49],106:[2,49],110:[2,49],118:[2,49],126:[2,49],128:[2,49],129:[2,49],132:[2,49],133:[2,49],134:[2,49],135:[2,49],136:[2,49],137:[2,49]},{4:204,5:3,7:4,8:5,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,26:[1,203],27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{1:[2,186],6:[2,186],25:[2,186],26:[2,186],49:[2,186],54:[2,186],57:[2,186],73:[2,186],78:[2,186],86:[2,186],91:[2,186],93:[2,186],102:[2,186],103:82,104:[2,186],105:[2,186],106:[2,186],109:83,110:[2,186],111:67,118:[2,186],126:[2,186],128:[2,186],129:[2,186],132:[1,73],133:[2,186],134:[2,186],135:[2,186],136:[2,186],137:[2,186]},{103:85,104:[1,63],106:[1,64],109:86,110:[1,66],111:67,126:[1,84]},{1:[2,187],6:[2,187],25:[2,187],26:[2,187],49:[2,187],54:[2,187],57:[2,187],73:[2,187],78:[2,187],86:[2,187],91:[2,187],93:[2,187],102:[2,187],103:82,104:[2,187],105:[2,187],106:[2,187],109:83,110:[2,187],111:67,118:[2,187],126:[2,187],128:[2,187],129:[2,187],132:[1,73],133:[2,187],134:[2,187],135:[2,187],136:[2,187],137:[2,187]},{1:[2,188],6:[2,188],25:[2,188],26:[2,188],49:[2,188],54:[2,188],57:[2,188],73:[2,188],78:[2,188],86:[2,188],91:[2,188],93:[2,188],102:[2,188],103:82,104:[2,188],105:[2,188],106:[2,188],109:83,110:[2,188],111:67,118:[2,188],126:[2,188],128:[2,188],129:[2,188],132:[1,73],133:[2,188],134:[2,188],135:[2,188],136:[2,188],137:[2,188]},{1:[2,189],6:[2,189],25:[2,189],26:[2,189],49:[2,189],54:[2,189],57:[2,189],66:[2,71],67:[2,71],68:[2,71],69:[2,71],71:[2,71],73:[2,189],74:[2,71],78:[2,189],84:[2,71],85:[2,71],86:[2,189],91:[2,189],93:[2,189],102:[2,189],104:[2,189],105:[2,189],106:[2,189],110:[2,189],118:[2,189],126:[2,189],128:[2,189],129:[2,189],132:[2,189],133:[2,189],134:[2,189],135:[2,189],136:[2,189],137:[2,189]},{62:88,66:[1,90],67:[1,91],68:[1,92],69:[1,93],70:94,71:[1,95],74:[1,96],81:87,84:[1,89],85:[2,107]},{62:98,66:[1,90],67:[1,91],68:[1,92],69:[1,93],70:94,71:[1,95],74:[1,96],81:97,84:[1,89],85:[2,107]},{66:[2,74],67:[2,74],68:[2,74],69:[2,74],71:[2,74],74:[2,74],84:[2,74],85:[2,74]},{1:[2,190],6:[2,190],25:[2,190],26:[2,190],49:[2,190],54:[2,190],57:[2,190],66:[2,71],67:[2,71],68:[2,71],69:[2,71],71:[2,71],73:[2,190],74:[2,71],78:[2,190],84:[2,71],85:[2,71],86:[2,190],91:[2,190],93:[2,190],102:[2,190],104:[2,190],105:[2,190],106:[2,190],110:[2,190],118:[2,190],126:[2,190],128:[2,190],129:[2,190],132:[2,190],133:[2,190],134:[2,190],135:[2,190],136:[2,190],137:[2,190]},{1:[2,191],6:[2,191],25:[2,191],26:[2,191],49:[2,191],54:[2,191],57:[2,191],73:[2,191],78:[2,191],86:[2,191],91:[2,191],93:[2,191],102:[2,191],104:[2,191],105:[2,191],106:[2,191],110:[2,191],118:[2,191],126:[2,191],128:[2,191],129:[2,191],132:[2,191],133:[2,191],134:[2,191],135:[2,191],136:[2,191],137:[2,191]},{1:[2,192],6:[2,192],25:[2,192],26:[2,192],49:[2,192],54:[2,192],57:[2,192],73:[2,192],78:[2,192],86:[2,192],91:[2,192],93:[2,192],102:[2,192],104:[2,192],105:[2,192],106:[2,192],110:[2,192],118:[2,192],126:[2,192],128:[2,192],129:[2,192],132:[2,192],133:[2,192],134:[2,192],135:[2,192],136:[2,192],137:[2,192]},{6:[1,207],7:205,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,25:[1,206],27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{7:208,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{24:209,25:[1,112],125:[1,210]},{1:[2,132],6:[2,132],25:[2,132],26:[2,132],49:[2,132],54:[2,132],57:[2,132],73:[2,132],78:[2,132],86:[2,132],91:[2,132],93:[2,132],97:211,98:[1,212],99:[1,213],102:[2,132],104:[2,132],105:[2,132],106:[2,132],110:[2,132],118:[2,132],126:[2,132],128:[2,132],129:[2,132],132:[2,132],133:[2,132],134:[2,132],135:[2,132],136:[2,132],137:[2,132]},{1:[2,146],6:[2,146],25:[2,146],26:[2,146],49:[2,146],54:[2,146],57:[2,146],73:[2,146],78:[2,146],86:[2,146],91:[2,146],93:[2,146],102:[2,146],104:[2,146],105:[2,146],106:[2,146],110:[2,146],118:[2,146],126:[2,146],128:[2,146],129:[2,146],132:[2,146],133:[2,146],134:[2,146],135:[2,146],136:[2,146],137:[2,146]},{1:[2,154],6:[2,154],25:[2,154],26:[2,154],49:[2,154],54:[2,154],57:[2,154],73:[2,154],78:[2,154],86:[2,154],91:[2,154],93:[2,154],102:[2,154],104:[2,154],105:[2,154],106:[2,154],110:[2,154],118:[2,154],126:[2,154],128:[2,154],129:[2,154],132:[2,154],133:[2,154],134:[2,154],135:[2,154],136:[2,154],137:[2,154]},{25:[1,214],103:82,104:[1,63],106:[1,64],109:83,110:[1,66],111:67,126:[1,81],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[1,78],136:[1,79],137:[1,80]},{120:215,122:216,123:[1,217]},{1:[2,96],6:[2,96],25:[2,96],26:[2,96],49:[2,96],54:[2,96],57:[2,96],73:[2,96],78:[2,96],86:[2,96],91:[2,96],93:[2,96],102:[2,96],104:[2,96],105:[2,96],106:[2,96],110:[2,96],118:[2,96],126:[2,96],128:[2,96],129:[2,96],132:[2,96],133:[2,96],134:[2,96],135:[2,96],136:[2,96],137:[2,96]},{7:218,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{1:[2,99],6:[2,99],24:219,25:[1,112],26:[2,99],49:[2,99],54:[2,99],57:[2,99],66:[2,71],67:[2,71],68:[2,71],69:[2,71],71:[2,71],73:[2,99],74:[2,71],78:[2,99],80:[1,220],84:[2,71],85:[2,71],86:[2,99],91:[2,99],93:[2,99],102:[2,99],104:[2,99],105:[2,99],106:[2,99],110:[2,99],118:[2,99],126:[2,99],128:[2,99],129:[2,99],132:[2,99],133:[2,99],134:[2,99],135:[2,99],136:[2,99],137:[2,99]},{1:[2,139],6:[2,139],25:[2,139],26:[2,139],49:[2,139],54:[2,139],57:[2,139],73:[2,139],78:[2,139],86:[2,139],91:[2,139],93:[2,139],102:[2,139],103:82,104:[2,139],105:[2,139],106:[2,139],109:83,110:[2,139],111:67,118:[2,139],126:[2,139],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[1,78],136:[1,79],137:[1,80]},{1:[2,45],6:[2,45],26:[2,45],102:[2,45],103:82,104:[2,45],106:[2,45],109:83,110:[2,45],111:67,126:[2,45],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[1,78],136:[1,79],137:[1,80]},{6:[1,72],102:[1,221]},{4:222,5:3,7:4,8:5,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{6:[2,128],25:[2,128],54:[2,128],57:[1,224],91:[2,128],92:223,93:[1,188],103:82,104:[1,63],106:[1,64],109:83,110:[1,66],111:67,126:[1,81],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[1,78],136:[1,79],137:[1,80]},{1:[2,114],6:[2,114],25:[2,114],26:[2,114],40:[2,114],49:[2,114],54:[2,114],57:[2,114],66:[2,114],67:[2,114],68:[2,114],69:[2,114],71:[2,114],73:[2,114],74:[2,114],78:[2,114],84:[2,114],85:[2,114],86:[2,114],91:[2,114],93:[2,114],102:[2,114],104:[2,114],105:[2,114],106:[2,114],110:[2,114],116:[2,114],117:[2,114],118:[2,114],126:[2,114],128:[2,114],129:[2,114],132:[2,114],133:[2,114],134:[2,114],135:[2,114],136:[2,114],137:[2,114]},{6:[2,52],25:[2,52],53:225,54:[1,226],91:[2,52]},{6:[2,123],25:[2,123],26:[2,123],54:[2,123],86:[2,123],91:[2,123]},{7:197,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,25:[1,143],27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,60:144,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],87:227,88:[1,56],89:[1,57],90:[1,55],94:142,96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{6:[2,129],25:[2,129],26:[2,129],54:[2,129],86:[2,129],91:[2,129]},{1:[2,113],6:[2,113],25:[2,113],26:[2,113],40:[2,113],43:[2,113],49:[2,113],54:[2,113],57:[2,113],66:[2,113],67:[2,113],68:[2,113],69:[2,113],71:[2,113],73:[2,113],74:[2,113],78:[2,113],80:[2,113],84:[2,113],85:[2,113],86:[2,113],91:[2,113],93:[2,113],102:[2,113],104:[2,113],105:[2,113],106:[2,113],110:[2,113],116:[2,113],117:[2,113],118:[2,113],126:[2,113],128:[2,113],129:[2,113],130:[2,113],131:[2,113],132:[2,113],133:[2,113],134:[2,113],135:[2,113],136:[2,113],137:[2,113],138:[2,113]},{24:228,25:[1,112],103:82,104:[1,63],106:[1,64],109:83,110:[1,66],111:67,126:[1,81],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[1,78],136:[1,79],137:[1,80]},{1:[2,142],6:[2,142],25:[2,142],26:[2,142],49:[2,142],54:[2,142],57:[2,142],73:[2,142],78:[2,142],86:[2,142],91:[2,142],93:[2,142],102:[2,142],103:82,104:[1,63],105:[1,229],106:[1,64],109:83,110:[1,66],111:67,118:[2,142],126:[2,142],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[1,78],136:[1,79],137:[1,80]},{1:[2,144],6:[2,144],25:[2,144],26:[2,144],49:[2,144],54:[2,144],57:[2,144],73:[2,144],78:[2,144],86:[2,144],91:[2,144],93:[2,144],102:[2,144],103:82,104:[1,63],105:[1,230],106:[1,64],109:83,110:[1,66],111:67,118:[2,144],126:[2,144],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[1,78],136:[1,79],137:[1,80]},{1:[2,150],6:[2,150],25:[2,150],26:[2,150],49:[2,150],54:[2,150],57:[2,150],73:[2,150],78:[2,150],86:[2,150],91:[2,150],93:[2,150],102:[2,150],104:[2,150],105:[2,150],106:[2,150],110:[2,150],118:[2,150],126:[2,150],128:[2,150],129:[2,150],132:[2,150],133:[2,150],134:[2,150],135:[2,150],136:[2,150],137:[2,150]},{1:[2,151],6:[2,151],25:[2,151],26:[2,151],49:[2,151],54:[2,151],57:[2,151],73:[2,151],78:[2,151],86:[2,151],91:[2,151],93:[2,151],102:[2,151],103:82,104:[1,63],105:[2,151],106:[1,64],109:83,110:[1,66],111:67,118:[2,151],126:[2,151],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[1,78],136:[1,79],137:[1,80]},{1:[2,155],6:[2,155],25:[2,155],26:[2,155],49:[2,155],54:[2,155],57:[2,155],73:[2,155],78:[2,155],86:[2,155],91:[2,155],93:[2,155],102:[2,155],104:[2,155],105:[2,155],106:[2,155],110:[2,155],118:[2,155],126:[2,155],128:[2,155],129:[2,155],132:[2,155],133:[2,155],134:[2,155],135:[2,155],136:[2,155],137:[2,155]},{116:[2,157],117:[2,157]},{27:155,28:[1,71],44:156,58:157,59:158,76:[1,68],89:[1,109],90:[1,110],113:231,115:154},{54:[1,232],116:[2,163],117:[2,163]},{54:[2,159],116:[2,159],117:[2,159]},{54:[2,160],116:[2,160],117:[2,160]},{54:[2,161],116:[2,161],117:[2,161]},{54:[2,162],116:[2,162],117:[2,162]},{1:[2,156],6:[2,156],25:[2,156],26:[2,156],49:[2,156],54:[2,156],57:[2,156],73:[2,156],78:[2,156],86:[2,156],91:[2,156],93:[2,156],102:[2,156],104:[2,156],105:[2,156],106:[2,156],110:[2,156],118:[2,156],126:[2,156],128:[2,156],129:[2,156],132:[2,156],133:[2,156],134:[2,156],135:[2,156],136:[2,156],137:[2,156]},{7:233,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{7:234,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{6:[2,52],25:[2,52],53:235,54:[1,236],78:[2,52]},{6:[2,91],25:[2,91],26:[2,91],54:[2,91],78:[2,91]},{6:[2,38],25:[2,38],26:[2,38],43:[1,237],54:[2,38],78:[2,38]},{6:[2,41],25:[2,41],26:[2,41],54:[2,41],78:[2,41]},{6:[2,42],25:[2,42],26:[2,42],43:[2,42],54:[2,42],78:[2,42]},{6:[2,43],25:[2,43],26:[2,43],43:[2,43],54:[2,43],78:[2,43]},{6:[2,44],25:[2,44],26:[2,44],43:[2,44],54:[2,44],78:[2,44]},{1:[2,4],6:[2,4],26:[2,4],102:[2,4]},{1:[2,194],6:[2,194],25:[2,194],26:[2,194],49:[2,194],54:[2,194],57:[2,194],73:[2,194],78:[2,194],86:[2,194],91:[2,194],93:[2,194],102:[2,194],103:82,104:[2,194],105:[2,194],106:[2,194],109:83,110:[2,194],111:67,118:[2,194],126:[2,194],128:[2,194],129:[2,194],132:[1,73],133:[1,76],134:[2,194],135:[2,194],136:[2,194],137:[2,194]},{1:[2,195],6:[2,195],25:[2,195],26:[2,195],49:[2,195],54:[2,195],57:[2,195],73:[2,195],78:[2,195],86:[2,195],91:[2,195],93:[2,195],102:[2,195],103:82,104:[2,195],105:[2,195],106:[2,195],109:83,110:[2,195],111:67,118:[2,195],126:[2,195],128:[2,195],129:[2,195],132:[1,73],133:[1,76],134:[2,195],135:[2,195],136:[2,195],137:[2,195]},{1:[2,196],6:[2,196],25:[2,196],26:[2,196],49:[2,196],54:[2,196],57:[2,196],73:[2,196],78:[2,196],86:[2,196],91:[2,196],93:[2,196],102:[2,196],103:82,104:[2,196],105:[2,196],106:[2,196],109:83,110:[2,196],111:67,118:[2,196],126:[2,196],128:[2,196],129:[2,196],132:[1,73],133:[2,196],134:[2,196],135:[2,196],136:[2,196],137:[2,196]},{1:[2,197],6:[2,197],25:[2,197],26:[2,197],49:[2,197],54:[2,197],57:[2,197],73:[2,197],78:[2,197],86:[2,197],91:[2,197],93:[2,197],102:[2,197],103:82,104:[2,197],105:[2,197],106:[2,197],109:83,110:[2,197],111:67,118:[2,197],126:[2,197],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[2,197],135:[2,197],136:[2,197],137:[2,197]},{1:[2,198],6:[2,198],25:[2,198],26:[2,198],49:[2,198],54:[2,198],57:[2,198],73:[2,198],78:[2,198],86:[2,198],91:[2,198],93:[2,198],102:[2,198],103:82,104:[2,198],105:[2,198],106:[2,198],109:83,110:[2,198],111:67,118:[2,198],126:[2,198],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[2,198],136:[2,198],137:[1,80]},{1:[2,199],6:[2,199],25:[2,199],26:[2,199],49:[2,199],54:[2,199],57:[2,199],73:[2,199],78:[2,199],86:[2,199],91:[2,199],93:[2,199],102:[2,199],103:82,104:[2,199],105:[2,199],106:[2,199],109:83,110:[2,199],111:67,118:[2,199],126:[2,199],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[1,78],136:[2,199],137:[1,80]},{1:[2,200],6:[2,200],25:[2,200],26:[2,200],49:[2,200],54:[2,200],57:[2,200],73:[2,200],78:[2,200],86:[2,200],91:[2,200],93:[2,200],102:[2,200],103:82,104:[2,200],105:[2,200],106:[2,200],109:83,110:[2,200],111:67,118:[2,200],126:[2,200],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[2,200],136:[2,200],137:[2,200]},{1:[2,185],6:[2,185],25:[2,185],26:[2,185],49:[2,185],54:[2,185],57:[2,185],73:[2,185],78:[2,185],86:[2,185],91:[2,185],93:[2,185],102:[2,185],103:82,104:[1,63],105:[2,185],106:[1,64],109:83,110:[1,66],111:67,118:[2,185],126:[1,81],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[1,78],136:[1,79],137:[1,80]},{1:[2,184],6:[2,184],25:[2,184],26:[2,184],49:[2,184],54:[2,184],57:[2,184],73:[2,184],78:[2,184],86:[2,184],91:[2,184],93:[2,184],102:[2,184],103:82,104:[1,63],105:[2,184],106:[1,64],109:83,110:[1,66],111:67,118:[2,184],126:[1,81],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[1,78],136:[1,79],137:[1,80]},{1:[2,103],6:[2,103],25:[2,103],26:[2,103],49:[2,103],54:[2,103],57:[2,103],66:[2,103],67:[2,103],68:[2,103],69:[2,103],71:[2,103],73:[2,103],74:[2,103],78:[2,103],84:[2,103],85:[2,103],86:[2,103],91:[2,103],93:[2,103],102:[2,103],104:[2,103],105:[2,103],106:[2,103],110:[2,103],118:[2,103],126:[2,103],128:[2,103],129:[2,103],132:[2,103],133:[2,103],134:[2,103],135:[2,103],136:[2,103],137:[2,103]},{1:[2,79],6:[2,79],25:[2,79],26:[2,79],40:[2,79],49:[2,79],54:[2,79],57:[2,79],66:[2,79],67:[2,79],68:[2,79],69:[2,79],71:[2,79],73:[2,79],74:[2,79],78:[2,79],80:[2,79],84:[2,79],85:[2,79],86:[2,79],91:[2,79],93:[2,79],102:[2,79],104:[2,79],105:[2,79],106:[2,79],110:[2,79],118:[2,79],126:[2,79],128:[2,79],129:[2,79],130:[2,79],131:[2,79],132:[2,79],133:[2,79],134:[2,79],135:[2,79],136:[2,79],137:[2,79],138:[2,79]},{1:[2,80],6:[2,80],25:[2,80],26:[2,80],40:[2,80],49:[2,80],54:[2,80],57:[2,80],66:[2,80],67:[2,80],68:[2,80],69:[2,80],71:[2,80],73:[2,80],74:[2,80],78:[2,80],80:[2,80],84:[2,80],85:[2,80],86:[2,80],91:[2,80],93:[2,80],102:[2,80],104:[2,80],105:[2,80],106:[2,80],110:[2,80],118:[2,80],126:[2,80],128:[2,80],129:[2,80],130:[2,80],131:[2,80],132:[2,80],133:[2,80],134:[2,80],135:[2,80],136:[2,80],137:[2,80],138:[2,80]},{1:[2,81],6:[2,81],25:[2,81],26:[2,81],40:[2,81],49:[2,81],54:[2,81],57:[2,81],66:[2,81],67:[2,81],68:[2,81],69:[2,81],71:[2,81],73:[2,81],74:[2,81],78:[2,81],80:[2,81],84:[2,81],85:[2,81],86:[2,81],91:[2,81],93:[2,81],102:[2,81],104:[2,81],105:[2,81],106:[2,81],110:[2,81],118:[2,81],126:[2,81],128:[2,81],129:[2,81],130:[2,81],131:[2,81],132:[2,81],133:[2,81],134:[2,81],135:[2,81],136:[2,81],137:[2,81],138:[2,81]},{1:[2,82],6:[2,82],25:[2,82],26:[2,82],40:[2,82],49:[2,82],54:[2,82],57:[2,82],66:[2,82],67:[2,82],68:[2,82],69:[2,82],71:[2,82],73:[2,82],74:[2,82],78:[2,82],80:[2,82],84:[2,82],85:[2,82],86:[2,82],91:[2,82],93:[2,82],102:[2,82],104:[2,82],105:[2,82],106:[2,82],110:[2,82],118:[2,82],126:[2,82],128:[2,82],129:[2,82],130:[2,82],131:[2,82],132:[2,82],133:[2,82],134:[2,82],135:[2,82],136:[2,82],137:[2,82],138:[2,82]},{73:[1,238]},{57:[1,189],73:[2,87],92:239,93:[1,188],103:82,104:[1,63],106:[1,64],109:83,110:[1,66],111:67,126:[1,81],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[1,78],136:[1,79],137:[1,80]},{73:[2,88]},{7:240,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,73:[2,122],76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{11:[2,116],28:[2,116],30:[2,116],31:[2,116],33:[2,116],34:[2,116],35:[2,116],36:[2,116],37:[2,116],38:[2,116],45:[2,116],46:[2,116],47:[2,116],51:[2,116],52:[2,116],73:[2,116],76:[2,116],79:[2,116],83:[2,116],88:[2,116],89:[2,116],90:[2,116],96:[2,116],100:[2,116],101:[2,116],104:[2,116],106:[2,116],108:[2,116],110:[2,116],119:[2,116],125:[2,116],127:[2,116],128:[2,116],129:[2,116],130:[2,116],131:[2,116]},{11:[2,117],28:[2,117],30:[2,117],31:[2,117],33:[2,117],34:[2,117],35:[2,117],36:[2,117],37:[2,117],38:[2,117],45:[2,117],46:[2,117],47:[2,117],51:[2,117],52:[2,117],73:[2,117],76:[2,117],79:[2,117],83:[2,117],88:[2,117],89:[2,117],90:[2,117],96:[2,117],100:[2,117],101:[2,117],104:[2,117],106:[2,117],108:[2,117],110:[2,117],119:[2,117],125:[2,117],127:[2,117],128:[2,117],129:[2,117],130:[2,117],131:[2,117]},{1:[2,86],6:[2,86],25:[2,86],26:[2,86],40:[2,86],49:[2,86],54:[2,86],57:[2,86],66:[2,86],67:[2,86],68:[2,86],69:[2,86],71:[2,86],73:[2,86],74:[2,86],78:[2,86],80:[2,86],84:[2,86],85:[2,86],86:[2,86],91:[2,86],93:[2,86],102:[2,86],104:[2,86],105:[2,86],106:[2,86],110:[2,86],118:[2,86],126:[2,86],128:[2,86],129:[2,86],130:[2,86],131:[2,86],132:[2,86],133:[2,86],134:[2,86],135:[2,86],136:[2,86],137:[2,86],138:[2,86]},{1:[2,104],6:[2,104],25:[2,104],26:[2,104],49:[2,104],54:[2,104],57:[2,104],66:[2,104],67:[2,104],68:[2,104],69:[2,104],71:[2,104],73:[2,104],74:[2,104],78:[2,104],84:[2,104],85:[2,104],86:[2,104],91:[2,104],93:[2,104],102:[2,104],104:[2,104],105:[2,104],106:[2,104],110:[2,104],118:[2,104],126:[2,104],128:[2,104],129:[2,104],132:[2,104],133:[2,104],134:[2,104],135:[2,104],136:[2,104],137:[2,104]},{1:[2,35],6:[2,35],25:[2,35],26:[2,35],49:[2,35],54:[2,35],57:[2,35],73:[2,35],78:[2,35],86:[2,35],91:[2,35],93:[2,35],102:[2,35],103:82,104:[2,35],105:[2,35],106:[2,35],109:83,110:[2,35],111:67,118:[2,35],126:[2,35],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[1,78],136:[1,79],137:[1,80]},{7:241,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{7:242,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{1:[2,109],6:[2,109],25:[2,109],26:[2,109],49:[2,109],54:[2,109],57:[2,109],66:[2,109],67:[2,109],68:[2,109],69:[2,109],71:[2,109],73:[2,109],74:[2,109],78:[2,109],84:[2,109],85:[2,109],86:[2,109],91:[2,109],93:[2,109],102:[2,109],104:[2,109],105:[2,109],106:[2,109],110:[2,109],118:[2,109],126:[2,109],128:[2,109],129:[2,109],132:[2,109],133:[2,109],134:[2,109],135:[2,109],136:[2,109],137:[2,109]},{6:[2,52],25:[2,52],53:243,54:[1,226],86:[2,52]},{6:[2,128],25:[2,128],26:[2,128],54:[2,128],57:[1,244],86:[2,128],91:[2,128],103:82,104:[1,63],106:[1,64],109:83,110:[1,66],111:67,126:[1,81],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[1,78],136:[1,79],137:[1,80]},{50:245,51:[1,58],52:[1,59]},{6:[2,53],25:[2,53],26:[2,53],27:105,28:[1,71],44:106,55:246,56:104,58:107,59:108,76:[1,68],89:[1,109],90:[1,110]},{6:[1,247],25:[1,248]},{6:[2,60],25:[2,60],26:[2,60],49:[2,60],54:[2,60]},{7:249,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{1:[2,23],6:[2,23],25:[2,23],26:[2,23],49:[2,23],54:[2,23],57:[2,23],73:[2,23],78:[2,23],86:[2,23],91:[2,23],93:[2,23],98:[2,23],99:[2,23],102:[2,23],104:[2,23],105:[2,23],106:[2,23],110:[2,23],118:[2,23],121:[2,23],123:[2,23],126:[2,23],128:[2,23],129:[2,23],132:[2,23],133:[2,23],134:[2,23],135:[2,23],136:[2,23],137:[2,23]},{6:[1,72],26:[1,250]},{1:[2,201],6:[2,201],25:[2,201],26:[2,201],49:[2,201],54:[2,201],57:[2,201],73:[2,201],78:[2,201],86:[2,201],91:[2,201],93:[2,201],102:[2,201],103:82,104:[2,201],105:[2,201],106:[2,201],109:83,110:[2,201],111:67,118:[2,201],126:[2,201],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[1,78],136:[1,79],137:[1,80]},{7:251,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{7:252,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{1:[2,204],6:[2,204],25:[2,204],26:[2,204],49:[2,204],54:[2,204],57:[2,204],73:[2,204],78:[2,204],86:[2,204],91:[2,204],93:[2,204],102:[2,204],103:82,104:[2,204],105:[2,204],106:[2,204],109:83,110:[2,204],111:67,118:[2,204],126:[2,204],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[1,78],136:[1,79],137:[1,80]},{1:[2,183],6:[2,183],25:[2,183],26:[2,183],49:[2,183],54:[2,183],57:[2,183],73:[2,183],78:[2,183],86:[2,183],91:[2,183],93:[2,183],102:[2,183],104:[2,183],105:[2,183],106:[2,183],110:[2,183],118:[2,183],126:[2,183],128:[2,183],129:[2,183],132:[2,183],133:[2,183],134:[2,183],135:[2,183],136:[2,183],137:[2,183]},{7:253,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{1:[2,133],6:[2,133],25:[2,133],26:[2,133],49:[2,133],54:[2,133],57:[2,133],73:[2,133],78:[2,133],86:[2,133],91:[2,133],93:[2,133],98:[1,254],102:[2,133],104:[2,133],105:[2,133],106:[2,133],110:[2,133],118:[2,133],126:[2,133],128:[2,133],129:[2,133],132:[2,133],133:[2,133],134:[2,133],135:[2,133],136:[2,133],137:[2,133]},{24:255,25:[1,112]},{24:258,25:[1,112],27:256,28:[1,71],59:257,76:[1,68]},{120:259,122:216,123:[1,217]},{26:[1,260],121:[1,261],122:262,123:[1,217]},{26:[2,176],121:[2,176],123:[2,176]},{7:264,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],95:263,96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{1:[2,97],6:[2,97],24:265,25:[1,112],26:[2,97],49:[2,97],54:[2,97],57:[2,97],73:[2,97],78:[2,97],86:[2,97],91:[2,97],93:[2,97],102:[2,97],103:82,104:[1,63],105:[2,97],106:[1,64],109:83,110:[1,66],111:67,118:[2,97],126:[2,97],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[1,78],136:[1,79],137:[1,80]},{1:[2,100],6:[2,100],25:[2,100],26:[2,100],49:[2,100],54:[2,100],57:[2,100],73:[2,100],78:[2,100],86:[2,100],91:[2,100],93:[2,100],102:[2,100],104:[2,100],105:[2,100],106:[2,100],110:[2,100],118:[2,100],126:[2,100],128:[2,100],129:[2,100],132:[2,100],133:[2,100],134:[2,100],135:[2,100],136:[2,100],137:[2,100]},{7:266,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{1:[2,140],6:[2,140],25:[2,140],26:[2,140],49:[2,140],54:[2,140],57:[2,140],66:[2,140],67:[2,140],68:[2,140],69:[2,140],71:[2,140],73:[2,140],74:[2,140],78:[2,140],84:[2,140],85:[2,140],86:[2,140],91:[2,140],93:[2,140],102:[2,140],104:[2,140],105:[2,140],106:[2,140],110:[2,140],118:[2,140],126:[2,140],128:[2,140],129:[2,140],132:[2,140],133:[2,140],134:[2,140],135:[2,140],136:[2,140],137:[2,140]},{6:[1,72],26:[1,267]},{7:268,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{6:[2,66],11:[2,117],25:[2,66],28:[2,117],30:[2,117],31:[2,117],33:[2,117],34:[2,117],35:[2,117],36:[2,117],37:[2,117],38:[2,117],45:[2,117],46:[2,117],47:[2,117],51:[2,117],52:[2,117],54:[2,66],76:[2,117],79:[2,117],83:[2,117],88:[2,117],89:[2,117],90:[2,117],91:[2,66],96:[2,117],100:[2,117],101:[2,117],104:[2,117],106:[2,117],108:[2,117],110:[2,117],119:[2,117],125:[2,117],127:[2,117],128:[2,117],129:[2,117],130:[2,117],131:[2,117]},{6:[1,270],25:[1,271],91:[1,269]},{6:[2,53],7:197,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,25:[2,53],26:[2,53],27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,60:144,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],86:[2,53],88:[1,56],89:[1,57],90:[1,55],91:[2,53],94:272,96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{6:[2,52],25:[2,52],26:[2,52],53:273,54:[1,226]},{1:[2,180],6:[2,180],25:[2,180],26:[2,180],49:[2,180],54:[2,180],57:[2,180],73:[2,180],78:[2,180],86:[2,180],91:[2,180],93:[2,180],102:[2,180],104:[2,180],105:[2,180],106:[2,180],110:[2,180],118:[2,180],121:[2,180],126:[2,180],128:[2,180],129:[2,180],132:[2,180],133:[2,180],134:[2,180],135:[2,180],136:[2,180],137:[2,180]},{7:274,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{7:275,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{116:[2,158],117:[2,158]},{27:155,28:[1,71],44:156,58:157,59:158,76:[1,68],89:[1,109],90:[1,110],115:276},{1:[2,165],6:[2,165],25:[2,165],26:[2,165],49:[2,165],54:[2,165],57:[2,165],73:[2,165],78:[2,165],86:[2,165],91:[2,165],93:[2,165],102:[2,165],103:82,104:[2,165],105:[1,277],106:[2,165],109:83,110:[2,165],111:67,118:[1,278],126:[2,165],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[1,78],136:[1,79],137:[1,80]},{1:[2,166],6:[2,166],25:[2,166],26:[2,166],49:[2,166],54:[2,166],57:[2,166],73:[2,166],78:[2,166],86:[2,166],91:[2,166],93:[2,166],102:[2,166],103:82,104:[2,166],105:[1,279],106:[2,166],109:83,110:[2,166],111:67,118:[2,166],126:[2,166],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[1,78],136:[1,79],137:[1,80]},{6:[1,281],25:[1,282],78:[1,280]},{6:[2,53],10:165,25:[2,53],26:[2,53],27:166,28:[1,71],29:167,30:[1,69],31:[1,70],41:283,42:164,44:168,46:[1,44],78:[2,53],89:[1,109]},{7:284,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,25:[1,285],27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{1:[2,85],6:[2,85],25:[2,85],26:[2,85],40:[2,85],49:[2,85],54:[2,85],57:[2,85],66:[2,85],67:[2,85],68:[2,85],69:[2,85],71:[2,85],73:[2,85],74:[2,85],78:[2,85],80:[2,85],84:[2,85],85:[2,85],86:[2,85],91:[2,85],93:[2,85],102:[2,85],104:[2,85],105:[2,85],106:[2,85],110:[2,85],118:[2,85],126:[2,85],128:[2,85],129:[2,85],130:[2,85],131:[2,85],132:[2,85],133:[2,85],134:[2,85],135:[2,85],136:[2,85],137:[2,85],138:[2,85]},{7:286,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,73:[2,120],76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{73:[2,121],103:82,104:[1,63],106:[1,64],109:83,110:[1,66],111:67,126:[1,81],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[1,78],136:[1,79],137:[1,80]},{1:[2,36],6:[2,36],25:[2,36],26:[2,36],49:[2,36],54:[2,36],57:[2,36],73:[2,36],78:[2,36],86:[2,36],91:[2,36],93:[2,36],102:[2,36],103:82,104:[2,36],105:[2,36],106:[2,36],109:83,110:[2,36],111:67,118:[2,36],126:[2,36],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[1,78],136:[1,79],137:[1,80]},{26:[1,287],103:82,104:[1,63],106:[1,64],109:83,110:[1,66],111:67,126:[1,81],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[1,78],136:[1,79],137:[1,80]},{6:[1,270],25:[1,271],86:[1,288]},{6:[2,66],25:[2,66],26:[2,66],54:[2,66],86:[2,66],91:[2,66]},{24:289,25:[1,112]},{6:[2,56],25:[2,56],26:[2,56],49:[2,56],54:[2,56]},{27:105,28:[1,71],44:106,55:290,56:104,58:107,59:108,76:[1,68],89:[1,109],90:[1,110]},{6:[2,54],25:[2,54],26:[2,54],27:105,28:[1,71],44:106,48:291,54:[2,54],55:103,56:104,58:107,59:108,76:[1,68],89:[1,109],90:[1,110]},{6:[2,61],25:[2,61],26:[2,61],49:[2,61],54:[2,61],103:82,104:[1,63],106:[1,64],109:83,110:[1,66],111:67,126:[1,81],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[1,78],136:[1,79],137:[1,80]},{1:[2,24],6:[2,24],25:[2,24],26:[2,24],49:[2,24],54:[2,24],57:[2,24],73:[2,24],78:[2,24],86:[2,24],91:[2,24],93:[2,24],98:[2,24],99:[2,24],102:[2,24],104:[2,24],105:[2,24],106:[2,24],110:[2,24],118:[2,24],121:[2,24],123:[2,24],126:[2,24],128:[2,24],129:[2,24],132:[2,24],133:[2,24],134:[2,24],135:[2,24],136:[2,24],137:[2,24]},{26:[1,292],103:82,104:[1,63],106:[1,64],109:83,110:[1,66],111:67,126:[1,81],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[1,78],136:[1,79],137:[1,80]},{1:[2,203],6:[2,203],25:[2,203],26:[2,203],49:[2,203],54:[2,203],57:[2,203],73:[2,203],78:[2,203],86:[2,203],91:[2,203],93:[2,203],102:[2,203],103:82,104:[2,203],105:[2,203],106:[2,203],109:83,110:[2,203],111:67,118:[2,203],126:[2,203],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[1,78],136:[1,79],137:[1,80]},{24:293,25:[1,112],103:82,104:[1,63],106:[1,64],109:83,110:[1,66],111:67,126:[1,81],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[1,78],136:[1,79],137:[1,80]},{24:294,25:[1,112]},{1:[2,134],6:[2,134],25:[2,134],26:[2,134],49:[2,134],54:[2,134],57:[2,134],73:[2,134],78:[2,134],86:[2,134],91:[2,134],93:[2,134],102:[2,134],104:[2,134],105:[2,134],106:[2,134],110:[2,134],118:[2,134],126:[2,134],128:[2,134],129:[2,134],132:[2,134],133:[2,134],134:[2,134],135:[2,134],136:[2,134],137:[2,134]},{24:295,25:[1,112]},{24:296,25:[1,112]},{1:[2,138],6:[2,138],25:[2,138],26:[2,138],49:[2,138],54:[2,138],57:[2,138],73:[2,138],78:[2,138],86:[2,138],91:[2,138],93:[2,138],98:[2,138],102:[2,138],104:[2,138],105:[2,138],106:[2,138],110:[2,138],118:[2,138],126:[2,138],128:[2,138],129:[2,138],132:[2,138],133:[2,138],134:[2,138],135:[2,138],136:[2,138],137:[2,138]},{26:[1,297],121:[1,298],122:262,123:[1,217]},{1:[2,174],6:[2,174],25:[2,174],26:[2,174],49:[2,174],54:[2,174],57:[2,174],73:[2,174],78:[2,174],86:[2,174],91:[2,174],93:[2,174],102:[2,174],104:[2,174],105:[2,174],106:[2,174],110:[2,174],118:[2,174],126:[2,174],128:[2,174],129:[2,174],132:[2,174],133:[2,174],134:[2,174],135:[2,174],136:[2,174],137:[2,174]},{24:299,25:[1,112]},{26:[2,177],121:[2,177],123:[2,177]},{24:300,25:[1,112],54:[1,301]},{25:[2,130],54:[2,130],103:82,104:[1,63],106:[1,64],109:83,110:[1,66],111:67,126:[1,81],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[1,78],136:[1,79],137:[1,80]},{1:[2,98],6:[2,98],25:[2,98],26:[2,98],49:[2,98],54:[2,98],57:[2,98],73:[2,98],78:[2,98],86:[2,98],91:[2,98],93:[2,98],102:[2,98],104:[2,98],105:[2,98],106:[2,98],110:[2,98],118:[2,98],126:[2,98],128:[2,98],129:[2,98],132:[2,98],133:[2,98],134:[2,98],135:[2,98],136:[2,98],137:[2,98]},{1:[2,101],6:[2,101],24:302,25:[1,112],26:[2,101],49:[2,101],54:[2,101],57:[2,101],73:[2,101],78:[2,101],86:[2,101],91:[2,101],93:[2,101],102:[2,101],103:82,104:[1,63],105:[2,101],106:[1,64],109:83,110:[1,66],111:67,118:[2,101],126:[2,101],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[1,78],136:[1,79],137:[1,80]},{102:[1,303]},{91:[1,304],103:82,104:[1,63],106:[1,64],109:83,110:[1,66],111:67,126:[1,81],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[1,78],136:[1,79],137:[1,80]},{1:[2,115],6:[2,115],25:[2,115],26:[2,115],40:[2,115],49:[2,115],54:[2,115],57:[2,115],66:[2,115],67:[2,115],68:[2,115],69:[2,115],71:[2,115],73:[2,115],74:[2,115],78:[2,115],84:[2,115],85:[2,115],86:[2,115],91:[2,115],93:[2,115],102:[2,115],104:[2,115],105:[2,115],106:[2,115],110:[2,115],116:[2,115],117:[2,115],118:[2,115],126:[2,115],128:[2,115],129:[2,115],132:[2,115],133:[2,115],134:[2,115],135:[2,115],136:[2,115],137:[2,115]},{7:197,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,60:144,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],94:305,96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{7:197,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,25:[1,143],27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,60:144,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],87:306,88:[1,56],89:[1,57],90:[1,55],94:142,96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{6:[2,124],25:[2,124],26:[2,124],54:[2,124],86:[2,124],91:[2,124]},{6:[1,270],25:[1,271],26:[1,307]},{1:[2,143],6:[2,143],25:[2,143],26:[2,143],49:[2,143],54:[2,143],57:[2,143],73:[2,143],78:[2,143],86:[2,143],91:[2,143],93:[2,143],102:[2,143],103:82,104:[1,63],105:[2,143],106:[1,64],109:83,110:[1,66],111:67,118:[2,143],126:[2,143],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[1,78],136:[1,79],137:[1,80]},{1:[2,145],6:[2,145],25:[2,145],26:[2,145],49:[2,145],54:[2,145],57:[2,145],73:[2,145],78:[2,145],86:[2,145],91:[2,145],93:[2,145],102:[2,145],103:82,104:[1,63],105:[2,145],106:[1,64],109:83,110:[1,66],111:67,118:[2,145],126:[2,145],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[1,78],136:[1,79],137:[1,80]},{116:[2,164],117:[2,164]},{7:308,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{7:309,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{7:310,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{1:[2,89],6:[2,89],25:[2,89],26:[2,89],40:[2,89],49:[2,89],54:[2,89],57:[2,89],66:[2,89],67:[2,89],68:[2,89],69:[2,89],71:[2,89],73:[2,89],74:[2,89],78:[2,89],84:[2,89],85:[2,89],86:[2,89],91:[2,89],93:[2,89],102:[2,89],104:[2,89],105:[2,89],106:[2,89],110:[2,89],116:[2,89],117:[2,89],118:[2,89],126:[2,89],128:[2,89],129:[2,89],132:[2,89],133:[2,89],134:[2,89],135:[2,89],136:[2,89],137:[2,89]},{10:165,27:166,28:[1,71],29:167,30:[1,69],31:[1,70],41:311,42:164,44:168,46:[1,44],89:[1,109]},{6:[2,90],10:165,25:[2,90],26:[2,90],27:166,28:[1,71],29:167,30:[1,69],31:[1,70],41:163,42:164,44:168,46:[1,44],54:[2,90],77:312,89:[1,109]},{6:[2,92],25:[2,92],26:[2,92],54:[2,92],78:[2,92]},{6:[2,39],25:[2,39],26:[2,39],54:[2,39],78:[2,39],103:82,104:[1,63],106:[1,64],109:83,110:[1,66],111:67,126:[1,81],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[1,78],136:[1,79],137:[1,80]},{7:313,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{73:[2,119],103:82,104:[1,63],106:[1,64],109:83,110:[1,66],111:67,126:[1,81],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[1,78],136:[1,79],137:[1,80]},{1:[2,37],6:[2,37],25:[2,37],26:[2,37],49:[2,37],54:[2,37],57:[2,37],73:[2,37],78:[2,37],86:[2,37],91:[2,37],93:[2,37],102:[2,37],104:[2,37],105:[2,37],106:[2,37],110:[2,37],118:[2,37],126:[2,37],128:[2,37],129:[2,37],132:[2,37],133:[2,37],134:[2,37],135:[2,37],136:[2,37],137:[2,37]},{1:[2,110],6:[2,110],25:[2,110],26:[2,110],49:[2,110],54:[2,110],57:[2,110],66:[2,110],67:[2,110],68:[2,110],69:[2,110],71:[2,110],73:[2,110],74:[2,110],78:[2,110],84:[2,110],85:[2,110],86:[2,110],91:[2,110],93:[2,110],102:[2,110],104:[2,110],105:[2,110],106:[2,110],110:[2,110],118:[2,110],126:[2,110],128:[2,110],129:[2,110],132:[2,110],133:[2,110],134:[2,110],135:[2,110],136:[2,110],137:[2,110]},{1:[2,48],6:[2,48],25:[2,48],26:[2,48],49:[2,48],54:[2,48],57:[2,48],73:[2,48],78:[2,48],86:[2,48],91:[2,48],93:[2,48],102:[2,48],104:[2,48],105:[2,48],106:[2,48],110:[2,48],118:[2,48],126:[2,48],128:[2,48],129:[2,48],132:[2,48],133:[2,48],134:[2,48],135:[2,48],136:[2,48],137:[2,48]},{6:[2,57],25:[2,57],26:[2,57],49:[2,57],54:[2,57]},{6:[2,52],25:[2,52],26:[2,52],53:314,54:[1,199]},{1:[2,202],6:[2,202],25:[2,202],26:[2,202],49:[2,202],54:[2,202],57:[2,202],73:[2,202],78:[2,202],86:[2,202],91:[2,202],93:[2,202],102:[2,202],104:[2,202],105:[2,202],106:[2,202],110:[2,202],118:[2,202],126:[2,202],128:[2,202],129:[2,202],132:[2,202],133:[2,202],134:[2,202],135:[2,202],136:[2,202],137:[2,202]},{1:[2,181],6:[2,181],25:[2,181],26:[2,181],49:[2,181],54:[2,181],57:[2,181],73:[2,181],78:[2,181],86:[2,181],91:[2,181],93:[2,181],102:[2,181],104:[2,181],105:[2,181],106:[2,181],110:[2,181],118:[2,181],121:[2,181],126:[2,181],128:[2,181],129:[2,181],132:[2,181],133:[2,181],134:[2,181],135:[2,181],136:[2,181],137:[2,181]},{1:[2,135],6:[2,135],25:[2,135],26:[2,135],49:[2,135],54:[2,135],57:[2,135],73:[2,135],78:[2,135],86:[2,135],91:[2,135],93:[2,135],102:[2,135],104:[2,135],105:[2,135],106:[2,135],110:[2,135],118:[2,135],126:[2,135],128:[2,135],129:[2,135],132:[2,135],133:[2,135],134:[2,135],135:[2,135],136:[2,135],137:[2,135]},{1:[2,136],6:[2,136],25:[2,136],26:[2,136],49:[2,136],54:[2,136],57:[2,136],73:[2,136],78:[2,136],86:[2,136],91:[2,136],93:[2,136],98:[2,136],102:[2,136],104:[2,136],105:[2,136],106:[2,136],110:[2,136],118:[2,136],126:[2,136],128:[2,136],129:[2,136],132:[2,136],133:[2,136],134:[2,136],135:[2,136],136:[2,136],137:[2,136]},{1:[2,137],6:[2,137],25:[2,137],26:[2,137],49:[2,137],54:[2,137],57:[2,137],73:[2,137],78:[2,137],86:[2,137],91:[2,137],93:[2,137],98:[2,137],102:[2,137],104:[2,137],105:[2,137],106:[2,137],110:[2,137],118:[2,137],126:[2,137],128:[2,137],129:[2,137],132:[2,137],133:[2,137],134:[2,137],135:[2,137],136:[2,137],137:[2,137]},{1:[2,172],6:[2,172],25:[2,172],26:[2,172],49:[2,172],54:[2,172],57:[2,172],73:[2,172],78:[2,172],86:[2,172],91:[2,172],93:[2,172],102:[2,172],104:[2,172],105:[2,172],106:[2,172],110:[2,172],118:[2,172],126:[2,172],128:[2,172],129:[2,172],132:[2,172],133:[2,172],134:[2,172],135:[2,172],136:[2,172],137:[2,172]},{24:315,25:[1,112]},{26:[1,316]},{6:[1,317],26:[2,178],121:[2,178],123:[2,178]},{7:318,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{1:[2,102],6:[2,102],25:[2,102],26:[2,102],49:[2,102],54:[2,102],57:[2,102],73:[2,102],78:[2,102],86:[2,102],91:[2,102],93:[2,102],102:[2,102],104:[2,102],105:[2,102],106:[2,102],110:[2,102],118:[2,102],126:[2,102],128:[2,102],129:[2,102],132:[2,102],133:[2,102],134:[2,102],135:[2,102],136:[2,102],137:[2,102]},{1:[2,141],6:[2,141],25:[2,141],26:[2,141],49:[2,141],54:[2,141],57:[2,141],66:[2,141],67:[2,141],68:[2,141],69:[2,141],71:[2,141],73:[2,141],74:[2,141],78:[2,141],84:[2,141],85:[2,141],86:[2,141],91:[2,141],93:[2,141],102:[2,141],104:[2,141],105:[2,141],106:[2,141],110:[2,141],118:[2,141],126:[2,141],128:[2,141],129:[2,141],132:[2,141],133:[2,141],134:[2,141],135:[2,141],136:[2,141],137:[2,141]},{1:[2,118],6:[2,118],25:[2,118],26:[2,118],49:[2,118],54:[2,118],57:[2,118],66:[2,118],67:[2,118],68:[2,118],69:[2,118],71:[2,118],73:[2,118],74:[2,118],78:[2,118],84:[2,118],85:[2,118],86:[2,118],91:[2,118],93:[2,118],102:[2,118],104:[2,118],105:[2,118],106:[2,118],110:[2,118],118:[2,118],126:[2,118],128:[2,118],129:[2,118],132:[2,118],133:[2,118],134:[2,118],135:[2,118],136:[2,118],137:[2,118]},{6:[2,125],25:[2,125],26:[2,125],54:[2,125],86:[2,125],91:[2,125]},{6:[2,52],25:[2,52],26:[2,52],53:319,54:[1,226]},{6:[2,126],25:[2,126],26:[2,126],54:[2,126],86:[2,126],91:[2,126]},{1:[2,167],6:[2,167],25:[2,167],26:[2,167],49:[2,167],54:[2,167],57:[2,167],73:[2,167],78:[2,167],86:[2,167],91:[2,167],93:[2,167],102:[2,167],103:82,104:[2,167],105:[2,167],106:[2,167],109:83,110:[2,167],111:67,118:[1,320],126:[2,167],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[1,78],136:[1,79],137:[1,80]},{1:[2,169],6:[2,169],25:[2,169],26:[2,169],49:[2,169],54:[2,169],57:[2,169],73:[2,169],78:[2,169],86:[2,169],91:[2,169],93:[2,169],102:[2,169],103:82,104:[2,169],105:[1,321],106:[2,169],109:83,110:[2,169],111:67,118:[2,169],126:[2,169],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[1,78],136:[1,79],137:[1,80]},{1:[2,168],6:[2,168],25:[2,168],26:[2,168],49:[2,168],54:[2,168],57:[2,168],73:[2,168],78:[2,168],86:[2,168],91:[2,168],93:[2,168],102:[2,168],103:82,104:[2,168],105:[2,168],106:[2,168],109:83,110:[2,168],111:67,118:[2,168],126:[2,168],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[1,78],136:[1,79],137:[1,80]},{6:[2,93],25:[2,93],26:[2,93],54:[2,93],78:[2,93]},{6:[2,52],25:[2,52],26:[2,52],53:322,54:[1,236]},{26:[1,323],103:82,104:[1,63],106:[1,64],109:83,110:[1,66],111:67,126:[1,81],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[1,78],136:[1,79],137:[1,80]},{6:[1,247],25:[1,248],26:[1,324]},{26:[1,325]},{1:[2,175],6:[2,175],25:[2,175],26:[2,175],49:[2,175],54:[2,175],57:[2,175],73:[2,175],78:[2,175],86:[2,175],91:[2,175],93:[2,175],102:[2,175],104:[2,175],105:[2,175],106:[2,175],110:[2,175],118:[2,175],126:[2,175],128:[2,175],129:[2,175],132:[2,175],133:[2,175],134:[2,175],135:[2,175],136:[2,175],137:[2,175]},{26:[2,179],121:[2,179],123:[2,179]},{25:[2,131],54:[2,131],103:82,104:[1,63],106:[1,64],109:83,110:[1,66],111:67,126:[1,81],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[1,78],136:[1,79],137:[1,80]},{6:[1,270],25:[1,271],26:[1,326]},{7:327,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{7:328,8:114,9:18,10:19,11:[1,20],12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:60,28:[1,71],29:47,30:[1,69],31:[1,70],32:22,33:[1,48],34:[1,49],35:[1,50],36:[1,51],37:[1,52],38:[1,53],39:21,44:61,45:[1,43],46:[1,44],47:[1,27],50:28,51:[1,58],52:[1,59],58:45,59:46,61:34,63:23,64:24,65:25,76:[1,68],79:[1,41],83:[1,26],88:[1,56],89:[1,57],90:[1,55],96:[1,36],100:[1,42],101:[1,54],103:37,104:[1,63],106:[1,64],107:38,108:[1,65],109:39,110:[1,66],111:67,119:[1,40],124:35,125:[1,62],127:[1,29],128:[1,30],129:[1,31],130:[1,32],131:[1,33]},{6:[1,281],25:[1,282],26:[1,329]},{6:[2,40],25:[2,40],26:[2,40],54:[2,40],78:[2,40]},{6:[2,58],25:[2,58],26:[2,58],49:[2,58],54:[2,58]},{1:[2,173],6:[2,173],25:[2,173],26:[2,173],49:[2,173],54:[2,173],57:[2,173],73:[2,173],78:[2,173],86:[2,173],91:[2,173],93:[2,173],102:[2,173],104:[2,173],105:[2,173],106:[2,173],110:[2,173],118:[2,173],126:[2,173],128:[2,173],129:[2,173],132:[2,173],133:[2,173],134:[2,173],135:[2,173],136:[2,173],137:[2,173]},{6:[2,127],25:[2,127],26:[2,127],54:[2,127],86:[2,127],91:[2,127]},{1:[2,170],6:[2,170],25:[2,170],26:[2,170],49:[2,170],54:[2,170],57:[2,170],73:[2,170],78:[2,170],86:[2,170],91:[2,170],93:[2,170],102:[2,170],103:82,104:[2,170],105:[2,170],106:[2,170],109:83,110:[2,170],111:67,118:[2,170],126:[2,170],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[1,78],136:[1,79],137:[1,80]},{1:[2,171],6:[2,171],25:[2,171],26:[2,171],49:[2,171],54:[2,171],57:[2,171],73:[2,171],78:[2,171],86:[2,171],91:[2,171],93:[2,171],102:[2,171],103:82,104:[2,171],105:[2,171],106:[2,171],109:83,110:[2,171],111:67,118:[2,171],126:[2,171],128:[1,75],129:[1,74],132:[1,73],133:[1,76],134:[1,77],135:[1,78],136:[1,79],137:[1,80]},{6:[2,94],25:[2,94],26:[2,94],54:[2,94],78:[2,94]}], +defaultActions: {58:[2,50],59:[2,51],89:[2,108],186:[2,88]}, +parseError: function parseError(str, hash) { + if (hash.recoverable) { + this.trace(str); + } else { + // ace_mod + var e = new Error(str) + e.location = hash.loc + throw e; + } +}, +parse: function parse(input) { + var self = this, stack = [0], vstack = [null], lstack = [], table = this.table, yytext = '', yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1; + this.lexer.setInput(input); + this.lexer.yy = this.yy; + this.yy.lexer = this.lexer; + this.yy.parser = this; + if (typeof this.lexer.yylloc == 'undefined') { + this.lexer.yylloc = {}; + } + var yyloc = this.lexer.yylloc; + lstack.push(yyloc); + var ranges = this.lexer.options && this.lexer.options.ranges; + if (typeof this.yy.parseError === 'function') { + this.parseError = this.yy.parseError; + } else { + this.parseError = Object.getPrototypeOf(this).parseError; + } + function popStack(n) { + stack.length = stack.length - 2 * n; + vstack.length = vstack.length - n; + lstack.length = lstack.length - n; + } + function lex() { + var token; + token = self.lexer.lex() || EOF; + if (typeof token !== 'number') { + token = self.symbols_[token] || token; + } + return token; + } + var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected; + while (true) { + state = stack[stack.length - 1]; + if (this.defaultActions[state]) { + action = this.defaultActions[state]; + } else { + if (symbol === null || typeof symbol == 'undefined') { + symbol = lex(); + } + action = table[state] && table[state][symbol]; + } + if (typeof action === 'undefined' || !action.length || !action[0]) { + var errStr = ''; + expected = []; + for (p in table[state]) { + if (this.terminals_[p] && p > TERROR) { + expected.push('\'' + this.terminals_[p] + '\''); + } + } + if (this.lexer.showPosition) { + errStr = 'Expecting ' + expected.join(', ') + ', got \'' + (this.terminals_[symbol] || symbol) + '\''; + } else { + errStr = 'Unexpected ' + (symbol == EOF ? 'end of input' : '\'' + (this.terminals_[symbol] || symbol) + '\''); + } + // ace_mod + if (this.lexer.yylloc.first_line !== yyloc.first_line) yyloc = this.lexer.yylloc; + this.parseError(errStr, { + text: this.lexer.match, + token: this.terminals_[symbol] || symbol, + line: this.lexer.yylineno, + loc: yyloc, + expected: expected + }); + } + if (action[0] instanceof Array && action.length > 1) { + throw new Error('Parse Error: multiple actions possible at state: ' + state + ', token: ' + symbol); + } + switch (action[0]) { + case 1: + stack.push(symbol); + vstack.push(this.lexer.yytext); + lstack.push(this.lexer.yylloc); + stack.push(action[1]); + symbol = null; + if (!preErrorSymbol) { + yyleng = this.lexer.yyleng; + yytext = this.lexer.yytext; + yylineno = this.lexer.yylineno; + yyloc = this.lexer.yylloc; + if (recovering > 0) { + recovering--; + } + } else { + symbol = preErrorSymbol; + preErrorSymbol = null; + } + break; + case 2: + len = this.productions_[action[1]][1]; + yyval.$ = vstack[vstack.length - len]; + yyval._$ = { + first_line: lstack[lstack.length - (len || 1)].first_line, + last_line: lstack[lstack.length - 1].last_line, + first_column: lstack[lstack.length - (len || 1)].first_column, + last_column: lstack[lstack.length - 1].last_column + }; + if (ranges) { + yyval._$.range = [ + lstack[lstack.length - (len || 1)].range[0], + lstack[lstack.length - 1].range[1] + ]; + } + r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack); + if (typeof r !== 'undefined') { + return r; + } + if (len) { + stack = stack.slice(0, -1 * len * 2); + vstack = vstack.slice(0, -1 * len); + lstack = lstack.slice(0, -1 * len); + } + stack.push(this.productions_[action[1]][0]); + vstack.push(yyval.$); + lstack.push(yyval._$); + newState = table[stack[stack.length - 2]][stack[stack.length - 1]]; + stack.push(newState); + break; + case 3: + return true; + } + } + return true; +}}; +undefined +function Parser () { + this.yy = {}; +} +Parser.prototype = parser;parser.Parser = Parser; + +module.exports = new Parser; + + +}); \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/coffee/parser_test.js b/node_modules/ace/lib/ace/mode/coffee/parser_test.js new file mode 100644 index 00000000..001262b6 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/coffee/parser_test.js @@ -0,0 +1,88 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +if (typeof process !== "undefined") { + require("amd-loader"); +} + +define(function(require, exports, module) { +"use strict"; + +var assert = require("../../test/assertions"); +var coffee = require("../coffee/coffee-script"); + +function assertLocation(e, sl, sc, el, ec) { + assert.equal(e.location.first_line, sl); + assert.equal(e.location.first_column, sc); + assert.equal(e.location.last_line, el); + assert.equal(e.location.last_column, ec); +} + +function parse(str) { + try { + coffee.parse(str).compile(); + } catch (e) { + return e; + } +} + +module.exports = { + "test parse valid coffee script": function() { + coffee.parse("square = (x) -> x * x"); + }, + + "test parse invalid coffee script": function() { + var e = parse("a = 12 f"); + assert.equal(e.message, "Unexpected 'IDENTIFIER'"); + assertLocation(e, 0, 4, 0, 5); + }, + + "test parse missing bracket": function() { + var e = parse("a = 12 f {\n\n"); + assert.equal(e.message, "missing }"); + assertLocation(e, 0, 10, 0, 10); + }, + "test unexpected indent": function() { + var e = parse("a\n a\n"); + assert.equal(e.message, "Unexpected 'INDENT'"); + assertLocation(e, 1, 0, 1, 1); + }, + "test invalid destructuring": function() { + var e = parse("\n{b: 5} = {}"); + assert.equal(e.message, '"5" cannot be assigned'); + assertLocation(e, 1, 4, 1, 4); + } +}; + +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec(); +} diff --git a/node_modules/ace/lib/ace/mode/coffee/rewriter.js b/node_modules/ace/lib/ace/mode/coffee/rewriter.js new file mode 100644 index 00000000..acb5c420 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/coffee/rewriter.js @@ -0,0 +1,516 @@ +/** + * Copyright (c) 2009-2013 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. + * + */ + +define(function(require, exports, module) { +// Generated by CoffeeScript 1.6.3 + + var BALANCED_PAIRS, CALL_CLOSERS, EXPRESSION_CLOSE, EXPRESSION_END, EXPRESSION_START, IMPLICIT_CALL, IMPLICIT_END, IMPLICIT_FUNC, IMPLICIT_UNSPACED_CALL, INVERSES, LINEBREAKS, SINGLE_CLOSERS, SINGLE_LINERS, generate, 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; + + generate = function(tag, value) { + var tok; + tok = [tag, value]; + tok.generated = true; + return tok; + }; + + exports.Rewriter = (function() { + function Rewriter() {} + + Rewriter.prototype.rewrite = function(tokens) { + this.tokens = tokens; + this.removeLeadingNewlines(); + this.closeOpenCalls(); + this.closeOpenIndexes(); + this.normalizeLines(); + this.tagPostfixConditionals(); + this.addImplicitBracesAndParens(); + this.addLocationDataToGeneratedTokens(); + 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.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.matchTags = function() { + var fuzz, i, j, pattern, _i, _ref, _ref1; + i = arguments[0], pattern = 2 <= arguments.length ? __slice.call(arguments, 1) : []; + fuzz = 0; + for (j = _i = 0, _ref = pattern.length; 0 <= _ref ? _i < _ref : _i > _ref; j = 0 <= _ref ? ++_i : --_i) { + while (this.tag(i + j + fuzz) === 'HERECOMMENT') { + fuzz += 2; + } + if (pattern[j] == null) { + continue; + } + if (typeof pattern[j] === 'string') { + pattern[j] = [pattern[j]]; + } + if (_ref1 = this.tag(i + j + fuzz), __indexOf.call(pattern[j], _ref1) < 0) { + return false; + } + } + return true; + }; + + Rewriter.prototype.looksObjectish = function(j) { + return this.matchTags(j, '@', null, ':') || this.matchTags(j, null, ':'); + }; + + Rewriter.prototype.findTagsBackwards = function(i, tags) { + var backStack, _ref, _ref1, _ref2, _ref3, _ref4, _ref5; + backStack = []; + while (i >= 0 && (backStack.length || (_ref2 = this.tag(i), __indexOf.call(tags, _ref2) < 0) && ((_ref3 = this.tag(i), __indexOf.call(EXPRESSION_START, _ref3) < 0) || this.tokens[i].generated) && (_ref4 = this.tag(i), __indexOf.call(LINEBREAKS, _ref4) < 0))) { + if (_ref = this.tag(i), __indexOf.call(EXPRESSION_END, _ref) >= 0) { + backStack.push(this.tag(i)); + } + if ((_ref1 = this.tag(i), __indexOf.call(EXPRESSION_START, _ref1) >= 0) && backStack.length) { + backStack.pop(); + } + i -= 1; + } + return _ref5 = this.tag(i), __indexOf.call(tags, _ref5) >= 0; + }; + + Rewriter.prototype.addImplicitBracesAndParens = function() { + var stack; + stack = []; + return this.scanTokens(function(token, i, tokens) { + var endAllImplicitCalls, endImplicitCall, endImplicitObject, forward, inImplicit, inImplicitCall, inImplicitControl, inImplicitObject, nextTag, offset, prevTag, prevToken, s, sameLine, stackIdx, stackTag, stackTop, startIdx, startImplicitCall, startImplicitObject, startsLine, tag, _ref, _ref1, _ref2, _ref3, _ref4, _ref5; + tag = token[0]; + prevTag = (prevToken = i > 0 ? tokens[i - 1] : [])[0]; + nextTag = (i < tokens.length - 1 ? tokens[i + 1] : [])[0]; + stackTop = function() { + return stack[stack.length - 1]; + }; + startIdx = i; + forward = function(n) { + return i - startIdx + n; + }; + inImplicit = function() { + var _ref, _ref1; + return (_ref = stackTop()) != null ? (_ref1 = _ref[2]) != null ? _ref1.ours : void 0 : void 0; + }; + inImplicitCall = function() { + var _ref; + return inImplicit() && ((_ref = stackTop()) != null ? _ref[0] : void 0) === '('; + }; + inImplicitObject = function() { + var _ref; + return inImplicit() && ((_ref = stackTop()) != null ? _ref[0] : void 0) === '{'; + }; + inImplicitControl = function() { + var _ref; + return inImplicit && ((_ref = stackTop()) != null ? _ref[0] : void 0) === 'CONTROL'; + }; + startImplicitCall = function(j) { + var idx; + idx = j != null ? j : i; + stack.push([ + '(', idx, { + ours: true + } + ]); + tokens.splice(idx, 0, generate('CALL_START', '(')); + if (j == null) { + return i += 1; + } + }; + endImplicitCall = function() { + stack.pop(); + tokens.splice(i, 0, generate('CALL_END', ')')); + return i += 1; + }; + endAllImplicitCalls = function() { + while (inImplicitCall()) { + endImplicitCall(); + } + }; + startImplicitObject = function(j, startsLine) { + var idx; + if (startsLine == null) { + startsLine = true; + } + idx = j != null ? j : i; + stack.push([ + '{', idx, { + sameLine: true, + startsLine: startsLine, + ours: true + } + ]); + tokens.splice(idx, 0, generate('{', generate(new String('{')))); + if (j == null) { + return i += 1; + } + }; + endImplicitObject = function(j) { + j = j != null ? j : i; + stack.pop(); + tokens.splice(j, 0, generate('}', '}')); + return i += 1; + }; + if (inImplicitCall() && (tag === 'IF' || tag === 'TRY' || tag === 'FINALLY' || tag === 'CATCH' || tag === 'CLASS' || tag === 'SWITCH')) { + stack.push([ + 'CONTROL', i, { + ours: true + } + ]); + return forward(1); + } + if (tag === 'INDENT' && inImplicit()) { + if (prevTag !== '=>' && prevTag !== '->' && prevTag !== '[' && prevTag !== '(' && prevTag !== ',' && prevTag !== '{' && prevTag !== 'TRY' && prevTag !== 'ELSE' && prevTag !== '=') { + while (inImplicitCall()) { + endImplicitCall(); + } + } + if (inImplicitControl()) { + stack.pop(); + } + stack.push([tag, i]); + return forward(1); + } + if (__indexOf.call(EXPRESSION_START, tag) >= 0) { + stack.push([tag, i]); + return forward(1); + } + if (__indexOf.call(EXPRESSION_END, tag) >= 0) { + while (inImplicit()) { + if (inImplicitCall()) { + endImplicitCall(); + } else if (inImplicitObject()) { + endImplicitObject(); + } else { + stack.pop(); + } + } + stack.pop(); + } + if ((__indexOf.call(IMPLICIT_FUNC, tag) >= 0 && token.spaced && !token.stringEnd || tag === '?' && i > 0 && !tokens[i - 1].spaced) && (__indexOf.call(IMPLICIT_CALL, nextTag) >= 0 || __indexOf.call(IMPLICIT_UNSPACED_CALL, nextTag) >= 0 && !((_ref = tokens[i + 1]) != null ? _ref.spaced : void 0) && !((_ref1 = tokens[i + 1]) != null ? _ref1.newLine : void 0))) { + if (tag === '?') { + tag = token[0] = 'FUNC_EXIST'; + } + startImplicitCall(i + 1); + return forward(2); + } + if (__indexOf.call(IMPLICIT_FUNC, tag) >= 0 && this.matchTags(i + 1, 'INDENT', null, ':') && !this.findTagsBackwards(i, ['CLASS', 'EXTENDS', 'IF', 'CATCH', 'SWITCH', 'LEADING_WHEN', 'FOR', 'WHILE', 'UNTIL'])) { + startImplicitCall(i + 1); + stack.push(['INDENT', i + 2]); + return forward(3); + } + if (tag === ':') { + if (this.tag(i - 2) === '@') { + s = i - 2; + } else { + s = i - 1; + } + while (this.tag(s - 2) === 'HERECOMMENT') { + s -= 2; + } + startsLine = s === 0 || (_ref2 = this.tag(s - 1), __indexOf.call(LINEBREAKS, _ref2) >= 0) || tokens[s - 1].newLine; + if (stackTop()) { + _ref3 = stackTop(), stackTag = _ref3[0], stackIdx = _ref3[1]; + if ((stackTag === '{' || stackTag === 'INDENT' && this.tag(stackIdx - 1) === '{') && (startsLine || this.tag(s - 1) === ',' || this.tag(s - 1) === '{')) { + return forward(1); + } + } + startImplicitObject(s, !!startsLine); + return forward(2); + } + if (inImplicitCall() && __indexOf.call(CALL_CLOSERS, tag) >= 0) { + if (prevTag === 'OUTDENT') { + endImplicitCall(); + return forward(1); + } + if (prevToken.newLine) { + endAllImplicitCalls(); + return forward(1); + } + } + if (inImplicitObject() && __indexOf.call(LINEBREAKS, tag) >= 0) { + stackTop()[2].sameLine = false; + } + if (__indexOf.call(IMPLICIT_END, tag) >= 0) { + while (inImplicit()) { + _ref4 = stackTop(), stackTag = _ref4[0], stackIdx = _ref4[1], (_ref5 = _ref4[2], sameLine = _ref5.sameLine, startsLine = _ref5.startsLine); + if (inImplicitCall() && prevTag !== ',') { + endImplicitCall(); + } else if (inImplicitObject() && sameLine && !startsLine) { + endImplicitObject(); + } else if (inImplicitObject() && tag === 'TERMINATOR' && prevTag !== ',' && !(startsLine && this.looksObjectish(i + 1))) { + endImplicitObject(); + } else { + break; + } + } + } + if (tag === ',' && !this.looksObjectish(i + 1) && inImplicitObject() && (nextTag !== 'TERMINATOR' || !this.looksObjectish(i + 2))) { + offset = nextTag === 'OUTDENT' ? 1 : 0; + while (inImplicitObject()) { + endImplicitObject(i + offset); + } + } + return forward(1); + }); + }; + + Rewriter.prototype.addLocationDataToGeneratedTokens = function() { + return this.scanTokens(function(token, i, tokens) { + var column, line, nextLocation, prevLocation, _ref, _ref1; + if (token[2]) { + return 1; + } + if (!(token.generated || token.explicit)) { + return 1; + } + if (token[0] === '{' && (nextLocation = (_ref = tokens[i + 1]) != null ? _ref[2] : void 0)) { + line = nextLocation.first_line, column = nextLocation.first_column; + } else if (prevLocation = (_ref1 = tokens[i - 1]) != null ? _ref1[2] : void 0) { + line = prevLocation.last_line, column = prevLocation.last_column; + } else { + line = column = 0; + } + token[2] = { + first_line: line, + first_column: column, + last_line: line, + last_column: column + }; + return 1; + }); + }; + + Rewriter.prototype.normalizeLines = function() { + var action, condition, indent, outdent, starter; + starter = indent = outdent = null; + condition = function(token, i) { + var _ref, _ref1, _ref2, _ref3; + return token[1] !== ';' && (_ref = token[0], __indexOf.call(SINGLE_CLOSERS, _ref) >= 0) && !(token[0] === 'TERMINATOR' && (_ref1 = this.tag(i + 1), __indexOf.call(EXPRESSION_CLOSE, _ref1) >= 0)) && !(token[0] === 'ELSE' && starter !== 'THEN') && !(((_ref2 = token[0]) === 'CATCH' || _ref2 === 'FINALLY') && (starter === '->' || starter === '=>')) || (_ref3 = token[0], __indexOf.call(CALL_CLOSERS, _ref3) >= 0) && this.tokens[i - 1].newLine; + }; + 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 j, tag, _i, _ref, _ref1, _ref2; + tag = token[0]; + if (tag === 'TERMINATOR') { + if (this.tag(i + 1) === 'ELSE' && this.tag(i - 1) !== 'OUTDENT') { + tokens.splice.apply(tokens, [i, 1].concat(__slice.call(this.indentation()))); + return 1; + } + if (_ref = this.tag(i + 1), __indexOf.call(EXPRESSION_CLOSE, _ref) >= 0) { + tokens.splice(i, 1); + return 0; + } + } + if (tag === 'CATCH') { + for (j = _i = 1; _i <= 2; j = ++_i) { + if (!((_ref1 = this.tag(i + j)) === 'OUTDENT' || _ref1 === 'TERMINATOR' || _ref1 === 'FINALLY')) { + continue; + } + tokens.splice.apply(tokens, [i + j, 0].concat(__slice.call(this.indentation()))); + return 2 + j; + } + } + if (__indexOf.call(SINGLE_LINERS, tag) >= 0 && this.tag(i + 1) !== 'INDENT' && !(tag === 'ELSE' && this.tag(i + 1) === 'IF')) { + starter = tag; + _ref2 = this.indentation(true), indent = _ref2[0], outdent = _ref2[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 prevTag, tag; + tag = token[0]; + prevTag = this.tokens[i - 1][0]; + return tag === 'TERMINATOR' || (tag === 'INDENT' && __indexOf.call(SINGLE_LINERS, prevTag) < 0); + }; + 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(implicit) { + var indent, outdent; + if (implicit == null) { + implicit = false; + } + indent = ['INDENT', 2]; + outdent = ['OUTDENT', 2]; + if (implicit) { + indent.generated = outdent.generated = true; + } + if (!implicit) { + indent.explicit = outdent.explicit = true; + } + return [indent, outdent]; + }; + + Rewriter.prototype.generate = generate; + + 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', 'THEN', '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', 'THROW', '@', '->', '=>', '[', '(', '{', '--', '++']; + + IMPLICIT_UNSPACED_CALL = ['+', '-']; + + 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_CLOSERS = ['.', '?.', '::', '?::']; + + +}); \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/coffee/scope.js b/node_modules/ace/lib/ace/mode/coffee/scope.js new file mode 100644 index 00000000..5834963b --- /dev/null +++ b/node_modules/ace/lib/ace/mode/coffee/scope.js @@ -0,0 +1,174 @@ +/** + * Copyright (c) 2009-2013 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. + * + */ + +define(function(require, exports, module) { +// Generated by CoffeeScript 1.6.3 + + 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() { + var _ref1; + if (((_ref1 = this.method) != null ? _ref1.name : void 0) || !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; + + })(); + + +}); \ No newline at end of file diff --git a/node_modules/ace/lib/ace/mode/coffee_highlight_rules.js b/node_modules/ace/lib/ace/mode/coffee_highlight_rules.js new file mode 100644 index 00000000..94c9476f --- /dev/null +++ b/node_modules/ace/lib/ace/mode/coffee_highlight_rules.js @@ -0,0 +1,233 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + + var oop = require("../lib/oop"); + var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + + oop.inherits(CoffeeHighlightRules, TextHighlightRules); + + function CoffeeHighlightRules() { + var identifier = "[$A-Za-z_\\x7f-\\uffff][$\\w\\x7f-\\uffff]*"; + + var keywords = ( + "this|throw|then|try|typeof|super|switch|return|break|by|continue|" + + "catch|class|in|instanceof|is|isnt|if|else|extends|for|own|" + + "finally|function|while|when|new|no|not|delete|debugger|do|loop|of|off|" + + "or|on|unless|until|and|yes" + ); + + var langConstant = ( + "true|false|null|undefined|NaN|Infinity" + ); + + var illegal = ( + "case|const|default|function|var|void|with|enum|export|implements|" + + "interface|let|package|private|protected|public|static|yield|" + + "__hasProp|slice|bind|indexOf" + ); + + var supportClass = ( + "Array|Boolean|Date|Function|Number|Object|RegExp|ReferenceError|String|" + + "Error|EvalError|InternalError|RangeError|ReferenceError|StopIteration|" + + "SyntaxError|TypeError|URIError|" + + "ArrayBuffer|Float32Array|Float64Array|Int16Array|Int32Array|Int8Array|" + + "Uint16Array|Uint32Array|Uint8Array|Uint8ClampedArray" + ); + + var supportFunction = ( + "Math|JSON|isNaN|isFinite|parseInt|parseFloat|encodeURI|" + + "encodeURIComponent|decodeURI|decodeURIComponent|String|" + ); + + var variableLanguage = ( + "window|arguments|prototype|document" + ); + + var keywordMapper = this.createKeywordMapper({ + "keyword": keywords, + "constant.language": langConstant, + "invalid.illegal": illegal, + "language.support.class": supportClass, + "language.support.function": supportFunction, + "variable.language": variableLanguage + }, "identifier"); + + var functionRule = { + token: ["paren.lparen", "variable.parameter", "paren.rparen", "text", "storage.type"], + regex: /(?:(\()((?:"[^")]*?"|'[^')]*?'|\/[^\/)]*?\/|[^()\"'\/])*?)(\))(\s*))?([\-=]>)/.source + }; + + var stringEscape = /\\(?:x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|[0-2][0-7]{0,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.)/; + + this.$rules = { + start : [ + { + token : "constant.numeric", + regex : "(?:0x[\\da-fA-F]+|(?:\\d+(?:\\.\\d+)?|\\.\\d+)(?:[eE][+-]?\\d+)?)" + }, { + stateName: "qdoc", + token : "string", regex : "'''", next : [ + {token : "string", regex : "'''", next : "start"}, + {token : "constant.language.escape", regex : stringEscape}, + {defaultToken: "string"} + ] + }, { + stateName: "qqdoc", + token : "string", + regex : '"""', + next : [ + {token : "string", regex : '"""', next : "start"}, + {token : "paren.string", regex : '#{', push : "start"}, + {token : "constant.language.escape", regex : stringEscape}, + {defaultToken: "string"} + ] + }, { + stateName: "qstring", + token : "string", regex : "'", next : [ + {token : "string", regex : "'", next : "start"}, + {token : "constant.language.escape", regex : stringEscape}, + {defaultToken: "string"} + ] + }, { + stateName: "qqstring", + token : "string.start", regex : '"', next : [ + {token : "string.end", regex : '"', next : "start"}, + {token : "paren.string", regex : '#{', push : "start"}, + {token : "constant.language.escape", regex : stringEscape}, + {defaultToken: "string"} + ] + }, { + stateName: "js", + token : "string", regex : "`", next : [ + {token : "string", regex : "`", next : "start"}, + {token : "constant.language.escape", regex : stringEscape}, + {defaultToken: "string"} + ] + }, { + regex: "[{}]", onMatch: function(val, state, stack) { + this.next = ""; + if (val == "{" && stack.length) { + stack.unshift("start", state); + return "paren"; + } + if (val == "}" && stack.length) { + stack.shift(); + this.next = stack.shift() || ""; + if (this.next.indexOf("string") != -1) + return "paren.string"; + } + return "paren"; + } + }, { + token : "string.regex", + regex : "///", + next : "heregex" + }, { + token : "string.regex", + regex : /(?:\/(?![\s=])[^[\/\n\\]*(?:(?:\\[\s\S]|\[[^\]\n\\]*(?:\\[\s\S][^\]\n\\]*)*])[^[\/\n\\]*)*\/)(?:[imgy]{0,4})(?!\w)/ + }, { + token : "comment", + regex : "###(?!#)", + next : "comment" + }, { + token : "comment", + regex : "#.*" + }, { + token : ["punctuation.operator", "text", "identifier"], + regex : "(\\.)(\\s*)(" + illegal + ")" + }, { + token : "punctuation.operator", + regex : "\\." + }, { + //class A extends B + token : ["keyword", "text", "language.support.class", + "text", "keyword", "text", "language.support.class"], + regex : "(class)(\\s+)(" + identifier + ")(?:(\\s+)(extends)(\\s+)(" + identifier + "))?" + }, { + //play = (...) -> + token : ["entity.name.function", "text", "keyword.operator", "text"].concat(functionRule.token), + regex : "(" + identifier + ")(\\s*)([=:])(\\s*)" + functionRule.regex + }, + functionRule, + { + token : "variable", + regex : "@(?:" + identifier + ")?" + }, { + token: keywordMapper, + regex : identifier + }, { + token : "punctuation.operator", + regex : "\\,|\\." + }, { + token : "storage.type", + regex : "[\\-=]>" + }, { + token : "keyword.operator", + regex : "(?:[-+*/%<>&|^!?=]=|>>>=?|\\-\\-|\\+\\+|::|&&=|\\|\\|=|<<=|>>=|\\?\\.|\\.{2,3}|[!*+-=><])" + }, { + token : "paren.lparen", + regex : "[({[]" + }, { + token : "paren.rparen", + regex : "[\\]})]" + }, { + token : "text", + regex : "\\s+" + }], + + + heregex : [{ + token : "string.regex", + regex : '.*?///[imgy]{0,4}', + next : "start" + }, { + token : "comment.regex", + regex : "\\s+(?:#.*)?" + }, { + token : "string.regex", + regex : "\\S+" + }], + + comment : [{ + token : "comment", + regex : '###', + next : "start" + }, { + defaultToken : "comment" + }] + }; + this.normalizeRules(); + } + + exports.CoffeeHighlightRules = CoffeeHighlightRules; +}); diff --git a/node_modules/ace/lib/ace/mode/coffee_worker.js b/node_modules/ace/lib/ace/mode/coffee_worker.js new file mode 100644 index 00000000..d68f1296 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/coffee_worker.js @@ -0,0 +1,73 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var Mirror = require("../worker/mirror").Mirror; +var coffee = require("../mode/coffee/coffee-script"); + +window.addEventListener = function() {}; + + +var Worker = exports.Worker = function(sender) { + Mirror.call(this, sender); + this.setTimeout(250); +}; + +oop.inherits(Worker, Mirror); + +(function() { + + this.onUpdate = function() { + var value = this.doc.getValue(); + var errors = []; + try { + coffee.parse(value).compile(); + } catch(e) { + var loc = e.location; + if (loc) { + errors.push({ + row: loc.first_line, + column: loc.first_column, + endRow: loc.last_line, + endColumn: loc.last_column, + text: e.message, + type: "error" + }); + } + } + this.sender.emit("annotate", errors); + }; + +}).call(Worker.prototype); + +}); diff --git a/node_modules/ace/lib/ace/mode/coldfusion.js b/node_modules/ace/lib/ace/mode/coldfusion.js new file mode 100644 index 00000000..0b4ea449 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/coldfusion.js @@ -0,0 +1,61 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var lang = require("../lib/lang"); +var HtmlMode = require("./html").Mode; +var ColdfusionHighlightRules = require("./coldfusion_highlight_rules").ColdfusionHighlightRules; + +var voidElements = "cfabort|cfapplication|cfargument|cfassociate|cfbreak|cfcache|cfcollection|cfcookie|cfdbinfo|cfdirectory|cfdump|cfelse|cfelseif|cferror|cfexchangecalendar|cfexchangeconnection|cfexchangecontact|cfexchangefilter|cfexchangetask|cfexit|cffeed|cffile|cfflush|cfftp|cfheader|cfhtmlhead|cfhttpparam|cfimage|cfimport|cfinclude|cfindex|cfinsert|cfinvokeargument|cflocation|cflog|cfmailparam|cfNTauthenticate|cfobject|cfobjectcache|cfparam|cfpdfformparam|cfprint|cfprocparam|cfprocresult|cfproperty|cfqueryparam|cfregistry|cfreportparam|cfrethrow|cfreturn|cfschedule|cfsearch|cfset|cfsetting|cfthrow|cfzipparam)".split("|"); + +var Mode = function() { + HtmlMode.call(this); + + this.HighlightRules = ColdfusionHighlightRules; +}; +oop.inherits(Mode, HtmlMode); + +(function() { + + // mix with html void elements + this.voidElements = oop.mixin(lang.arrayToMap(voidElements), this.voidElements); + + this.getNextLineIndent = function(state, line, tab) { + return this.$getIndent(line); + }; + + this.$id = "ace/mode/coldfusion"; +}).call(Mode.prototype); + +exports.Mode = Mode; +}); diff --git a/node_modules/ace/lib/ace/mode/coldfusion_highlight_rules.js b/node_modules/ace/lib/ace/mode/coldfusion_highlight_rules.js new file mode 100644 index 00000000..5feff6d6 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/coldfusion_highlight_rules.js @@ -0,0 +1,49 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var JavaScriptHighlightRules = require("./javascript_highlight_rules").JavaScriptHighlightRules; +var HtmlHighlightRules = require("./html_highlight_rules").HtmlHighlightRules; + +var ColdfusionHighlightRules = function() { + HtmlHighlightRules.call(this); + + this.embedTagRules(JavaScriptHighlightRules, "cfjs-", "cfscript"); + + this.normalizeRules(); +}; + +oop.inherits(ColdfusionHighlightRules, HtmlHighlightRules); + +exports.ColdfusionHighlightRules = ColdfusionHighlightRules; +}); diff --git a/node_modules/ace/lib/ace/mode/coldfusion_test.js b/node_modules/ace/lib/ace/mode/coldfusion_test.js new file mode 100644 index 00000000..b55fb1c5 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/coldfusion_test.js @@ -0,0 +1,67 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +if (typeof process !== "undefined") { + require("amd-loader"); +} + +define(function(require, exports, module) { +"use strict"; + +var EditSession = require("../edit_session").EditSession; +var Range = require("../range").Range; +var ColdfusionMode = require("./coldfusion").Mode; +var assert = require("../test/assertions"); + +module.exports = { + setUp : function() { + this.mode = new ColdfusionMode(); + }, + + "test: toggle comment lines" : function() { + var session = new EditSession([" abc", " cde", "fg"]); + + var range = new Range(0, 3, 1, 1); + var comment = this.mode.toggleCommentLines("start", session, 0, 1); + assert.equal([" ", " ", "fg"].join("\n"), session.toString()); + }, + + "test: next line indent should be the same as the current line indent" : function() { + assert.equal(" ", this.mode.getNextLineIndent("start", " abc")); + assert.equal("", this.mode.getNextLineIndent("start", "abc")); + assert.equal("\t", this.mode.getNextLineIndent("start", "\tabc")); + } +}; + +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec() +} diff --git a/node_modules/ace/lib/ace/mode/csharp.js b/node_modules/ace/lib/ace/mode/csharp.js new file mode 100644 index 00000000..a3b2964f --- /dev/null +++ b/node_modules/ace/lib/ace/mode/csharp.js @@ -0,0 +1,61 @@ +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextMode = require("./text").Mode; +var CSharpHighlightRules = require("./csharp_highlight_rules").CSharpHighlightRules; +var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent; +var CstyleBehaviour = require("./behaviour/cstyle").CstyleBehaviour; +var CStyleFoldMode = require("./folding/csharp").FoldMode; + +var Mode = function() { + this.HighlightRules = CSharpHighlightRules; + this.$outdent = new MatchingBraceOutdent(); + this.$behaviour = new CstyleBehaviour(); + this.foldingRules = new CStyleFoldMode(); +}; +oop.inherits(Mode, TextMode); + +(function() { + + this.lineCommentStart = "//"; + this.blockComment = {start: "/*", end: "*/"}; + + this.getNextLineIndent = function(state, line, tab) { + var indent = this.$getIndent(line); + + var tokenizedLine = this.getTokenizer().getLineTokens(line, state); + var tokens = tokenizedLine.tokens; + + if (tokens.length && tokens[tokens.length-1].type == "comment") { + return indent; + } + + if (state == "start") { + var match = line.match(/^.*[\{\(\[]\s*$/); + if (match) { + indent += tab; + } + } + + return indent; + }; + + this.checkOutdent = function(state, line, input) { + return this.$outdent.checkOutdent(line, input); + }; + + this.autoOutdent = function(state, doc, row) { + this.$outdent.autoOutdent(doc, row); + }; + + + this.createWorker = function(session) { + return null; + }; + + this.$id = "ace/mode/csharp"; +}).call(Mode.prototype); + +exports.Mode = Mode; +}); diff --git a/node_modules/ace/lib/ace/mode/csharp_highlight_rules.js b/node_modules/ace/lib/ace/mode/csharp_highlight_rules.js new file mode 100644 index 00000000..6e7ba5d4 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/csharp_highlight_rules.js @@ -0,0 +1,93 @@ +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var DocCommentHighlightRules = require("./doc_comment_highlight_rules").DocCommentHighlightRules; +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + +var CSharpHighlightRules = function() { + var keywordMapper = this.createKeywordMapper({ + "variable.language": "this", + "keyword": "abstract|event|new|struct|as|explicit|null|switch|base|extern|object|this|bool|false|operator|throw|break|finally|out|true|byte|fixed|override|try|case|float|params|typeof|catch|for|private|uint|char|foreach|protected|ulong|checked|goto|public|unchecked|class|if|readonly|unsafe|const|implicit|ref|ushort|continue|in|return|using|decimal|int|sbyte|virtual|default|interface|sealed|volatile|delegate|internal|short|void|do|is|sizeof|while|double|lock|stackalloc|else|long|static|enum|namespace|string|var|dynamic", + "constant.language": "null|true|false" + }, "identifier"); + + // regexp must not have capturing parentheses. Use (?:) instead. + // regexps are ordered -> the first match is used + + this.$rules = { + "start" : [ + { + token : "comment", + regex : "\\/\\/.*$" + }, + DocCommentHighlightRules.getStartRule("doc-start"), + { + token : "comment", // multi line comment + regex : "\\/\\*", + next : "comment" + }, { + token : "string", // character + regex : /'(?:.|\\(:?u[\da-fA-F]+|x[\da-fA-F]+|[tbrf'"n]))'/ + }, { + token : "string", start : '"', end : '"|$', next: [ + {token: "constant.language.escape", regex: /\\(:?u[\da-fA-F]+|x[\da-fA-F]+|[tbrf'"n])/}, + {token: "invalid", regex: /\\./} + ] + }, { + token : "string", start : '@"', end : '"', next:[ + {token: "constant.language.escape", regex: '""'} + ] + }, { + token : "constant.numeric", // hex + regex : "0[xX][0-9a-fA-F]+\\b" + }, { + token : "constant.numeric", // float + regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b" + }, { + token : "constant.language.boolean", + regex : "(?:true|false)\\b" + }, { + token : keywordMapper, + regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b" + }, { + token : "keyword.operator", + regex : "!|\\$|%|&|\\*|\\-\\-|\\-|\\+\\+|\\+|~|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\\|\\||\\?\\:|\\*=|%=|\\+=|\\-=|&=|\\^=|\\b(?:in|instanceof|new|delete|typeof|void)" + }, { + token : "keyword", + regex : "^\\s*#(if|else|elif|endif|define|undef|warning|error|line|region|endregion|pragma)" + }, { + token : "punctuation.operator", + regex : "\\?|\\:|\\,|\\;|\\." + }, { + token : "paren.lparen", + regex : "[[({]" + }, { + token : "paren.rparen", + regex : "[\\])}]" + }, { + token : "text", + regex : "\\s+" + } + ], + "comment" : [ + { + token : "comment", // closing comment + regex : ".*?\\*\\/", + next : "start" + }, { + token : "comment", // comment spanning whole line + regex : ".+" + } + ] + }; + + this.embedRules(DocCommentHighlightRules, "doc-", + [ DocCommentHighlightRules.getEndRule("start") ]); + this.normalizeRules(); +}; + +oop.inherits(CSharpHighlightRules, TextHighlightRules); + +exports.CSharpHighlightRules = CSharpHighlightRules; +}); diff --git a/node_modules/ace/lib/ace/mode/css.js b/node_modules/ace/lib/ace/mode/css.js new file mode 100644 index 00000000..6fef5ccd --- /dev/null +++ b/node_modules/ace/lib/ace/mode/css.js @@ -0,0 +1,100 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextMode = require("./text").Mode; +var CssHighlightRules = require("./css_highlight_rules").CssHighlightRules; +var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent; +var WorkerClient = require("../worker/worker_client").WorkerClient; +var CssBehaviour = require("./behaviour/css").CssBehaviour; +var CStyleFoldMode = require("./folding/cstyle").FoldMode; + +var Mode = function() { + this.HighlightRules = CssHighlightRules; + this.$outdent = new MatchingBraceOutdent(); + this.$behaviour = new CssBehaviour(); + this.foldingRules = new CStyleFoldMode(); +}; +oop.inherits(Mode, TextMode); + +(function() { + + this.foldingRules = "cStyle"; + this.blockComment = {start: "/*", end: "*/"}; + + this.getNextLineIndent = function(state, line, tab) { + var indent = this.$getIndent(line); + + // ignore braces in comments + var tokens = this.getTokenizer().getLineTokens(line, state).tokens; + if (tokens.length && tokens[tokens.length-1].type == "comment") { + return indent; + } + + var match = line.match(/^.*\{\s*$/); + if (match) { + indent += tab; + } + + return indent; + }; + + this.checkOutdent = function(state, line, input) { + return this.$outdent.checkOutdent(line, input); + }; + + this.autoOutdent = function(state, doc, row) { + this.$outdent.autoOutdent(doc, row); + }; + + this.createWorker = function(session) { + var worker = new WorkerClient(["ace"], "ace/mode/css_worker", "Worker"); + worker.attachToDocument(session.getDocument()); + + worker.on("annotate", function(e) { + session.setAnnotations(e.data); + }); + + worker.on("terminate", function() { + session.clearAnnotations(); + }); + + return worker; + }; + + this.$id = "ace/mode/css"; +}).call(Mode.prototype); + +exports.Mode = Mode; + +}); diff --git a/node_modules/ace/lib/ace/mode/css/csslint.js b/node_modules/ace/lib/ace/mode/css/csslint.js new file mode 100644 index 00000000..c3c79a80 --- /dev/null +++ b/node_modules/ace/lib/ace/mode/css/csslint.js @@ -0,0 +1,9628 @@ +define(function(require, exports, module) { +/*! +CSSLint +Copyright (c) 2014 Nicole Sullivan and Nicholas C. Zakas. All rights reserved. + +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. + +*/ +/* Build: v0.10.0 22-July-2014 01:17:52 */ +/*! +Parser-Lib +Copyright (c) 2009-2011 Nicholas C. Zakas. All rights reserved. + +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. + +*/ +/* Version v0.2.5, Build time: 7-May-2014 03:37:38 */ +var parserlib = {}; +(function(){ + +/** + * A generic base to inherit from for any object + * that needs event handling. + * @class EventTarget + * @constructor + */ +function EventTarget(){ + + /** + * The array of listeners for various events. + * @type Object + * @property _listeners + * @private + */ + this._listeners = {}; +} + +EventTarget.prototype = { + + //restore constructor + constructor: EventTarget, + + /** + * Adds a listener for a given event type. + * @param {String} type The type of event to add a listener for. + * @param {Function} listener The function to call when the event occurs. + * @return {void} + * @method addListener + */ + addListener: function(type, listener){ + if (!this._listeners[type]){ + this._listeners[type] = []; + } + + this._listeners[type].push(listener); + }, + + /** + * Fires an event based on the passed-in object. + * @param {Object|String} event An object with at least a 'type' attribute + * or a string indicating the event name. + * @return {void} + * @method fire + */ + fire: function(event){ + if (typeof event == "string"){ + event = { type: event }; + } + if (typeof event.target != "undefined"){ + event.target = this; + } + + if (typeof event.type == "undefined"){ + throw new Error("Event object missing 'type' property."); + } + + if (this._listeners[event.type]){ + + //create a copy of the array and use that so listeners can't chane + var listeners = this._listeners[event.type].concat(); + for (var i=0, len=listeners.length; i < len; i++){ + listeners[i].call(this, event); + } + } + }, + + /** + * Removes a listener for a given event type. + * @param {String} type The type of event to remove a listener from. + * @param {Function} listener The function to remove from the event. + * @return {void} + * @method removeListener + */ + removeListener: function(type, listener){ + if (this._listeners[type]){ + var listeners = this._listeners[type]; + for (var i=0, len=listeners.length; i < len; i++){ + if (listeners[i] === listener){ + listeners.splice(i, 1); + break; + } + } + + + } + } +}; +/** + * Convenient way to read through strings. + * @namespace parserlib.util + * @class StringReader + * @constructor + * @param {String} text The text to read. + */ +function StringReader(text){ + + /** + * The input text with line endings normalized. + * @property _input + * @type String + * @private + */ + this._input = text.replace(/\n\r?/g, "\n"); + + + /** + * The row for the character to be read next. + * @property _line + * @type int + * @private + */ + this._line = 1; + + + /** + * The column for the character to be read next. + * @property _col + * @type int + * @private + */ + this._col = 1; + + /** + * The index of the character in the input to be read next. + * @property _cursor + * @type int + * @private + */ + this._cursor = 0; +} + +StringReader.prototype = { + + //restore constructor + constructor: StringReader, + + //------------------------------------------------------------------------- + // Position info + //------------------------------------------------------------------------- + + /** + * Returns the column of the character to be read next. + * @return {int} The column of the character to be read next. + * @method getCol + */ + getCol: function(){ + return this._col; + }, + + /** + * Returns the row of the character to be read next. + * @return {int} The row of the character to be read next. + * @method getLine + */ + getLine: function(){ + return this._line ; + }, + + /** + * Determines if you're at the end of the input. + * @return {Boolean} True if there's no more input, false otherwise. + * @method eof + */ + eof: function(){ + return (this._cursor == this._input.length); + }, + + //------------------------------------------------------------------------- + // Basic reading + //------------------------------------------------------------------------- + + /** + * Reads the next character without advancing the cursor. + * @param {int} count How many characters to look ahead (default is 1). + * @return {String} The next character or null if there is no next character. + * @method peek + */ + peek: function(count){ + var c = null; + count = (typeof count == "undefined" ? 1 : count); + + //if we're not at the end of the input... + if (this._cursor < this._input.length){ + + //get character and increment cursor and column + c = this._input.charAt(this._cursor + count - 1); + } + + return c; + }, + + /** + * Reads the next character from the input and adjusts the row and column + * accordingly. + * @return {String} The next character or null if there is no next character. + * @method read + */ + read: function(){ + var c = null; + + //if we're not at the end of the input... + if (this._cursor < this._input.length){ + + //if the last character was a newline, increment row count + //and reset column count + if (this._input.charAt(this._cursor) == "\n"){ + this._line++; + this._col=1; + } else { + this._col++; + } + + //get character and increment cursor and column + c = this._input.charAt(this._cursor++); + } + + return c; + }, + + //------------------------------------------------------------------------- + // Misc + //------------------------------------------------------------------------- + + /** + * Saves the current location so it can be returned to later. + * @method mark + * @return {void} + */ + mark: function(){ + this._bookmark = { + cursor: this._cursor, + line: this._line, + col: this._col + }; + }, + + reset: function(){ + if (this._bookmark){ + this._cursor = this._bookmark.cursor; + this._line = this._bookmark.line; + this._col = this._bookmark.col; + delete this._bookmark; + } + }, + + //------------------------------------------------------------------------- + // Advanced reading + //------------------------------------------------------------------------- + + /** + * Reads up to and including the given string. Throws an error if that + * string is not found. + * @param {String} pattern The string to read. + * @return {String} The string when it is found. + * @throws Error when the string pattern is not found. + * @method readTo + */ + readTo: function(pattern){ + + var buffer = "", + c; + + /* + * First, buffer must be the same length as the pattern. + * Then, buffer must end with the pattern or else reach the + * end of the input. + */ + while (buffer.length < pattern.length || buffer.lastIndexOf(pattern) != buffer.length - pattern.length){ + c = this.read(); + if (c){ + buffer += c; + } else { + throw new Error("Expected \"" + pattern + "\" at line " + this._line + ", col " + this._col + "."); + } + } + + return buffer; + + }, + + /** + * Reads characters while each character causes the given + * filter function to return true. The function is passed + * in each character and either returns true to continue + * reading or false to stop. + * @param {Function} filter The function to read on each character. + * @return {String} The string made up of all characters that passed the + * filter check. + * @method readWhile + */ + readWhile: function(filter){ + + var buffer = "", + c = this.read(); + + while(c !== null && filter(c)){ + buffer += c; + c = this.read(); + } + + return buffer; + + }, + + /** + * Reads characters that match either text or a regular expression and + * returns those characters. If a match is found, the row and column + * are adjusted; if no match is found, the reader's state is unchanged. + * reading or false to stop. + * @param {String|RegExp} matchter If a string, then the literal string + * value is searched for. If a regular expression, then any string + * matching the pattern is search for. + * @return {String} The string made up of all characters that matched or + * null if there was no match. + * @method readMatch + */ + readMatch: function(matcher){ + + var source = this._input.substring(this._cursor), + value = null; + + //if it's a string, just do a straight match + if (typeof matcher == "string"){ + if (source.indexOf(matcher) === 0){ + value = this.readCount(matcher.length); + } + } else if (matcher instanceof RegExp){ + if (matcher.test(source)){ + value = this.readCount(RegExp.lastMatch.length); + } + } + + return value; + }, + + + /** + * Reads a given number of characters. If the end of the input is reached, + * it reads only the remaining characters and does not throw an error. + * @param {int} count The number of characters to read. + * @return {String} The string made up the read characters. + * @method readCount + */ + readCount: function(count){ + var buffer = ""; + + while(count--){ + buffer += this.read(); + } + + return buffer; + } + +}; +/** + * Type to use when a syntax error occurs. + * @class SyntaxError + * @namespace parserlib.util + * @constructor + * @param {String} message The error message. + * @param {int} line The line at which the error occurred. + * @param {int} col The column at which the error occurred. + */ +function SyntaxError(message, line, col){ + + /** + * The column at which the error occurred. + * @type int + * @property col + */ + this.col = col; + + /** + * The line at which the error occurred. + * @type int + * @property line + */ + this.line = line; + + /** + * The text representation of the unit. + * @type String + * @property text + */ + this.message = message; + +} + +//inherit from Error +SyntaxError.prototype = new Error(); +/** + * Base type to represent a single syntactic unit. + * @class SyntaxUnit + * @namespace parserlib.util + * @constructor + * @param {String} text The text of the unit. + * @param {int} line The line of text on which the unit resides. + * @param {int} col The column of text on which the unit resides. + */ +function SyntaxUnit(text, line, col, type){ + + + /** + * The column of text on which the unit resides. + * @type int + * @property col + */ + this.col = col; + + /** + * The line of text on which the unit resides. + * @type int + * @property line + */ + this.line = line; + + /** + * The text representation of the unit. + * @type String + * @property text + */ + this.text = text; + + /** + * The type of syntax unit. + * @type int + * @property type + */ + this.type = type; +} + +/** + * Create a new syntax unit based solely on the given token. + * Convenience method for creating a new syntax unit when + * it represents a single token instead of multiple. + * @param {Object} token The token object to represent. + * @return {parserlib.util.SyntaxUnit} The object representing the token. + * @static + * @method fromToken + */ +SyntaxUnit.fromToken = function(token){ + return new SyntaxUnit(token.value, token.startLine, token.startCol); +}; + +SyntaxUnit.prototype = { + + //restore constructor + constructor: SyntaxUnit, + + /** + * Returns the text representation of the unit. + * @return {String} The text representation of the unit. + * @method valueOf + */ + valueOf: function(){ + return this.text; + }, + + /** + * Returns the text representation of the unit. + * @return {String} The text representation of the unit. + * @method toString + */ + toString: function(){ + return this.text; + } + +}; +/*global StringReader, SyntaxError*/ + +/** + * Generic TokenStream providing base functionality. + * @class TokenStreamBase + * @namespace parserlib.util + * @constructor + * @param {String|StringReader} input The text to tokenize or a reader from + * which to read the input. + */ +function TokenStreamBase(input, tokenData){ + + /** + * The string reader for easy access to the text. + * @type StringReader + * @property _reader + * @private + */ + this._reader = input ? new StringReader(input.toString()) : null; + + /** + * Token object for the last consumed token. + * @type Token + * @property _token + * @private + */ + this._token = null; + + /** + * The array of token information. + * @type Array + * @property _tokenData + * @private + */ + this._tokenData = tokenData; + + /** + * Lookahead token buffer. + * @type Array + * @property _lt + * @private + */ + this._lt = []; + + /** + * Lookahead token buffer index. + * @type int + * @property _ltIndex + * @private + */ + this._ltIndex = 0; + + this._ltIndexCache = []; +} + +/** + * Accepts an array of token information and outputs + * an array of token data containing key-value mappings + * and matching functions that the TokenStream needs. + * @param {Array} tokens An array of token descriptors. + * @return {Array} An array of processed token data. + * @method createTokenData + * @static + */ +TokenStreamBase.createTokenData = function(tokens){ + + var nameMap = [], + typeMap = {}, + tokenData = tokens.concat([]), + i = 0, + len = tokenData.length+1; + + tokenData.UNKNOWN = -1; + tokenData.unshift({name:"EOF"}); + + for (; i < len; i++){ + nameMap.push(tokenData[i].name); + tokenData[tokenData[i].name] = i; + if (tokenData[i].text){ + typeMap[tokenData[i].text] = i; + } + } + + tokenData.name = function(tt){ + return nameMap[tt]; + }; + + tokenData.type = function(c){ + return typeMap[c]; + }; + + return tokenData; +}; + +TokenStreamBase.prototype = { + + //restore constructor + constructor: TokenStreamBase, + + //------------------------------------------------------------------------- + // Matching methods + //------------------------------------------------------------------------- + + /** + * Determines if the next token matches the given token type. + * If so, that token is consumed; if not, the token is placed + * back onto the token stream. You can pass in any number of + * token types and this will return true if any of the token + * types is found. + * @param {int|int[]} tokenTypes Either a single token type or an array of + * token types that the next token might be. If an array is passed, + * it's assumed that the token can be any of these. + * @param {variant} channel (Optional) The channel to read from. If not + * provided, reads from the default (unnamed) channel. + * @return {Boolean} True if the token type matches, false if not. + * @method match + */ + match: function(tokenTypes, channel){ + + //always convert to an array, makes things easier + if (!(tokenTypes instanceof Array)){ + tokenTypes = [tokenTypes]; + } + + var tt = this.get(channel), + i = 0, + len = tokenTypes.length; + + while(i < len){ + if (tt == tokenTypes[i++]){ + return true; + } + } + + //no match found, put the token back + this.unget(); + return false; + }, + + /** + * Determines if the next token matches the given token type. + * If so, that token is consumed; if not, an error is thrown. + * @param {int|int[]} tokenTypes Either a single token type or an array of + * token types that the next token should be. If an array is passed, + * it's assumed that the token must be one of these. + * @param {variant} channel (Optional) The channel to read from. If not + * provided, reads from the default (unnamed) channel. + * @return {void} + * @method mustMatch + */ + mustMatch: function(tokenTypes, channel){ + + var token; + + //always convert to an array, makes things easier + if (!(tokenTypes instanceof Array)){ + tokenTypes = [tokenTypes]; + } + + if (!this.match.apply(this, arguments)){ + token = this.LT(1); + throw new SyntaxError("Expected " + this._tokenData[tokenTypes[0]].name + + " at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol); + } + }, + + //------------------------------------------------------------------------- + // Consuming methods + //------------------------------------------------------------------------- + + /** + * Keeps reading from the token stream until either one of the specified + * token types is found or until the end of the input is reached. + * @param {int|int[]} tokenTypes Either a single token type or an array of + * token types that the next token should be. If an array is passed, + * it's assumed that the token must be one of these. + * @param {variant} channel (Optional) The channel to read from. If not + * provided, reads from the default (unnamed) channel. + * @return {void} + * @method advance + */ + advance: function(tokenTypes, channel){ + + while(this.LA(0) !== 0 && !this.match(tokenTypes, channel)){ + this.get(); + } + + return this.LA(0); + }, + + /** + * Consumes the next token from the token stream. + * @return {int} The token type of the token that was just consumed. + * @method get + */ + get: function(channel){ + + var tokenInfo = this._tokenData, + reader = this._reader, + value, + i =0, + len = tokenInfo.length, + found = false, + token, + info; + + //check the lookahead buffer first + if (this._lt.length && this._ltIndex >= 0 && this._ltIndex < this._lt.length){ + + i++; + this._token = this._lt[this._ltIndex++]; + info = tokenInfo[this._token.type]; + + //obey channels logic + while((info.channel !== undefined && channel !== info.channel) && + this._ltIndex < this._lt.length){ + this._token = this._lt[this._ltIndex++]; + info = tokenInfo[this._token.type]; + i++; + } + + //here be dragons + if ((info.channel === undefined || channel === info.channel) && + this._ltIndex <= this._lt.length){ + this._ltIndexCache.push(i); + return this._token.type; + } + } + + //call token retriever method + token = this._getToken(); + + //if it should be hidden, don't save a token + if (token.type > -1 && !tokenInfo[token.type].hide){ + + //apply token channel + token.channel = tokenInfo[token.type].channel; + + //save for later + this._token = token; + this._lt.push(token); + + //save space that will be moved (must be done before array is truncated) + this._ltIndexCache.push(this._lt.length - this._ltIndex + i); + + //keep the buffer under 5 items + if (this._lt.length > 5){ + this._lt.shift(); + } + + //also keep the shift buffer under 5 items + if (this._ltIndexCache.length > 5){ + this._ltIndexCache.shift(); + } + + //update lookahead index + this._ltIndex = this._lt.length; + } + + /* + * Skip to the next token if: + * 1. The token type is marked as hidden. + * 2. The token type has a channel specified and it isn't the current channel. + */ + info = tokenInfo[token.type]; + if (info && + (info.hide || + (info.channel !== undefined && channel !== info.channel))){ + return this.get(channel); + } else { + //return just the type + return token.type; + } + }, + + /** + * Looks ahead a certain number of tokens and returns the token type at + * that position. This will throw an error if you lookahead past the + * end of input, past the size of the lookahead buffer, or back past + * the first token in the lookahead buffer. + * @param {int} The index of the token type to retrieve. 0 for the + * current token, 1 for the next, -1 for the previous, etc. + * @return {int} The token type of the token in the given position. + * @method LA + */ + LA: function(index){ + var total = index, + tt; + if (index > 0){ + //TODO: Store 5 somewhere + if (index > 5){ + throw new Error("Too much lookahead."); + } + + //get all those tokens + while(total){ + tt = this.get(); + total--; + } + + //unget all those tokens + while(total < index){ + this.unget(); + total++; + } + } else if (index < 0){ + + if(this._lt[this._ltIndex+index]){ + tt = this._lt[this._ltIndex+index].type; + } else { + throw new Error("Too much lookbehind."); + } + + } else { + tt = this._token.type; + } + + return tt; + + }, + + /** + * Looks ahead a certain number of tokens and returns the token at + * that position. This will throw an error if you lookahead past the + * end of input, past the size of the lookahead buffer, or back past + * the first token in the lookahead buffer. + * @param {int} The index of the token type to retrieve. 0 for the + * current token, 1 for the next, -1 for the previous, etc. + * @return {Object} The token of the token in the given position. + * @method LA + */ + LT: function(index){ + + //lookahead first to prime the token buffer + this.LA(index); + + //now find the token, subtract one because _ltIndex is already at the next index + return this._lt[this._ltIndex+index-1]; + }, + + /** + * Returns the token type for the next token in the stream without + * consuming it. + * @return {int} The token type of the next token in the stream. + * @method peek + */ + peek: function(){ + return this.LA(1); + }, + + /** + * Returns the actual token object for the last consumed token. + * @return {Token} The token object for the last consumed token. + * @method token + */ + token: function(){ + return this._token; + }, + + /** + * Returns the name of the token for the given token type. + * @param {int} tokenType The type of token to get the name of. + * @return {String} The name of the token or "UNKNOWN_TOKEN" for any + * invalid token type. + * @method tokenName + */ + tokenName: function(tokenType){ + if (tokenType < 0 || tokenType > this._tokenData.length){ + return "UNKNOWN_TOKEN"; + } else { + return this._tokenData[tokenType].name; + } + }, + + /** + * Returns the token type value for the given token name. + * @param {String} tokenName The name of the token whose value should be returned. + * @return {int} The token type value for the given token name or -1 + * for an unknown token. + * @method tokenName + */ + tokenType: function(tokenName){ + return this._tokenData[tokenName] || -1; + }, + + /** + * Returns the last consumed token to the token stream. + * @method unget + */ + unget: function(){ + //if (this._ltIndex > -1){ + if (this._ltIndexCache.length){ + this._ltIndex -= this._ltIndexCache.pop();//--; + this._token = this._lt[this._ltIndex - 1]; + } else { + throw new Error("Too much lookahead."); + } + } + +}; + + +parserlib.util = { +StringReader: StringReader, +SyntaxError : SyntaxError, +SyntaxUnit : SyntaxUnit, +EventTarget : EventTarget, +TokenStreamBase : TokenStreamBase +}; +})(); +/* +Parser-Lib +Copyright (c) 2009-2011 Nicholas C. Zakas. All rights reserved. + +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. + +*/ +/* Version v0.2.5, Build time: 7-May-2014 03:37:38 */ +(function(){ +var EventTarget = parserlib.util.EventTarget, +TokenStreamBase = parserlib.util.TokenStreamBase, +StringReader = parserlib.util.StringReader, +SyntaxError = parserlib.util.SyntaxError, +SyntaxUnit = parserlib.util.SyntaxUnit; + +var Colors = { + aliceblue :"#f0f8ff", + antiquewhite :"#faebd7", + aqua :"#00ffff", + aquamarine :"#7fffd4", + azure :"#f0ffff", + beige :"#f5f5dc", + bisque :"#ffe4c4", + black :"#000000", + blanchedalmond :"#ffebcd", + blue :"#0000ff", + blueviolet :"#8a2be2", + brown :"#a52a2a", + burlywood :"#deb887", + cadetblue :"#5f9ea0", + chartreuse :"#7fff00", + chocolate :"#d2691e", + coral :"#ff7f50", + cornflowerblue :"#6495ed", + cornsilk :"#fff8dc", + crimson :"#dc143c", + cyan :"#00ffff", + darkblue :"#00008b", + darkcyan :"#008b8b", + darkgoldenrod :"#b8860b", + darkgray :"#a9a9a9", + darkgrey :"#a9a9a9", + darkgreen :"#006400", + darkkhaki :"#bdb76b", + darkmagenta :"#8b008b", + darkolivegreen :"#556b2f", + darkorange :"#ff8c00", + darkorchid :"#9932cc", + darkred :"#8b0000", + darksalmon :"#e9967a", + darkseagreen :"#8fbc8f", + darkslateblue :"#483d8b", + darkslategray :"#2f4f4f", + darkslategrey :"#2f4f4f", + darkturquoise :"#00ced1", + darkviolet :"#9400d3", + deeppink :"#ff1493", + deepskyblue :"#00bfff", + dimgray :"#696969", + dimgrey :"#696969", + dodgerblue :"#1e90ff", + firebrick :"#b22222", + floralwhite :"#fffaf0", + forestgreen :"#228b22", + fuchsia :"#ff00ff", + gainsboro :"#dcdcdc", + ghostwhite :"#f8f8ff", + gold :"#ffd700", + goldenrod :"#daa520", + gray :"#808080", + grey :"#808080", + green :"#008000", + greenyellow :"#adff2f", + honeydew :"#f0fff0", + hotpink :"#ff69b4", + indianred :"#cd5c5c", + indigo :"#4b0082", + ivory :"#fffff0", + khaki :"#f0e68c", + lavender :"#e6e6fa", + lavenderblush :"#fff0f5", + lawngreen :"#7cfc00", + lemonchiffon :"#fffacd", + lightblue :"#add8e6", + lightcoral :"#f08080", + lightcyan :"#e0ffff", + lightgoldenrodyellow :"#fafad2", + lightgray :"#d3d3d3", + lightgrey :"#d3d3d3", + lightgreen :"#90ee90", + lightpink :"#ffb6c1", + lightsalmon :"#ffa07a", + lightseagreen :"#20b2aa", + lightskyblue :"#87cefa", + lightslategray :"#778899", + lightslategrey :"#778899", + lightsteelblue :"#b0c4de", + lightyellow :"#ffffe0", + lime :"#00ff00", + limegreen :"#32cd32", + linen :"#faf0e6", + magenta :"#ff00ff", + maroon :"#800000", + mediumaquamarine:"#66cdaa", + mediumblue :"#0000cd", + mediumorchid :"#ba55d3", + mediumpurple :"#9370d8", + mediumseagreen :"#3cb371", + mediumslateblue :"#7b68ee", + mediumspringgreen :"#00fa9a", + mediumturquoise :"#48d1cc", + mediumvioletred :"#c71585", + midnightblue :"#191970", + mintcream :"#f5fffa", + mistyrose :"#ffe4e1", + moccasin :"#ffe4b5", + navajowhite :"#ffdead", + navy :"#000080", + oldlace :"#fdf5e6", + olive :"#808000", + olivedrab :"#6b8e23", + orange :"#ffa500", + orangered :"#ff4500", + orchid :"#da70d6", + palegoldenrod :"#eee8aa", + palegreen :"#98fb98", + paleturquoise :"#afeeee", + palevioletred :"#d87093", + papayawhip :"#ffefd5", + peachpuff :"#ffdab9", + peru :"#cd853f", + pink :"#ffc0cb", + plum :"#dda0dd", + powderblue :"#b0e0e6", + purple :"#800080", + red :"#ff0000", + rosybrown :"#bc8f8f", + royalblue :"#4169e1", + saddlebrown :"#8b4513", + salmon :"#fa8072", + sandybrown :"#f4a460", + seagreen :"#2e8b57", + seashell :"#fff5ee", + sienna :"#a0522d", + silver :"#c0c0c0", + skyblue :"#87ceeb", + slateblue :"#6a5acd", + slategray :"#708090", + slategrey :"#708090", + snow :"#fffafa", + springgreen :"#00ff7f", + steelblue :"#4682b4", + tan :"#d2b48c", + teal :"#008080", + thistle :"#d8bfd8", + tomato :"#ff6347", + turquoise :"#40e0d0", + violet :"#ee82ee", + wheat :"#f5deb3", + white :"#ffffff", + whitesmoke :"#f5f5f5", + yellow :"#ffff00", + yellowgreen :"#9acd32", + //CSS2 system colors http://www.w3.org/TR/css3-color/#css2-system + activeBorder :"Active window border.", + activecaption :"Active window caption.", + appworkspace :"Background color of multiple document interface.", + background :"Desktop background.", + buttonface :"The face background color for 3-D elements that appear 3-D due to one layer of surrounding border.", + buttonhighlight :"The color of the border facing the light source for 3-D elements that appear 3-D due to one layer of surrounding border.", + buttonshadow :"The color of the border away from the light source for 3-D elements that appear 3-D due to one layer of surrounding border.", + buttontext :"Text on push buttons.", + captiontext :"Text in caption, size box, and scrollbar arrow box.", + graytext :"Grayed (disabled) text. This color is set to #000 if the current display driver does not support a solid gray color.", + greytext :"Greyed (disabled) text. This color is set to #000 if the current display driver does not support a solid grey color.", + highlight :"Item(s) selected in a control.", + highlighttext :"Text of item(s) selected in a control.", + inactiveborder :"Inactive window border.", + inactivecaption :"Inactive window caption.", + inactivecaptiontext :"Color of text in an inactive caption.", + infobackground :"Background color for tooltip controls.", + infotext :"Text color for tooltip controls.", + menu :"Menu background.", + menutext :"Text in menus.", + scrollbar :"Scroll bar gray area.", + threeddarkshadow :"The color of the darker (generally outer) of the two borders away from the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.", + threedface :"The face background color for 3-D elements that appear 3-D due to two concentric layers of surrounding border.", + threedhighlight :"The color of the lighter (generally outer) of the two borders facing the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.", + threedlightshadow :"The color of the darker (generally inner) of the two borders facing the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.", + threedshadow :"The color of the lighter (generally inner) of the two borders away from the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.", + window :"Window background.", + windowframe :"Window frame.", + windowtext :"Text in windows." +}; +/*global SyntaxUnit, Parser*/ +/** + * Represents a selector combinator (whitespace, +, >). + * @namespace parserlib.css + * @class Combinator + * @extends parserlib.util.SyntaxUnit + * @constructor + * @param {String} text The text representation of the unit. + * @param {int} line The line of text on which the unit resides. + * @param {int} col The column of text on which the unit resides. + */ +function Combinator(text, line, col){ + + SyntaxUnit.call(this, text, line, col, Parser.COMBINATOR_TYPE); + + /** + * The type of modifier. + * @type String + * @property type + */ + this.type = "unknown"; + + //pretty simple + if (/^\s+$/.test(text)){ + this.type = "descendant"; + } else if (text == ">"){ + this.type = "child"; + } else if (text == "+"){ + this.type = "adjacent-sibling"; + } else if (text == "~"){ + this.type = "sibling"; + } + +} + +Combinator.prototype = new SyntaxUnit(); +Combinator.prototype.constructor = Combinator; + +/*global SyntaxUnit, Parser*/ +/** + * Represents a media feature, such as max-width:500. + * @namespace parserlib.css + * @class MediaFeature + * @extends parserlib.util.SyntaxUnit + * @constructor + * @param {SyntaxUnit} name The name of the feature. + * @param {SyntaxUnit} value The value of the feature or null if none. + */ +function MediaFeature(name, value){ + + SyntaxUnit.call(this, "(" + name + (value !== null ? ":" + value : "") + ")", name.startLine, name.startCol, Parser.MEDIA_FEATURE_TYPE); + + /** + * The name of the media feature + * @type String + * @property name + */ + this.name = name; + + /** + * The value for the feature or null if there is none. + * @type SyntaxUnit + * @property value + */ + this.value = value; +} + +MediaFeature.prototype = new SyntaxUnit(); +MediaFeature.prototype.constructor = MediaFeature; + +/*global SyntaxUnit, Parser*/ +/** + * Represents an individual media query. + * @namespace parserlib.css + * @class MediaQuery + * @extends parserlib.util.SyntaxUnit + * @constructor + * @param {String} modifier The modifier "not" or "only" (or null). + * @param {String} mediaType The type of media (i.e., "print"). + * @param {Array} parts Array of selectors parts making up this selector. + * @param {int} line The line of text on which the unit resides. + * @param {int} col The column of text on which the unit resides. + */ +function MediaQuery(modifier, mediaType, features, line, col){ + + SyntaxUnit.call(this, (modifier ? modifier + " ": "") + (mediaType ? mediaType : "") + (mediaType && features.length > 0 ? " and " : "") + features.join(" and "), line, col, Parser.MEDIA_QUERY_TYPE); + + /** + * The media modifier ("not" or "only") + * @type String + * @property modifier + */ + this.modifier = modifier; + + /** + * The mediaType (i.e., "print") + * @type String + * @property mediaType + */ + this.mediaType = mediaType; + + /** + * The parts that make up the selector. + * @type Array + * @property features + */ + this.features = features; + +} + +MediaQuery.prototype = new SyntaxUnit(); +MediaQuery.prototype.constructor = MediaQuery; + +/*global Tokens, TokenStream, SyntaxError, Properties, Validation, ValidationError, SyntaxUnit, + PropertyValue, PropertyValuePart, SelectorPart, SelectorSubPart, Selector, + PropertyName, Combinator, MediaFeature, MediaQuery, EventTarget */ + +/** + * A CSS3 parser. + * @namespace parserlib.css + * @class Parser + * @constructor + * @param {Object} options (Optional) Various options for the parser: + * starHack (true|false) to allow IE6 star hack as valid, + * underscoreHack (true|false) to interpret leading underscores + * as IE6-7 targeting for known properties, ieFilters (true|false) + * to indicate that IE < 8 filters should be accepted and not throw + * syntax errors. + */ +function Parser(options){ + + //inherit event functionality + EventTarget.call(this); + + + this.options = options || {}; + + this._tokenStream = null; +} + +//Static constants +Parser.DEFAULT_TYPE = 0; +Parser.COMBINATOR_TYPE = 1; +Parser.MEDIA_FEATURE_TYPE = 2; +Parser.MEDIA_QUERY_TYPE = 3; +Parser.PROPERTY_NAME_TYPE = 4; +Parser.PROPERTY_VALUE_TYPE = 5; +Parser.PROPERTY_VALUE_PART_TYPE = 6; +Parser.SELECTOR_TYPE = 7; +Parser.SELECTOR_PART_TYPE = 8; +Parser.SELECTOR_SUB_PART_TYPE = 9; + +Parser.prototype = function(){ + + var proto = new EventTarget(), //new prototype + prop, + additions = { + + //restore constructor + constructor: Parser, + + //instance constants - yuck + DEFAULT_TYPE : 0, + COMBINATOR_TYPE : 1, + MEDIA_FEATURE_TYPE : 2, + MEDIA_QUERY_TYPE : 3, + PROPERTY_NAME_TYPE : 4, + PROPERTY_VALUE_TYPE : 5, + PROPERTY_VALUE_PART_TYPE : 6, + SELECTOR_TYPE : 7, + SELECTOR_PART_TYPE : 8, + SELECTOR_SUB_PART_TYPE : 9, + + //----------------------------------------------------------------- + // Grammar + //----------------------------------------------------------------- + + _stylesheet: function(){ + + /* + * stylesheet + * : [ CHARSET_SYM S* STRING S* ';' ]? + * [S|CDO|CDC]* [ import [S|CDO|CDC]* ]* + * [ namespace [S|CDO|CDC]* ]* + * [ [ ruleset | media | page | font_face | keyframes ] [S|CDO|CDC]* ]* + * ; + */ + + var tokenStream = this._tokenStream, + charset = null, + count, + token, + tt; + + this.fire("startstylesheet"); + + //try to read character set + this._charset(); + + this._skipCruft(); + + //try to read imports - may be more than one + while (tokenStream.peek() == Tokens.IMPORT_SYM){ + this._import(); + this._skipCruft(); + } + + //try to read namespaces - may be more than one + while (tokenStream.peek() == Tokens.NAMESPACE_SYM){ + this._namespace(); + this._skipCruft(); + } + + //get the next token + tt = tokenStream.peek(); + + //try to read the rest + while(tt > Tokens.EOF){ + + try { + + switch(tt){ + case Tokens.MEDIA_SYM: + this._media(); + this._skipCruft(); + break; + case Tokens.PAGE_SYM: + this._page(); + this._skipCruft(); + break; + case Tokens.FONT_FACE_SYM: + this._font_face(); + this._skipCruft(); + break; + case Tokens.KEYFRAMES_SYM: + this._keyframes(); + this._skipCruft(); + break; + case Tokens.VIEWPORT_SYM: + this._viewport(); + this._skipCruft(); + break; + case Tokens.UNKNOWN_SYM: //unknown @ rule + tokenStream.get(); + if (!this.options.strict){ + + //fire error event + this.fire({ + type: "error", + error: null, + message: "Unknown @ rule: " + tokenStream.LT(0).value + ".", + line: tokenStream.LT(0).startLine, + col: tokenStream.LT(0).startCol + }); + + //skip braces + count=0; + while (tokenStream.advance([Tokens.LBRACE, Tokens.RBRACE]) == Tokens.LBRACE){ + count++; //keep track of nesting depth + } + + while(count){ + tokenStream.advance([Tokens.RBRACE]); + count--; + } + + } else { + //not a syntax error, rethrow it + throw new SyntaxError("Unknown @ rule.", tokenStream.LT(0).startLine, tokenStream.LT(0).startCol); + } + break; + case Tokens.S: + this._readWhitespace(); + break; + default: + if(!this._ruleset()){ + + //error handling for known issues + switch(tt){ + case Tokens.CHARSET_SYM: + token = tokenStream.LT(1); + this._charset(false); + throw new SyntaxError("@charset not allowed here.", token.startLine, token.startCol); + case Tokens.IMPORT_SYM: + token = tokenStream.LT(1); + this._import(false); + throw new SyntaxError("@import not allowed here.", token.startLine, token.startCol); + case Tokens.NAMESPACE_SYM: + token = tokenStream.LT(1); + this._namespace(false); + throw new SyntaxError("@namespace not allowed here.", token.startLine, token.startCol); + default: + tokenStream.get(); //get the last token + this._unexpectedToken(tokenStream.token()); + } + + } + } + } catch(ex) { + if (ex instanceof SyntaxError && !this.options.strict){ + this.fire({ + type: "error", + error: ex, + message: ex.message, + line: ex.line, + col: ex.col + }); + } else { + throw ex; + } + } + + tt = tokenStream.peek(); + } + + if (tt != Tokens.EOF){ + this._unexpectedToken(tokenStream.token()); + } + + this.fire("endstylesheet"); + }, + + _charset: function(emit){ + var tokenStream = this._tokenStream, + charset, + token, + line, + col; + + if (tokenStream.match(Tokens.CHARSET_SYM)){ + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + + this._readWhitespace(); + tokenStream.mustMatch(Tokens.STRING); + + token = tokenStream.token(); + charset = token.value; + + this._readWhitespace(); + tokenStream.mustMatch(Tokens.SEMICOLON); + + if (emit !== false){ + this.fire({ + type: "charset", + charset:charset, + line: line, + col: col + }); + } + } + }, + + _import: function(emit){ + /* + * import + * : IMPORT_SYM S* + * [STRING|URI] S* media_query_list? ';' S* + */ + + var tokenStream = this._tokenStream, + tt, + uri, + importToken, + mediaList = []; + + //read import symbol + tokenStream.mustMatch(Tokens.IMPORT_SYM); + importToken = tokenStream.token(); + this._readWhitespace(); + + tokenStream.mustMatch([Tokens.STRING, Tokens.URI]); + + //grab the URI value + uri = tokenStream.token().value.replace(/^(?:url\()?["']?([^"']+?)["']?\)?$/, "$1"); + + this._readWhitespace(); + + mediaList = this._media_query_list(); + + //must end with a semicolon + tokenStream.mustMatch(Tokens.SEMICOLON); + this._readWhitespace(); + + if (emit !== false){ + this.fire({ + type: "import", + uri: uri, + media: mediaList, + line: importToken.startLine, + col: importToken.startCol + }); + } + + }, + + _namespace: function(emit){ + /* + * namespace + * : NAMESPACE_SYM S* [namespace_prefix S*]? [STRING|URI] S* ';' S* + */ + + var tokenStream = this._tokenStream, + line, + col, + prefix, + uri; + + //read import symbol + tokenStream.mustMatch(Tokens.NAMESPACE_SYM); + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + this._readWhitespace(); + + //it's a namespace prefix - no _namespace_prefix() method because it's just an IDENT + if (tokenStream.match(Tokens.IDENT)){ + prefix = tokenStream.token().value; + this._readWhitespace(); + } + + tokenStream.mustMatch([Tokens.STRING, Tokens.URI]); + /*if (!tokenStream.match(Tokens.STRING)){ + tokenStream.mustMatch(Tokens.URI); + }*/ + + //grab the URI value + uri = tokenStream.token().value.replace(/(?:url\()?["']([^"']+)["']\)?/, "$1"); + + this._readWhitespace(); + + //must end with a semicolon + tokenStream.mustMatch(Tokens.SEMICOLON); + this._readWhitespace(); + + if (emit !== false){ + this.fire({ + type: "namespace", + prefix: prefix, + uri: uri, + line: line, + col: col + }); + } + + }, + + _media: function(){ + /* + * media + * : MEDIA_SYM S* media_query_list S* '{' S* ruleset* '}' S* + * ; + */ + var tokenStream = this._tokenStream, + line, + col, + mediaList;// = []; + + //look for @media + tokenStream.mustMatch(Tokens.MEDIA_SYM); + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + + this._readWhitespace(); + + mediaList = this._media_query_list(); + + tokenStream.mustMatch(Tokens.LBRACE); + this._readWhitespace(); + + this.fire({ + type: "startmedia", + media: mediaList, + line: line, + col: col + }); + + while(true) { + if (tokenStream.peek() == Tokens.PAGE_SYM){ + this._page(); + } else if (tokenStream.peek() == Tokens.FONT_FACE_SYM){ + this._font_face(); + } else if (tokenStream.peek() == Tokens.VIEWPORT_SYM){ + this._viewport(); + } else if (!this._ruleset()){ + break; + } + } + + tokenStream.mustMatch(Tokens.RBRACE); + this._readWhitespace(); + + this.fire({ + type: "endmedia", + media: mediaList, + line: line, + col: col + }); + }, + + + //CSS3 Media Queries + _media_query_list: function(){ + /* + * media_query_list + * : S* [media_query [ ',' S* media_query ]* ]? + * ; + */ + var tokenStream = this._tokenStream, + mediaList = []; + + + this._readWhitespace(); + + if (tokenStream.peek() == Tokens.IDENT || tokenStream.peek() == Tokens.LPAREN){ + mediaList.push(this._media_query()); + } + + while(tokenStream.match(Tokens.COMMA)){ + this._readWhitespace(); + mediaList.push(this._media_query()); + } + + return mediaList; + }, + + /* + * Note: "expression" in the grammar maps to the _media_expression + * method. + + */ + _media_query: function(){ + /* + * media_query + * : [ONLY | NOT]? S* media_type S* [ AND S* expression ]* + * | expression [ AND S* expression ]* + * ; + */ + var tokenStream = this._tokenStream, + type = null, + ident = null, + token = null, + expressions = []; + + if (tokenStream.match(Tokens.IDENT)){ + ident = tokenStream.token().value.toLowerCase(); + + //since there's no custom tokens for these, need to manually check + if (ident != "only" && ident != "not"){ + tokenStream.unget(); + ident = null; + } else { + token = tokenStream.token(); + } + } + + this._readWhitespace(); + + if (tokenStream.peek() == Tokens.IDENT){ + type = this._media_type(); + if (token === null){ + token = tokenStream.token(); + } + } else if (tokenStream.peek() == Tokens.LPAREN){ + if (token === null){ + token = tokenStream.LT(1); + } + expressions.push(this._media_expression()); + } + + if (type === null && expressions.length === 0){ + return null; + } else { + this._readWhitespace(); + while (tokenStream.match(Tokens.IDENT)){ + if (tokenStream.token().value.toLowerCase() != "and"){ + this._unexpectedToken(tokenStream.token()); + } + + this._readWhitespace(); + expressions.push(this._media_expression()); + } + } + + return new MediaQuery(ident, type, expressions, token.startLine, token.startCol); + }, + + //CSS3 Media Queries + _media_type: function(){ + /* + * media_type + * : IDENT + * ; + */ + return this._media_feature(); + }, + + /** + * Note: in CSS3 Media Queries, this is called "expression". + * Renamed here to avoid conflict with CSS3 Selectors + * definition of "expression". Also note that "expr" in the + * grammar now maps to "expression" from CSS3 selectors. + * @method _media_expression + * @private + */ + _media_expression: function(){ + /* + * expression + * : '(' S* media_feature S* [ ':' S* expr ]? ')' S* + * ; + */ + var tokenStream = this._tokenStream, + feature = null, + token, + expression = null; + + tokenStream.mustMatch(Tokens.LPAREN); + + feature = this._media_feature(); + this._readWhitespace(); + + if (tokenStream.match(Tokens.COLON)){ + this._readWhitespace(); + token = tokenStream.LT(1); + expression = this._expression(); + } + + tokenStream.mustMatch(Tokens.RPAREN); + this._readWhitespace(); + + return new MediaFeature(feature, (expression ? new SyntaxUnit(expression, token.startLine, token.startCol) : null)); + }, + + //CSS3 Media Queries + _media_feature: function(){ + /* + * media_feature + * : IDENT + * ; + */ + var tokenStream = this._tokenStream; + + tokenStream.mustMatch(Tokens.IDENT); + + return SyntaxUnit.fromToken(tokenStream.token()); + }, + + //CSS3 Paged Media + _page: function(){ + /* + * page: + * PAGE_SYM S* IDENT? pseudo_page? S* + * '{' S* [ declaration | margin ]? [ ';' S* [ declaration | margin ]? ]* '}' S* + * ; + */ + var tokenStream = this._tokenStream, + line, + col, + identifier = null, + pseudoPage = null; + + //look for @page + tokenStream.mustMatch(Tokens.PAGE_SYM); + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + + this._readWhitespace(); + + if (tokenStream.match(Tokens.IDENT)){ + identifier = tokenStream.token().value; + + //The value 'auto' may not be used as a page name and MUST be treated as a syntax error. + if (identifier.toLowerCase() === "auto"){ + this._unexpectedToken(tokenStream.token()); + } + } + + //see if there's a colon upcoming + if (tokenStream.peek() == Tokens.COLON){ + pseudoPage = this._pseudo_page(); + } + + this._readWhitespace(); + + this.fire({ + type: "startpage", + id: identifier, + pseudo: pseudoPage, + line: line, + col: col + }); + + this._readDeclarations(true, true); + + this.fire({ + type: "endpage", + id: identifier, + pseudo: pseudoPage, + line: line, + col: col + }); + + }, + + //CSS3 Paged Media + _margin: function(){ + /* + * margin : + * margin_sym S* '{' declaration [ ';' S* declaration? ]* '}' S* + * ; + */ + var tokenStream = this._tokenStream, + line, + col, + marginSym = this._margin_sym(); + + if (marginSym){ + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + + this.fire({ + type: "startpagemargin", + margin: marginSym, + line: line, + col: col + }); + + this._readDeclarations(true); + + this.fire({ + type: "endpagemargin", + margin: marginSym, + line: line, + col: col + }); + return true; + } else { + return false; + } + }, + + //CSS3 Paged Media + _margin_sym: function(){ + + /* + * margin_sym : + * TOPLEFTCORNER_SYM | + * TOPLEFT_SYM | + * TOPCENTER_SYM | + * TOPRIGHT_SYM | + * TOPRIGHTCORNER_SYM | + * BOTTOMLEFTCORNER_SYM | + * BOTTOMLEFT_SYM | + * BOTTOMCENTER_SYM | + * BOTTOMRIGHT_SYM | + * BOTTOMRIGHTCORNER_SYM | + * LEFTTOP_SYM | + * LEFTMIDDLE_SYM | + * LEFTBOTTOM_SYM | + * RIGHTTOP_SYM | + * RIGHTMIDDLE_SYM | + * RIGHTBOTTOM_SYM + * ; + */ + + var tokenStream = this._tokenStream; + + if(tokenStream.match([Tokens.TOPLEFTCORNER_SYM, Tokens.TOPLEFT_SYM, + Tokens.TOPCENTER_SYM, Tokens.TOPRIGHT_SYM, Tokens.TOPRIGHTCORNER_SYM, + Tokens.BOTTOMLEFTCORNER_SYM, Tokens.BOTTOMLEFT_SYM, + Tokens.BOTTOMCENTER_SYM, Tokens.BOTTOMRIGHT_SYM, + Tokens.BOTTOMRIGHTCORNER_SYM, Tokens.LEFTTOP_SYM, + Tokens.LEFTMIDDLE_SYM, Tokens.LEFTBOTTOM_SYM, Tokens.RIGHTTOP_SYM, + Tokens.RIGHTMIDDLE_SYM, Tokens.RIGHTBOTTOM_SYM])) + { + return SyntaxUnit.fromToken(tokenStream.token()); + } else { + return null; + } + + }, + + _pseudo_page: function(){ + /* + * pseudo_page + * : ':' IDENT + * ; + */ + + var tokenStream = this._tokenStream; + + tokenStream.mustMatch(Tokens.COLON); + tokenStream.mustMatch(Tokens.IDENT); + + //TODO: CSS3 Paged Media says only "left", "center", and "right" are allowed + + return tokenStream.token().value; + }, + + _font_face: function(){ + /* + * font_face + * : FONT_FACE_SYM S* + * '{' S* declaration [ ';' S* declaration ]* '}' S* + * ; + */ + var tokenStream = this._tokenStream, + line, + col; + + //look for @page + tokenStream.mustMatch(Tokens.FONT_FACE_SYM); + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + + this._readWhitespace(); + + this.fire({ + type: "startfontface", + line: line, + col: col + }); + + this._readDeclarations(true); + + this.fire({ + type: "endfontface", + line: line, + col: col + }); + }, + + _viewport: function(){ + /* + * viewport + * : VIEWPORT_SYM S* + * '{' S* declaration? [ ';' S* declaration? ]* '}' S* + * ; + */ + var tokenStream = this._tokenStream, + line, + col; + + tokenStream.mustMatch(Tokens.VIEWPORT_SYM); + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + + this._readWhitespace(); + + this.fire({ + type: "startviewport", + line: line, + col: col + }); + + this._readDeclarations(true); + + this.fire({ + type: "endviewport", + line: line, + col: col + }); + + }, + + _operator: function(inFunction){ + + /* + * operator (outside function) + * : '/' S* | ',' S* | /( empty )/ + * operator (inside function) + * : '/' S* | '+' S* | '*' S* | '-' S* /( empty )/ + * ; + */ + + var tokenStream = this._tokenStream, + token = null; + + if (tokenStream.match([Tokens.SLASH, Tokens.COMMA]) || + (inFunction && tokenStream.match([Tokens.PLUS, Tokens.STAR, Tokens.MINUS]))){ + token = tokenStream.token(); + this._readWhitespace(); + } + return token ? PropertyValuePart.fromToken(token) : null; + + }, + + _combinator: function(){ + + /* + * combinator + * : PLUS S* | GREATER S* | TILDE S* | S+ + * ; + */ + + var tokenStream = this._tokenStream, + value = null, + token; + + if(tokenStream.match([Tokens.PLUS, Tokens.GREATER, Tokens.TILDE])){ + token = tokenStream.token(); + value = new Combinator(token.value, token.startLine, token.startCol); + this._readWhitespace(); + } + + return value; + }, + + _unary_operator: function(){ + + /* + * unary_operator + * : '-' | '+' + * ; + */ + + var tokenStream = this._tokenStream; + + if (tokenStream.match([Tokens.MINUS, Tokens.PLUS])){ + return tokenStream.token().value; + } else { + return null; + } + }, + + _property: function(){ + + /* + * property + * : IDENT S* + * ; + */ + + var tokenStream = this._tokenStream, + value = null, + hack = null, + tokenValue, + token, + line, + col; + + //check for star hack - throws error if not allowed + if (tokenStream.peek() == Tokens.STAR && this.options.starHack){ + tokenStream.get(); + token = tokenStream.token(); + hack = token.value; + line = token.startLine; + col = token.startCol; + } + + if(tokenStream.match(Tokens.IDENT)){ + token = tokenStream.token(); + tokenValue = token.value; + + //check for underscore hack - no error if not allowed because it's valid CSS syntax + if (tokenValue.charAt(0) == "_" && this.options.underscoreHack){ + hack = "_"; + tokenValue = tokenValue.substring(1); + } + + value = new PropertyName(tokenValue, hack, (line||token.startLine), (col||token.startCol)); + this._readWhitespace(); + } + + return value; + }, + + //Augmented with CSS3 Selectors + _ruleset: function(){ + /* + * ruleset + * : selectors_group + * '{' S* declaration? [ ';' S* declaration? ]* '}' S* + * ; + */ + + var tokenStream = this._tokenStream, + tt, + selectors; + + + /* + * Error Recovery: If even a single selector fails to parse, + * then the entire ruleset should be thrown away. + */ + try { + selectors = this._selectors_group(); + } catch (ex){ + if (ex instanceof SyntaxError && !this.options.strict){ + + //fire error event + this.fire({ + type: "error", + error: ex, + message: ex.message, + line: ex.line, + col: ex.col + }); + + //skip over everything until closing brace + tt = tokenStream.advance([Tokens.RBRACE]); + if (tt == Tokens.RBRACE){ + //if there's a right brace, the rule is finished so don't do anything + } else { + //otherwise, rethrow the error because it wasn't handled properly + throw ex; + } + + } else { + //not a syntax error, rethrow it + throw ex; + } + + //trigger parser to continue + return true; + } + + //if it got here, all selectors parsed + if (selectors){ + + this.fire({ + type: "startrule", + selectors: selectors, + line: selectors[0].line, + col: selectors[0].col + }); + + this._readDeclarations(true); + + this.fire({ + type: "endrule", + selectors: selectors, + line: selectors[0].line, + col: selectors[0].col + }); + + } + + return selectors; + + }, + + //CSS3 Selectors + _selectors_group: function(){ + + /* + * selectors_group + * : selector [ COMMA S* selector ]* + * ; + */ + var tokenStream = this._tokenStream, + selectors = [], + selector; + + selector = this._selector(); + if (selector !== null){ + + selectors.push(selector); + while(tokenStream.match(Tokens.COMMA)){ + this._readWhitespace(); + selector = this._selector(); + if (selector !== null){ + selectors.push(selector); + } else { + this._unexpectedToken(tokenStream.LT(1)); + } + } + } + + return selectors.length ? selectors : null; + }, + + //CSS3 Selectors + _selector: function(){ + /* + * selector + * : simple_selector_sequence [ combinator simple_selector_sequence ]* + * ; + */ + + var tokenStream = this._tokenStream, + selector = [], + nextSelector = null, + combinator = null, + ws = null; + + //if there's no simple selector, then there's no selector + nextSelector = this._simple_selector_sequence(); + if (nextSelector === null){ + return null; + } + + selector.push(nextSelector); + + do { + + //look for a combinator + combinator = this._combinator(); + + if (combinator !== null){ + selector.push(combinator); + nextSelector = this._simple_selector_sequence(); + + //there must be a next selector + if (nextSelector === null){ + this._unexpectedToken(tokenStream.LT(1)); + } else { + + //nextSelector is an instance of SelectorPart + selector.push(nextSelector); + } + } else { + + //if there's not whitespace, we're done + if (this._readWhitespace()){ + + //add whitespace separator + ws = new Combinator(tokenStream.token().value, tokenStream.token().startLine, tokenStream.token().startCol); + + //combinator is not required + combinator = this._combinator(); + + //selector is required if there's a combinator + nextSelector = this._simple_selector_sequence(); + if (nextSelector === null){ + if (combinator !== null){ + this._unexpectedToken(tokenStream.LT(1)); + } + } else { + + if (combinator !== null){ + selector.push(combinator); + } else { + selector.push(ws); + } + + selector.push(nextSelector); + } + } else { + break; + } + + } + } while(true); + + return new Selector(selector, selector[0].line, selector[0].col); + }, + + //CSS3 Selectors + _simple_selector_sequence: function(){ + /* + * simple_selector_sequence + * : [ type_selector | universal ] + * [ HASH | class | attrib | pseudo | negation ]* + * | [ HASH | class | attrib | pseudo | negation ]+ + * ; + */ + + var tokenStream = this._tokenStream, + + //parts of a simple selector + elementName = null, + modifiers = [], + + //complete selector text + selectorText= "", + + //the different parts after the element name to search for + components = [ + //HASH + function(){ + return tokenStream.match(Tokens.HASH) ? + new SelectorSubPart(tokenStream.token().value, "id", tokenStream.token().startLine, tokenStream.token().startCol) : + null; + }, + this._class, + this._attrib, + this._pseudo, + this._negation + ], + i = 0, + len = components.length, + component = null, + found = false, + line, + col; + + + //get starting line and column for the selector + line = tokenStream.LT(1).startLine; + col = tokenStream.LT(1).startCol; + + elementName = this._type_selector(); + if (!elementName){ + elementName = this._universal(); + } + + if (elementName !== null){ + selectorText += elementName; + } + + while(true){ + + //whitespace means we're done + if (tokenStream.peek() === Tokens.S){ + break; + } + + //check for each component + while(i < len && component === null){ + component = components[i++].call(this); + } + + if (component === null){ + + //we don't have a selector + if (selectorText === ""){ + return null; + } else { + break; + } + } else { + i = 0; + modifiers.push(component); + selectorText += component.toString(); + component = null; + } + } + + + return selectorText !== "" ? + new SelectorPart(elementName, modifiers, selectorText, line, col) : + null; + }, + + //CSS3 Selectors + _type_selector: function(){ + /* + * type_selector + * : [ namespace_prefix ]? element_name + * ; + */ + + var tokenStream = this._tokenStream, + ns = this._namespace_prefix(), + elementName = this._element_name(); + + if (!elementName){ + /* + * Need to back out the namespace that was read due to both + * type_selector and universal reading namespace_prefix + * first. Kind of hacky, but only way I can figure out + * right now how to not change the grammar. + */ + if (ns){ + tokenStream.unget(); + if (ns.length > 1){ + tokenStream.unget(); + } + } + + return null; + } else { + if (ns){ + elementName.text = ns + elementName.text; + elementName.col -= ns.length; + } + return elementName; + } + }, + + //CSS3 Selectors + _class: function(){ + /* + * class + * : '.' IDENT + * ; + */ + + var tokenStream = this._tokenStream, + token; + + if (tokenStream.match(Tokens.DOT)){ + tokenStream.mustMatch(Tokens.IDENT); + token = tokenStream.token(); + return new SelectorSubPart("." + token.value, "class", token.startLine, token.startCol - 1); + } else { + return null; + } + + }, + + //CSS3 Selectors + _element_name: function(){ + /* + * element_name + * : IDENT + * ; + */ + + var tokenStream = this._tokenStream, + token; + + if (tokenStream.match(Tokens.IDENT)){ + token = tokenStream.token(); + return new SelectorSubPart(token.value, "elementName", token.startLine, token.startCol); + + } else { + return null; + } + }, + + //CSS3 Selectors + _namespace_prefix: function(){ + /* + * namespace_prefix + * : [ IDENT | '*' ]? '|' + * ; + */ + var tokenStream = this._tokenStream, + value = ""; + + //verify that this is a namespace prefix + if (tokenStream.LA(1) === Tokens.PIPE || tokenStream.LA(2) === Tokens.PIPE){ + + if(tokenStream.match([Tokens.IDENT, Tokens.STAR])){ + value += tokenStream.token().value; + } + + tokenStream.mustMatch(Tokens.PIPE); + value += "|"; + + } + + return value.length ? value : null; + }, + + //CSS3 Selectors + _universal: function(){ + /* + * universal + * : [ namespace_prefix ]? '*' + * ; + */ + var tokenStream = this._tokenStream, + value = "", + ns; + + ns = this._namespace_prefix(); + if(ns){ + value += ns; + } + + if(tokenStream.match(Tokens.STAR)){ + value += "*"; + } + + return value.length ? value : null; + + }, + + //CSS3 Selectors + _attrib: function(){ + /* + * attrib + * : '[' S* [ namespace_prefix ]? IDENT S* + * [ [ PREFIXMATCH | + * SUFFIXMATCH | + * SUBSTRINGMATCH | + * '=' | + * INCLUDES | + * DASHMATCH ] S* [ IDENT | STRING ] S* + * ]? ']' + * ; + */ + + var tokenStream = this._tokenStream, + value = null, + ns, + token; + + if (tokenStream.match(Tokens.LBRACKET)){ + token = tokenStream.token(); + value = token.value; + value += this._readWhitespace(); + + ns = this._namespace_prefix(); + + if (ns){ + value += ns; + } + + tokenStream.mustMatch(Tokens.IDENT); + value += tokenStream.token().value; + value += this._readWhitespace(); + + if(tokenStream.match([Tokens.PREFIXMATCH, Tokens.SUFFIXMATCH, Tokens.SUBSTRINGMATCH, + Tokens.EQUALS, Tokens.INCLUDES, Tokens.DASHMATCH])){ + + value += tokenStream.token().value; + value += this._readWhitespace(); + + tokenStream.mustMatch([Tokens.IDENT, Tokens.STRING]); + value += tokenStream.token().value; + value += this._readWhitespace(); + } + + tokenStream.mustMatch(Tokens.RBRACKET); + + return new SelectorSubPart(value + "]", "attribute", token.startLine, token.startCol); + } else { + return null; + } + }, + + //CSS3 Selectors + _pseudo: function(){ + + /* + * pseudo + * : ':' ':'? [ IDENT | functional_pseudo ] + * ; + */ + + var tokenStream = this._tokenStream, + pseudo = null, + colons = ":", + line, + col; + + if (tokenStream.match(Tokens.COLON)){ + + if (tokenStream.match(Tokens.COLON)){ + colons += ":"; + } + + if (tokenStream.match(Tokens.IDENT)){ + pseudo = tokenStream.token().value; + line = tokenStream.token().startLine; + col = tokenStream.token().startCol - colons.length; + } else if (tokenStream.peek() == Tokens.FUNCTION){ + line = tokenStream.LT(1).startLine; + col = tokenStream.LT(1).startCol - colons.length; + pseudo = this._functional_pseudo(); + } + + if (pseudo){ + pseudo = new SelectorSubPart(colons + pseudo, "pseudo", line, col); + } + } + + return pseudo; + }, + + //CSS3 Selectors + _functional_pseudo: function(){ + /* + * functional_pseudo + * : FUNCTION S* expression ')' + * ; + */ + + var tokenStream = this._tokenStream, + value = null; + + if(tokenStream.match(Tokens.FUNCTION)){ + value = tokenStream.token().value; + value += this._readWhitespace(); + value += this._expression(); + tokenStream.mustMatch(Tokens.RPAREN); + value += ")"; + } + + return value; + }, + + //CSS3 Selectors + _expression: function(){ + /* + * expression + * : [ [ PLUS | '-' | DIMENSION | NUMBER | STRING | IDENT ] S* ]+ + * ; + */ + + var tokenStream = this._tokenStream, + value = ""; + + while(tokenStream.match([Tokens.PLUS, Tokens.MINUS, Tokens.DIMENSION, + Tokens.NUMBER, Tokens.STRING, Tokens.IDENT, Tokens.LENGTH, + Tokens.FREQ, Tokens.ANGLE, Tokens.TIME, + Tokens.RESOLUTION, Tokens.SLASH])){ + + value += tokenStream.token().value; + value += this._readWhitespace(); + } + + return value.length ? value : null; + + }, + + //CSS3 Selectors + _negation: function(){ + /* + * negation + * : NOT S* negation_arg S* ')' + * ; + */ + + var tokenStream = this._tokenStream, + line, + col, + value = "", + arg, + subpart = null; + + if (tokenStream.match(Tokens.NOT)){ + value = tokenStream.token().value; + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + value += this._readWhitespace(); + arg = this._negation_arg(); + value += arg; + value += this._readWhitespace(); + tokenStream.match(Tokens.RPAREN); + value += tokenStream.token().value; + + subpart = new SelectorSubPart(value, "not", line, col); + subpart.args.push(arg); + } + + return subpart; + }, + + //CSS3 Selectors + _negation_arg: function(){ + /* + * negation_arg + * : type_selector | universal | HASH | class | attrib | pseudo + * ; + */ + + var tokenStream = this._tokenStream, + args = [ + this._type_selector, + this._universal, + function(){ + return tokenStream.match(Tokens.HASH) ? + new SelectorSubPart(tokenStream.token().value, "id", tokenStream.token().startLine, tokenStream.token().startCol) : + null; + }, + this._class, + this._attrib, + this._pseudo + ], + arg = null, + i = 0, + len = args.length, + elementName, + line, + col, + part; + + line = tokenStream.LT(1).startLine; + col = tokenStream.LT(1).startCol; + + while(i < len && arg === null){ + + arg = args[i].call(this); + i++; + } + + //must be a negation arg + if (arg === null){ + this._unexpectedToken(tokenStream.LT(1)); + } + + //it's an element name + if (arg.type == "elementName"){ + part = new SelectorPart(arg, [], arg.toString(), line, col); + } else { + part = new SelectorPart(null, [arg], arg.toString(), line, col); + } + + return part; + }, + + _declaration: function(){ + + /* + * declaration + * : property ':' S* expr prio? + * | /( empty )/ + * ; + */ + + var tokenStream = this._tokenStream, + property = null, + expr = null, + prio = null, + error = null, + invalid = null, + propertyName= ""; + + property = this._property(); + if (property !== null){ + + tokenStream.mustMatch(Tokens.COLON); + this._readWhitespace(); + + expr = this._expr(); + + //if there's no parts for the value, it's an error + if (!expr || expr.length === 0){ + this._unexpectedToken(tokenStream.LT(1)); + } + + prio = this._prio(); + + /* + * If hacks should be allowed, then only check the root + * property. If hacks should not be allowed, treat + * _property or *property as invalid properties. + */ + propertyName = property.toString(); + if (this.options.starHack && property.hack == "*" || + this.options.underscoreHack && property.hack == "_") { + + propertyName = property.text; + } + + try { + this._validateProperty(propertyName, expr); + } catch (ex) { + invalid = ex; + } + + this.fire({ + type: "property", + property: property, + value: expr, + important: prio, + line: property.line, + col: property.col, + invalid: invalid + }); + + return true; + } else { + return false; + } + }, + + _prio: function(){ + /* + * prio + * : IMPORTANT_SYM S* + * ; + */ + + var tokenStream = this._tokenStream, + result = tokenStream.match(Tokens.IMPORTANT_SYM); + + this._readWhitespace(); + return result; + }, + + _expr: function(inFunction){ + /* + * expr + * : term [ operator term ]* + * ; + */ + + var tokenStream = this._tokenStream, + values = [], + //valueParts = [], + value = null, + operator = null; + + value = this._term(inFunction); + if (value !== null){ + + values.push(value); + + do { + operator = this._operator(inFunction); + + //if there's an operator, keep building up the value parts + if (operator){ + values.push(operator); + } /*else { + //if there's not an operator, you have a full value + values.push(new PropertyValue(valueParts, valueParts[0].line, valueParts[0].col)); + valueParts = []; + }*/ + + value = this._term(inFunction); + + if (value === null){ + break; + } else { + values.push(value); + } + } while(true); + } + + //cleanup + /*if (valueParts.length){ + values.push(new PropertyValue(valueParts, valueParts[0].line, valueParts[0].col)); + }*/ + + return values.length > 0 ? new PropertyValue(values, values[0].line, values[0].col) : null; + }, + + _term: function(inFunction){ + + /* + * term + * : unary_operator? + * [ NUMBER S* | PERCENTAGE S* | LENGTH S* | ANGLE S* | + * TIME S* | FREQ S* | function | ie_function ] + * | STRING S* | IDENT S* | URI S* | UNICODERANGE S* | hexcolor + * ; + */ + + var tokenStream = this._tokenStream, + unary = null, + value = null, + endChar = null, + token, + line, + col; + + //returns the operator or null + unary = this._unary_operator(); + if (unary !== null){ + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + } + + //exception for IE filters + if (tokenStream.peek() == Tokens.IE_FUNCTION && this.options.ieFilters){ + + value = this._ie_function(); + if (unary === null){ + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + } + + //see if it's a simple block + } else if (inFunction && tokenStream.match([Tokens.LPAREN, Tokens.LBRACE, Tokens.LBRACKET])){ + + token = tokenStream.token(); + endChar = token.endChar; + value = token.value + this._expr(inFunction).text; + if (unary === null){ + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + } + tokenStream.mustMatch(Tokens.type(endChar)); + value += endChar; + this._readWhitespace(); + + //see if there's a simple match + } else if (tokenStream.match([Tokens.NUMBER, Tokens.PERCENTAGE, Tokens.LENGTH, + Tokens.ANGLE, Tokens.TIME, + Tokens.FREQ, Tokens.STRING, Tokens.IDENT, Tokens.URI, Tokens.UNICODE_RANGE])){ + + value = tokenStream.token().value; + if (unary === null){ + line = tokenStream.token().startLine; + col = tokenStream.token().startCol; + } + this._readWhitespace(); + } else { + + //see if it's a color + token = this._hexcolor(); + if (token === null){ + + //if there's no unary, get the start of the next token for line/col info + if (unary === null){ + line = tokenStream.LT(1).startLine; + col = tokenStream.LT(1).startCol; + } + + //has to be a function + if (value === null){ + + /* + * This checks for alpha(opacity=0) style of IE + * functions. IE_FUNCTION only presents progid: style. + */ + if (tokenStream.LA(3) == Tokens.EQUALS && this.options.ieFilters){ + value = this._ie_function(); + } else { + value = this._function(); + } + } + + /*if (value === null){ + return null; + //throw new Error("Expected identifier at line " + tokenStream.token().startLine + ", character " + tokenStream.token().startCol + "."); + }*/ + + } else { + value = token.value; + if (unary === null){ + line = token.startLine; + col = token.startCol; + } + } + + } + + return value !== null ? + new PropertyValuePart(unary !== null ? unary + value : value, line, col) : + null; + + }, + + _function: function(){ + + /* + * function + * : FUNCTION S* expr ')' S* + * ; + */ + + var tokenStream = this._tokenStream, + functionText = null, + expr = null, + lt; + + if (tokenStream.match(Tokens.FUNCTION)){ + functionText = tokenStream.token().value; + this._readWhitespace(); + expr = this._expr(true); + functionText += expr; + + //START: Horrible hack in case it's an IE filter + if (this.options.ieFilters && tokenStream.peek() == Tokens.EQUALS){ + do { + + if (this._readWhitespace()){ + functionText += tokenStream.token().value; + } + + //might be second time in the loop + if (tokenStream.LA(0) == Tokens.COMMA){ + functionText += tokenStream.token().value; + } + + tokenStream.match(Tokens.IDENT); + functionText += tokenStream.token().value; + + tokenStream.match(Tokens.EQUALS); + functionText += tokenStream.token().value; + + //functionText += this._term(); + lt = tokenStream.peek(); + while(lt != Tokens.COMMA && lt != Tokens.S && lt != Tokens.RPAREN){ + tokenStream.get(); + functionText += tokenStream.token().value; + lt = tokenStream.peek(); + } + } while(tokenStream.match([Tokens.COMMA, Tokens.S])); + } + + //END: Horrible Hack + + tokenStream.match(Tokens.RPAREN); + functionText += ")"; + this._readWhitespace(); + } + + return functionText; + }, + + _ie_function: function(){ + + /* (My own extension) + * ie_function + * : IE_FUNCTION S* IDENT '=' term [S* ','? IDENT '=' term]+ ')' S* + * ; + */ + + var tokenStream = this._tokenStream, + functionText = null, + expr = null, + lt; + + //IE function can begin like a regular function, too + if (tokenStream.match([Tokens.IE_FUNCTION, Tokens.FUNCTION])){ + functionText = tokenStream.token().value; + + do { + + if (this._readWhitespace()){ + functionText += tokenStream.token().value; + } + + //might be second time in the loop + if (tokenStream.LA(0) == Tokens.COMMA){ + functionText += tokenStream.token().value; + } + + tokenStream.match(Tokens.IDENT); + functionText += tokenStream.token().value; + + tokenStream.match(Tokens.EQUALS); + functionText += tokenStream.token().value; + + //functionText += this._term(); + lt = tokenStream.peek(); + while(lt != Tokens.COMMA && lt != Tokens.S && lt != Tokens.RPAREN){ + tokenStream.get(); + functionText += tokenStream.token().value; + lt = tokenStream.peek(); + } + } while(tokenStream.match([Tokens.COMMA, Tokens.S])); + + tokenStream.match(Tokens.RPAREN); + functionText += ")"; + this._readWhitespace(); + } + + return functionText; + }, + + _hexcolor: function(){ + /* + * There is a constraint on the color that it must + * have either 3 or 6 hex-digits (i.e., [0-9a-fA-F]) + * after the "#"; e.g., "#000" is OK, but "#abcd" is not. + * + * hexcolor + * : HASH S* + * ; + */ + + var tokenStream = this._tokenStream, + token = null, + color; + + if(tokenStream.match(Tokens.HASH)){ + + //need to do some validation here + + token = tokenStream.token(); + color = token.value; + if (!/#[a-f0-9]{3,6}/i.test(color)){ + throw new SyntaxError("Expected a hex color but found '" + color + "' at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol); + } + this._readWhitespace(); + } + + return token; + }, + + //----------------------------------------------------------------- + // Animations methods + //----------------------------------------------------------------- + + _keyframes: function(){ + + /* + * keyframes: + * : KEYFRAMES_SYM S* keyframe_name S* '{' S* keyframe_rule* '}' { + * ; + */ + var tokenStream = this._tokenStream, + token, + tt, + name, + prefix = ""; + + tokenStream.mustMatch(Tokens.KEYFRAMES_SYM); + token = tokenStream.token(); + if (/^@\-([^\-]+)\-/.test(token.value)) { + prefix = RegExp.$1; + } + + this._readWhitespace(); + name = this._keyframe_name(); + + this._readWhitespace(); + tokenStream.mustMatch(Tokens.LBRACE); + + this.fire({ + type: "startkeyframes", + name: name, + prefix: prefix, + line: token.startLine, + col: token.startCol + }); + + this._readWhitespace(); + tt = tokenStream.peek(); + + //check for key + while(tt == Tokens.IDENT || tt == Tokens.PERCENTAGE) { + this._keyframe_rule(); + this._readWhitespace(); + tt = tokenStream.peek(); + } + + this.fire({ + type: "endkeyframes", + name: name, + prefix: prefix, + line: token.startLine, + col: token.startCol + }); + + this._readWhitespace(); + tokenStream.mustMatch(Tokens.RBRACE); + + }, + + _keyframe_name: function(){ + + /* + * keyframe_name: + * : IDENT + * | STRING + * ; + */ + var tokenStream = this._tokenStream, + token; + + tokenStream.mustMatch([Tokens.IDENT, Tokens.STRING]); + return SyntaxUnit.fromToken(tokenStream.token()); + }, + + _keyframe_rule: function(){ + + /* + * keyframe_rule: + * : key_list S* + * '{' S* declaration [ ';' S* declaration ]* '}' S* + * ; + */ + var tokenStream = this._tokenStream, + token, + keyList = this._key_list(); + + this.fire({ + type: "startkeyframerule", + keys: keyList, + line: keyList[0].line, + col: keyList[0].col + }); + + this._readDeclarations(true); + + this.fire({ + type: "endkeyframerule", + keys: keyList, + line: keyList[0].line, + col: keyList[0].col + }); + + }, + + _key_list: function(){ + + /* + * key_list: + * : key [ S* ',' S* key]* + * ; + */ + var tokenStream = this._tokenStream, + token, + key, + keyList = []; + + //must be least one key + keyList.push(this._key()); + + this._readWhitespace(); + + while(tokenStream.match(Tokens.COMMA)){ + this._readWhitespace(); + keyList.push(this._key()); + this._readWhitespace(); + } + + return keyList; + }, + + _key: function(){ + /* + * There is a restriction that IDENT can be only "from" or "to". + * + * key + * : PERCENTAGE + * | IDENT + * ; + */ + + var tokenStream = this._tokenStream, + token; + + if (tokenStream.match(Tokens.PERCENTAGE)){ + return SyntaxUnit.fromToken(tokenStream.token()); + } else if (tokenStream.match(Tokens.IDENT)){ + token = tokenStream.token(); + + if (/from|to/i.test(token.value)){ + return SyntaxUnit.fromToken(token); + } + + tokenStream.unget(); + } + + //if it gets here, there wasn't a valid token, so time to explode + this._unexpectedToken(tokenStream.LT(1)); + }, + + //----------------------------------------------------------------- + // Helper methods + //----------------------------------------------------------------- + + /** + * Not part of CSS grammar, but useful for skipping over + * combination of white space and HTML-style comments. + * @return {void} + * @method _skipCruft + * @private + */ + _skipCruft: function(){ + while(this._tokenStream.match([Tokens.S, Tokens.CDO, Tokens.CDC])){ + //noop + } + }, + + /** + * Not part of CSS grammar, but this pattern occurs frequently + * in the official CSS grammar. Split out here to eliminate + * duplicate code. + * @param {Boolean} checkStart Indicates if the rule should check + * for the left brace at the beginning. + * @param {Boolean} readMargins Indicates if the rule should check + * for margin patterns. + * @return {void} + * @method _readDeclarations + * @private + */ + _readDeclarations: function(checkStart, readMargins){ + /* + * Reads the pattern + * S* '{' S* declaration [ ';' S* declaration ]* '}' S* + * or + * S* '{' S* [ declaration | margin ]? [ ';' S* [ declaration | margin ]? ]* '}' S* + * Note that this is how it is described in CSS3 Paged Media, but is actually incorrect. + * A semicolon is only necessary following a declaration is there's another declaration + * or margin afterwards. + */ + var tokenStream = this._tokenStream, + tt; + + + this._readWhitespace(); + + if (checkStart){ + tokenStream.mustMatch(Tokens.LBRACE); + } + + this._readWhitespace(); + + try { + + while(true){ + + if (tokenStream.match(Tokens.SEMICOLON) || (readMargins && this._margin())){ + //noop + } else if (this._declaration()){ + if (!tokenStream.match(Tokens.SEMICOLON)){ + break; + } + } else { + break; + } + + //if ((!this._margin() && !this._declaration()) || !tokenStream.match(Tokens.SEMICOLON)){ + // break; + //} + this._readWhitespace(); + } + + tokenStream.mustMatch(Tokens.RBRACE); + this._readWhitespace(); + + } catch (ex) { + if (ex instanceof SyntaxError && !this.options.strict){ + + //fire error event + this.fire({ + type: "error", + error: ex, + message: ex.message, + line: ex.line, + col: ex.col + }); + + //see if there's another declaration + tt = tokenStream.advance([Tokens.SEMICOLON, Tokens.RBRACE]); + if (tt == Tokens.SEMICOLON){ + //if there's a semicolon, then there might be another declaration + this._readDeclarations(false, readMargins); + } else if (tt != Tokens.RBRACE){ + //if there's a right brace, the rule is finished so don't do anything + //otherwise, rethrow the error because it wasn't handled properly + throw ex; + } + + } else { + //not a syntax error, rethrow it + throw ex; + } + } + + }, + + /** + * In some cases, you can end up with two white space tokens in a + * row. Instead of making a change in every function that looks for + * white space, this function is used to match as much white space + * as necessary. + * @method _readWhitespace + * @return {String} The white space if found, empty string if not. + * @private + */ + _readWhitespace: function(){ + + var tokenStream = this._tokenStream, + ws = ""; + + while(tokenStream.match(Tokens.S)){ + ws += tokenStream.token().value; + } + + return ws; + }, + + + /** + * Throws an error when an unexpected token is found. + * @param {Object} token The token that was found. + * @method _unexpectedToken + * @return {void} + * @private + */ + _unexpectedToken: function(token){ + throw new SyntaxError("Unexpected token '" + token.value + "' at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol); + }, + + /** + * Helper method used for parsing subparts of a style sheet. + * @return {void} + * @method _verifyEnd + * @private + */ + _verifyEnd: function(){ + if (this._tokenStream.LA(1) != Tokens.EOF){ + this._unexpectedToken(this._tokenStream.LT(1)); + } + }, + + //----------------------------------------------------------------- + // Validation methods + //----------------------------------------------------------------- + _validateProperty: function(property, value){ + Validation.validate(property, value); + }, + + //----------------------------------------------------------------- + // Parsing methods + //----------------------------------------------------------------- + + parse: function(input){ + this._tokenStream = new TokenStream(input, Tokens); + this._stylesheet(); + }, + + parseStyleSheet: function(input){ + //just passthrough + return this.parse(input); + }, + + parseMediaQuery: function(input){ + this._tokenStream = new TokenStream(input, Tokens); + var result = this._media_query(); + + //if there's anything more, then it's an invalid selector + this._verifyEnd(); + + //otherwise return result + return result; + }, + + /** + * Parses a property value (everything after the semicolon). + * @return {parserlib.css.PropertyValue} The property value. + * @throws parserlib.util.SyntaxError If an unexpected token is found. + * @method parserPropertyValue + */ + parsePropertyValue: function(input){ + + this._tokenStream = new TokenStream(input, Tokens); + this._readWhitespace(); + + var result = this._expr(); + + //okay to have a trailing white space + this._readWhitespace(); + + //if there's anything more, then it's an invalid selector + this._verifyEnd(); + + //otherwise return result + return result; + }, + + /** + * Parses a complete CSS rule, including selectors and + * properties. + * @param {String} input The text to parser. + * @return {Boolean} True if the parse completed successfully, false if not. + * @method parseRule + */ + parseRule: function(input){ + this._tokenStream = new TokenStream(input, Tokens); + + //skip any leading white space + this._readWhitespace(); + + var result = this._ruleset(); + + //skip any trailing white space + this._readWhitespace(); + + //if there's anything more, then it's an invalid selector + this._verifyEnd(); + + //otherwise return result + return result; + }, + + /** + * Parses a single CSS selector (no comma) + * @param {String} input The text to parse as a CSS selector. + * @return {Selector} An object representing the selector. + * @throws parserlib.util.SyntaxError If an unexpected token is found. + * @method parseSelector + */ + parseSelector: function(input){ + + this._tokenStream = new TokenStream(input, Tokens); + + //skip any leading white space + this._readWhitespace(); + + var result = this._selector(); + + //skip any trailing white space + this._readWhitespace(); + + //if there's anything more, then it's an invalid selector + this._verifyEnd(); + + //otherwise return result + return result; + }, + + /** + * Parses an HTML style attribute: a set of CSS declarations + * separated by semicolons. + * @param {String} input The text to parse as a style attribute + * @return {void} + * @method parseStyleAttribute + */ + parseStyleAttribute: function(input){ + input += "}"; // for error recovery in _readDeclarations() + this._tokenStream = new TokenStream(input, Tokens); + this._readDeclarations(); + } + }; + + //copy over onto prototype + for (prop in additions){ + if (additions.hasOwnProperty(prop)){ + proto[prop] = additions[prop]; + } + } + + return proto; +}(); + + +/* +nth + : S* [ ['-'|'+']? INTEGER? {N} [ S* ['-'|'+'] S* INTEGER ]? | + ['-'|'+']? INTEGER | {O}{D}{D} | {E}{V}{E}{N} ] S* + ; +*/ +/*global Validation, ValidationTypes, ValidationError*/ +var Properties = { + + //A + "align-items" : "flex-start | flex-end | center | baseline | stretch", + "align-content" : "flex-start | flex-end | center | space-between | space-around | stretch", + "align-self" : "auto | flex-start | flex-end | center | baseline | stretch", + "-webkit-align-items" : "flex-start | flex-end | center | baseline | stretch", + "-webkit-align-content" : "flex-start | flex-end | center | space-between | space-around | stretch", + "-webkit-align-self" : "auto | flex-start | flex-end | center | baseline | stretch", + "alignment-adjust" : "auto | baseline | before-edge | text-before-edge | middle | central | after-edge | text-after-edge | ideographic | alphabetic | hanging | mathematical | | ", + "alignment-baseline" : "baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical", + "animation" : 1, + "animation-delay" : { multi: "
    2. ").text(item.description).addClass(item.done ? "done": ""); + listItem.append($(" + + + + + \ No newline at end of file diff --git a/node_modules/frontdoor/frontdoor.js b/node_modules/frontdoor/frontdoor.js new file mode 100644 index 00000000..b9e61a28 --- /dev/null +++ b/node_modules/frontdoor/frontdoor.js @@ -0,0 +1,20 @@ +"use strict"; + +require("amd-loader"); + +var Route = require("./lib/route"); +var Section = require("./lib/section"); +var Types = require("./lib/types"); +var middleware = require("./lib/middleware"); +var Api = require("./lib/api"); + +module.exports = function(description) { + return new Api(description); +}; + +module.exports.Section = Section; +module.exports.Route = Route; +module.exports.Types = Types; +module.exports.middleware = middleware; + + diff --git a/node_modules/frontdoor/lib/api-client.js b/node_modules/frontdoor/lib/api-client.js new file mode 100644 index 00000000..f181c770 --- /dev/null +++ b/node_modules/frontdoor/lib/api-client.js @@ -0,0 +1,128 @@ +define(function(require, exports, module) { + "use strict"; + + var assert = require("assert"); + var format = require("util").format; + var join = require("path").join; + + module.exports = createClient; + createClient.buildApi = buildApi; + + function createClient(endpoint, options, callback) { + if (!callback) + return createClient(endpoint, {}, options); + + var baseUrl = options.baseUrl || endpoint.split("/").slice(0, -1).join("/"); + var request = options.request || require("./http_node" + "" /* hide this module from the packager */); + + function rest(path, requestOptions, callback) { + var url = baseUrl + path; + if (!requestOptions.query) requestOptions.query = {}; + if (options.accessToken) + requestOptions.query.access_token = options.accessToken; + + if (options.username) { + requestOptions.username = options.username; + requestOptions.password = options.password; + } + + request(url, requestOptions, callback); + } + + request(endpoint, {}, function(err, description, data) { + if (err) return callback(err); + + var client = buildApi(description, rest); + callback(null, client); + }); + } + + function buildApi(description, rest) { + var api = createSection(description, rest, "/"); + return api; + } + + function createSection(description, rest, path) { + var section = {}; + if (description.sections) { + description.sections.forEach(function(sectionDesc) { + assert(sectionDesc.name, "API section has no name"); + assert(!section[sectionDesc.name], format("Section with name '%s' already exists", sectionDesc.name)); + console.log("section", sectionDesc.name) + section[sectionDesc.name] = createSection(sectionDesc, rest, join(path, sectionDesc.name)); + }); + } + + if (description.routes) { + description.routes.forEach(function(route) { + var name = route.name || route.method; + assert(!section[name], format("Route with name '%s' already exists", name)); + + section[name] = createRoute(route, rest, path); + }); + } + + return section; + } + + function createRoute(route, rest, path) { + return function request(options, requestOptions, callback) { + if (arguments.length == 1) return request({}, {}, arguments[0]); + if (arguments.length == 2) return request(arguments[0], {}, arguments[1]); + + // check for required arguments + for (var key in route.params) { + var param = route.params[key]; + if (!param.optional && !options.hasOwnProperty(key)) { + return callback(new TypeError(format("Missing required parameter '%s'", key))); + } + } + + // check for additional arguments + for (var key in options) { + if (!route.params[key]) { + return callback(new TypeError(format("Argument '%s' is not supported by the API", key))); + } + } + + // TODO verify types + // TODO serialize arguments + + // fill in parameters + path = join(path, route.route.replace(/\/:([\w\.\-\_]+)(\*?)/g, function(match, key, wildcard) { + if (wildcard) return ""; + return options[key].toString(); + })); + + // populate query string + var query = {}; + for (var key in route.params) { + if (route.params[key].source !== "query") continue; + if (!options.hasOwnProperty(key)) continue; + + query[key] = options[key]; + } + // options passed in have higher prio + for (var key in requestOptions.query || {}) { + query[key] = requestOptions.query[key]; + } + + // populate body + var body = {}; + for (var key in route.params) { + if (route.params[key].source !== "body") continue; + if (!options.hasOwnProperty(key)) continue; + + body[key] = options[key]; + } + + requestOptions.contentType = "application/json"; + requestOptions.query = query; + if (Object.keys(body).length) + requestOptions.body = body; + + // do request + rest(path, requestOptions, callback); + }; + } +}); \ No newline at end of file diff --git a/node_modules/frontdoor/lib/api-client_test.js b/node_modules/frontdoor/lib/api-client_test.js new file mode 100644 index 00000000..8a562acd --- /dev/null +++ b/node_modules/frontdoor/lib/api-client_test.js @@ -0,0 +1,92 @@ +"use strict"; +"use server"; + +require("amd-loader"); + +var assert = require("assert"); +var sinon = require("sinon"); +var http = require("http"); + +var frontdoor = require("../frontdoor"); +var createClient = require("./api-client"); + +module.exports = { + + "test client/server integration": function(next) { + this.getUsers = function(params, callback) { + console.log(params) + callback(null, [{ + id: 1, + name: "fjakobs", + first: params.first + }]); + }; + this.addUser = sinon.stub(); + this.getUser = function(params, callback) { + console.log(params) + callback(null, { + id: params.uid, + name: "fjakobs" + }); + }; + + var api = frontdoor(); + api.section("users") + .get("/", { + name: "getAll", + params: { + first: { + type: "int", + source: "query", + optional: true + } + } + }, this.getUsers) + .get("/:uid", this.getUser) + .post("/:uid", { + params: { + name: { + source: "body" + } + } + }, this.addUser); + + api.get("/describe.json", { + name: "describe" + }, frontdoor.middleware.describeApi(api)); + + var port = process.env.PORT || 8383; + this.server = http.createServer(api.handle).listen(port, function() { + createClient("http://localhost:" + port + "/describe.json", function(err, client) { + assert.equal(err, null); + + client.users.get({ uid: 123}, function(err, user) { + assert.equal(user.id, 123); + assert.equal(err, null); + + client.users.getAll({ first: 100}, function(err, users) { + assert.equal(err, null); + assert.equal(users[0].first, 100); + + next(); + }); + }); + }); + }); + }, + + // ">test real API server": function(next) { + // createClient("http://127.0.0.1:8081/api.json", function(err, client) { + // assert.equal(err, null); + // console.log(err, Object.keys(client), client.vfs); + // client.vfs.get(function(err, res) { + // console.log(err, res); + // assert.equal(err, null); + + // next(); + // }) + // }); + // } +}; + +!module.parent && require("asyncjs").test.testcase(module.exports).exec(); \ No newline at end of file diff --git a/node_modules/frontdoor/lib/api.js b/node_modules/frontdoor/lib/api.js new file mode 100644 index 00000000..90492115 --- /dev/null +++ b/node_modules/frontdoor/lib/api.js @@ -0,0 +1,11 @@ +"use strict"; + +var Section = require("./section"); +var middleware = require("./middleware"); + +module.exports = function Api(description) { + Section.call(this, "", description); + + this.use(middleware.jsonWriter()); +}; + diff --git a/node_modules/frontdoor/lib/api_test.js b/node_modules/frontdoor/lib/api_test.js new file mode 100644 index 00000000..a6fc7b52 --- /dev/null +++ b/node_modules/frontdoor/lib/api_test.js @@ -0,0 +1,464 @@ +"use strict"; + +"use server"; + +var assert = require("assert"); +var sinon = require("sinon"); + +var Api = require("./api"); + +module.exports = { + + setUp: function() { + this.res = { + writeHead: sinon.stub(), + end: sinon.stub() + }; + }, + + "test API routing": function() { + var root = new Api("API"); + var channels = root.section("channels", "Channels"); + + var next = sinon.stub(); + var listChannels = sinon.stub(); + var getChannel = sinon.stub(); + var delChannel = sinon.stub(); + + function reset() { + next.reset(); + listChannels.reset(); + getChannel.reset(); + delChannel.reset(); + } + + channels.get("/", listChannels); + + channels.get("/:id", { + params: { + id: { type: "int" } + } + }, getChannel); + + channels.del("/:id", { + params: { + id: { type: "int" } + } + }, delChannel); + + root.handle({ + method: "GET", + url: "/channels" + }, this.res, next); + sinon.assert.notCalled(next); + sinon.assert.calledOnce(listChannels); + sinon.assert.notCalled(getChannel); + sinon.assert.notCalled(delChannel); + reset(); + + root.handle({ + method: "GET", + url: "/channels/123" + }, this.res, next); + sinon.assert.notCalled(next); + sinon.assert.notCalled(listChannels); + sinon.assert.calledOnce(getChannel); + sinon.assert.notCalled(delChannel); + reset(); + + root.handle({ + method: "GET", + url: "/channels/abcd" + }, this.res, next); + sinon.assert.called(next); + sinon.assert.notCalled(listChannels); + sinon.assert.notCalled(getChannel); + sinon.assert.notCalled(delChannel); + reset(); + + root.handle({ + method: "DELETE", + url: "/channels/123" + }, this.res, next); + sinon.assert.notCalled(next); + sinon.assert.notCalled(listChannels); + sinon.assert.notCalled(getChannel); + sinon.assert.calledOnce(delChannel); + reset(); + }, + + "test two sections with same name should be additive": function() { + var next = sinon.stub(); + var getUser = sinon.stub(); + var getProject = sinon.stub(); + + function reset() { + next.reset(); + getUser.reset(); + getProject.reset(); + } + + var root = new Api("API"); + + var users = root.section("users"); + users.get("/:uid", getUser); + + var projects = root.section("users"); + projects.get("/:uid/:pid", getProject); + + root.handle({ + method: "GET", + url: "/users/fjakobs" + }, this.res, next); + sinon.assert.notCalled(next); + sinon.assert.calledOnce(getUser); + sinon.assert.notCalled(getProject); + reset(); + + root.handle({ + method: "GET", + url: "/users/fjakobs/ace" + }, this.res, next); + sinon.assert.notCalled(next); + sinon.assert.notCalled(getUser); + sinon.assert.calledOnce(getProject); + reset(); + }, + + "test add route to root": function() { + var onPing = sinon.stub(); + + var root = new Api("API"); + root.get("/ping", onPing); + + root.handle({ + method: "GET", + url: "/ping" + }, this.res, assert.fail); + sinon.assert.calledOnce(onPing); + }, + + "test section middleware shall only be called if the route was matched": function() { + var root = new Api(); + + var next = sinon.stub(); + var mw1 = sinon.stub().callsArg(2); + var mw2 = sinon.stub().callsArg(2); + var mw3 = sinon.stub().callsArg(2); + var cb1 = sinon.stub(); + var cb2 = sinon.stub(); + + next.displayName = "next"; + mw1.displayName = "mw1"; + mw2.displayName = "mw2"; + mw3.displayName = "mw3"; + cb1.displayName = "cb1"; + cb2.displayName = "cb2"; + + function reset() { + next.reset(); + mw1.reset(); + mw2.reset(); + mw3.reset(); + cb1.reset(); + cb2.reset(); + } + + root.use(mw1); + var s1 = root.section("s1"); + s1.use(mw2); + s1.get("/juhu", cb1); + + var s2 = root.section("s2"); + s2.use(mw3); + s2.get("/kinners", cb2); + + root.handle({ + method: "GET", + url: "/s1/juhu" + }, this.res, next); + sinon.assert.notCalled(next); + sinon.assert.callOrder(mw1, mw2, cb1); + sinon.assert.notCalled(mw3); + reset(); + + root.handle({ + method: "GET", + url: "/s2/kinners" + }, this.res, next); + sinon.assert.callOrder(mw1, mw3, cb2); + sinon.assert.notCalled(next); + sinon.assert.notCalled(mw2); + reset(); + + root.handle({ + method: "GET", + url: "/nothing/here" + }, this.res, next); + sinon.assert.calledOnce(next); + sinon.assert.notCalled(mw1); + sinon.assert.notCalled(mw2); + sinon.assert.notCalled(mw3); + reset(); + }, + + "test handler can be an array": function() { + var next = sinon.stub(); + var middleware1 = sinon.stub().callsArg(2); + var middleware2 = sinon.stub().callsArg(2); + var handler = sinon.stub(); + + function reset() { + next.reset(); + middleware1.reset(); + middleware2.reset(); + handler.reset(); + } + + var root = new Api(); + root.get("/juhu", [middleware1, middleware2, handler]); + + root.handle({ + method: "GET", + url: "/juhu" + }, this.res, next); + sinon.assert.notCalled(next); + sinon.assert.callOrder(middleware1, middleware2, handler); + reset(); + + root.handle({ + method: "GET", + url: "/nothing" + }, this.res, next); + sinon.assert.calledOnce(next); + sinon.assert.notCalled(middleware1); + sinon.assert.notCalled(middleware2); + sinon.assert.notCalled(handler); + reset(); + }, + + "test add route to '/' of a section": function() { + var onGet = sinon.stub(); + var next = sinon.stub(); + + var root = new Api(); + root.section("juhu") + .get("/", onGet); + + root.handle({ + method: "GET", + url: "/juhu" + }, this.res, next); + + sinon.assert.calledOnce(onGet); + sinon.assert.notCalled(next); + }, + + "test parameter decoding": function() { + var onPost = sinon.stub(); + + var root = new Api(); + root.put("/post/:id", { + params: { + id: {}, + name: {}, + age: { + source: "query", + type: "int" + } + } + }, onPost); + + root.handle({ + method: "PUT", + url: "/post/fab?age=34", + body: { + name: "Fabian" + } + }, this.res, assert.fail); + var params = onPost.args[0][0].params; + assert.equal(params.name, "Fabian"); + assert.equal(params.id, "fab"); + assert.equal(params.age, 34); + + root.handle({ + method: "PUT", + url: "/post/fab?age=34" + }, this.res, assert.fail); + sinon.assert.calledWith(this.res.writeHead, 422); + var errors = JSON.parse(this.res.end.args[0][0]).errors; + assert.equal(errors.length, 1); + assert.equal(errors[0].resource, "root"); + assert.equal(errors[0].field, "name"); + assert.equal(errors[0].code, "missing_field"); + + this.res.writeHead.reset(); + this.res.end.reset(); + + root.handle({ + method: "PUT", + url: "/post/fab?age=juhu", + body: { name: "Fabian"} + }, this.res, assert.fail); + sinon.assert.calledWith(this.res.writeHead, 422); + var errors = JSON.parse(this.res.end.args[0][0]).errors; + assert.equal(errors.length, 1); + assert.equal(errors[0].resource, "root"); + assert.equal(errors[0].field, "age"); + assert.equal(errors[0].type_expected, "int"); + assert.equal(errors[0].code, "invalid"); + }, + + "test custom type with register": function() { + var DateType = { + parse: function(string) { + if (!/\d{13}/.test(string)) + throw new Error("not a timestamp"); + + return new Date(parseInt(string, 10)); + }, + check: function(value) { + return value instanceof Date; + } + }; + + var onGet = sinon.stub(); + + var root = new Api(); + var section = root.section("ts"); + section.registerType("ts", DateType); + section.get("/:ts", { + params: { + ts: { + type: "ts" + } + } + }, onGet); + + var req = {}; + assert.ok(root.match(req, "/ts/1353676299181", "get")); + root.handle({ + method: "GET", + url: "/ts/1353676299181" + }, {}, assert.fail); + assert.ok(onGet.args[0][0].params.ts instanceof Date); + + assert.ok(!root.match(req, "/ts/353676299181", "get")); + assert.ok(!root.match(req, "/abc", "get")); + }, + + "test describe API": function() { + var root = new Api("api"); + var handler = sinon.stub(); + + root.section("users", "User management") + .get("/", { + name: "get", + description: "list all users", + }, handler) + .put("/:id", { + params: { + id: { type: /\d{4}/ }, + name: { + type: "string", + body: true + }, + age: { + body: true, + optional: true, + type: "int" + } + } + }, handler) + .delete("/:id", handler); + + var description = root.describe(); + // console.log(JSON.stringify(description, null, " ")); + + var expected = { + "description": "api", + "sections": [ + { + "name": "users", + "description": "User management", + "routes": [ + { + "route": "/", + "method": "get", + "name": "get", + "description": "list all users" + }, + { + "route": "/:id", + "method": "put", + "params": { + "id": { + "type": "/\\d{4}/", + "source": "url", + "optional": false + }, + "name": { + "type": "string", + "source": "body", + "optional": false + }, + "age": { + "type": "int", + "source": "body", + "optional": true + } + } + }, + { + "route": "/:id", + "method": "delete", + "params": { + "id": { + "type": "string", + "source": "url", + "optional": false + } + } + } + ] + } + ] + }; + assert.equal(JSON.stringify(description), JSON.stringify(expected)); + + }, + + "test handler with two arguments should be treated as function(params, callback) {}": function() { + var root = new Api(); + root.get("/check/:id", function(params, callback) { + assert.equal(params.id, "123"); + callback(null, {"ok": 1}); + }); + + root.get("/fail", function(params, callback) { + callback("error"); + }); + + root.handle({ + method: "GET", + url: "/check/123" + }, this.res, assert.fail); + assert.equal(JSON.parse(this.res.end.args[0][0]).ok, 1); + + var called = false; + root.handle({ + method: "GET", + url: "/fail" + }, this.res, function(err) { + assert.equal(err, "error"); + called = true; + }); + + assert(called); + } + + // test checks can be async + // fromString, fromJson +}; + +!module.parent && require("asyncjs").test.testcase(module.exports).exec(); diff --git a/node_modules/frontdoor/lib/http_node.js b/node_modules/frontdoor/lib/http_node.js new file mode 100644 index 00000000..83b16b83 --- /dev/null +++ b/node_modules/frontdoor/lib/http_node.js @@ -0,0 +1,169 @@ +"use strict"; + +var http = require("http"); +var https = require("https"); +var qs = require("querystring"); +var error = require("http-error"); +var URL = require("url"); +var debug = require("debug")("http:client"); + +module.exports = request; + +function request(url, options, callback) { + if (!callback) + return request(url, {}, options); + + if (typeof options == "string") + return request(url, {method: options}, callback); + + var method = options.method || "GET"; + var headers = options.headers || {}; + var body = options.body || ""; + var contentType = options.contentType + || "application/x-www-form-urlencoded; charset=UTF-8"; + var timeout = options.hasOwnProperty("timeout") ? options.timeout : 10000; + var parsedUrl = parseUrl(url, options.query); + + if (typeof body == "object") { + if (contentType.indexOf("application/json") === 0) { + try { + body = JSON.stringify(body); + } catch(e) { + return done(new Error("Could not serialize body as json")); + } + } + if (contentType.indexOf("application/x-www-form-urlencoded") === 0) { + body = qs.stringify(body); + } + else { + body = body.toString(); + } + } + + var isHttps = parsedUrl.protocol == "https:"; + var proto = isHttps ? https : http; + var reqOptions = { + hostname: parsedUrl.hostname, + port: parsedUrl.port || (isHttps ? 443 : 80), + path: parsedUrl.path, + method: method, + headers: { + "Content-Type": contentType, + "Content-Length": body.length + } + }; + + if (Object.keys(parsedUrl.query).length) + reqOptions.path += "?" + qs.stringify(parsedUrl.query); + + if (options.username) + reqOptions.auth = options.username + ":" + options.password; + + for (var header in headers) + reqOptions.headers[header] = headers[header]; + + // TODO + if (options.progress) {} + + var req = proto.request(reqOptions, function(res) { + var responseText = ""; + + res.on("data", function(chunk) { + responseText += chunk.toString(); + }); + + res.on("end", function(chunk) { + if (chunk) + responseText += chunk.toString(); + var status = res.statusCode; + + var fields = { + body: responseText, + status: status, + headers: res.headers + }; + + var data; + switch (options.overrideMimeType || res.headers["content-type"]) { + case "application/json": + try { + data = JSON.parse(responseText); + } catch (e) { + return done(e); + } + break; + default: + data = responseText; + } + + var err; + if (status > 299) + err = new error.HttpError(responseText, status); + + if (debug.enabled) { + var req = "REQ: " + JSON.stringify(body || {}); + if (err) { + debug( + "ERROR", + res.statusCode, reqOptions.method, + URL.format(parsedUrl), + req, "RES", data, err + ); + } + else { + debug( + res.statusCode, reqOptions.method, + URL.format(parsedUrl), + req, "RES", data + ); + } + } + + done(err, data, fields); + }); + }); + + var timedout = false; + if (timeout) { + req.setTimeout(timeout, function() { + timedout = true; + var err = new Error("Timeout"); + err.code = "ETIMEOUT"; + done(err); + }); + } + + req.end(body); + + req.on("error", function(e) { + if (debug.enabled) { + debug( + "ERROR", + reqOptions.method, + URL.format(parsedUrl), + e + ); + } + + done(e); + }); + + var called = false; + function done(err, data, res) { + if (called) return; + called = true; + callback(err, data, res); + } + + return req; +} + +function parseUrl(url, query) { + query = query || {}; + var parsedUrl = URL.parse(url, true); + for (var key in query) + parsedUrl.query[key] = query[key]; + + delete parsedUrl.search; + return parsedUrl; +} \ No newline at end of file diff --git a/node_modules/frontdoor/lib/middleware.js b/node_modules/frontdoor/lib/middleware.js new file mode 100644 index 00000000..1dc8721a --- /dev/null +++ b/node_modules/frontdoor/lib/middleware.js @@ -0,0 +1,35 @@ +"use strict"; + +var error = require("http-error"); + +exports.jsonWriter = function() { + return function(req, res, next) { + if (res.json) return next(); + + res.json = function(json, headers, code) { + var data; + try { + data = JSON.stringify(json); + } catch(e) { + console.error(e); + return next(new error.InternalServerError("Could not stringify JSON")); + } + + if (req.parsedUrl && req.parsedUrl.query.jsonp) + data = req.parsedUrl.query.jsonp + "(" + data + ")"; + + headers = headers || {}; + headers["Content-Type"] = "application/json"; + res.writeHead(code || 200, headers); + res.end(data); + }; + + next(); + }; +}; + +exports.describeApi = function(root) { + return function(req, res, next) { + res.json(root.describe()); + }; +}; \ No newline at end of file diff --git a/node_modules/frontdoor/lib/route.js b/node_modules/frontdoor/lib/route.js new file mode 100644 index 00000000..0c699ab7 --- /dev/null +++ b/node_modules/frontdoor/lib/route.js @@ -0,0 +1,280 @@ +define(function(require, exports, module) { +"use strict"; + +var RegExpType = require("./types").RegExp; +var Types = require("./types").Types; +var flatten = require("./utils").flatten; +var error = require("http-error"); + +module.exports = function Route(route, options, handler, types) { + + // options is optional + if (typeof options == "function" || Array.isArray(options)) { + types = handler; + handler = options; + options = {}; + } + + options.route = route; + types = types || new Types(); + + this.middlewares = flatten(handler); + + this.middlewares = this.middlewares.map(function(handler) { + if (handler.length == 2) { + handler = wrapHandler(handler); + } + return handler; + }); + + this.middlewares.unshift(decodeParams); + + this.method = (options.method || "GET").toLowerCase(); + + var self = this; + var keys = []; + var params = options.params || {}; + var routeRe = normalizePath(options.route, keys, params); + params = normalizeParams(params); + + function wrapHandler(handler) { + return function(req, res, next) { + handler(req.params || {}, function(err, json, headers, code) { + if (err) return next(err); + + res.json(json, headers, code); + }); + }; + } + + /** + * Creates a rgular expression to match this route. + * Url param names are stored in `keys` and the `params` are completed with + * the default values for url parameters. + */ + function normalizePath(path, keys, params) { + for (var name in params) { + var param = params[name]; + if (typeof param == "string" || param instanceof RegExp) + params[name] = { type: param}; + } + + path = path + .concat("/?") + .replace(/\/:([\w\.\-\_]+)(\*?)/g, function(match, key, wildcard) { + keys.push(key); + if (!params[key]) { + params[key] = {}; + } + // url params default to type string and optional=false + var param = params[key]; + param.type = param.type || "string"; + param.optional = false; + + if (!param.source) + param.source = "url"; + + if (param.source !== "url") + throw new Error("Url parameters must have 'url' as source but found '" + param.source + "'"); + + if (wildcard) + return "(/*)"; + else + return "/([^\\/]+)"; + }) + .replace(/([\/.])/g, '\\$1') + .replace(/\*/g, '(.*)'); + + return new RegExp('^' + path + '$'); + } + + function normalizeParams(params) { + for (var name in params) { + var param = params[name]; + + if (param.source == "query") { + // query params default to string + param.type = param.type || "string"; + } + else if (!param.source || param.source == "body") { + // body params default to json + param.type = param.type || "json"; + param.source = "body"; + } + else if (param.source === "url") { + param.type = param.type || "string"; + } + else { + throw new Error("parameter source muste be 'url', 'query' or 'body'"); + } + + // optional defaults to false + param.optional = !!param.optional; + + // allow regular expressions as types + if (param.type instanceof RegExp) + param.type = new RegExpType(param.type); + + // convert all types to type objects + param.type = types.get(param.type); + } + + return params; + } + + /** + * Check if the given path matched the route regular expression. If + * the regular expression doesn't match or parsing fails `match` will + * return `false` + **/ + this.match = function(req, path) { + var m = path.match(routeRe); + if (!m) return false; + + var match = {}; + for (var i = 0; i < keys.length; i++) { + var value = m[i+1]; + var key = keys[i]; + var param = params[key]; + var type = param.type; + try { + value = type.parse(value); + } catch (e) { + return false; + } + if (!type.check(value)) { + return false; + } + match[key] = value; + } + req.match = match; + return true; + }; + + /** + * Middleware to validate the parameters. It will take `req.match` for + * url params, decode the query and body parameters. If validation passes + * the decoded and validated parameters are stored in `req.params` + * otherwhise an error is returned. + */ + function decodeParams(req, res, next) { + var urlParams = req.match; + if (!urlParams) return; + + var body = req.body || {}; + var query = req.parsedUrl.query; + + req.params = req.params || {}; + var errors = []; + + // marker object + var EMPTY = {}; + + // 1. check if all required params are there + for (var key in params) { + var param = params[key]; + if ( + (!param.optional) && ( + (param.source == "body" && !(key in body)) || + (param.source == "query" && !(key in query)) || + (param.source == "url" && !(key in urlParams)) + ) + ) { + errors.push({ + "resource": self.name || "root", + "field": key, + "source": param.source, + "code": "missing_field" + }); + } + else { + var type = param.type; + var value = EMPTY; + var isValid = true; + switch(param.source) { + case "body": + if (param.optional && !(key in body)) + break; + + value = body[key]; // body is already JSON parsed + isValid = type.check(value); + break; + case "query": + if (param.optional && !(key in query)) + break; + + try { + value = type.parse(query[key]); + } catch(e) { + isValid = false; + } + isValid = isValid === false ? false : type.check(value); + break; + case "url": + if (param.optional && !(key in urlParams)) + break; + + value = urlParams[key]; // is already parsed and checked + isValid = true; + break; + } + + if (!isValid) { + errors.push({ + "resource": self.name || "root", + "field": key, + "type_expected": type.toString(), + "code": "invalid" + }); + } + else { + if (value !== EMPTY) + req.params[key] = value; + else if ("default" in param) + req.params[key] = param.default; + + } + } + } + + if (errors.length) { + var err = new error.UnprocessableEntity("Validation failed"); + err.errors = errors; + return next(err); + } + next(); + } + + this.describe = function() { + var route = { + route: options.route, + method: this.method + }; + + if (options.name) + route.name = options.name; + + if (options.description) + route.description = options.description; + + route.params = {}; + for (var name in params) { + var param = params[name]; + route.params[name] = { + name: param.name, + type: param.type.toString(), + source: param.source, + optional: param.optional + }; + if (param.description) + route.params[name].description = param.description; + } + + if (!Object.keys(route.params).length) + delete route.params; + + return route; + }; +}; + +}); \ No newline at end of file diff --git a/node_modules/frontdoor/lib/route_test.js b/node_modules/frontdoor/lib/route_test.js new file mode 100644 index 00000000..3d98b710 --- /dev/null +++ b/node_modules/frontdoor/lib/route_test.js @@ -0,0 +1,137 @@ +"use strict"; + +"use server"; + +var assert = require("assert"); +var sinon = require("sinon"); + +var Route = require("./route"); + +module.exports = { + "test router: simple route with argument": function() { + var route = new Route("/user/:name", sinon.stub()); + + var req = {}; + assert.equal(route.match(req, "/juhu"), false); + assert.equal(route.match(req, "/juhu/12"), false); + + assert.equal(route.match(req, "/user/fabian"), true); + assert.equal(req.match.name, "fabian"); + }, + + "test router: simple route with number argument": function() { + var route = new Route("/user/:id", { + params: { + id: { + type: "int" + } + } + }, sinon.stub()); + + var req = {}; + assert.equal(route.match(req, "/user/fabian"), false); + assert.equal(route.match(req, "/user/123"), true); + assert.equal(req.match.id, 123); + }, + + "test router: for params if the value is a string it is treated as the type": function() { + var route = new Route("/user/:id", { + params: { + id: "int" + } + }, sinon.stub()); + + var req = {}; + assert.equal(route.match(req, "/user/123"), true); + assert.equal(req.match.id, 123); + }, + + "test router: complex route with wildcard arguments": function() { + var route = new Route("/user/:name/:rest*", { + params: { + id: { + type: "int" + }, + rest: { + type: "string" + } + } + }, sinon.stub()); + + var req = {}; + + assert.equal(route.match(req, "/user/fabian"), false); + assert.equal(route.match(req, "/user/fabian/"), true); + assert.equal(req.match.name, "fabian"); + assert.equal(req.match.rest, "/"); + assert.equal(route.match(req, "/user/fabian/abc"), true); + assert.equal(req.match.name, "fabian"); + assert.equal(req.match.rest, "/abc"); + assert.equal(route.match(req, "/user/fabian/abc/123"), true); + assert.equal(req.match.name, "fabian"); + assert.equal(req.match.rest, "/abc/123"); + }, + + "test router: complex route with multiple arguments": function() { + var route = new Route("/user/:name/:id", { + params: { + id: { + type: "int" + } + } + }, sinon.stub()); + + var req = {}; + + assert.equal(route.match(req, "/user/fabian"), false); + assert.equal(route.match(req, "/user/123"), false); + assert.equal(route.match(req, "/user/fabian/123"), true); + assert.equal(req.match.id, 123); + assert.equal(req.match.name, "fabian"); + }, + + "test regexp types": function() { + var route = new Route("/users/:uid", { + params: { + uid: /u\d+/ + } + }, sinon.stub()); + + var req = {}; + + assert.ok(route.match(req, "/users/u123")); + assert.ok(!route.match(req, "/users/_u123")); + }, + + "test custom type without register": function() { + var DateType = { + parse: function(string) { + if (!/\d{13}/.test(string)) + throw new Error("not a timestamp"); + + return new Date(parseInt(string, 10)); + }, + check: function(value) { + return value instanceof Date; + } + }; + + var route = new Route("/ts/:ts", { + params: { + ts: { + type: DateType + } + } + }, sinon.stub()); + + var req = {}; + + assert.ok(route.match(req, "/ts/1353676299181")); + assert.ok(req.match.ts instanceof Date); + + assert.ok(!route.match(req, "/ts/353676299181")); + assert.ok(!route.match(req, "/ts/abc")); + } +}; + +!module.parent && require("asyncjs").test.testcase(module.exports).exec(); diff --git a/node_modules/frontdoor/lib/section.js b/node_modules/frontdoor/lib/section.js new file mode 100644 index 00000000..1e8edbfa --- /dev/null +++ b/node_modules/frontdoor/lib/section.js @@ -0,0 +1,209 @@ +define(function(require, exports, module) { + +"use strict"; + +var url = require("url"); +var Types = require("./types").Types; +var Route = require("./route"); +var flatten = require("./utils").flatten; + +module.exports = function Section(name, description, types) { + + types = types || new Types(); + var routes = []; + var sections = {}; + var self = this; + + this.middlewares = []; + this.errorHandlers = []; + this.name = name; + + var methods = ["head", "get", "put", "post", "delete", "patch", "upgrade", "options"]; + methods.forEach(function(method) { + routes[method] = []; + + self[method] = (function(method, route, options, handler) { + // options is optional + if (typeof options == "function" || Array.isArray(options)) { + handler = options; + options = {}; + } + options.method = method; + return self._route(route, options, handler); + }).bind(self, method); + }); + this.del = this["delete"]; + + this.registerType = types.register.bind(types); + + this.all = function(method, route, options, handler) { + var self = this; + var args = arguments; + + methods.forEach(function(method) { + self[method].apply(self, args); + }); + }; + + this.use = function(middleware) { + this.middlewares.push.apply(this.middlewares, flatten(middleware)); + }; + + this.error = function(middleware) { + this.errorHandlers.push.apply(this.errorHandlers, flatten(middleware)); + }; + + this._route = function(route, options, handler) { + route = new Route(route, options, handler, types); + route.parent = this; + routes[route.method].push(route); + return this; + }; + + this.section = function(name, description) { + var section = new Section(name, description, types); + section.parent = this; + if (!sections[name]) + sections[name] = []; + + sections[name].push(section); + return section; + }; + + this._rootHandler = function(req, res) { + this.handle(req, res, function(err) { + if (err) { + res.statusCode = err.code || err.statusCode || 500; + res.end(err.message || err.toString); + } else { + res.statusCode = 404; + res.end("cannot " + req.method); + } + }); + }; + + this.handle = (function(path, req, res, next) { + var that = this; + + if (arguments.length == 2) { + return this._rootHandler.apply(this, arguments); + } + + if (arguments.length === 3) { + req = arguments[0]; + res = arguments[1]; + next = arguments[2]; + + if (!req.parsedUrl) + req.parsedUrl = url.parse(req.url, true); + + path = req.parsedUrl.pathname; + } + + req.params = req.params || {}; + + var method = req.method.toLowerCase(); + if (methods.indexOf(method) == -1) + return next(); + + var handler = this.match(req, path, method); + if (!handler) + return next(); + + var middleware = []; + var errorHandlers = []; + while (handler) { + middleware.unshift.apply(middleware, handler.middlewares || []); + errorHandlers.unshift.apply(errorHandlers, handler.errorHandlers || []); + handler = handler.parent; + } + + var i = 0; + function processNext() { + handler = middleware[i++]; + if (!handler || i > middleware.length) + return next(); + + handler(req, res, function(err) { + if (err) + return that.handleError(errorHandlers, err, req, res, next); + + processNext(); + }); + } + + processNext(); + }).bind(this); + + this.handleError = function (errorHandlers, err, req, res, next) { + var i = 0; + function processNext(err) { + if (!err) + return next(); + + var handler = errorHandlers[i++]; + if (!handler || i > errorHandlers.length) + return next(err); + + handler(err, req, res, processNext); + } + + processNext(err); + }; + + this.match = function(req, path, method) { + var splitPath = path.split("/"); + if (!splitPath[0]) + splitPath.shift(); + if (splitPath.length) { + var section = sections[splitPath[0]]; + if (section && section.length) { + var subPath = "/" + splitPath.slice(1).join("/"); + for (var i = 0; i < section.length; i++) { + var handler = section[i].match(req, subPath, method); + if (handler) + return handler; + } + } + } + + var methodRoutes = routes[method]; + for (var i = 0; i < methodRoutes.length; i++) { + var route = methodRoutes[i]; + if (route.match(req, path)) + return route; + } + }; + + this.describe = function() { + // sections and routes + var api = {}; + + if (name) + api.name = name; + + if (description) + api.description = description; + api.sections = []; + for (var key in sections) { + for (var i=0; i < sections[key].length; i++) { + api.sections.push(sections[key][i].describe()); + } + } + if (!api.sections.length) + delete api.sections; + + api.routes = []; + for (var method in routes) { + for (var i=0; i < routes[method].length; i++) { + api.routes.push(routes[method][i].describe()); + } + } + if (!api.routes.length) + delete api.routes; + + return api; + }; +}; + +}); \ No newline at end of file diff --git a/node_modules/frontdoor/lib/types.js b/node_modules/frontdoor/lib/types.js new file mode 100644 index 00000000..9256c8aa --- /dev/null +++ b/node_modules/frontdoor/lib/types.js @@ -0,0 +1,132 @@ +define(function(require, exports, module) { +"use strict"; + +var inherits = require("util").inherits; + +exports.Types = function() { + this.types = {}; + + this.register("string", new exports.String()); + this.register("number", new exports.Number()); + this.register("boolean", new exports.Boolean()); + this.register("int", new exports.Integer()); + this.register("json", new exports.Json()); + this.register("array", new exports.Array()); + this.register("array[string]", new exports.Array(new exports.String())); +}; +exports.Types.prototype.register = function(name, type) { + type.name = name; + if (type instanceof RegExp) + type = new exports.RegExp(type); + + this.types[name] = type; + return this; +}; +exports.Types.prototype.get = function(name) { + // if it already is a type return it + if (name.check && name.parse) + return name; + + var type = this.types[name]; + if (!type) + throw new Error("Unknown type ", name); + + return type; +}; + +exports.Type = function() {}; +exports.Type.prototype.parse = function(string) { + return string; +}; +exports.Type.prototype.check = function(value) { + return true; +}; +exports.Type.prototype.toString = function() { + return this.name; +}; + +exports.RegExp = function(re) { + this.re = re; +}; +inherits(exports.RegExp, exports.Type); +exports.RegExp.prototype.parse = function(value) { + return value.toString(); +}; +exports.RegExp.prototype.check = function(value) { + value = value.toString(); + var match = value.match(this.re); + return match && value === match[0]; +}; +exports.RegExp.prototype.toString = function() { + return (this.name ? this.name + " " : "") + this.re.toString(); +}; + +exports.Json = function() {}; +inherits(exports.Json, exports.Type); +exports.Json.prototype.parse = function(string) { + return JSON.parse(string); +}; + +exports.Array = function(itemType) { + this.itemType = itemType; +}; +inherits(exports.Array, exports.Json); +exports.Array.prototype.check = function(value) { + if (!Array.isArray(value)) + return false; + + if (!this.itemType) + return true; + + for (var i = 0; i < value.length; i++) { + if (!this.itemType.check(value[i])) + return false; + } + return true; +}; + +exports.String = function() {}; +inherits(exports.String, exports.Type); +exports.String.prototype.check = function(value) { + return typeof value == "string"; +}; + +exports.Number = function() {}; +inherits(exports.Number, exports.Type); +exports.Number.prototype.parse = function(string) { + var value = parseFloat(string); + if (isNaN(value)) + throw new TypeError("Could not parse string as number"); + return value; +}; +exports.Number.prototype.check = function(value) { + return typeof value == "number" || !isNaN(parseFloat(value)); +}; + +exports.Integer = function(min, max) { + this.min = min === undefined ? Number.MIN_VALUE : min; + this.max - max === undefined ? Number.MAX_VALUE : max; +}; +inherits(exports.Integer, exports.Type); +exports.Integer.prototype.parse = function(string) { + return parseInt(string, 10); +}; +exports.Integer.prototype.check = function(value) { + return ( + typeof value == "number" && Math.round(value) == value + ); +}; + +exports.Boolean = function() {}; +inherits(exports.Boolean, exports.Type); +exports.Boolean.prototype.parse = function(string) { + if (string !== "true" && string !== "false") + throw new Error("Could not parse '" + string +"' as a boolean"); + + return string == "true"; +}; +exports.Boolean.prototype.check = function(value) { + return typeof value == "boolean"; +}; + +}); \ No newline at end of file diff --git a/node_modules/frontdoor/lib/types_test.js b/node_modules/frontdoor/lib/types_test.js new file mode 100644 index 00000000..1e15f5da --- /dev/null +++ b/node_modules/frontdoor/lib/types_test.js @@ -0,0 +1,28 @@ +"use strict"; + +"use server"; + +var assert = require("assert"); + +var types = require("./types"); + +module.exports = { + "test string array type": function() { + var t = new types.Array(new types.String()); + + assert.ok(t.check(["a", "b", "c"])); + assert.ok(!t.check([12, "b", "c"])); + }, + + "test array type": function() { + var t = new types.Array(); + + assert.ok(t.check(["a", "b", "c"])); + assert.ok(t.check([12, "b", "c"])); + assert.ok(!t.check({})); + assert.ok(!t.check(12)); + assert.ok(!t.check("juhu")); + } +}; + +!module.parent && require("asyncjs").test.testcase(module.exports).exec(); \ No newline at end of file diff --git a/node_modules/frontdoor/lib/utils.js b/node_modules/frontdoor/lib/utils.js new file mode 100644 index 00000000..96e999a9 --- /dev/null +++ b/node_modules/frontdoor/lib/utils.js @@ -0,0 +1,18 @@ +define(function(require, exports, module) { + +exports.flatten = function(arr, ret){ + if (!Array.isArray(arr)) + return [arr]; + + ret = ret || []; + for (var i = 0; i < arr.length; ++i) { + if (Array.isArray(arr[i])) { + exports.flatten(arr[i], ret); + } else { + ret.push(arr[i]); + } + } + return ret; +}; + +}); \ No newline at end of file diff --git a/node_modules/frontdoor/package.json b/node_modules/frontdoor/package.json new file mode 100644 index 00000000..df2ae136 --- /dev/null +++ b/node_modules/frontdoor/package.json @@ -0,0 +1,37 @@ +{ + "author": "Ajax.org B.V. ", + "contributors": [{ + "name": "Fabian Jakobs", + "email": "fabian@c9.io" + }], + "name": "frontdoor", + "description": "Frontdoor is a libarary for creating RESTful API servers.", + "version": "0.0.1", + "scripts": { + "test": "find lib | grep '_test.js$' | xargs -n 1 node" + }, + "licenses": [{ + "type": "MIT", + "url": "http://github.com/frontdoor/smith/raw/master/LICENSE" + }], + "repository": { + "type": "git", + "url": "git://github.com/c9/frontdoor.git" + }, + "main": "frontdoor.js", + "engines": { + "node": ">=0.6.0" + }, + "dependencies": { + "http-error": "~0.0.1", + "request": "~2.12.0", + "amd-loader": "~0.0.5" + }, + "devDependencies": { + "asyncjs": "~0.0.9", + "sinon": "~1.3.0", + + "express": "3.0.3", + "ejs": "*" + } +} \ No newline at end of file diff --git a/node_modules/kaefer/Makefile b/node_modules/kaefer/Makefile new file mode 100644 index 00000000..15076386 --- /dev/null +++ b/node_modules/kaefer/Makefile @@ -0,0 +1,26 @@ + +.PHONY: test + +REPORTER = spec + +test: + @NODE_ENV=test ./node_modules/.bin/mocha \ + --reporter $(REPORTER) + +test-w: + @NODE_ENV=test ./node_modules/.bin/mocha \ + --reporter $(REPORTER) \ + --growl \ + --watch + +test-integration: + node test/integration/chaos_monkey.js + node test/integration/smith_test.js + +test-cov: lib-cov + @INSTINCT_COV=1 $(MAKE) test REPORTER=html-cov > public/coverage.html + +lib-cov: + @node_modules/.bin/jscoverage lib lib-cov --coverage + +.PHONY: test test-w test-integration \ No newline at end of file diff --git a/node_modules/kaefer/index.js b/node_modules/kaefer/index.js new file mode 100644 index 00000000..a0ec8304 --- /dev/null +++ b/node_modules/kaefer/index.js @@ -0,0 +1,16 @@ +require("amd-loader"); + +if (process.env.CONNECT_COV) { + exports.Server = require("./lib-cov/server"); + exports.connectClient = require("./lib-cov/client"); + exports.ReliableSocket = require("./lib-cov/reliable_socket"); + exports.ReconnectSocket = require("./lib-cov/reconnect_socket"); + exports.version = require("./lib-cov/version"); +} +else { + exports.Server = require("./lib/server"); + exports.connectClient = require("./lib/client"); + exports.ReliableSocket = require("./lib/reliable_socket"); + exports.ReconnectSocket = require("./lib/reconnect_socket"); + exports.version = require("./lib/version"); +} diff --git a/node_modules/kaefer/lib/client.js b/node_modules/kaefer/lib/client.js new file mode 100644 index 00000000..3f6bd7f0 --- /dev/null +++ b/node_modules/kaefer/lib/client.js @@ -0,0 +1,122 @@ +define(function(require, exports, module) { + +"use strict"; + +var ReliableSocket = require("./reliable_socket"); +var ReconnectSocket = require("./reconnect_socket"); +var version = require("./version").protocol; + +/** + * Creates a reliable socket with automatic reconnects + */ +var connectClient = module.exports = function(connectEio, options) { + var reconnectSocket = new ReconnectSocket(); + options = options || {}; + options.seq = options.seq || 20000; + + var socket = new ReliableSocket(reconnectSocket, options); + socket.on("disconnect", function() { + socket.id = null; + }); + + var connectAttempts = 0; + var isReconnecting = false; + var preConnectCheck = options.preConnectCheck || function(cb) { cb(null, true); }; + + function connect() { + if (reconnectSocket.readyState !== "away") { + // Lets double check that the socket isn't in the process of going away + setTimeout(function() { + if (connectAttempts === 0 && reconnectSocket.readyState === "away") + connect(); + }, 250); + return; + } + + preConnectCheck(function(err, shouldConnect) { + if (err || !shouldConnect) + return reconnect(); + + reconnectSocket.setSocket(null); + + var eioSocket = connectEio(); + eioSocket.on("open", function() { + eioSocket.send(JSON.stringify({ + type: "handshake", + session: socket.id, + seq: socket.seq, + version: version + })); + }); + + eioSocket.on("message", function handshakeReply(msg) { + try { + msg = JSON.parse(msg); + } catch (e) {} + + if (msg.type !== "handshake reply" || !msg.seq) { + socket.close(); + return reconnect(); // Make sure we never end up in a disconnected state + } + + // backend has changed! + if (socket.id && socket.id !== msg.session) + socket.disconnect(); + + socket.id = msg.session; + + eioSocket.off("message", handshakeReply); + connectAttempts = 0; + + if (socket.recId == -1) + socket.recId = msg.seq; + + reconnectSocket.setSocket(eioSocket); + }); + + eioSocket.on("error", function(e) { + console.error("Socket error; reconnecting:", e); + eioSocket.close(); + reconnect(); + }); + eioSocket.on("close", function(e) { + console.error("Socket close; reconnecting:", e); + reconnect(); + }); + }); + } + + var timer; + function reconnect(delay) { + if (isReconnecting && typeof delay !== "number") + return; + + reconnectSocket.setSocket(null); + connectAttempts += 1; + + if (typeof delay !== "number") { + if (connectAttempts < 10) { + delay = 250; + } + else { + delay = Math.min(60000, 250 * Math.pow(2, connectAttempts - 10)); + } + } + + isReconnecting = true; + console.log("Schedule re-connect in: " + delay); + socket.emit("reconnectDelay", { delay: delay }); + + clearTimeout(timer); + timer = setTimeout(function() { + isReconnecting = false; + connect(); + }, delay); + } + + socket.connect = connect; + socket.reconnect = reconnect; + return socket; +}; + +}); \ No newline at end of file diff --git a/node_modules/kaefer/lib/reconnect_socket.js b/node_modules/kaefer/lib/reconnect_socket.js new file mode 100644 index 00000000..0e5ced1e --- /dev/null +++ b/node_modules/kaefer/lib/reconnect_socket.js @@ -0,0 +1,107 @@ +define(function(require, exports, module) { +"use strict"; + +var util = require("./util"); +var EventEmitter = require("events").EventEmitter; + +/** + * Wraps an engine.io socket. + * + * The engine.io socket can be replaced onder the hood without affecting the + * wrapper. + * + * Emits 'away' if the wrapped socket is closed and 'back' if the wrapped socket + * is set to a new engine.io socket. + */ +var ReconnectSocket = module.exports = function(socket) { + EventEmitter.call(this); + + this.listeners = { + "close": this.onClose.bind(this), + "message": this.onMessage.bind(this), + "drain": this.onDrain.bind(this) + }; + + if (socket) + this.setSocket(socket); +}; + +util.inherits(ReconnectSocket, EventEmitter); + +ReconnectSocket.prototype.setSocket = function(socket) { + if (!this.socket && !socket || this.socket == socket) + return; + + var that = this; + + // cleanup old socket + if (this.socket) { + for (var type in this.listeners) { + this.socket.removeListener(type, this.listeners[type]); + } + this.socket.close(); + } + + // setup new socket + if (socket) { + for (var type in this.listeners) { + socket.on(type, this.listeners[type]); + } + } + + this.socket = socket; + + if (!this.socket) { + this.emit("away"); + } + else { + if (socket.readyState == "open") { + this.emit("back"); + } + else { + socket.on("open", function() { + that.emit("back"); + }); + } + } +}; + +ReconnectSocket.prototype.send = function(msg) { + if (!this.socket || this.socket.readyState !== "open") + return; + + try { this.socket.send(msg); } + catch (e) { + this.setSocket(null); + this.emit('error', e); + } +}; + +Object.defineProperty(ReconnectSocket.prototype, "readyState", { + get : function() { + if (!this.socket) + return "away"; + else if (this.socket.readyState == "open") + return "open"; + else + return "reconnecting"; + } +}); + +ReconnectSocket.prototype.close = function() { + this.setSocket(null); +}; + +ReconnectSocket.prototype.onClose = function() { + this.setSocket(null); +}; + +ReconnectSocket.prototype.onMessage = function(message) { + this.emit("message", message); +}; + +ReconnectSocket.prototype.onDrain = function() { + this.emit("drain"); +}; + +}); \ No newline at end of file diff --git a/node_modules/kaefer/lib/reliable_socket.js b/node_modules/kaefer/lib/reliable_socket.js new file mode 100644 index 00000000..a3b16bc1 --- /dev/null +++ b/node_modules/kaefer/lib/reliable_socket.js @@ -0,0 +1,317 @@ +define(function(require, exports, module) { +"use strict"; + +var util = require("./util"); +var EventEmitter = require("events").EventEmitter; + +/** + * Makes sure that each messages reaches the receiver. Uses sliding windows + * and acknowledgements to guarantee that. + * + * @param socket {ReconnectSocket} The transport layer for the reliable socket + * @param options {Object} Options to specify + * object: + * seq {Number} initial sequence number + * ackTimeout {Number} time to wait in ms before auto ack received messages + * disconnectTimeout {Number} time to waint in away state before disconnecting + * the connection + */ +var ReliableSocket = module.exports = function(socket, options) { + EventEmitter.call(this); + + this.socket = socket; + + options = options || {}; + this.options = options; + + this.initialCongestionWindowSize = 5; + this.congestionWindowSize = this.initialCongestionWindowSize; + this.slowStartThreshold = options.slowStartThreshold || 300; + this.ackTimeout = options.ackTimeout || 200; + this.disconnectTimeout = options.disconnectTimeout || 10 * 1000; + this.retransmissionTimeout = 3000; + this.maxRtt = options.maxRtt || 10000; + this.minRtt = options.minRtt || 2000; + + this.debug = options.debug || false; + this.seq = options.seq || 1; + this.recId = -1; + this.connected = false; + + // messages sent while not connected + this.buffer = []; + + // sent but not yet acknowledged messages + this.unacked = {}; + + socket.on("message", this.onMessage.bind(this)); + socket.on("away", this.onAway.bind(this)); + socket.on("back", this.onBack.bind(this)); + socket.on("error", function(e){ console.error(e.message); }); + + // var that = this; + // setInterval(function() { + // console.log({ + // retransmissionTimeout: that.retransmissionTimeout, + // congestionWindowSize: that.congestionWindowSize, + // srtt: that.srtt, + // rttVar: that.rttVar + // }); + // }, 2000); +}; + +util.inherits(ReliableSocket, EventEmitter); + +Object.defineProperty(ReliableSocket.prototype, "readyState", { + get : function() { + return this.socket.readyState; + } +}); + +ReliableSocket.prototype.onMessage = function(msg) { + if (typeof msg == "string") { + try { + msg = JSON.parse(unescape(msg)); + } catch(e) {} + } + this.debug && console.log("on message", msg, this.seq); + + if (!msg || !msg.ack) + return; + + // remove acknowledged messages from our buffer + var ack = msg.ack; + for (var key in this.unacked) { + var unacked = this.unacked[key]; + if (unacked.seq <= ack) + unacked.acknowledge(); + } + + if (Object.keys(this.unacked).length < this.congestionWindowSize) + this._flush(); + + var recId = msg.seq; + if (recId) { + var expectedId = this.recId + 1; + if (recId == expectedId || this.recId == -1) { + this.recId = recId; + this._delayedAck(); + } else if (recId < expectedId) { + this.debug && console.log("dupe", recId, expectedId); + // we already saw this packet. Make sure the other side knows it + this._ack(); + return; + } else { + this.debug && console.log("miss", recId, expectedId); + // we miss packets in between + this._ack(); + return; + } + } + + if (msg.d) { + try { + this.emit("message", msg.d); + } catch (e) { + console.error(e.stack); + // Don't let engine.io catch this, it'll consider it a parser error, + // making us reconnect + setTimeout(function() { throw e; }); + } + } +}; + +ReliableSocket.prototype.onAway = function() { + this.debug && console.log("away"); + this._scheduleDisconnect("client connection went away"); + this.emit("away"); +}; + +ReliableSocket.prototype.onBack = function() { + this.debug && console.log("back"); + this._cancelDisconnect(); + + if (!this.connected) { + this.connected = true; + this.emit("connect"); + } + this.emit("back"); + + if (this.buffer.length) + this._flush(); + else + this._ack(); +}; + +ReliableSocket.prototype._scheduleDisconnect = function(reason) { + var that = this; + this._cancelDisconnect(); + this.debug && console.log("schedule disconnect"); + this._disconnectTimer = setTimeout(function() { + that.disconnect(reason); + }, this.disconnectTimeout); +}; + +ReliableSocket.prototype._cancelDisconnect = function() { + this.debug && console.log("cancel disconnect"); + clearTimeout(this._disconnectTimer); +}; + +ReliableSocket.prototype._delayedAck = function() { + var that = this; + this._cancelDelayedAck(); + this._ackTimer = setTimeout(function() { + that._ack(); + }, this.ackTimeout); +}; + +ReliableSocket.prototype._cancelDelayedAck = function() { + clearTimeout(this._ackTimer); +}; + +ReliableSocket.prototype._ack = function() { + if (this.socket.readyState == "open") { + this.debug && console.log("send ack", this.recId); + this.socket.send(encodeURI(JSON.stringify({ + ack: this.recId + }))); + } +}; + +ReliableSocket.prototype._flush = function() { + if (this.socket.readyState == "open" && this.buffer.length) { + var toSend = Math.min( + this.congestionWindowSize - Object.keys(this.unacked).length, + this.buffer.length + ); + + this.debug && console.log("flush", toSend, "messages"); + for (var i=0; i 0) + that.debug && console.log("retry", msg.seq, that.congestionWindowSize, that.retransmissionTimeout); + + that._updateCongestionWindowSize(false); + if (!msg.tries) + that._updateRetransmissionTimeout(Date.now() - msg.ts); + }, + serialize: function() { + return escape(JSON.stringify({ + ack: that.recId, + seq: msg.seq, + d: data + })); + } + }; + + msg.send(); +}; + +ReliableSocket.prototype._updateCongestionWindowSize = function(timeout) { + if (timeout) { + this.slowStartThreshold = Math.max(Math.floor(this.congestionWindowSize / 2), 50); + this.congestionWindowSize = this.initialCongestionWindowSize; + } + else { + if (this.congestionWindowSize > this.slowStartThreshold) + this.congestionWindowSize += 1; + else + this.congestionWindowSize *= 2; + } +}; + +// use TCP algorithm to compute the retransmission timeout +// http://de.wikipedia.org/wiki/Transmission_Control_Protocol#Retransmission_Timer +ReliableSocket.prototype._updateRetransmissionTimeout = function(rtt) { + if (!rtt) { + // there was a timeout + this.retransmissionTimeout = Math.min(this.retransmissionTimeout * 2, this.maxRtt); + this.srtt = null; + } + else if (!this.srtt) { + this.srtt = rtt; + this.rttVar = 0.5 * rtt; + this.retransmissionTimeout = rtt * this.rttVar; + } + else { + var alpha = 1/8; + var beta = 1/4; + this.srtt = (1-alpha) * this.srtt + alpha * rtt; + this.rttVar = (1-beta) * this.rttVar + beta * (Math.abs(this.srtt - rtt)); + this.retransmissionTimeout = this.srtt + 4 * this.rttVar; + } + + this.retransmissionTimeout = Math.min(Math.max(this.retransmissionTimeout, this.minRtt), this.maxRtt); +}; + +}); \ No newline at end of file diff --git a/node_modules/kaefer/lib/server.js b/node_modules/kaefer/lib/server.js new file mode 100644 index 00000000..1337242a --- /dev/null +++ b/node_modules/kaefer/lib/server.js @@ -0,0 +1,95 @@ +"use strict"; + +/** + * server: + * - keep pool of connections (by id) + * - disconnected connections expire after N seconds + * + * client: + * - keeps one persistent connection + * + * initial handshake: + * - client receives eio connect event + * - client generates connection id and sends it to the server + * - server creates a connection and stores it in the connection pool + * + * reconnect handshake: + * - client receives eio connect event + * - server looks up connection by id + * - if server finds connection resume and fire 'back' event on the client + * - if server doesn't find connection, reset the connection and start a new one (fire 'connect' event) + */ + +var util = require("./util"); +var EventEmitter = require("events").EventEmitter; + +var ReliableSocket = require("./reliable_socket"); +var ReconnectSocket = require("./reconnect_socket"); +var version = require("./version").protocol; + +var Server = module.exports = function(engine, socketOptions) { + EventEmitter.call(this); + + var that = this; + this.sockets = {}; + this.socketOptions = socketOptions || {}; + this.socketOptions.seq = this.socketOptions.seq || 10000; + + engine.on("connection", function(socket) { + socket.once("message", function handshake(msg) { + try { + msg = JSON.parse(msg); + } catch (e) {} + + if ( + !msg || + msg.type !== "handshake" || + !msg.seq || + msg.version != version + ) { + socket.close(); + return; + } + + var transport = that.getConnection(msg.session); + socket.send(JSON.stringify({ + "type": "handshake reply", + "session": transport.id, + "seq": transport.seq + })); + + if (transport.recId == -1) + transport.recId = msg.seq; + + transport.socket.setSocket(socket); + }); + }); +}; + +util.inherits(Server, EventEmitter); + +Server.prototype.getConnection = function(id) { + var transport; + + if (id) { + transport = this.sockets[id]; + if (transport) { + return transport; + } + } + + id = util.uid(); + transport = this.sockets[id] = new ReliableSocket(new ReconnectSocket(), this.socketOptions); + transport.on("disconnect", this.disconnect.bind(this, transport)); + transport.id = id; + this.emit("connection", transport); + return transport; +}; + +Server.prototype.disconnect = function(transport) { + delete this.sockets[transport.id]; + if (transport) { + transport.close(); + this.emit("disconnect", transport); + } +}; \ No newline at end of file diff --git a/node_modules/kaefer/lib/util.js b/node_modules/kaefer/lib/util.js new file mode 100644 index 00000000..beefc319 --- /dev/null +++ b/node_modules/kaefer/lib/util.js @@ -0,0 +1,11 @@ +define(function(require, exports, module) { + +exports.inherits = function(Child, Parent) { + Child.prototype = Object.create(Parent.prototype, { constructor: { value: Child }}); +} + +exports.uid = function() { + return (Date.now() + Math.random() * 0x100000000).toString(36) + (Math.random() * 0x100000000).toString(36); +} + +}); \ No newline at end of file diff --git a/node_modules/kaefer/lib/version.js b/node_modules/kaefer/lib/version.js new file mode 100644 index 00000000..ecdfc9b4 --- /dev/null +++ b/node_modules/kaefer/lib/version.js @@ -0,0 +1,7 @@ +define(function(require, exports, module) { + +// on each backwards incompatible protocol change the version number must be +// increased +exports.protocol = 8; + +}); \ No newline at end of file diff --git a/node_modules/kaefer/package.json b/node_modules/kaefer/package.json new file mode 100644 index 00000000..5fd74395 --- /dev/null +++ b/node_modules/kaefer/package.json @@ -0,0 +1,26 @@ +{ + "name": "kaefer", + "version": "0.1.0", + "description": "Reliable transport on top of engine.io", + "author": "Cloud9 Inc. ", + "contributors": [{ + "name": "Fabian Jakobs", + "email": "fabian@c9.io" + }], + "dependencies": { + "engine.io": "~1.3.1", + "engine.io-client": "~1.3.1", + "amd-loader": "*" + }, + "devDependencies": { + "smith": "~0.1.22", + "vfs-local": "~0.3.13", + "mocha": "~1.8.2", + "sinon": "~1.7.3", + "chai": "~1.8.1", + "async": "~0.2.7" + }, + "scripts": { + "test": "make test && make test-integration" + } +} diff --git a/node_modules/kaefer/test/integration/chaos_monkey.js b/node_modules/kaefer/test/integration/chaos_monkey.js new file mode 100755 index 00000000..be4a561e --- /dev/null +++ b/node_modules/kaefer/test/integration/chaos_monkey.js @@ -0,0 +1,94 @@ +#!/usr/bin/env node +"use strict"; + +var assert = require("assert"); +var engine = require("engine.io"); +var client = require("engine.io-client"); + +var kaefer = require("../.."); + +var server = new kaefer.Server(engine.listen(7878), { debug: false }); + +var messages = { + "a": [], + "b": [], + "c": [], + "d": [] +}; + +server.on("connection", function (socket) { + send(socket, 100); + + socket.on("away", function() { console.log("server away"); }); + socket.on("back", function() { console.log("server back"); }); + + socket.on("message", function(msg) { + console.log("<-", msg); + messages[msg.l].push(msg); + if (msg.l == "b") { + send(socket, msg.i + 1, msg.f); + } + }); +}); + +function connect() { + return client("ws://localhost:7878"); +} + +var socket = kaefer.connectClient(connect, { debug: false }); +socket.on("away", function() { console.log("client away"); }); +socket.on("back", function() { console.log("client back"); }); + +socket.on("message", function(msg){ + console.log("->", msg); + messages[msg.l].push(msg); + if (msg.l == "c") { + send(socket, msg.i + 1); + } + + if (msg.i > 110) { + ["a", "b", "c", "d"].forEach(function(l) { + messages[l] = messages[l].sort(function(a, b) { + return a.i > b.i ? 1 : -1; + }); + }); + console.log(messages); + ["a", "b", "c", "d"].forEach(function(l) { + for (var i = 0; i < messages[l].length; i++) { + assert(messages[l][i].i == 100+i); + } + }); + process.exit(); + } +}); + +socket.connect(); + +function send(socket, i) { + setTimeout(function() { + ["a", "b", "c", "d"].forEach(function(l) { + socket.send({ + l: l, + i: i + }); + }); + }, Math.random() * 100); +} + +// chaos monkey + +// simulate 20% packet loss +var sendOriginal = socket.socket.send; +socket.socket.send = function() { + if (Math.random() > 0.2) + return sendOriginal.apply(this, arguments); +}; + +// disconnect randomly +(function loop() { + setTimeout(function() { + console.log("close connection"); + socket.socket.close(); + loop(); + }, Math.random() * 1000 + 100); +})(); diff --git a/node_modules/kaefer/test/integration/congestion_control_test.js b/node_modules/kaefer/test/integration/congestion_control_test.js new file mode 100755 index 00000000..97954e27 --- /dev/null +++ b/node_modules/kaefer/test/integration/congestion_control_test.js @@ -0,0 +1,65 @@ +#!/usr/bin/env node +"use strict"; + +"use server"; + +var async = require("async"); + +// +// fast sender +// + +var engine = require("engine.io"); +var kaefer = require("../.."); + +var server = new kaefer.Server(engine.listen(7878)); + +var N = 5000; +var M = 100; + +server.on("connection", function (socket) { + // send as fast as possible + async.timesSeries(N, function(n, next) { + socket.send({ + msg: new Array(M).join("-"), + n: n + }); + setImmediate(next); + }, function() { + console.log("DONE sending"); + socket.on("drain", function() { + console.log("DRAIN"); + }); + }); +}); + +// +// slow receiver +// + +var client = require("engine.io-client"); +var connectClient = kaefer.connectClient; + +function connect() { + return client("ws://localhost:7878"); +} + +var socket = connectClient(connect); +socket.connect(); + +var i = 0; +socket.on("message", function(data) { + if (i++ % 100 === 0) + console.log("Data", data, i); + if (data.n === N-1) { + console.log(data); + done(); + } +}); + + +var start = Date.now(); +function done() { + console.log("Sending", N, "messages of size", M, "took", Date.now() - start, "ms"); + process.exit(); +} \ No newline at end of file diff --git a/node_modules/kaefer/test/integration/smith_test.js b/node_modules/kaefer/test/integration/smith_test.js new file mode 100755 index 00000000..d12902ac --- /dev/null +++ b/node_modules/kaefer/test/integration/smith_test.js @@ -0,0 +1,51 @@ +#!/usr/bin/env node +"use strict"; + +"use server"; + +var smith = require("smith"); + +// +// SERVER +// + +var engine = require("engine.io"); +var kaefer = require("../.."); +var VfsWorker = require('vfs-socket/worker').Worker; +var vfsLocal = require("vfs-local"); + +var server = new kaefer.Server(engine.listen(7878)); + +server.on("connection", function (socket) { + var transport = new smith.EngineIoTransport(socket, true); + var worker = new VfsWorker(vfsLocal({root: __dirname + "/.." })); + worker.connect(transport); + + socket.on("message", function(msg){ + console.log("->", msg); + }); +}); + +// +// CLIENT +// + +var Consumer = require("vfs-socket/consumer").Consumer; +var client = require("engine.io-client"); +var connectClient = kaefer.connectClient; + +function connect() { + return client("ws://localhost:7878"); +} + +var socket = connectClient(connect); +socket.connect(); + +var consumer = new Consumer(); +var transport = new smith.EngineIoTransport(socket, true); +consumer.connect(transport, function(err, vfs) { + vfs.stat("/", {}, function() { + console.log(arguments); + process.exit(); + }); +}); \ No newline at end of file diff --git a/node_modules/kaefer/test/reliable_socket_test.js b/node_modules/kaefer/test/reliable_socket_test.js new file mode 100755 index 00000000..235bc86a --- /dev/null +++ b/node_modules/kaefer/test/reliable_socket_test.js @@ -0,0 +1,106 @@ +#!/usr/bin/env node + +/*global describe it before after beforeEach afterEach */ +"use strict"; + +"use server"; + +require("c9/inline-mocha")(module); + +var kaefer = require(".."); +var ReliableSocket = kaefer.ReliableSocket; +var ReconnectSocket = kaefer.ReconnectSocket; +var EventEmitter = require("events").EventEmitter; + +var expect = require("chai").expect; +var sinon = require("sinon"); + +describe("Reliable Socket", function(){ + this.timeout(2000); + + var clock; + beforeEach(function() { + clock = sinon.useFakeTimers(); + }); + + afterEach(function () { + clock.restore(); + }); + + describe("buffer messages while away", function() { + + var reconnect = new ReconnectSocket(); + var socket = new ReliableSocket(reconnect); + + it("should add messages to the buffer while away", function() { + expect(reconnect.readyState).to.equal("away"); + expect(socket.buffer).to.have.length(0); + + socket.send("msg"); + expect(socket.buffer).to.have.length(1); + }); + + it("should flush the buffer once the connection is back", function() { + //var mockEio = new EventEmitter(); + var mockEio = createMockEio(); + expect(socket.buffer).to.have.length(1); + reconnect.setSocket(mockEio); + sinon.assert.called(mockEio.send); + expect(socket.buffer).to.have.length(0); + }); + }); + + describe("acknowledge packets", function() { + + var eio, reconnect, socket; + + beforeEach(function() { + eio = createMockEio(); + reconnect = new ReconnectSocket(eio); + socket = new ReliableSocket(reconnect, { + debug: false, + ackTimeout: 200, + seq: 500 + }); + }); + + it("should automatically acknowledge packets after ack timeout", function() { + socket._ack = sinon.spy(); + eio.emit("message", JSON.stringify({ + seq: 123, + d: "msg", + ack: 500 + })); + + sinon.assert.notCalled(socket._ack); + clock.tick(199); + sinon.assert.notCalled(socket._ack); + clock.tick(2); + sinon.assert.called(socket._ack); + }); + + it("should not acknowledge packets if a packet is sent before the ack timeout", function() { + socket._ack = sinon.spy(); + eio.emit("message", JSON.stringify({ + seq: 123, + d: "msg", + ack: 500 + })); + + sinon.assert.notCalled(socket._ack); + clock.tick(199); + socket.send("message"); + sinon.assert.notCalled(socket._ack); + clock.tick(2); + sinon.assert.notCalled(socket._ack); + }); + + }); +}); + +function createMockEio() { + var mock = new EventEmitter(); + mock.readyState = "open"; + mock.send = sinon.spy(); + return mock; +} \ No newline at end of file diff --git a/node_modules/smith/.gitignore b/node_modules/smith/.gitignore new file mode 100644 index 00000000..8f55571c --- /dev/null +++ b/node_modules/smith/.gitignore @@ -0,0 +1,3 @@ +node_modules +.settings.xml +.c9revisions diff --git a/node_modules/smith/.npmignore b/node_modules/smith/.npmignore new file mode 100644 index 00000000..26406e22 --- /dev/null +++ b/node_modules/smith/.npmignore @@ -0,0 +1,3 @@ +samples +test + diff --git a/node_modules/smith/.travis.yml b/node_modules/smith/.travis.yml new file mode 100644 index 00000000..f669a496 --- /dev/null +++ b/node_modules/smith/.travis.yml @@ -0,0 +1,7 @@ +language: node_js +node_js: + - 0.10 + - 0.8 + - 0.6 +script: ./test-all.sh + diff --git a/node_modules/smith/LICENSE b/node_modules/smith/LICENSE new file mode 100644 index 00000000..9e077f64 --- /dev/null +++ b/node_modules/smith/LICENSE @@ -0,0 +1,21 @@ +The MIT License + +Copyright (c) 2012 Ajax.org B.V + +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. \ No newline at end of file diff --git a/node_modules/smith/README.markdown b/node_modules/smith/README.markdown new file mode 100644 index 00000000..f4afb109 --- /dev/null +++ b/node_modules/smith/README.markdown @@ -0,0 +1,238 @@ +# Smith + +[![Build Status](https://secure.travis-ci.org/c9/smith.png)](http://travis-ci.org/c9/smith) + +Smith is an RPC agent system for Node.JS used in architect and vfs. + +## Usage + +Smith can be used in any situation where you have a duplex node stream. This +can be over tcp, stdio, a pipe, or anything that sends bytes back and forth. + +### TCP client-server example + +In this example, I have a TCP server that serves an add function to any agent +clients who want to consume the service. + +For the server, we create a small agent and serve it on a listening tcp port. + +```js +var net = require('net'); +var Agent = require('smith').Agent; + +var api = { + add: function (a, b, callback) { + callback(null, a + b); + } +}; + +// Start a TCP server +net.createServer(function (socket) { + // Create the agent that serves the shared api. + var agent = new Agent(api); + // Connect to the remote agent + agent.connect(socket, function (err, api) { + if (err) return console.error(err.stack); + console.log("A new client connected"); + }); + // Log when the agent disconnects + agent.on("disconnect", function (err) { + console.error("The client disconnected") + if (err) console.error(err.stack); + }); + +}).listen(1337, function () { + console.log("Agent server listening on port 1337"); +}); +``` + +Then to consume this TCP service, we can create an agent and connect it to the +tcp server. + +```js +var net = require('net'); +var Agent = require('smith').Agent; + +var socket = net.connect(1337, function () { + // Create our client + var agent = new Agent() + agent.connect(socket, function (err, api) { + api.add(4, 5, function (err, result) { + if (err) throw err; + console.log("4 + 5 = %s", result); + agent.disconnect(); + }); + }); +}); +``` + +For an example of how to reconnect if the connection goes down, see +https://github.com/c9/smith/blob/master/samples/tcp-client-autoreconnect.js + +### STDIO Parent-Child Example + +Here we create a node process that spawns a child process, and the two talk to eachother calling functions both directions. + +Both share a simple API library. + +```js +exports.ping = function (callback) { + callback(null, process.pid + " pong"); +} +``` + +The parent creates an Agent,spawns the child, and connects. + +```js +var spawn = require('child_process').spawn; +var Agent = require('smith').Agent; +var Transport = require('smith').Transport; + +// Create an agent instance using the shared API +var agent = new Agent(require('./process-shared-api')); + +// Spawn the child process that runs the other half. +var child = spawn(process.execPath, [__dirname + "/process-child.js"]); +// Forward the child's console output +child.stderr.pipe(process.stderr); + +var transport = new Transport(child.stdout, child.stdin); +agent.connect(transport, function (err, api) { + if (err) throw err; + // Call the child's API in a loop + function loop() { + api.ping(function (err, message) { + if (err) throw err; + console.log("Child says %s", message); + }) + setTimeout(loop, Math.random() * 1000); + } + loop(); +}); +``` + +The child resumes stdin, creates an Agent, and connects. + +```js +var Agent = require('smith').Agent; +var Transport = require('smith').Transport; + +// Redirect logs to stderr since stdout is used for data +console.log = console.error; + +// Start listening on stdin for smith rpc data. +process.stdin.resume(); + +var agent = new Agent(require('./process-shared-api')); +var transport = new Transport(process.stdin, process.stdout); +agent.connect(transport, function (err, api) { + if (err) throw err; + // Call the parent's API in a loop + function loop() { + api.ping(function (err, message) { + if (err) throw err; + console.log("Got %s from parent", message); + }) + setTimeout(loop, Math.random() * 1000); + } + loop(); +}); +``` + +## Class: Agent + +Agent is the main class used in smith. It represents an agent in your mesh +network. It provides a set of service functions exposed as async functions. + +### new Agent(api) + +Create a new Agent instance that serves the functions listed in `api`. + +### agent.api + +The functions this agent serves locally to remote agents. + +### agent.remoteApi + +A object containing proxy functions for the api functions in the remote agent. +Calling these functions when the remote is offline will result in the last +argument being called with a ENOTCONNECTED error (assuming it's a function). + +### agent.connectionTimeout + +If the connection hasn't happened by 10,000 ms, an ETIMEDOUT error will +happen. To change the timeoutvalue, change `connectionTimeout` on either the +instance or the prototype. Set to zero to disable. + +### Event: 'connect' + +`function (remoteApi) { }` + +When the rpc handshake is complete, the agent will emit a connect event +containing the remoteApi. + +### Event: 'disconnect' + +`function () { }` + +Emitted when the transport dies and the remote becomes offline + +### Event: 'drain' + +When the writable stream in the transport emits drain, it's forwarded here + +### agent.connect(transport, [callback])) + +Start the connection to a new remote agent using `transport`. Emits `connect` when +ready or `error` on failure. Optionally use the callback to get `(err, api, +agent)` results. + +The `transport` argument is either a Transport instance or a duplex Stream. +The callback will be called with `(err, remoteApi)`. + +### agent.disconnect(err) + +Tell the agent to disconnect from the transport with optional error reason `err`. + +### agent.send(message) + +Encode a message and send it on the transport. Used internally to send +function calls. Returns false if the kernel buffer is full. + +## Class: Transport + +Transport is a wrapper around a duplex socket to allow two Agent instances to +talk to eachother. A transport will shut down itself if either end of the +socket ends and emit an `error` event. + +### new Transport(input, [output]) + +Pass in either a duplex Stream instance or two streams (one readable, one +writable). This transport object can then be used to connect to another +Agent. + +### Event: 'message' + +`function (message) { }` + +Emitted when a message arrives from the remote end of the transport.ts + +### Event: 'drain' + +`function () { }` + +Emitted when the writable stream emits drain. (The write buffer is empty.) + +### Event: 'disconnect' + +`function (err) { }` + +Emitted when the transport dies. If this was caused by an error, it will be +emitted here. + +### transport.send(message) + +Send a message to the other end of the transport. Message is JSON +serializable object with the addition of being able to serialize node Buffer +instances and `undefined` values. Returns true if the kernel buffer is full +and you should pause your incoming stream. diff --git a/node_modules/smith/component.json b/node_modules/smith/component.json new file mode 100644 index 00000000..ee637928 --- /dev/null +++ b/node_modules/smith/component.json @@ -0,0 +1,11 @@ +{ + "name": "smith", + "description": "Smith is an RPC agent system for Node.JS used in architect and vfs.", + "version": "0.1.16", + "main": "smith.js", + "dependencies": { + "creationix/msgpack-js-browser": "*", + "juliangruber/events": "*" + }, + "scripts": ["smith.js"] +} diff --git a/node_modules/smith/package.json b/node_modules/smith/package.json new file mode 100644 index 00000000..c23d0edb --- /dev/null +++ b/node_modules/smith/package.json @@ -0,0 +1,32 @@ +{ + "author": "Ajax.org B.V. ", + "contributors": [ + { + "name": "Tim Caswell", + "email": "tim@c9.io>" + } + ], + "name": "smith", + "description": "Smith is an RPC agent system for Node.JS used in architect and vfs.", + "version": "0.1.22", + "scripts": { + "test": "./test-all.sh" + }, + "licenses": [ + { + "type": "MIT", + "url": "http://github.com/c9/smith/raw/master/LICENSE" + } + ], + "repository": { + "type": "git", + "url": "git://github.com/c9/smith.git" + }, + "main": "smith.js", + "engines": { + "node": ">=0.6.0" + }, + "dependencies": { + "msgpack-js": "~0.1.0" + } +} diff --git a/node_modules/smith/protocol.markdown b/node_modules/smith/protocol.markdown new file mode 100644 index 00000000..30d7f9ab --- /dev/null +++ b/node_modules/smith/protocol.markdown @@ -0,0 +1,114 @@ +This document explains the actual protocol smith uses to communicate between +agents. + +The Transport class handles message framing and msgpack serializing on top of +whatever stream you give it. This can be tcp, pipe, or something else. The +msgpack library used has slightly extended the format to add `Buffer` and +`undefined` value types for a fuller range of node primitives. If desired +another transport can be used in place that implements the same interface. + +Encoded on top of the serialzation format is reference cycles and callback +functions. + +Since functions can be serialized, rpc using callbacks is natural. Simply +pass your callback as an argument and the other side will get a proxy function +when it's deserialized. When they call that proxy function, a message will be +sent back and your callback will get called with the deserialized arguments +(which can include yet another callback). Since the callbacks are executed on +their native side, closure variables and all other state is preserved. +Callbacks functions must be called once and only once to prevent memory leaks. +If the transport goes down, all pending callbacks will get called with an +error object as their first argument. It's advised to use node-style +callbacks in your APIs. The named function in the Agent can be called +multiple times. + +### Function Encoding + +Functions are encoded as an object with one key, `$`. The value of this object is the +unique function index in the local function repository. Function keys are +integers. An example encoded function can look like `{$: 3}` where +`remote.callbacks[3]` is the real function. Numbers are reused as soon as +they are freed (when the function is called). + +### Cycle Encoding + +Cycles are also encoded as `$` keyed objects. The value is the path to +the actual value as an array of strings. In this way it works like a file- +system symlink. For example. Given the following cyclic object: + +```js +var entry = { + name: "Bob", + boss: { name: "Steve" } +}; +entry.self = entry; +entry.manager = entry.boss; +``` + +The following encoded object is generated by the internal `freeze` function. + +```js +{ + name: 'Bob', + boss: { name: 'Steve' }, + self: { $: [] }, + manager: { $: [ 'boss' ] } +} +``` + +See that the path `[]` points to the root object itself, and `['boss']` points to +the boss property in the root. + +## Function Calling + +Every RPC message is a function call. There are three kinds of function calls +and they are all encoded the same way. A call is sent over the transport as a flat array. The first item is the function name or key, the rest are arguments to that function. There is no return value since everything is async. Use callbacks to get results. + +In these examples, we'll assume the following setup: Given a pair A and B, A has the api function "add", and B has none. They are connected to eachother through some transport. + +### Named functions + +To call a named function simply pass the function name as the first array value. + +B calls A's "add" function and passes it `(3, 5, function (err, result) {...})` + +``` +B->A ["add", 3, 4, {$:1}] +``` + +### Callback functions + +To call a callback, use the integer key the other side gave you and it will route the arguments to the callback. + +A responds to B's "add" query. + +``` +A->B [1, null, 7] +``` + +### "ready" call (connection handshake) + +In the initial connection handshake, both sides call a virtual "ready" function passing in a single callback. The other side will reply using this callback with an array of function names. This result is used to populate the wrapper functions in remote.api. + +The handshake in our example would have looked like this. + +``` +A->B ["ready", {$:1}] +B->A ["ready", {$:1}] +B->A [1, []] +A->B [1, ["add"]] +``` + +Note that both sides can do the handshake at the same time. Also note that the function key numbers are independently namespaced per Remote instance. Since this was the first callback for both sides, they both used `1` as the callback key. B then responded using the callback that it has no api functions by sending an empty array. A responded by saying it has one. + +As soon as one side receives the api list for the other side, it will emit the "connect" event and be ready to use. + +## Debugging tips + +A very powerful debugging trick is to log all messages in the protocol. On the first line of `Remote.prototype._onMessage`, add this log statement. + +```js +console.log(process.pid, message); +``` + +This will log the process id of the process receiving the message as well as the message already msgpack decoded (but not yet livened). diff --git a/node_modules/smith/samples/process-child.js b/node_modules/smith/samples/process-child.js new file mode 100644 index 00000000..698cf691 --- /dev/null +++ b/node_modules/smith/samples/process-child.js @@ -0,0 +1,23 @@ +var Agent = require('smith').Agent; +var Transport = require('smith').Transport; + +// Redirect logs to stderr since stdout is used for data +console.log = console.error; + +// Start listening on stdin for smith rpc data. +process.stdin.resume(); + +var agent = new Agent(require('./process-shared-api')); +var transport = new Transport(process.stdin, process.stdout); +agent.connect(transport, function (err, api) { + if (err) throw err; + // Call the parent's API in a loop + function loop() { + api.ping(function (err, message) { + if (err) throw err; + console.log("Got %s from parent", message); + }) + setTimeout(loop, Math.random() * 1000); + } + loop(); +}); diff --git a/node_modules/smith/samples/process-parent.js b/node_modules/smith/samples/process-parent.js new file mode 100644 index 00000000..5e63d72c --- /dev/null +++ b/node_modules/smith/samples/process-parent.js @@ -0,0 +1,25 @@ +var spawn = require('child_process').spawn; +var Agent = require('smith').Agent; +var Transport = require('smith').Transport; + +// Create an agent instance using the shared API +var agent = new Agent(require('./process-shared-api')); + +// Spawn the child process that runs the other half. +var child = spawn(process.execPath, [__dirname + "/process-child.js"]); +// Forward the child's console output +child.stderr.pipe(process.stderr); + +var transport = new Transport(child.stdout, child.stdin); +agent.connect(transport, function (err, api) { + if (err) throw err; + // Call the child's API in a loop + function loop() { + api.ping(function (err, message) { + if (err) throw err; + console.log("Child says %s", message); + }) + setTimeout(loop, Math.random() * 1000); + } + loop(); +}); diff --git a/node_modules/smith/samples/process-shared-api.js b/node_modules/smith/samples/process-shared-api.js new file mode 100644 index 00000000..1e0e4c54 --- /dev/null +++ b/node_modules/smith/samples/process-shared-api.js @@ -0,0 +1,4 @@ +// A very simple API +exports.ping = function (callback) { + callback(null, process.pid + " pong"); +} diff --git a/node_modules/smith/samples/tcp-client-autoreconnect.js b/node_modules/smith/samples/tcp-client-autoreconnect.js new file mode 100644 index 00000000..256a707f --- /dev/null +++ b/node_modules/smith/samples/tcp-client-autoreconnect.js @@ -0,0 +1,56 @@ +var net = require('net'); +var Agent = require('smith').Agent; +var Transport = require('smith').Transport; + +// Create our client agent. +var agent = new Agent(); + +var backoff = 1000; +var add; + +// Query the API to test the connection +function query() { + var a = Math.floor(Math.random() * 10) + 1; + var b = Math.floor(Math.random() * 10) + 1; + console.log("%s + %s = ...", a, b); + add(a, b, function (err, result) { + if (err) console.error(err.stack); + else console.log("%s + %s = %s", a, b, result); + }); +} + +// On the first connect, store a reference to the add function and start +// calling it on an interval +agent.once("connect", function (api) { + add = api.add; + console.log("Running query() every 3000 ms"); + setInterval(query, 3000); + query(); +}); + +// On every connect, log the connection and reset the backoff time. +agent.on("connect", function () { + console.log("Connected!"); + if (backoff > 1000) { + console.log(" Resetting backoff to 1000ms."); + backoff = 1000; + } +}); + +// Set up auto-reconnect and do initial connection +agent.on("disconnect", onError); +connect(); + +function connect() { + var socket = net.connect(1337, function () { + agent.connect(new Transport(socket)); + }); + socket.on("error", onError); +} + +function onError(err) { + if (err) console.error(err.stack); + console.log("Reconnecting in %s ms", backoff); + setTimeout(connect, backoff); + backoff *= 2; +} diff --git a/node_modules/smith/samples/tcp-client.js b/node_modules/smith/samples/tcp-client.js new file mode 100644 index 00000000..4026d6cd --- /dev/null +++ b/node_modules/smith/samples/tcp-client.js @@ -0,0 +1,14 @@ +var net = require('net'); +var Agent = require('smith').Agent; + +var socket = net.connect(1337, function () { + // Create our client + var agent = new Agent() + agent.connect(socket, function (err, api) { + api.add(4, 5, function (err, result) { + if (err) throw err; + console.log("4 + 5 = %s", result); + agent.disconnect(); + }); + }); +}); diff --git a/node_modules/smith/samples/tcp-server.js b/node_modules/smith/samples/tcp-server.js new file mode 100644 index 00000000..930c27dd --- /dev/null +++ b/node_modules/smith/samples/tcp-server.js @@ -0,0 +1,27 @@ +var net = require('net'); +var Agent = require('smith').Agent; + +var api = { + add: function (a, b, callback) { + callback(null, a + b); + } +}; + +// Start a TCP server +net.createServer(function (socket) { + // Create the agent that serves the shared api. + var agent = new Agent(api); + // Connect to the remote agent + agent.connect(socket, function (err, api) { + if (err) return console.error(err.stack); + console.log("A new client connected"); + }); + // Log when the agent disconnects + agent.on("disconnect", function (err) { + console.error("The client disconnected") + if (err) console.error(err.stack); + }); + +}).listen(1337, function () { + console.log("Agent server listening on port 1337"); +}); diff --git a/node_modules/smith/smith.js b/node_modules/smith/smith.js new file mode 100644 index 00000000..d0f8d989 --- /dev/null +++ b/node_modules/smith/smith.js @@ -0,0 +1,825 @@ +/* +Copyright (c) 2012 Ajax.org B.V + +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. +*/ +( // Module boilerplate to support browser globals, node.js and AMD. + (typeof module !== "undefined" && function (m) { module.exports = m(require('events'), require('msgpack-js')); }) || + (typeof define === "function" && function (m) { define("smith", ["events", "msgpack-js"], m); }) || + (function (m) { window.smith = m(window.events, window.msgpack); }) +)(function (events, msgpack) { +"use strict"; +var EventEmitter = events.EventEmitter; + +function inherits(Child, Parent) { + Child.prototype = Object.create(Parent.prototype, { constructor: { value: Child }}); +} + +var exports = {}; + +exports.msgpack = msgpack; +exports.Agent = Agent; +exports.Transport = Transport; +exports.deFramer = deFramer; +exports.liven = liven; +exports.freeze = freeze; +exports.getType = getType; + +//////////////////////////////////////////////////////////////////////////////// + +// Transport is a connection between two Agents. It lives on top of a duplex, +// binary stream. +// @input - the stream we listen for data on +// @output - the stream we write to (can be the same object as input) +// @send(message) - send a message to the other side +// "message" - event emitted when we get a message from the other side. +// "disconnect" - the transport was disconnected +// "error" - event emitted for stream error or disconnect +// "drain" - drain event from output stream +function Transport(input) { + var self = this; + var output; + if (Array.isArray(input)) { + output = input[1]; + input = input[0]; + } else { + output = input; + } + this.input = input; + this.output = output; + + if (!input.readable) throw new Error("Input is not readable"); + if (!output.writable) throw new Error("Output is not writable"); + + // Attach event listeners + input.on("data", onData); + input.on("end", onDisconnect); + input.on("timeout", onDisconnect); + input.on("close", onDisconnect); + input.on("error", onError); + output.on("drain", onDrain); + if (output !== input) { + output.on("end", onDisconnect); + output.on("timeout", onDisconnect); + output.on("close", onDisconnect); + output.on("error", onError); + } + + var parse = deFramer(function(err, frame) { + if (err) + return self.emit("error", err); + + var message; + try { + message = msgpack.decode(frame); + } catch (err) { + return self.emit("error", err); + } + + exports.debug && console.log(process.pid + " <- " + require('util').inspect(message, false, 2, true)); + self.emit("message", message); + }); + + // Route data chunks to the parser, but check for errors + function onData(chunk) { + parse(chunk); + } + + // Forward drain events from the writable stream + function onDrain() { + self.emit("drain"); + } + // Forward all error events to the transport + function onError(err) { + self.emit("error", err); + } + function onDisconnect() { + // Remove all the listeners we added and destroy the streams + input.removeListener("data", onData); + input.removeListener("end", onDisconnect); + input.removeListener("timeout", onDisconnect); + input.removeListener("close", onDisconnect); + output.removeListener("drain", onDrain); + if (input.destroy) input.destroy(); + if (input !== output) { + output.removeListener("end", onDisconnect); + output.removeListener("timeout", onDisconnect); + output.removeListener("close", onDisconnect); + if (output.destroy && output !== process.stdout) output.destroy(); + } + self.emit("disconnect"); + } + this.disconnect = onDisconnect; +} +inherits(Transport, EventEmitter); + +Transport.prototype.send = function (message) { + // Uncomment to debug protocol + exports.debug && console.log(process.pid + " -> " + require('util').inspect(message, false, 2, true)); + + // Serialize the messsage. + var frame = msgpack.encode(message); + + // Send a 4 byte length header before the frame. + var header = new Buffer(10); + header.writeUInt32BE(frame.length, 0); + + // Compute 4 byte jenkins hash + var a = frame.length >> 24, + b = (frame.length >> 16) & 0xff, + c = (frame.length >> 8) & 0xff, + d = frame.length & 0xff; + + // Little bit inlined, but fast + var hash = 0; + hash += a; + hash += hash << 10; + hash += hash >> 6; + hash += b; + hash += hash << 10; + hash += hash >> 6; + hash += c; + hash += hash << 10; + hash += hash >> 6; + hash += d; + hash += hash << 10; + hash += hash >> 6; + + // Shuffle bits + hash += hash << 3; + hash = hash ^ (hash >> 11); + hash += hash << 15; + hash |= 0; + header.writeInt32BE(hash, 4, true); + + // 2 Reserved bytes for future usage + header.writeUInt16BE(0, 8); + + this.output.write(header); + + + // Send the serialized message. + return this.output.write(frame); +}; + +// A simple state machine that consumes raw bytes and emits frame events. +// Returns a parser function that consumes buffers. It emits message buffers +// via onMessage callback passed in. +function deFramer(onFrame) { + var buffer; + var state = 0; + var length = 0; + var expected_hash = 0; + var hash = 0; + var offset; + return function parse(chunk) { + for (var i = 0, l = chunk.length; i < l; i++) { + switch (state) { + case 0: + length |= chunk[i] << 24; + expected_hash = 0; + state = 1; + break; + case 1: length |= chunk[i] << 16; state = 2; break; + case 2: length |= chunk[i] << 8; state = 3; break; + case 3: + length |= chunk[i]; + expected_hash += chunk[i]; + expected_hash += expected_hash << 10; + expected_hash += expected_hash >> 6; + + // Shuffle bits + expected_hash += expected_hash << 3; + expected_hash = expected_hash ^ (expected_hash >> 11); + expected_hash += expected_hash << 15; + expected_hash |= 0; + + hash = 0; + state = 4; + break; + case 4: hash |= chunk[i] << 24; state = 5; break; + case 5: hash |= chunk[i] << 16; state = 6; break; + case 6: hash |= chunk[i] << 8; state = 7; break; + case 7: hash |= chunk[i]; state = 8; + if (hash !== expected_hash) { + return onFrame(new Error("Hash mismatch, expected: " + expected_hash + + " got: " + hash + ", chunk: " + chunk)); + } + + if (length > 100 * 1024 * 1024) { + return onFrame(new Error("Too big buffer " + length + + ", chunk: " + chunk)); + } + + buffer = new Buffer(length); + offset = 0; + state = 9; + break; + // Two reserved bytes + case 9: state = 10; break; + case 10: state = 11; break; + + // Data itself + case 11: + var len = l - i; + var emit = false; + if (len + offset >= length) { + emit = true; + len = length - offset; + } + // TODO: optimize for case where a copy isn't needed can a slice can + // be used instead? + chunk.copy(buffer, offset, i, i + len); + offset += len; + i += len - 1; + if (emit) { + onFrame(null, buffer); + state = 0; + length = 0; + buffer = undefined; + offset = undefined; + } + break; + } + + // Common case + if (state <= 3 && !emit) { + expected_hash += chunk[i]; + expected_hash += expected_hash << 10; + expected_hash += expected_hash >> 6; + } + + emit = false; + } + }; +} + +//////////////////////////////////////////////////////////////////////////////// + +// Agent is an API serving node in the architect-agent rpc mesh. It contains +// a table of functions that actually do the work and serve them to a Agent +// agent. An agent can connect to one other agent at a time. +function Agent(api) { + if (!this instanceof Agent) throw new Error("Forgot to use new with Agent constructor"); + + this.api = api || {}; + + // Bind event handlers and callbacks + this.disconnect = this.disconnect.bind(this); + this._onMessage = this._onMessage.bind(this); + this._onDrain = this._onDrain.bind(this); + this._onReady = this._onReady.bind(this); + this._getFunction = this._getFunction.bind(this); + this._storeFunction = this._storeFunction.bind(this); + + this.remoteApi = {}; // Persist the API object between connections + this.transport = undefined; + this.callbacks = undefined; + this.nextKey = undefined; +} +inherits(Agent, EventEmitter); + +// Time to wait for Agent connections to finish +Agent.prototype.connectionTimeout = 10000; + +Agent.prototype.connect = function (transport, callback) { + // If they passed in a raw stream, wrap it. + if (!(transport instanceof Transport)) + transport = new Transport(transport); + + this.transport = transport; + this.callbacks = {}; + this.nextKey = 1; + + transport.on("error", this.disconnect); + transport.on("disconnect", this.disconnect); + transport.on("message", this._onMessage); + transport.on("drain", this._onDrain); + + // Handshake with the other end + this.send(["ready", this._onReady]); + + // Start timeout and route events to callback + this.on("connect", onConnect); + this.on("disconnect", onDisconnect); + this.on("error", onError); + var timeout; + if (this.connectionTimeout) { + timeout = setTimeout(onTimeout, this.connectionTimeout); + } + + var self = this; + function onConnect(api) { + reset(); + if (callback) callback(null, api); + } + function onDisconnect(err) { + onError(err || new Error("EDISCONNECT: Agent disconnected")); + } + function onError(err) { + reset(); + if (callback) callback(err); + else self.emit("error", err); + } + function onTimeout() { + reset(); + var err = new Error("ETIMEDOUT: Timeout while waiting for Agent agent to connect."); + err.code = "ETIMEDOUT"; + self.emit("error", err); + } + // Only one event should happen, so stop event listeners on first event. + function reset() { + self.removeListener("connect", onConnect); + self.removeListener("disconnect", onDisconnect); + self.removeListener("error", onError); + clearTimeout(timeout); + } +}; + +Agent.prototype.send = function (message) { + message = freeze(message, this._storeFunction); + if (!this.transport) { + console.log("smith can't send:") + // console.dir(this) + console.dir(message) + console.trace() + return + } + + try { var result = this.transport.send(message); } + catch(e) { console.error("Could not send message: ", e.message ); } + + return result; +}; + +Agent.prototype._onReady = function (names, env) { + if (!Array.isArray(names)) return; + var self = this; + names.forEach(function (name) { + // Ignore already set functions so that existing function references + // stay valid. + if (self.remoteApi.hasOwnProperty(name)) return; + self.remoteApi[name] = function () { + // When disconnected we can't forward the call. + if (!self.transport) { + var callback = arguments[arguments.length - 1]; + if (typeof callback === "function") { + setTimeout(function(){ + var err = new Error("ENOTCONNECTED: Agent is offline, try again later"); + err.code = "ENOTCONNECTED"; + callback(err); + }, 10); + } + return; + } + var args = [name]; + args.push.apply(args, arguments); + return self.send(args); + }; + }); + this.remoteEnv = env; + this._emitConnect(); +}; + +Agent.prototype._emitConnect = function () { + this.emit("connect", this.remoteApi); +}; + +// Disconnect resets the state of the Agent, flushes callbacks and emits a +// "disconnect" event with optional error object. +Agent.prototype.disconnect = function (err) { + if (!this.transport) { + // Agent is already disconnected + return; + } + + var cerr = err; + if (!cerr) { + cerr = new Error("EDISCONNECT: Agent disconnected"); + cerr.code = "EDISCONNECT"; + } + + // Flush any callbacks + if (this.callbacks) { + var callbacks = this.callbacks; + this.callbacks = undefined; + forEach(callbacks, function (callback) { + callback(cerr); + }); + } + + // Disconnect from transport + if (this.transport) { + this.transport.removeListener("error", this.disconnect); + this.transport.removeListener("disconnect", this.disconnect); + this.transport.removeListener("message", this._onMessage); + this.transport.removeListener("drain", this._onDrain); + this.transport.disconnect(); + this.transport = undefined; + } + + this.emit("disconnect", err); + this.nextKey = undefined; +}; + +// Forward drain events +Agent.prototype._onDrain = function () { + this.emit("drain"); +}; + +// Route incoming messages to the right functions +Agent.prototype._onMessage = function (message) { + + if (!(Array.isArray(message) && message.length)) { + return this.emit("error", new Error("Message should be an array")); + } + + message = liven(message, this._getFunction); + var id = message[0]; + + var fn; + if (id === "ready") { + var keys = Object.keys(this.api); + var env = typeof process !== "undefined" && process.env; + fn = function (callback) { + callback(keys, env); + }; + } + else { + fn = typeof id === "string" ? this.api[id] : this.callbacks[id]; + if (!fn) console.log("MISSING ID", id); + } + if (typeof fn !== "function") { + return this.emit("error", new Error("Should be function")); + } + fn.apply(this, message.slice(1)); +}; + +// Create a proxy function that calls fn key on the Agent side. +// This is for when a Agent passes a callback to a local function. +Agent.prototype._getFunction = function (key) { + // var transport = this.transport; + var _self = this; + return function () { + // Call a Agent function using [key, args...] + var args = [key]; + // Push is actually fast http://jsperf.com/array-push-vs-concat-vs-unshift + args.push.apply(args, arguments); + return _self.send(args); + }; +}; + +// This is for when we call a Agent function and pass in a callback +Agent.prototype._storeFunction = function (fn) { + if (!this.callbacks) + return new Error("Agent disconnected"); + + var key = this.nextKey; + while (this.callbacks.hasOwnProperty(key)) { + key = (key + 1) >> 0; + if (key === this.nextKey) { + throw new Error("Ran out of keys!!"); + } + } + this.nextKey = (key + 1) >> 0; + + var callbacks = this.callbacks; + var self = this; + // Wrap is a self cleaning function and store in the index + callbacks[key] = function () { + delete callbacks[key]; + self.nextKey = key; + return fn.apply(this, arguments); + }; + return key; +}; + +// Convert a js object into a serializable object when functions are +// encountered, the storeFunction callback is called for each one. +// storeFunction takes in a function and returns a unique id number. Cycles +// are stored as object with a single $ key and an array of strigs as the +// path. Functions are stored as objects with a single $ key and id as value. +// props. properties starting with "$" have an extra $ prepended. +function freeze(value, storeFunction) { + var seen = []; + var paths = []; + function find(value, path) { + // find the type of the value + var type = getType(value); + // pass primitives through as-is + if (type !== "function" && type !== "object" && type !== "array" && type !== "date") { + return value; + } + + // Look for duplicates + var index = seen.indexOf(value); + if (index >= 0) { + return { "$": paths[index] }; + } + // If not seen, put it in the registry + index = seen.length; + seen[index] = value; + paths[index] = path; + + var o; + // Look for functions + if (type === "function") { + o = storeFunction(value); + } + + if (type === "date") { + o = {d:value.getTime()}; + } + + if (o) return {$:o}; + + // Recurse on objects and arrays + return map(value, function (sub, key) { + return find(sub, path.concat([key])); + }, null, function (key) { + return key[0] === "$" ? "$" + key : key; + }); + } + return find(value, []); +} + +// Converts flat objects into live objects. Cycles are re-connected and +// functions are inserted. The getFunction callback is called whenever a +// frozen function is encountered. It expects an ID and returns the function +function liven(message, getFunction) { + function find(value, parent, key) { + // find the type of the value + var type = getType(value); + + // Unescape $$+ escaped keys + if (key[0] === "$") key = key.substr(1); + + // pass primitives through as-is + if (type !== "function" && type !== "object" && type !== "array") { + parent[key] = value; + return value; + } + + // Load Specials + if (value.hasOwnProperty("$")) { + var special = value.$; + // Load backreferences + if (Array.isArray(special)) { + parent[key] = get(obj.root, special); + return parent[key]; + } + if (typeof special === "object") { + parent[key] = new Date(special.d); + return parent[key]; + } + // Load functions + parent[key] = getFunction(special); + return parent[key]; + } + + // Recurse on objects and arrays + var o = Array.isArray(value) ? [] : {}; + parent[key] = o; + forEach(value, function (sub, key) { + find(sub, o, key); + }); + return obj; + } + var obj = {}; + find(message, obj, "root"); + return obj.root; +} + +//////////////////////////////////////////////////////////////////////////////// + +// Typeof is broken in javascript, add support for null and buffer types +function getType(value) { + if (value === null) { + return "null"; + } + if (Array.isArray(value)) { + return "array"; + } + if (typeof Buffer !== "undefined" && Buffer.isBuffer(value)) { + return "buffer"; + } + // TODO: find a way to work with Date instances from other contexts. + if (value instanceof Date) { + return "date"; + } + return typeof value; +} + +// Traverse an object to get a value at a path +function get(root, path) { + var target = root; + for (var i = 0, l = path.length; i < l; i++) { + target = target[path[i]]; + } + return target; +} + +// forEach that works on both arrays and objects +function forEach(value, callback, thisp) { + if (typeof value.forEach === "function") { + return value.forEach.call(value, callback, thisp); + } + var keys = Object.keys(value); + for (var i = 0, l = keys.length; i < l; i++) { + var key = keys[i]; + callback.call(thisp, value[key], key, value); + } +} + +// map that works on both arrays and objects +function map(value, callback, thisp, keyMap) { + if (typeof value.map === "function") { + return value.map.call(value, callback, thisp); + } + var obj = {}; + var keys = Object.keys(value); + for (var i = 0, l = keys.length; i < l; i++) { + var key = keys[i]; + obj[keyMap ? keyMap(key) : key] = callback.call(thisp, value[key], key, value); + } + return obj; +} + + +exports.WebSocketTransport = WebSocketTransport; +inherits(WebSocketTransport, Transport); + +// "message" - event emitted when we get a message from the other side. +// "disconnect" - the transport was disconnected +// "error" - event emitted for stream error or disconnect +// "drain" - drain event from output stream +function WebSocketTransport(socket) { + this.socket = socket; + var self = this; + + socket.on("message", onMessage); + socket.on("close", onDisconnect); + socket.on("error", onError); + function onError(err) { + self.emit("error", err); + } + function onMessage(data) { + var message; + try { message = msgpack.decode(data); } + catch (err) { return onError(err); } + exports.debug && console.log(process.pid + " <- " + require('util').inspect(message, false, 2, true)); + self.emit("message", message); + } + function onDisconnect() { + // Remove all the listeners we added and destroy the socket + socket.removeListener("message", onMessage); + socket.removeListener("close", onDisconnect); + self.emit("disconnect"); + } + this.disconnect = onDisconnect; + // TODO: Implement "drain" event, pause(), and resume() properly. + // function onDrain() { + // self.emit("drain"); + // } +} + +WebSocketTransport.prototype.send = function (message) { + // Uncomment to debug protocol + exports.debug && console.log(process.pid + " -> " + require('util').inspect(message, false, 2, true)); + var data; + try { data = msgpack.encode(message); } + catch (err) { return this.emit("error", err); } + this.socket.send(data, {binary: true}); +}; + +exports.BrowserTransport = BrowserTransport; +inherits(BrowserTransport, Transport); + +function BrowserTransport(websocket) { + this.websocket = websocket; + var self = this; + + websocket.binaryType = 'arraybuffer'; + websocket.onmessage = function (evt) { + var message; + try { message = msgpack.decode(evt.data); } + catch (err) { return onError(err); } + exports.debug && console.log("<-", message); + self.emit("message", message); + }; + + websocket.onclose = function (evt) { + }; + + websocket.onerror = function (evt) { + onError(new Error(evt.data)); + }; + + function onError(err) { + self.emit("error", err); + } + + function onDisconnect() { + // Remove all the listeners we added and destroy the socket + delete websocket.onmessage; + delete websocket.onclose; + self.emit("disconnect"); + } + this.disconnect = onDisconnect; +} + +BrowserTransport.prototype.send = function (message) { + // Uncomment to debug protocol + exports.debug && console.log("->", message); + var data; + try { data = msgpack.encode(message); } + catch (err) { return this.emit("error", err); } + this.websocket.send(data); +}; + +exports.EngineIoTransport = EngineIoTransport; +inherits(EngineIoTransport, Transport); +function EngineIoTransport(socket) { + var self = this; + this.socket = socket; + + // Route errors from socket to transport. + function onError(err) { + self.emit("error", err); + } + + // Parse and route messages from socket to transport. + function onMessage(message) { + if (Array.isArray(message)) { + if (exports.debug) { + console.log("<-", message); + } + self.emit("message", message); + } + else { + self.emit("legacy", message); + } + } + + // Route close events as disconnect events + function onClose(reason) { + self.emit("disconnect", reason); + cleanup(); + } + + function onDrain() { + self.emit("drain"); + } + + function onDisconnect(err) { + self.emit("disconnect", err); + cleanup(); + } + + socket.on("error", onError); + socket.on("message", onMessage); + socket.on("close", onClose); + socket.on("drain", onDrain); + socket.on("disconnect", onDisconnect); + + this.disconnect = function () { + socket.close(); + }; + + function cleanup() { + socket.removeListener("error", onError); + socket.removeListener("message", onMessage); + socket.removeListener("close", onClose); + socket.removeListener("drain", onDrain); + socket.removeListener("disconnect", onDisconnect); + } + + // Encode and route send calls to socket. + this.send = function (message) { + if (exports.debug && Array.isArray(message)) { + console.log("->", message); + } + return socket.send(message); + }; + +} + + +return exports; +}); diff --git a/node_modules/smith/test-all.sh b/node_modules/smith/test-all.sh new file mode 100755 index 00000000..66a65a29 --- /dev/null +++ b/node_modules/smith/test-all.sh @@ -0,0 +1,14 @@ +#!/bin/sh +cd tests +npm install +echo "\nChecking message deframer..." && \ +node test-framer.js && \ +echo "\nChecking message scrubber..." && \ +node test-scrubber.js && \ +echo "\nChecking Agent interface..." && \ +node test-agent.js && \ +echo "\nChecking for memory leaks..." && \ +node test-memory-leaks.js && \ +echo "\nTesting in browser..." && \ +echo "DISABLED: phantomjs doesn't support binary-websockets yet" +# node test-browser.js diff --git a/node_modules/smith/tests/README b/node_modules/smith/tests/README new file mode 100644 index 00000000..ea5d403d --- /dev/null +++ b/node_modules/smith/tests/README @@ -0,0 +1 @@ +To run these tests, grab the server's dependencies with `npm install`. You may need to `npm install -g jam` first. diff --git a/node_modules/smith/tests/helpers.js b/node_modules/smith/tests/helpers.js new file mode 100644 index 00000000..4ca75931 --- /dev/null +++ b/node_modules/smith/tests/helpers.js @@ -0,0 +1,45 @@ +// Mini test framework for async tests. +var assert = require('assert'); +global.setImmediate = global.setImmediate || process.nextTick; + +var expectations = {}; +function expect(message) { expectations[message] = new Error("Missing expectation: " + message); } +function fulfill(message) { delete expectations[message]; } +process.addListener('exit', function () { + Object.keys(expectations).forEach(function (message) { + throw expectations[message]; + }); +}); + +global.assert = assert; +global.expect = expect; +global.fulfill = fulfill; + +var Stream = require('stream').Stream; +var Transport = require('..').Transport; + +// Make a fake pipe pair for testing. +global.makePair = function makePair(a, b, log) { + var left = new Stream(); + var right = new Stream(); + left.writable = true; + left.readable = true; + right.writable = true; + right.readable = true; + left.write = function (chunk) { + setImmediate(function () { + if (log) console.log(a,"->",b,chunk); + right.emit("data", chunk); + }); + }; + right.write = function (chunk) { + setImmediate(function () { + if (log) console.log(b,"->",a,chunk); + left.emit("data", chunk); + }); + }; + var pair = {}; + pair[a] = new Transport(left); + pair[b] = new Transport(right); + return pair; +} diff --git a/node_modules/smith/tests/package.json b/node_modules/smith/tests/package.json new file mode 100644 index 00000000..0295910d --- /dev/null +++ b/node_modules/smith/tests/package.json @@ -0,0 +1,21 @@ +{ + "name": "smith-browsertest", + "prvate": true, + "version": "0.0.0", + "scripts": { + "install": "jam install" + }, + "dependencies": { + "ws": "~0.4.21", + "stack": "~0.1.0", + "creationix": "~0.3.1", + "jamjs": "~0.2.8" + }, + "jam": { + "packageDir": "public/jam", + "baseUrl": "public", + "dependencies": { + "msgpack-js": "~0.1.2" + } + } +} diff --git a/node_modules/smith/tests/phantom.js b/node_modules/smith/tests/phantom.js new file mode 100755 index 00000000..c7032f8d --- /dev/null +++ b/node_modules/smith/tests/phantom.js @@ -0,0 +1,28 @@ +#!/usr/bin/env phantomjs + +var url = require('system').env.URL; +console.log('Loading ' + url + ' in headless browser...'); + +var page = require('webpage').create(); + +page.onConsoleMessage = function (msg) { + console.log(msg); +}; + +page.onError = function (msg, trace) { + console.log(msg); + trace.forEach(function(item) { + console.log(' ', item.file, ':', item.line); + }); + phantom.exit(1); +}; + +page.onLoadFinished = function (status) { + if (status !== "success") { + console.log("page.open failed"); + phantom.exit(2); + } +}; + +page.open(url); + diff --git a/node_modules/smith/tests/public/.gitignore b/node_modules/smith/tests/public/.gitignore new file mode 100644 index 00000000..b883a941 --- /dev/null +++ b/node_modules/smith/tests/public/.gitignore @@ -0,0 +1 @@ +jam diff --git a/node_modules/smith/tests/public/index.html b/node_modules/smith/tests/public/index.html new file mode 100644 index 00000000..dc00fc1d --- /dev/null +++ b/node_modules/smith/tests/public/index.html @@ -0,0 +1,34 @@ + + + + + Smith + + + +

      Smith

      + + + + + + + + + + +
      TestResult
      + + + + diff --git a/node_modules/smith/tests/public/smith.js b/node_modules/smith/tests/public/smith.js new file mode 120000 index 00000000..056dc9af --- /dev/null +++ b/node_modules/smith/tests/public/smith.js @@ -0,0 +1 @@ +../../smith.js \ No newline at end of file diff --git a/node_modules/smith/tests/public/test.js b/node_modules/smith/tests/public/test.js new file mode 100644 index 00000000..9fdeba79 --- /dev/null +++ b/node_modules/smith/tests/public/test.js @@ -0,0 +1,85 @@ +// PhantomJS doesn't support bind yet +Function.prototype.bind = Function.prototype.bind || function (thisp) { + var fn = this; + return function () { + return fn.apply(thisp, arguments); + }; +}; + +var body = document.querySelector("tbody"); +var expectations = {}; +function expect(name) { + expectations[name] = setTimeout(function () { + post("expected '" + name + "'", "timeout", false); + }, 1000); +} +function fulfill(name) { + post("fulfilled '" + name + "'", name, true); + clearTimeout(expectations[name]); +} + +function fail(err) { + post(err.message, err.stack, false); +} +function assert(name, value) { + post(name, value, value); +} +function assertEqual(name, expected, actual) { + post(name + " === " + expected, actual + " === " + expected, expected === actual); +} + +function post(name, result, pass) { + var tr = document.createElement('tr'); + tr.setAttribute("class", pass ? "passed" : "failed"); + var td = document.createElement('td'); + td.textContent = name; + tr.appendChild(td); + td = document.createElement('td'); + td.textContent = result; + tr.appendChild(td); + body.appendChild(tr); + if (pass) console.log(name); + else throw new Error(name + "\n" + result); +} + + +expect("smith loads"); +require(["smith"], function (smith) { + fulfill("smith loads"); + + + ////////////////////////////////////////////////////////////////////////// + + var Agent = smith.Agent; + var BrowserTransport = smith.BrowserTransport; + + assertEqual("typeof smith", "object", typeof smith); + assertEqual("typeof smith.Agent", "function", typeof smith.Agent); + assertEqual("typeof smith.BrowserTransport", "function", typeof smith.BrowserTransport); + + var agent = new Agent(); + + assert("agent instanceof smith.Agent", agent instanceof smith.Agent); + + expect("socket opened"); + var ws = new WebSocket(window.location.origin.replace(/^http/, "ws") + "/"); + ws.onopen = function () { + fulfill("socket opened"); + expect("agent connected"); + agent.connect(new BrowserTransport(ws, true), function (err, serverAgent) { + if (err) return fail(err); + fulfill("agent connected"); + assertEqual("typeof serverAgent", "object", typeof serverAgent); + expect("called add"); + serverAgent.add(5, 7, function (err, result) { + if (err) return fail(err); + fulfill("called add"); + assertEqual("5 + 7", 12, result); + }); + }); + }; + + ////////////////////////////////////////////////////////////////////////// + + +}); diff --git a/node_modules/smith/tests/test-agent.js b/node_modules/smith/tests/test-agent.js new file mode 100644 index 00000000..e4f9cd3a --- /dev/null +++ b/node_modules/smith/tests/test-agent.js @@ -0,0 +1,84 @@ +require('./helpers'); +var Agent = require('..').Agent; +var Transport = require('..').Transport; + +var a = new Agent({ + add: function (a, b, callback) { + callback(a + b); + } +}); +var b = new Agent(); +process.nextTick(testFakeTransport) + +expect("test1"); +function testFakeTransport() { + fulfill("test1"); + console.log("Testing fake transport"); + var pair = makePair("A", "B", true) + expect("connect AB"); + a.connect(pair.A, function (err, AB) { + if (err) throw err; + fulfill("connect AB"); + console.log("A is connected to B!"); + }); + expect("connect BA"); + b.connect(pair.B, function (err, BA) { + if (err) throw err; + fulfill("connect BA"); + console.log("B is connected to A!"); + expect("result"); + BA.add(1, 2, function (result) { + fulfill("result"); + console.log("Result", result); + assert.equal(result, 3); + testSocketTransport(); + }); + }); +} + +expect("alldone"); +expect("test2"); +function testSocketTransport() { + console.log("Test 2 using real tcp server"); + fulfill("test2"); + var net = require('net'); + expect("connect1"); + var server = net.createServer(function (socket) { + fulfill("connect1"); + socket.on('data', function (chunk) { + console.log("B->A (%s):", chunk.length, chunk); + }); + expect("connectAB"); + a.connect(new Transport(socket), function (err, AB) { + if (err) throw err; + fulfill("connectAB"); + console.log("A is connected to B!"); + }); + console.log("connection"); + }); + server.listen(function () { + var port = server.address().port; + expect("connect2"); + var socket = net.connect(port, function () { + fulfill("connect2"); + expect("connectBA"); + b.connect(new Transport(socket), function (err, BA) { + if (err) throw err; + fulfill("connectBA"); + console.log("B is connected to A!"); + expect("result2"); + BA.add(1, 2, function (result) { + fulfill("result2"); + console.log("Result", result); + assert.equal(result, 3); + socket.end(); + server.close(); + fulfill("alldone"); + }); + }); + }); + socket.on("data", function (chunk) { + console.log("A->B (%s):", chunk.length, chunk); + }); + }); +} diff --git a/node_modules/smith/tests/test-browser.js b/node_modules/smith/tests/test-browser.js new file mode 100644 index 00000000..b7ac8ea9 --- /dev/null +++ b/node_modules/smith/tests/test-browser.js @@ -0,0 +1,43 @@ +var creationix = require('creationix'); +var stack = require('stack'); +var http = require('http'); +var WebSocketServer = require('ws').Server +var spawn = require('child_process').spawn; + +var Agent = require('smith').Agent; +var WebSocketTransport = require('smith').WebSocketTransport + + +var api = { + add: function (a, b, callback) { + callback(null, a + b); + } +}; + +var server = http.createServer(stack( + creationix.log(), + creationix.static("/", __dirname + "/public") +)); + +var wss = new WebSocketServer({server: server}); +wss.on("connection", function (websocket) { + var agent = new Agent(api); + agent.connect(new WebSocketTransport(websocket, true), function (err, browserAgent) { + if (err) throw err; + console.log({browserAgent:browserAgent}); + }); +}); + +server.listen(8080, function () { + var url = "http://localhost:" + server.address().port + "/index.html"; + console.log(__dirname + "/phantom.js") + var env = Object.create(process.env); + env.URL = url; + console.log(url); + var phantom = spawn("phantomjs", [__dirname + "/phantom.js"], {env: env, customFds: [-1, 1, 2]}); + phantom.on("exit", function (code, signal) { + if (code) throw new Error("Child died with code " + code); + }); + +}); + diff --git a/node_modules/smith/tests/test-framer.js b/node_modules/smith/tests/test-framer.js new file mode 100644 index 00000000..35ffe46f --- /dev/null +++ b/node_modules/smith/tests/test-framer.js @@ -0,0 +1,90 @@ +require('./helpers'); +var deFramer = require('..').deFramer; + +// Given an array of message buffers, this returns a single buffer that contains +// all the messages framed. +function frameMessages(messages) { + var i, l = messages.length; + + // Calculate total size of final buffer + var total = l * 10; + for (i = 0; i < l; i++) { + total += messages[i].length; + } + + // Create and fill in final buffer + var buffer = new Buffer(total); + var offset = 0; + for (i = 0; i < l; i++) { + var message = messages[i]; + var length = message.length; + buffer.writeUInt32BE(length, offset); + + // Compute 4 byte hash + var a = length >> 24, + b = (length >> 16) & 0xff, + c = (length >> 8) & 0xff, + d = length & 0xff; + + // Little bit inlined, but fast + var hash = 0; + hash += a; + hash += hash << 10; + hash += hash >> 6; + hash += b; + hash += hash << 10; + hash += hash >> 6; + hash += c; + hash += hash << 10; + hash += hash >> 6; + hash += d; + hash += hash << 10; + hash += hash >> 6; + + // Shuffle bits + hash += hash << 3; + hash = hash ^ (hash >> 11); + hash += hash << 15; + hash |= 0; + buffer.writeInt32BE(hash, offset + 4); + + // Reserved bytes + buffer.writeUInt16BE(0, offset + 8); + + message.copy(buffer, offset + 10); + offset += length + 10; + } + + return buffer; +}; + +// Test the de-framer by creating a sample message stream and simulating packet +// sizes from one-byte-per-packet to all-messages-in-one-packet. +var input = [ + {hello: "world"}, + {Goodbye: "Sanity"}, + [1,2,3,4,5,6,7,6,5,4,3,2,1], + + // Big string that will use multiple bytes for length + // (Regression test for hashing) + new Array(300).join('A') +]; +var message = frameMessages(input.map(function (item) { + return new Buffer(JSON.stringify(item)); })); +var length = message.length; +for (var step = 1; step < length; step++) { + var output = []; + var parser = deFramer(function (err, message) { + if (err) throw err; + output.push(JSON.parse(message.toString())); + }); + for (var offset = 0; offset < length; offset += step) { + var end = offset + step + if (end > length) { end = length; } + var chunk = message.slice(offset, end); + console.log(chunk); + parser(chunk); + } + assert.deepEqual(input, output); +} + diff --git a/node_modules/smith/tests/test-memory-leaks.js b/node_modules/smith/tests/test-memory-leaks.js new file mode 100644 index 00000000..039255c3 --- /dev/null +++ b/node_modules/smith/tests/test-memory-leaks.js @@ -0,0 +1,71 @@ +require('./helpers'); +var Agent = require('..').Agent; +var Transport = require('..').Transport; + +var a = new Agent({ + add: function (a, b, callback) { + callback(a + b); + } +}); +var b = new Agent(); +var samples = []; + +var pair = makePair("A", "B"); +a.connect(pair.A, function (err, AB) { + if (err) throw err; + console.log("A is connected to B!"); +}); +b.connect(pair.B, function (err, BA) { + if (err) throw err; + console.log("B is connected to A!"); + var left = 300000; + for (var i = 0; i < 100; i++) { + test(); + } + + function test() { + BA.add(1, 2, function (result) { + assert.equal(result, 3); + if (left % 10000 === 0) { + var sample = process.memoryUsage(); + console.log(sample); + samples.push(sample); + } + if (--left > 0) test(); + else if (left === 0) done(); + }); + } +}); + + +expect("done"); +function done() { + // Trim the first few samples to not include startup time + samples = samples.slice(4); + getSlope("rss"); + fulfill("done"); +} + +function getSlope(key) { + var sum = 0; + var max = 0; + var min = Infinity; + samples.forEach(function (sample) { + var value = sample[key]; + sum += value; + if (value > max) max = value; + if (value < min) min = value; + }); + var mean = sum / samples.length; + var deviation = 0; + samples.forEach(function (sample) { + var diff = mean - sample[key]; + deviation += diff * diff; + }); + deviation = Math.sqrt(deviation / (samples.length - 1)); + var limit = mean / 10; + console.log("%s: min %s, mean %s, max %s, standard deviation %s", key, min, mean, max, deviation); + if (deviation > limit) { + throw new Error("Deviation for " + key + " over " + limit + ", probably a memory leak"); + } +} diff --git a/node_modules/smith/tests/test-scrubber.js b/node_modules/smith/tests/test-scrubber.js new file mode 100644 index 00000000..0b8514f2 --- /dev/null +++ b/node_modules/smith/tests/test-scrubber.js @@ -0,0 +1,87 @@ +require('./helpers'); +var freeze = require('..').freeze; +var liven = require('..').liven; +var getType = require('..').getType; + +function foo() {} +var cycle = {a:true,b:false, d:[1,2,3]}; +cycle.e = cycle.d; +cycle.cycle = cycle; +var pairs = [ + [{$:1,$$:2,$$$:3,$$$$:4}, {$$:1,$$$:2,$$$$:3,$$$$$:4}], + [true, true], + [false, false], + [null, null], + [undefined, undefined], + [42, 42], + [foo, {$:1}], + [[1,2,3,foo],[1,2,3,{$:2}]], + ["Hello", "Hello"], + [new Buffer([0,1,2,3,4,5,6]), new Buffer([0,1,2,3,4,5,6])], + [{fn:foo}, {fn:{$:3}}], + [cycle, {a:true,b:false,d:[1,2,3],e:{$:["d"]},cycle:{$:[]}}], + [new Date("Sun, 28 Mar 1982 11:46:00 MST"), {$:{d:0x59eaaaee40}}] +]; + +var functions = {}; +var nextKey = 0; +function storeFunction(fn) { + var id = ++nextKey; + functions[id] = fn; + return id; +} +function getFunction(id) { + var fn = functions[id]; + delete functions[id]; + return fn; +} + +pairs.forEach(function (pair) { + var live = pair[0]; + var dead = pair[1]; + console.log("testing", pair); + var frozen = freeze(live, storeFunction); + if (!deepEqual(frozen, dead)) { + console.error({actual:frozen,expected:dead}); + throw new Error("freeze fail"); + } + var relive = liven(frozen, getFunction); + if (!deepEqual(relive, live)) { + console.error({actual:relive,expected:live}); + throw new Error("liven fail"); + } +}); + +function deepEqual(a, b) { + var seen = []; + function find(a, b) { + if (a === b) return true; + var type = getType(a); + if (getType(b) !== type) return false; + if (type === "buffer" || type === "date") return a.toString() === b.toString(); + if (type !== "object" && type !== "array") return a === b; + + // Ignore cycles for now + // TODO: this isn't enough + if (seen.indexOf(a) >= 0) { + return true; + } + seen.push(a); + + if (type === "array") { + if (a.length !== b.length) return false; + for (var i = 0, l = a.length; i < l; i++) { + if (!find(a[i], b[i])) return false; + } + return true; + } + var keys = Object.getOwnPropertyNames(a); + if (!deepEqual(keys, Object.getOwnPropertyNames(b))) return false; + for (var i = 0, l = keys.length; i < l; i++) { + var key = keys[i]; + if (!find(a[key],b[key])) return false; + } + return true; + } + return find(a, b); +} diff --git a/node_modules/treehugger/README.md b/node_modules/treehugger/README.md new file mode 100644 index 00000000..6f1254c5 --- /dev/null +++ b/node_modules/treehugger/README.md @@ -0,0 +1,166 @@ +treehugger.js +============= + +`treehugger.js` is a Javascript library for program processing. It +has generic means to represent and manipulate (analyze, transform) +[abstract syntax trees (ASTs)](http://en.wikipedia.org/wiki/Abstract_syntax_tree). +It consists of three parts: + +* A generic ASTs representation format, inspired by [ATerms](http://www.meta-environment.org/Meta-Environment/ATerms)) + that can be used to represent programs written in any language (Java, Ruby, Javascript) + `lib/treehugger/tree.js` +* A set of generic traversals to query, manipulate and annotate these ASTs, + inspired by [Stratego/XT](http://strategoxt.org) + `lib/treehugger/traverse.js` +* A set of analyses for specific languages. Currently: + - Javascript: a ([UglifyJS](https://github.com/mishoo/UglifyJS)-based) parser + and analyses reconstructing the type structure and first attempts at type-inference. + `lib/treehugger/js/*.js` + +The project relies on [require.js](http://requirejs.org) for library loading. + +AST Representation +------------------ + +ast.js uses a few simple data structures to represent ASTs and a textual representation +that makes it easy to debug and write these ASTs. The textual representation +is best introduced by example. + +Consider a simple expresion language with expression as follows: + + 2 + 3 * 1 + +A parser could turn this into the following AST: + + Add + / \ + Num Mul + | / \ + 2 Num Num + | | + 3 1 + +Which is expressed using treehugger.js's textual representation as follows: + + Add(Num("2"), Mul(Num("3"), Num("1"))) + +Using the `treehugger.js` API this AST can be contructed as follows: + + var tree = require('treehugger/tree'); + var node = tree.cons("Add", [tree.cons("Num", [tree.string("2")]), + tree.cons("Mul", [tree.cons("Num", [tree.string("3")]), + tree.cons("Num", [tree.string("1")])])]); + +Or, more simply: + + var node = tree.parse('Add(Num("2"), Mul(Num("3"), Num("1")))'); + +treehugger.js has three kinds of AST node types: + +* Strings (e.g. `"2"`, `"myVariable"`), usually representing identifiers or other + textual values. +* Lists (e.g. `["a", "b", None()]`) +* Constructors (or simply: cons nodes) (e.g. `None()` or `Num("2")`), used to represent + language constructs in the language, such as operators, loop constructs, etc. + + +AST Analysis +------------ + +Treehugger.js is based on the concept of _generic traversals_. A generic traversal +traverses the tree in a particular order, for instance from top to bottom or from +the bottom up. At every node the traversal comes accross you can apply one or transformations. +Tranformations can either be AST _patterns_, _transformation functions_ or a combination of both. + +The `treehugger/traverse.js` library adds a number of methods to AST nodes that make traversals simpler: + +* `collectTopDown` (traverses the tree top to bottom until finding a match, collecting all matches and returning them as a list) +* `traverseTopDown` (traverses the tree top to bottom until finding a match) +* (more are coming) + +A _transformation_ can be either: + +* A textual AST pattern +* A textual AST pattern followed by a transformation function that is passed a binding object +* A transformation function + +Each transform either _matches_ or _doesn't_ match. If a transformation function matches, +it returns a non-falsy value (usually a new AST node), if it doesn't, it returns `false`. +A simple example: + + var node = tree.parse('Add(Num("2"), Mul(Num("3"), Num("1")))'); + node.collectTopDown("Num(_)").debug(); + +This will traverse the AST and look for nodes that match the Num(_) _pattern_, +where `_` (a wildcard) can be anything. The `collectTopDown` traversal traverses +the AST from top to bottom, and on the way collects all matches and returns them +as an `ListNode`. The result of the `collectTopDown` call in this case will be: + + [Num("2"), Num("3"), Num("1")] + +The `.debug()` call prints the result to the Javascript console (`console.log`). + +So, what if we want to only return the numbers, not the `Num(...)` constructors? +If we follow a textual pattern by a function, we can transform the result: + + var node = tree.parse('Add(Num("2"), Mul(Num("3"), Num("1")))'); + node.collectTopDown("Num(n)", function(b) { return b.n; }).debug(); + +Instead of using the placeholder `_`, we now used `n`. The function is passed a +_bindings_ object whose `n` property will contain the value of the placeholder. +So, the following will be printed to the Javascript console: + + ["2", "3", "1"] + +If we want to match _either_ `Num` or `Mul` nodes we can add a pattern for that +to the `collectTopDown` call: + + var node = tree.parse('Add(Num("2"), Mul(Num("3"), Num("1")))'); + node.collectTopDown( + "Num(n)", function(b) { + return b.n; + }, + "Mul(op1, op2)", function(b) { + return b.op1; + } + ).debug(); + +This will print: + + ["2", Num("3")] + +Why is that? The AST is traversed top to bottom by `collectTopDown`. On its way, it will +try to match every node first against the `Num(n)` pattern. If that succeeds, +the function after it in the argument list is executed, if the function returns +a value other than `false`, the traversal stops at that branch and the result +is added to the result list. If the `"Num(n)"` pattern did _not_ match, it is +matched against `"Mul(op1, op2)"`. Again, if this pattern matches, the function +is executed etc. etc. The `collectTopDown` traversal will not traverse down to the +`Num("3")` and `Num("1")` nodes, because the traversal stopped when matching the +`Mul(..., ...)` node -- if, instead the tranformation function would have returned +`false, the traversal would have proceeded down those nodes as well. + +License (MIT) +------------- + +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. + +Demo +---- + +You can see [treehugger.js in action in this simple demo](http://ajaxorg.github.com/treehugger/test.html). \ No newline at end of file diff --git a/node_modules/treehugger/lib/demo.js b/node_modules/treehugger/lib/demo.js new file mode 100644 index 00000000..a5aebcf0 --- /dev/null +++ b/node_modules/treehugger/lib/demo.js @@ -0,0 +1,38 @@ +require({ + baseUrl: "lib" +}, ["treehugger/tree", "treehugger/traverse", "treehugger/js/parse", "jquery", + "treehugger/js/acorn", "treehugger/js/acorn_loose" +], function(tree, traverse, parsejs, jq, acorn, acorn_loose) { + +window.acorn_loose = acorn_loose + function log(message) { + $("#output").val($("#output").val() + message + "\n"); + } + + function exec() { + var js = $("#code").val(); + var analysisJs = $("#analysis").val(); + $("#output").val(""); + + var t = performance.now(); + var ast = parsejs.parse(js); + t -= performance.now(); + $("#ast").val(t + "\n" + ast.toPrettyString()); + try { + eval(analysisJs); + } catch(e) { + $("#output").val("JS Error"); + console.log(e.message) + } + } + + tree.Node.prototype.log = function() { + $("#output").val(this.toPrettyString()); + } + + require.ready(function() { + $("#code").keyup(exec); + $("#runbutton").click(exec); + exec(); + }); +}); diff --git a/node_modules/treehugger/lib/jquery.js b/node_modules/treehugger/lib/jquery.js new file mode 100644 index 00000000..11e6d067 --- /dev/null +++ b/node_modules/treehugger/lib/jquery.js @@ -0,0 +1,9046 @@ +/*! + * jQuery JavaScript Library v1.6.4 + * http://jquery.com/ + * + * Copyright 2011, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Mon Sep 12 18:54:48 2011 -0400 + */ +(function( window, undefined ) { + +// Use the correct document accordingly with window argument (sandbox) +var document = window.document, + navigator = window.navigator, + location = window.location; +var jQuery = (function() { + +// Define a local copy of jQuery +var jQuery = function( selector, context ) { + // The jQuery object is actually just the init constructor 'enhanced' + return new jQuery.fn.init( selector, context, rootjQuery ); + }, + + // Map over jQuery in case of overwrite + _jQuery = window.jQuery, + + // Map over the $ in case of overwrite + _$ = window.$, + + // A central reference to the root jQuery(document) + rootjQuery, + + // A simple way to check for HTML strings or ID strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, + + // Check if a string has a non-whitespace character in it + rnotwhite = /\S/, + + // Used for trimming whitespace + trimLeft = /^\s+/, + trimRight = /\s+$/, + + // Check for digits + rdigit = /\d/, + + // Match a standalone tag + rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, + + // JSON RegExp + rvalidchars = /^[\],:{}\s]*$/, + rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, + rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, + rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, + + // Useragent RegExp + rwebkit = /(webkit)[ \/]([\w.]+)/, + ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/, + rmsie = /(msie) ([\w.]+)/, + rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/, + + // Matches dashed string for camelizing + rdashAlpha = /-([a-z]|[0-9])/ig, + rmsPrefix = /^-ms-/, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return ( letter + "" ).toUpperCase(); + }, + + // Keep a UserAgent string for use with jQuery.browser + userAgent = navigator.userAgent, + + // For matching the engine and version of the browser + browserMatch, + + // The deferred used on DOM ready + readyList, + + // The ready event handler + DOMContentLoaded, + + // Save a reference to some core methods + toString = Object.prototype.toString, + hasOwn = Object.prototype.hasOwnProperty, + push = Array.prototype.push, + slice = Array.prototype.slice, + trim = String.prototype.trim, + indexOf = Array.prototype.indexOf, + + // [[Class]] -> type pairs + class2type = {}; + +jQuery.fn = jQuery.prototype = { + constructor: jQuery, + init: function( selector, context, rootjQuery ) { + var match, elem, ret, doc; + + // Handle $(""), $(null), or $(undefined) + if ( !selector ) { + return this; + } + + // Handle $(DOMElement) + if ( selector.nodeType ) { + this.context = this[0] = selector; + this.length = 1; + return this; + } + + // The body element only exists once, optimize finding it + if ( selector === "body" && !context && document.body ) { + this.context = document; + this[0] = document.body; + this.selector = selector; + this.length = 1; + return this; + } + + // Handle HTML strings + if ( typeof selector === "string" ) { + // Are we dealing with HTML string or an ID? + if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = quickExpr.exec( selector ); + } + + // Verify a match, and that no context was specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) { + context = context instanceof jQuery ? context[0] : context; + doc = (context ? context.ownerDocument || context : document); + + // If a single string is passed in and it's a single tag + // just do a createElement and skip the rest + ret = rsingleTag.exec( selector ); + + if ( ret ) { + if ( jQuery.isPlainObject( context ) ) { + selector = [ document.createElement( ret[1] ) ]; + jQuery.fn.attr.call( selector, context, true ); + + } else { + selector = [ doc.createElement( ret[1] ) ]; + } + + } else { + ret = jQuery.buildFragment( [ match[1] ], [ doc ] ); + selector = (ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment).childNodes; + } + + return jQuery.merge( this, selector ); + + // HANDLE: $("#id") + } else { + elem = document.getElementById( match[2] ); + + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id !== match[2] ) { + return rootjQuery.find( selector ); + } + + // Otherwise, we inject the element directly into the jQuery object + this.length = 1; + this[0] = elem; + } + + this.context = document; + this.selector = selector; + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return (context || rootjQuery).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return rootjQuery.ready( selector ); + } + + if (selector.selector !== undefined) { + this.selector = selector.selector; + this.context = selector.context; + } + + return jQuery.makeArray( selector, this ); + }, + + // Start with an empty selector + selector: "", + + // The current version of jQuery being used + jquery: "1.6.4", + + // The default length of a jQuery object is 0 + length: 0, + + // The number of elements contained in the matched element set + size: function() { + return this.length; + }, + + toArray: function() { + return slice.call( this, 0 ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num == null ? + + // Return a 'clean' array + this.toArray() : + + // Return just the object + ( num < 0 ? this[ this.length + num ] : this[ num ] ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems, name, selector ) { + // Build a new jQuery matched element set + var ret = this.constructor(); + + if ( jQuery.isArray( elems ) ) { + push.apply( ret, elems ); + + } else { + jQuery.merge( ret, elems ); + } + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + ret.context = this.context; + + if ( name === "find" ) { + ret.selector = this.selector + (this.selector ? " " : "") + selector; + } else if ( name ) { + ret.selector = this.selector + "." + name + "(" + selector + ")"; + } + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + // (You can seed the arguments with an array of args, but this is + // only used internally.) + each: function( callback, args ) { + return jQuery.each( this, callback, args ); + }, + + ready: function( fn ) { + // Attach the listeners + jQuery.bindReady(); + + // Add the callback + readyList.done( fn ); + + return this; + }, + + eq: function( i ) { + return i === -1 ? + this.slice( i ) : + this.slice( i, +i + 1 ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ), + "slice", slice.call(arguments).join(",") ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map(this, function( elem, i ) { + return callback.call( elem, i, elem ); + })); + }, + + end: function() { + return this.prevObject || this.constructor(null); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: [].sort, + splice: [].splice +}; + +// Give the init function the jQuery prototype for later instantiation +jQuery.fn.init.prototype = jQuery.fn; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + target = arguments[1] || {}; + // skip the boolean and the target + i = 2; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction(target) ) { + target = {}; + } + + // extend jQuery itself if only one argument is passed + if ( length === i ) { + target = this; + --i; + } + + for ( ; i < length; i++ ) { + // Only deal with non-null/undefined values + if ( (options = arguments[ i ]) != null ) { + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { + if ( copyIsArray ) { + copyIsArray = false; + clone = src && jQuery.isArray(src) ? src : []; + + } else { + clone = src && jQuery.isPlainObject(src) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend({ + noConflict: function( deep ) { + if ( window.$ === jQuery ) { + window.$ = _$; + } + + if ( deep && window.jQuery === jQuery ) { + window.jQuery = _jQuery; + } + + return jQuery; + }, + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Hold (or release) the ready event + holdReady: function( hold ) { + if ( hold ) { + jQuery.readyWait++; + } else { + jQuery.ready( true ); + } + }, + + // Handle when the DOM is ready + ready: function( wait ) { + // Either a released hold or an DOMready/load event and not yet ready + if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( !document.body ) { + return setTimeout( jQuery.ready, 1 ); + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + + // Trigger any bound ready events + if ( jQuery.fn.trigger ) { + jQuery( document ).trigger( "ready" ).unbind( "ready" ); + } + } + }, + + bindReady: function() { + if ( readyList ) { + return; + } + + readyList = jQuery._Deferred(); + + // Catch cases where $(document).ready() is called after the + // browser event has already occurred. + if ( document.readyState === "complete" ) { + // Handle it asynchronously to allow scripts the opportunity to delay ready + return setTimeout( jQuery.ready, 1 ); + } + + // Mozilla, Opera and webkit nightlies currently support this event + if ( document.addEventListener ) { + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", jQuery.ready, false ); + + // If IE event model is used + } else if ( document.attachEvent ) { + // ensure firing before onload, + // maybe late but safe also for iframes + document.attachEvent( "onreadystatechange", DOMContentLoaded ); + + // A fallback to window.onload, that will always work + window.attachEvent( "onload", jQuery.ready ); + + // If IE and not a frame + // continually check to see if the document is ready + var toplevel = false; + + try { + toplevel = window.frameElement == null; + } catch(e) {} + + if ( document.documentElement.doScroll && toplevel ) { + doScrollCheck(); + } + } + }, + + // See test/unit/core.js for details concerning isFunction. + // Since version 1.3, DOM methods and functions like alert + // aren't supported. They return false on IE (#2968). + isFunction: function( obj ) { + return jQuery.type(obj) === "function"; + }, + + isArray: Array.isArray || function( obj ) { + return jQuery.type(obj) === "array"; + }, + + // A crude way of determining if an object is a window + isWindow: function( obj ) { + return obj && typeof obj === "object" && "setInterval" in obj; + }, + + isNaN: function( obj ) { + return obj == null || !rdigit.test( obj ) || isNaN( obj ); + }, + + type: function( obj ) { + return obj == null ? + String( obj ) : + class2type[ toString.call(obj) ] || "object"; + }, + + isPlainObject: function( obj ) { + // Must be an Object. + // Because of IE, we also have to check the presence of the constructor property. + // Make sure that DOM nodes and window objects don't pass through, as well + if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { + return false; + } + + try { + // Not own constructor property must be Object + if ( obj.constructor && + !hasOwn.call(obj, "constructor") && + !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { + return false; + } + } catch ( e ) { + // IE8,9 Will throw exceptions on certain host objects #9897 + return false; + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + + var key; + for ( key in obj ) {} + + return key === undefined || hasOwn.call( obj, key ); + }, + + isEmptyObject: function( obj ) { + for ( var name in obj ) { + return false; + } + return true; + }, + + error: function( msg ) { + throw msg; + }, + + parseJSON: function( data ) { + if ( typeof data !== "string" || !data ) { + return null; + } + + // Make sure leading/trailing whitespace is removed (IE can't handle it) + data = jQuery.trim( data ); + + // Attempt to parse using the native JSON parser first + if ( window.JSON && window.JSON.parse ) { + return window.JSON.parse( data ); + } + + // Make sure the incoming data is actual JSON + // Logic borrowed from http://json.org/json2.js + if ( rvalidchars.test( data.replace( rvalidescape, "@" ) + .replace( rvalidtokens, "]" ) + .replace( rvalidbraces, "")) ) { + + return (new Function( "return " + data ))(); + + } + jQuery.error( "Invalid JSON: " + data ); + }, + + // Cross-browser xml parsing + parseXML: function( data ) { + var xml, tmp; + try { + if ( window.DOMParser ) { // Standard + tmp = new DOMParser(); + xml = tmp.parseFromString( data , "text/xml" ); + } else { // IE + xml = new ActiveXObject( "Microsoft.XMLDOM" ); + xml.async = "false"; + xml.loadXML( data ); + } + } catch( e ) { + xml = undefined; + } + if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; + }, + + noop: function() {}, + + // Evaluates a script in a global context + // Workarounds based on findings by Jim Driscoll + // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context + globalEval: function( data ) { + if ( data && rnotwhite.test( data ) ) { + // We use execScript on Internet Explorer + // We use an anonymous function so that context is window + // rather than jQuery in Firefox + ( window.execScript || function( data ) { + window[ "eval" ].call( window, data ); + } )( data ); + } + }, + + // Convert dashed to camelCase; used by the css and data modules + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); + }, + + // args is for internal usage only + each: function( object, callback, args ) { + var name, i = 0, + length = object.length, + isObj = length === undefined || jQuery.isFunction( object ); + + if ( args ) { + if ( isObj ) { + for ( name in object ) { + if ( callback.apply( object[ name ], args ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.apply( object[ i++ ], args ) === false ) { + break; + } + } + } + + // A special, fast, case for the most common use of each + } else { + if ( isObj ) { + for ( name in object ) { + if ( callback.call( object[ name ], name, object[ name ] ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) { + break; + } + } + } + } + + return object; + }, + + // Use native String.trim function wherever possible + trim: trim ? + function( text ) { + return text == null ? + "" : + trim.call( text ); + } : + + // Otherwise use our own trimming functionality + function( text ) { + return text == null ? + "" : + text.toString().replace( trimLeft, "" ).replace( trimRight, "" ); + }, + + // results is for internal usage only + makeArray: function( array, results ) { + var ret = results || []; + + if ( array != null ) { + // The window, strings (and functions) also have 'length' + // The extra typeof function check is to prevent crashes + // in Safari 2 (See: #3039) + // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 + var type = jQuery.type( array ); + + if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) { + push.call( ret, array ); + } else { + jQuery.merge( ret, array ); + } + } + + return ret; + }, + + inArray: function( elem, array ) { + if ( !array ) { + return -1; + } + + if ( indexOf ) { + return indexOf.call( array, elem ); + } + + for ( var i = 0, length = array.length; i < length; i++ ) { + if ( array[ i ] === elem ) { + return i; + } + } + + return -1; + }, + + merge: function( first, second ) { + var i = first.length, + j = 0; + + if ( typeof second.length === "number" ) { + for ( var l = second.length; j < l; j++ ) { + first[ i++ ] = second[ j ]; + } + + } else { + while ( second[j] !== undefined ) { + first[ i++ ] = second[ j++ ]; + } + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, inv ) { + var ret = [], retVal; + inv = !!inv; + + // Go through the array, only saving the items + // that pass the validator function + for ( var i = 0, length = elems.length; i < length; i++ ) { + retVal = !!callback( elems[ i ], i ); + if ( inv !== retVal ) { + ret.push( elems[ i ] ); + } + } + + return ret; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var value, key, ret = [], + i = 0, + length = elems.length, + // jquery objects are treated as arrays + isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; + + // Go through the array, translating each of the items to their + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + + // Go through every key on the object, + } else { + for ( key in elems ) { + value = callback( elems[ key ], key, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + } + + // Flatten any nested arrays + return ret.concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + if ( typeof context === "string" ) { + var tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + var args = slice.call( arguments, 2 ), + proxy = function() { + return fn.apply( context, args.concat( slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; + + return proxy; + }, + + // Mutifunctional method to get and set values to a collection + // The value/s can optionally be executed if it's a function + access: function( elems, key, value, exec, fn, pass ) { + var length = elems.length; + + // Setting many attributes + if ( typeof key === "object" ) { + for ( var k in key ) { + jQuery.access( elems, k, key[k], exec, fn, value ); + } + return elems; + } + + // Setting one attribute + if ( value !== undefined ) { + // Optionally, function values get executed if exec is true + exec = !pass && exec && jQuery.isFunction(value); + + for ( var i = 0; i < length; i++ ) { + fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); + } + + return elems; + } + + // Getting an attribute + return length ? fn( elems[0], key ) : undefined; + }, + + now: function() { + return (new Date()).getTime(); + }, + + // Use of jQuery.browser is frowned upon. + // More details: http://docs.jquery.com/Utilities/jQuery.browser + uaMatch: function( ua ) { + ua = ua.toLowerCase(); + + var match = rwebkit.exec( ua ) || + ropera.exec( ua ) || + rmsie.exec( ua ) || + ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) || + []; + + return { browser: match[1] || "", version: match[2] || "0" }; + }, + + sub: function() { + function jQuerySub( selector, context ) { + return new jQuerySub.fn.init( selector, context ); + } + jQuery.extend( true, jQuerySub, this ); + jQuerySub.superclass = this; + jQuerySub.fn = jQuerySub.prototype = this(); + jQuerySub.fn.constructor = jQuerySub; + jQuerySub.sub = this.sub; + jQuerySub.fn.init = function init( selector, context ) { + if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { + context = jQuerySub( context ); + } + + return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); + }; + jQuerySub.fn.init.prototype = jQuerySub.fn; + var rootjQuerySub = jQuerySub(document); + return jQuerySub; + }, + + browser: {} +}); + +// Populate the class2type map +jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +}); + +browserMatch = jQuery.uaMatch( userAgent ); +if ( browserMatch.browser ) { + jQuery.browser[ browserMatch.browser ] = true; + jQuery.browser.version = browserMatch.version; +} + +// Deprecated, use jQuery.browser.webkit instead +if ( jQuery.browser.webkit ) { + jQuery.browser.safari = true; +} + +// IE doesn't match non-breaking spaces with \s +if ( rnotwhite.test( "\xA0" ) ) { + trimLeft = /^[\s\xA0]+/; + trimRight = /[\s\xA0]+$/; +} + +// All jQuery objects should point back to these +rootjQuery = jQuery(document); + +// Cleanup functions for the document ready method +if ( document.addEventListener ) { + DOMContentLoaded = function() { + document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + jQuery.ready(); + }; + +} else if ( document.attachEvent ) { + DOMContentLoaded = function() { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( document.readyState === "complete" ) { + document.detachEvent( "onreadystatechange", DOMContentLoaded ); + jQuery.ready(); + } + }; +} + +// The DOM ready check for Internet Explorer +function doScrollCheck() { + if ( jQuery.isReady ) { + return; + } + + try { + // If IE is used, use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + document.documentElement.doScroll("left"); + } catch(e) { + setTimeout( doScrollCheck, 1 ); + return; + } + + // and execute any waiting functions + jQuery.ready(); +} + +return jQuery; + +})(); + + +var // Promise methods + promiseMethods = "done fail isResolved isRejected promise then always pipe".split( " " ), + // Static reference to slice + sliceDeferred = [].slice; + +jQuery.extend({ + // Create a simple deferred (one callbacks list) + _Deferred: function() { + var // callbacks list + callbacks = [], + // stored [ context , args ] + fired, + // to avoid firing when already doing so + firing, + // flag to know if the deferred has been cancelled + cancelled, + // the deferred itself + deferred = { + + // done( f1, f2, ...) + done: function() { + if ( !cancelled ) { + var args = arguments, + i, + length, + elem, + type, + _fired; + if ( fired ) { + _fired = fired; + fired = 0; + } + for ( i = 0, length = args.length; i < length; i++ ) { + elem = args[ i ]; + type = jQuery.type( elem ); + if ( type === "array" ) { + deferred.done.apply( deferred, elem ); + } else if ( type === "function" ) { + callbacks.push( elem ); + } + } + if ( _fired ) { + deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] ); + } + } + return this; + }, + + // resolve with given context and args + resolveWith: function( context, args ) { + if ( !cancelled && !fired && !firing ) { + // make sure args are available (#8421) + args = args || []; + firing = 1; + try { + while( callbacks[ 0 ] ) { + callbacks.shift().apply( context, args ); + } + } + finally { + fired = [ context, args ]; + firing = 0; + } + } + return this; + }, + + // resolve with this as context and given arguments + resolve: function() { + deferred.resolveWith( this, arguments ); + return this; + }, + + // Has this deferred been resolved? + isResolved: function() { + return !!( firing || fired ); + }, + + // Cancel + cancel: function() { + cancelled = 1; + callbacks = []; + return this; + } + }; + + return deferred; + }, + + // Full fledged deferred (two callbacks list) + Deferred: function( func ) { + var deferred = jQuery._Deferred(), + failDeferred = jQuery._Deferred(), + promise; + // Add errorDeferred methods, then and promise + jQuery.extend( deferred, { + then: function( doneCallbacks, failCallbacks ) { + deferred.done( doneCallbacks ).fail( failCallbacks ); + return this; + }, + always: function() { + return deferred.done.apply( deferred, arguments ).fail.apply( this, arguments ); + }, + fail: failDeferred.done, + rejectWith: failDeferred.resolveWith, + reject: failDeferred.resolve, + isRejected: failDeferred.isResolved, + pipe: function( fnDone, fnFail ) { + return jQuery.Deferred(function( newDefer ) { + jQuery.each( { + done: [ fnDone, "resolve" ], + fail: [ fnFail, "reject" ] + }, function( handler, data ) { + var fn = data[ 0 ], + action = data[ 1 ], + returned; + if ( jQuery.isFunction( fn ) ) { + deferred[ handler ](function() { + returned = fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise().then( newDefer.resolve, newDefer.reject ); + } else { + newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] ); + } + }); + } else { + deferred[ handler ]( newDefer[ action ] ); + } + }); + }).promise(); + }, + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + if ( obj == null ) { + if ( promise ) { + return promise; + } + promise = obj = {}; + } + var i = promiseMethods.length; + while( i-- ) { + obj[ promiseMethods[i] ] = deferred[ promiseMethods[i] ]; + } + return obj; + } + }); + // Make sure only one callback list will be used + deferred.done( failDeferred.cancel ).fail( deferred.cancel ); + // Unexpose cancel + delete deferred.cancel; + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + return deferred; + }, + + // Deferred helper + when: function( firstParam ) { + var args = arguments, + i = 0, + length = args.length, + count = length, + deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ? + firstParam : + jQuery.Deferred(); + function resolveFunc( i ) { + return function( value ) { + args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; + if ( !( --count ) ) { + // Strange bug in FF4: + // Values changed onto the arguments object sometimes end up as undefined values + // outside the $.when method. Cloning the object into a fresh array solves the issue + deferred.resolveWith( deferred, sliceDeferred.call( args, 0 ) ); + } + }; + } + if ( length > 1 ) { + for( ; i < length; i++ ) { + if ( args[ i ] && jQuery.isFunction( args[ i ].promise ) ) { + args[ i ].promise().then( resolveFunc(i), deferred.reject ); + } else { + --count; + } + } + if ( !count ) { + deferred.resolveWith( deferred, args ); + } + } else if ( deferred !== firstParam ) { + deferred.resolveWith( deferred, length ? [ firstParam ] : [] ); + } + return deferred.promise(); + } +}); + + + +jQuery.support = (function() { + + var div = document.createElement( "div" ), + documentElement = document.documentElement, + all, + a, + select, + opt, + input, + marginDiv, + support, + fragment, + body, + testElementParent, + testElement, + testElementStyle, + tds, + events, + eventName, + i, + isSupported; + + // Preliminary tests + div.setAttribute("className", "t"); + div.innerHTML = "
      a"; + + + all = div.getElementsByTagName( "*" ); + a = div.getElementsByTagName( "a" )[ 0 ]; + + // Can't get basic test support + if ( !all || !all.length || !a ) { + return {}; + } + + // First batch of supports tests + select = document.createElement( "select" ); + opt = select.appendChild( document.createElement("option") ); + input = div.getElementsByTagName( "input" )[ 0 ]; + + support = { + // IE strips leading whitespace when .innerHTML is used + leadingWhitespace: ( div.firstChild.nodeType === 3 ), + + // Make sure that tbody elements aren't automatically inserted + // IE will insert them into empty tables + tbody: !div.getElementsByTagName( "tbody" ).length, + + // Make sure that link elements get serialized correctly by innerHTML + // This requires a wrapper element in IE + htmlSerialize: !!div.getElementsByTagName( "link" ).length, + + // Get the style information from getAttribute + // (IE uses .cssText instead) + style: /top/.test( a.getAttribute("style") ), + + // Make sure that URLs aren't manipulated + // (IE normalizes it by default) + hrefNormalized: ( a.getAttribute( "href" ) === "/a" ), + + // Make sure that element opacity exists + // (IE uses filter instead) + // Use a regex to work around a WebKit issue. See #5145 + opacity: /^0.55$/.test( a.style.opacity ), + + // Verify style float existence + // (IE uses styleFloat instead of cssFloat) + cssFloat: !!a.style.cssFloat, + + // Make sure that if no value is specified for a checkbox + // that it defaults to "on". + // (WebKit defaults to "" instead) + checkOn: ( input.value === "on" ), + + // Make sure that a selected-by-default option has a working selected property. + // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) + optSelected: opt.selected, + + // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) + getSetAttribute: div.className !== "t", + + // Will be defined later + submitBubbles: true, + changeBubbles: true, + focusinBubbles: false, + deleteExpando: true, + noCloneEvent: true, + inlineBlockNeedsLayout: false, + shrinkWrapBlocks: false, + reliableMarginRight: true + }; + + // Make sure checked status is properly cloned + input.checked = true; + support.noCloneChecked = input.cloneNode( true ).checked; + + // Make sure that the options inside disabled selects aren't marked as disabled + // (WebKit marks them as disabled) + select.disabled = true; + support.optDisabled = !opt.disabled; + + // Test to see if it's possible to delete an expando from an element + // Fails in Internet Explorer + try { + delete div.test; + } catch( e ) { + support.deleteExpando = false; + } + + if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { + div.attachEvent( "onclick", function() { + // Cloning a node shouldn't copy over any + // bound event handlers (IE does this) + support.noCloneEvent = false; + }); + div.cloneNode( true ).fireEvent( "onclick" ); + } + + // Check if a radio maintains it's value + // after being appended to the DOM + input = document.createElement("input"); + input.value = "t"; + input.setAttribute("type", "radio"); + support.radioValue = input.value === "t"; + + input.setAttribute("checked", "checked"); + div.appendChild( input ); + fragment = document.createDocumentFragment(); + fragment.appendChild( div.firstChild ); + + // WebKit doesn't clone checked state correctly in fragments + support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; + + div.innerHTML = ""; + + // Figure out if the W3C box model works as expected + div.style.width = div.style.paddingLeft = "1px"; + + body = document.getElementsByTagName( "body" )[ 0 ]; + // We use our own, invisible, body unless the body is already present + // in which case we use a div (#9239) + testElement = document.createElement( body ? "div" : "body" ); + testElementStyle = { + visibility: "hidden", + width: 0, + height: 0, + border: 0, + margin: 0, + background: "none" + }; + if ( body ) { + jQuery.extend( testElementStyle, { + position: "absolute", + left: "-1000px", + top: "-1000px" + }); + } + for ( i in testElementStyle ) { + testElement.style[ i ] = testElementStyle[ i ]; + } + testElement.appendChild( div ); + testElementParent = body || documentElement; + testElementParent.insertBefore( testElement, testElementParent.firstChild ); + + // Check if a disconnected checkbox will retain its checked + // value of true after appended to the DOM (IE6/7) + support.appendChecked = input.checked; + + support.boxModel = div.offsetWidth === 2; + + if ( "zoom" in div.style ) { + // Check if natively block-level elements act like inline-block + // elements when setting their display to 'inline' and giving + // them layout + // (IE < 8 does this) + div.style.display = "inline"; + div.style.zoom = 1; + support.inlineBlockNeedsLayout = ( div.offsetWidth === 2 ); + + // Check if elements with layout shrink-wrap their children + // (IE 6 does this) + div.style.display = ""; + div.innerHTML = "
      "; + support.shrinkWrapBlocks = ( div.offsetWidth !== 2 ); + } + + div.innerHTML = "
      t
      "; + tds = div.getElementsByTagName( "td" ); + + // Check if table cells still have offsetWidth/Height when they are set + // to display:none and there are still other visible table cells in a + // table row; if so, offsetWidth/Height are not reliable for use when + // determining if an element has been hidden directly using + // display:none (it is still safe to use offsets if a parent element is + // hidden; don safety goggles and see bug #4512 for more information). + // (only IE 8 fails this test) + isSupported = ( tds[ 0 ].offsetHeight === 0 ); + + tds[ 0 ].style.display = ""; + tds[ 1 ].style.display = "none"; + + // Check if empty table cells still have offsetWidth/Height + // (IE < 8 fail this test) + support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); + div.innerHTML = ""; + + // Check if div with explicit width and no margin-right incorrectly + // gets computed margin-right based on width of container. For more + // info see bug #3333 + // Fails in WebKit before Feb 2011 nightlies + // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right + if ( document.defaultView && document.defaultView.getComputedStyle ) { + marginDiv = document.createElement( "div" ); + marginDiv.style.width = "0"; + marginDiv.style.marginRight = "0"; + div.appendChild( marginDiv ); + support.reliableMarginRight = + ( parseInt( ( document.defaultView.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0; + } + + // Remove the body element we added + testElement.innerHTML = ""; + testElementParent.removeChild( testElement ); + + // Technique from Juriy Zaytsev + // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/ + // We only care about the case where non-standard event systems + // are used, namely in IE. Short-circuiting here helps us to + // avoid an eval call (in setAttribute) which can cause CSP + // to go haywire. See: https://developer.mozilla.org/en/Security/CSP + if ( div.attachEvent ) { + for( i in { + submit: 1, + change: 1, + focusin: 1 + } ) { + eventName = "on" + i; + isSupported = ( eventName in div ); + if ( !isSupported ) { + div.setAttribute( eventName, "return;" ); + isSupported = ( typeof div[ eventName ] === "function" ); + } + support[ i + "Bubbles" ] = isSupported; + } + } + + // Null connected elements to avoid leaks in IE + testElement = fragment = select = opt = body = marginDiv = div = input = null; + + return support; +})(); + +// Keep track of boxModel +jQuery.boxModel = jQuery.support.boxModel; + + + + +var rbrace = /^(?:\{.*\}|\[.*\])$/, + rmultiDash = /([A-Z])/g; + +jQuery.extend({ + cache: {}, + + // Please use with caution + uuid: 0, + + // Unique for each copy of jQuery on the page + // Non-digits removed to match rinlinejQuery + expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), + + // The following elements throw uncatchable exceptions if you + // attempt to add expando properties to them. + noData: { + "embed": true, + // Ban all objects except for Flash (which handle expandos) + "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", + "applet": true + }, + + hasData: function( elem ) { + elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; + + return !!elem && !isEmptyDataObject( elem ); + }, + + data: function( elem, name, data, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var thisCache, ret, + internalKey = jQuery.expando, + getByName = typeof name === "string", + + // We have to handle DOM nodes and JS objects differently because IE6-7 + // can't GC object references properly across the DOM-JS boundary + isNode = elem.nodeType, + + // Only DOM nodes need the global jQuery cache; JS object data is + // attached directly to the object so GC can occur automatically + cache = isNode ? jQuery.cache : elem, + + // Only defining an ID for JS objects if its cache already exists allows + // the code to shortcut on the same path as a DOM node with no cache + id = isNode ? elem[ jQuery.expando ] : elem[ jQuery.expando ] && jQuery.expando; + + // Avoid doing any more work than we need to when trying to get data on an + // object that has no data at all + if ( (!id || (pvt && id && (cache[ id ] && !cache[ id ][ internalKey ]))) && getByName && data === undefined ) { + return; + } + + if ( !id ) { + // Only DOM nodes need a new unique ID for each element since their data + // ends up in the global cache + if ( isNode ) { + elem[ jQuery.expando ] = id = ++jQuery.uuid; + } else { + id = jQuery.expando; + } + } + + if ( !cache[ id ] ) { + cache[ id ] = {}; + + // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery + // metadata on plain JS objects when the object is serialized using + // JSON.stringify + if ( !isNode ) { + cache[ id ].toJSON = jQuery.noop; + } + } + + // An object can be passed to jQuery.data instead of a key/value pair; this gets + // shallow copied over onto the existing cache + if ( typeof name === "object" || typeof name === "function" ) { + if ( pvt ) { + cache[ id ][ internalKey ] = jQuery.extend(cache[ id ][ internalKey ], name); + } else { + cache[ id ] = jQuery.extend(cache[ id ], name); + } + } + + thisCache = cache[ id ]; + + // Internal jQuery data is stored in a separate object inside the object's data + // cache in order to avoid key collisions between internal data and user-defined + // data + if ( pvt ) { + if ( !thisCache[ internalKey ] ) { + thisCache[ internalKey ] = {}; + } + + thisCache = thisCache[ internalKey ]; + } + + if ( data !== undefined ) { + thisCache[ jQuery.camelCase( name ) ] = data; + } + + // TODO: This is a hack for 1.5 ONLY. It will be removed in 1.6. Users should + // not attempt to inspect the internal events object using jQuery.data, as this + // internal data object is undocumented and subject to change. + if ( name === "events" && !thisCache[name] ) { + return thisCache[ internalKey ] && thisCache[ internalKey ].events; + } + + // Check for both converted-to-camel and non-converted data property names + // If a data property was specified + if ( getByName ) { + + // First Try to find as-is property data + ret = thisCache[ name ]; + + // Test for null|undefined property data + if ( ret == null ) { + + // Try to find the camelCased property + ret = thisCache[ jQuery.camelCase( name ) ]; + } + } else { + ret = thisCache; + } + + return ret; + }, + + removeData: function( elem, name, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var thisCache, + + // Reference to internal data cache key + internalKey = jQuery.expando, + + isNode = elem.nodeType, + + // See jQuery.data for more information + cache = isNode ? jQuery.cache : elem, + + // See jQuery.data for more information + id = isNode ? elem[ jQuery.expando ] : jQuery.expando; + + // If there is already no cache entry for this object, there is no + // purpose in continuing + if ( !cache[ id ] ) { + return; + } + + if ( name ) { + + thisCache = pvt ? cache[ id ][ internalKey ] : cache[ id ]; + + if ( thisCache ) { + + // Support interoperable removal of hyphenated or camelcased keys + if ( !thisCache[ name ] ) { + name = jQuery.camelCase( name ); + } + + delete thisCache[ name ]; + + // If there is no data left in the cache, we want to continue + // and let the cache object itself get destroyed + if ( !isEmptyDataObject(thisCache) ) { + return; + } + } + } + + // See jQuery.data for more information + if ( pvt ) { + delete cache[ id ][ internalKey ]; + + // Don't destroy the parent cache unless the internal data object + // had been the only thing left in it + if ( !isEmptyDataObject(cache[ id ]) ) { + return; + } + } + + var internalCache = cache[ id ][ internalKey ]; + + // Browsers that fail expando deletion also refuse to delete expandos on + // the window, but it will allow it on all other JS objects; other browsers + // don't care + // Ensure that `cache` is not a window object #10080 + if ( jQuery.support.deleteExpando || !cache.setInterval ) { + delete cache[ id ]; + } else { + cache[ id ] = null; + } + + // We destroyed the entire user cache at once because it's faster than + // iterating through each key, but we need to continue to persist internal + // data if it existed + if ( internalCache ) { + cache[ id ] = {}; + // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery + // metadata on plain JS objects when the object is serialized using + // JSON.stringify + if ( !isNode ) { + cache[ id ].toJSON = jQuery.noop; + } + + cache[ id ][ internalKey ] = internalCache; + + // Otherwise, we need to eliminate the expando on the node to avoid + // false lookups in the cache for entries that no longer exist + } else if ( isNode ) { + // IE does not allow us to delete expando properties from nodes, + // nor does it have a removeAttribute function on Document nodes; + // we must handle all of these cases + if ( jQuery.support.deleteExpando ) { + delete elem[ jQuery.expando ]; + } else if ( elem.removeAttribute ) { + elem.removeAttribute( jQuery.expando ); + } else { + elem[ jQuery.expando ] = null; + } + } + }, + + // For internal use only. + _data: function( elem, name, data ) { + return jQuery.data( elem, name, data, true ); + }, + + // A method for determining if a DOM node can handle the data expando + acceptData: function( elem ) { + if ( elem.nodeName ) { + var match = jQuery.noData[ elem.nodeName.toLowerCase() ]; + + if ( match ) { + return !(match === true || elem.getAttribute("classid") !== match); + } + } + + return true; + } +}); + +jQuery.fn.extend({ + data: function( key, value ) { + var data = null; + + if ( typeof key === "undefined" ) { + if ( this.length ) { + data = jQuery.data( this[0] ); + + if ( this[0].nodeType === 1 ) { + var attr = this[0].attributes, name; + for ( var i = 0, l = attr.length; i < l; i++ ) { + name = attr[i].name; + + if ( name.indexOf( "data-" ) === 0 ) { + name = jQuery.camelCase( name.substring(5) ); + + dataAttr( this[0], name, data[ name ] ); + } + } + } + } + + return data; + + } else if ( typeof key === "object" ) { + return this.each(function() { + jQuery.data( this, key ); + }); + } + + var parts = key.split("."); + parts[1] = parts[1] ? "." + parts[1] : ""; + + if ( value === undefined ) { + data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]); + + // Try to fetch any internally stored data first + if ( data === undefined && this.length ) { + data = jQuery.data( this[0], key ); + data = dataAttr( this[0], key, data ); + } + + return data === undefined && parts[1] ? + this.data( parts[0] ) : + data; + + } else { + return this.each(function() { + var $this = jQuery( this ), + args = [ parts[0], value ]; + + $this.triggerHandler( "setData" + parts[1] + "!", args ); + jQuery.data( this, key, value ); + $this.triggerHandler( "changeData" + parts[1] + "!", args ); + }); + } + }, + + removeData: function( key ) { + return this.each(function() { + jQuery.removeData( this, key ); + }); + } +}); + +function dataAttr( elem, key, data ) { + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + + var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); + + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = data === "true" ? true : + data === "false" ? false : + data === "null" ? null : + !jQuery.isNaN( data ) ? parseFloat( data ) : + rbrace.test( data ) ? jQuery.parseJSON( data ) : + data; + } catch( e ) {} + + // Make sure we set the data so it isn't changed later + jQuery.data( elem, key, data ); + + } else { + data = undefined; + } + } + + return data; +} + +// TODO: This is a hack for 1.5 ONLY to allow objects with a single toJSON +// property to be considered empty objects; this property always exists in +// order to make sure JSON.stringify does not expose internal metadata +function isEmptyDataObject( obj ) { + for ( var name in obj ) { + if ( name !== "toJSON" ) { + return false; + } + } + + return true; +} + + + + +function handleQueueMarkDefer( elem, type, src ) { + var deferDataKey = type + "defer", + queueDataKey = type + "queue", + markDataKey = type + "mark", + defer = jQuery.data( elem, deferDataKey, undefined, true ); + if ( defer && + ( src === "queue" || !jQuery.data( elem, queueDataKey, undefined, true ) ) && + ( src === "mark" || !jQuery.data( elem, markDataKey, undefined, true ) ) ) { + // Give room for hard-coded callbacks to fire first + // and eventually mark/queue something else on the element + setTimeout( function() { + if ( !jQuery.data( elem, queueDataKey, undefined, true ) && + !jQuery.data( elem, markDataKey, undefined, true ) ) { + jQuery.removeData( elem, deferDataKey, true ); + defer.resolve(); + } + }, 0 ); + } +} + +jQuery.extend({ + + _mark: function( elem, type ) { + if ( elem ) { + type = (type || "fx") + "mark"; + jQuery.data( elem, type, (jQuery.data(elem,type,undefined,true) || 0) + 1, true ); + } + }, + + _unmark: function( force, elem, type ) { + if ( force !== true ) { + type = elem; + elem = force; + force = false; + } + if ( elem ) { + type = type || "fx"; + var key = type + "mark", + count = force ? 0 : ( (jQuery.data( elem, key, undefined, true) || 1 ) - 1 ); + if ( count ) { + jQuery.data( elem, key, count, true ); + } else { + jQuery.removeData( elem, key, true ); + handleQueueMarkDefer( elem, type, "mark" ); + } + } + }, + + queue: function( elem, type, data ) { + if ( elem ) { + type = (type || "fx") + "queue"; + var q = jQuery.data( elem, type, undefined, true ); + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !q || jQuery.isArray(data) ) { + q = jQuery.data( elem, type, jQuery.makeArray(data), true ); + } else { + q.push( data ); + } + } + return q || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + fn = queue.shift(), + defer; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + } + + if ( fn ) { + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift("inprogress"); + } + + fn.call(elem, function() { + jQuery.dequeue(elem, type); + }); + } + + if ( !queue.length ) { + jQuery.removeData( elem, type + "queue", true ); + handleQueueMarkDefer( elem, type, "queue" ); + } + } +}); + +jQuery.fn.extend({ + queue: function( type, data ) { + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + } + + if ( data === undefined ) { + return jQuery.queue( this[0], type ); + } + return this.each(function() { + var queue = jQuery.queue( this, type, data ); + + if ( type === "fx" && queue[0] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + }); + }, + dequeue: function( type ) { + return this.each(function() { + jQuery.dequeue( this, type ); + }); + }, + // Based off of the plugin by Clint Helfers, with permission. + // http://blindsignals.com/index.php/2009/07/jquery-delay/ + delay: function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[time] || time : time; + type = type || "fx"; + + return this.queue( type, function() { + var elem = this; + setTimeout(function() { + jQuery.dequeue( elem, type ); + }, time ); + }); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, object ) { + if ( typeof type !== "string" ) { + object = type; + type = undefined; + } + type = type || "fx"; + var defer = jQuery.Deferred(), + elements = this, + i = elements.length, + count = 1, + deferDataKey = type + "defer", + queueDataKey = type + "queue", + markDataKey = type + "mark", + tmp; + function resolve() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + } + while( i-- ) { + if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) || + ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) || + jQuery.data( elements[ i ], markDataKey, undefined, true ) ) && + jQuery.data( elements[ i ], deferDataKey, jQuery._Deferred(), true ) )) { + count++; + tmp.done( resolve ); + } + } + resolve(); + return defer.promise(); + } +}); + + + + +var rclass = /[\n\t\r]/g, + rspace = /\s+/, + rreturn = /\r/g, + rtype = /^(?:button|input)$/i, + rfocusable = /^(?:button|input|object|select|textarea)$/i, + rclickable = /^a(?:rea)?$/i, + rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, + nodeHook, boolHook; + +jQuery.fn.extend({ + attr: function( name, value ) { + return jQuery.access( this, name, value, true, jQuery.attr ); + }, + + removeAttr: function( name ) { + return this.each(function() { + jQuery.removeAttr( this, name ); + }); + }, + + prop: function( name, value ) { + return jQuery.access( this, name, value, true, jQuery.prop ); + }, + + removeProp: function( name ) { + name = jQuery.propFix[ name ] || name; + return this.each(function() { + // try/catch handles cases where IE balks (such as removing a property on window) + try { + this[ name ] = undefined; + delete this[ name ]; + } catch( e ) {} + }); + }, + + addClass: function( value ) { + var classNames, i, l, elem, + setClass, c, cl; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).addClass( value.call(this, j, this.className) ); + }); + } + + if ( value && typeof value === "string" ) { + classNames = value.split( rspace ); + + for ( i = 0, l = this.length; i < l; i++ ) { + elem = this[ i ]; + + if ( elem.nodeType === 1 ) { + if ( !elem.className && classNames.length === 1 ) { + elem.className = value; + + } else { + setClass = " " + elem.className + " "; + + for ( c = 0, cl = classNames.length; c < cl; c++ ) { + if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) { + setClass += classNames[ c ] + " "; + } + } + elem.className = jQuery.trim( setClass ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classNames, i, l, elem, className, c, cl; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).removeClass( value.call(this, j, this.className) ); + }); + } + + if ( (value && typeof value === "string") || value === undefined ) { + classNames = (value || "").split( rspace ); + + for ( i = 0, l = this.length; i < l; i++ ) { + elem = this[ i ]; + + if ( elem.nodeType === 1 && elem.className ) { + if ( value ) { + className = (" " + elem.className + " ").replace( rclass, " " ); + for ( c = 0, cl = classNames.length; c < cl; c++ ) { + className = className.replace(" " + classNames[ c ] + " ", " "); + } + elem.className = jQuery.trim( className ); + + } else { + elem.className = ""; + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isBool = typeof stateVal === "boolean"; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( i ) { + jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); + }); + } + + return this.each(function() { + if ( type === "string" ) { + // toggle individual class names + var className, + i = 0, + self = jQuery( this ), + state = stateVal, + classNames = value.split( rspace ); + + while ( (className = classNames[ i++ ]) ) { + // check each className given, space seperated list + state = isBool ? state : !self.hasClass( className ); + self[ state ? "addClass" : "removeClass" ]( className ); + } + + } else if ( type === "undefined" || type === "boolean" ) { + if ( this.className ) { + // store className if set + jQuery._data( this, "__className__", this.className ); + } + + // toggle whole className + this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; + } + }); + }, + + hasClass: function( selector ) { + var className = " " + selector + " "; + for ( var i = 0, l = this.length; i < l; i++ ) { + if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { + return true; + } + } + + return false; + }, + + val: function( value ) { + var hooks, ret, + elem = this[0]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.nodeName.toLowerCase() ] || jQuery.valHooks[ elem.type ]; + + if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { + return ret; + } + + ret = elem.value; + + return typeof ret === "string" ? + // handle most common string cases + ret.replace(rreturn, "") : + // handle cases where value is null/undef or number + ret == null ? "" : ret; + } + + return undefined; + } + + var isFunction = jQuery.isFunction( value ); + + return this.each(function( i ) { + var self = jQuery(this), val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call( this, i, self.val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + } else if ( typeof val === "number" ) { + val += ""; + } else if ( jQuery.isArray( val ) ) { + val = jQuery.map(val, function ( value ) { + return value == null ? "" : value + ""; + }); + } + + hooks = jQuery.valHooks[ this.nodeName.toLowerCase() ] || jQuery.valHooks[ this.type ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + }); + } +}); + +jQuery.extend({ + valHooks: { + option: { + get: function( elem ) { + // attributes.value is undefined in Blackberry 4.7 but + // uses .value. See #6932 + var val = elem.attributes.value; + return !val || val.specified ? elem.value : elem.text; + } + }, + select: { + get: function( elem ) { + var value, + index = elem.selectedIndex, + values = [], + options = elem.options, + one = elem.type === "select-one"; + + // Nothing was selected + if ( index < 0 ) { + return null; + } + + // Loop through all the selected options + for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { + var option = options[ i ]; + + // Don't return options that are disabled or in a disabled optgroup + if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && + (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + // Fixes Bug #2551 -- select.val() broken in IE after form.reset() + if ( one && !values.length && options.length ) { + return jQuery( options[ index ] ).val(); + } + + return values; + }, + + set: function( elem, value ) { + var values = jQuery.makeArray( value ); + + jQuery(elem).find("option").each(function() { + this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; + }); + + if ( !values.length ) { + elem.selectedIndex = -1; + } + return values; + } + } + }, + + attrFn: { + val: true, + css: true, + html: true, + text: true, + data: true, + width: true, + height: true, + offset: true + }, + + attrFix: { + // Always normalize to ensure hook usage + tabindex: "tabIndex" + }, + + attr: function( elem, name, value, pass ) { + var nType = elem.nodeType; + + // don't get/set attributes on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return undefined; + } + + if ( pass && name in jQuery.attrFn ) { + return jQuery( elem )[ name ]( value ); + } + + // Fallback to prop when attributes are not supported + if ( !("getAttribute" in elem) ) { + return jQuery.prop( elem, name, value ); + } + + var ret, hooks, + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + // Normalize the name if needed + if ( notxml ) { + name = jQuery.attrFix[ name ] || name; + + hooks = jQuery.attrHooks[ name ]; + + if ( !hooks ) { + // Use boolHook for boolean attributes + if ( rboolean.test( name ) ) { + hooks = boolHook; + + // Use nodeHook if available( IE6/7 ) + } else if ( nodeHook ) { + hooks = nodeHook; + } + } + } + + if ( value !== undefined ) { + + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return undefined; + + } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + elem.setAttribute( name, "" + value ); + return value; + } + + } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + + ret = elem.getAttribute( name ); + + // Non-existent attributes return null, we normalize to undefined + return ret === null ? + undefined : + ret; + } + }, + + removeAttr: function( elem, name ) { + var propName; + if ( elem.nodeType === 1 ) { + name = jQuery.attrFix[ name ] || name; + + jQuery.attr( elem, name, "" ); + elem.removeAttribute( name ); + + // Set corresponding property to false for boolean attributes + if ( rboolean.test( name ) && (propName = jQuery.propFix[ name ] || name) in elem ) { + elem[ propName ] = false; + } + } + }, + + attrHooks: { + type: { + set: function( elem, value ) { + // We can't allow the type property to be changed (since it causes problems in IE) + if ( rtype.test( elem.nodeName ) && elem.parentNode ) { + jQuery.error( "type property can't be changed" ); + } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { + // Setting the type on a radio button after the value resets the value in IE6-9 + // Reset value to it's default in case type is set after value + // This is for element creation + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + }, + // Use the value property for back compat + // Use the nodeHook for button elements in IE6/7 (#1954) + value: { + get: function( elem, name ) { + if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { + return nodeHook.get( elem, name ); + } + return name in elem ? + elem.value : + null; + }, + set: function( elem, value, name ) { + if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { + return nodeHook.set( elem, value, name ); + } + // Does not return so that setAttribute is also used + elem.value = value; + } + } + }, + + propFix: { + tabindex: "tabIndex", + readonly: "readOnly", + "for": "htmlFor", + "class": "className", + maxlength: "maxLength", + cellspacing: "cellSpacing", + cellpadding: "cellPadding", + rowspan: "rowSpan", + colspan: "colSpan", + usemap: "useMap", + frameborder: "frameBorder", + contenteditable: "contentEditable" + }, + + prop: function( elem, name, value ) { + var nType = elem.nodeType; + + // don't get/set properties on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return undefined; + } + + var ret, hooks, + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + if ( notxml ) { + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + return (elem[ name ] = value); + } + + } else { + if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + return elem[ name ]; + } + } + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set + // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + var attributeNode = elem.getAttributeNode("tabindex"); + + return attributeNode && attributeNode.specified ? + parseInt( attributeNode.value, 10 ) : + rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? + 0 : + undefined; + } + } + } +}); + +// Add the tabindex propHook to attrHooks for back-compat +jQuery.attrHooks.tabIndex = jQuery.propHooks.tabIndex; + +// Hook for boolean attributes +boolHook = { + get: function( elem, name ) { + // Align boolean attributes with corresponding properties + // Fall back to attribute presence where some booleans are not supported + var attrNode; + return jQuery.prop( elem, name ) === true || ( attrNode = elem.getAttributeNode( name ) ) && attrNode.nodeValue !== false ? + name.toLowerCase() : + undefined; + }, + set: function( elem, value, name ) { + var propName; + if ( value === false ) { + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + // value is true since we know at this point it's type boolean and not false + // Set boolean attributes to the same name and set the DOM property + propName = jQuery.propFix[ name ] || name; + if ( propName in elem ) { + // Only set the IDL specifically if it already exists on the element + elem[ propName ] = true; + } + + elem.setAttribute( name, name.toLowerCase() ); + } + return name; + } +}; + +// IE6/7 do not support getting/setting some attributes with get/setAttribute +if ( !jQuery.support.getSetAttribute ) { + + // Use this for any attribute in IE6/7 + // This fixes almost every IE6/7 issue + nodeHook = jQuery.valHooks.button = { + get: function( elem, name ) { + var ret; + ret = elem.getAttributeNode( name ); + // Return undefined if nodeValue is empty string + return ret && ret.nodeValue !== "" ? + ret.nodeValue : + undefined; + }, + set: function( elem, value, name ) { + // Set the existing or create a new attribute node + var ret = elem.getAttributeNode( name ); + if ( !ret ) { + ret = document.createAttribute( name ); + elem.setAttributeNode( ret ); + } + return (ret.nodeValue = value + ""); + } + }; + + // Set width and height to auto instead of 0 on empty string( Bug #8150 ) + // This is for removals + jQuery.each([ "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + set: function( elem, value ) { + if ( value === "" ) { + elem.setAttribute( name, "auto" ); + return value; + } + } + }); + }); +} + + +// Some attributes require a special call on IE +if ( !jQuery.support.hrefNormalized ) { + jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + get: function( elem ) { + var ret = elem.getAttribute( name, 2 ); + return ret === null ? undefined : ret; + } + }); + }); +} + +if ( !jQuery.support.style ) { + jQuery.attrHooks.style = { + get: function( elem ) { + // Return undefined in the case of empty string + // Normalize to lowercase since IE uppercases css property names + return elem.style.cssText.toLowerCase() || undefined; + }, + set: function( elem, value ) { + return (elem.style.cssText = "" + value); + } + }; +} + +// Safari mis-reports the default selected property of an option +// Accessing the parent's selectedIndex property fixes it +if ( !jQuery.support.optSelected ) { + jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { + get: function( elem ) { + var parent = elem.parentNode; + + if ( parent ) { + parent.selectedIndex; + + // Make sure that it also works with optgroups, see #5701 + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + return null; + } + }); +} + +// Radios and checkboxes getter/setter +if ( !jQuery.support.checkOn ) { + jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + get: function( elem ) { + // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified + return elem.getAttribute("value") === null ? "on" : elem.value; + } + }; + }); +} +jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { + set: function( elem, value ) { + if ( jQuery.isArray( value ) ) { + return (elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0); + } + } + }); +}); + + + + +var rnamespaces = /\.(.*)$/, + rformElems = /^(?:textarea|input|select)$/i, + rperiod = /\./g, + rspaces = / /g, + rescape = /[^\w\s.|`]/g, + fcleanup = function( nm ) { + return nm.replace(rescape, "\\$&"); + }; + +/* + * A number of helper functions used for managing events. + * Many of the ideas behind this code originated from + * Dean Edwards' addEvent library. + */ +jQuery.event = { + + // Bind an event to an element + // Original by Dean Edwards + add: function( elem, types, handler, data ) { + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + if ( handler === false ) { + handler = returnFalse; + } else if ( !handler ) { + // Fixes bug #7229. Fix recommended by jdalton + return; + } + + var handleObjIn, handleObj; + + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + } + + // Make sure that the function being executed has a unique ID + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure + var elemData = jQuery._data( elem ); + + // If no elemData is found then we must be trying to bind to one of the + // banned noData elements + if ( !elemData ) { + return; + } + + var events = elemData.events, + eventHandle = elemData.handle; + + if ( !events ) { + elemData.events = events = {}; + } + + if ( !eventHandle ) { + elemData.handle = eventHandle = function( e ) { + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ? + jQuery.event.handle.apply( eventHandle.elem, arguments ) : + undefined; + }; + } + + // Add elem as a property of the handle function + // This is to prevent a memory leak with non-native events in IE. + eventHandle.elem = elem; + + // Handle multiple events separated by a space + // jQuery(...).bind("mouseover mouseout", fn); + types = types.split(" "); + + var type, i = 0, namespaces; + + while ( (type = types[ i++ ]) ) { + handleObj = handleObjIn ? + jQuery.extend({}, handleObjIn) : + { handler: handler, data: data }; + + // Namespaced event handlers + if ( type.indexOf(".") > -1 ) { + namespaces = type.split("."); + type = namespaces.shift(); + handleObj.namespace = namespaces.slice(0).sort().join("."); + + } else { + namespaces = []; + handleObj.namespace = ""; + } + + handleObj.type = type; + if ( !handleObj.guid ) { + handleObj.guid = handler.guid; + } + + // Get the current list of functions bound to this event + var handlers = events[ type ], + special = jQuery.event.special[ type ] || {}; + + // Init the event handler queue + if ( !handlers ) { + handlers = events[ type ] = []; + + // Check for a special event handler + // Only use addEventListener/attachEvent if the special + // events handler returns false + if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + // Bind the global event handler to the element + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle, false ); + + } else if ( elem.attachEvent ) { + elem.attachEvent( "on" + type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add the function to the element's handler list + handlers.push( handleObj ); + + // Keep track of which events have been used, for event optimization + jQuery.event.global[ type ] = true; + } + + // Nullify elem to prevent memory leaks in IE + elem = null; + }, + + global: {}, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, pos ) { + // don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + if ( handler === false ) { + handler = returnFalse; + } + + var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType, + elemData = jQuery.hasData( elem ) && jQuery._data( elem ), + events = elemData && elemData.events; + + if ( !elemData || !events ) { + return; + } + + // types is actually an event object here + if ( types && types.type ) { + handler = types.handler; + types = types.type; + } + + // Unbind all events for the element + if ( !types || typeof types === "string" && types.charAt(0) === "." ) { + types = types || ""; + + for ( type in events ) { + jQuery.event.remove( elem, type + types ); + } + + return; + } + + // Handle multiple events separated by a space + // jQuery(...).unbind("mouseover mouseout", fn); + types = types.split(" "); + + while ( (type = types[ i++ ]) ) { + origType = type; + handleObj = null; + all = type.indexOf(".") < 0; + namespaces = []; + + if ( !all ) { + // Namespaced event handlers + namespaces = type.split("."); + type = namespaces.shift(); + + namespace = new RegExp("(^|\\.)" + + jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)"); + } + + eventType = events[ type ]; + + if ( !eventType ) { + continue; + } + + if ( !handler ) { + for ( j = 0; j < eventType.length; j++ ) { + handleObj = eventType[ j ]; + + if ( all || namespace.test( handleObj.namespace ) ) { + jQuery.event.remove( elem, origType, handleObj.handler, j ); + eventType.splice( j--, 1 ); + } + } + + continue; + } + + special = jQuery.event.special[ type ] || {}; + + for ( j = pos || 0; j < eventType.length; j++ ) { + handleObj = eventType[ j ]; + + if ( handler.guid === handleObj.guid ) { + // remove the given handler for the given type + if ( all || namespace.test( handleObj.namespace ) ) { + if ( pos == null ) { + eventType.splice( j--, 1 ); + } + + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + + if ( pos != null ) { + break; + } + } + } + + // remove generic event handler if no more handlers exist + if ( eventType.length === 0 || pos != null && eventType.length === 1 ) { + if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) { + jQuery.removeEvent( elem, type, elemData.handle ); + } + + ret = null; + delete events[ type ]; + } + } + + // Remove the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + var handle = elemData.handle; + if ( handle ) { + handle.elem = null; + } + + delete elemData.events; + delete elemData.handle; + + if ( jQuery.isEmptyObject( elemData ) ) { + jQuery.removeData( elem, undefined, true ); + } + } + }, + + // Events that are safe to short-circuit if no handlers are attached. + // Native DOM events should not be added, they may have inline handlers. + customEvent: { + "getData": true, + "setData": true, + "changeData": true + }, + + trigger: function( event, data, elem, onlyHandlers ) { + // Event object or event type + var type = event.type || event, + namespaces = [], + exclusive; + + if ( type.indexOf("!") >= 0 ) { + // Exclusive events trigger only for the exact event (no namespaces) + type = type.slice(0, -1); + exclusive = true; + } + + if ( type.indexOf(".") >= 0 ) { + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split("."); + type = namespaces.shift(); + namespaces.sort(); + } + + if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) { + // No jQuery handlers for this event type, and it can't have inline handlers + return; + } + + // Caller can pass in an Event, Object, or just an event type string + event = typeof event === "object" ? + // jQuery.Event object + event[ jQuery.expando ] ? event : + // Object literal + new jQuery.Event( type, event ) : + // Just the event type (string) + new jQuery.Event( type ); + + event.type = type; + event.exclusive = exclusive; + event.namespace = namespaces.join("."); + event.namespace_re = new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)"); + + // triggerHandler() and global events don't bubble or run the default action + if ( onlyHandlers || !elem ) { + event.preventDefault(); + event.stopPropagation(); + } + + // Handle a global trigger + if ( !elem ) { + // TODO: Stop taunting the data cache; remove global events and always attach to document + jQuery.each( jQuery.cache, function() { + // internalKey variable is just used to make it easier to find + // and potentially change this stuff later; currently it just + // points to jQuery.expando + var internalKey = jQuery.expando, + internalCache = this[ internalKey ]; + if ( internalCache && internalCache.events && internalCache.events[ type ] ) { + jQuery.event.trigger( event, data, internalCache.handle.elem ); + } + }); + return; + } + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // Clean up the event in case it is being reused + event.result = undefined; + event.target = elem; + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data != null ? jQuery.makeArray( data ) : []; + data.unshift( event ); + + var cur = elem, + // IE doesn't like method names with a colon (#3533, #8272) + ontype = type.indexOf(":") < 0 ? "on" + type : ""; + + // Fire event on the current element, then bubble up the DOM tree + do { + var handle = jQuery._data( cur, "handle" ); + + event.currentTarget = cur; + if ( handle ) { + handle.apply( cur, data ); + } + + // Trigger an inline bound script + if ( ontype && jQuery.acceptData( cur ) && cur[ ontype ] && cur[ ontype ].apply( cur, data ) === false ) { + event.result = false; + event.preventDefault(); + } + + // Bubble up to document, then to window + cur = cur.parentNode || cur.ownerDocument || cur === event.target.ownerDocument && window; + } while ( cur && !event.isPropagationStopped() ); + + // If nobody prevented the default action, do it now + if ( !event.isDefaultPrevented() ) { + var old, + special = jQuery.event.special[ type ] || {}; + + if ( (!special._default || special._default.call( elem.ownerDocument, event ) === false) && + !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name name as the event. + // Can't use an .isFunction)() check here because IE6/7 fails that test. + // IE<9 dies on focus to hidden element (#1486), may want to revisit a try/catch. + try { + if ( ontype && elem[ type ] ) { + // Don't re-trigger an onFOO event when we call its FOO() method + old = elem[ ontype ]; + + if ( old ) { + elem[ ontype ] = null; + } + + jQuery.event.triggered = type; + elem[ type ](); + } + } catch ( ieError ) {} + + if ( old ) { + elem[ ontype ] = old; + } + + jQuery.event.triggered = undefined; + } + } + + return event.result; + }, + + handle: function( event ) { + event = jQuery.event.fix( event || window.event ); + // Snapshot the handlers list since a called handler may add/remove events. + var handlers = ((jQuery._data( this, "events" ) || {})[ event.type ] || []).slice(0), + run_all = !event.exclusive && !event.namespace, + args = Array.prototype.slice.call( arguments, 0 ); + + // Use the fix-ed Event rather than the (read-only) native event + args[0] = event; + event.currentTarget = this; + + for ( var j = 0, l = handlers.length; j < l; j++ ) { + var handleObj = handlers[ j ]; + + // Triggered event must 1) be non-exclusive and have no namespace, or + // 2) have namespace(s) a subset or equal to those in the bound event. + if ( run_all || event.namespace_re.test( handleObj.namespace ) ) { + // Pass in a reference to the handler function itself + // So that we can later remove it + event.handler = handleObj.handler; + event.data = handleObj.data; + event.handleObj = handleObj; + + var ret = handleObj.handler.apply( this, args ); + + if ( ret !== undefined ) { + event.result = ret; + if ( ret === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + + if ( event.isImmediatePropagationStopped() ) { + break; + } + } + } + return event.result; + }, + + props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "), + + fix: function( event ) { + if ( event[ jQuery.expando ] ) { + return event; + } + + // store a copy of the original event object + // and "clone" to set read-only properties + var originalEvent = event; + event = jQuery.Event( originalEvent ); + + for ( var i = this.props.length, prop; i; ) { + prop = this.props[ --i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Fix target property, if necessary + if ( !event.target ) { + // Fixes #1925 where srcElement might not be defined either + event.target = event.srcElement || document; + } + + // check if target is a textnode (safari) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + // Add relatedTarget, if necessary + if ( !event.relatedTarget && event.fromElement ) { + event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement; + } + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && event.clientX != null ) { + var eventDocument = event.target.ownerDocument || document, + doc = eventDocument.documentElement, + body = eventDocument.body; + + event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0); + event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0); + } + + // Add which for key events + if ( event.which == null && (event.charCode != null || event.keyCode != null) ) { + event.which = event.charCode != null ? event.charCode : event.keyCode; + } + + // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs) + if ( !event.metaKey && event.ctrlKey ) { + event.metaKey = event.ctrlKey; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && event.button !== undefined ) { + event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) )); + } + + return event; + }, + + // Deprecated, use jQuery.guid instead + guid: 1E8, + + // Deprecated, use jQuery.proxy instead + proxy: jQuery.proxy, + + special: { + ready: { + // Make sure the ready event is setup + setup: jQuery.bindReady, + teardown: jQuery.noop + }, + + live: { + add: function( handleObj ) { + jQuery.event.add( this, + liveConvert( handleObj.origType, handleObj.selector ), + jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) ); + }, + + remove: function( handleObj ) { + jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj ); + } + }, + + beforeunload: { + setup: function( data, namespaces, eventHandle ) { + // We only want to do this special case on windows + if ( jQuery.isWindow( this ) ) { + this.onbeforeunload = eventHandle; + } + }, + + teardown: function( namespaces, eventHandle ) { + if ( this.onbeforeunload === eventHandle ) { + this.onbeforeunload = null; + } + } + } + } +}; + +jQuery.removeEvent = document.removeEventListener ? + function( elem, type, handle ) { + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle, false ); + } + } : + function( elem, type, handle ) { + if ( elem.detachEvent ) { + elem.detachEvent( "on" + type, handle ); + } + }; + +jQuery.Event = function( src, props ) { + // Allow instantiation without the 'new' keyword + if ( !this.preventDefault ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = (src.defaultPrevented || src.returnValue === false || + src.getPreventDefault && src.getPreventDefault()) ? returnTrue : returnFalse; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // timeStamp is buggy for some events on Firefox(#3843) + // So we won't rely on the native value + this.timeStamp = jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +function returnFalse() { + return false; +} +function returnTrue() { + return true; +} + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + preventDefault: function() { + this.isDefaultPrevented = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + + // if preventDefault exists run it on the original event + if ( e.preventDefault ) { + e.preventDefault(); + + // otherwise set the returnValue property of the original event to false (IE) + } else { + e.returnValue = false; + } + }, + stopPropagation: function() { + this.isPropagationStopped = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + // if stopPropagation exists run it on the original event + if ( e.stopPropagation ) { + e.stopPropagation(); + } + // otherwise set the cancelBubble property of the original event to true (IE) + e.cancelBubble = true; + }, + stopImmediatePropagation: function() { + this.isImmediatePropagationStopped = returnTrue; + this.stopPropagation(); + }, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse +}; + +// Checks if an event happened on an element within another element +// Used in jQuery.event.special.mouseenter and mouseleave handlers +var withinElement = function( event ) { + + // Check if mouse(over|out) are still within the same parent element + var related = event.relatedTarget, + inside = false, + eventType = event.type; + + event.type = event.data; + + if ( related !== this ) { + + if ( related ) { + inside = jQuery.contains( this, related ); + } + + if ( !inside ) { + + jQuery.event.handle.apply( this, arguments ); + + event.type = eventType; + } + } +}, + +// In case of event delegation, we only need to rename the event.type, +// liveHandler will take care of the rest. +delegate = function( event ) { + event.type = event.data; + jQuery.event.handle.apply( this, arguments ); +}; + +// Create mouseenter and mouseleave events +jQuery.each({ + mouseenter: "mouseover", + mouseleave: "mouseout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + setup: function( data ) { + jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig ); + }, + teardown: function( data ) { + jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement ); + } + }; +}); + +// submit delegation +if ( !jQuery.support.submitBubbles ) { + + jQuery.event.special.submit = { + setup: function( data, namespaces ) { + if ( !jQuery.nodeName( this, "form" ) ) { + jQuery.event.add(this, "click.specialSubmit", function( e ) { + // Avoid triggering error on non-existent type attribute in IE VML (#7071) + var elem = e.target, + type = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.type : ""; + + if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) { + trigger( "submit", this, arguments ); + } + }); + + jQuery.event.add(this, "keypress.specialSubmit", function( e ) { + var elem = e.target, + type = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.type : ""; + + if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) { + trigger( "submit", this, arguments ); + } + }); + + } else { + return false; + } + }, + + teardown: function( namespaces ) { + jQuery.event.remove( this, ".specialSubmit" ); + } + }; + +} + +// change delegation, happens here so we have bind. +if ( !jQuery.support.changeBubbles ) { + + var changeFilters, + + getVal = function( elem ) { + var type = jQuery.nodeName( elem, "input" ) ? elem.type : "", + val = elem.value; + + if ( type === "radio" || type === "checkbox" ) { + val = elem.checked; + + } else if ( type === "select-multiple" ) { + val = elem.selectedIndex > -1 ? + jQuery.map( elem.options, function( elem ) { + return elem.selected; + }).join("-") : + ""; + + } else if ( jQuery.nodeName( elem, "select" ) ) { + val = elem.selectedIndex; + } + + return val; + }, + + testChange = function testChange( e ) { + var elem = e.target, data, val; + + if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) { + return; + } + + data = jQuery._data( elem, "_change_data" ); + val = getVal(elem); + + // the current data will be also retrieved by beforeactivate + if ( e.type !== "focusout" || elem.type !== "radio" ) { + jQuery._data( elem, "_change_data", val ); + } + + if ( data === undefined || val === data ) { + return; + } + + if ( data != null || val ) { + e.type = "change"; + e.liveFired = undefined; + jQuery.event.trigger( e, arguments[1], elem ); + } + }; + + jQuery.event.special.change = { + filters: { + focusout: testChange, + + beforedeactivate: testChange, + + click: function( e ) { + var elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : ""; + + if ( type === "radio" || type === "checkbox" || jQuery.nodeName( elem, "select" ) ) { + testChange.call( this, e ); + } + }, + + // Change has to be called before submit + // Keydown will be called before keypress, which is used in submit-event delegation + keydown: function( e ) { + var elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : ""; + + if ( (e.keyCode === 13 && !jQuery.nodeName( elem, "textarea" ) ) || + (e.keyCode === 32 && (type === "checkbox" || type === "radio")) || + type === "select-multiple" ) { + testChange.call( this, e ); + } + }, + + // Beforeactivate happens also before the previous element is blurred + // with this event you can't trigger a change event, but you can store + // information + beforeactivate: function( e ) { + var elem = e.target; + jQuery._data( elem, "_change_data", getVal(elem) ); + } + }, + + setup: function( data, namespaces ) { + if ( this.type === "file" ) { + return false; + } + + for ( var type in changeFilters ) { + jQuery.event.add( this, type + ".specialChange", changeFilters[type] ); + } + + return rformElems.test( this.nodeName ); + }, + + teardown: function( namespaces ) { + jQuery.event.remove( this, ".specialChange" ); + + return rformElems.test( this.nodeName ); + } + }; + + changeFilters = jQuery.event.special.change.filters; + + // Handle when the input is .focus()'d + changeFilters.focus = changeFilters.beforeactivate; +} + +function trigger( type, elem, args ) { + // Piggyback on a donor event to simulate a different one. + // Fake originalEvent to avoid donor's stopPropagation, but if the + // simulated event prevents default then we do the same on the donor. + // Don't pass args or remember liveFired; they apply to the donor event. + var event = jQuery.extend( {}, args[ 0 ] ); + event.type = type; + event.originalEvent = {}; + event.liveFired = undefined; + jQuery.event.handle.call( elem, event ); + if ( event.isDefaultPrevented() ) { + args[ 0 ].preventDefault(); + } +} + +// Create "bubbling" focus and blur events +if ( !jQuery.support.focusinBubbles ) { + jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler while someone wants focusin/focusout + var attaches = 0; + + jQuery.event.special[ fix ] = { + setup: function() { + if ( attaches++ === 0 ) { + document.addEventListener( orig, handler, true ); + } + }, + teardown: function() { + if ( --attaches === 0 ) { + document.removeEventListener( orig, handler, true ); + } + } + }; + + function handler( donor ) { + // Donor event is always a native one; fix it and switch its type. + // Let focusin/out handler cancel the donor focus/blur event. + var e = jQuery.event.fix( donor ); + e.type = fix; + e.originalEvent = {}; + jQuery.event.trigger( e, null, e.target ); + if ( e.isDefaultPrevented() ) { + donor.preventDefault(); + } + } + }); +} + +jQuery.each(["bind", "one"], function( i, name ) { + jQuery.fn[ name ] = function( type, data, fn ) { + var handler; + + // Handle object literals + if ( typeof type === "object" ) { + for ( var key in type ) { + this[ name ](key, data, type[key], fn); + } + return this; + } + + if ( arguments.length === 2 || data === false ) { + fn = data; + data = undefined; + } + + if ( name === "one" ) { + handler = function( event ) { + jQuery( this ).unbind( event, handler ); + return fn.apply( this, arguments ); + }; + handler.guid = fn.guid || jQuery.guid++; + } else { + handler = fn; + } + + if ( type === "unload" && name !== "one" ) { + this.one( type, data, fn ); + + } else { + for ( var i = 0, l = this.length; i < l; i++ ) { + jQuery.event.add( this[i], type, handler, data ); + } + } + + return this; + }; +}); + +jQuery.fn.extend({ + unbind: function( type, fn ) { + // Handle object literals + if ( typeof type === "object" && !type.preventDefault ) { + for ( var key in type ) { + this.unbind(key, type[key]); + } + + } else { + for ( var i = 0, l = this.length; i < l; i++ ) { + jQuery.event.remove( this[i], type, fn ); + } + } + + return this; + }, + + delegate: function( selector, types, data, fn ) { + return this.live( types, data, fn, selector ); + }, + + undelegate: function( selector, types, fn ) { + if ( arguments.length === 0 ) { + return this.unbind( "live" ); + + } else { + return this.die( types, null, fn, selector ); + } + }, + + trigger: function( type, data ) { + return this.each(function() { + jQuery.event.trigger( type, data, this ); + }); + }, + + triggerHandler: function( type, data ) { + if ( this[0] ) { + return jQuery.event.trigger( type, data, this[0], true ); + } + }, + + toggle: function( fn ) { + // Save reference to arguments for access in closure + var args = arguments, + guid = fn.guid || jQuery.guid++, + i = 0, + toggler = function( event ) { + // Figure out which function to execute + var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i; + jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 ); + + // Make sure that clicks stop + event.preventDefault(); + + // and execute the function + return args[ lastToggle ].apply( this, arguments ) || false; + }; + + // link all the functions, so any of them can unbind this click handler + toggler.guid = guid; + while ( i < args.length ) { + args[ i++ ].guid = guid; + } + + return this.click( toggler ); + }, + + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + } +}); + +var liveMap = { + focus: "focusin", + blur: "focusout", + mouseenter: "mouseover", + mouseleave: "mouseout" +}; + +jQuery.each(["live", "die"], function( i, name ) { + jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) { + var type, i = 0, match, namespaces, preType, + selector = origSelector || this.selector, + context = origSelector ? this : jQuery( this.context ); + + if ( typeof types === "object" && !types.preventDefault ) { + for ( var key in types ) { + context[ name ]( key, data, types[key], selector ); + } + + return this; + } + + if ( name === "die" && !types && + origSelector && origSelector.charAt(0) === "." ) { + + context.unbind( origSelector ); + + return this; + } + + if ( data === false || jQuery.isFunction( data ) ) { + fn = data || returnFalse; + data = undefined; + } + + types = (types || "").split(" "); + + while ( (type = types[ i++ ]) != null ) { + match = rnamespaces.exec( type ); + namespaces = ""; + + if ( match ) { + namespaces = match[0]; + type = type.replace( rnamespaces, "" ); + } + + if ( type === "hover" ) { + types.push( "mouseenter" + namespaces, "mouseleave" + namespaces ); + continue; + } + + preType = type; + + if ( liveMap[ type ] ) { + types.push( liveMap[ type ] + namespaces ); + type = type + namespaces; + + } else { + type = (liveMap[ type ] || type) + namespaces; + } + + if ( name === "live" ) { + // bind live handler + for ( var j = 0, l = context.length; j < l; j++ ) { + jQuery.event.add( context[j], "live." + liveConvert( type, selector ), + { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } ); + } + + } else { + // unbind live handler + context.unbind( "live." + liveConvert( type, selector ), fn ); + } + } + + return this; + }; +}); + +function liveHandler( event ) { + var stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret, + elems = [], + selectors = [], + events = jQuery._data( this, "events" ); + + // Make sure we avoid non-left-click bubbling in Firefox (#3861) and disabled elements in IE (#6911) + if ( event.liveFired === this || !events || !events.live || event.target.disabled || event.button && event.type === "click" ) { + return; + } + + if ( event.namespace ) { + namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)"); + } + + event.liveFired = this; + + var live = events.live.slice(0); + + for ( j = 0; j < live.length; j++ ) { + handleObj = live[j]; + + if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) { + selectors.push( handleObj.selector ); + + } else { + live.splice( j--, 1 ); + } + } + + match = jQuery( event.target ).closest( selectors, event.currentTarget ); + + for ( i = 0, l = match.length; i < l; i++ ) { + close = match[i]; + + for ( j = 0; j < live.length; j++ ) { + handleObj = live[j]; + + if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) && !close.elem.disabled ) { + elem = close.elem; + related = null; + + // Those two events require additional checking + if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) { + event.type = handleObj.preType; + related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0]; + + // Make sure not to accidentally match a child element with the same selector + if ( related && jQuery.contains( elem, related ) ) { + related = elem; + } + } + + if ( !related || related !== elem ) { + elems.push({ elem: elem, handleObj: handleObj, level: close.level }); + } + } + } + } + + for ( i = 0, l = elems.length; i < l; i++ ) { + match = elems[i]; + + if ( maxLevel && match.level > maxLevel ) { + break; + } + + event.currentTarget = match.elem; + event.data = match.handleObj.data; + event.handleObj = match.handleObj; + + ret = match.handleObj.origHandler.apply( match.elem, arguments ); + + if ( ret === false || event.isPropagationStopped() ) { + maxLevel = match.level; + + if ( ret === false ) { + stop = false; + } + if ( event.isImmediatePropagationStopped() ) { + break; + } + } + } + + return stop; +} + +function liveConvert( type, selector ) { + return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspaces, "&"); +} + +jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + + "change select submit keydown keypress keyup error").split(" "), function( i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( data, fn ) { + if ( fn == null ) { + fn = data; + data = null; + } + + return arguments.length > 0 ? + this.bind( name, data, fn ) : + this.trigger( name ); + }; + + if ( jQuery.attrFn ) { + jQuery.attrFn[ name ] = true; + } +}); + + + +/*! + * Sizzle CSS Selector Engine + * Copyright 2011, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * More information: http://sizzlejs.com/ + */ +(function(){ + +var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, + done = 0, + toString = Object.prototype.toString, + hasDuplicate = false, + baseHasDuplicate = true, + rBackslash = /\\/g, + rNonWord = /\W/; + +// Here we check if the JavaScript engine is using some sort of +// optimization where it does not always call our comparision +// function. If that is the case, discard the hasDuplicate value. +// Thus far that includes Google Chrome. +[0, 0].sort(function() { + baseHasDuplicate = false; + return 0; +}); + +var Sizzle = function( selector, context, results, seed ) { + results = results || []; + context = context || document; + + var origContext = context; + + if ( context.nodeType !== 1 && context.nodeType !== 9 ) { + return []; + } + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + var m, set, checkSet, extra, ret, cur, pop, i, + prune = true, + contextXML = Sizzle.isXML( context ), + parts = [], + soFar = selector; + + // Reset the position of the chunker regexp (start from head) + do { + chunker.exec( "" ); + m = chunker.exec( soFar ); + + if ( m ) { + soFar = m[3]; + + parts.push( m[1] ); + + if ( m[2] ) { + extra = m[3]; + break; + } + } + } while ( m ); + + if ( parts.length > 1 && origPOS.exec( selector ) ) { + + if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { + set = posProcess( parts[0] + parts[1], context ); + + } else { + set = Expr.relative[ parts[0] ] ? + [ context ] : + Sizzle( parts.shift(), context ); + + while ( parts.length ) { + selector = parts.shift(); + + if ( Expr.relative[ selector ] ) { + selector += parts.shift(); + } + + set = posProcess( selector, set ); + } + } + + } else { + // Take a shortcut and set the context if the root selector is an ID + // (but not if it'll be faster if the inner selector is an ID) + if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && + Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { + + ret = Sizzle.find( parts.shift(), context, contextXML ); + context = ret.expr ? + Sizzle.filter( ret.expr, ret.set )[0] : + ret.set[0]; + } + + if ( context ) { + ret = seed ? + { expr: parts.pop(), set: makeArray(seed) } : + Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); + + set = ret.expr ? + Sizzle.filter( ret.expr, ret.set ) : + ret.set; + + if ( parts.length > 0 ) { + checkSet = makeArray( set ); + + } else { + prune = false; + } + + while ( parts.length ) { + cur = parts.pop(); + pop = cur; + + if ( !Expr.relative[ cur ] ) { + cur = ""; + } else { + pop = parts.pop(); + } + + if ( pop == null ) { + pop = context; + } + + Expr.relative[ cur ]( checkSet, pop, contextXML ); + } + + } else { + checkSet = parts = []; + } + } + + if ( !checkSet ) { + checkSet = set; + } + + if ( !checkSet ) { + Sizzle.error( cur || selector ); + } + + if ( toString.call(checkSet) === "[object Array]" ) { + if ( !prune ) { + results.push.apply( results, checkSet ); + + } else if ( context && context.nodeType === 1 ) { + for ( i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) { + results.push( set[i] ); + } + } + + } else { + for ( i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && checkSet[i].nodeType === 1 ) { + results.push( set[i] ); + } + } + } + + } else { + makeArray( checkSet, results ); + } + + if ( extra ) { + Sizzle( extra, origContext, results, seed ); + Sizzle.uniqueSort( results ); + } + + return results; +}; + +Sizzle.uniqueSort = function( results ) { + if ( sortOrder ) { + hasDuplicate = baseHasDuplicate; + results.sort( sortOrder ); + + if ( hasDuplicate ) { + for ( var i = 1; i < results.length; i++ ) { + if ( results[i] === results[ i - 1 ] ) { + results.splice( i--, 1 ); + } + } + } + } + + return results; +}; + +Sizzle.matches = function( expr, set ) { + return Sizzle( expr, null, null, set ); +}; + +Sizzle.matchesSelector = function( node, expr ) { + return Sizzle( expr, null, null, [node] ).length > 0; +}; + +Sizzle.find = function( expr, context, isXML ) { + var set; + + if ( !expr ) { + return []; + } + + for ( var i = 0, l = Expr.order.length; i < l; i++ ) { + var match, + type = Expr.order[i]; + + if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { + var left = match[1]; + match.splice( 1, 1 ); + + if ( left.substr( left.length - 1 ) !== "\\" ) { + match[1] = (match[1] || "").replace( rBackslash, "" ); + set = Expr.find[ type ]( match, context, isXML ); + + if ( set != null ) { + expr = expr.replace( Expr.match[ type ], "" ); + break; + } + } + } + } + + if ( !set ) { + set = typeof context.getElementsByTagName !== "undefined" ? + context.getElementsByTagName( "*" ) : + []; + } + + return { set: set, expr: expr }; +}; + +Sizzle.filter = function( expr, set, inplace, not ) { + var match, anyFound, + old = expr, + result = [], + curLoop = set, + isXMLFilter = set && set[0] && Sizzle.isXML( set[0] ); + + while ( expr && set.length ) { + for ( var type in Expr.filter ) { + if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) { + var found, item, + filter = Expr.filter[ type ], + left = match[1]; + + anyFound = false; + + match.splice(1,1); + + if ( left.substr( left.length - 1 ) === "\\" ) { + continue; + } + + if ( curLoop === result ) { + result = []; + } + + if ( Expr.preFilter[ type ] ) { + match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); + + if ( !match ) { + anyFound = found = true; + + } else if ( match === true ) { + continue; + } + } + + if ( match ) { + for ( var i = 0; (item = curLoop[i]) != null; i++ ) { + if ( item ) { + found = filter( item, match, i, curLoop ); + var pass = not ^ !!found; + + if ( inplace && found != null ) { + if ( pass ) { + anyFound = true; + + } else { + curLoop[i] = false; + } + + } else if ( pass ) { + result.push( item ); + anyFound = true; + } + } + } + } + + if ( found !== undefined ) { + if ( !inplace ) { + curLoop = result; + } + + expr = expr.replace( Expr.match[ type ], "" ); + + if ( !anyFound ) { + return []; + } + + break; + } + } + } + + // Improper expression + if ( expr === old ) { + if ( anyFound == null ) { + Sizzle.error( expr ); + + } else { + break; + } + } + + old = expr; + } + + return curLoop; +}; + +Sizzle.error = function( msg ) { + throw "Syntax error, unrecognized expression: " + msg; +}; + +var Expr = Sizzle.selectors = { + order: [ "ID", "NAME", "TAG" ], + + match: { + ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, + CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, + NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/, + ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/, + TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/, + CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/, + POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/, + PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/ + }, + + leftMatch: {}, + + attrMap: { + "class": "className", + "for": "htmlFor" + }, + + attrHandle: { + href: function( elem ) { + return elem.getAttribute( "href" ); + }, + type: function( elem ) { + return elem.getAttribute( "type" ); + } + }, + + relative: { + "+": function(checkSet, part){ + var isPartStr = typeof part === "string", + isTag = isPartStr && !rNonWord.test( part ), + isPartStrNotTag = isPartStr && !isTag; + + if ( isTag ) { + part = part.toLowerCase(); + } + + for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { + if ( (elem = checkSet[i]) ) { + while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} + + checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ? + elem || false : + elem === part; + } + } + + if ( isPartStrNotTag ) { + Sizzle.filter( part, checkSet, true ); + } + }, + + ">": function( checkSet, part ) { + var elem, + isPartStr = typeof part === "string", + i = 0, + l = checkSet.length; + + if ( isPartStr && !rNonWord.test( part ) ) { + part = part.toLowerCase(); + + for ( ; i < l; i++ ) { + elem = checkSet[i]; + + if ( elem ) { + var parent = elem.parentNode; + checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false; + } + } + + } else { + for ( ; i < l; i++ ) { + elem = checkSet[i]; + + if ( elem ) { + checkSet[i] = isPartStr ? + elem.parentNode : + elem.parentNode === part; + } + } + + if ( isPartStr ) { + Sizzle.filter( part, checkSet, true ); + } + } + }, + + "": function(checkSet, part, isXML){ + var nodeCheck, + doneName = done++, + checkFn = dirCheck; + + if ( typeof part === "string" && !rNonWord.test( part ) ) { + part = part.toLowerCase(); + nodeCheck = part; + checkFn = dirNodeCheck; + } + + checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML ); + }, + + "~": function( checkSet, part, isXML ) { + var nodeCheck, + doneName = done++, + checkFn = dirCheck; + + if ( typeof part === "string" && !rNonWord.test( part ) ) { + part = part.toLowerCase(); + nodeCheck = part; + checkFn = dirNodeCheck; + } + + checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML ); + } + }, + + find: { + ID: function( match, context, isXML ) { + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + return m && m.parentNode ? [m] : []; + } + }, + + NAME: function( match, context ) { + if ( typeof context.getElementsByName !== "undefined" ) { + var ret = [], + results = context.getElementsByName( match[1] ); + + for ( var i = 0, l = results.length; i < l; i++ ) { + if ( results[i].getAttribute("name") === match[1] ) { + ret.push( results[i] ); + } + } + + return ret.length === 0 ? null : ret; + } + }, + + TAG: function( match, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( match[1] ); + } + } + }, + preFilter: { + CLASS: function( match, curLoop, inplace, result, not, isXML ) { + match = " " + match[1].replace( rBackslash, "" ) + " "; + + if ( isXML ) { + return match; + } + + for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { + if ( elem ) { + if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) { + if ( !inplace ) { + result.push( elem ); + } + + } else if ( inplace ) { + curLoop[i] = false; + } + } + } + + return false; + }, + + ID: function( match ) { + return match[1].replace( rBackslash, "" ); + }, + + TAG: function( match, curLoop ) { + return match[1].replace( rBackslash, "" ).toLowerCase(); + }, + + CHILD: function( match ) { + if ( match[1] === "nth" ) { + if ( !match[2] ) { + Sizzle.error( match[0] ); + } + + match[2] = match[2].replace(/^\+|\s*/g, ''); + + // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' + var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec( + match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || + !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); + + // calculate the numbers (first)n+(last) including if they are negative + match[2] = (test[1] + (test[2] || 1)) - 0; + match[3] = test[3] - 0; + } + else if ( match[2] ) { + Sizzle.error( match[0] ); + } + + // TODO: Move to normal caching system + match[0] = done++; + + return match; + }, + + ATTR: function( match, curLoop, inplace, result, not, isXML ) { + var name = match[1] = match[1].replace( rBackslash, "" ); + + if ( !isXML && Expr.attrMap[name] ) { + match[1] = Expr.attrMap[name]; + } + + // Handle if an un-quoted value was used + match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" ); + + if ( match[2] === "~=" ) { + match[4] = " " + match[4] + " "; + } + + return match; + }, + + PSEUDO: function( match, curLoop, inplace, result, not ) { + if ( match[1] === "not" ) { + // If we're dealing with a complex expression, or a simple one + if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { + match[3] = Sizzle(match[3], null, null, curLoop); + + } else { + var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); + + if ( !inplace ) { + result.push.apply( result, ret ); + } + + return false; + } + + } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { + return true; + } + + return match; + }, + + POS: function( match ) { + match.unshift( true ); + + return match; + } + }, + + filters: { + enabled: function( elem ) { + return elem.disabled === false && elem.type !== "hidden"; + }, + + disabled: function( elem ) { + return elem.disabled === true; + }, + + checked: function( elem ) { + return elem.checked === true; + }, + + selected: function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + parent: function( elem ) { + return !!elem.firstChild; + }, + + empty: function( elem ) { + return !elem.firstChild; + }, + + has: function( elem, i, match ) { + return !!Sizzle( match[3], elem ).length; + }, + + header: function( elem ) { + return (/h\d/i).test( elem.nodeName ); + }, + + text: function( elem ) { + var attr = elem.getAttribute( "type" ), type = elem.type; + // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) + // use getAttribute instead to test this case + return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null ); + }, + + radio: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type; + }, + + checkbox: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type; + }, + + file: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "file" === elem.type; + }, + + password: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "password" === elem.type; + }, + + submit: function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && "submit" === elem.type; + }, + + image: function( elem ) { + return elem.nodeName.toLowerCase() === "input" && "image" === elem.type; + }, + + reset: function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && "reset" === elem.type; + }, + + button: function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && "button" === elem.type || name === "button"; + }, + + input: function( elem ) { + return (/input|select|textarea|button/i).test( elem.nodeName ); + }, + + focus: function( elem ) { + return elem === elem.ownerDocument.activeElement; + } + }, + setFilters: { + first: function( elem, i ) { + return i === 0; + }, + + last: function( elem, i, match, array ) { + return i === array.length - 1; + }, + + even: function( elem, i ) { + return i % 2 === 0; + }, + + odd: function( elem, i ) { + return i % 2 === 1; + }, + + lt: function( elem, i, match ) { + return i < match[3] - 0; + }, + + gt: function( elem, i, match ) { + return i > match[3] - 0; + }, + + nth: function( elem, i, match ) { + return match[3] - 0 === i; + }, + + eq: function( elem, i, match ) { + return match[3] - 0 === i; + } + }, + filter: { + PSEUDO: function( elem, match, i, array ) { + var name = match[1], + filter = Expr.filters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + + } else if ( name === "contains" ) { + return (elem.textContent || elem.innerText || Sizzle.getText([ elem ]) || "").indexOf(match[3]) >= 0; + + } else if ( name === "not" ) { + var not = match[3]; + + for ( var j = 0, l = not.length; j < l; j++ ) { + if ( not[j] === elem ) { + return false; + } + } + + return true; + + } else { + Sizzle.error( name ); + } + }, + + CHILD: function( elem, match ) { + var type = match[1], + node = elem; + + switch ( type ) { + case "only": + case "first": + while ( (node = node.previousSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + + if ( type === "first" ) { + return true; + } + + node = elem; + + case "last": + while ( (node = node.nextSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + + return true; + + case "nth": + var first = match[2], + last = match[3]; + + if ( first === 1 && last === 0 ) { + return true; + } + + var doneName = match[0], + parent = elem.parentNode; + + if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { + var count = 0; + + for ( node = parent.firstChild; node; node = node.nextSibling ) { + if ( node.nodeType === 1 ) { + node.nodeIndex = ++count; + } + } + + parent.sizcache = doneName; + } + + var diff = elem.nodeIndex - last; + + if ( first === 0 ) { + return diff === 0; + + } else { + return ( diff % first === 0 && diff / first >= 0 ); + } + } + }, + + ID: function( elem, match ) { + return elem.nodeType === 1 && elem.getAttribute("id") === match; + }, + + TAG: function( elem, match ) { + return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match; + }, + + CLASS: function( elem, match ) { + return (" " + (elem.className || elem.getAttribute("class")) + " ") + .indexOf( match ) > -1; + }, + + ATTR: function( elem, match ) { + var name = match[1], + result = Expr.attrHandle[ name ] ? + Expr.attrHandle[ name ]( elem ) : + elem[ name ] != null ? + elem[ name ] : + elem.getAttribute( name ), + value = result + "", + type = match[2], + check = match[4]; + + return result == null ? + type === "!=" : + type === "=" ? + value === check : + type === "*=" ? + value.indexOf(check) >= 0 : + type === "~=" ? + (" " + value + " ").indexOf(check) >= 0 : + !check ? + value && result !== false : + type === "!=" ? + value !== check : + type === "^=" ? + value.indexOf(check) === 0 : + type === "$=" ? + value.substr(value.length - check.length) === check : + type === "|=" ? + value === check || value.substr(0, check.length + 1) === check + "-" : + false; + }, + + POS: function( elem, match, i, array ) { + var name = match[2], + filter = Expr.setFilters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } + } + } +}; + +var origPOS = Expr.match.POS, + fescape = function(all, num){ + return "\\" + (num - 0 + 1); + }; + +for ( var type in Expr.match ) { + Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) ); + Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) ); +} + +var makeArray = function( array, results ) { + array = Array.prototype.slice.call( array, 0 ); + + if ( results ) { + results.push.apply( results, array ); + return results; + } + + return array; +}; + +// Perform a simple check to determine if the browser is capable of +// converting a NodeList to an array using builtin methods. +// Also verifies that the returned array holds DOM nodes +// (which is not the case in the Blackberry browser) +try { + Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType; + +// Provide a fallback method if it does not work +} catch( e ) { + makeArray = function( array, results ) { + var i = 0, + ret = results || []; + + if ( toString.call(array) === "[object Array]" ) { + Array.prototype.push.apply( ret, array ); + + } else { + if ( typeof array.length === "number" ) { + for ( var l = array.length; i < l; i++ ) { + ret.push( array[i] ); + } + + } else { + for ( ; array[i]; i++ ) { + ret.push( array[i] ); + } + } + } + + return ret; + }; +} + +var sortOrder, siblingCheck; + +if ( document.documentElement.compareDocumentPosition ) { + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { + return a.compareDocumentPosition ? -1 : 1; + } + + return a.compareDocumentPosition(b) & 4 ? -1 : 1; + }; + +} else { + sortOrder = function( a, b ) { + // The nodes are identical, we can exit early + if ( a === b ) { + hasDuplicate = true; + return 0; + + // Fallback to using sourceIndex (in IE) if it's available on both nodes + } else if ( a.sourceIndex && b.sourceIndex ) { + return a.sourceIndex - b.sourceIndex; + } + + var al, bl, + ap = [], + bp = [], + aup = a.parentNode, + bup = b.parentNode, + cur = aup; + + // If the nodes are siblings (or identical) we can do a quick check + if ( aup === bup ) { + return siblingCheck( a, b ); + + // If no parents were found then the nodes are disconnected + } else if ( !aup ) { + return -1; + + } else if ( !bup ) { + return 1; + } + + // Otherwise they're somewhere else in the tree so we need + // to build up a full list of the parentNodes for comparison + while ( cur ) { + ap.unshift( cur ); + cur = cur.parentNode; + } + + cur = bup; + + while ( cur ) { + bp.unshift( cur ); + cur = cur.parentNode; + } + + al = ap.length; + bl = bp.length; + + // Start walking down the tree looking for a discrepancy + for ( var i = 0; i < al && i < bl; i++ ) { + if ( ap[i] !== bp[i] ) { + return siblingCheck( ap[i], bp[i] ); + } + } + + // We ended someplace up the tree so do a sibling check + return i === al ? + siblingCheck( a, bp[i], -1 ) : + siblingCheck( ap[i], b, 1 ); + }; + + siblingCheck = function( a, b, ret ) { + if ( a === b ) { + return ret; + } + + var cur = a.nextSibling; + + while ( cur ) { + if ( cur === b ) { + return -1; + } + + cur = cur.nextSibling; + } + + return 1; + }; +} + +// Utility function for retreiving the text value of an array of DOM nodes +Sizzle.getText = function( elems ) { + var ret = "", elem; + + for ( var i = 0; elems[i]; i++ ) { + elem = elems[i]; + + // Get the text from text nodes and CDATA nodes + if ( elem.nodeType === 3 || elem.nodeType === 4 ) { + ret += elem.nodeValue; + + // Traverse everything else, except comment nodes + } else if ( elem.nodeType !== 8 ) { + ret += Sizzle.getText( elem.childNodes ); + } + } + + return ret; +}; + +// Check to see if the browser returns elements by name when +// querying by getElementById (and provide a workaround) +(function(){ + // We're going to inject a fake input element with a specified name + var form = document.createElement("div"), + id = "script" + (new Date()).getTime(), + root = document.documentElement; + + form.innerHTML = ""; + + // Inject it into the root element, check its status, and remove it quickly + root.insertBefore( form, root.firstChild ); + + // The workaround has to do additional checks after a getElementById + // Which slows things down for other browsers (hence the branching) + if ( document.getElementById( id ) ) { + Expr.find.ID = function( match, context, isXML ) { + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + + return m ? + m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? + [m] : + undefined : + []; + } + }; + + Expr.filter.ID = function( elem, match ) { + var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); + + return elem.nodeType === 1 && node && node.nodeValue === match; + }; + } + + root.removeChild( form ); + + // release memory in IE + root = form = null; +})(); + +(function(){ + // Check to see if the browser returns only elements + // when doing getElementsByTagName("*") + + // Create a fake element + var div = document.createElement("div"); + div.appendChild( document.createComment("") ); + + // Make sure no comments are found + if ( div.getElementsByTagName("*").length > 0 ) { + Expr.find.TAG = function( match, context ) { + var results = context.getElementsByTagName( match[1] ); + + // Filter out possible comments + if ( match[1] === "*" ) { + var tmp = []; + + for ( var i = 0; results[i]; i++ ) { + if ( results[i].nodeType === 1 ) { + tmp.push( results[i] ); + } + } + + results = tmp; + } + + return results; + }; + } + + // Check to see if an attribute returns normalized href attributes + div.innerHTML = ""; + + if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && + div.firstChild.getAttribute("href") !== "#" ) { + + Expr.attrHandle.href = function( elem ) { + return elem.getAttribute( "href", 2 ); + }; + } + + // release memory in IE + div = null; +})(); + +if ( document.querySelectorAll ) { + (function(){ + var oldSizzle = Sizzle, + div = document.createElement("div"), + id = "__sizzle__"; + + div.innerHTML = "

      "; + + // Safari can't handle uppercase or unicode characters when + // in quirks mode. + if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { + return; + } + + Sizzle = function( query, context, extra, seed ) { + context = context || document; + + // Only use querySelectorAll on non-XML documents + // (ID selectors don't work in non-HTML documents) + if ( !seed && !Sizzle.isXML(context) ) { + // See if we find a selector to speed up + var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query ); + + if ( match && (context.nodeType === 1 || context.nodeType === 9) ) { + // Speed-up: Sizzle("TAG") + if ( match[1] ) { + return makeArray( context.getElementsByTagName( query ), extra ); + + // Speed-up: Sizzle(".CLASS") + } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) { + return makeArray( context.getElementsByClassName( match[2] ), extra ); + } + } + + if ( context.nodeType === 9 ) { + // Speed-up: Sizzle("body") + // The body element only exists once, optimize finding it + if ( query === "body" && context.body ) { + return makeArray( [ context.body ], extra ); + + // Speed-up: Sizzle("#ID") + } else if ( match && match[3] ) { + var elem = context.getElementById( match[3] ); + + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id === match[3] ) { + return makeArray( [ elem ], extra ); + } + + } else { + return makeArray( [], extra ); + } + } + + try { + return makeArray( context.querySelectorAll(query), extra ); + } catch(qsaError) {} + + // qSA works strangely on Element-rooted queries + // We can work around this by specifying an extra ID on the root + // and working up from there (Thanks to Andrew Dupont for the technique) + // IE 8 doesn't work on object elements + } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { + var oldContext = context, + old = context.getAttribute( "id" ), + nid = old || id, + hasParent = context.parentNode, + relativeHierarchySelector = /^\s*[+~]/.test( query ); + + if ( !old ) { + context.setAttribute( "id", nid ); + } else { + nid = nid.replace( /'/g, "\\$&" ); + } + if ( relativeHierarchySelector && hasParent ) { + context = context.parentNode; + } + + try { + if ( !relativeHierarchySelector || hasParent ) { + return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra ); + } + + } catch(pseudoError) { + } finally { + if ( !old ) { + oldContext.removeAttribute( "id" ); + } + } + } + } + + return oldSizzle(query, context, extra, seed); + }; + + for ( var prop in oldSizzle ) { + Sizzle[ prop ] = oldSizzle[ prop ]; + } + + // release memory in IE + div = null; + })(); +} + +(function(){ + var html = document.documentElement, + matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector; + + if ( matches ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9 fails this) + var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ), + pseudoWorks = false; + + try { + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( document.documentElement, "[test!='']:sizzle" ); + + } catch( pseudoError ) { + pseudoWorks = true; + } + + Sizzle.matchesSelector = function( node, expr ) { + // Make sure that attribute selectors are quoted + expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']"); + + if ( !Sizzle.isXML( node ) ) { + try { + if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) { + var ret = matches.call( node, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || !disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9, so check for that + node.document && node.document.nodeType !== 11 ) { + return ret; + } + } + } catch(e) {} + } + + return Sizzle(expr, null, null, [node]).length > 0; + }; + } +})(); + +(function(){ + var div = document.createElement("div"); + + div.innerHTML = "
      "; + + // Opera can't find a second classname (in 9.6) + // Also, make sure that getElementsByClassName actually exists + if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { + return; + } + + // Safari caches class attributes, doesn't catch changes (in 3.2) + div.lastChild.className = "e"; + + if ( div.getElementsByClassName("e").length === 1 ) { + return; + } + + Expr.order.splice(1, 0, "CLASS"); + Expr.find.CLASS = function( match, context, isXML ) { + if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { + return context.getElementsByClassName(match[1]); + } + }; + + // release memory in IE + div = null; +})(); + +function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + + if ( elem ) { + var match = false; + + elem = elem[dir]; + + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 && !isXML ){ + elem.sizcache = doneName; + elem.sizset = i; + } + + if ( elem.nodeName.toLowerCase() === cur ) { + match = elem; + break; + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + + if ( elem ) { + var match = false; + + elem = elem[dir]; + + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 ) { + if ( !isXML ) { + elem.sizcache = doneName; + elem.sizset = i; + } + + if ( typeof cur !== "string" ) { + if ( elem === cur ) { + match = true; + break; + } + + } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { + match = elem; + break; + } + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +if ( document.documentElement.contains ) { + Sizzle.contains = function( a, b ) { + return a !== b && (a.contains ? a.contains(b) : true); + }; + +} else if ( document.documentElement.compareDocumentPosition ) { + Sizzle.contains = function( a, b ) { + return !!(a.compareDocumentPosition(b) & 16); + }; + +} else { + Sizzle.contains = function() { + return false; + }; +} + +Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement; + + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +var posProcess = function( selector, context ) { + var match, + tmpSet = [], + later = "", + root = context.nodeType ? [context] : context; + + // Position selectors must be done after the filter + // And so must :not(positional) so we move all PSEUDOs to the end + while ( (match = Expr.match.PSEUDO.exec( selector )) ) { + later += match[0]; + selector = selector.replace( Expr.match.PSEUDO, "" ); + } + + selector = Expr.relative[selector] ? selector + "*" : selector; + + for ( var i = 0, l = root.length; i < l; i++ ) { + Sizzle( selector, root[i], tmpSet ); + } + + return Sizzle.filter( later, tmpSet ); +}; + +// EXPOSE +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; +jQuery.expr[":"] = jQuery.expr.filters; +jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; + + +})(); + + +var runtil = /Until$/, + rparentsprev = /^(?:parents|prevUntil|prevAll)/, + // Note: This RegExp should be improved, or likely pulled from Sizzle + rmultiselector = /,/, + isSimple = /^.[^:#\[\.,]*$/, + slice = Array.prototype.slice, + POS = jQuery.expr.match.POS, + // methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend({ + find: function( selector ) { + var self = this, + i, l; + + if ( typeof selector !== "string" ) { + return jQuery( selector ).filter(function() { + for ( i = 0, l = self.length; i < l; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + }); + } + + var ret = this.pushStack( "", "find", selector ), + length, n, r; + + for ( i = 0, l = this.length; i < l; i++ ) { + length = ret.length; + jQuery.find( selector, this[i], ret ); + + if ( i > 0 ) { + // Make sure that the results are unique + for ( n = length; n < ret.length; n++ ) { + for ( r = 0; r < length; r++ ) { + if ( ret[r] === ret[n] ) { + ret.splice(n--, 1); + break; + } + } + } + } + } + + return ret; + }, + + has: function( target ) { + var targets = jQuery( target ); + return this.filter(function() { + for ( var i = 0, l = targets.length; i < l; i++ ) { + if ( jQuery.contains( this, targets[i] ) ) { + return true; + } + } + }); + }, + + not: function( selector ) { + return this.pushStack( winnow(this, selector, false), "not", selector); + }, + + filter: function( selector ) { + return this.pushStack( winnow(this, selector, true), "filter", selector ); + }, + + is: function( selector ) { + return !!selector && ( typeof selector === "string" ? + jQuery.filter( selector, this ).length > 0 : + this.filter( selector ).length > 0 ); + }, + + closest: function( selectors, context ) { + var ret = [], i, l, cur = this[0]; + + // Array + if ( jQuery.isArray( selectors ) ) { + var match, selector, + matches = {}, + level = 1; + + if ( cur && selectors.length ) { + for ( i = 0, l = selectors.length; i < l; i++ ) { + selector = selectors[i]; + + if ( !matches[ selector ] ) { + matches[ selector ] = POS.test( selector ) ? + jQuery( selector, context || this.context ) : + selector; + } + } + + while ( cur && cur.ownerDocument && cur !== context ) { + for ( selector in matches ) { + match = matches[ selector ]; + + if ( match.jquery ? match.index( cur ) > -1 : jQuery( cur ).is( match ) ) { + ret.push({ selector: selector, elem: cur, level: level }); + } + } + + cur = cur.parentNode; + level++; + } + } + + return ret; + } + + // String + var pos = POS.test( selectors ) || typeof selectors !== "string" ? + jQuery( selectors, context || this.context ) : + 0; + + for ( i = 0, l = this.length; i < l; i++ ) { + cur = this[i]; + + while ( cur ) { + if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { + ret.push( cur ); + break; + + } else { + cur = cur.parentNode; + if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) { + break; + } + } + } + } + + ret = ret.length > 1 ? jQuery.unique( ret ) : ret; + + return this.pushStack( ret, "closest", selectors ); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1; + } + + // index in selector + if ( typeof elem === "string" ) { + return jQuery.inArray( this[0], jQuery( elem ) ); + } + + // Locate the position of the desired element + return jQuery.inArray( + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[0] : elem, this ); + }, + + add: function( selector, context ) { + var set = typeof selector === "string" ? + jQuery( selector, context ) : + jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), + all = jQuery.merge( this.get(), set ); + + return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? + all : + jQuery.unique( all ) ); + }, + + andSelf: function() { + return this.add( this.prevObject ); + } +}); + +// A painfully simple check to see if an element is disconnected +// from a document (should be improved, where feasible). +function isDisconnected( node ) { + return !node || !node.parentNode || node.parentNode.nodeType === 11; +} + +jQuery.each({ + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return jQuery.dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return jQuery.dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return jQuery.nth( elem, 2, "nextSibling" ); + }, + prev: function( elem ) { + return jQuery.nth( elem, 2, "previousSibling" ); + }, + nextAll: function( elem ) { + return jQuery.dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return jQuery.dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return jQuery.dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return jQuery.dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return jQuery.sibling( elem.parentNode.firstChild, elem ); + }, + children: function( elem ) { + return jQuery.sibling( elem.firstChild ); + }, + contents: function( elem ) { + return jQuery.nodeName( elem, "iframe" ) ? + elem.contentDocument || elem.contentWindow.document : + jQuery.makeArray( elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var ret = jQuery.map( this, fn, until ), + // The variable 'args' was introduced in + // https://github.com/jquery/jquery/commit/52a0238 + // to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed. + // http://code.google.com/p/v8/issues/detail?id=1050 + args = slice.call(arguments); + + if ( !runtil.test( name ) ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + ret = jQuery.filter( selector, ret ); + } + + ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; + + if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { + ret = ret.reverse(); + } + + return this.pushStack( ret, name, args.join(",") ); + }; +}); + +jQuery.extend({ + filter: function( expr, elems, not ) { + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return elems.length === 1 ? + jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : + jQuery.find.matches(expr, elems); + }, + + dir: function( elem, dir, until ) { + var matched = [], + cur = elem[ dir ]; + + while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { + if ( cur.nodeType === 1 ) { + matched.push( cur ); + } + cur = cur[dir]; + } + return matched; + }, + + nth: function( cur, result, dir, elem ) { + result = result || 1; + var num = 0; + + for ( ; cur; cur = cur[dir] ) { + if ( cur.nodeType === 1 && ++num === result ) { + break; + } + } + + return cur; + }, + + sibling: function( n, elem ) { + var r = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + r.push( n ); + } + } + + return r; + } +}); + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, keep ) { + + // Can't pass null or undefined to indexOf in Firefox 4 + // Set to 0 to skip string check + qualifier = qualifier || 0; + + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep(elements, function( elem, i ) { + var retVal = !!qualifier.call( elem, i, elem ); + return retVal === keep; + }); + + } else if ( qualifier.nodeType ) { + return jQuery.grep(elements, function( elem, i ) { + return (elem === qualifier) === keep; + }); + + } else if ( typeof qualifier === "string" ) { + var filtered = jQuery.grep(elements, function( elem ) { + return elem.nodeType === 1; + }); + + if ( isSimple.test( qualifier ) ) { + return jQuery.filter(qualifier, filtered, !keep); + } else { + qualifier = jQuery.filter( qualifier, filtered ); + } + } + + return jQuery.grep(elements, function( elem, i ) { + return (jQuery.inArray( elem, qualifier ) >= 0) === keep; + }); +} + + + + +var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, + rleadingWhitespace = /^\s+/, + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, + rtagName = /<([\w:]+)/, + rtbody = /", "" ], + legend: [ 1, "
      ", "
      " ], + thead: [ 1, "", "
      " ], + tr: [ 2, "", "
      " ], + td: [ 3, "", "
      " ], + col: [ 2, "", "
      " ], + area: [ 1, "", "" ], + _default: [ 0, "", "" ] + }; + +wrapMap.optgroup = wrapMap.option; +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// IE can't serialize and "; + + if (top == self) { + document.body.insertAdjacentHTML("beforeend", + ""); + document.frames["nav"].document.open(); + document.frames["nav"].document.write(str); + document.frames["nav"].document.close(); + } + + this.iframe = document.frames["nav"];// : document.getElementById("nav").contentWindow; + //Check to see if url has been manually changed + this.timer2 = setInterval(function(){ + if (!apf.history.changingHash && location.hash != "#" + apf.history.tab) { + var name = location.hash.replace(/^#/, ""); + var tab = apf.history.tab; + apf.history.setHash(name, true, true); + apf.history.tab = tab; + apf.history.hasChanged(name); + } + }, apf.history.delay || 1); + } + else { + preInit(); + apf.history.lastUrl = location.href.toString(); + this.timer2 = setInterval(function(){ + if (apf.history.lastUrl == location.href.toString()) + return; + + apf.history.lastUrl = location.href.toString(); + //var tab = location.href.replace(/^.*#(.*)$/, "$1") + var tab = location.hash.replace("#", "");//.replace(/^.*#(.*)$/,"$1"); + apf.history.hasChanged(decodeURI(tab)); + }, 20); + } + }, + to_name: null, + + /** + * Sets the hash value of the location bar in the browser. This is used + * to represent the state of the application for use by the back and forward + * buttons, as well as for use when bookmarking or sharing URLs. + * @param {String} name The new hash value + * @param {Boolean} timed Whether to add a delay to setting the value + * @param {Boolean} force Forces the change to overwrite any existing value + */ + setHash: function(name, timed, force) { + if (this.changing || this.tab == name || !force + && decodeURIComponent(location.hash) == "#" + decodeURIComponent(name)) { + this.to_name = name; + return; + } + + if (!apf.supportHashChange && apf.isIE && !timed) { + this.to_name = name; + return $setTimeout(function(){ + apf.history.setHash(apf.history.to_name, true, force); + }, 200); + } + + this.changePage(name); + if (!this.inited) + return this.init(name); + + if (!apf.supportHashChange && apf.isIE) { + var h = this.iframe.document.body + .appendChild(this.iframe.document.createElement('h1')); + h.id = name; + h.innerHTML = "1"; + } + + (!apf.supportHashChange && apf.isIE ? this.iframe : window).location.href = "#" + name; + + if (!apf.isIE && !apf.isGecko && !apf.isIphone) + apf.history.lastUrl = location.href.toString(); + //else if (apf.isIE8) + }, + + timer: null, + changePage: function(tab, force) { + if (!apf.supportHashChange && apf.isIE) { + this.tab = tab; + this.changingHash = true; + clearTimeout(this.timer); + this.timer = $setTimeout(function(){ + location.hash = tab; + apf.history.changingHash = false; + }, 1); + } + }, + + update: function(tab) { + var i, l, idx = 0; + + // check past: + for (i = 0, l = this.past.length; i < l && idx === 0; i++) { + if (this.past[i] == tab) + idx = i + 1; + } + if (idx > 0) { + // part of past up till tab (Array.slice), EXCLUDING tab + this.future = this.past.slice(idx, this.past.length - 1) + .concat(this.future).makeUnique(); + this.past.splice(idx, this.past.length - (idx)); + idx = -idx; + } + else { + // check future: + for (i = 0, l = this.future.length; i < l && idx === 0; i++) { + if (this.future[i] == tab) { + idx = i + 1; + // current past + part of the future up till tab + // (Array.splice), INCLUDING tab + this.past = this.past.concat(this.future + .splice(0, this.future.length - idx)).makeUnique(); + } + } + if (idx === 0) { + this.past.push(tab); + idx = 1; + } + } + + return idx; + }, + + hasChanged: function(tab, force) { + if (tab == this.tab && !force) + return; + this.changePage(tab, force); + + this.changing = true; + if (apf.dispatchEvent("hashchange", { + oldURL: this.tab, + newURL: tab, + tab: tab, + index: this.update(tab) + }) === false) { + tab = location.hash = this.tab; + }; + this.changing = false; + + this.tab = tab; + } +}; + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +apf.config = new apf.Class().$init(); +apf.extend(apf.config, { + //Defaults + disableRightClick: false, + allowSelect: false, + allowBlur: true, + autoDisableActions: true, + autoDisable: false, /** @todo fix this to only autodisable when createmodel is not true */ + disableF5 : true, + autoHideLoading: true, + disableSpace: true, + defaultPage: "home", + disableBackspace: true, + undokeys: false, + outline: false, + dragOutline: false, + resizeOutline: false, + autoDisableNavKeys: true, + disableTabbing: false, + resourcePath: null, + initdelay: true, + liveText: false, + + + + skinset: "default", + name: apf.isO3 ? "o3App" : self.window && window.location.href.replace(/[^0-9A-Za-z_]/g, "_"), + + tags: {}, + defaults: {}, + baseurl: "", + + "empty-message" : "No items", + "loading-message" : "Loading...", + "offline-message" : "You are currently offline.", + + setDefaults: function(){ + + }, + + getDefault: function(type, prop) { + var d = this.defaults[type]; + if (!d) + return; + + for (var i = d.length - 1; i >= 0; i--) { + if (d[i][0] == prop) + return d[i][1]; + } + }, + + $handlePropSet: function(name, value) { + //this[name] = value; + //@todo I dont want to go through all the code again, maybe later + this[name.replace(/-(\w)/g, function(m, m1) { + return m1.toUpperCase() + })] = this[name] = value; + + (this.$propHandlers && this.$propHandlers[name] + || apf.GuiElement.propHandlers[name] || apf.K).call(this, value); + }, + + $inheritProperties: {}, + + $propHandlers: { + "baseurl" : function(value) { + this.baseurl = apf.parseExpression(value); + }, + "language" : function(value) { + + }, + "resource-path" : function(value) { + this.resourcePath = apf.parseExpression(value || "") + .replace(/resources\/?|\/$/g, ''); + }, + + + "skinset" : function(value) { + if (this.$amlLoaded) + apf.skins.changeSkinset(value); + }, + + + "outline" : function(value) { + this.dragOutline = + this.resizeOutline = + this.outline = apf.isTrue(value); + }, + "drag-outline" : function(value) { + this.dragOutline = value + ? apf.isTrue(value) + : false; + }, + "resize-outline" : function(value) { + this.resizeOutline = value + ? !apf.isFalse(value) + : false; + }, + + + "login" : function(value, x) { + apf.auth.init(x); + }, + + + + + + "debug" : function(value) { + + apf.debug = value; + } + } +}); + + +if (apf.history) + apf.addEventListener("load", function(){ + apf.history.init(apf.config.defaultPage, "tab"); + }); + + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +apf.offline = { + onLine: true +}; + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + +/** + * Stores data using a {@link term.datainstruction data instruction}. + * + * + * @param {String} instruction The {@link term.datainstruction data instruction} to be used to store the data. + * @param {Object} [options] The options for this instruction. Available properties include: + * - multicall ([[Boolean]]): Whether this call should not be executed immediately, but saved for later sending using the `purge()` command + * - userdata (`Mixed`): Any data that is useful to access in the callback function + * - args ([[Array]]): The arguments of the call, overriding any specified in the data instruction + * - [xmlContext] ([[XMLElement]]): The subject of the xpath queries + * - [callback] ([[Function]]): The code that is executed when the call returns, either successfully or not + * {: #saveDataOptions} + */ +apf.saveData = + +/** + * Retrieves data using a {@link term.datainstruction data instruction}. + * + * #### Example + * + * Here are several uses for data instructions: + * + * ```xml + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * ``` + * + * @method getData + * @param {String} instruction The {@link term.datainstruction data instruction} to be used to retrieve the data. + * @param {XMLElement} [xmlContext] The subject of the xpath queries + * @param {Object} [options] The options for this instruction. Available properties include: + * - multicall ([[Boolean]]): Whether this call should not be executed immediately, but saved for later sending using the `purge()` command + * - userdata (`Mixed`): Any data that is useful to access in the callback function + * - args ([[Array]]): The arguments of the call, overriding any specified in the data instruction + * - [xmlContext] ([[XMLElement]]): The subject of the xpath queries + * - [callback] ([[Function]]): The code that is executed when the call returns, either successfully or not + * @param {Function} [callback] The code that is executed when the call returns, either successfully or not + */ +apf.getData = function(instruction, options) { + if (!instruction) return false; + + //Instruction type detection + var result, chr = instruction.charAt(0), callback = options.callback; + + + var gCallback = + + + function(data, state, extra) { + var callback = options.callback + + if (state != apf.SUCCESS) + return callback(data, state, extra || {}); + + //Change this to warning? + /*if (!data) { + throw new Error(apf.formatErrorString(0, null, + "Loading new data", "Could not load data. \n\ + Data instruction: '" + instruction + "'")); + }*/ + + return callback(data, state, extra || {}); + } + + if (!options) options = {}; //@todo optimize? + var fParsed = options.fParsed || (instruction.indexOf("{") > -1 || instruction.indexOf("[") > -1 + ? apf.lm.compile(instruction, { + withopt: true, + precall: options.precall, + alwayscb: true, + simplexpath: true + }) + : {str: instruction, type: 2}); + + if (options.precall && !options._pc) { + options.asyncs = fParsed.asyncs; + options._pc = 1; + } + + //@todo hack because we're not using compileNode.. an imperfection.. + if (fParsed.type == 3) { + if (fParsed.xpaths[0]) { + var model = fParsed.xpaths[0], xpath = fParsed.xpaths[1]; + + //@todo can this be async? + if (model == "#" || xpath == "#") { //When there is a set model and not a generated xpath + var m = (apf.lm.compile(instruction, { + xpathmode: 5 + }))(); + + //@todo apf3 this needs to be fixed in live markup + if (typeof m != "string") { + model = m.model && m.model.$isModel && m.model; + if (model) + xpath = m.xpath; + else if (m.model) { + model = apf.xmldb.findModel(m.model); + xpath = apf.xmlToXpath(m.model, model.data) + (m.xpath ? "/" + m.xpath : ""); //@todo make this better + } + else { + //Model is not yet available. When it comes available we will be recalled (at least for prop binds) + return; + } + } + else model = null; + } + else { + + model = apf.nameserver.get("model", model) + + } + + + + return gCallback(model.data.selectSingleNode(xpath), apf.SUCCESS, {}); + } + else { + + + return gCallback(options.xmlNode.data.selectSingleNode(fParsed.xpaths[1]), apf.SUCCESS, {}); + } + } + + //xml generation + if (chr == "<") { + //string only + if (fParsed.type == 2) + result = fParsed.str; + else + return fParsed(options.xmlNode, gCallback, options); + } + //jslt fetching data + else if ((chr == "[" || chr == "{")) { //(fParsed.asyncs || fParsed.models) && + return fParsed(options.xmlNode, gCallback, options); + } + //url + else { + if (fParsed.type == 1 || fParsed.type == 3) { + var callback2 = callback; + callback = options.callback = function(data, state, extra) { + if (options._pc === true) + return; + + if (state != apf.SUCCESS) + return callback2.apply(this, arguments); + + var url = data.split(" "), method = "get"; + if (url.length > 1 && url[0].length < 10) { + method = url.shift(); + url = url.join(" "); + } + else url = data; + + callback = options.callback = callback2; + apf.oHttp.exec(method, [url], gCallback, options); + } + fParsed(options.xmlNode, gCallback, options); + } + else { + if (options._pc === true) + return; + + var url = instruction.split(" "), method = "get"; + if (url.length > 1 && url[0].length < 10) { + method = url.shift(); + url = url.join(" "); + } + else { + url = instruction; + } + + apf.oHttp.exec(method, [url.replace(/\\/g, "")], gCallback, options); + } + } + + if (result) { + if (callback) + gCallback(result, apf.SUCCESS, {}); + else { + //apf.console.warn("Returning data directly in apf.getData(). \ + //This means that all callback communication ends in void!"); + return result; + } + } +}; + + +/** + * Creates a model object based on a {@link term.datainstruction data instruction}. + * + * @param {String} instruction The {@link term.datainstruction data instruction} to be used to retrieve the data for the model + * @param {apf.AmlNode} amlNode The element the model is added to + */ +apf.setModel = function(instruction, amlNode) { + if (!instruction) return; + + //Find existing model + var fParsed = instruction.indexOf("{") > -1 || instruction.indexOf("[") > -1 + ? apf.lm.compile(instruction, { + //precall : false, + alwayscb: true + }) + : { + type: 2, + str: instruction + }; + + if (instruction == "@default" || fParsed.type == 2) { + + var model = apf.nameserver.get("model", instruction); + if (model) + return model.register(amlNode); + else + + if (instruction == "@default") + return; + + //@todo apf3.0 check here if string is valid url (relative or absolute) + if (instruction.indexOf(".") == -1 && instruction.indexOf("/") == -1) { + + return; + } + } + + //Just an xpath doesnt work. We don't have context + //var l, x; + if (fParsed.type == 3) {//This won't work for complex xpaths + if (fParsed.models) { //check for # in xpaths[i] to determine if its calculated + if (fParsed.xpaths.length == 2 && fParsed.xpaths[0] != '#' && fParsed.xpaths [1] != '#') { + + + + apf.nameserver.get("model", fParsed.xpaths[0]).register(amlNode, fParsed.xpaths[1]); + + return; + } + } + + } + + if (amlNode.clear) + amlNode.clear("loading"); + + //Complex data fetch (possibly async) - data is loaded only once. + //Potential property binding has to take of the rest + apf.getData(instruction, { + parsed: fParsed, + xmlNode: amlNode && amlNode.xmlRoot, + callback: function(data, state, extra) { + //@todo apf3.0 call onerror on amlNode + if (state != apf.SUCCESS) { + throw new Error(apf.formatErrorString(0, null, + "Loading new data", "Could not load data into model. \ + \nMessage: " + extra.message + "\ + \nInstruction: '" + instruction + "'")); + } + + if (!data) + return amlNode.clear && amlNode.clear(); + + if (typeof data == "string") { + if (data.charAt(0) == "<") + data = apf.getXml(data); + else { + //Assuming web service returned url + if (data.indexOf("http://") == 0) + return apf.setModel(data, amlNode); + else { + throw new Error("Invalid data from server");//@todo apf3.0 make proper apf error handling. apf.onerror + } + } + } + + if (data.nodeFunc) { //Assuming a model was passed -- data.localName == "model" && + data.register(amlNode); + return; + } + + var model = apf.xmldb.findModel(data); //See if data is already loaded into a model + if (model) + model.register(amlNode, apf.xmlToXpath(data, model.data)); //@todo move function to xml library + else + new apf.model().register(amlNode).load(data); + }}); +}; + + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + +/* + * @version: 1.0 Alpha-1 + * @author: Coolite Inc. http://www.coolite.com/ + * @date: 2008-04-13 + * @copyright: Copyright (c) 2006-2008, Coolite Inc. (http://www.coolite.com/). All rights reserved. + * @license: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/. + * @website: http://www.datejs.com/ + */ + +(function () { + var $C = { + /* Culture Name */ + name: "en-US", + englishName: "English (United States)", + nativeName: "English (United States)", + + /* Day Name Strings */ + dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], + abbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], + shortestDayNames: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"], + firstLetterDayNames: ["S", "M", "T", "W", "T", "F", "S"], + + /* Month Name Strings */ + monthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], + abbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], + + /* AM/PM Designators */ + amDesignator: "AM", + pmDesignator: "PM", + + firstDayOfWeek: 0, + twoDigitYearMax: 2029, + + /** + * The dateElementOrder is based on the order of the + * format specifiers in the formatPatterns.DatePattern. + * + * Example: +
      +         shortDatePattern    dateElementOrder
      +         ------------------  ---------------- 
      +         "M/d/yyyy"          "mdy"
      +         "dd/MM/yyyy"        "dmy"
      +         "yyyy-MM-dd"        "ymd"
      +         
      + * + * The correct dateElementOrder is required by the parser to + * determine the expected order of the date elements in the + * string being parsed. + */ + dateElementOrder: "mdy", + + /* Standard date and time format patterns */ + formatPatterns: { + shortDate: "M/d/yyyy", + longDate: "dddd, MMMM dd, yyyy", + shortTime: "h:mm tt", + longTime: "h:mm:ss tt", + fullDateTime: "dddd, MMMM dd, yyyy h:mm:ss tt", + sortableDateTime: "yyyy-MM-ddTHH:mm:ss", + universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ", + rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT", + monthDay: "MMMM dd", + yearMonth: "MMMM, yyyy" + }, + + /** + * NOTE: If a string format is not parsing correctly, but + * you would expect it parse, the problem likely lies below. + * + * The following regex patterns control most of the string matching + * within the parser. + * + * The Month name and Day name patterns were automatically generated + * and in general should be (mostly) correct. + * + * Beyond the month and day name patterns are natural language strings. + * Example: "next", "today", "months" + * + * These natural language string may NOT be correct for this culture. + * If they are not correct, please translate and edit this file + * providing the correct regular expression pattern. + * + * If you modify this file, please post your revised CultureInfo file + * to the Datejs Forum located at http://www.datejs.com/forums/. + * + * Please mark the subject of the post with [CultureInfo]. Example: + * Subject: [CultureInfo] Translated "da-DK" Danish(Denmark) + * + * We will add the modified patterns to the master source files. + * + * As well, please review the list of "Future Strings" section below. + */ + regexPatterns: { + jan: /^jan(uary)?/i, + feb: /^feb(ruary)?/i, + mar: /^mar(ch)?/i, + apr: /^apr(il)?/i, + may: /^may/i, + jun: /^jun(e)?/i, + jul: /^jul(y)?/i, + aug: /^aug(ust)?/i, + sep: /^sep(t(ember)?)?/i, + oct: /^oct(ober)?/i, + nov: /^nov(ember)?/i, + dec: /^dec(ember)?/i, + + sun: /^su(n(day)?)?/i, + mon: /^mo(n(day)?)?/i, + tue: /^tu(e(s(day)?)?)?/i, + wed: /^we(d(nesday)?)?/i, + thu: /^th(u(r(s(day)?)?)?)?/i, + fri: /^fr(i(day)?)?/i, + sat: /^sa(t(urday)?)?/i, + + future: /^next/i, + past: /^last|past|prev(ious)?/i, + add: /^(\+|aft(er)?|from|hence)/i, + subtract: /^(\-|bef(ore)?|ago)/i, + + yesterday: /^yes(terday)?/i, + today: /^t(od(ay)?)?/i, + tomorrow: /^tom(orrow)?/i, + now: /^n(ow)?/i, + + millisecond: /^ms|milli(second)?s?/i, + second: /^sec(ond)?s?/i, + minute: /^mn|min(ute)?s?/i, + hour: /^h(our)?s?/i, + week: /^w(eek)?s?/i, + month: /^m(onth)?s?/i, + day: /^d(ay)?s?/i, + year: /^y(ear)?s?/i, + + shortMeridian: /^(a|p)/i, + longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i, + timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i, + ordinalSuffix: /^\s*(st|nd|rd|th)/i, + timeContext: /^\s*(\:|a(?!u|p)|p)/i + }, + + timezones: [ + {name:"UTC", offset:"-000"}, + {name:"GMT", offset:"-000"}, + {name:"EST", offset:"-0500"}, + {name:"EDT", offset:"-0400"}, + {name:"CST", offset:"-0600"}, + {name:"CDT", offset:"-0500"}, + {name:"MST", offset:"-0700"}, + {name:"MDT", offset:"-0600"}, + {name:"PST", offset:"-0800"}, + {name:"PDT", offset:"-0700"} + ] + }; + + var $D = Date, + $P = $D.prototype, + p = function(s, l) { + if (!l) + l = 2; + return ("000" + s).slice(l * -1); + }; + + /** + * Resets the time of this Date object to 12:00 AM (00:00), which is the + * start of the day. + * @return {Date} this + */ + $P.clearTime = function() { + this.setHours(0); + this.setMinutes(0); + this.setSeconds(0); + this.setMilliseconds(0); + return this; + }; + + /** + * Resets the time of this Date object to the current time ('now'). + * @return {Date} this + */ + $P.setTimeToNow = function() { + var n = new Date(); + this.setHours(n.getHours()); + this.setMinutes(n.getMinutes()); + this.setSeconds(n.getSeconds()); + this.setMilliseconds(n.getMilliseconds()); + return this; + }; + + /** + * Gets a date that is set to the current date. The time is set to the start + * of the day (00:00 or 12:00 AM). + * @return {Date} The current date. + */ + $D.today = function() { + return new Date().clearTime(); + }; + + /** + * Compares the first date to the second date and returns an number indication + * of their relative values. + * @param {Date} First Date object to compare [Required]. + * @param {Date} Second Date object to compare to [Required]. + * @return {Number} -1 = date1 is lessthan date2. 0 = values are equal. + * 1 = date1 is greaterthan date2. + */ + $D.compare = function(date1, date2) { + if (isNaN(date1) || isNaN(date2)) + throw new Error(date1 + " - " + date2); + else if (date1 instanceof Date && date2 instanceof Date) + return (date1 < date2) ? -1 : (date1 > date2) ? 1 : 0; + else + throw new TypeError(date1 + " - " + date2); + }; + + /** + * Compares the first Date object to the second Date object and returns true + * if they are equal. + * @param {Date} First Date object to compare [Required] + * @param {Date} Second Date object to compare to [Required] + * @return {Boolean} true if dates are equal. false if they are not equal. + */ + $D.equals = function(date1, date2) { + return (date1.compareTo(date2) === 0); + }; + + /** + * Gets the day number (0-6) if given a CultureInfo specific string which is + * a valid dayName, abbreviatedDayName or shortestDayName (two char). + * @param {String} The name of the day (eg. "Monday, "Mon", "tuesday", "tue", "We", "we"). + * @return {Number} The day number + */ + $D.getDayNumberFromName = function(name) { + var n = $C.dayNames, + m = $C.abbreviatedDayNames, + o = $C.shortestDayNames, + s = name.toLowerCase(); + for (var i = 0; i < n.length; i++) { + if (n[i].toLowerCase() == s || m[i].toLowerCase() == s || o[i].toLowerCase() == s) + return i; + } + return -1; + }; + + /** + * Gets the month number (0-11) if given a Culture Info specific string which + * is a valid monthName or abbreviatedMonthName. + * @param {String} The name of the month (eg. "February, "Feb", "october", "oct"). + * @return {Number} The day number + */ + $D.getMonthNumberFromName = function(name) { + var n = $C.monthNames, + m = $C.abbreviatedMonthNames, + s = name.toLowerCase(); + for (var i = 0; i < n.length; i++) { + if (n[i].toLowerCase() == s || m[i].toLowerCase() == s) + return i; + } + return -1; + }; + + /** + * Determines if the current date instance is within a LeapYear. + * @param {Number} The year. + * @return {Boolean} true if date is within a LeapYear, otherwise false. + */ + $D.isLeapYear = function(year) { + return ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0); + }; + + /** + * Gets the number of days in the month, given a year and month value. + * Automatically corrects for LeapYear. + * @param {Number} The year. + * @param {Number} The month (0-11). + * @return {Number} The number of days in the month. + */ + $D.getDaysInMonth = function(year, month) { + return [31, ($D.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]; + }; + + $D.getTimezoneAbbreviation = function(offset) { + var z = $C.timezones, p; + for (var i = 0; i < z.length; i++) { + if (z[i].offset === offset) + return z[i].name; + } + return null; + }; + + $D.getTimezoneOffset = function(name) { + var z = $C.timezones, p; + for (var i = 0; i < z.length; i++) { + if (z[i].name === name.toUpperCase()) + return z[i].offset; + } + return null; + }; + + /** + * Returns a new Date object that is an exact date and time copy of the + * original instance. + * @return {Date} A new Date instance + */ + $P.clone = function() { + return new Date(this.getTime()); + }; + + /** + * Compares this instance to a Date object and returns an number indication + * of their relative values. + * @param {Date} Date object to compare [Required] + * @return {Number} -1 = this is lessthan date. 0 = values are equal. + * 1 = this is greaterthan date. + */ + $P.compareTo = function(date) { + return Date.compare(this, date); + }; + + /** + * Compares this instance to another Date object and returns true if they are equal. + * @param {Date} Date object to compare. If no date to compare, new Date() + * [now] is used. + * @return {Boolean} true if dates are equal. false if they are not equal. + */ + $P.equals = function(date) { + return Date.equals(this, date || new Date()); + }; + + /** + * Determines if this instance is between a range of two dates or equal to + * either the start or end dates. + * @param {Date} Start of range [Required] + * @param {Date} End of range [Required] + * @return {Boolean} true is this is between or equal to the start and end + * dates, else false + */ + $P.between = function(start, end) { + return this.getTime() >= start.getTime() && this.getTime() <= end.getTime(); + }; + + /** + * Determines if this date occurs after the date to compare to. + * @param {Date} Date object to compare. If no date to compare, new Date() + * ("now") is used. + * @return {Boolean} true if this date instance is greater than the date to + * compare to (or "now"), otherwise false. + */ + $P.isAfter = function(date) { + return this.compareTo(date || new Date()) === 1; + }; + + /** + * Determines if this date occurs before the date to compare to. + * @param {Date} Date object to compare. If no date to compare, new Date() + * ("now") is used. + * @return {Boolean} true if this date instance is less than the date to + * compare to (or "now"). + */ + $P.isBefore = function(date) { + return (this.compareTo(date || new Date()) === -1); + }; + + /** + * Determines if the current Date instance occurs on the same Date as the supplied 'date'. + * If no 'date' to compare to is provided, the current Date instance is compared to 'today'. + * @param {Date} Date object to compare. If no date to compare, the current Date ("now") is used. + * @return {Boolean} true if this Date instance occurs on the same Day as the supplied 'date'. + */ + $P.isToday = $P.isSameDay = function(date) { + return this.clone().clearTime().equals((date || new Date()).clone().clearTime()); + }; + + /** + * Adds the specified number of milliseconds to this instance. + * @param {Number} The number of milliseconds to add. The number can be + * positive or negative [Required] + * @return {Date} this + */ + $P.addMilliseconds = function(value) { + this.setMilliseconds(this.getMilliseconds() + value * 1); + return this; + }; + + /** + * Adds the specified number of seconds to this instance. + * @param {Number} The number of seconds to add. The number can be positive + * or negative [Required] + * @return {Date} this + */ + $P.addSeconds = function(value) { + return this.addMilliseconds(value * 1000); + }; + + /** + * Adds the specified number of seconds to this instance. + * @param {Number} The number of seconds to add. The number can be positive + * or negative [Required] + * @return {Date} this + */ + $P.addMinutes = function(value) { + return this.addMilliseconds(value * 60000); /* 60*1000 */ + }; + + /** + * Adds the specified number of hours to this instance. + * @param {Number} The number of hours to add. The number can be positive + * or negative [Required] + * @return {Date} this + */ + $P.addHours = function(value) { + return this.addMilliseconds(value * 3600000); /* 60*60*1000 */ + }; + + /** + * Adds the specified number of days to this instance. + * @param {Number} The number of days to add. The number can be positive + * or negative [Required] + * @return {Date} this + */ + $P.addDays = function(value) { + this.setDate(this.getDate() + value * 1); + return this; + }; + + /** + * Adds the specified number of weeks to this instance. + * @param {Number} The number of weeks to add. The number can be positive + * or negative [Required] + * @return {Date} this + */ + $P.addWeeks = function(value) { + return this.addDays(value * 7); + }; + + /** + * Adds the specified number of months to this instance. + * @param {Number} The number of months to add. The number can be positive + * or negative [Required] + * @return {Date} this + */ + $P.addMonths = function(value) { + var n = this.getDate(); + this.setDate(1); + this.setMonth(this.getMonth() + value * 1); + this.setDate(Math.min(n, $D.getDaysInMonth(this.getFullYear(), this.getMonth()))); + return this; + }; + + /** + * Adds the specified number of years to this instance. + * @param {Number} The number of years to add. The number can be positive + * or negative [Required] + * @return {Date} this + */ + $P.addYears = function(value) { + return this.addMonths(value * 12); + }; + + /** + * Adds (or subtracts) to the value of the years, months, weeks, days, hours, + * minutes, seconds, milliseconds of the date instance using given configuration + * object. Positive and Negative values allowed. + * Example +
      
      +    Date.today().add( { days: 1, months: 1 } )
      +     
      +    new Date().add( { years: -1 } )
      +    
      + * @param {Object} Configuration object containing attributes (months, days, etc.) + * @return {Date} this + */ + $P.add = function(config) { + if (typeof config == "number") { + this._orient = config; + return this; + } + + var x = config; + + if (x.milliseconds) + this.addMilliseconds(x.milliseconds); + if (x.seconds) + this.addSeconds(x.seconds); + if (x.minutes) + this.addMinutes(x.minutes); + if (x.hours) + this.addHours(x.hours); + if (x.weeks) + this.addWeeks(x.weeks); + if (x.months) + this.addMonths(x.months); + if (x.years) + this.addYears(x.years); + if (x.days) + this.addDays(x.days); + return this; + }; + + var $y, $m, $d; + + /** + * Get the week number. Week one (1) is the week which contains the first + * Thursday of the year. Monday is considered the first day of the week. + * This algorithm is a JavaScript port of the work presented by Claus + * Tøndering at http://www.tondering.dk/claus/cal/node8.html#SECTION00880000000000000000 + * .getWeek() Algorithm Copyright (c) 2008 Claus Tondering. + * The .getWeek() function does NOT convert the date to UTC. The local datetime + * is used. Please use .getISOWeek() to get the week of the UTC converted date. + * @return {Number} 1 to 53 + */ + $P.getWeek = function() { + var a, b, c, d, e, f, g, n, s, w; + + $y = (!$y) ? this.getFullYear() : $y; + $m = (!$m) ? this.getMonth() + 1 : $m; + $d = (!$d) ? this.getDate() : $d; + + if ($m <= 2) { + a = $y - 1; + b = (a / 4 | 0) - (a / 100 | 0) + (a / 400 | 0); + c = ((a - 1) / 4 | 0) - ((a - 1) / 100 | 0) + ((a - 1) / 400 | 0); + s = b - c; + e = 0; + f = $d - 1 + (31 * ($m - 1)); + } else { + a = $y; + b = (a / 4 | 0) - (a / 100 | 0) + (a / 400 | 0); + c = ((a - 1) / 4 | 0) - ((a - 1) / 100 | 0) + ((a - 1) / 400 | 0); + s = b - c; + e = s + 1; + f = $d + ((153 * ($m - 3) + 2) / 5) + 58 + s; + } + + g = (a + b) % 7; + d = (f + g - e) % 7; + n = (f + 3 - d) | 0; + + if (n < 0) { + w = 53 - ((g - s) / 5 | 0); + } else if (n > 364 + s) { + w = 1; + } else { + w = (n / 7 | 0) + 1; + } + + $y = $m = $d = null; + + return w; + }; + + /** + * Get the ISO 8601 week number. Week one ("01") is the week which contains the + * first Thursday of the year. Monday is considered the first day of the week. + * The .getISOWeek() function does convert the date to it's UTC value. + * Please use .getWeek() to get the week of the local date. + * @return {String} "01" to "53" + */ + $P.getISOWeek = function() { + $y = this.getUTCFullYear(); + $m = this.getUTCMonth() + 1; + $d = this.getUTCDate(); + return p(this.getWeek()); + }; + + /** + * Moves the date to Monday of the week set. Week one (1) is the week which + * contains the first Thursday of the year. + * @param {Number} A Number (1 to 53) that represents the week of the year. + * @return {Date} this + */ + $P.setWeek = function(n) { + return this.moveToDayOfWeek(1).addWeeks(n - this.getWeek()); + }; + + // private + var validate = function(n, min, max, name) { + if (typeof n == "undefined") + return false; + else if (typeof n != "number") + throw new TypeError(n + " is not a Number."); + else if (n < min || n > max) + throw new RangeError(n + " is not a valid value for " + name + "."); + return true; + }; + + /** + * Validates the number is within an acceptable range for milliseconds [0-999]. + * @param {Number} The number to check if within range. + * @return {Boolean} true if within range, otherwise false. + */ + $D.validateMillisecond = function(value) { + return validate(value, 0, 999, "millisecond"); + }; + + /** + * Validates the number is within an acceptable range for seconds [0-59]. + * @param {Number} The number to check if within range. + * @return {Boolean} true if within range, otherwise false. + */ + $D.validateSecond = function(value) { + return validate(value, 0, 59, "second"); + }; + + /** + * Validates the number is within an acceptable range for minutes [0-59]. + * @param {Number} The number to check if within range. + * @return {Boolean} true if within range, otherwise false. + */ + $D.validateMinute = function(value) { + return validate(value, 0, 59, "minute"); + }; + + /** + * Validates the number is within an acceptable range for hours [0-23]. + * @param {Number} The number to check if within range. + * @return {Boolean} true if within range, otherwise false. + */ + $D.validateHour = function(value) { + return validate(value, 0, 23, "hour"); + }; + + /** + * Validates the number is within an acceptable range for the days in a month + * [0 - MaxDaysInMonth]. + * @param {Number} The number to check if within range. + * @return {Boolean} true if within range, otherwise false. + */ + $D.validateDay = function(value, year, month) { + return validate(value, 1, $D.getDaysInMonth(year, month), "day"); + }; + + /** + * Validates the number is within an acceptable range for months [0-11]. + * @param {Number} The number to check if within range. + * @return {Boolean} true if within range, otherwise false. + */ + $D.validateMonth = function(value) { + return validate(value, 0, 11, "month"); + }; + + /** + * Validates the number is within an acceptable range for years. + * @param {Number} The number to check if within range. + * @return {Boolean} true if within range, otherwise false. + */ + $D.validateYear = function(value) { + return validate(value, 0, 9999, "year"); + }; + + /** + * Set the value of year, month, day, hour, minute, second, millisecond of + * date instance using given configuration object. + * Example +
      
      +    Date.today().set( { day: 20, month: 1 } )
      +
      +    new Date().set( { millisecond: 0 } )
      +    
      + * + * @param {Object} Configuration object containing attributes (month, day, etc.) + * @return {Date} this + */ + $P.set = function(config) { + if ($D.validateMillisecond(config.millisecond)) + this.addMilliseconds(config.millisecond - this.getMilliseconds()); + + if ($D.validateSecond(config.second)) + this.addSeconds(config.second - this.getSeconds()); + + if ($D.validateMinute(config.minute)) + this.addMinutes(config.minute - this.getMinutes()); + + if ($D.validateHour(config.hour)) + this.addHours(config.hour - this.getHours()); + + if ($D.validateMonth(config.month)) + this.addMonths(config.month - this.getMonth()); + + if ($D.validateYear(config.year)) + this.addYears(config.year - this.getFullYear()); + + /* day has to go last because you can't validate the day without first knowing the month */ + if ($D.validateDay(config.day, this.getFullYear(), this.getMonth())) + this.addDays(config.day - this.getDate()); + + if (config.timezone) + this.setTimezone(config.timezone); + + if (config.timezoneOffset) + this.setTimezoneOffset(config.timezoneOffset); + + if (config.week && validate(config.week, 0, 53, "week")) + this.setWeek(config.week); + + return this; + }; + + /** + * Moves the date to the first day of the month. + * @return {Date} this + */ + $P.moveToFirstDayOfMonth = function() { + return this.set({ day: 1 }); + }; + + /** + * Moves the date to the last day of the month. + * @return {Date} this + */ + $P.moveToLastDayOfMonth = function() { + return this.set({ day: $D.getDaysInMonth(this.getFullYear(), this.getMonth())}); + }; + + /** + * Moves the date to the next n'th occurrence of the dayOfWeek starting from + * the beginning of the month. The number (-1) is a magic number and will return + * the last occurrence of the dayOfWeek in the month. + * @param {Number} The dayOfWeek to move to + * @param {Number} The n'th occurrence to move to. Use (-1) to return the + * last occurrence in the month + * @return {Date} this + */ + $P.moveToNthOccurrence = function(dayOfWeek, occurrence) { + var shift = 0; + if (occurrence > 0) { + shift = occurrence - 1; + } + else if (occurrence === -1) { + this.moveToLastDayOfMonth(); + if (this.getDay() !== dayOfWeek) + this.moveToDayOfWeek(dayOfWeek, -1); + return this; + } + return this.moveToFirstDayOfMonth().addDays(-1) + .moveToDayOfWeek(dayOfWeek, +1).addWeeks(shift); + }; + + /** + * Move to the next or last dayOfWeek based on the orient value. + * @param {Number} The dayOfWeek to move to + * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional] + * @return {Date} this + */ + $P.moveToDayOfWeek = function(dayOfWeek, orient) { + var diff = (dayOfWeek - this.getDay() + 7 * (orient || +1)) % 7; + return this.addDays((diff === 0) ? diff += 7 * (orient || +1) : diff); + }; + + /** + * Move to the next or last month based on the orient value. + * @param {Number} The month to move to. 0 = January, 11 = December + * @param {Number} Forward (+1) or Back (-1). Defaults to +1. [Optional] + * @return {Date} this + */ + $P.moveToMonth = function(month, orient) { + var diff = (month - this.getMonth() + 12 * (orient || +1)) % 12; + return this.addMonths((diff === 0) ? diff += 12 * (orient || +1) : diff); + }; + + /** + * Get the Ordinal day (numeric day number) of the year, adjusted for leap year. + * @return {Number} 1 through 365 (366 in leap years) + */ + $P.getOrdinalNumber = function() { + return Math.ceil((this.clone().clearTime() + - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1; + }; + + /** + * Get the time zone abbreviation of the current date. + * @return {String} The abbreviated time zone name (e.g. "EST") + */ + $P.getTimezone = function() { + return $D.getTimezoneAbbreviation(this.getUTCOffset()); + }; + + $P.setTimezoneOffset = function(offset) { + var here = this.getTimezoneOffset(), there = Number(offset) * -6 / 10; + return this.addMinutes(there - here); + }; + + $P.setTimezone = function(offset) { + return this.setTimezoneOffset($D.getTimezoneOffset(offset)); + }; + + /** + * Indicates whether Daylight Saving Time is observed in the current time zone. + * @return {Boolean} true|false + */ + $P.hasDaylightSavingTime = function() { + return (Date.today().set({month: 0, day: 1}).getTimezoneOffset() + !== Date.today().set({month: 6, day: 1}).getTimezoneOffset()); + }; + + /** + * Indicates whether this Date instance is within the Daylight Saving Time + * range for the current time zone. + * @return {Boolean} true|false + */ + $P.isDaylightSavingTime = function() { + return Date.today().set({month: 0, day: 1}).getTimezoneOffset() != this.getTimezoneOffset(); + }; + + /** + * Get the offset from UTC of the current date. + * @return {String} The 4-character offset string prefixed with + or - (e.g. "-0500") + */ + $P.getUTCOffset = function() { + var n = this.getTimezoneOffset() * -10 / 6, r; + if (n < 0) { + r = (n - 10000).toString(); + return r.charAt(0) + r.substr(2); + } + else { + r = (n + 10000).toString(); + return "+" + r.substr(1); + } + }; + + $P.getUTCTime = function() { + //Date.UTC(year, month[, date[, hrs[, min[, sec[, ms]]]]]) + return Date.UTC(this.getUTCFullYear(), this.getUTCMonth(), this.getUTCDate(), + this.getUTCHours(), this.getUTCMinutes(), this.getUTCSeconds(), + this.getUTCMilliseconds()); + }; + + /** + * Returns the number of milliseconds between this date and date. + * @param {Date} Defaults to now + * @return {Number} The diff in milliseconds + */ + $P.getElapsed = function(date) { + return (date || new Date()) - this; + }; + + if (!$P.toISOString) { + /** + * Converts the current date instance into a string with an ISO 8601 format. + * The date is converted to it's UTC value. + * @return {String} ISO 8601 string of date + */ + $P.toISOString = function() { + // From http://www.json.org/json.js. Public Domain. + function f(n) { + return n < 10 ? '0' + n : n; + } + + return '"' + this.getUTCFullYear() + '-' + + f(this.getUTCMonth() + 1) + '-' + + f(this.getUTCDate()) + 'T' + + f(this.getUTCHours()) + ':' + + f(this.getUTCMinutes()) + ':' + + f(this.getUTCSeconds()) + 'Z"'; + }; + } + + // private + $P._toString = $P.toString; + + /** + * Converts the value of the current Date object to its equivalent string representation. + * Format Specifiers +
      +    CUSTOM DATE AND TIME FORMAT STRINGS
      +    Format  Description                                                                  Example
      +    ------  ---------------------------------------------------------------------------  -----------------------
      +     s      The seconds of the minute between 0-59.                                      "0" to "59"
      +     ss     The seconds of the minute with leading zero if required.                     "00" to "59"
      +     
      +     m      The minute of the hour between 0-59.                                         "0"  or "59"
      +     mm     The minute of the hour with leading zero if required.                        "00" or "59"
      +     
      +     h      The hour of the day between 1-12.                                            "1"  to "12"
      +     hh     The hour of the day with leading zero if required.                           "01" to "12"
      +     
      +     H      The hour of the day between 0-23.                                            "0"  to "23"
      +     HH     The hour of the day with leading zero if required.                           "00" to "23"
      +     
      +     d      The day of the month between 1 and 31.                                       "1"  to "31"
      +     dd     The day of the month with leading zero if required.                          "01" to "31"
      +     ddd    Abbreviated day name. $C.abbreviatedDayNames.                                "Mon" to "Sun" 
      +     dddd   The full day name. $C.dayNames.                                              "Monday" to "Sunday"
      +     
      +     M      The month of the year between 1-12.                                          "1" to "12"
      +     MM     The month of the year with leading zero if required.                         "01" to "12"
      +     MMM    Abbreviated month name. $C.abbreviatedMonthNames.                            "Jan" to "Dec"
      +     MMMM   The full month name. $C.monthNames.                                          "January" to "December"
      +
      +     yy     The year as a two-digit number.                                              "99" or "08"
      +     yyyy   The full four digit year.                                                    "1999" or "2008"
      +     
      +     t      Displays the first character of the A.M./P.M. designator.                    "A" or "P"
      +            $C.amDesignator or $C.pmDesignator
      +     tt     Displays the A.M./P.M. designator.                                           "AM" or "PM"
      +            $C.amDesignator or $C.pmDesignator
      +     
      +     S      The ordinal suffix ("st, "nd", "rd" or "th") of the current day.            "st, "nd", "rd" or "th"
      +
      +|| *Format* || *Description* || *Example* ||
      +|| d      || The CultureInfo shortDate Format Pattern                                     || "M/d/yyyy" ||
      +|| D      || The CultureInfo longDate Format Pattern                                      || "dddd, MMMM dd, yyyy" ||
      +|| F      || The CultureInfo fullDateTime Format Pattern                                  || "dddd, MMMM dd, yyyy h:mm:ss tt" ||
      +|| m      || The CultureInfo monthDay Format Pattern                                      || "MMMM dd" ||
      +|| r      || The CultureInfo rfc1123 Format Pattern                                       || "ddd, dd MMM yyyy HH:mm:ss GMT" ||
      +|| s      || The CultureInfo sortableDateTime Format Pattern                              || "yyyy-MM-ddTHH:mm:ss" ||
      +|| t      || The CultureInfo shortTime Format Pattern                                     || "h:mm tt" ||
      +|| T      || The CultureInfo longTime Format Pattern                                      || "h:mm:ss tt" ||
      +|| u      || The CultureInfo universalSortableDateTime Format Pattern                     || "yyyy-MM-dd HH:mm:ssZ" ||
      +|| y      || The CultureInfo yearMonth Format Pattern                                     || "MMMM, yyyy" ||
      +     
      +
      +    STANDARD DATE AND TIME FORMAT STRINGS
      +    Format  Description                                                                  Example ("en-US")
      +    ------  ---------------------------------------------------------------------------  -----------------------
      +     d      The CultureInfo shortDate Format Pattern                                     "M/d/yyyy"
      +     D      The CultureInfo longDate Format Pattern                                      "dddd, MMMM dd, yyyy"
      +     F      The CultureInfo fullDateTime Format Pattern                                  "dddd, MMMM dd, yyyy h:mm:ss tt"
      +     m      The CultureInfo monthDay Format Pattern                                      "MMMM dd"
      +     r      The CultureInfo rfc1123 Format Pattern                                       "ddd, dd MMM yyyy HH:mm:ss GMT"
      +     s      The CultureInfo sortableDateTime Format Pattern                              "yyyy-MM-ddTHH:mm:ss"
      +     t      The CultureInfo shortTime Format Pattern                                     "h:mm tt"
      +     T      The CultureInfo longTime Format Pattern                                      "h:mm:ss tt"
      +     u      The CultureInfo universalSortableDateTime Format Pattern                     "yyyy-MM-dd HH:mm:ssZ"
      +     y      The CultureInfo yearMonth Format Pattern                                     "MMMM, yyyy"
      +    
      + * @param {String} A format string consisting of one or more format spcifiers [Optional]. + * @return {String} A string representation of the current Date object. + */ + $P.toString = function(format) { + var x = this; + + // Standard Date and Time Format Strings. Formats pulled from CultureInfo file and + // may vary by culture. + if (format && format.length == 1) { + var c = $C.formatPatterns; + x.t = x.toString; + switch (format) { + case "d": + return x.t(c.shortDate); + case "D": + return x.t(c.longDate); + case "F": + return x.t(c.fullDateTime); + case "m": + return x.t(c.monthDay); + case "r": + return x.t(c.rfc1123); + case "s": + return x.t(c.sortableDateTime); + case "t": + return x.t(c.shortTime); + case "T": + return x.t(c.longTime); + case "u": + return x.t(c.universalSortableDateTime); + case "y": + return x.t(c.yearMonth); + } + } + + var ord = function (n) { + switch (n * 1) { + case 1: + case 21: + case 31: + return "st"; + case 2: + case 22: + return "nd"; + case 3: + case 23: + return "rd"; + default: + return "th"; + } + }; + + return format ? format.replace(/(\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S)/g, + function (m) { + if (m.charAt(0) === "\\") { + return m.replace("\\", ""); + } + x.h = x.getHours; + switch (m) { + case "hh": + return p(x.h() < 13 ? (x.h() === 0 ? 12 : x.h()) : (x.h() - 12)); + case "h": + return x.h() < 13 ? (x.h() === 0 ? 12 : x.h()) : (x.h() - 12); + case "HH": + return p(x.h()); + case "H": + return x.h(); + case "mm": + return p(x.getMinutes()); + case "m": + return x.getMinutes(); + case "ss": + return p(x.getSeconds()); + case "s": + return x.getSeconds(); + case "yyyy": + return p(x.getFullYear(), 4); + case "yy": + return p(x.getFullYear()); + case "dddd": + return $C.dayNames[x.getDay()]; + case "ddd": + return $C.abbreviatedDayNames[x.getDay()]; + case "dd": + return p(x.getDate()); + case "d": + return x.getDate(); + case "MMMM": + return $C.monthNames[x.getMonth()]; + case "MMM": + return $C.abbreviatedMonthNames[x.getMonth()]; + case "MM": + return p((x.getMonth() + 1)); + case "M": + return x.getMonth() + 1; + case "t": + return x.h() < 12 ? $C.amDesignator.substring(0, 1) : $C.pmDesignator.substring(0, 1); + case "tt": + return x.h() < 12 ? $C.amDesignator : $C.pmDesignator; + case "S": + return ord(x.getDate()); + default: + return m; + } + } + ) : this._toString(); + }; +}()); + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: socket://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * @class apf.layout + * + * Takes care of the spatial order of elements within the display area + * of the browser. Layouts can be saved to XML and loaded again. Window + * elements are dockable, which means the user can change the layout as s/he + * wishes. The state of the layout can be saved as XML at any time. + * + * #### Example + * + * This example shows five windows which have a layout defined in layout.xml. + * + * ```xml + * + * + * + * + * + * + * + * + * ``` + * + * This is the layout file containing two layouts (_layout.xml_): + * + * ```xml + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * ``` + * + * By binding on the _layout.xml_ you can easily create a layout manager. + * + * ```xml + * + * + * + * + * + * + * + * + * + * + * + * + * Add Layout + * + * ``` + * + * @default_private + */ + // @todo a __WITH_DOM_REPARENTING should be added which can remove many of the functions of this element. + +apf.layout = { + compile: function(oHtml) { + var l = this.layouts[oHtml.getAttribute("id")]; + if (!l) return false; + + var root = l.root.copy();//is there a point to copying? + + l.layout.compile(root); + l.layout.reset(); + }, + + removeAll: function(aData) { + aData.children.length = null + + var htmlId = this.getHtmlId(aData.pHtml); + if (!this.rules[htmlId]) + delete this.qlist[htmlId]; + }, + + timer: null, + qlist: {}, + dlist: [], + $hasQueue: false, + + queue: function(oHtml, obj, compile, q) { + if (!q) { + this.$hasQueue = true; + q = this.qlist; + } + + var id; + if (!(id = this.getHtmlId(oHtml))) + id = apf.setUniqueHtmlId(oHtml); + + if (q[id]) { + if (obj) + q[id][2].push(obj); + if (compile) + q[id][1] = compile; + return; + } + + q[id] = [oHtml, compile, [obj]]; + + if (!this.timer) + this.timer = apf.setZeroTimeout(function(){ + apf.layout.processQueue(); + }); + }, + + processQueue: function(){ + var i, id, l, qItem, list; + + for (i = 0; i < this.dlist.length; i++) { + if (this.dlist[i].hidden) + this.dlist[i].hide(); + else + this.dlist[i].show(); + } + + do { + var newq = {}; + var qlist = this.qlist; + this.qlist = {}; + + this.$hasQueue = false; + + for (id in qlist) { + qItem = qlist[id]; + + if (qItem[1]) + apf.layout.compileAlignment(qItem[1]); + + list = qItem[2]; + for (i = 0, l = list.length; i < l; i++) { + if (list[i]) { + if (list[i].$amlDestroyed) + continue; + //if (list[i].$amlLoaded) + list[i].$updateLayout(); + /*else + this.queue(qItem[0], list[i], null, newq);*/ + } + } + + apf.layout.activateRules(qItem[0]); + } + } while (this.$hasQueue); + + if (apf.hasSingleRszEvent) + apf.layout.forceResize(); + + this.dlist = []; + + apf.setZeroTimeout.clearTimeout(this.timer); + this.timer = null; + }, + + rules: {}, + onresize: {}, + + getHtmlId: function(oHtml) { + return oHtml.getAttribute ? oHtml.getAttribute("id") : 1; + }, + + /** + * Adds layout rules to the resize event of the browser. Use this instead + * of `"onresize"` events to add rules that specify determine the layout. + * @param {HTMLElement} oHtml The element that triggers the execution of the rules. + * @param {String} id The identifier for the rules within the resize function of this element. Use this to easily update or remove the rules added. + * @param {String} rules The JavaScript code that is executed when the html element resizes. + * @param {Boolean} [overwrite] Whether the rules are added to the resize function or overwrite the previous set rules with the specified id. + */ + setRules: function(oHtml, id, rules, overwrite) { + if (!this.getHtmlId(oHtml)) + apf.setUniqueHtmlId(oHtml); + if (!this.rules[this.getHtmlId(oHtml)]) + this.rules[this.getHtmlId(oHtml)] = {}; + + var ruleset = this.rules[this.getHtmlId(oHtml)][id]; + if (!overwrite && ruleset) { + this.rules[this.getHtmlId(oHtml)][id] = rules + "\n" + ruleset; + } + else + this.rules[this.getHtmlId(oHtml)][id] = rules; + }, + + /** + * Retrieves the rules set for the `"resize"` event of an HTML element specified by an identifier + * @param {HTMLElement} oHtml The element that triggers the execution of the rules. + * @param {String} id The identifier for the rules within the resize function of this element. + */ + getRules: function(oHtml, id) { + return id + ? this.rules[this.getHtmlId(oHtml)][id] + : this.rules[this.getHtmlId(oHtml)]; + }, + + /** + * Removes the rules set for the `"resize"` event of an html element specified by an identifier + * @param {HTMLElement} oHtml The element that triggers the execution of the rules. + * @param {String} id The identifier for the rules within the resize function of this element. + */ + removeRule: function(oHtml, id) { + var htmlId = this.getHtmlId(oHtml); + if (!this.rules[htmlId]) + return; + + var ret = this.rules[htmlId][id] || false; + delete this.rules[htmlId][id]; + + var prop; + for (prop in this.rules[htmlId]) { + + } + if (!prop) + delete this.rules[htmlId] + + if (apf.hasSingleRszEvent) { + if (this.onresize[htmlId]) + this.onresize[htmlId] = null; + else { + var p = oHtml.parentNode; + while (p && p.nodeType == 1 && !this.onresize[p.getAttribute("id")]) { + p = p.parentNode; + } + + if (p && p.nodeType == 1) { + var x = this.onresize[p.getAttribute("id")]; + if (x.children) + delete x.children[htmlId] + } + } + } + + return ret; + }, + + /** + * Activates the rules set for an HTML element + * @param {HTMLElement} oHtml The element that triggers the execution of the rules. + * @param {Boolean} [no_exec] + */ + activateRules: function(oHtml, no_exec) { + if (!oHtml) { //!apf.hasSingleRszEvent && + var prop, obj; + for (prop in this.rules) { + obj = document.getElementById(prop); + if (!obj || obj.onresize) // || this.onresize[prop] + continue; + this.activateRules(obj); + } + + if (apf.hasSingleRszEvent && apf.layout.$onresize) + apf.layout.$onresize(); + return; + } + + var rsz, id, rule, rules, strRules = []; + if (!apf.hasSingleRszEvent) { + rules = this.rules[this.getHtmlId(oHtml)]; + if (!rules) { + oHtml.onresize = null; + return false; + } + + for (id in rules) { //might need optimization using join() + if (typeof rules[id] != "string") + continue; + strRules.push(rules[id]); + } + + //apf.console.info(strRules.join("\n")); + rsz = apf.needsCssPx + ? new Function(strRules.join("\n")) + : new Function(strRules.join("\n").replace(/ \+ 'px'|try\{\}catch\(e\)\{\}\n/g,"")) + + oHtml.onresize = rsz; + if (!no_exec) + rsz(); + } + else { + var htmlId = this.getHtmlId(oHtml); + rules = this.rules[htmlId]; + if (!rules) { + //@todo keep .children + //delete this.onresize[htmlId]; + return false; + } + + for (id in rules) { //might need optimization using join() + if (typeof rules[id] != "string") + continue; + strRules.push(rules[id]); + } + + var p = oHtml.parentNode; + while (p && p.nodeType == 1 && !this.onresize[p.getAttribute("id")]) { + p = p.parentNode; + } + + var f = new Function(strRules.join("\n"));//.replace(/try\{/g, "").replace(/}catch\(e\)\{\s*\}/g, "\n") + if (this.onresize[htmlId]) + f.children = this.onresize[htmlId].children; + + if (p && p.nodeType == 1) { + var x = this.onresize[p.getAttribute("id")]; + this.onresize[htmlId] = (x.children || (x.children = {}))[htmlId] = f; + } + else { + this.onresize[htmlId] = f; + } + if (!no_exec) + f(); + + if (!apf.layout.$onresize) { + var rsz = function(f) { + //@todo fix this + try{ + var c = []; + for (var name in f) + if (f[name]) + c.unshift(f[name]); + for (var i = 0; i < c.length; i++){ + c[i](); + if (c[i].children) { + rsz(c[i].children); + } + } + } + catch (e) { + + } + } + + apf.addListener(window, "resize", apf.layout.$onresize = function(){ + if (apf.config.resize !== false) { + rsz(apf.layout.onresize); + } + }); + } + } + }, + + /** + * Forces calling the resize rules for an HTML element + * @param {HTMLElement} oHtml The element for which the rules are executed. + */ + forceResize: function(oHtml, force) { + if (!force) return; + + if (apf.hasSingleRszEvent) + return apf.layout.$onresize && apf.layout.$onresize(); + + /* @todo this should be done recursive, old way for now + apf.hasSingleRszEvent + ? this.onresize[this.getHtmlId(oHtml)] + : + */ + + var rsz = oHtml.onresize; + if (rsz) + rsz(); + + var els = oHtml.getElementsByTagName("*"); + for (var i = 0, l = els.length; i < l; i++) { + if (els[i] && els[i].onresize) + els[i].onresize(); + } + }, + + paused: {}, + + /** + * Temporarily disables the resize rules for the HTML element. + * @param {HTMLElement} oHtml The element for which the rules are paused. + * @param {Function} func The resize code that is used temporarily for resize of the HTML element. + */ + pause: function(oHtml, replaceFunc) { + if (apf.hasSingleRszEvent) { + var htmlId = this.getHtmlId(oHtml); + this.paused[htmlId] = this.onresize[htmlId] || true; + + if (replaceFunc) { + this.onresize[htmlId] = replaceFunc; + this.onresize[htmlId].children = this.paused[htmlId].children; + replaceFunc(); + } + else + delete this.onresize[htmlId]; + } + else { + this.paused[this.getHtmlId(oHtml)] = oHtml.onresize || true; + + if (replaceFunc) { + oHtml.onresize = replaceFunc; + replaceFunc(); + } + else + oHtml.onresize = null; + } + }, + + /** + * Enables paused resize rules for the HTML element + * @param {HTMLElement} oHtml The element for which the rules were paused. + */ + play: function(oHtml) { + if (!this.paused[this.getHtmlId(oHtml)]) + return; + + if (apf.hasSingleRszEvent) { + var htmlId = this.getHtmlId(oHtml); + var oldFunc = this.paused[htmlId]; + if (typeof oldFunc == "function") { + this.onresize[htmlId] = oldFunc; + //oldFunc(); + } + else + delete this.onresize[htmlId]; + + if (apf.layout.$onresize) + apf.layout.$onresize(); + + this.paused[this.getHtmlId(oHtml)] = null; + } + else { + var oldFunc = this.paused[this.getHtmlId(oHtml)]; + if (typeof oldFunc == "function") { + oHtml.onresize = oldFunc; + oldFunc(); + } + else + oHtml.onresize = null; + + this.paused[this.getHtmlId(oHtml)] = null; + } + } +}; + + +/** + * @private + */ +apf.getWindowWidth = function(){ + return apf.isIE ? document.documentElement.offsetWidth - apf.windowHorBorder : window.innerWidth; +}; +/** + * @private + */ +apf.getWindowHeight = function(){ + return apf.isIE ? document.documentElement.offsetHeight - apf.windowVerBorder : window.innerHeight; +}; + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +// Only add setZeroTimeout to the window object, and hide everything +// else in a closure. +apf.setZeroTimeout = !window.postMessage + ? (function() { + function setZeroTimeout() { + return $setTimeout.apply(null, arguments); + } + setZeroTimeout.clearTimeout = function() { + return clearTimeout.apply(null, arguments); + }; + return setZeroTimeout; + })() + : (function() { + var timeouts = []; + var messageName = "zero-timeout-message"; + + // Like setTimeout, but only takes a function argument. There's + // no time argument (always zero) and no arguments (you have to + // use a closure). + function setZeroTimeout(fn) { + var id = timeouts.push(fn); + window.postMessage(messageName, "*"); + return id; + } + + setZeroTimeout.clearTimeout = function(id) { + timeouts[id] = null; + } + + function handleMessage(e) { + if (!e) e = event; + if (e.source == window && e.data == messageName) { + apf.stopPropagation(e); + if (timeouts.length > 0 && (t = timeouts.shift())) + t(); + } + } + + apf.addListener(window, "message", handleMessage, true); + + // Add the one thing we want added to the window object. + return setZeroTimeout; + })(); + + + + +/* + * + */ +apf.queue = { + //@todo apf3.0 + q: {}, + + timer: null, + add: function(id, f) { + this.q[id] = f; + if (!this.timer) + + this.timer = apf.setZeroTimeout(function(){ + apf.queue.empty(); + }); + + }, + + remove: function(id) { + delete this.q[id]; + }, + + empty: function(prop) { + + apf.setZeroTimeout.clearTimeout(this.timer); + + this.timer = null; + + + if (apf.layout && apf.layout.$hasQueue) + apf.layout.processQueue(); + + + if (apf.xmldb && apf.xmldb.$hasQueue) + apf.xmldb.notifyQueued(); + + + var q = this.q; + this.q = {}; + for (var prop in q) { + var f = q[prop]; + if (f) { + delete q[prop]; + f(); + } + } + } +}; + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * This abstraction is using for resizing block elements. Resizing is allowed + * with square elements in vertical, horizontal or both planes. Symmetric + * resizing is possible with SHIFT button. + * + * @private + * @default_private + * @constructor + * + * @author Lukasz Lipinski + * @version %I%, %G% + * @since 1.0 + * + */ + +apf.resize = function() { + /** + * {Boolean} scalex resizing in horizontal plane, default is true + * Possible values: + * true resizing in horizontal plane is allowed + * false resizing in horizontal plane is not allowed + * {Boolean} scaley resizing in vertical plane, default is true + * Possible values: + * true resizing in vertical plane is allowed + * false resizing in vertical plane is not allowed + * {Boolean} scaleratio resizing in horizontal or vertical plane only is not allowed. Resizing in two dimensions plane at the same time is allowed. + * Possible values: + * true resizing in two dimensions plane at the same time is allowed + * false Resizing in two dimensions plane at the same time is not allowed + * {Number} dwidth the minimal horizontal size of Block element, default is 56 pixels + * {Number} dheight the minimal vertical size of Block element, default is 56 pixels + */ + this.scales = { + scalex: false, + scaley: false, + scaleratio: false, + dwidth: 0, + dheight: 0, + snap: false, + gridW: 48, + gridH: 48 + }; + + /* + * html representation of resized block element + */ + this.htmlElement; + + /** + * store object representations of inputs elements + */ + var squares = []; + + this.init = function() { + squares = [ + new apf.resize.square("top", "left", this), + new apf.resize.square("top", "middle", this), + new apf.resize.square("top", "right", this), + new apf.resize.square("middle", "left", this), + new apf.resize.square("middle", "right", this), + new apf.resize.square("bottom", "left", this), + new apf.resize.square("bottom", "middle", this), + new apf.resize.square("bottom", "right", this)]; + }; + + /** + * Links block element with resize feature + * + * @param {HTMLElement} oHtml html representation of block element + * @param {Object} scales blocks scale settings + */ + this.grab = function(oHtml, scales) { + this.htmlElement = oHtml; + this.scales = scales; + + if (!squares.length) + this.init(); + this.show(); + }; + + /** + * Hides all block squares + */ + this.hide = function() { + for (var i = 0, l = squares.length; i < l; i++) { + squares[i].visible = false; + squares[i].repaint(); + } + }; + + /** + * Shows all block squares + */ + this.show = function() { + var sx = this.scales.scalex; + var sy = this.scales.scaley; + var sr = this.scales.scaleratio; + + for (var i = 0, l = squares.length, s; i < l; i++) { + s = squares[i]; + s.visible = sx && sy + ? true + : (sy && !sx + ? (s.posX == "middle" + ? true + : false) + : (sx && !sy + ? (s.posY == "middle" + ? true + : false) + : (sr + ? ((s.posY == "top" || s.posY == "bottom") + && s.posX !== "middle" + ? true + : false) + : false))); + + s.repaint(); + } + }; + + /** + * Destroys all block squares + */ + this.destroy = function(){ + for (var i = 0; i < squares.length; i++) { + squares[i].destroy(); + } + }; +}; + +/* + * Creates html and object representation for square element. Square is used for + * resizing block elements. + * + * @param {String} posY square vertical align relative to resized block element + * Possible values: + * top square is on top of resized block element + * middle square is in the middle of the resized block element + * bottom square is on the bottom of resized block element + * @param {String} posX square vertical align relative to resized block element + * Possible values: + * left square is on the left of resized block element + * middle square is in the middle of the resized block element + * right square is on the right of resized block element + * @param {Object} objResize object of resize class + * @constructor + */ +apf.resize.square = function(posY, posX, objResize) { + /* + * Square visibility + */ + this.visible = true; + /* + * square vertical align relative to resized block element + */ + this.posX = posX; + /* + * square vertical align relative to resized block element + */ + this.posY = posY; + + var margin = 0; + var _self = this; + + /* + * html represenation of square element + */ + this.htmlElement = objResize.htmlElement.parentNode.appendChild(document.createElement('div')); + apf.setStyleClass(this.htmlElement, "square"); + + /* + * Repaints square + */ + this.repaint = function() { + if (this.visible) { + var block = objResize.htmlElement; + this.htmlElement.style.display = "block"; + + var bw = parseInt(block.style.width) + apf.getDiff(block)[0]; + var bh = parseInt(block.style.height) + apf.getDiff(block)[1]; + var bt = parseInt(block.style.top); + var bl = parseInt(block.style.left); + + var sw = this.htmlElement.offsetWidth; + var sh = this.htmlElement.offsetHeight; + + var t = posY == "top" + ? bt - margin - sh + : posY == "middle" + ? bt + bh/2 - sh/2 + : bt + bh + margin; + var l = posX == "left" + ? bl - margin - sw + : posX == "middle" + ? bl + bw/2 - sw/2 + : bl + bw + margin; + + var c = (posY == "middle" + ? "w-resize" + : (posX == "middle" + ? "n-resize" + : (posY + posX == "topleft" + || posY + posX == "bottomright") + ? "nw-resize" + : "ne-resize")); + + this.htmlElement.style.top = (t - 1) + "px"; + this.htmlElement.style.left = (l - 1) + "px"; + this.htmlElement.style.cursor = c; + } + else { + //IE bug + var sw = this.htmlElement.offsetWidth; + this.htmlElement.style.display = 'none'; + } + }; + + this.destroy = function(){ + apf.destroyHtmlNode(this.htmlElement); + }; + + /* Events */ + this.htmlElement.onmouseover = function(e) { + apf.setStyleClass(_self.htmlElement, "squareHover"); + }; + + this.htmlElement.onmouseout = function(e) { + apf.setStyleClass(_self.htmlElement, "", ["squareHover"]); + }; + + this.htmlElement.onmousedown = function(e) { + e = (e || event); + + var block = objResize.htmlElement, + + sx = e.clientX, + sy = e.clientY, + + pt = block.parentNode.offsetTop, + pl = block.parentNode.offsetLeft, + + dw = objResize.scales.dwidth, + dh = objResize.scales.dheight, + + snap = objResize.scales.snap, + gridH = objResize.scales.gridH, + gridW = objResize.scales.gridW, + + objBlock = apf.flow.isBlock(block), + r = objBlock.other.ratio, + + posX = _self.posX, + posY = _self.posY, + + width, height, top, left, dx, dy, + prev_w, prev_h, + + l = parseInt(block.style.left), + t = parseInt(block.style.top), + w = parseInt(block.style.width), + h = parseInt(block.style.height), + resized = false; + + objResize.onresizedone(w, h, t, l); + + if (e.preventDefault) { + e.preventDefault(); + } + + document.onmousemove = function(e) { + e = (e || event); + + dx = e.clientX - sx; + dy = e.clientY - sy; + var shiftKey = e.shiftKey, + proportion = r; + + if (shiftKey) { + if (posX == "right" && posY == "bottom") { + width = w + dx; + height = width/proportion; + left = l; + top = t; + } + else if (posX == "right" && posY == "top") { + width = w + dx; + height = width/proportion; + left = l; + top = t - dx/proportion; + } + else if (posX == "left" && posY == "bottom") { + width = w - dx; + height = width/proportion; + left = l + dx; + top = t; + } + else if (posX == "left" && posY == "top") { + width = w - dx; + height = width/proportion; + left = l + dx; + top = t + dx/proportion; + } + + /* Keep minimal size */ + if (width >= dw && height >= dh) { + width = prev_w = Math.max(dw, width); + height = prev_h = Math.max(dh, height); + } + else { + width = prev_w; + height = prev_h; + return false; + } + } + else { + width = posX == "right" + ? w + dx + : (posX == "left" + ? w - dx + : w); + height = posY == "bottom" + ? h + dy + : (posY == "top" + ? h - dy + : h); + left = posX == "right" + ? l + : (posX == "left" + ? Math.min(l + w - dw, l + dx) + : l); + top = posY == "bottom" + ? t + : (posY == "top" + ? Math.min(t + h - dh, t + dy) + : t); + + /* Keep minimal size */ + width = Math.max(dw, width); + height = Math.max(dh, height); + } + + if (snap) { + left = Math.floor(left / gridW) * gridW; + top = Math.floor(top / gridH) * gridH; + width = Math.ceil(width / gridW) * gridW; + height = Math.ceil(height / gridH) * gridH; + } + + if (objResize.onresize) { + objResize.onresize(block, top, left, width, height); + } + + objResize.show(); + + resized = true; + }; + + document.onmouseup = function(e) { + document.onmousemove = null; + if (objResize.onresizedone && resized) { + objResize.onresizedone(width, height, top, left); + objBlock.other.ratio = width / height; + resized = false; + } + }; + }; +}; + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * + * Controls the skinning modifications for AML. + * + * @private + */ +apf.skins = { + skins: {}, + css: [], + // @TODO Doc these ? + _events: ["onmousemove", "onmousedown", "onmouseup", "onmouseout", + "onclick", "ondragcopy", "ondragstart", "ondblclick"], + + /* *********** + Init + ************/ + Init: function(xmlNode, refNode, path) { + /* + get data from refNode || xmlNode + - name + - icon-path + - media-path + + all paths of the xmlNode are relative to the src attribute of refNode + all paths of the refNode are relative to the index.html + images/ is replaced if there is a refNode to the relative path from index to the skin + /images/ + */ + var name = (refNode ? refNode.getAttribute("id") : null) + || xmlNode.getAttribute("id"); + var base = (refNode ? (refNode.getAttribute("src") || "").match(/\//) || path : "") + ? (path || refNode.getAttribute("src")).replace(/\/[^\/]*$/, "") + "/" + : ""; //@todo make this absolute? + + var mediaPath = null, iconPath = null; + mediaPath = xmlNode.getAttribute("media-path"); + if (mediaPath !== null) + mediaPath = apf.getAbsolutePath(base || apf.hostPath, mediaPath); + else if (refNode) { + mediaPath = refNode.getAttribute("media-path"); + if (mediaPath !== null) + mediaPath = apf.getAbsolutePath(apf.hostPath, mediaPath); + else + mediaPath = apf.getAbsolutePath(base || apf.hostPath, "images/"); + } + + iconPath = xmlNode.getAttribute("icon-path"); + if (iconPath !== null) + iconPath = apf.getAbsolutePath(base || apf.hostPath, iconPath); + else if (refNode) { + iconPath = refNode.getAttribute("icon-path"); + if (iconPath !== null) + iconPath = apf.getAbsolutePath(apf.hostPath, iconPath); + else + iconPath = apf.getAbsolutePath(base || apf.hostPath, "icons/"); + } + + if (!name) + name = "default"; + + if (xmlNode.getAttribute("id")) + document.body.className += " " + xmlNode.getAttribute("id"); + + var names = name.split("|"); + name = names[0]; + + if (!this.skins[name] || name == "default") { + this.skins[name] = { + base: base, + name: name, + iconPath: iconPath, + mediaPath: mediaPath, + templates: {}, + originals: {}, + xml: xmlNode + } + + if (names.length > 1) { + for (var i = 0; i < names.length; i++) + this.skins[names[i]] = this.skins[name]; + } + } + + if (!this.skins["default"] && this.$first == refNode) + this.skins["default"] = this.skins[name]; + + var nodes = xmlNode.childNodes; + for (var i = nodes.length - 1; i >= 0; i--) { + if (nodes[i].nodeType != 1) + continue; + + //this.templates[nodes[i].tagName] = nodes[i]; + this.skins[name].templates[nodes[i].getAttribute("name")] = nodes[i]; + if (nodes[i].ownerDocument) + this.importSkinDef(nodes[i], base, name); + } + + this.purgeCss(mediaPath, iconPath); + + if (this.queue[name]) { + for (var prop in this.queue[name]) { + this.queue[name][prop](); + } + } + }, + + /** + * Loads a stylesheet from a URL. + * @param {String} filename The url to load the stylesheet from + * @param {String} [title] Title of the stylesheet to load + * @method loadStylesheet + */ + loadStylesheet: function(filename, title) { + var o; + with (o = document.getElementsByTagName("head")[0].appendChild(document.createElement("LINK"))) { + rel = "stylesheet"; + type = "text/css"; + href = filename; + title = title; + } + + return o; + }, + + /* *********** + Import + ************/ + importSkinDef: function(xmlNode, basepath, name) { + var i, l, nodes = $xmlns(xmlNode, "style", apf.ns.aml), tnode, node; + for (i = 0, l = nodes.length; i < l; i++) { + node = nodes[i]; + + if (node.getAttribute("src")) + this.loadStylesheet(apf.getAbsolutePath(basepath, node.getAttribute("src"))); + else { + var test = true; + if (node.getAttribute("condition")) { + try { + test = eval(node.getAttribute("condition")); + } + catch (e) { + test = false; + } + } + + if (test) { + //#-ifndef __PROCESSED + tnode = node.firstChild; + while (tnode) { + this.css.push(tnode.nodeValue); + tnode = tnode.nextSibling; + } + /*#-else + this.css.push(nodes[i].firstChild.nodeValue); + #-endif*/ + } + } + } + + nodes = $xmlns(xmlNode, "alias", apf.ns.apf); + var t = this.skins[name].templates; + for (i = 0; i < nodes.length; i++) { + if (!nodes[i].firstChild) + continue; + t[nodes[i].firstChild.nodeValue.toLowerCase()] = xmlNode; + } + }, + + loadedCss: "", + purgeCss: function(imagepath, iconpath) { + if (!this.css.length) + return; + + var cssString = this.css.join("\n").replace(/images\//g, imagepath).replace(/icons\//g, iconpath); + apf.importCssString(cssString); + + + + this.css = []; + }, + + loadCssInWindow: function(skinName, win, imagepath, iconpath) { + this.css = []; + var name = skinName.split(":"); + var skin = this.skins[name[0]]; + var template = skin.templates[name[1]]; + this.importSkinDef(template, skin.base, skin.name); + var cssString = this.css.join("\n").replace(/images\//g, imagepath).replace(/icons\//g, iconpath); + apf.importCssString(cssString); + + this.css = []; + }, + + /* *********** + Retrieve + ************/ + setSkinPaths: function(skinName, amlNode) { + skinName = skinName.split(":"); + var name = skinName[0]; + var type = skinName[1]; + + + + amlNode.iconPath = this.skins[name].iconPath; + amlNode.mediaPath = this.skins[name].mediaPath; + }, + + getTemplate: function(skinName, noError) { + skinName = skinName.split(":"); + var name = skinName[0]; + var type = skinName[1]; + + if (!this.skins[name]) { + if (noError) + return false; + + + + return false; + } + + if (!this.skins[name].templates[type]) + return false; + + var skin = this.skins[name].templates[type]; + var originals = this.skins[name].originals[type]; + if (!originals) { + originals = this.skins[name].originals[type] = {}; + + + + var nodes = $xmlns(skin, "presentation", apf.ns.aml)[0].childNodes; + for (var i = 0; i < nodes.length; i++) { + if (nodes[i].nodeType != 1) continue; + originals[nodes[i].baseName || nodes[i][apf.TAGNAME]] = nodes[i]; + } + } + + /*for (var item in originals) { + pNodes[item] = originals[item]; + }*/ + + return originals; + }, + + getCssString: function(skinName) { + return apf.queryValue($xmlns(this.skins[skinName.split(":")[0]].xml, + "style", apf.ns.aml)[0], "text()"); + }, + + + changeSkinset: function(value) { + var node = apf.document.documentElement; + while (node) { + if (node && node.nodeFunc == apf.NODE_VISIBLE + && node.hasFeature(apf.__PRESENTATION__) && !node.skinset) { + node.$propHandlers["skinset"].call(node, value);//$forceSkinChange + node.skinset = null; + } + + //Walk tree + if (node.firstChild || node.nextSibling) { + node = node.firstChild || node.nextSibling; + } + else { + do { + node = node.parentNode; + } while (node && !node.nextSibling) + + if (node) + node = node.nextSibling; + } + } + }, + + + queue: {}, + waitForSkin: function(skinset, id, callback) { + if (this.skins[skinset]) + return; + + (this.queue[skinset] || (this.queue[skinset] = {}))[id] = callback; + return true; + }, + + + + setIcon: function(oHtml, strQuery, iconPath) { + if (!strQuery) { + oHtml.style.backgroundImage = ""; + return; + } + + if (oHtml.tagName.toLowerCase() == "img") { + oHtml.setAttribute("src", strQuery + ? (iconPath || "") + strQuery + : ""); + return; + } + + + + //Assuming image url + { + + + oHtml.style.backgroundImage = "url(" + (strQuery.substr(0, 4) == "http" ? "" : iconPath || "") + + strQuery + ")"; + } + } +}; + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * Object handling sorting in a similar way as xslt. + * + * @constructor + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.8 + * + * @private + */ +apf.Sort = function(xmlNode) { + var settings = {}; + + //use this function to parse the each node + this.parseXml = function(xmlNode, clear) { + if (clear) settings = {}; + + settings.order = xmlNode.order; + settings.getValue = xmlNode.csort || xmlNode.$compile("sort"); + settings.getNodes = self[xmlNode["nodes-method"]]; + + settings.ascending = (settings.order || "").indexOf("desc") == -1; + settings.order = null; + + if (xmlNode["data-type"]) + settings.method = sort_methods[xmlNode["data-type"]]; + else if (xmlNode["sort-method"]) { + settings.method = self[xmlNode["sort-method"]]; + + + } + else + settings.method = sort_methods["alpha"]; + + var str = xmlNode["date-format"]; + if (str) { + settings.sort_dateFmtStr = str; + settings.method = sort_methods["date"]; + var result = str.match(/(D+|Y+|M+|h+|m+|s+)/g); + if (result) { + for (var pos = {}, i = 0; i < result.length; i++) + pos[result[i].substr(0, 1)] = i + 1; + settings.dateFormat = new RegExp(str.replace(/([^\sDYMhms])/g, '\\$1') + .replace(/YYYY/, "(\\d\\d\\d\\d)") + .replace(/(DD|YY|MM|hh|mm|ss)/g, "(\\d\\d)")); + settings.dateReplace = "$" + pos["M"] + "/$" + pos["D"] + "/$" + pos["Y"]; + if (pos["h"]) + settings.dateReplace += " $" + pos["h"] + ":$" + pos["m"] + ":$" + pos["s"]; + } + } + }; + + this.set = function(struct, clear) { + if (clear) settings = {}; + + apf.extend(settings, struct); + + if (settings.ascending == undefined) + settings.ascending = struct.order + ? struct.order.indexOf("desc") == -1 + : true; + + settings.order = null; + + if (struct["type"]) + settings.method = sort_methods[struct["type"]]; + else if (struct["method"]) + settings.method = self[struct["method"]]; + else if (!settings.method) + settings.method = sort_methods["alpha"]; + + if (struct.format) { + settings.sort_dateFmtStr = struct.format; + //settings.method = sort_methods["date"]; + var result = str.match(/(D+|Y+|M+|h+|m+|s+)/g); + if (result) { + for (var pos = {}, i = 0; i < result.length; i++) + pos[result[i].substr(0, 1)] = i + 1; + settings.dateFormat = new RegExp(str.replace(/([^\sDYMhms])/g, '\\$1') + .replace(/YYYY/, "(\\d\\d\\d\\d)") + .replace(/(DD|YY|MM|hh|mm|ss)/g, "(\\d\\d)")); + settings.dateReplace = "$" + pos["M"] + "/$" + pos["D"] + "/$" + pos["Y"]; + if (pos["h"]) + settings.dateReplace += " $" + pos["h"] + ":$" + pos["m"] + ":$" + pos["s"]; + } + } + + if (!settings.getValue) { + settings.getValue = function(item) { + return apf.queryValue(item, settings.xpath); + } + } + }; + + this.get = function(){ + return apf.extend({}, settings); + }; + + //use this function in __xmlUpdate [this function isnt done yet] + this.findSortSibling = function(pNode, xmlNode) { + var nodes = getNodes ? getNodes(pNode, xmlNode) : this.getTraverseNodes(pNode); + + for (var i = 0; i < nodes.length; i++) + if (!compare(xmlNode, nodes[i], true, sortSettings)) + return nodes[i]; + + return null; + }; + + // Sorting methods for sort() + var sort_intmask = ["", "0", "00", "000", "0000", "00000", "000000", + "0000000", "00000000", "000000000", "0000000000", "00000000000", + "000000000000", "0000000000000", "00000000000000"]; + var sort_methods = { + "alpha" : function (n) { + return n.toString().toLowerCase() + }, + + "number" : function (t) { + if (!t) var t = 0; + return (t.length < sort_intmask.length + ? sort_intmask[sort_intmask.length - t.length] + : "") + t; + }, + + "date" : function (t, args) { + var sort_dateFormat = settings.dateFormat; + var sort_dateReplace = settings.dateReplace; + var sort_dateFmtStr = settings.sort_dateFmtStr; + + var d;//|| (args && sort_dateFmtStr != args[0]) + if (!sort_dateFormat) { + d = new Date(t); + } + else if (sort_dateFmtStr == '*') + d = apf.date.getDateTime(t); + else + d = (new Date(t.replace(sort_dateFormat, sort_dateReplace))).getTime(); + var t = "" + d.getTime();//parseInt(d); + if (t == "NaN") + t = "0"; + return (t.length < sort_intmask.length ? sort_intmask[sort_intmask.length + - t.length] : "") + t; + } + }; + + /* + sort(xpath, sort_xpath, sort_alpha, boolDesc, from, len) + jsort(n,f,p,ps,sm,desc,sp,ep) + */ + //var order, xpath, type, method, getNodes, dateFormat, dateReplace, sort_dateFmtStr, getValue; + this.apply = function(n, args, func, start, len) { + var sa = [], i = n.length; + + // build string-sortable list with sort method + while (i--) { + var v = settings.getValue(n[i]); + if (n) + sa[sa.length] = { + toString: function(){ + return this.v; + }, + xmlNode: n[i], + v: (settings.method || sort_methods.alpha)(v || "", args, n[i]) + }; + } + + // sort it + sa.sort(); + + //iterate like foreach + var end = len ? Math.min(sa.length, start + len) : sa.length; + if (!start) + start = 0; + + if (func) { + if (settings.ascending) + for (i = start; i < end; i++) + f(i, end, sa[i].xmlNode, sa[i].v); + else + for (i = end - 1; i >= start; i--) + f(end - i - 1, end, sa[i].xmlNode, sa[i].v); + } + else { + //this could be optimized by reusing n... time it later + var res = []; + if (settings.ascending) + for (i = start; i < end; i++) + res[res.length] = sa[i].xmlNode; + else + for (i = end - 1; i >= start; i--) + res[res.length] = sa[i].xmlNode; + return res; + } + }; + + if (xmlNode) + this.parseXml(xmlNode); +}; + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * The library that is used for the animations inside elements. + * + * @class apf.tween + * + * @default_private + */ +apf.tween = (function(apf) { + +var modules = { + //Animation Modules + left: function(oHtml, value) { + oHtml.style.left = value + PX; + }, + right: function(oHtml, value) { + oHtml.style.left = ""; + oHtml.style.right = value + PX; + }, + top: function(oHtml, value) { + oHtml.style.top = value + PX; + }, + bottom: function(oHtml, value) { + oHtml.style.top = ""; + oHtml.style.bottom = value + PX; + }, + width: function(oHtml, value, center) { + oHtml.style.width = value + PX; + }, + height: function(oHtml, value, center) { + oHtml.style.height = value + PX; + }, + scrollTop: function(oHtml, value, center) { + oHtml.scrollTop = value; + }, + scrollLeft: function(oHtml, value, center) { + oHtml.scrollLeft = value; + }, + paddingTop: function(oHtml, value, center) { + oHtml.style.paddingTop = value + "px"; + }, + boxFlex: function(oHtml, value, center) { + oHtml.style[apf.CSSPREFIX + "BoxFlex"] = value; + }, + "height-rsz": function(oHtml, value, center) { + oHtml.style.height = value + PX; + if (apf.hasSingleResizeEvent && apf.layout.$onresize) + apf.layout.$onresize(); + }, + mwidth: function(oHtml, value, info) { + var diff = apf.getDiff(oHtml); + oHtml.style.width = value + PX; + oHtml.style.marginLeft = -1 * (value / 2 + (parseInt(apf.getStyle(oHtml, + "borderLeftWidth")) || diff[0]/2) + (info.margin || 0)) + PX; + }, + mheight: function(oHtml, value, info) { + var diff = apf.getDiff(oHtml); + oHtml.style.height = value + PX; + oHtml.style.marginTop = (-1 * value / 2 - (parseInt(apf.getStyle(oHtml, + "borderTopWidth")) || diff[1]/2) + (info.margin || 0)) + PX; + }, + scrollwidth: function(oHtml, value) { + oHtml.style.width = value + PX; + oHtml.scrollLeft = oHtml.scrollWidth; + }, + scrollheight_old: function(oHtml, value) { + try { + oHtml.style.height = value + PX; + oHtml.scrollTop = oHtml.scrollHeight; + } + catch (e) { + alert(value) + } + }, + scrollheight: function(oHtml, value, info) { + var diff = apf.getHeightDiff(oHtml), + oInt = info.$int || oHtml; + + oHtml.style.height = Math.max((value + (info.diff || 0)), 0) + PX; + oInt.scrollTop = oInt.scrollHeight - oInt.offsetHeight - diff + + (info.diff || 0) - (apf.isGecko ? 16 : 0); //@todo where does this 16 come from?? + }, + scrolltop: function(oHtml, value) { + oHtml.style.height = value + PX; + oHtml.style.top = (-1 * value - 2) + PX; + oHtml.scrollTop = 0;//oHtml.scrollHeight - oHtml.offsetHeight; + }, + clipright: function(oHtml, value, center) { + oHtml.style.clip = "rect(auto, auto, auto, " + value + "px)"; + oHtml.style.marginLeft = (-1 * value) + PX; + }, + fade: function(oHtml, value) { + if (!apf.supportOpacity && apf.hasStyleFilters) + oHtml.style.filter = value == 1 ? "" : "alpha(opacity=" + parseInt(value * 100) + ")"; + else + oHtml.style.opacity = value; + }, + bgcolor: function(oHtml, value) { + oHtml.style.backgroundColor = value; + }, + textcolor: function(oHtml, value) { + oHtml.style.color = value; + }, + htmlcss: function(oHtml, value, obj) { + if (apf.hasStyleFilters && obj.type == "filter") + oHtml.style.filter = value == 1 ? "" : "progid:DXImageTransform.Microsoft.Alpha(opacity=" + value + ")"; + else + oHtml.style[obj.type] = value + (obj.needsPx ? PX : ""); + }, + transformscale: function(oHtml, value, obj) { + oHtml.style[obj.type] = SCALEA + parseFloat(value) + SCALEB; + }, + transformrotate: function(oHtml, value, obj) { + oHtml.style[obj.type] = ROTATEA + parseFloat(value) + ROTATEB; + }, + transformvalscale: function(value) { + return SCALEA + parseFloat(value) + SCALEB; + }, + transformvalrotate: function(value) { + return ROTATEA + parseFloat(value) + ROTATEB; + } +}; + +var ID = "id", + PX = "px", + NUM = "number", + TRANSVAL = "transformval", + TRANSFORM = "transform", + SCALE = "scale", + SCALEA = "scale(", + ROTATEA = "rotate(", + SCALEB = ")", + ROTATEB = "deg)", + CSSTIMING = ["linear", "ease-in", "ease-out", "ease", "ease-in-out", "cubic-bezier"], + CSSPROPS = { + "left" : "left", + "right" : "right", + "top" : "top", + "bottom" : "bottom", + "width" : "width", + "height" : "height", + "scrollTop" : false, + "scrollLeft" : false, + "mwidth" : false, + "mheight" : false, + "scrollwidth" : false, + "scrollheight": false, + "fade" : "opacity", + "opacity" : "opacity", + "bgcolor" : "background-color", + "textcolor" : "color", + "transform" : "transform" + }, + __pow = Math.pow, + __round = Math.round, + + queue = {}, + + current= null, + + setQueue = function(oHtml, stepFunction) { + var id = oHtml.getAttribute(ID); + if (!id) { + apf.setUniqueHtmlId(oHtml); + id = oHtml.getAttribute(ID); + } + + if (!queue[id]) + queue[id] = []; + + queue[id].push(stepFunction); + if (queue[id].length == 1) + stepFunction(0); + }, + + nextQueue = function(oHtml) { + var q = queue[oHtml.getAttribute(ID)]; + if (!q) return; + + q.shift(); //Remove current step function + + if (q.length) + q[0](0); + }, + + clearQueue = function(oHtml, bStop) { + var q = queue[oHtml.getAttribute(ID)]; + if (!q) return; + + if (bStop && current && current.control) + current.control.stop = true; + q.length = 0; + }, + + purgeQueue = function(oHtml) { + var id = oHtml.getAttribute(ID); + if (!id) { + apf.setUniqueHtmlId(oHtml); + id = oHtml.getAttribute(ID); + } + + for (var i in queue) { + if (i == id) + queue[i] = []; + } + }, + + // @TODO Doc + /** + * Calculates all the steps of an animation between a + * begin and end value based on three tween strategies + * + * @method calcSteps + * @param {Function} + func * @param {String} + fromValue * @param {String} + fromValue * @param {Number} + nrOfSteps */ + calcSteps = function(func, fromValue, toValue, nrOfSteps) { + var i = 0, + l = nrOfSteps - 1, + steps = [fromValue]; + + // backward compatibility... + if (typeof func == NUM) { + if (!func) + func = apf.tween.linear; + else if (func == 1) + func = apf.tween.easeInCubic; + else if (func == 2) + func = apf.tween.easeOutCubic; + } + + /* + func should have the following signature: + func(t, x_min, dx) + where 0 <= t <= 1, dx = x_max - x_min + + easeInCubic: function(t, x_min, dx) { + return dx * pow(t, 3) + x_min; + } + */ + for (i = 0; i < l; ++i) + steps.push(func(i / nrOfSteps, fromValue, toValue - fromValue)); + steps.push(toValue); + + return steps; + }, + + // @TODO Doc + /** + * Calculates all the steps of an animation between a + * begin and end value for colors + * + * @method calcColorSteps + * @param {Function} + animtype * @param {String} + fromValue * @param {String} + fromValue * @param {Number} + nrOfSteps */ + calcColorSteps = function(animtype, fromValue, toValue, nrOfSteps) { + var d2, d1, + c = apf.color.colorshex, + a = parseInt((c[fromValue] || fromValue).slice(1), 16), + b = parseInt((c[toValue] || toValue).slice(1), 16), + i = 0, + out = []; + + for (; i < nrOfSteps; i++){ + d1 = i / (nrOfSteps - 1), d2 = 1 - d1; + out[out.length] = "#" + ("000000" + + ((__round((a & 0xff) * d2 + (b & 0xff) * d1) & 0xff) | + (__round((a & 0xff00) * d2 + (b & 0xff00) * d1) & 0xff00) | + (__round((a & 0xff0000) * d2 + (b & 0xff0000) * d1) & 0xff0000)).toString(16)).slice(-6); + } + + return out; + }, + + // @TODO Doc wtf is stop ? + /** + * Tweens a single property of a single element or HTML element from a + * start to an end value. + * + * #### Example + * + * ```javascript + * apf.tween.single(myDiv, { + * type : "left", + * from : 10, + * to : 100, + * anim : apf.tween.EASEIN + * }); + * ``` + * + * #### Example + * + * Multiple animations can be run after each other + * by calling this function multiple times. + * + * ```javascript + * apf.tween.single(myDiv, options).single(myDiv2, options2); + * ``` + * + * @method single + * @param {DOMNode} oHtml The object to animate. + * @param {Object} info The animation settings. The following properties are available: + * - type ([[String]]): The property to be animated. These are predefined + * property handlers and can be added by adding a + * method to `apf.tween` with the name of the property + * modifier. There are several handlers available. + * - `"left"`: Sets the left position + * - `"right"`: Sets the right position + * - `"top"`: Sets the top position + * - `"bottom"`: Sets the bottom position + * - `"width"` : Sets the horizontal size + * - `"height"`: Sets the vertical size + * - `"scrollTop"`: Sets the scoll position + * - `"mwidth"` : Sets the width and the margin-left to width/2 + * - `"mheight"` : Sets the height ant the margin-top to height/2 + * - `"scrollwidth"`: Sets the width an sets the scroll to the maximum size + * - `"scrollheight"`: Sets the height an sets the scroll to the maximum size + * - `"scrolltop"` : Sets the height and the top as the negative height value + * - `"fade"` : Sets the opacity property + * - `"bgcolor"`: Sets the background color + * - `"textcolor"`: Sets the text color + * - from ([[Number]] or [[String]]): The start value of the animation + * - to ([[Number]] or [[String]]): The end value of the animation + * - [steps] ([[Number]]): The number of steps to divide the tween in + * - [interval] ([[Number]]): The time between each step + * - [anim] ([[Number]]): The distribution of change between the step over the entire animation. + * - [color] ([[Boolean]]): Specifies whether the specified values are colors + * - [userdata] (`Mixed`): Any data you would like to have available in your callback methods + * - [onfinish] ([[Function]]): A function that is called at the end of the animation + * - [oneach] ([[Function]]): A function that is called at each step of the animation + * - [control] ([[Object]]): An object that can stop the animation at any point + * Methods: + * stop set on the object passed . + */ + single = function(oHtml, info) { + info = apf.extend({steps: 10, interval: 5, anim: apf.tween.linear, control: {}}, info); + info.steps = Math.ceil(info.steps * apf.animSteps); + info.interval = Math.ceil(info.interval * apf.animInterval); + + if (oHtml.nodeFunc > 100) { + info.$int = oHtml.$int; + oHtml = oHtml.$ext; + } + try { //@TODO hack where currentStyle is still undefined + if ("fixed|absolute|relative".indexOf(apf.getStyle(oHtml, "position")) == -1) + oHtml.style.position = "relative"; + } catch (e) {} + + var useCSSAnim = (false && apf.supportCSSAnim && apf.supportCSSTransition && CSSPROPS[info.type]), + isTransform = (info.type == TRANSFORM); + + info.method = useCSSAnim ? info.type : isTransform + ? modules[TRANSFORM + (info.subType || SCALE)] + : modules[info.type] + ? modules[info.type] + : (info.needsPx = needsPix[info.type] || false) + ? modules.htmlcss + : modules.htmlcss; + + + + if (useCSSAnim) { + var type = CSSPROPS[info.type]; + if (type === false) + return apf.tween; + info.type = type || info.type; + if (isTransform) { + if (!info.subType) + info.subType = SCALE; + info.type = apf.supportCSSAnim; + } + + var transform = (isTransform) + ? modules[TRANSVAL + (info.subType || SCALE)] + : null; + + oHtml.style[info.type] = isTransform + ? transform(info.from) + : info.from + (needsPix[info.type] ? PX : ""); + $setTimeout(function() { + oHtml.style[info.type] = isTransform + ? transform(info.to) + : info.to + (needsPix[info.type] ? PX : ""); + oHtml.offsetTop; //force style recalc + oHtml.style[apf.cssPrefix + "Transition"] = info.type + " " + ((info.steps + * info.interval) / 1000) + "s " + + CSSTIMING[info.anim || 0]; + var f = function() { + if (info.onfinish) + info.onfinish(oHtml, info.userdata); + oHtml.style[apf.cssPrefix + "Transition"] = ""; + oHtml.removeEventListener(apf.cssAnimEvent, f); + }; + oHtml.addEventListener(apf.cssAnimEvent, f); + }); + return apf.tween; + } + + if (info.control) { + info.control.state = apf.tween.RUNNING; + info.control.stop = function(){ + info.control.state = apf.tween.STOPPING; + clearQueue(oHtml); + if (info.onstop) + info.onstop(oHtml, info.userdata); + } + } + + var steps = info.color + ? calcColorSteps(info.anim, info.from, info.to, info.steps) + : calcSteps(info.anim, parseFloat(info.from), parseFloat(info.to), info.steps), + stepFunction = function(step) { + if (info.control && info.control.state) { + info.control.state = apf.tween.STOPPED; + return; + } + + current = info; + + if (info.onbeforeeach + && info.onbeforeeach(oHtml, info.userdata) === false) + return; + + try { + info.method(oHtml, steps[step], info); + } + catch (e) {} + + if (info.oneach) + info.oneach(oHtml, info.userdata); + + if (step < info.steps) + return $setTimeout(function(){stepFunction(step + 1)}, info.interval); + + current = null; + if (info.control) + info.control.state = apf.tween.STOPPED; + if (info.onfinish) + info.onfinish(oHtml, info.userdata); + + nextQueue(oHtml); + }; + + if (info.type.indexOf("scroll") > -1) + purgeQueue(oHtml); + setQueue(oHtml, stepFunction); + + return apf.tween; + }, + + // @TODO Doc wtf is stop + /** + * Tweens multiple properties of a single element or html element from a + * start to an end value. + * + * #### Example + * + * Here we are, animating both the left and width at the same time: + * + * ```javascript + * apf.tween.multi(myDiv, { + * anim : apf.tween.EASEIN + * tweens : [{ + * type : "left", + * from : 10, + * to : 100, + * }, + * { + * type : "width", + * from : 100, + * to : 400, + * }] + * }); + * ```` + * + * #### Example + * + * Multiple animations can be run after each other + * by calling this function multiple times. + * + * ```javascript + * apf.tween.multi(myDiv, options).multi(myDiv2, options2); + * ``` + * + * @method multi + * @param {DOMNode} oHtml The object to animate. + * @param {Object} info The settings of the animation. It contains the following properties: + * - [steps] ([[Number]]): The number of steps to divide the tween in + * - [interval] ([[Number]]): The time between each step + * - [anim] ([[Number]]): The distribution of change between the step over + * the entire animation + * - [onfinish] ([[Function]]): A function that is called at the end of the animation + * - [oneach] ([[Function]]): A function that is called at each step of the animation + * - [oHtml] ([[HTMLElement]]): Another HTML element to animate. + * - [control] ([[Object]]): An object that can stop the animation at any point. It contains the following properties: + * - stop ([[Boolean]]): Specifies whether the animation should stop. + * - [tweens] ([[Array]]): A collection of simple objects specifying the single + * value animations that are to be executed simultaneously. + * (for the properties of these single tweens see the + * [[apf.tween.single]] method). + */ + multi = function(oHtml, info) { + info = apf.extend({steps: 10, interval: 5, anim: apf.tween.linear, control: {}}, info); + info.steps = Math.ceil(info.steps * apf.animSteps); + info.interval = Math.ceil(info.interval * apf.animInterval); + + if (oHtml.nodeFunc > 100) { + info.$int = oHtml.$int; + oHtml = oHtml.$ext; + } + + var animCSS, isTransform, + useCSSAnim = false && apf.supportCSSAnim && apf.supportCSSTransition, + hasCSSAnims = false, + cssDuration = ((info.steps * info.interval) / 1000), + cssAnim = CSSTIMING[info.anim || 0], + steps = [], + stepsTo = [], + i = 0, + l = info.tweens.length; + + for (; i < l; i++) { + var data = info.tweens[i]; + + if (data.oHtml && data.oHtml.nodeFunc > 100) { + data.$int = data.oHtml.$int; + data.oHtml = data.oHtml.$ext; + } + + animCSS = (useCSSAnim && CSSPROPS[data.type]); + isTransform = (data.type == TRANSFORM); + if (isTransform) { + if (!data.subType) + data.subType = SCALE; + data.type = apf.supportCSSAnim; + } + + data.method = animCSS + ? data.type + : isTransform + ? modules[TRANSFORM + (data.subType)] + : modules[data.type] + ? modules[data.type] + : (data.needsPx = needsPix[data.type] || false) + ? modules.htmlcss + : modules.htmlcss; + + + + + if (animCSS) { + var type = isTransform ? data.type : CSSPROPS[data.type]; + data.type = type || data.type; + var transform = modules[TRANSVAL + (data.subType)] + + oHtml.style[data.type] = isTransform + ? transform(data.from) + : data.from + (needsPix[data.type] ? PX : ""); + stepsTo.push([data.type, isTransform + ? transform(data.to) + : data.to + (needsPix[data.type] ? PX : "")]); + steps.push(data.type + " " + cssDuration + "s " + cssAnim + " 0"); + + hasCSSAnims = true; + } + else { + steps.push(data.color + ? calcColorSteps(info.anim, data.from, data.to, info.steps) + : calcSteps(info.anim, parseFloat(data.from), parseFloat(data.to), info.steps)); + } + } + + if (hasCSSAnims) { + oHtml.style[apf.cssPrefix + "Transition"] = steps.join(","); + oHtml.offsetTop; //force style recalc + var count = 0, + func = function() { + count++; + if (count == stepsTo.length) { + if (info.onfinish) + info.onfinish(oHtml, info.userdata); + oHtml.style[apf.cssPrefix + "Transition"] = ""; + oHtml.removeEventListener(apf.cssAnimEvent, func); + } + }; + oHtml.addEventListener(apf.cssAnimEvent, func, false); + for (var k = 0, j = stepsTo.length; k < j; k++) + oHtml.style[stepsTo[k][0]] = stepsTo[k][1]; + return apf.tween; + } + + if (info.control) { + info.control.state = apf.tween.RUNNING; + info.control.stop = function(){ + if (info.control.state == apf.tween.STOPPED) + return; + + info.control.state = apf.tween.STOPPING; + clearQueue(oHtml); + if (info.onstop) + info.onstop(oHtml, info.userdata); + } + } + + var tweens = info.tweens, + stepFunction = function(step) { + if (info.control && info.control.state) { + info.control.state = apf.tween.STOPPED; + return; + } + + current = info; + + try { + for (var i = 0; i < steps.length; i++) { + tweens[i].method(tweens[i].oHtml || oHtml, + steps[i][step], tweens[i]); + } + } catch (e) {} + + if (info.oneach) + info.oneach(oHtml, info.userdata); + + if (step < info.steps) + return $setTimeout(function(){stepFunction(step + 1)}, info.interval); + + current = null; + if (info.control) + info.control.state = apf.tween.STOPPED; + if (info.onfinish) + info.onfinish(oHtml, info.userdata); + + nextQueue(oHtml); + }; + + setQueue(oHtml, stepFunction); + + return apf.tween; + }, + + /** + * Tweens an element or HTML element from its current state to a CSS class. + * + * #### Example + * + * Multiple animations can be run after each other by calling this function + * multiple times. + * + * ```javascript + * apf.tween.css(myDiv, 'class1').multi(myDiv2, 'class2'); + * ``` + * + * @method apf.tween.css + * @param {DOMNode} oHtml The object to animate. + * @param {String} className The class name that defines the CSS properties to be set or removed. + * @param {Object} info The settings of the animation. The following properties are available: + * Properties: + * - [steps] ([[Number]]): The number of steps to divide the tween in + * - [interval] ([[Number]]): The time between each step + * - [anim] ([[Number]]): The distribution of change between the step over the entire animation + * - [onfinish] ([[Function]]): A function that is called at the end of the animation + * - [oneach] ([[Function]]): A function that is called at each step of the animation + * - [control] ([[Object]]): An object that can stop the animation at any point. It contains the following property: + * - stop ([[Boolean]]): Specifies whether the animation should stop. + * @param {Boolean} remove Specifies whether the class is set or removed from the element + */ + css = function(oHtml, className, info, remove) { + (info = info || {}).tweens = []; + + if (oHtml.nodeFunc > 100) + oHtml = oHtml.$ext; + + if (remove) + apf.setStyleClass(oHtml, "", [className]); + + var resetAnim = function(remove, callback) { + if (remove) + apf.setStyleClass(oHtml, "", [className]); + else + apf.setStyleClass(oHtml, className); + + //Reset CSS values + for (var i = 0; i < info.tweens.length; i++){ + if (info.tweens[i].type == "filter") + continue; + + oHtml.style[info.tweens[i].type] = ""; + } + + if (callback) + callback.apply(this, arguments); + } + + var onfinish = info.onfinish, + onstop = info.onstop; + info.onfinish = function(){resetAnim(remove, onfinish);} + info.onstop = function(){resetAnim(!remove, onstop);} + + var result, newvalue, curvalue, j, isColor, style, rules, i, + tweens = {}; + for (i = 0; i < document.styleSheets.length; i++) { + rules = document.styleSheets[i][apf.styleSheetRules]; + if (!rules || !rules.length) + continue; + for (j = rules.length - 1; j >= 0; j--) { + var rule = rules[j]; + + if (!rule.style || !rule.selectorText.match("\." + className + "$")) + continue; + + for (style in rule.style) { + if (!rule.style[style] || cssProps.indexOf("|" + style + "|") == -1) + continue; + + if (style == "filter") { + if (!rule.style[style].match(/opacity\=([\d\.]+)/)) + continue; + newvalue = RegExp.$1; + + result = (apf.getStyleRecur(oHtml, style) || "") + .match(/opacity\=([\d\.]+)/); + curvalue = result ? RegExp.$1 : 100; + isColor = false; + + if (newvalue == curvalue) { + if (remove) curvalue = 100; + else newvalue = 100; + } + } + else { + newvalue = remove && oHtml.style[style] || rule.style[style]; + if (remove) oHtml.style[style] = ""; + curvalue = apf.getStyleRecur(oHtml, style); + isColor = style.match(/color/i) ? true : false; + } + + tweens[style] = { + type: style, + from: (isColor ? String : parseFloat)(remove + ? newvalue + : curvalue), + to: (isColor ? String : parseFloat)(remove + ? curvalue + : newvalue), + color: isColor, + needsPx: needsPix[style.toLowerCase()] || false + }; + } + } + } + + for (var prop in tweens) + info.tweens.push(tweens[prop]); + + if (remove) + apf.setStyleClass(oHtml, className); + + return multi(oHtml, info); + }, + + cssRemove = function(oHtml, className, info) { + css(oHtml, className, info, true); + }, + + needsPix = { + "left" : true, + "top" : true, + "bottom" : true, + "right" : true, + "width" : true, + "height" : true, + "fontSize" : true, + "lineHeight" : true, + "textIndent" : true, + "marginLeft" : true, + "marginTop" : true, + "marginRight" : true, + "marginBottom": true + }, + + cssProps = "|backgroundColor|backgroundPosition|color|width|filter" + + "|height|left|top|bottom|right|fontSize" + + "|letterSpacing|lineHeight|textIndent|opacity" + + "|paddingLeft|paddingTop|paddingRight|paddingBottom" + + "|borderLeftWidth|borderTopWidth|borderRightWidth|borderBottomWidth" + + "|borderLeftColor|borderTopColor|borderRightColor|borderBottomColor" + + "|marginLeft|marginTop|marginRight|marginBottom" + + "|transform|", // transforms are special and get special treatment + cssTransforms = "|scale|rotate|"; + +return { + single: single, + multi: multi, + css: css, + cssRemove: cssRemove, + clearQueue: clearQueue, + addModule: function(name, func, force) { + if (typeof name != "string" || typeof func != "function" || (modules[name] && !force)) + return this; + modules[name] = func; + return this; + }, + /** Linear tweening method */ + NORMAL: 0, + /** Ease-in tweening method */ + EASEIN: 1, + /** Ease-out tweening method */ + EASEOUT: 2, + + RUNNING: 0, + STOPPING: 1, + STOPPED: 2, + + calcColorSteps: calcColorSteps, + + linear: function(t, x_min, dx) { + return dx * t + x_min; + }, + easeInQuad: function(t, x_min, dx) { + return dx * __pow(t, 2) + x_min; + }, + easeOutQuad: function(t, x_min, dx) { + return -dx * t * (t - 2) + x_min; + }, + easeInOutQuad: function(t, x_min, dx) { + if ((t /= .5) < 1) + return dx / 2 * t * t + x_min; + return -dx / 2 * ((--t) * (t - 2) - 1) + x_min; + }, + easeInCubic: function(t, x_min, dx) { + return dx * __pow(t, 3) + x_min; + }, + easeOutCubic: function(t, x_min, dx) { + return dx * (__pow(t - 1, 3) + 1) + x_min; + }, + easeInOutCubic: function(t, x_min, dx) { + if ((t /= .5) < 1) + return dx / 2 * __pow(t, 3) + x_min; + return dx / 2 * (__pow(t - 2, 3) + 2) + x_min; + }, + easeInQuart: function(t, x_min, dx) { + return dx * __pow(t, 4) + x_min; + }, + easeOutQuart: function(t, x_min, dx) { + return -dx * (__pow(t - 1, 4) - 1) + x_min; + }, + easeInOutQuart: function(t, x_min, dx) { + if ((t /= .5) < 1) + return dx / 2 * __pow(t, 4) + x_min; + return -dx / 2 * (__pow(t - 2, 4) - 2) + x_min; + }, + easeInQuint: function(t, x_min, dx) { + return dx * __pow(t, 5) + x_min; + }, + easeOutQuint: function(t, x_min, dx) { + return dx * (__pow(t - 1, 5) + 1) + x_min; + }, + easeInOutQuint: function(t, x_min, dx) { + if ((t /= .5) < 1) + return dx / 2 * __pow(t, 5) + x_min; + return dx / 2 * (__pow(t - 2, 5) + 2) + x_min; + }, + easeInSine: function(t, x_min, dx) { + return -dx * Math.cos(t * (Math.PI / 2)) + dx + x_min; + }, + easeOutSine: function(t, x_min, dx) { + return dx * Math.sin(t * (Math.PI / 2)) + x_min; + }, + easeInOutSine: function(t, x_min, dx) { + return -dx / 2 * (Math.cos(Math.PI * t) - 1) + x_min; + }, + easeInExpo: function(t, x_min, dx) { + return (t == 0) ? x_min : dx * __pow(2, 10 * (t - 1)) + x_min; + }, + easeOutExpo: function(t, x_min, dx) { + return (t == 1) ? x_min + dx : dx * (-__pow(2, -10 * t) + 1) + x_min; + }, + easeInOutExpo: function(t, x_min, dx) { + if (t == 0) + return x_min; + if (t == 1) + return x_min + dx; + if ((t /= .5) < 1) + return dx / 2 * __pow(2, 10 * (t - 1)) + x_min; + return dx / 2 * (-__pow(2, -10 * --t) + 2) + x_min; + }, + easeInCirc: function(t, x_min, dx) { + return -dx * (Math.sqrt(1 - t * t) - 1) + x_min; + }, + easeOutCirc: function(t, x_min, dx) { + return dx * Math.sqrt(1 - (t -= 1) * t) + x_min; + }, + easeInOutCirc: function(t, x_min, dx) { + if ((t /= .5) < 1) + return -dx / 2 * (Math.sqrt(1 - t * t) - 1) + x_min; + return dx / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1) + x_min; + }, + easeInElastic: function(t, x_min, dx) { + var s = 1.70158, + p = .3, + a = dx; + if (t == 0) + return x_min; + if (t == 1) + return x_min + dx; + if (!a || a < Math.abs(dx)) { + a = dx; + s = p / 4; + } + else + s = p / (2 * Math.PI) * Math.asin (dx / a); + return -(a * __pow(2, 10 * (t -= 1)) * Math.sin((t * 1 - s) * (2 * Math.PI) / p)) + x_min; + }, + easeOutElastic: function(t, x_min, dx) { + var s = 1.70158, + p = .3, + a = dx; + if (t == 0) + return x_min; + if (t == 1) + return x_min + dx; + if (a < Math.abs(dx)) { + a = dx; + s = p / 4; + } + else { + s = p / (2 * Math.PI) * Math.asin(dx / a); + } + return a * __pow(2, -10 * t) * Math.sin((t - s) * (2 * Math.PI) / p) + dx + x_min; + }, + easeInOutElastic: function(t, x_min, dx) { + var s = 1.70158, + p = 0, + a = dx; + if (t == 0) + return x_min; + if ((t / 2) == 2) + return x_min + dx; + if (!p) + p = .3 * 1.5; + if (a < Math.abs(dx)) { + a = dx; + s = p / 4; + } + else { + s = p / (2 * Math.PI) * Math.asin(dx / a); + } + if (t < 1) + return -.5 * (a * __pow(2, 10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p)) + x_min; + return a * __pow(2, -10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p) * .5 + dx + x_min; + }, + easeInBack: function(t, x_min, dx) { + var s = 1.70158; + return dx * __pow(t, 2) * ((s + 1) * t - s) + x_min; + }, + easeOutBack: function(t, x_min, dx) { + var s = 1.70158; + return dx * ((t -= 1) * t * ((s + 1) * t + s) + 1) + x_min; + }, + easeInOutBack: function(t, x_min, dx) { + var s = 1.70158; + if ((t / 2) < 1) + return dx / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + x_min; + return dx / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + x_min; + }, + easeInBounce: function(t, x_min, dx) { + return dx - apf.tween.easeOutBounce(1 - t, 0, dx) + x_min; + }, + easeOutBounce: function(t, x_min, dx) { + if (t < (1 / 2.75)) + return dx * (7.5625 * t * t) + x_min; + else if (t < (2 / 2.75)) + return dx * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + x_min; + else if (t < (2.5 / 2.75)) + return dx * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + x_min; + else + return dx * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + x_min; + }, + easeInOutBounce: function(t, x_min, dx) { + if (t < 1 / 2) + return apf.tween.easeInBounce(t * 2, 0, dx) * .5 + x_min; + return apf.tween.easeOutBounce(t * 2 - 1, 0, dx) * .5 + dx * .5 + x_min; + } +}; + +})(apf); + + + + + + + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * The XML database object provides local storage for XML data. This object + * routes all changes to the XML data to the data bound objects. It also + * provides utility functions for XML handling. + * + * @class apf.xmldb + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.8 + * @additional + * + * @default_private + */ +apf.xmldb = new (function(){ + var _self = this; + + this.xmlDocTag = "a_doc"; + this.xmlIdTag = "a_id"; + this.xmlListenTag = "a_listen"; + this.htmlIdTag = "id"; + this.disableRDB = false; + + this.$xmlDocLut = []; + this.$nodeCount = {}; + + var cleanRE = / (?:a_doc|a_id|a_listen|a_loaded)=(?:"|')[^'"]+(?:"|')/g, + whiteRE = />[\s\n\r\t]+= 0; i--) { + if (lut[ids[i]]) { + delete this.$listeners[ids[i]]; + delete lut[ids[1]]; + } + } + + xmlNode.setAttribute(this.xmlListenTag, Object.keys(lut).join(";"));// + ";" + } + + /* + * @todo Use this function when an element really unbinds from a + * piece of data and does not uses it for caching + * @private + */ + this.removeNodeListener = function(xmlNode, o, id) { + var listen = xmlNode.getAttribute(this.xmlListenTag); + var nodes = (listen ? listen.split(";") : []); + if (id && id.charAt(0) == "p") { + id = this.$listeners[id]; + delete this.$listeners[id]; + } + else { + id = "e" + o.$uniqueId; + + + } + + for (var newnodes = [], i = 0; i < nodes.length; i++) { + if (nodes[i] != id) + newnodes.push(nodes[i]); + } + + xmlNode.setAttribute(this.xmlListenTag, newnodes.join(";"));// + ";" + + return xmlNode; + }; + + /** + * Sets the value of a text node. If the node doesn't exist, it is created. + * + * Changes are propagated to the databound elements listening for changes + * on the data changed. + * + * @param {XMLElement} pNode The parent of the text node. + * @param {String} value The value of the text node. + * @param {String} [xpath] The xpath statement which selects the text node. + * @param {apf.UndoData} [undoObj] The undo object that is responsible for archiving the changes. + */ + this.setTextNode = + apf.setTextNode = function(pNode, value, xpath, undoObj, range) { + var tNode; + + if (xpath) { + tNode = pNode.selectSingleNode(xpath); + if (!tNode) + return; + pNode = tNode.nodeType == 1 ? tNode : null; + } + if (pNode.nodeType != 1) + tNode = pNode; + else if (pNode || !tNode) { + tNode = pNode.selectSingleNode("text()"); + + if (!tNode) + tNode = pNode.appendChild(pNode.ownerDocument.createTextNode(""));//createCDATASection + } + + //Action Tracker Support + if (undoObj && !undoObj.$filled) { + undoObj.extra.oldValue = tNode.nodeValue; + undoObj.$filled = true; + } + + //Apply Changes + if (range) { //@todo apf3.0 range + undoObj.extra.range = range; + + } + else { + tNode.nodeValue = value; + + if (tNode.$regbase) + tNode.$setValue(value); + } + + this.applyChanges("text", tNode.parentNode, undoObj); + + + this.applyRDB(["setTextNode", pNode, value, xpath], undoObj || {xmlNode: pNode}); //@todo apf3.0 for range support + + }; + + /** + * Sets an attribute on a node. Changes are propagated to the databound + * elements listening for changes on the data changed. + * + * @param {XMLElement} xmlNode The XML node to set the attribute on. + * @param {String} name The name of the attribute. + * @param {String} value The value of the attribute. + * @param {String} [xpath] The xpath statement to select the attribute. + * @param {apf.UndoData} [undoObj] The undo object that is responsible for archiving the changes. + */ + this.setAttribute = + apf.setAttribute = function(xmlNode, name, value, xpath, undoObj, range) { + //Action Tracker Support + if (undoObj && !undoObj.$filled) { + undoObj.name = name; + undoObj.$filled = true; + } + + //Apply Changes + if (range) { //@todo apf3.0 range + undoObj.extra.range = range; + } + else + (xpath ? xmlNode.selectSingleNode(xpath) : xmlNode).setAttribute(name, value); + + this.applyChanges("attribute", xmlNode, undoObj); + + this.applyRDB(["setAttribute", xmlNode, name, value, xpath], undoObj || {xmlNode: xmlNode}); //@todo apf3.0 for range support + + }; + + /** + * Removes an attribute of an XML node. Changes are propagated to the + * databound elements listening for changes on the data changed. + * + * @param {XMLElement} xmlNode The XML node to delete the attribute from + * @param {String} name The name of the attribute. + * @param {String} [xpath] The xpath statement to select the attribute. + * @param {apf.UndoData} [undoObj] The undo object that is responsible for archiving the changes. + */ + this.removeAttribute = + apf.removeAttribute = function(xmlNode, name, xpath, undoObj) { + //if(xmlNode.nodeType != 1) xmlNode.nodeValue = value; + + //Action Tracker Support + if (undoObj && !undoObj.$filled) { + undoObj.name = name; + undoObj.$filled = true; + } + + //Apply Changes + (xpath ? xmlNode.selectSingleNode(xpath) : xmlNode).removeAttribute(name); + this.applyChanges("attribute", xmlNode, undoObj); + + + this.applyRDB(["removeAttribute", xmlNode, name, xpath], undoObj || {xmlNode: xmlNode}); + + }; + + /** + * Replace one node with another. Changes are propagated to the + * databound elements listening for changes on the data changed. + * + * @param {XMLElement} oldNode The XML node to remove. + * @param {XMLElement} newNode The XML node to set. + * @param {String} [xpath] The xpath statement to select the attribute. + * @param {apf.UndoData} [undoObj] The undo object that is responsible for archiving the changes. + */ + this.replaceNode = + apf.replaceNode = function(newNode, oldNode, xpath, undoObj) { + //if(xmlNode.nodeType != 1) xmlNode.nodeValue = value; + + //Apply Changes + if (xpath) + oldNode = oldNode.selectSingleNode(xpath); + + // @todo: only do this once! - should store on the undo object + if (oldNode.ownerDocument.importNode && newNode.ownerDocument != oldNode.ownerDocument) { + var oldNodeS = newNode; + newNode = oldNode.ownerDocument.importNode(newNode, true); //Safari issue not auto importing nodes + if (oldNodeS.parentNode) + oldNodeS.parentNode.removeChild(oldNodeS); + } + + + this.applyRDB(["replaceNode", oldNode, this.cleanXml(newNode.xml), xpath], undoObj || {xmlNode: oldNode}); + + + //Action Tracker Support + if (undoObj && !undoObj.$filled) { + undoObj.$filled = true; + undoObj.oldNode = oldNode; + undoObj.xmlNode = newNode; + } + + this.cleanNode(newNode); + + var parentNode = oldNode.parentNode; + if (!parentNode) + return; + + parentNode.replaceChild(newNode, oldNode); + this.copyConnections(oldNode, newNode); + + this.applyChanges("replacenode", newNode, undoObj); + + return newNode; + }; + + /** + * Creates a new element under a parent XML node. Changes are propagated + * to the databound elements listening for changes on the data changed. + * + * @param {XMLElement} pNode The parent XML node to add the new element to. + * @param {String} tagName The tagName of the {@link term.datanode data node} to add. + * @param {Array} attr list of the attributes to set. Each item is another array with the name and value. + * @param {XMLElement} beforeNode The XML node which indicates the insertion point. + * @param {String} [xpath] The xpath statement to select the attribute. + * @param {apf.UndoData} [undoObj] The undo object that is responsible for archiving the changes. + */ + this.addChildNode = + apf.addChildNode = function(pNode, tagName, attr, beforeNode, undoObj) { + //Create New Node + var xmlNode = pNode.insertBefore(pNode.ownerDocument + .createElement(tagName), beforeNode); + + //Set Attributes + for (var i = 0; i < attr.length; i++) + xmlNode.setAttribute(attr[i][0], attr[i][1]); + + //Action Tracker Support + if (undoObj && !undoObj.$filled) { + undoObj.extra.addedNode = xmlNode; + undoObj.$filled = true; + } + + this.applyChanges("add", xmlNode, undoObj); + + + this.applyRDB(["addChildNode", pNode, tagName, attr, beforeNode], undoObj || {xmlNode: pNode}); + + + return xmlNode; + }; + + /** + * Appends an XML node to a parent. Changes are propagated + * to the databound elements listening for changes on the data changed. + * + * @param {XMLElement} pNode The parent XML node to add the element to. + * @param {XMLElement} xmlNode The XML node to insert. + * @param {XMLElement} beforeNode The XML node which indicates the insertion point. + * @param {Boolean} unique Specifies whether the parent can only contain one element with a certain tag name. + * @param {String} [xpath] The xpath statement to select the parent node. + * @param {apf.UndoData} [undoObj] The undo object that is responsible for archiving the changes. + */ + this.appendChild = + apf.appendChild = function(pNode, xmlNode, beforeNode, unique, xpath, undoObj) { + if (pNode == xmlNode.parentNode) //Shouldn't this be the same document? + return apf.xmldb.moveNode(pNode, xmlNode, beforeNode, null, xpath, undoObj); + + if (unique && pNode.selectSingleNode(xmlNode.tagName)) + return false; + + // @todo: only do this once! - should store on the undo object + if (pNode.ownerDocument.importNode && pNode.ownerDocument != xmlNode.ownerDocument) { + var oldNode = xmlNode; + xmlNode = pNode.ownerDocument.importNode(xmlNode, true); //Safari issue not auto importing nodes + if (oldNode.parentNode) + oldNode.parentNode.removeChild(oldNode); + } + + + this.applyRDB(["appendChild", pNode, this.cleanXml(xmlNode.xml), beforeNode, unique, xpath], undoObj || {xmlNode: pNode}); + + + //Add xmlNode to parent pNode or one selected by xpath statement + if (xpath) { + var addedNodes = []; + pNode = apf.createNodeFromXpath(pNode, xpath, addedNodes); + if (addedNodes.length) { + pNode.appendChild(xmlNode); + while (addedNodes.length) { + if (pNode == addedNodes.pop() && addedNodes.length) + pNode = pNode.parentNode; + } + } + } + else if (xmlNode.parentNode) + this.removeNode(xmlNode); + + if (undoObj && !undoObj.$filled) { + undoObj.$filled = true; + this.cleanNode(xmlNode); + } + else + this.cleanNode(xmlNode); + + pNode.insertBefore(xmlNode, beforeNode); + + //detect if xmlNode should be removed somewhere else + //- [17-2-2004] changed pNode (2nd arg applychange) into xmlNode + + this.applyChanges("add", xmlNode, undoObj); + + return xmlNode; + }; + + /** + * Moves an XML node to a parent node. Changes are propagated + * to the databound elements listening for changes on the data changed. + * + * @param {XMLElement} pNode The new parent XML node of the node. + * @param {XMLElement} xmlNode The XML node to move. + * @param {XMLElement} beforeNode The XML node which indicates the insertion point. + * @param {String} [xpath] The xpath statement to select the parent node. + * @param {apf.UndoData} [undoObj] The undo object that is responsible for archiving the changes. + */ + this.moveNode = + apf.moveNode = function(pNode, xmlNode, beforeNode, xpath, undoObj) { + //Action Tracker Support + if (!undoObj) + undoObj = {extra:{}}; + + undoObj.extra.oldParent = xmlNode.parentNode; + undoObj.extra.beforeNode = xmlNode.nextSibling; + undoObj.extra.parent = (xpath ? pNode.selectSingleNode(xpath) : pNode); + + this.applyChanges("move-away", xmlNode, undoObj); + + //Set new id if the node change document (for safari this should be fixed) + //@todo I don't get this if... + /*if (!apf.isWebkit + && xmlNode.getAttribute(this.xmlIdTag) + && apf.xmldb.getXmlDocId(xmlNode) != apf.xmldb.getXmlDocId(pNode)) { + xmlNode.removeAttribute(this.xmlIdTag)); + this.nodeConnect(apf.xmldb.getXmlDocId(pNode), xmlNode); + }*/ + + // @todo: only do this once! - should store on the undo object + if (pNode.ownerDocument.importNode && pNode.ownerDocument != xmlNode.ownerDocument) { + var oldNode = xmlNode; + xmlNode = pNode.ownerDocument.importNode(xmlNode, true); //Safari issue not auto importing nodes + if (oldNode.parentNode) + oldNode.parentNode.removeChild(oldNode); + } + + + this.applyRDB(["moveNode", pNode, xmlNode, beforeNode, xpath], undoObj || {xmlNode: pNode}); //note: important that transport of rdb is async + + + undoObj.extra.parent.insertBefore(xmlNode, beforeNode); + this.applyChanges("move", xmlNode, undoObj); + }; + + /** + * Removes an XML node from its parent. Changes are propagated + * to the databound elements listening for changes on the data changed. + * + * @param {XMLElement} xmlNode The XML node to remove from the dom tree. + * @param {String} [xpath] The xpath statement to select the parent node. + * @param {apf.UndoData} [undoObj] The undo object that is responsible for archiving the changes. + */ + this.removeNode = + apf.removeNode = function(xmlNode, xpath, undoObj) { + if (xpath) + xmlNode = xmlNode.selectSingleNode(xpath); + + //ActionTracker Support + if (undoObj && !undoObj.$filled) { + undoObj.$filled = true; + undoObj.extra.parent = xmlNode.parentNode; + undoObj.extra.removedNode = xmlNode; + undoObj.extra.beforeNode = xmlNode.nextSibling; + } + + + this.applyRDB(["removeNode", xmlNode, xpath], undoObj || {xmlNode: xmlNode}); //note: important that transport of rdb is async + + + //Apply Changes + this.applyChanges("remove", xmlNode, undoObj); + var p = xmlNode.parentNode; + if (!p) + return; + + p.removeChild(xmlNode); + this.applyChanges("redo-remove", xmlNode, null, p);//undoObj + + //@todo clean xmlNode after removal?? + }; + + /** + * Removes a list of XML nodes from their parent. Changes are propagated + * to the databound elements listening for changes on the data changed. + * + * @param {Array} xmlNodeList A list of XML nodes to remove. + * @param {apf.UndoData} [undoObj] The undo object that is responsible for archiving the changes. + */ + this.removeNodeList = + apf.removeNodeList = function(xmlNodeList, undoObj) { + + this.applyRDB(["removeNodeList", xmlNodeList, null], undoObj || {xmlNode: p}); + + + //if(xpath) xmlNode = xmlNode.selectSingleNode(xpath); + for (var rData = [], i = 0; i < xmlNodeList.length; i++) { //This can be optimized by looping nearer to xmlUpdate + //ActionTracker Support + if (undoObj) { + rData.push({ + pNode: xmlNodeList[i].parentNode, + removedNode: xmlNodeList[i], + beforeNode: xmlNodeList[i].nextSibling + }); + } + + //Apply Changes + this.applyChanges("remove", xmlNodeList[i], undoObj); + var p = xmlNodeList[i].parentNode; + p.removeChild(xmlNodeList[i]); + this.applyChanges("redo-remove", xmlNodeList[i], null, p);//undoObj + } + + if (undoObj && !undoObj.$filled) { + undoObj.$filled = true; + undoObj.extra.removeList = rData; + } + }; + + /* + * Looks for this.$listeners and executes their $xmlUpdate methods. + * @private + */ + var notifyQueue = {}, notifyTimer; + this.$hasQueue = false; + this.applyChanges = function(action, xmlNode, undoObj, nextloop) { + if (undoObj && undoObj.$dontapply) return; + + + if (undoObj && !undoObj.xmlNode) //@todo are we sure about this? + undoObj.xmlNode = xmlNode; + + //Set Variables + var oParent = nextloop, + loopNode = (xmlNode.nodeType == 1 ? xmlNode : xmlNode.parentNode); + + //var xmlId = xmlNode.getAttribute(this.xmlIdTag); + + if (!this.delayUpdate && "|remove|move-away|".indexOf("|" + action + "|") > -1) + this.notifyQueued(); //empty queue + + var listen, uId, uIds, i, j, hash, info, amlNode, runTimer, found, done = {}; + while (loopNode && loopNode.nodeType == 1) { + //Get List of Node this.$listeners ID's + listen = loopNode.getAttribute(this.xmlListenTag); + + if (listen) { + uIds = listen.split(";"); + + for (i = 0; i < uIds.length; i++) { + uId = uIds[i]; + if (!uId || done[uId]) continue; + done[uId] = true; + + //Property support + /*if (uId.charAt(0) == "p") { + uId = uId.split("|"); + + //@todo apf3.0 should this be exactly like in class.js? + //@todo optimize this to check the async flag: parsed[3] & 4 + + amlNode = apf.all[uId[1]]; //It's possible the aml node dissapeared in this loop. + if (amlNode) { + var model = apf.all[uId[3]]; + var xpath = model.$propBinds[uId[1]][uId[2]].root; + + amlNode.$execProperty(uId[2], xpath + ? model.data.selectSingleNode(xpath) + : model.data); + } + continue; + }*/ + + hash = notifyQueue[uId]; + if (!hash) + notifyQueue[uId] = hash = []; + + // Filtering + if (!apf.isO3 && "|update|attribute|text|".indexOf("|" + action + "|") > -1) { + found = false; + for (j = 0; j < hash.length; j++) { + if (hash[j] && xmlNode == hash[j][1] + && "|update|attribute|text|" + .indexOf("|" + hash[j][0] + "|") > -1) { + hash[j] = null; + found = true; + continue; + } + } + + hash.push([action, xmlNode, loopNode, undoObj, oParent]); + runTimer = true; + continue; + } + + //!this.delayUpdate && <- that doesnt work because of information that is destroyed + if (apf.isO3 || "|remove|move-away|move|add|".indexOf("|" + action + "|") > -1) { + if (this.$listeners[uId]) { + this.$listeners[uId]([action, xmlNode, + loopNode, undoObj, oParent]); + } + /*amlNode = apf.all[uId]; + if (amlNode) + amlNode.$xmlUpdate(action, xmlNode, + loopNode, undoObj, oParent);*/ + } + else { + hash.push([action, xmlNode, loopNode, undoObj, oParent]); + runTimer = true; + } + } + } + + //Go one level up + loopNode = loopNode.parentNode || nextloop; + if (loopNode == nextloop) + nextloop = null; + } + + if (true || undoObj && !this.delayUpdate) { + //Ok this was an action let's not delay execution + apf.xmldb.notifyQueued(); + } + else if (runTimer) { + apf.setZeroTimeout.clearTimeout(notifyTimer); + //@todo find a better solution for this (at the end of a event stack unroll) + this.$hasQueue = true; + notifyTimer = apf.setZeroTimeout(function(){ + //this.$hasQueue = true; + apf.xmldb.notifyQueued(); + }); + } + }; + + /* + * @todo in actiontracker - add stack auto purging + * - when undo item is purged which was a removed, remove cache item + * @todo shouldn't the removeNode method remove all this.$listeners? + * @todo rename to processQueue + * @private + */ + this.notifyQueued = function(){ + this.$hasQueue = false; + + var myQueue = notifyQueue; + notifyQueue = {}; + + apf.setZeroTimeout.clearTimeout(notifyTimer); + for (var uId in myQueue) { + if (!uId) continue; + + var q = myQueue[uId]; + var func = this.$listeners[uId]; + //!amlNode || + if (!q || !func) + continue; + + //Run queue items + for (var i = 0; i < q.length; i++) { + if (!q[i]) + continue; + + //Update xml data + //amlNode.$xmlUpdate.apply(amlNode, q[i]); + func(q[i]); + } + } + + + }; + + /** + * @private + */ + this.notifyListeners = function(xmlNode) { + //This should be done recursive + var listen = xmlNode.getAttribute(apf.xmldb.xmlListenTag); + if (listen) { + listen = listen.split(";"); + for (var j = 0; j < listen.length; j++) { + apf.all[listen[j]].$xmlUpdate("synchronize", xmlNode, xmlNode); + //load(xmlNode); + } + } + }; + + + /* + * Sends Message through transport to tell remote databound this.$listeners + * that data has been changed + * @private + */ + this.applyRDB = function(args, undoObj) { + return; + + var xmlNode = undoObj.localName || !undoObj.xmlNode + ? args[1] && args[1].length && args[1][0] || args[1] + : undoObj.xmlNode; + + if (xmlNode.nodeType == 2) + xmlNode = xmlNode.ownerElement || xmlNode.selectSingleNode(".."); + + var mdlId = apf.xmldb.getXmlDocId(xmlNode), + model = apf.nameserver.get("model", mdlId); + if (!model && apf.isO3) + model = self[mdlId]; + if (!model) { + if (!apf.nameserver.getAll("remote").length) + return; + + return; + } + + if (!model.rdb) return; + var rdb = model.rdb; + + // Add the messages to the undo object + if (undoObj.action) + rdb.$queueMessage(args, model, undoObj); + // Or send message now + else { + clearTimeout(rdb.queueTimer); + + rdb.$queueMessage(args, model, rdb); + // use a timeout to batch consecutive calls into one RDB call + rdb.queueTimer = $setTimeout(function() { + rdb.$processQueue(rdb); + }); + } + + }; + + + /** + * @private + */ + this.copyConnections = function(fromNode, toNode) { + //This should copy recursive + try { + toNode.setAttribute(this.xmlListenTag, fromNode.getAttribute(this.xmlListenTag)); + } + catch (e) {} + try { + toNode.setAttribute(this.xmlIdTag, fromNode.getAttribute(this.xmlIdTag)); + } + catch (e) {} + }; + + /** + * @private + */ + this.cleanXml = function(xml) { + if (typeof xml != "string") + return xml; + return xml.replace(cleanRE, "").replace(whiteRE, "><"); + }; + + /** + * @private + */ + this.cleanNode = function(xmlNode) { + try { + var i, nodes = xmlNode.selectNodes("descendant-or-self::node()[@" + this.xmlListenTag + "]"); + for (i = nodes.length - 1; i >= 0; i--) + nodes[i].removeAttribute(this.xmlListenTag); + nodes = xmlNode.selectNodes("descendant-or-self::node()[@" + this.xmlIdTag + "]"); + for (i = nodes.length - 1; i >= 0; i--) + nodes[i].removeAttribute(this.xmlIdTag); + nodes = xmlNode.selectNodes("descendant-or-self::node()[@" + this.xmlDocTag + "]"); + for (i = nodes.length - 1; i >= 0; i--) + nodes[i].removeAttribute(this.xmlDocTag); + nodes = xmlNode.selectNodes("descendant-or-self::node()[@a_loaded]"); + for (i = nodes.length - 1; i >= 0; i--) + nodes[i].removeAttribute("a_loaded"); + } + catch (e) {} + + return xmlNode; + }; + + /** + * Returns a copy of the passed {@link term.datanode data node}. Bound + * data nodes contain special attributes to track them. These attributes + * are removed from the copied node when using this method. + * + * @param {XMLElement} xmlNode The {@link term.datanode data node} to copy. + * @return {XMLElement} The copy of the {@link term.datanode data node}. + */ + this.copy = + this.getCleanCopy = + apf.getCleanCopy = function(xmlNode) { + return apf.xmldb.cleanNode(xmlNode.cloneNode(true)); + }; + + /** + * Unbind all APF Elements from a certain Form + * @private + */ + this.unbind = function(frm) { + //Loop through objects of all apf + for (var lookup = {}, i = 0; i < frm.apf.all.length; i++) + if (frm.apf.all[i] && frm.apf.all[i].unloadBindings) + lookup[frm.apf.all[i].unloadBindings()] = true; + + //Remove Listen Nodes + for (var k = 0; k < this.$xmlDocLut.length; k++) { + + if (!this.$xmlDocLut[k]) continue; + + + var Nodes = this.$xmlDocLut[k].selectNodes("//self::node()[@" + + this.xmlListenTag + "]"); + if (!Nodes) continue; + + //Loop through Nodes and rebuild listen array + for (var i = 0; i < Nodes.length; i++) { + var listen = Nodes[i].getAttribute(this.xmlListenTag).split(";"); + for (var nListen = [], j = 0; j < listen.length; j++) + if (!lookup[listen[j]]) + nListen.push(listen[j]); + + //Optimization?? + if (nListen.length != listen.length) + Nodes[i].setAttribute(this.xmlListenTag, nListen.join(";")); + } + } + + if (window.clearInterval) + window.clearInterval(this.$gcInterval); + }; + + /* + * @private + * @todo xml doc leakage + */ + this.getXmlDocId = function(xmlNode, model) { + var docEl = xmlNode.ownerDocument.documentElement; + if (!apf.isChildOf(docEl, xmlNode)) + docEl = xmlNode; + + var docId = (docEl || xmlNode).getAttribute(this.xmlDocTag) + || this.$xmlDocLut.indexOf(docEl || xmlNode.ownerDocument || xmlNode); + + if (model && apf.nameserver.get("model", docId) != model) { + docId = null; + docEl = xmlNode; + } + + if (!docId || docId == -1) { + docId = this.$xmlDocLut.push(docEl || xmlNode.ownerDocument || xmlNode) - 1; + if (docEl) + docEl.setAttribute(this.xmlDocTag, String(docId)); + } + + if (model) + apf.nameserver.register("model", docId, model); + + + return docId; + }; +}); + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * @class apf.http + * + * This object does what is commonly known as Ajax; it **A**synchronously + * communicates using **J**avaScript, **A**nd in most + * cases it sends or receives **X**ml. It allows for easy HTTP + * communication from within the browser. + * + * This object provides caching on top of + * the browser's cache. This enables you to optimize your application, because + * this can be set on a per call basis. + * + * #### Example: + * + * Retrieving content over HTTP synchronously: + * + * ```javascript + * var http = new apf.http(); + * var data = http.get("http://www.example.com/mydata.jsp", {async: false}); + * alert(data); + * ``` + * + * #### Example: + * + * Retrieving content over HTTP asynchronously: + * + * ```javascript + * var http = new apf.http(); + * http.get("http://www.example.com/mydata.jsp", { + * callback: function(data, state, extra) { + * if (state != apf.SUCCESS) + * return alert('an error has occurred'); + * + * alert(data); + * } + * }); + * ``` + * + * #### Example: + * + * An asynchronous HTTP request, with retry: + * + * ```javascript + * var http = new apf.http(); + * http.get("http://www.example.com/mydata.jsp", { + * callback: function(data, state, extra) { + * if (state != apf.SUCCESS) { + * var oError = new Error(apf.formatErrorString(0, null, + * "While loading data", "Could not load data\n" + extra.message)); + * + * if (extra.tpModule.retryTimeout(extra, state, null, oError) === true) + * return true; + * + * throw oError; + * } + * + * alert(data); + * } + * }); + * ``` + */ +/** + * @event error Fires when a communication error occurs. + * @bubbles + * @cancelable Prevents a communication error to be thrown. + * @param {Object} e An object returned by the callback. It contains the following properties: + * - error ([[Error]]): The error object that is thrown when the event + * callback doesn't return false. + * - state ([[Number]]): The state of the call. Possible values include: + * - `apf.SUCCESS`: The request was successfull + * - `apf.TIMEOUT`: The request has timed out. + * - `apf.ERROR`: An error has occurred while making the request. + * - `apf.OFFLINE`: The request was made while the application was offline. + * - userdata (`Mixed`): Data that the caller wanted to be available in + * the callback of the HTTP request. + * - http ([[XMLHttpRequest]]): The object that executed the actual HTTP request. + * - url ([[String]]): The URL that was requested. + * - tpModule ([[apf.http]]): The teleport module that is making the request. + * - id ([[Number]]): The id of the request. + * - message ([[String]]): The error message. + * + * @define http + * @default_private + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.4 + */ +apf.http = function(){ + this.queue = [null]; + this.callbacks = {}; + this.cache = {}; + + /** + * Sets the timeout of http requests in milliseconds. Default is 10000ms (10s). + * @type {Number} + */ + this.timeout = this.timeout || 10000; //default 10 seconds + + /** + * Sets whether this element routes traffic through a server proxy. + * + * #### Remarks + * + * This can also be set on a per call basis. See {@link apf.http.get}. + * + * + * @type {Boolean} + */ + this.autoroute = this.autoroute || false; + + /** + * String specifying the URL to the route script. + * + * #### Remarks + * + * The route script will receive the route information in three extra headers: + * - `X-Route-Request` : Contains the destination URL + * - `X-Proxy-Request` : Contains the proxy URL + * - `X-Compress-Response` : Set to 'gzip' + * + * @type {String} + */ + this["route-server"] = this["route-server"] || null; + + if (!this.$uniqueId) + this.$uniqueId = apf.all.push(this) - 1; + + this.toString = this.toString || function(){ + return "[Ajax.org Teleport Component : (HTTP)]"; + }; + + + + /** + * Makes an HTTP request that receives XML. + * @param {String} url The url that is accessed. + * @param {Object} options The options for the HTTP request. It contains the following properties: + * - async ([[Boolean]]): Specifies whether the request is sent asynchronously. Defaults to true. + * - userdata (`Mixed`): custom data that is available to the callback function. + * - method ([[String]]): The request method (`POST`|`GET`|`PUT`|`DELETE`). Defaults to `GET`. + * - nocache ([[Boolean]]): Specifies whether browser caching is prevented. + * - data ([[String]]): the data sent in the body of the message. + * - autoroute ([[Boolean]]): Specifies whether the request can fallback to a server proxy. + * - caching ([[Boolean]]): Specifies whether the request should use internal caching. + * - ignoreOffline ([[Boolean]]): Specifies whether to ignore offline catching. + * - callback ([[Function]]): The handler that gets called whenever the + * request completes successfully or with an error, + * or when the request times out. + */ + this.getXml = function(url, callback, options) { + if (!options) options = {}; + options.useXML = true; + options.callback = callback; + return this.get(url, options); + }; + + this.getJSON = function(url, callback, options) { + if (!options) options = {}; + options.callback = callback; + options.useJSON = true; + return this.get(url, options); + }; + + /** + * Makes an HTTP request. + * @param {String} url The URL that is accessed. + * @param {Object} options The options for the HTTP request. It contains the following properties: + * - async ([[Boolean]]): Specifies whether the request is sent asynchronously. Defaults to true. + * - userdata (`Mixed`): Custom data that is available to the callback function. + * - method ([[String]]): The request method (POST|GET|PUT|DELETE). Defaults to GET. + * - nocache ([[Boolean]]): Specifies whether browser caching is prevented. + * - data ([[String]]): The data sent in the body of the message. + * - useXML ([[Boolean]]): Specifies whether the result should be interpreted as xml. + * - autoroute ([[Boolean]]): Specifies whether the request can fallback to a server proxy. + * - caching ([[Boolean]]): Specifies whether the request should use internal caching. + * - ignoreOffline ([[Boolean]]): Specifies whether to ignore offline catching. + * - contentType ([[String]]): The mime type of the message + * - withCredentials ([[Boolean]]): Value of the withCredentials field for CORS requests + * - callback ([[Function]]): The handler that gets called whenever the + * request completes successfully or with an error, + * or when the request times out. + */ + this.get = this.$get = function(url, options) { + if (!options) + options = {}; + + var _self = this; + var id = options.id; + + + + + var binary = apf.hasXhrBinary && options.binary; + var async = options.async = (options.async || binary + || typeof options.async == "undefined" || apf.isOpera || false); + + + if (apf.isWebkit) + url = apf.html_entity_decode(url); + + + var data = options.data || ""; + + if (apf.isNot(id)) { + + var http = apf.getHttpReq(); + + id = this.queue.push({ + http: http, + url: url, + callback: options.callback, + retries: 0, + options: options + }) - 1; + + + } + else { + var http = this.queue[id].http; + + + http.abort(); + } + + if (async) { + + { + http.onreadystatechange = function(){ + if (!_self.queue[id] || http.readyState != 4) + return; + if (async && arguments.callee.caller) + $setTimeout(function(){_self.receive(id)}); + else + _self.receive(id); + } + } + } + + var autoroute = this.autoroute && apf.isOpera + ? true //Bug in opera + : (options.autoroute || this.shouldAutoroute), + httpUrl = autoroute ? this["route-server"] : url; + + + var headers = []; + + function setRequestHeader(name, value) { + + http.setRequestHeader(name, value); + } + + var errorFound = false; + try { + if (options.nocache) + httpUrl = apf.getNoCacheUrl(httpUrl); + + + + var requestedWithParam = apf.config ? apf.config["requested-with-getparam"] : null; + if (requestedWithParam) { + httpUrl += (httpUrl.indexOf("?") == -1 ? "?" : "&") + + encodeURIComponent(requestedWithParam) + "=1"; + } + // global support for protection against Cross Site Request Forgery + // attacks by supplying a token to the global APF config object. This + // token will be appended to the URL and sent for each XHR. + // Warning: if you are doing CORS, be sure to use a different method! + var CSRFHeader = apf.config ? apf.config["csrf-header"] : null; + var CSRFToken = apf.config ? apf.config["csrf-token"] : null; + if (CSRFHeader) { + setRequestHeader("X-CSRF-Token", CSRFHeader); + } + else if (CSRFToken) { + CSRFToken = CSRFToken.split("=").map(function(s) { return encodeURIComponent(s); }).join("="); + httpUrl += (httpUrl.indexOf("?") == -1 ? "?" : "&") + CSRFToken; + } + + var withCredentials = false; + if ("withCredentials" in options) { + withCredentials = options.withCredentials; + } + else { + withCredentials = (apf.config && apf.config["cors-with-credentials"]) || false; + } + + http.withCredentials = withCredentials; + http.open(this.method || options.method || "GET", httpUrl, async); + + if (options.username) { + setRequestHeader("Authorization", "Basic " + + apf.crypto.Base64.encode(options.username + ":" + options.password)) + } + + //@todo OPERA ERROR's here... on retry [is this still applicable?] + if (!requestedWithParam) + setRequestHeader("X-Requested-With", "XMLHttpRequest"); + + if (!options.headers || !options.headers["Content-type"]) + setRequestHeader("Content-type", options.contentType || this.contentType + || (this.useXML || options.useXML ? "text/xml" : "text/plain")); + + if (autoroute) { + setRequestHeader("X-Route-Request", url); + setRequestHeader("X-Proxy-Request", url); + setRequestHeader("X-Compress-Response", "gzip"); + } + + if (binary) { + setRequestHeader("Cache-Control", "no-cache"); + setRequestHeader("X-File-Name", binary.filename); + setRequestHeader("X-File-Size", binary.filesize); + setRequestHeader("Content-Type", "application/octet-stream"); + } + } + catch (e) { + errorFound = e.message; + } + + if (errorFound) { + var useOtherXH = false; + + // Retry request by routing it + if (!useOtherXH && this.autoroute && !autoroute) { + + + this.shouldAutoroute = true; + + options.autoroute = true; + return this.get(url, options); + } + + if (!useOtherXH) { + //Routing didn't work either... Throwing error + var noClear = options.callback ? options.callback(null, apf.ERROR, { + userdata: options.userdata, + http: http, + url: url, + tpModule: this, + id: id, + message: "Permission denied accessing remote resource: " + + url + "\nMessage: " + errorFound + }) : false; + if (!noClear) + this.clearQueueItem(id); + + return; + } + } + + if (this.$headerHook) + this.$headerHook(http); + + //Set request headers + if (options.headers) { + for (var name in options.headers) + setRequestHeader(name, options.headers[name]); + } + + + + function handleError(){ + var msg = self.navigator && self.navigator.onLine + ? "File or Resource not available " + url + : "Browser is currently working offline"; + + + + var state = self.navigator && navigator.onLine + ? apf.ERROR + : apf.TIMEOUT; + + // File not found + var noClear = options.callback ? options.callback(null, state, { + userdata: options.userdata, + http: http, + url: url, + tpModule: _self, + id: id, + message: msg + }) : false; + if (!noClear) + _self.clearQueueItem(id); + } + + function send(isLocal) { + var hasError; + + if (apf.isIE && isLocal) { //When local IE calls onreadystate immediately + var oldWinOnerror = window.onerror; + window.onerror = function(){ + if (arguments.caller && arguments.caller.callee == send) { + window.onerror = oldWinOnerror; + //_self.receive(id); + //setTimeout(function(){handleError();}); + return true; + } + else { + window.onerror = oldWinOnerror; + + if (oldWinOnerror) + return oldWinOnerror.apply(window, arguments); + } + } + http.send(data); + window.onerror = oldWinOnerror; + } + else { + try { + if (binary && http.sendAsBinary) { + binary.blob = getBinaryBlob(data, http, binary); + http.sendAsBinary(binary.blob.data); + } + else + http.send(data); + } + catch (e) { + hasError = true; + } + } + + if (hasError) { + handleError(); + return; + } + else if (binary && http.upload) { + http.upload.onprogress = function(e) { + apf.dispatchEvent("http.uploadprogress", { + loaded: e.loaded - binary.blob.size, + extra: e, + bubbles: true + }); + }; + } + } + + if (!async) { + send.call(this); + return this.receive(id); + } + else { + if (apf.loadsLocalFilesSync && location.protocol == "file:" + && url.indexOf("http://") == -1) { + $setTimeout(function(){ + send.call(_self, true); + }); + } + else + send.call(_self); + + return id; + } + }; + + + if (!this.exec) { + /** + * A method that all async objects should implement. + * + * @private + */ + this.exec = function(method, args, callback, options) { + if (!options) + options = {}; + + var url = args[0], query = ""; + if (!options.method) + options.method = method.toUpperCase(); + if (!options.callback) + options.callback = callback; + + this.contentType = "application/x-www-form-urlencoded"; + this.$get( + apf.getAbsolutePath(apf.config.baseurl, url), + options.method == "GET" + ? options + : apf.extend({data : query}, options) + ); + } + } + + + /** + * Sends the binary blob to the server, and multipart encodes it if needed. This code + * will only be executed on Gecko since it's currently the only browser that + * supports direct file access. + * @private + */ + function getBinaryBlob(data, http, binary) { + var boundary = "----apfbound".appendRandomNumber(5), + dashdash = "--", + crlf = "\r\n", + multipartBlob = "", + multipartSize = 0; + + // Build multipart request + if (binary.multipart) { + http.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + boundary); + // Build RFC2388 blob + multipartBlob += dashdash + boundary + crlf + + 'Content-Disposition: form-data; name="' + (binary.filedataname || binary.filename) + + '"; filename="' + binary.filename + '"' + crlf + + 'Content-Type: application/octet-stream' + crlf + crlf + + data + crlf + + dashdash + boundary + dashdash + crlf; + + multipartSize = multipartBlob.length - data.length; + data = multipartBlob; + } + // Send blob or multipart blob depending on config + return {size: multipartSize, data: data}; + } + + /** + * @private + */ + this.receive = function(id) { + if (!this.queue[id]) + return false; + + var qItem = this.queue[id], + http = qItem.http, + callback = qItem.callback; + //if (apf.isGecko) + // var apf = self.apf || apf; // needed here to fix a rare ReferenceError in FF + + + + /*if (self.navigator && navigator.onLine === false && + (location.protocol != "file:" + || qItem.url.indexOf("http://") > -1)) + return false;*/ + + // Test if HTTP object is ready + if (qItem.async) { + try { + if (http.status) {} + } + catch (e) { + var _self = this; + return $setTimeout(function(){ + _self.receive(id) + }, 10); + } + } + + + + //Gonna check for validity of the http response + var errorMessage = [], + extra = { + + tpModule: this, + http: http, + status: http.status, + url: qItem.url, + callback: callback, + id: id, + retries: qItem.retries || 0, + userdata: qItem.options.userdata + }; + + // Check HTTP Status + // The message didn't receive the server. We consider this a timeout (i.e. 12027) + if (http.status > 600) + return this.$timeout(id); + + extra.data = qItem.options.useJSON + ? eval("(" + http.responseText + ")") + : http.responseText; //Can this error? + + if (http.status >= 400 && http.status < 600 || http.status < 10 + && (http.status != 0 || !apf.isIE && !http.responseText)) { //qItem.url.substr(0, 6) == "file:/" + + //@todo This should probably have an RPC specific handler + if (http.status == 401) { + var auth = apf.document.getElementsByTagNameNS(apf.ns.apf, "auth")[0]; + if (auth) { + var wasDelayed = qItem.isAuthDelayed; + qItem.isAuthDelayed = true; + if (auth.authRequired(extra, wasDelayed) === true) + return; + } + } + + + errorMessage.push("HTTP error [" + id + "]:" + http.status + "\n" + + http.responseText); + } + + // Check for XML Errors + if (qItem.options.useXML || this.useXML) { + /* Note (Mike, Oct 14th 2008): for WebDAV, I had to copy the lines below, + it required custom responseXML handling/ + parsing. + If you alter this code, please correct + webdav.js appropriately. + */ + if ((http.responseText || "").replace(/^[\s\n\r]+|[\s\n\r]+$/g, "") == "") + errorMessage.push("Received an empty XML document (0 bytes)"); + else { + try { + var xmlDoc = (http.responseXML && http.responseXML.documentElement) + ? apf.xmlParseError(http.responseXML) + : apf.getXmlDom(http.responseText); + + if (!apf.supportNamespaces) + xmlDoc.setProperty("SelectionLanguage", "XPath"); + + extra.data = xmlDoc.documentElement; + } + catch (e) { + errorMessage.push("Received invalid XML\n\n" + e.message); + } + } + } + + //Process errors if there are any + if (errorMessage.length) { + extra.message = errorMessage.join("\n"); + + + + // Send callback error state + if (!callback || !callback(extra.data, apf.ERROR, extra)) + this.clearQueueItem(id); + + return; + } + + + + + + //Http call was successfull Success + if (!callback || !callback(extra.data, apf.SUCCESS, extra)) + this.clearQueueItem(id); + + return extra.data; + }; + + this.$timeout = function(id) { + if (!this.queue[id]) + return false; + + var qItem = this.queue[id], + http = qItem.http; + + + + // Test if HTTP object is ready + try { + if (http.status) {} + } + catch (e) { + var _self = this; + return $setTimeout(function(){ + _self.$timeout(id) + }, 10); + } + + var callback = qItem.callback; + + http.abort(); + + + + var extra; + var noClear = callback ? callback(null, apf.TIMEOUT, extra = { + + userdata: qItem.options.userdata, + http: http, + url: qItem.url, + tpModule: this, + id: id, + message: "HTTP Call timed out", + retries: qItem.retries || 0 + }) : false; + + + + if (!noClear) + this.clearQueueItem(id); + }; + + /** + * Checks if the request has timed out. If so, it is retried + * three times before an exception is thrown. Request retrying is a very + * good way to create a robust Ajax application. In many cases, even with + * good connections, requests still time out. + * @param {Object} extra The information object given as a third + * argument of the HTTP request callback. + * @param {Number} state The return code of the HTTP request. It contains the following properties: + * - `apf.SUCCESS`: the request was successfull + * - `apf.TIMEOUT`: the request has timed out. + * - `apf.ERROR`: an error occurred while making the request. + * - `apf.OFFLINE`: the request was made while the application was offline. + * @param {apf.AmlNode} [amlNode] The element receiving the error event. + * @param {Error} [oError] The error to be thrown when the request is + * not retried. + * @param {Number} [maxRetries] The number of retries that are done before + * the request times out. Default is 3. + */ + this.retryTimeout = function(extra, state, amlNode, oError, maxRetries) { + if (state == apf.TIMEOUT + && extra.retries < (maxRetries || apf.maxHttpRetries)) + return extra.tpModule.retry(extra.id); + + oError = oError || new Error(apf.formatErrorString(0, + this, "Communication " + (state == apf.TIMEOUT + ? "timeout" + : "error"), "Url: " + extra.url + "\nInfo: " + extra.message)); + + if ((amlNode || apf).dispatchEvent("error", apf.extend({ + error: oError, + state: state, + extra: extra, + bubbles: true + }, extra)) === false) + return 2; + }; + + /** + * Removes the item from the queue. This is usually done automatically. + * However, when the callback returns `true` the queue isn't cleared; for instance, + * when a request is retried. The id of the call + * is found on the `'extra'` object, the third argument of the callback. + * + * #### Example + * + * ```javascript + * http.clearQueueItem(extra.id); + * ``` + * + * @param {Number} id The id of the call that should be removed from the queue. + */ + this.clearQueueItem = function(id) { + if (!this.queue[id]) + return false; + + + + if (apf.releaseHTTP && !apf.isGecko) + apf.releaseHTTP(this.queue[id].http); + + this.queue[id] = null; + delete this.queue[id]; + + return true; + }; + + /** + * Retries a call based on its id. The id of the call is found on the + * `'extra'` object, the third argument of the callback. + * + * #### Example + * + * ```javascript + * function callback(data, state, extra) { + * if (state == apf.TIMEOUT && extra.retries < apf.maxHttpRetries) + * return extra.tpModule.retry(extra.id); + * + * //Do stuff here + * } + * ``` + * + * @param {Number} id The id of the call that should be retried. + */ + this.retry = function(id) { + if (!this.queue[id]) + return false; + + var qItem = this.queue[id]; + + + + + + qItem.retries++; + qItem.options.id = id; + this.get(qItem.url, qItem.options); + + return true; + }; + + /** + * Cancels a call based on its id. The id of the call is found on the + * `'extra'` object, the third argument of the callback. + * + * @see apf.http.clearQueueItem + * + * @param {Number} id The id of the call that should be canceled. + */ + this.cancel = function(id) { + if (id === null) + id = this.queue.length - 1; + + if (!this.queue[id]) + return false; + + if (apf.isGecko) + this.queue[id].http.abort(); + + this.clearQueueItem(id); + }; + + if (!this.$loadAml && !this.instantiate && !this.call) { + /** + * @private + */ + this.$loadAml = function(x) { + var receive = this["receive"]; + + for (var i = 0, l = this.childNodes.length; i < l; i++) { + if (this.childNodes[i].nodeType != 1) + continue; + + var url = this.childNodes[i].getAttribute("url"), + callback = self[this.childNodes[i].getAttribute("receive") || receive], + options = { + useXML: this.childNodes[i].getAttribute("type") == "XML", + async: !apf.isFalse(this.childNodes[i].getAttribute("async")) + }; + + this[this.childNodes[i].getAttribute("name")] = function(data, userdata) { + options.userdata = userdata; + options.data = data; + return this.get(url, options); + } + } + }; + + /** + * @private + */ + this.instantiate = function(x) { + var url = x.getAttribute("src"), + options = { + async: x.getAttribute("async") != "false", + nocache: true + }; + + this.getURL = function(data, userdata) { + options.data = data; + options.userdata = userdata; + options.callback = this.callbacks.getURL; + return this.get(url, options); + } + + var name = "http" + Math.round(Math.random() * 100000); + apf.setReference(name, this); + + return name + ".getURL()"; + }; + + /** + * @private + */ + this.call = function(method, args) { + this[method].call(this, args); + }; + } +}; + + + +apf.Init.run("http"); + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: socket://www.fsf.org. + * + */ + + + + + + + + + + + + + + + + + + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +/** + * The parser of the Ajax.org Markup Language. Besides aml this parser takes care + * of distributing parsing tasks to other parsers like the native html parser and + * the xsd parser. + * @parser + * @private + * + * @define include element that loads another aml files. + * Example: + * + * + * + * @attribute {String} src the location of the aml file to include in this application. + * + */ +apf.DOMParser = function(){}; + +apf.DOMParser.prototype = new (function(){ + this.caseInsensitive = true; + this.preserveWhiteSpace = false; //@todo apf3.0 whitespace issue + + this.$waitQueue = {} + this.$callCount = 0; + + // privates + var RE = [ + /\<\!(DOCTYPE|doctype)[^>]*>/, + / /g, + /<\s*\/?\s*(?:\w+:\s*)[\w-]*[\s>\/]/g + ], + XPATH = "//@*[not(contains(local-name(), '.')) and not(translate(local-name(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz') = local-name())]"; + + this.parseFromString = function(xmlStr, mimeType, options) { + var xmlNode; + if (this.caseInsensitive) { + //replace(/&\w+;/, ""). replace this by something else + //.replace(RE[1], " ") + var str = xmlStr.replace(RE[0], "") + .replace(RE[2], //.replace(/^[\r\n\s]*/, "") + function(m){ return m.toLowerCase(); }); + + /* @todo apf3.0 integrate this + x.ownerDocument.setProperty("SelectionNamespaces", + "xmlns:a='" + apf.ns.aml + "'"); + */ + + if (!this.supportNamespaces) + str = str.replace(/xmlns\=\"[^"]*\"/g, ""); + + + + var xmlNode = apf.getXmlDom(str); + if (apf.xmlParseError) apf.xmlParseError(xmlNode); + xmlNode = xmlNode.documentElement; + + } + else { + xmlNode = apf.getXmlDom(xmlStr, null, this.preserveWhiteSpace || apf.debug).documentElement; + } + + return this.parseFromXml(xmlNode, options); + }; + + //@todo prevent leakage by not recording .$aml + this.parseFromXml = function(xmlNode, options) { + var doc, docFrag, amlNode, beforeNode; + if (!options) + options = {}; + + if (!options.delayedRender && !options.include) { + //Create a new document + if (options.doc) { + doc = options.doc; + docFrag = options.docFrag || doc.createDocumentFragment(); + } + else { + doc = new apf.AmlDocument(); + doc.$aml = xmlNode; + doc.$domParser = this; + } + if (options.host) + doc.$parentNode = options.host; //This is for sub docs that need to access the outside tree + + + + //Let's start building our tree + amlNode = this.$createNode(doc, xmlNode.nodeType, xmlNode); //Root node + (docFrag || doc).appendChild(amlNode); + if (options.htmlNode) + amlNode.$int = options.htmlNode; + } + else { + amlNode = options.amlNode; + doc = options.doc; + + if (options.include) { + var n = amlNode.childNodes; + var p = n.indexOf(options.beforeNode); + var rest = p ? n.splice(p, n.length - p) : []; + } + } + + //Set parse context + this.$parseContext = [amlNode, options]; + + this.$addParseState(amlNode, options || {}); + + //First pass - Node creation + var nodes, nodelist = {}, prios = [], _self = this; + var recur; + (recur = function(amlNode, nodes) { + var cL, newNode, node, nNodes, + cNodes = amlNode.childNodes, + i = 0, + l = nodes.length; + for (; i < l; i++) { + //Create child + newNode = _self.$createNode(doc, (node = nodes[i]).nodeType, node); + if (!newNode) continue; //for preserveWhiteSpace support + + cNodes[cL = cNodes.length] = newNode; //Add to children + + //Set tree refs + newNode.parentNode = amlNode; + if (cL > 0) + (newNode.previousSibling = cNodes[cL - 1]).nextSibling = newNode; + + //Create children + if (!newNode.render && newNode.canHaveChildren && (nNodes = node.childNodes).length) + recur(newNode, nNodes); + + //newNode.$aml = node; //@todo should be deprecated... + + //Store high prio nodes for prio insertion + if (newNode.$parsePrio) { + if (newNode.$parsePrio == "001") { + newNode.dispatchEvent("DOMNodeInsertedIntoDocument"); //{relatedParent : nodes[j].parentNode} + continue; + } + + (nodelist[newNode.$parsePrio] || (prios.push(newNode.$parsePrio) + && (nodelist[newNode.$parsePrio] = []))).push(newNode); //for second pass + } + } + + amlNode.firstChild = cNodes[0]; + amlNode.lastChild = cNodes[cL]; + })(amlNode, xmlNode.childNodes); + + if (options.include && rest.length) { + var index = n.length - 1; + n.push.apply(n, rest); + var last = n[index]; + var next = n[index + 1]; + (next.previousSibling = last).nextSibling = next; + amlNode.lastChild = n[n.length - 1]; + } + + if (options.delay) { + amlNode.$parseOptions = { + prios: prios, + nodelist: nodelist + }; + return (docFrag || doc); + } + + //Second pass - Document Insert signalling + prios.sort(); + var i, j, l, l2; + for (i = 0, l = prios.length; i < l; i++) { + nodes = nodelist[prios[i]]; + for (j = 0, l2 = nodes.length; j < l2; j++) { + nodes[j].dispatchEvent("DOMNodeInsertedIntoDocument"); //{relatedParent : nodes[j].parentNode} + } + } + + if (this.$waitQueue[amlNode.$uniqueId] + && this.$waitQueue[amlNode.$uniqueId].$shouldWait) + return (docFrag || doc); + + if (options.timeout) { + $setTimeout(function(){ + _self.$continueParsing(amlNode, options); + }); + } + else { + this.$continueParsing(amlNode, options); + } + + return (docFrag || doc); + }; + + this.$isPaused = function(amlNode) { + return this.$waitQueue[amlNode.$uniqueId] && + this.$waitQueue[amlNode.$uniqueId].$shouldWait > 0; + } + + this.$addParseState = function(amlNode, options) { + var waitQueue = this.$waitQueue[amlNode.$uniqueId] + || (this.$waitQueue[amlNode.$uniqueId] = []) + waitQueue.pushUnique(options); + + return waitQueue; + } + + this.$pauseParsing = function(amlNode, options) { + var waitQueue = this.$waitQueue[amlNode.$uniqueId]; + if (!waitQueue.$shouldWait) waitQueue.$shouldWait = 0; + waitQueue.$shouldWait++; + } + + this.$continueParsing = function(amlNode, options) { + if (!amlNode) + amlNode = apf.document.documentElement; + + var uId = amlNode.$uniqueId; + if (uId in this.$waitQueue) { + var item = this.$waitQueue[uId]; + + if (item.$shouldWait && --item.$shouldWait) + return false; + + var node = amlNode.parentNode; + while (node && node.nodeType == 1) { + if (this.$waitQueue[node.$uniqueId] + && this.$waitQueue[node.$uniqueId].$shouldWait) + return false; + node = node.parentNode; + } + + var parseAmlNode = apf.all[uId]; + delete this.$waitQueue[uId]; + if (parseAmlNode) { + for (var i = 0; i < item.length; i++) + this.$parseState(parseAmlNode, item[i]); + } + + //@todo Check for shouldWait here? + } + else + this.$parseState(amlNode, options || {}); + + delete this.$parseContext; + } + + this.$parseState = function(amlNode, options) { + this.$callCount++; + + if (amlNode.$parseOptions) { + var prios = amlNode.$parseOptions.prios, + nodelist = amlNode.$parseOptions.nodelist, + i, j, l, l2, node; + delete amlNode.$parseOptions; + + //Second pass - Document Insert signalling + prios.sort(); + for (i = 0, l = prios.length; i < l; i++) { + var nodes = nodelist[prios[i]]; + for (j = 0, l2 = nodes.length; j < l2; j++) { + if (!(node = nodes[j]).parentNode || node.$amlLoaded) //@todo generalize this using compareDocumentPosition + continue; + nodes[j].dispatchEvent("DOMNodeInsertedIntoDocument"); //{relatedParent : nodes[j].parentNode} + } + } + } + + //instead of $amlLoaded use something more generic see compareDocumentPosition + if (!options.ignoreSelf && !amlNode.$amlLoaded) + amlNode.dispatchEvent("DOMNodeInsertedIntoDocument"); //{relatedParent : nodes[j].parentNode} + + //Recursively signal non prio nodes + (function _recur(nodes) { + var node, nNodes; + for (var i = 0, l = nodes.length; i < l; i++) { + if (!(node = nodes[i]).$amlLoaded) { + node.dispatchEvent("DOMNodeInsertedIntoDocument"); //{relatedParent : nodes[j].parentNode} + } + + //Create children + if (!node.render && (nNodes = node.childNodes).length) + _recur(nNodes); + } + })(amlNode.childNodes); + + if (!--this.$callCount && !options.delay) + apf.queue.empty(); + + if (options.callback) + options.callback.call(amlNode.ownerDocument); + }; + + this.$createNode = function(doc, nodeType, xmlNode, namespaceURI, nodeName, nodeValue) { + var o; + + switch (nodeType) { + case 1: + var id, prefix; + if (xmlNode) { + if ((namespaceURI = xmlNode.namespaceURI || apf.ns.xhtml) + && !(prefix = doc.$prefixes[namespaceURI])) { + doc.$prefixes[prefix = xmlNode.prefix || xmlNode.scopeName || ""] = namespaceURI; + doc.$namespaceURIs[namespaceURI] = prefix; + + if (!doc.namespaceURI && !prefix) { + doc.namespaceURI = namespaceURI; + doc.prefix = prefix; + } + } + nodeName = xmlNode.baseName || xmlNode.localName || xmlNode.tagName.split(":").pop(); + } + else { + prefix = doc.$prefixes[namespaceURI] || ""; + } + + + + var els = apf.namespaces[namespaceURI].elements; + + + + o = new (els[nodeName] || els["@default"])(null, nodeName); + + o.prefix = prefix || ""; + o.namespaceURI = namespaceURI; + o.tagName = prefix ? prefix + ":" + nodeName : nodeName; + + if (xmlNode) { + if ((id = xmlNode.getAttribute("id")) && !self[id]) + o.$propHandlers["id"].call(o, o.id = id); + + //attributes + var attr = xmlNode.attributes, n; + for (var a, na, i = 0, l = attr.length; i < l; i++) { + o.attributes.push(na = new apf.AmlAttr(o, + (n = (a = attr[i]).nodeName), a.nodeValue)); + + if (n == "render") + o.render = true; + else + + if (n.substr(0, 2) == "on") + na.$triggerUpdate(); + } + } + + break; + case 2: + o = new apf.AmlAttr(); + o.name = o.nodeName = nodeName; + if (nodeValue || (nodeValue = xmlNode && xmlNode.nodeValue)) + o.value = o.nodeValue = nodeValue; + + if (xmlNode) { + if (xmlNode.namespaceURI && !(o.prefix = doc.$namespaceURIs[o.namespaceURI = xmlNode.namespaceURI])) + doc.$prefixes[o.prefix = xmlNode.prefix || xmlNode.scopeName] = o.namespaceURI; + } + else { + o.prefix = doc.$prefixes[namespaceURI]; + } + + break; + case 3: + if (xmlNode) + nodeValue = xmlNode && xmlNode.nodeValue; + if (!this.preserveWhiteSpace && !(nodeValue || "").trim()) + return; + + o = new apf.AmlText(); + o.nodeValue = nodeValue || xmlNode && xmlNode.nodeValue; + break; + case 7: + var target = nodeName || xmlNode && xmlNode.nodeName; + + o = new apf.aml.processingInstructions[target](); + + o.target = o.nodeName = target; + o.data = o.nodeValue = nodeValue || xmlNode && xmlNode.nodeValue; + break; + case 4: + o = new apf.AmlCDATASection(); + o.nodeValue = nodeValue || xmlNode && xmlNode.nodeValue; + break; + case 5: //unsupported + o = new apf.AmlNode(); + o.nodeType = nodeType; + break; + case 6: //unsupported + o = new apf.AmlNode(); + o.nodeType = nodeType; + break; + case 8: + o = new apf.AmlComment(); + o.nodeValue = nodeValue || xmlNode && xmlNode.nodeValue; + break; + case 9: + o = new apf.AmlDocument(); + o.$domParser = this; + break; + case 10: //unsupported + o = new apf.AmlNode(); + o.nodeType = nodeType; + break; + case 11: + o = new apf.AmlDocumentFragment(); + break; + } + + o.ownerDocument = doc; + o.$aml = xmlNode; + + return o; + }; +})(); + +/** + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.8 + */ +apf.AmlNamespace = function(){ + this.elements = {}; + this.processingInstructions = {}; +}; + +apf.AmlNamespace.prototype = { + setElement: function(tagName, fConstr) { + return this.elements[tagName] = fConstr; + }, + + setProcessingInstruction: function(target, fConstr) { + this.processingInstructions[target] = fConstr; + } +}; + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +/** + * The parser of the Ajax.org Markup Language. Besides aml this parser takes care + * of distributing parsing tasks to other parsers like the native html parser and + * the xsd parser. + * @parser + * @private + * + * @define include element that loads another aml files. + * Example: + * + * + * + * @attribute {String} src the location of the aml file to include in this application. + * + */ +apf.aml = new apf.AmlNamespace(); +apf.setNamespace("http://ajax.org/2005/aml", apf.aml); + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + +apf.__AMLNODE__ = 1 << 14; + + + +/** + * All elements inheriting from this {@link term.baseclass baseclass} have Document Object Model (DOM) support. The DOM + * is the primary method for accessing and manipulating an XML document. This + * includes HTML documents and AML documents. Every element in the ajax.org + * markup language can be manipulated using the W3C DOM. This means + * that every element and attribute you can set in the XML format, can be + * changed, set, removed, reparented, _e.t.c._ at runtime. This offers a great deal of + * flexibility. + * + * Well known methods + * from this specification are: `appendChild`, `removeChild`, `setAttribute`, and + * `insertBefore`--to name a few. The Ajax.org Platform aims to implement DOM1 + * completely and parts of DOM2. For more information see {@link http://www.w3.org/DOM/} + * or {@link http://www.w3schools.com/dom/default.asp}. + * + * #### Example: + * + * Here's a basic window using the Ajax.org Markup Language (AML): + * + * ```xml + * + * + * + * ``` + * + * + * Using the Document Object Model in JavaScript: + * + * ```javascript + * //The following line is only there for completeness sake. In fact apf + * //automatically adds a reference in javascript called winExample based + * //on the id it has. + * var winExample = apf.document.getElementById("winExample"); + * winExample.setAttribute("title", "Example"); + * winExample.setAttribute("icon", "icoFolder.gif"); + * winExample.setAttribute("left", "100"); + * + * var lblNew = apf.document.createElement("label"); + * winExample.appendChild(lblNew); + * lblNew.setAttribute("caption", "Example"); + * + * tstButton.setAttribute("caption", "Click me"); + * ``` + * + * That would be the same as having the following AML: + * + * ```xml + * + * + * + * + * ``` + * + * #### Remarks + * Because the W3C DOM is native to all modern browsers the internet is full + * of tutorials and documentation for this API. If you need more information, + * it's a good idea to search for tutorials online. + * + * @class apf.AmlNode + * @baseclass + * @inherits apf.Class + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.5 + */ +/** + * @event DOMNodeInserted Fires when a DOM node is inserted. + */ +/** + * @event DOMNodeInsertedIntoDocument Fires when a DOM node is inserted into the document. + */ +/** + * @event DOMNodeRemoved Fires when a DOM node is removed. + */ +/** + * @event DOMNodeRemovedFromDocument Fires when a DOM node is removed from a document. + */ + +apf.AmlNode = function(){ + this.$init(function(){ + /** + * Nodelist containing all the child nodes of this element. + */ + this.childNodes = []; //@todo AmlNodeList + }); +}; + +(function() { + + + /** + * Returns a string representation of this object. + * @returns A string defining the object. + */ + this.toString = function(){ + if (this.nodeName) + return "[" + this.nodeName.uCaseFirst() + " Node]"; + + return "[" + this.localName.uCaseFirst() + " Element Node, <" + + (this.prefix ? this.prefix + ":" : "") + this.localName + " " + + this.attributes.join(" ") + + " /> : " + (this.name || this.$uniqueId || "") + "]"; + }; + + + /** + * Number specifying the type of node within the document. + * @type {Number} + */ + this.$regbase = this.$regbase | apf.__AMLNODE__; + + /** + * The constant for a DOM element node. + * @type {Number} + */ + this.NODE_ELEMENT = 1; + /** + * The constant for a DOM attribute node. + * @type {Number} + */ + this.NODE_ATTRIBUTE = 2; + /** + * The constant for a DOM text node. + * @type {Number} + */ + this.NODE_TEXT = 3; + /** + * The constant for a DOM cdata section node. + * @type {Number} + */ + this.NODE_CDATA_SECTION = 4; + /** + * The constant for a DOM entity reference node. + * @type {Number} + */ + this.NODE_ENTITY_REFERENCE = 5; + /** + * The constant for a DOM entity node. + * @type {Number} + */ + this.NODE_ENTITY = 6; + /** + * The constant for a DOM processing instruction node. + * @type {Number} + */ + this.NODE_PROCESSING_INSTRUCTION = 7; + /** + * The constant for a DOM comment node. + * @type {Number} + */ + this.NODE_COMMENT = 8; + /** + * The constant for a DOM document node. + * @type {Number} + */ + this.NODE_DOCUMENT = 9; + /** + * The constant for a DOM document type node. + * @type {Number} + */ + this.NODE_DOCUMENT_TYPE = 10; + /** + * The constant for a DOM document fragment node. + * @type {Number} + */ + this.NODE_DOCUMENT_FRAGMENT = 11; + /** + * The constant for a DOM notation node. + * @type {Number} + */ + this.NODE_NOTATION = 12; + + + + /** + * The document node of this application + * @type {apf.AmlDocument} + */ + this.ownerDocument = null; + + /** + * Returns the value of the current node. + * @type {apf.AmlNode} + */ + this.nodeValue = ""; + + /** + * The namespace URI of the node, or `null` if it is unspecified (read-only). + * + * When the node is a document, it returns the XML namespace for the current + * document. + * @type {String} + */ + this.namespaceURI = ""; + + /* + * @todo + */ + //this.baseURI = alsdjlasdj + + /* + * @todo + */ + //this.prefix = asdkljahqsdkh + + /** + * + * @inheritdoc apf.AmlNode.insertBefore + * + */ + this.appendChild = + + /** + * Inserts an element before another element in the list of children of this + * element. If the element was already a child of another element it is + * removed from that parent before adding it this element. + * + * @method insertBefore + * @param {apf.AmlNode} amlNode The element to insert as child of this element. + * @param {apf.AmlNode} beforeNode The element which determines the insertion position of the element. + * @return {apf.AmlNode} The inserted node + */ + this.insertBefore = function(amlNode, beforeNode, noHtmlDomEdit) { + + + if (this.nodeType == this.NODE_DOCUMENT) { + if (this.childNodes.length) { + throw new Error(apf.formatErrorString(0, this, + "Insertbefore DOM operation", + "Only one top level element is allowed in an AML document.")); + } + else this.documentElement = amlNode; //@todo apf3.0 removal + } + + if (amlNode == beforeNode) + return amlNode; + + if (this == amlNode) { + throw new Error(apf.formatErrorString(0, this, + "Insertbefore DOM operation", + "Cannot append node as a child of itself.")); + } + + if (amlNode.nodeType == this.NODE_DOCUMENT_FRAGMENT) { + var nodes = amlNode.childNodes.slice(0); + for (var i = 0, l = nodes.length; i < l; i++) { + this.insertBefore(nodes[i], beforeNode); + } + return amlNode; + } + + var isMoveWithinParent = amlNode.parentNode == this, + oldParentHtmlNode = amlNode.$pHtmlNode, + oldParent = amlNode.parentNode, + index = -1, + _self = this; + + if (beforeNode) { + index = this.childNodes.indexOf(beforeNode); + if (index < 0) { + + + return false; + } + } + + if (!amlNode.ownerDocument) + amlNode.ownerDocument = this.ownerDocument || apf.ownerDocument; + + if (amlNode.parentNode) + amlNode.removeNode(isMoveWithinParent, true);//noHtmlDomEdit); + amlNode.parentNode = this; + + if (beforeNode) + index = this.childNodes.indexOf(beforeNode); + + if (beforeNode) { + amlNode.nextSibling = beforeNode; + amlNode.previousSibling = beforeNode.previousSibling; + beforeNode.previousSibling = amlNode; + if (amlNode.previousSibling) + amlNode.previousSibling.nextSibling = amlNode; + } + + if (index >= 0) { + this.childNodes = this.childNodes.slice(0, index).concat(amlNode, + this.childNodes.slice(index)); + } + else { + index = this.childNodes.push(amlNode) - 1; + + amlNode.nextSibling = null; + if (index > 0) { + amlNode.previousSibling = this.childNodes[index - 1]; + amlNode.previousSibling.nextSibling = amlNode; + } + else { + amlNode.previousSibling = null; + } + } + + this.firstChild = this.childNodes[0]; + this.lastChild = this.childNodes[this.childNodes.length - 1]; + + //@todo fix event struture, fix tree events + var initialAppend = !amlNode.$amlLoaded; + function triggerUpdate(){ + amlNode.$pHtmlNode = _self.canHaveChildren ? _self.$int : document.body; + + //@todo this is a hack, a good solution should be found + if (document.adoptNode && amlNode.$ext && amlNode.$ext.nodeType == 1) { + var reappendlist = []; + var iframelist = apf.getArrayFromNodelist( + amlNode.$ext.getElementsByTagName("iframe")); + if (amlNode.$ext.tagName == "IFRAME") + document.adoptNode(amlNode.$ext); + + for (var i = 0; i < iframelist.length; i++) { + reappendlist[i] = [ + iframelist[i].parentNode, + iframelist[i].nextSibling, + document.adoptNode(iframelist[i]), + ] + } + } + + var nextNode = beforeNode; + if (!initialAppend && !noHtmlDomEdit && amlNode.$ext && !amlNode.$coreHtml) { + nextNode = beforeNode; + while (nextNode && !(nextNode.$altExt || nextNode.$ext)) { + nextNode = nextNode.nextSibling; + } + + amlNode.$pHtmlNode.insertBefore(amlNode.$altExt || amlNode.$ext, + nextNode && (nextNode.$altExt || nextNode.$ext) || null); + + for (var i = reappendlist.length - 1; i >= 0; i--) { + reappendlist[i][0].insertBefore( + reappendlist[i][2], + reappendlist[i][1]); + } + reappendlist = []; + } + + //Signal node and all it's ancestors + amlNode.dispatchEvent("DOMNodeInserted", { + $beforeNode: beforeNode, + relatedNode: _self, + $isMoveWithinParent: isMoveWithinParent, + $oldParentHtmlNode: oldParentHtmlNode, + $oldParent: oldParent, + bubbles: true + }); + + if (initialAppend && !noHtmlDomEdit && beforeNode && amlNode.$ext && !amlNode.$coreHtml) { + nextNode = beforeNode; + while (nextNode && !(nextNode.$altExt || nextNode.$ext)) { + nextNode = nextNode.nextSibling; + } + + amlNode.$pHtmlNode.insertBefore(amlNode.$altExt || amlNode.$ext, + nextNode && (nextNode.$altExt || nextNode.$ext) || null); + + for (var i = reappendlist.length - 1; i >= 0; i--) { + reappendlist[i][0].insertBefore( + reappendlist[i][2], + reappendlist[i][1]); + } + } + } + + var doc = this.nodeType == this.NODE_DOCUMENT ? this : this.ownerDocument; + if (!doc || doc.$domParser.$isPaused(this)) + return amlNode; + + // Don't update the tree if this is a doc fragment or if this element is not inited yet + if (this.nodeType == this.NODE_DOCUMENT_FRAGMENT || !this.$amlLoaded) + return amlNode; + + //@todo review this... + if (initialAppend && !amlNode.render) { // && (nNodes = node.childNodes).length ?? + (this.ownerDocument || this).$domParser.$continueParsing(amlNode, {delay: true}); + } + + triggerUpdate(); + return amlNode; + }; + + /** + * Removes this element from the document hierarchy. Call-chaining is + * supported. + * + */ + this.removeNode = function(doOnlyAdmin, noHtmlDomEdit) { + + + if (!this.parentNode || !this.parentNode.childNodes) + return this; + + + + this.parentNode.childNodes.remove(this); + + //If we're not loaded yet, just remove us from the aml to be parsed + if (this.$amlLoaded && !apf.isDestroying) { + //this.parentNode.$aml.removeChild(this.$aml); + + this.dispatchEvent("DOMNodeRemoved", { + relatedNode: this.parentNode, + bubbles: true, + $doOnlyAdmin: doOnlyAdmin + }); + + if (!noHtmlDomEdit && !doOnlyAdmin && this.$ext && this.$ext.parentNode) { + this.$ext.parentNode.removeChild(this.$ext); + //delete this.$ext; //WTF??? + } + } + + if (this.parentNode.firstChild == this) + this.parentNode.firstChild = this.nextSibling; + if (this.parentNode.lastChild == this) + this.parentNode.lastChild = this.previousSibling; + + if (this.nextSibling) + this.nextSibling.previousSibling = this.previousSibling; + if (this.previousSibling) + this.previousSibling.nextSibling = this.nextSibling; + + this.$pHtmlNode = + this.parentNode = + this.previousSibling = + this.nextSibling = null; + + return this; + }; + + /** + * Removes a child from the node list of this element. Call-chaining is + * supported. + * @param {apf.AmlNode} childNode The child node to remove + */ + this.removeChild = function(childNode) { + + + childNode.removeNode(); + return this; + }; + + //@todo + this.replaceChild = function(){}; + + /** + * Clones this element, creating an exact copy of it--but does not insert + * it in the document hierarchy. + * + * @param {Boolean} deep Specifies whether the elements are cloned recursively. + * @return {apf.AmlNode} The cloned element. + */ + this.cloneNode = function(deep) { + if (deep && this.nodeType == 1) { + return this.ownerDocument.$domParser.parseFromXml(this, { + doc: this.ownerDocument, + delay: true + }).childNodes[0]; + } + else { + return this.ownerDocument.$domParser.$createNode( + this.ownerDocument, this.nodeType, this); + } + }; + + //@todo + this.canDispatch = function(namespaceURI, type) {}; + + //@todo + this.compareDocumentPosition = function(otherNode) { + /* + DOCUMENT_POSITION_DISCONNECTED = 0x01; + DOCUMENT_POSITION_PRECEDING = 0x02; + DOCUMENT_POSITION_FOLLOWING = 0x04; + DOCUMENT_POSITION_CONTAINS = 0x08; + DOCUMENT_POSITION_CONTAINED_BY = 0x10; + */ + }; + + this.hasAttributes = function(){ + return this.attributes && this.attributes.length; + }; + + this.hasChildNodes = function(){ + return this.childNodes && this.childNodes.length; + }; + + this.isDefaultNamespace = function(namespaceURI) { + if (node.nodeType == 1) { + if (!this.prefix) + return this.namespaceURI == namespaceURI; + + //@todo Loop through attributes here + } + + var node = this.parentNode || this.ownerElement; + return node && node.isDefaultNamespace(namespaceURI); + }; + + this.lookupNamespaceURI = function(prefix) { + if (node.nodeType == 1) { + if (this.namespaceURI && prefix == this.prefix) + return this.namespaceURI ; + + //@todo Loop through attributes here + } + + var node = this.parentNode || this.ownerElement; + return node && node.lookupNamespaceURI(prefix); + }; + + this.lookupPrefix = function(namespaceURI) { + if (this.nodeType == 1) { + if (namespaceURI == this.namespaceURI && this.prefix) + return this.prefix; + + //@todo Loop through attributes here + } + + var node = this.parentNode || this.ownerElement; + return node && node.lookupPrefix(namespaceURI); + }; + + this.normalize = function(){}; + + // *** Xpath support *** // + + /** + * Queries the AML DOM using the W3C xPath query language and returns a node + * list. This is not an official API call, but can be useful in certain cases. + * + * @param {String} sExpr The xpath expression to query the AML DOM tree with. + * @param {apf.AmlNode} [contextNode] The element that serves as the starting point of the search. Defaults to this element. + * @returns {NodeList} List of found nodes. + */ + this.selectNodes = function(sExpr, contextNode) { + if (!apf) return; + + if (!apf.XPath) + apf.runXpath(); + return apf.XPath.selectNodes(sExpr, + contextNode || (this.nodeType == 9 ? this.documentElement : this)); + }; + + /** + * Queries the AML dom using the W3C xPath query language and returns a single + * node. This is not an official API call, but can be useful in certain cases. + * + * @param {String} sExpr The xpath expression to query the AML DOM tree with. + * @param {apf.AmlNode} [contextNode] The element that serves as the starting point of the search. Defaults to this element. + * @returns {apf.AmlNode} The first node that matches the query. + */ + this.selectSingleNode = function(sExpr, contextNode) { + if (!apf) return; + + if (!apf.XPath) + apf.runXpath(); + return apf.XPath.selectNodes(sExpr, + contextNode || (this.nodeType == 9 ? this.documentElement : this))[0]; + }; + + /*this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + + }, true);*/ +}).call(apf.AmlNode.prototype = new apf.Class()); + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + +/** + * Represents a single element within an AML node. + * + * @class apf.AmlElement + * @baseclass + * @inherits apf.AmlNode + */ + + +apf.AmlElement = function(struct, tagName) { + var $init = this.$init; + this.$init = function(tagName, nodeFunc, struct) { + this.$supportedProperties = this.$supportedProperties.slice(); + + var prop, p, q; + p = this.$propHandlers; + q = this.$propHandlers = {}; + for (prop in p) + q[prop] = p[prop]; + + p = this.$booleanProperties; + q = this.$booleanProperties = {}; + for (prop in p) + q[prop] = p[prop]; + + return $init.call(this, tagName, nodeFunc, struct); + }; + + this.$init(function(tagName, nodeFunc, struct) { + this.$events = {}; + this.$inheritProperties = {}; + + /* + * A node list containing all the attributes. This is implemented according to the + * W3C specification. + * + * For more information, see [[apf.AmlElement.getAttribute]] and [[apf.AmlElement.setAttribute]]. + * + * #### Example + * + * ```javascript + * for (var i = 0; i < obj.attributes.length; i++) { + * alert(obj.attributes.item(i)); + * } + * ``` + * @type {apf.AmlNamedNodeMap} + */ + this.attributes = new apf.AmlNamedNodeMap(this); //@todo apf3.0 move to init? + + /** + * Defines the purpose of this element. Possible values include: + * - `apf.NODE_VISIBLE`: This element has a GUI representation + * - `apf.NODE_HIDDEN`: This element does not display a GUI + * @type {Number} + */ + this.nodeFunc = nodeFunc; + + /** + * The local name of this element + * @type {String} + */ + this.localName = tagName; //@todo + + //Parse struct to create attributes and child nodes + if (struct) { + var nodes, prop, i, l, attr; + if (struct.childNodes) { + nodes = struct.childNodes; + delete struct.childNodes; //why delete? + } + + //Attributes + for (prop in struct) { + if (prop == "htmlNode") continue; + + attr = new apf.AmlAttr(this, prop, struct[prop]); + + //These exceptions should be generalized + if (prop == "id") + this.$propHandlers["id"].call(this, this.id = struct.id); + else if (prop == "hotkey") + this.$propHandlers["hotkey"].call(this, this.hotkey = struct.hotkey); + else if (prop.substr(0, 2) == "on") + attr.$triggerUpdate(); + + this.attributes.push(attr); + } + + if (!this.ownerDocument) { + this.ownerDocument = apf.document; + this.prefix = "a"; + this.namespaceURI = apf.ns.aml; + this.tagName = tagName; + } + + if (nodes) { + this.childNodes = nodes; + + for (i = 0, l = nodes.length; i < l; i++) { + nodes[i].nextSibling = nodes[i + 1] || null; + nodes[i].previousSibling = nodes[i - 1] || null; + nodes[i].parentNode = this; + } + this.firstChild = nodes[0] || null; + this.lastChild = nodes[nodes.length - 1] || null; + } + + //Temp hack + this.$aml = apf.$emptyNode || (apf.$emptyNode = apf.getXml("")); + } + }); + + if (tagName) //of typeof is not function and not true + $init.call(this, tagName, apf.NODE_HIDDEN, struct); +}; + +(function(){ + /** + * A number specifying the type of node within the document. + * @type {Number} + */ + this.nodeType = this.NODE_ELEMENT; + this.canHaveChildren = true; + + this.$propHandlers = { + /** + * @attribute {String} id The identifier of this element. When set, this + * identifier is the name of the variable in JavaScript to access this + * element directly. This identifier is also the way to get a reference to + * this element using `apf.document.getElementById()`. + * + * #### Example + * + * ```xml + * + * + * alert(barExample); + * + * ``` + */ + "id": function(value) { + + + if (this.name == value || !value) + return; + + if (self[this.name] == this) { + self[this.name] = null; + + apf.nameserver.remove(this.localName, this); + apf.nameserver.remove("all", this); + + } + + + + if (!self[value] || !self[value].hasFeature) { + try { + self[value] = this; + } + catch (ex) { + + } + } + + + //@todo dispatch event for new name creation. + //@todo old name disposal + + apf.nameserver.register(this.localName, value, this) + apf.nameserver.register("all", value, this) + + + this.name = value; + } + }; + + this.$booleanProperties = {}; + this.$inheritProperties = {}; + this.$supportedProperties = []; + + /** + * Returns a list of elements with the given tag name. + * + * The subtree below the specified element is searched, excluding the + * element itself. + * + * @param {String} tagName The tag name to look for. The special string "*" represents any tag name. + * @param {Boolean} [norecur] If specified, defines whether or not to check recursively + * @return {NodeList} Contains any nodes matching the search string + */ + this.getElementsByTagName = function(tagName, norecur) { + tagName = tagName.toLowerCase(); + var node, i, l, + nodes = this.childNodes, + result = []; + for (i = 0, l = nodes.length; i < l; i++) { + if ((node = nodes[i]).nodeType != 1) + continue; + + if (node.tagName == tagName || tagName == "*") + result.push(node); + + if (!norecur && node.nodeType == 1) + result = result.concat(node.getElementsByTagName(tagName)); + } + + return result; + }; + + /** + * Returns a list of elements with the given tag name and the specified namespace URI. + * + * The subtree below the specified element is searched, excluding the + * element itself. + * + * @param {String} namespaceURI The namespace URI name to look for. + * @param {String} localName The tag name to look for. The special string "*" represents any tag name. + * @param {Boolean} [norecur] If specified, defines whether or not to check recursively + * @return {NodeList} Contains any nodes matching the search string + */ + this.getElementsByTagNameNS = function(namespaceURI, localName, norecur) { + localName = localName.toLowerCase(); + var node, i, l, + nodes = this.childNodes, + result = []; + for (i = 0, l = nodes.length; i < l; i++) { + if ((node = nodes[i]).nodeType != 1) + continue; + + if (node.namespaceURI == namespaceURI && (node.localName == localName || localName == "*")) + result.push(node); + + if (!norecur && node.nodeType == 1) + result = result.concat(node.getElementsByTagNameNS(namespaceURI, localName)); + } + + return result; + }; + + /** + * Sets an attribute on this element. + * @chainable + * @param {String} name The name of the attribute to which the value is set + * @param {String} value The new value of the attribute. + * @param {Boolean} [noTrigger] If specified, does not emit events + * [[apf.AmlNode@DOMNodeInsertedIntoDocument]] and [[apf.AmlNode@DOMNodeInserted]]. + */ + this.setAttribute = function(name, value, noTrigger) { + name = name.toLowerCase(); + + var a = this.attributes.getNamedItem(name); + if (!a) { + this.attributes.push(a = new apf.AmlAttr(this, name, value)); + + if (!this.$amlLoaded && name != "id" && name != "hotkey") + return; + + if (noTrigger) + a.$setValue(value); + else { + //@todo apf3.0 domattr + a.dispatchEvent("DOMNodeInsertedIntoDocument", { + relatedNode: this + }); + + //@todo apf3.0 domattr + a.dispatchEvent("DOMNodeInserted", { + relatedNode: this, + bubbles: true + }); + } + + return; + } + + var oldValue = a.nodeValue; + a.$setValue(value); + + if (noTrigger || !this.$amlLoaded) + return; + + //@todo apf3.0 domattr + a.$triggerUpdate(null, oldValue); + }; + + //@todo apf3.0 domattr + this.setAttributeNode = function(attrNode) { + this.attributes.setNamedItem(attrNode); + }; + + this.setAttributeNS = function(namespaceURI, name, value) { + return this.setAttribute(name, value); + }; + + //@todo apf3.0 domattr + this.hasAttribute = function(name) { + return this.getAttributeNode(name) ? true : false; + }; + + //@todo + this.hasAttributeNS = function(namespaceURI, name) { + return this.hasAttribute(name); + }; + + /** + * Removes an attribute from this element. + * @chainable + * @param {String} name The name of the attribute to remove. + * @returns {apf.AmlElement} The modified element. + */ + this.removeAttribute = function(name){ //@todo apf3.0 domattr + this.attributes.removeNamedItem(name); + return this; + }; + + //@todo apf3.0 domattr + this.removeAttributeNS = function(namespaceURI, name) { + return this.removeAttribute(name); + }; + + //@todo apf3.0 domattr + this.removeAttributeNode = function(attrNode) { + this.attributes.removeNamedItem(attrNode.name); //@todo this should probably be slightly different. + }; + + /** + * Retrieves the value of an attribute of this element. + * + * @param {String} name The name of the attribute for which to return the value. + * @param {Boolean} [inherited] if specified, takes into consideration that the attribute is inherited + * @return {String} The value of the attribute, or `null` if none was found with the name specified. + */ + this.getAttribute = function(name, inherited) { + var item = this.attributes.getNamedItem(name); + return item ? (inherited + ? item.inheritedValue || item.nodeValue + : item.nodeValue) : null; + }; + + /** + * Retrieves the attribute node for a given name + * + * @param {String} name The name of the attribute to find. + * @return {apf.AmlNode} The attribute node, or `null` if none was found with the name specified. + */ + this.getAttributeNode = function(name) { + return this.attributes.getNamedItem(name); + }; + + this.getBoundingClientRect = function(){ + return new apf.AmlTextRectangle(this); + }; + + //@todo + this.querySelector = function(){ + // here we should use: http://code.google.com/p/css2xpath/source/browse/trunk/src/css2xpath.js + }; + + //@todo + this.querySelectorAll = function(){ + // here we should use: http://code.google.com/p/css2xpath/source/browse/trunk/src/css2xpath.js + }; + + //@todo + this.scrollIntoView = function(){ + + }; + + /** + * Replaces the child AML elements with new AML. + * @param {Mixed} amlDefNode The AML to be loaded. This can be a string or a parsed piece of XML. + * @param {HTMLElement} oInt The HTML parent of the created AML elements. + */ + this.replaceMarkup = function(amlDefNode, options) { + + + if (!options) + options = {}; + + if (!options.$intAML) + options.$intAML = this.$aml; + if (!options.$int) + options.$int = this.$int; + options.clear = true; + + //Remove All the childNodes + for (var i = this.childNodes.length - 1; i >= 0; i--) { + var oItem = this.childNodes[i]; + /*var nodes = oItem.childNodes; + for (var k = 0; k < nodes.length; k++) + if (nodes[k].destroy) + nodes[k].destroy(true); + + if (oItem.$aml && oItem.$aml.parentNode) + oItem.$aml.parentNode.removeChild(oItem.$aml);*/ + + if (oItem.destroy) + oItem.destroy(true); + + if (oItem.$ext != this.$int) + apf.destroyHtmlNode(oItem.$ext); + } + + this.childNodes.length = 0; + + if (options.noLoadingMsg !== false) + this.$int.innerHTML = "
      loading...
      "; + + //Do an insertMarkup + this.insertMarkup(amlDefNode, options); + }; + + /** + * Inserts new AML into this element. + * @param {Mixed} amlDefNode The AML to be loaded. This can be a string or a parsed piece of XML. + * @param {Object} options Additional options to pass. It can include the following properties: + * - callback ([[Function]]): A function to call once the insertion completes. + * - clear ([[Boolean]]): If set, the AML has the attribute "clear" attached to it + */ + this.insertMarkup = function(amlDefNode, options) { + + + + + var _self = this; + var include = new apf.XiInclude(); + + if (amlDefNode.trim().charAt(0) == "<") + amlDefNode = apf.getXml(amlDefNode); + + include.setAttribute("href", amlDefNode); + if (options && options.clear) + include.setAttribute("clear", true); + include.options = options; + include.callback = function(){ + _self.dispatchEvent("afteramlinserted", {src: amlDefNode}); + options && options.callback && options.callback(); + setTimeout(function(){ + include.destroy(true, true); + }); + }; + this.appendChild(include); + }; + + //@todo prefix only needs on top element + this.serialize = function(shallow) { + if (shallow || !this.firstChild) { + return "<" + + (this.prefix + ? this.prefix + ":" + this.localName + " xmlns:" + + this.prefix + "=\"" + this.namespaceURI + "\"" + : this.localName) + (this.attributes && this.attributes.length ? " " : "") + + (this.attributes && this.attributes.join(" ") || "") + + "/>"; + } + else { + var str = ["<" + + (this.prefix + ? this.prefix + ":" + this.localName + " xmlns:" + + this.prefix + "=\"" + this.namespaceURI + "\"" + : this.localName) + (this.attributes && this.attributes.length ? " " : "") + + (this.attributes && this.attributes.join(" ") || "") + + ">"]; + + for (var i = this.firstChild; i; i = i.nextSibling) + str.push(i.serialize()); + + return str.join("") + ""; + } + }; + + this.$setInheritedAttribute = function(prop) { + var value, node = this, isInherit = false; + + value = node.getAttribute(prop); + if (!value) { + node = node.parentNode; + + //Second argument fetches special inheritance value, if any + while (node && node.nodeType == 1 && !(value = node.getAttribute(prop, true))) { + node = node.parentNode; + } + + isInherit = true; + } + + if (!value && apf.config && prop) + value = apf.config[prop]; + + if (value) { + + //Remove any bounds if relevant + this.$clearDynamicProperty(prop); + + } + + if (isInherit) + this.$inheritProperties[prop] = 2; + + if (value) { + + if (typeof value == "string" + && (value.indexOf("{") > -1 || value.indexOf("[") > -1)) { + this.$setDynamicProperty(prop, value); + } + else + + this.setProperty(prop, value, false, false, 2); + } + + return value; + }; + + //@todo in proper W3C implementation this needs to change + //@todo this won't work with a combo of remove/append + this.addEventListener("DOMNodeInserted", function(e) { + if (e.currentTarget != this || e.$isMoveWithinParent || !e.$oldParent) + return; + + //Check inherited attributes for reparenting + /* + States: + -1 Set + undefined Pass through + 2 Inherited + 3 Semi-inherited + 10 Dynamic property + */ + var vOld, vNew; + var aci = apf.config.$inheritProperties; + for (var prop in aci) { + vOld = apf.getInheritedAttribute(e.$oldParent, prop); + vNew = apf.getInheritedAttribute(this.parentNode, prop); + + //Property has changed, lets recursively set it on inherited nodes + if (vOld != vNew) { + //@todo code duplication from class.js + (function recur(nodes) { + var i, l, node, n; + for (i = 0, l = nodes.length; i < l; i++) { + node = nodes[i]; + if (node.nodeType != 1 && node.nodeType != 7) + continue; + + //Pass through + n = node.$inheritProperties[prop]; + if (aci[prop] == 1 && !n) + recur(node.childNodes); + + //Set inherited property + //@todo why are dynamic properties overwritten?? + else if (!(n < 0)) {//Will also pass through undefined - but why??? @todo seems inefficient + if (n == 3) { + var sameValue = node[prop]; + node[prop] = null; + } + node.setProperty(prop, n != 3 + ? vNew + : sameValue, false, false, n); //This is recursive already + } + } + })([this]); + } + } + }); + + this.$handlePropSet = function(prop, value, force) { + if (this.$booleanProperties[prop]) + value = apf.isTrue(value); + + + + this[prop] = value; + + var handler; + return (handler = this.$propHandlers && this.$propHandlers[prop] + || this.nodeFunc == apf.NODE_VISIBLE && apf.GuiElement && apf.GuiElement.propHandlers[prop] || null) + && handler.call(this, value, prop, force); + }; + + //var aci = apf.config.$inheritProperties; << UNUSED + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + var a, i, l, attr = this.attributes; + + + + + + + + //Set all attributes + for (i = 0, l = attr.length; i < l; i++) { + attr[i].dispatchEvent("DOMNodeInsertedIntoDocument"); + } + }, true); + + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + this.$amlLoaded = true; + }); +}).call(apf.AmlElement.prototype = new apf.AmlNode()); + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +//@todo apf3.0 The functions seem to not set nodeValue... +apf.AmlCharacterData = function(){ + this.data = ""; + this.length = 0; + + this.$init(true); + + this.appendData = function(sValue) { + this.dispatchEvent("DOMCharacterDataModified", { + value: sValue + }); + }; + + this.deleteData = function(nOffset, nCount) { + this.dispatchEvent("DOMCharacterDataModified", { + offset: nOffset, + count: nCount + }); + }; + + this.insertData = function(nOffset, nCount) { + this.dispatchEvent("DOMCharacterDataModified", { + offset: nOffset, + count: nCount + }); + }; + + this.replaceData = function(nOffset, nCount, sValue) { + this.dispatchEvent("DOMCharacterDataModified", { + offset: nOffset, + count: nCount, + value: sValue + }); + }; + + this.substringData = function(nOffset, nCount) {}; +} +apf.AmlCharacterData.prototype = new apf.AmlNode(); + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +apf.AmlText = function(isPrototype) { + this.$init(isPrototype); +}; + +(function(){ + this.nodeType = this.NODE_TEXT; + this.nodeName = "#text"; + + this.serialize = function(){ + return apf.escapeXML(this.nodeValue); + }; + + + + //@todo think about using this.replaceData(); + this.$setValue = function(value) { + //if (!this.$amlLoaded) + //return; + + this.dispatchEvent("DOMCharacterDataModified", { + bubbles: true, + prevValue: this.nodeValue, + newValue: this.nodeValue = value + }); + + if (this.$amlLoaded && this.$ext) + this.$ext.nodeValue = value; + } + + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + var pHtmlNode; + if (!(pHtmlNode = this.parentNode.$int) || this.parentNode.hasFeature(apf.__CHILDVALUE__)) + return; + + this.$amlLoaded = true; + + var nodeValue = this.nodeValue; + + //@todo optimize for inside elements? + if (apf.config.liveText && !this.parentNode.hasFeature(apf.__CHILDVALUE__) + && (nodeValue.indexOf("{") > -1 || nodeValue.indexOf("[") > -1)) { + + //Convert to live markup pi + this.$supportedProperties = []; + this.$propHandlers = {}; + this.$booleanProperties = {}; + this.$inheritProperties = {}; + + this.$propHandlers["calcdata"] = apf.LiveMarkupPi.prototype.$propHandlers["calcdata"]; + + this.$setInheritedAttribute = apf.AmlElement.prototype.$setInheritedAttribute; + + this.implement(apf.StandardBinding); + + + pHtmlNode.appendChild(this.$ext = document.createElement("span")); + this.$setDynamicProperty("calcdata", this.nodeValue); + + return; + } + + if (apf.hasTextNodeWhiteSpaceBug) { + var nodeValue = nodeValue.replace(/[\t\n\r ]+/g, " "); + + if (nodeValue && nodeValue != " ") + this.$ext = pHtmlNode.appendChild( + pHtmlNode.ownerDocument.createTextNode(nodeValue)); + } + else + this.$ext = pHtmlNode.appendChild( + pHtmlNode.ownerDocument.createTextNode(nodeValue)); + }, true); +}).call(apf.AmlText.prototype = new apf.AmlCharacterData()); + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +apf.AmlAttr = function(ownerElement, name, value) { + this.$init(); + + if (ownerElement) { + this.ownerElement = ownerElement; + this.ownerDocument = ownerElement.ownerDocument; + } + + this.nodeName = this.name = name; + this.nodeValue = this.value = value; +}; + +(function(){ + this.nodeType = this.NODE_ATTRIBUTE; + + this.MODIFICATION = 1; + this.ADDITION = 2; + this.REMOVAL = 3; + + this.serialize = + this.toString = function(){ + return this.name + "=\"" + apf.escapeXML(String(this.value)) + "\""; + }; + + + + this.$setValue = function(value) { + this.nodeValue = this.value = value; + this.specified = true; + + //@todo apf3.0 domattr + this.ownerElement.dispatchEvent("DOMAttrModified", { + relatedNode: this, + attrChange: this.MODIFICATION, + attrName: this.name, + newValue: value, + prevValue: this.$lastValue || "", + bubbles: true + }); + + this.$lastValue = value; + }; + + this.$triggerUpdate = function(e, oldValue) { + var name = this.name, + value = this.value || this.nodeValue, + host = this.ownerElement, + isEvent = name.substr(0, 2) == "on"; + + if (!this.specified) { + //@todo This should be generalized + if (isEvent && this.$lastValue == value + || name == "id" && host.id) { + this.specified = true; + return; + } + } + + if (isEvent) { + if (host.$events[name]) + host.removeEventListener(name.substr(2), host.$events[name]); + if (value) + host.addEventListener(name, (host.$events[name] = + (typeof value == "string" + ? + new Function('event', value) + + : value))); + return; + } + + if (this.specified) + host.$clearDynamicProperty(name); + + if (typeof value == "string" && (host.$attrExcludePropBind[name] || + (value.indexOf("{") > -1 || value.indexOf("[") > -1))) + host.$setDynamicProperty(name, value); + else + + { + host.setProperty(name, value); //@todo apf3.0 is this a lot slower? + } + //host.$handlePropSet(name, value); + + if (this.specified) { + //@todo apf3.0 domattr - slow? + host.dispatchEvent("DOMAttrModified", { //@todo this is not good, node might not be specified at init + relatedNode: this, + attrChange: this.MODIFICATION, + attrName: name, + newValue: value, + prevValue: this.$lastValue || "", + bubbles: true + }); + } + else this.specified = true; + + this.$lastValue = value; + }; + + //@todo apf3.0 domattr + this.addEventListener("DOMNodeInsertedIntoDocument", this.$triggerUpdate); +}).call(apf.AmlAttr.prototype = new apf.AmlNode()); + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +apf.AmlCDATASection = function(isPrototype) { + this.nodeType = this.NODE_CDATA_SECTION; + this.nodeName = "#cdata-section"; + + this.$init(isPrototype); +}; + +apf.AmlCDATASection.prototype = new apf.AmlText(true); +apf.AmlCDATASection.prototype.serialize = function(){ + return ""; +}; + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +apf.AmlComment = function(isPrototype) { + this.nodeType = this.NODE_COMMENT; + this.nodeName = "#comment"; + + this.$init(isPrototype); +}; + +(function(){ + this.serialize = function(){ + return ""; + }; + + this.$setValue = function(value) { + this.dispatchEvent("DOMCharacterDataModified", { + bubbles: true, + newValue: value, + prevValue: this.nodeValue + }); + } +}).call(apf.AmlComment.prototype = new apf.AmlCharacterData()); + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +apf.AmlConfiguration = function(isPrototype) { + this.parameterNames = []; + + this.$init(isPrototype); +}; + +(function(){ + this.setParameter = this.setProperty; + + this.getParameter = this.getProperty; + + this.canSetParameter = function(name, value){ //@todo for value + return this.parameterNames.indexOf(name) > -1; + }; +}).call(apf.AmlConfiguration.prototype = new apf.Class()); + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * The AML document. This is the root of the DOM tree and has a nodeType with + * value 9 (`apf.NODE_DOCUMENT`). + * + * @class apf.AmlDocument + * @inherits apf.AmlNode + * @inherits apf.Class + * @default_private + * @see apf.AmlDom + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.8 + */ +apf.AmlDocument = function(){ + this.$prefixes = {}; + this.$namespaceURIs = {}; + + this.domConfig = new apf.AmlConfiguration(); + + + this.$init(); +}; + +(function() { + /** + * The type of node within the document. + * @type {Number} + */ + this.nodeType = this.NODE_DOCUMENT; + this.nodeFunc = apf.NODE_HIDDEN; + this.nodeName = "#document"; + + this.$amlLoaded = true; + + this.activeElement = null; //@todo alias of window.foccussed; + this.doctype = null; + this.domConfig = null; + this.implementation = null; + this.characterSet = apf.characterSet; + + /** + * The root element node of the AML application. This is an element with + * the tagName `'application'`. This is similar to the `'html'` element for regular HTML. + * @type {apf.AmlNode} + */ + this.documentElement = null; + + /** + * Gets a AML element based on its id. + * @param {String} id The id of the AML element to return. + * @return {apf.AmlElement} The AML element with the id specified. + */ + this.getElementById = function(id) { + return self[id]; + }; + + /** + * Returns a list of elements with the given tag name. + * + * The subtree below the [[apf.AmlDocument.documentElement]] is searched, excluding the + * element itself. + * + * @param {String} tagName The tag name to look for. The special string "*" represents any tag name. + * @return {NodeList} Contains any nodes matching the search string + */ + this.getElementsByTagName = function(tagName) { + var docEl, res = (docEl = this.documentElement) + .getElementsByTagName(tagName); + + if (tagName == "*" || docEl.tagName == tagName) + res.unshift(docEl); + return res; + }; + + /** + * Returns a list of elements with the given tag name and the specified namespace URI. + * + * The subtree below the [[apf.AmlDocument.documentElement]] is searched, excluding the + * element itself. + * + * @param {String} namespaceURI The namespace URI name to look for. + * @param {String} tagName The tag name to look for. The special string "*" represents any tag name. + * @return {NodeList} Contains any nodes matching the search string + */ + this.getElementsByTagNameNS = function(nameSpaceURI, tagName) { + var docEl, + res = (docEl = this.documentElement) + .getElementsByTagNameNS(nameSpaceURI, tagName); + + if (tagName == "*" || docEl.tagName == tagName && docEl.namespaceURI == nameSpaceURI) + res.unshift(docEl); + return res; + }; + + /** + * Creates a new AML element. + * + * @param {Mixed} qualifiedName Information about the new node to create. Possible values include: + * - [[String]]: The tag name of the new element to create + * - [[String]]: The AML definition for a single or multiple elemnts + * - [[XMLElement]]: The AML definition for a single or multiple elements + * @return {apf.AmlElement} The created AML element + */ + this.createElement = function(qualifiedName) { + return this.$domParser.$createNode(this, this.NODE_ELEMENT, null, + this.namespaceURI, qualifiedName); + }; + + /** + * Creates a new AML element within the given namespace. + * + * @param {String} namespaceURI The namespace URI name to use + * @param {Mixed} qualifiedName Information about the new node to create. Possible values include: + * - [[String]]: The tag name of the new element to create + * - [[String]]: The AML definition for a single or multiple elemnts + * - [[XMLElement]]: The AML definition for a single or multiple elements + * @return {apf.AmlElement} The created AML element + */ + this.createElementNS = function(namespaceURI, qualifiedName) { + return this.$domParser.$createNode(this, this.NODE_ELEMENT, null, + namespaceURI, qualifiedName); + }; + + /** + * Creates a copy of a node from an external document that can be inserted into the current document. + * + * @param {apf.AmlNode} node The node to import and copy + * @param {Boolean} [deep] Indicates whether the descendants of the imported node should also be imported + * @return {apf.AmlNode} The imported node + */ + this.importNode = function(node, deep) { + if (deep && node.nodeType == 1) { + return this.$domParser.parseFromXml(node, { + doc: this, + delay: true + }).childNodes[0]; + } + else { + return this.$domParser.$createNode(this, node.nodeType, node); + } + }; + + /** + * Creates and returns a new attribute node. + * + * @param {String} nodeName The name of the attribute + * @return {apf.AmlNode} The attribute node + */ + this.createAttribute = function(nodeName) { + return this.$domParser.$createNode(this, this.NODE_ATTRIBUTE, null, + this.nameSpaceURI, nodeName); + }; + + /** + * Creates and returns a new attribute node, within a specified URI. + * + * @param {String} nameSpaceURI The name of the URI + * @param {String} nodeName The name of the attribute + * @return {apf.AmlNode} The attribute node + */ + this.createAttributeNS = function(nameSpaceURI, nodeName) { + return this.$domParser.$createNode(this, this.NODE_ATTRIBUTE, null, + nameSpaceURI, nodeName); + }; + /** + * Creates and returns a new [[apf.AmlEvent]] . + */ + this.createEvent = function(){ + return new apf.AmlEvent(); + }; + + /** + * Creates and returns a new comment node. + * @param {String} nodeValue The data to be added to the comment + * @return {apf.AmlNode} The comment node + */ + this.createComment = function(nodeValue) { + return this.$domParser.$createNode(this, this.NODE_COMMENT, null, null, + null, nodeValue); + }; + + /** + * Creates and returns a new processing instruction node. + * @param {String} target The target part of the processing instruction node, like `` + * @param {String} data The data to be added to the PI + * @return {apf.AmlNode} The processing instruction node + */ + this.createProcessingInstruction = function(target, data) { + return this.$domParser.$createNode(this, this.NODE_PROCESSING_INSTRUCTION, + null, null, target, data); + }; + + /** + * Creates and returns a new CDATA section node. + * @param {String} nodeValue The data to be added to the CDATA node + * @return {apf.AmlNode} The CDATA section node + */ + this.createCDATASection = function(nodeValue) { + return this.$domParser.$createNode(this, this.NODE_CDATA_SECTION, null, + null, null, nodeValue); + }; + + /** + * Creates and returns a new Text node. + * @param {String} nodeValue The data to be added to the text node + * @return {apf.AmlNode} The Text node + */ + this.createTextNode = function(nodeValue) { + return this.$domParser.$createNode(this, this.NODE_TEXT, null, null, + null, nodeValue); + }; + + /** + * Creates and returns a new document fragment. + */ + + this.createDocumentFragment = function(){ + return this.$domParser.$createNode(this, this.NODE_DOCUMENT_FRAGMENT); + }; + + // @todo + this.querySelector = function(){}; + + // @todo + this.querySelectorAll = function(){}; + + + + // @todo + this.hasFocus = function(){ + + } + + +}).call(apf.AmlDocument.prototype = new apf.AmlNode()); + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +apf.AmlDocumentFragment = function(isPrototype) { + this.$init(isPrototype); +}; + +apf.AmlDocumentFragment.prototype = new apf.AmlNode(); +apf.AmlDocumentFragment.prototype.nodeName = "#document-fragment"; +apf.AmlDocumentFragment.prototype.nodeType = + apf.AmlDocumentFragment.prototype.NODE_DOCUMENT_FRAGMENT; + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +/** + * Implementation of the W3C event object. An instance of this class is passed as + * the first argument of any event handler. As per event, it contains different + * properties giving context based information about the event. + * @class apf.AmlEvent + * @default_private + */ +apf.AmlEvent = function(name, data) { + this.name = name; + + var prop; + for (prop in data) + this[prop] = data[prop]; +}; + +apf.AmlEvent.prototype = { + + bubbles: false, + cancelBubble: false, + + + /** + * Cancels the event (if it is cancelable), without stopping further + * propagation of the event. + */ + preventDefault: function(){ + this.returnValue = false; + }, + + + /** + * Prevents further propagation of the current event. + */ + stopPropagation: function(){ + this.cancelBubble = true; + }, + + + stop: function() { + this.returnValue = false; + + this.cancelBubble = true; + + } +}; + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +//@todo apf3.0 +apf.AmlNamedNodeMap = function(host) { + this.$host = host; +}; + +(function(){ + this.getNamedItem = function(name) { + for (var i = 0; i < this.length; i++) { + if (this[i].name == name) + return this[i]; + } + return false; + }; + + this.setNamedItem = function(node) { + var name = node.name; + for (var item, i = this.length - 1; i >= 0; i--) { + if (this[i].name == name) { + this[i].ownerElement = null; + this.splice(i, 1); + break; + } + } + + this.push(node); + + node.ownerElement = this.$host; + node.ownerDocument = this.$host.ownerDocument; + node.$triggerUpdate(); + }; + + //@todo apf3.0 domattr + this.removeNamedItem = function(name) { + //Should deconstruct dynamic properties + + for (var item, i = this.length - 1; i >= 0; i--) { + if (this[i].name == name) { + item = this[i]; + this.splice(i, 1); + break; + } + } + if (!item) return false; + + //@todo hack! + //this should be done properly + var oldValue = item.nodeValue; + item.nodeValue = item.value = ""; + item.$triggerUpdate(null, oldValue); + item.ownerElement = null; + item.nodeValue = item.value = oldValue; + + return item; + }; + + this.item = function(i) { + return this[i]; + }; + + //if (apf.isIE < 8) { //Only supported by IE8 and above + this.length = 0; + + this.splice = function(pos, length) { + for (var i = pos, l = this.length - length; i < l; i++) { + this[i] = this[i + 1]; + } + delete this[i]; + this.length -= length; + } + + this.push = function(o) { + this[this.length++] = o; + return this.length; + } + //} + + this.join = function(glue) { + var x = []; + for (var e, a, i = 0, l = this.length; i < l; i++) { + if ((e = (a = this[i]).ownerElement) && e.$inheritProperties[a.nodeName] != 2) + x.push(this[i]); + } + return x.join(glue); + } +}).call(apf.AmlNamedNodeMap.prototype = {}); //apf.isIE < 8 ? {} : [] + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +apf.AmlProcessingInstruction = function(isPrototype) { + this.$init(isPrototype); +}; + +(function(){ + this.nodeType = this.NODE_PROCESSING_INSTRUCTION; + + /* + * @todo docs + */ + this.data = null; + + /* + * @todo docs + */ + this.target = null; + + this.serialize = function(){ + return ""; + }; + + this.reload = function(){ + this.$handlePropSet("data", this.data); + }; + + //1 = force no bind rule, 2 = force bind rule + this.$attrExcludePropBind = apf.extend({ + calcdata: 0 //Start in code mode + }, this.$attrExcludePropBind); + + this.getAttribute = function(){}; + this.$setInheritedAttribute = apf.AmlElement.prototype.$setInheritedAttribute; + this.$supportedProperties = []; + this.$propHandlers = {}; + this.$booleanProperties = {}; + this.$inheritProperties = {}; + + + + this.$setValue = function(value) { + this.setProperty("data", value); + }; + + this.$handlePropSet = function(prop, value, force) { + this[prop] = value; + if (prop == "data") { + this.$clearDynamicProperty("calcdata"); + this.$setDynamicProperty("calcdata", value); + } + + else if (prop == "target") { + //not implemented + } + else if (this.$propHandlers[prop]) { + this.$propHandlers[prop].call(this, value, prop); + } + }; + + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + var pHtmlNode = e.pHtmlNode; + if (!pHtmlNode && (this.parentNode.$bindingRule + || !(pHtmlNode = this.parentNode.$int))) + return; + + pHtmlNode.appendChild(this.$ext = document.createElement("span")); + this.$ext.host = this; + + + + this.$setDynamicProperty("calcdata", this.data); + + + }, true); + + /*this.addEventListener("DOMNodeRemovedFromDocument", function(e) { + this.$clearDynamicProperty("calcdata"); + });*/ + + this.$destroy = function(){ + this.$clearDynamicProperty("calcdata"); + this.$propHandlers["calcdata"].call(this, ""); + }; +}).call(apf.AmlProcessingInstruction.prototype = new apf.AmlNode()); + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +apf.AmlTextRectangle = function(host) { + var _self = this; + function handler(){ + var pos = _self.getAbsolutePosition(_self.$ext); + _self.setProperty("left", pos[0]); + _self.setProperty("top", pos[1]); + _self.setProperty("right", document.documentElement.offsetWidth - pos[0]); + _self.setProperty("bottom", document.documentElement.offsetWidth - pos[1]); + } + + host.addEventListener("prop.width", handler); + host.addEventListener("prop.height", handler); + host.addEventListener("prop.left", handler); + host.addEventListener("prop.top", handler); + + handler.call(host); +}; +apf.AmlTextRectangle.prototype = new apf.Class(); + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/* + * An object creating the XHTML namespace for the aml parser. + * + * @constructor + * @parser + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.8 + */ +apf.xhtml = new apf.AmlNamespace(); +apf.setNamespace("http://www.w3.org/1999/xhtml", apf.xhtml); + + +/* +if (apf.getTextNode(x)) { + var data = { + amlNode: x, + htmlNode: o + } + + +} + +*/ + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +apf.XhtmlElement = function(struct, tagName) { + this.$init(tagName || true, apf.NODE_VISIBLE, struct); + + this.$xoe = this.addEventListener; + this.addEventListener = this.$xae; + this.removeEventListener = this.$xre; + + var _self = this; + this.$de = function(e) { + _self.dispatchEvent(e.type, null, e); + } +}; + +(function(){ + var excludedEvents = { + "contextmenu": 1, + "keydown": 1, + "keypress": 1, + "keyup": 1, + "DOMNodeInserted": 2, + "DOMNodeInsertedIntoDocument": 2, + "DOMNodeRemoved": 2, + "DOMNodeRemovedFromDocument": 2 + }; + + this.$xae = function(type, fn) { + this.$xoe.apply(this, arguments); + + if (excludedEvents[type] > (this.editable ? 0 : 1) + || type.substr(0, 5) == "prop.") + return; + + if (this.$ext) { + if (type.substr(0,2) == "on") + type = type.substr(2); + apf.addListener(this.$ext, type, this.$de); + } + }; + + this.$xre = function(type, fn) { + apf.AmlElement.prototype.removeEventListener.apply(this, arguments); + + + + if (this.$ext) + apf.removeListener(this.$ext, type, this.$de); + } + + this.$handlePropSet = function(name, value, force, inherit) { + if (this.$booleanProperties[name]) + value = apf.isTrue(value); + + this[name] = value; + var handler = this.$propHandlers && this.$propHandlers[name] + || apf.GuiElement.propHandlers[name]; + + if (handler) + handler.call(this, value, null, name); + else if (this.$int && (force || this.$amlLoaded)) { + this.$int.setAttribute(apf.isIE && apf.isIE < 8 && name == "class" + ? "className" : name, value); + } + }; + + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + var pHtmlNode; + if (!(pHtmlNode = this.$pHtmlNode = this.parentNode.$int)) + return; + + var str, aml = this.$aml; + if (aml) { + if (aml.serialize) + str = aml.serialize(); + else { + aml = aml.cloneNode(false); + str = aml.xml || aml.nodeValue; + } + + str = str.replace(/ on\w+="[^"]*"| on\w+='[^']*'/g, ""); + + this.$ext = + this.$int = apf.insertHtmlNode(null, pHtmlNode, null, apf.html_entity_decode(str)); + } + else { + this.$ext = this.$int = + pHtmlNode.appendChild(document.createElement(this.localName)); + } + + if (this.localName != "a") + this.$ext.host = this; + + this.style = this.$ext.style; + }, true); + + + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + this.$amlLoaded = true; + + if (this.$setLayout) + this.$setLayout(); + }); + +}).call(apf.XhtmlElement.prototype = new apf.AmlElement()); + +apf.Init.addConditional(function(){ + if (apf.isO3) return; + var prot = apf.XhtmlElement.prototype; + + //prot.implement(apf.Interactive); + prot.implement( + + apf.Anchoring + + ); + + + prot.$drawn = true; + prot.$setLayout = apf.GuiElement.prototype.$setLayout; + + prot.addEventListener("DOMNodeInserted", function(e) { + if (e.currentTarget == this + && "vbox|hbox|table".indexOf(this.parentNode.localName) == -1) { + this.$setLayout(); + } + }); + +}, null, ["interactive"]); + +apf.xhtml.setElement("@default", apf.XhtmlElement); + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +apf.XhtmlBodyElement = function(struct, tagName) { + this.$init(tagName || "body", apf.NODE_VISIBLE, struct); +}; + +(function(){ + + + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + if (!this.ownerDocument.body) + this.ownerDocument.body = this; + + this.$ext = + this.$int = document.body; + }, true); +}).call(apf.XhtmlBodyElement.prototype = new apf.AmlElement()); + +apf.Init.addConditional(function(){ + if (apf.isO3) return; + var prot = apf.XhtmlBodyElement.prototype; + + +}, null, ["interactive"]); + +apf.xhtml.setElement("body", apf.XhtmlBodyElement); + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * @todo description + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.4 + */ +apf.XhtmlHtmlElement = function(struct, tagName) { + this.$init(tagName || "html", apf.NODE_VISIBLE, struct); + + + + this.$ext = document.documentElement; + this.$ext.host = this; + + this.$int = document.body; + this.$tabList = []; //Prevents documentElement from being focussed + this.$focussable = apf.KEYBOARD; + this.focussable = true; + this.visible = true; + this.$isWindowContainer = true; + //this.focus = function(){ this.dispatchEvent("focus"); }; + //this.blur = function(){ this.dispatchEvent("blur"); }; + + this.implement(apf.Focussable); + + + apf.window.$addFocus(this); + + + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + var i, l, n, a, c, + attr = this.attributes, doc = this.ownerDocument; + for (i = 0, l = attr.length; i < l; i++) { + n = (a = attr[i]).nodeName.split(":"); + if (n[0] == "xmlns") { + if (c = n[1]) { + doc.$prefixes[c] = a.nodeValue; + doc.$namespaceURIs[a.nodeValue] = c; + } + else { + doc.namespaceURI = a.nodeValue; + } + } + } + + if (!doc.namespaceURI) + doc.namespaceURI = apf.ns.xhtml; + }); +}; +apf.XhtmlHtmlElement.prototype = new apf.XhtmlElement(); + +apf.xhtml.setElement("html", apf.XhtmlHtmlElement); + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +apf.XhtmlIgnoreElement = function(struct, tagName) { + this.$init(tagName, apf.NODE_VISIBLE, struct); +}; + +apf.XhtmlIgnoreElement.prototype = new apf.AmlElement(); + +apf.xhtml.setElement("script", apf.XhtmlIgnoreElement); +apf.xhtml.setElement("noscript", apf.XhtmlIgnoreElement); +apf.xhtml.setElement("head", apf.XhtmlIgnoreElement); +apf.xhtml.setElement("meta", apf.XhtmlIgnoreElement); + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +apf.XhtmlInputElement = function(struct, tagName) { + this.$init(tagName || "input", apf.NODE_VISIBLE, struct); +}; + +(function(){ + this.$xae = apf.XhtmlElement.prototype.$xae; + this.$xre = apf.XhtmlElement.prototype.$xre; + this.$handlePropSet = function(name, value, force) { + if (name == "type") + return; + + return apf.XhtmlElement.prototype.$handlePropSet.call(this, name, value, force); + }; + + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + var pHtmlNode; + if (!(pHtmlNode = this.parentNode.$int)) + return; + + if (this.$aml) { + this.$ext = + this.$int = apf.insertHtmlNode(this.$aml.serialize + ? this.$aml + : this.$aml.cloneNode(false), pHtmlNode); + } + else { + this.$ext = this.$int = document.createElement(this.localName); + if (this.getAttribute("type")) + this.$int.setAttribute("type", this.getAttribute("type")); + pHtmlNode.appendChild(this.$int); + } + }, true); +}).call(apf.XhtmlInputElement.prototype = new apf.AmlElement()); + +apf.xhtml.setElement("input", apf.XhtmlInputElement); + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +apf.XhtmlOptionElement = function(struct, tagName) { + this.$init(tagName || "option", apf.NODE_VISIBLE, struct); +}; + +(function(){ + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + this.$ext = + this.$int = this.parentNode.$int.appendChild( + this.parentNode.$int.ownerDocument.createElement("option")); + + if (this.value) + this.$int.setAttribute("value", this.value); + }, true); +}).call(apf.XhtmlOptionElement.prototype = new apf.AmlElement()); + +apf.xhtml.setElement("option", apf.XhtmlOptionElement); + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +apf.XhtmlSkipChildrenElement = function(struct, tagName) { + this.$init(tagName, apf.NODE_VISIBLE, struct); +}; + +(function(){ + this.canHaveChildren = false; + + this.$redraw = function(){ + var _self = this; + apf.queue.add("redraw" + this.$uniqueId, function(){ + var pHtmlNode = _self.$ext.parentNode; + var beforeNode = _self.$ext.nextSibling; + pHtmlNode.removeChild(_self.$ext); + + _self.$ext = apf.insertHtmlNode(null, pHtmlNode, beforeNode, _self.$aml + ? (_self.$aml.serialize ? _self.$aml.serialize() : _self.$aml.xml) + : _self.serialize()); + }); + } + + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + var pHtmlNode; + if (!(pHtmlNode = this.parentNode.$int)) + return; + + this.$ext = apf.insertHtmlNode(null, pHtmlNode, null, this.$aml + ? (this.$aml.serialize ? this.$aml.serialize() : this.$aml.xml) + : this.serialize()); + }, true); +}).call(apf.XhtmlSkipChildrenElement.prototype = new apf.AmlElement()); + +apf.xhtml.setElement("object", apf.XhtmlSkipChildrenElement); +apf.xhtml.setElement("embed", apf.XhtmlSkipChildrenElement); +apf.xhtml.setElement("table", apf.XhtmlSkipChildrenElement); + +apf.xhtml.setElement("pre", apf.XhtmlSkipChildrenElement); + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* #-ifdef __WITH_HTML5 +if (tagName == "input") { + objName = apf.HTML5INPUT[objName = x.getAttribute("type")] + || objName || "textbox"; +} +//#-endif*/ + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +//XForms + + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * Object creating the XML Include namespace for the aml parser. + * + * @constructor + * @parser + * + * @allownode simpleType, complexType + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.8 + */ +apf.xinclude = new apf.AmlNamespace(); +apf.setNamespace("http://www.w3.org/2001/XInclude", apf.xinclude); + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +/** + * Defines a list of acceptable values + */ +apf.XiInclude = function(struct, tagName) { + this.$init(tagName || "include", apf.NODE_HIDDEN, struct); +}; + +apf.xinclude.setElement("include", apf.XiInclude); +apf.aml.setElement("include", apf.XiInclude); + +//@todo test defer="true" situation +(function(){ + this.$parsePrio = "002"; + + //1 = force no bind rule, 2 = force bind rule + /*this.$attrExcludePropBind = apf.extend({ + href: 1, + src: 1 + }, this.$attrExcludePropBind);*/ + + this.$propHandlers["href"] = + this.$propHandlers["src"] = function(value) { + if (typeof value != "string") + return finish.call(this, value); + + if (value.trim().charAt(0) == "<") { + loadIncludeFile.call(this, value.trim()); + return; + } + + this.$path = value.charAt(0) == "{" //@todo this shouldn't happen anymore + ? value + : apf.getAbsolutePath(apf.hostPath, value); + + var domParser = this.ownerDocument.$domParser; + if (!this.defer) { + domParser.$pauseParsing.apply(domParser, + this.$parseContext = domParser.$parseContext || [this.parentNode]); + } + + //var basePath = apf.hostPath;//only for recursion: apf.getDirname(xmlNode.getAttribute("filename")) || + loadIncludeFile.call(this, this.$path); + }; + + function done(xmlNode) { + var addedNode = this.previousSibling || this.nextSibling; + + if (this.callback) { + this.callback({ + xmlNode: xmlNode, + amlNode: this.parentNode, + addedNode: addedNode + }) + } + + addedNode.dispatchEvent("DOMNodeInserted", { + $beforeNode: addedNode.nextSibling, + relatedNode: this.parentNode, + $isMoveWithinParent: false, + bubbles: true + }); + + //@todo hack!! this should never happen. Find out why it happens + if (this.parentNode) + this.parentNode.removeChild(this); + } + + function finish(xmlNode) { + var domParser = this.ownerDocument.$domParser; + + if (this.clear) + this.parentNode.$int.innerHTML = ""; + + if (xmlNode) { + domParser.parseFromXml(xmlNode, { + doc: this.ownerDocument, + amlNode: this.parentNode, + beforeNode: this, + include: true + }); + + if (!this.defer && this.$parseContext) { + var o = (this.$parseContext[1] || (this.$parseContext[1] = {})), + cb = o.callback, + _self = this; + + o.callback = function(){ + done.call(_self, xmlNode); + if (cb) + cb.call(_self.ownerDocument); + }; + + //@todo this is wrong... probably based on load order of last include element. Please rearchitect parse continuation. + if (domParser.$continueParsing(this.$parseContext[0]) === false) { + var o2 = (domParser.$parseContext[1] || (domParser.$parseContext[1] = {})), + cb2 = o.callback; + o2.callback = function(){ + if (cb) + cb.call(_self.ownerDocument); + domParser.$continueParsing(_self.$parseContext[0]); + }; + } + } + else + done.call(this, xmlNode); + } + else { + if (!this.defer) + domParser.$continueParsing(this.$parseContext[0]); + + done.call(this, xmlNode); + } + } + + function loadIncludeFile(path) { + + + var _self = this; + apf.getData(path, apf.extend(this.options || {}, { + + callback: function(xmlString, state, extra) { + if (state != apf.SUCCESS) { + var oError = new Error(apf.formatErrorString(1007, + _self, "Loading Includes", "Could not load Include file '" + + (path || _self.src) + + "'\nReason: " + extra.message)); + + if (extra.tpModule.retryTimeout(extra, state, null, oError) === true) + return true; + + apf.console.error(oError.message); + + finish.call(_self, null); + + //throw oError; + return; + } + + //@todo apf3.0 please make one way of doing this + xmlString = xmlString.replace(/\<\!DOCTYPE[^>]*>/, "") + .replace(/^[\r\n\s]*/, ""); //.replace(/ /g, " ") + if (!apf.supportNamespaces) + xmlString = xmlString.replace(/xmlns\=\"[^"]*\"/g, ""); + + if (xmlString.indexOf("" + + xmlString + ""; + + var xmlNode = apf.getXml(xmlString, null, true);//apf.getAmlDocFromString(xmlString); + + if (!xmlNode) { + throw new Error(apf.formatErrorString(0, null, + "Loading include", + "Could not parse include file. Maybe the file does not exist?", xmlNode)); + } + xmlNode.setAttribute("filename", extra.url); + + + + finish.call(_self, xmlNode); //@todo add recursive includes support here + }, + async: true, + ignoreOffline: true + })); + } +}).call(apf.XiInclude.prototype = new apf.AmlElement()); + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ +apf.__LIVEEDIT__ = 1 << 23; + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + +apf.__ANCHORING__ = 1 << 13; + + + +/** + * All elements inheriting from this {@link term.baseclass baseclass} have anchoring features. Each side of the + * element can be attached at a certain distance to its parent's rectangle. + * + * When the parent is resized, the anchored side of the element stays + * at the specified distance at all times. If both sides are anchored, the + * element size is changed to make sure the specified distance is maintained. + * + * #### Example + * + * This example shows a bar that has a 10% margin around it, and contains a + * frame that is displayed using different calculations and settings. + * + * ```xml + * + * + * + * ``` + * + * ### Remarks + * + * This is one of three positioning methods. The other two are Alignment and Grid. + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.3 + * @baseclass + * @layout + */ +apf.Anchoring = function(){ + this.$regbase = this.$regbase | apf.__ANCHORING__; + this.$anchors = []; + + var VERTICAL = 1; + var HORIZONTAL = 2; + + this.$updateQueue = 0; + this.$inited = + this.$parsed = + this.$anchoringEnabled = false; + this.$hordiff = + this.$verdiff = 0; + this.$rule_v = + this.$rule_h = + this.$rule_header = ""; + + var l = apf.layout; + + this.$supportedProperties.push("anchors"); + + var propHandlers = { + "right" : function(value, prop) { + if (!this.$anchoringEnabled && !this.$setLayout("anchoring")) + return; + + if (!value && value !== 0) + this.$ext.style[prop] = ""; + + //@note Removed apf.isParsing here to activate general queuing + if (!this.$updateQueue) + l.queue(this.$pHtmlNode, this); + this.$updateQueue = this.$updateQueue | HORIZONTAL; + }, + + "bottom" : function(value, prop) { + if (!this.$anchoringEnabled && !this.$setLayout("anchoring")) + return; + + if (!value && value !== 0) + this.$ext.style[prop] = ""; + + //@note Removed apf.isParsing here to activate general queuing + if (!this.$updateQueue) + l.queue(this.$pHtmlNode, this); + this.$updateQueue = this.$updateQueue | VERTICAL; + } + }; + propHandlers.left = propHandlers.width = propHandlers.right; + propHandlers.top = propHandlers.height = propHandlers.bottom; + + this.$propHandlers["anchors"] = function(value) { + this.$anchors = value ? value.splitSafe("(?:, *| )") : []; + + if (!this.$anchoringEnabled && !this.$setLayout("anchoring")) + return; + + if (!this.$updateQueue && apf.loaded) + l.queue(this.$pHtmlNode, this); + this.$updateQueue = this.$updateQueue | HORIZONTAL | VERTICAL; + }; + + /** + * Turns anchoring off. + * + */ + this.$disableAnchoring = function(activate) { + //!this.$parsed || + if (!this.$inited || !this.$anchoringEnabled || !this.$pHtmlNode) + return; + + l.removeRule(this.$pHtmlNode, this.$uniqueId + "_anchors"); + if (l.queue) + l.queue(this.$pHtmlNode); + + for (var prop in propHandlers) { + delete this.$propHandlers[prop]; + } + + this.removeEventListener("DOMNodeRemoved", remove); + this.removeEventListener("DOMNodeInserted", reparent); + + if (this.$ext) { + this.$ext.style.left = + this.$ext.style.right = + this.$ext.style.top = + this.$ext.style.bottom = + this.$ext.style.width = + this.$ext.style.height = + this.$ext.style.position = ""; + } + + /*if (this.right) + this.$ext.style.left = apf.getHtmlLeft(this.$ext) + "px"; + + if (this.bottom) + this.$ext.style.top = apf.getHtmlTop(this.$ext) + "px";*/ + + this.removeEventListener("prop.visible", visibleHandler); + + this.$inited = false; + this.$anchoringEnabled = false; //isn't this redundant? + }; + + + /** + * @attribute {Number | String} [left] Sets or gets a way to determine the amount of pixels from the left border of this element to the left edge of it's parent's border. This attribute can also contain percentages, arithmetic and even full expressions. + * + * #### Example + * + * ```xml + * + * ``` + */ + /** + * @attribute {Number | String} [right] Sets or gets a way to determine the amount of pixels from the right border of this element to the right edge of its parent's border. + * This attribute can also contain percentages, arithmetic and even full expressions. + * + * #### Example + * + * ```xml + * + * ``` + */ + /** + * @attribute {Number | String} [width] Sets or gets a way to determine the amount of pixels from the left border to the right border of this element. + * This attribute can also contain percentages, arithmetic and even full expressions. + * + * #### Example + * + * ```xml + * + * ``` + */ + /** + * @attribute {Number | String} [top] Sets or gets a way to determine the amount of pixels from the top border of this element to the top edge of its parent's border. + * This attribute can also contain percentages, arithmetic and even full expressions. + * + * #### Example + * + * ```xml + * + * ``` + */ + /** + * @attribute {Number | String} [bottom] Sets or gets a way to determine the amount of pixels from the bottom border of this element to the bottom edge of its parent's border. + * This attribute can also contain percentages, arithmetic and even full expressions. + * + * #### Example + * + * ```xml + * + * ``` + */ + /** + * @attribute {Number | String} [height] Sets or gets a way to determine the amount of pixels from the top border to the bottom border of this element. + * This attribute can also contain percentages, arithmetic and even full expressions. + * + * #### Example + * + * ```xml + * + * ``` + */ + /* + * Enables anchoring based on attributes set in the AML of this element + */ + this.$enableAnchoring = function(){ + if (this.$inited) //@todo add code to reenable anchoring rules (when showing) + return; + + // *** Properties and Attributes *** // + apf.extend(this.$propHandlers, propHandlers); + + // *** Event handlers *** // + this.addEventListener("DOMNodeRemoved", remove); + this.addEventListener("DOMNodeInserted", reparent); + this.addEventListener("prop.visible", visibleHandler); + + this.$updateQueue = 0 + | ((this.left || this.width || this.right || this.anchors) && HORIZONTAL) + | ((this.top || this.height || this.bottom || this.anchors) && VERTICAL) ; + + if (this.$updateQueue) + l.queue(this.$pHtmlNode, this); + + this.$inited = true; + this.$anchoringEnabled = true; + }; + + function visibleHandler(e) { + if (!(this.$rule_header || this.$rule_v || this.$rule_h) || !this.parentNode) + return; + + if (e.value) { + if (this.$rule_v || this.$rule_h) { + var rules = this.$rule_header + "\n" + this.$rule_v + "\n" + this.$rule_h; + l.setRules(this.$pHtmlNode, this.$uniqueId + "_anchors", rules); + //this.$ext.style.display = "none"; + l.queue(this.$pHtmlNode, this); + } + l.processQueue(); + } + else { + l.removeRule(this.$pHtmlNode, this.$uniqueId + "_anchors"); + l.queue(this.$pHtmlNode) + } + } + + function remove(e) { + if (e && (e.$doOnlyAdmin || e.currentTarget != this)) + return; + + if (l.queue && this.$pHtmlNode) { + l.removeRule(this.$pHtmlNode, this.$uniqueId + "_anchors"); + l.queue(this.$pHtmlNode) + } + } + + function reparent(e) { + if (!this.$amlLoaded || e.currentTarget != this) + return; + + if (!e.$isMoveWithinParent && this.$parsed) //@todo hmm weird state check + this.$moveAnchoringRules(e.$oldParentHtmlNode); + //else if (e.relatedNode == this) //@todo test this + //e.currentTarget.$setLayout("anchoring"); + } + + this.$moveAnchoringRules = function(oldParent, updateNow) { + var rules = oldParent && l.removeRule(oldParent, this.$uniqueId + "_anchors"); + if (rules) + l.queue(oldParent); + + if (!this.$rule_v && !this.$rule_h && !this.$rule_header) + return; + + this.$rule_header = getRuleHeader.call(this); + rules = this.$rule_header + "\n" + this.$rule_v + "\n" + this.$rule_h; + + //@todo sometimes the content is not displayed anymore (when reparenting by xinclude) + //this.$ext.style.display = "none"; + + l.setRules(this.$pHtmlNode, this.$uniqueId + "_anchors", rules); + l.queue(this.$pHtmlNode, this); + }; + + this.$hasAnchorRules = function(){ + return this.$rule_v || this.$rule_h ? true : false; + }; + + function getRuleHeader(){ + if (!this.$pHtmlDoc) return ""; + return "try{\ + var oHtml = " + (apf.hasHtmlIdsInJs + ? this.$ext.getAttribute("id") + : "document.getElementById('" + + this.$ext.getAttribute("id") + "')") + ";\ + \ + var pWidth = " + (this.$pHtmlNode == this.$pHtmlDoc.body + ? "apf.getWindowWidth()" //@todo only needed for debug? + : "apf.getHtmlInnerWidth(oHtml.parentNode)") + ";\ + \ + var pHeight = " + (this.$pHtmlNode == this.$pHtmlDoc.body + ? "apf.getWindowHeight()" //@todo only needed for debug? + : "apf.getHtmlInnerHeight(oHtml.parentNode)") + ";\ + }catch(e){\ + }"; + } + + /** + * Sets the anchoring percentage. + * @param {String} expr An expression that's converted to a string + * @param {Number} An integer value that's used to convert to a percentage; for example, 50 becomes .5 + * @returns {String} The anchor percentage + */ + function setPercentage(expr, value) { + return String(expr).replace(apf.percentageMatch, "((" + value + " * $1)/100)"); + } + + + this.$recalcAnchoring = function(queueDelay) { + this.$updateQueue = this.$updateQueue | HORIZONTAL | VERTICAL; + this.$updateLayout(); + l.queue(this.$pHtmlNode, this); + + if (!queueDelay) + l.processQueue(); + }; + + + function visCheck(){ + if (this.$updateQueue) { + this.$updateLayout(); + apf.layout.activateRules(this.$ext.parentNode); + } + } + + this.$updateLayout = function(){ + if (!this.$anchoringEnabled) + return; + + if (!apf.window.vManager.check(this, "anchoring", visCheck)) + return; + + if (!this.$parsed) { + if (!this.$ext.getAttribute("id")) + apf.setUniqueHtmlId(this.$ext); + + this.$rule_header = getRuleHeader.call(this); + this.$parsed = true; + } + + if (!this.$updateQueue) { + if (this.visible && this.$ext.style.display == "none") + this.$ext.style.display = ""; + return; + } + + if (this.draggable == "relative") { + if ("absolute|fixed|relative".indexOf(apf.getStyle(this.$ext, "position")) == -1) //@todo apf3.1 the IDE doesn't like this + this.$ext.style.position = "absolute"; + } + else if (this.left || this.left === 0 || this.top || this.top === 0 + || this.right || this.right === 0 || this.bottom || this.bottom === 0 + || this.$anchors.length) { + if ("absolute|fixed".indexOf(apf.getStyle(this.$ext, "position")) == -1) + this.$ext.style.position = "absolute"; + } + else if (!this.center) { + if ("absolute|fixed|relative".indexOf(apf.getStyle(this.$ext, "position")) == -1) + this.$ext.style.position = "relative"; + if (!this.width) + this.$ext.style.width = ""; + if (!this.height) + this.$ext.style.height = ""; + } + + var rules; + if (this.$updateQueue & HORIZONTAL) { + rules = []; + + this.$hordiff = apf.getWidthDiff(this.$ext); + + var left = this.$anchors[3] || this.left, + right = this.$anchors[1] || this.right, + width = this.width, hasLeft = left || left === 0, + hasRight = right || right === 0, + hasWidth = width || width === 0; + + if (right && typeof right == "string") + right = setPercentage(right, "pWidth"); + + if (hasLeft) { + if (parseInt(left) != left) { + left = setPercentage(left, "pWidth"); + rules.push("oHtml.style.left = (" + left + ") + 'px'"); + } + else + this.$ext.style.left = left + "px"; + } + if ((apf.hasStyleAnchors || !hasLeft) && hasRight) { + if (parseInt(right) != right) { + right = setPercentage(right, "pWidth"); + rules.push("oHtml.style.right = (" + right + ") + 'px'"); + } + else + this.$ext.style.right = right + "px"; + } + + if (hasLeft && hasRight) { //right != null && left != null) { + if (!apf.hasStyleAnchors) + rules.push("oHtml.style.width = (pWidth - (" + right + + ") - (" + left + ") - " + this.$hordiff + ") + 'px'"); + else + this.$ext.style.width = ""; + } + else if (hasWidth && typeof this.maxwidth == "number" && typeof this.minwidth == "number") { + if (parseInt(width) != width) { + this.width = width = (this.width || "").replace(/--(\d+)/, "-(-$1)"); + width = setPercentage(width, "pWidth"); + rules.push("oHtml.style.width = Math.max(" + + (this.minwidth - this.$hordiff) + + ", Math.min(" + (this.maxwidth - this.$hordiff) + ", " + + width + " - " + this.$hordiff + ")) + 'px'"); + } + else { + this.$ext.style.width = ((width > this.minwidth + ? (width < this.maxwidth + ? width + : this.maxwidth) + : this.minwidth) - this.$hordiff) + "px"; + } + } + + this.$rule_h = (rules.length + ? "try{" + rules.join(";}catch(e) {};try{") + ";}catch(e) {};" + : ""); + } + + if (this.$updateQueue & VERTICAL) { + rules = []; + + this.$verdiff = apf.getHeightDiff(this.$ext); + + var top = this.$anchors[0] || this.top, + bottom = this.$anchors[2] || this.bottom, + height = this.height, hasTop = top || top === 0, + hasBottom = bottom || bottom === 0, + hasHeight = height || height === 0; + + if (bottom && typeof bottom == "string") + bottom = setPercentage(bottom, "pHeight"); + + if (hasTop) { + if (parseInt(top) != top) { + top = setPercentage(top, "pHeight"); + rules.push("oHtml.style.top = (" + top + ") + 'px'"); + } + else + this.$ext.style.top = top + "px"; + } + if ((apf.hasStyleAnchors || !hasTop) && hasBottom) { + if (parseInt(bottom) != bottom) { + rules.push("oHtml.style.bottom = (" + bottom + ") + 'px'"); + } + else + this.$ext.style.bottom = bottom + "px"; + } + if (hasTop && hasBottom) { //bottom != null && top != null) { + if (!apf.hasStyleAnchors) + rules.push("oHtml.style.height = (pHeight - (" + bottom + + ") - (" + top + ") - " + this.$verdiff + ") + 'px'"); + else + this.$ext.style.height = ""; + } + else if (hasHeight && typeof this.minheight == "number") { + if (parseInt(height) != height) { + height = setPercentage(height, "pHeight"); + rules.push("oHtml.style.height = Math.max(" + + (this.minheight - this.$verdiff) + + ", Math.min(" + (this.maxheight - this.$verdiff) + ", " + + height + " - " + this.$verdiff + ")) + 'px'"); + } + else { + this.$ext.style.height = Math.max(0, (height > this.minheight + ? (height < this.maxheight + ? height + : this.maxheight) + : this.minheight) - this.$verdiff) + "px"; + } + } + + this.$rule_v = (rules.length + ? "try{" + rules.join(";}catch(e) {};try{") + ";}catch(e) {};" + : ""); + } + + if (this.$rule_v || this.$rule_h) { + l.setRules(this.$pHtmlNode, this.$uniqueId + "_anchors", + this.$rule_header + "\n" + this.$rule_v + "\n" + this.$rule_h, true); + } + else { + l.removeRule(this.$pHtmlNode, this.$uniqueId + "_anchors"); + } + + this.$updateQueue = 0; + + if (this.$box && !apf.hasFlexibleBox) //temporary fix + apf.layout.forceResize(this.$ext); + }; + + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + //if (this.$updateQueue) + //this.$updateLayout(); + }); + + this.addEventListener("DOMNodeRemovedFromDocument", function(e) { + this.$disableAnchoring(); + }); +}; + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ +apf.__CONTENTEDITABLE__ = 1 << 24; + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + +apf.__GUIELEMENT__ = 1 << 15; +apf.__VALIDATION__ = 1 << 6; + + + +/** + * All elements inheriting from this {@link term.baseclass baseclass} are an AML component. + * + * @class apf.GuiElement + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.4 + * + * @baseclass + * @inherits apf.AmlElement + * @inherits apf.Anchoring + * @inherits apf.DelayedRender + * @inherits apf.DragDrop + * @inherits apf.Focussable + * @inherits apf.Interactive + * @inherits apf.Validation + * + */ +/** + * @attribute {String} span Sets or gets the number of columns that this element spans. Only used inside a table element. + */ +/** + * @attribute {String | Number} margin Sets or gets margin values. + * + * Set these sizes as a quarter of strings, in the usual top, right, bottom, left sequence, or pass an empty string to turn off margins. + */ +/** + * @attribute {String} align Sets or gets the edge of the parent to which this + * element aligns. + * + * The possible values are a combination of "left", "middle", "right", "top", "bottom" and "slider" ,and optionally a size. + * Combinations are combined with the pipe (`"|"`) character. + * + */ +/** + * @attribute {Mixed} left Sets or gets the left position of this element. Depending + * on the choosen layout method the unit can be pixels, a percentage or an + * expression. + */ +/** + * @attribute {Mixed} top Sets or gets the top position of this element. Depending + * on the choosen layout method the unit can be pixels, a percentage or an + * expression. + */ +/** + * @attribute {Mixed} right Sets or gets the right position of this element. Depending + * on the choosen layout method the unit can be pixels, a percentage or an + * expression. + */ +/** + * @attribute {Mixed} bottom Sets or gets the bottom position of this element. Depending + * on the choosen layout method the unit can be pixels, a percentage or an + * expression. + */ +/** + * @attribute {Mixed} width Sets or gets the different between the left edge and the + * right edge of this element. Depending on the choosen layout method the + * unit can be pixels, a percentage or an expression. + * + * #### Remarks + * + * When used as a child of a grid element the width can also be set as '*'. + * This will fill the rest space. + */ +/** + * @attribute {Mixed} height Sets or gets the different between the top edge and the + * bottom edge of this element. Depending on the choosen layout method the + * unit can be pixels, a percentage or an expression. + * + * #### Remarks + * + * When used as a child of a grid element the height can also be set as '*'. + * This will fill the rest space. + */ +/** + * @event resize Fires when the element changes width or height. + */ +/** + * @event contextmenu Fires when the user requests a context menu, either + * using the keyboard or mouse. + * @bubbles + * @cancelable Prevents the default context menu from appearing. + * @param {Object} e The standard event object. Contains the following properties: + * - x ([[Number]]): The x coordinate where the contextmenu is requested on + * - y ([[Number]]): The y coordinate where the contextmenu is requested on + * - htmlEvent ([[Event]]): The HTML event object that triggered this event from being called + */ +/** + * @event focus Fires when this element receives focus. + */ +/** + * @event blur Fires when this element loses focus. + */ +/** + * @event keydown Fires when this element has focus and the user presses a key on the keyboard. + * @bubbles + * @cancelable Prevents the default key action. + * @param {Object} e The standard event object. Contains the following properties: + * - ctrlKey ([[Boolean]]): Specifies whether the [[keys: Ctrl]] key was pressed + * - shiftKey ([[Boolean]]): Specifies whether the [[keys: Shift]] key was pressed + * - altKey ([[Boolean]]): Specifies whether the [[keys: Alt ]] key was pressed + * - keyCode ([[Number]]): Indicates which key was pressed. This is an ascii number + * - htmlEvent ([[Event]]): the HTML event object that triggered this event from being called + * + */ +apf.GuiElement = function(){ + this.$init(true); +}; + +(function(){ + this.$regbase = this.$regbase | apf.__GUIELEMENT__; + + this.$focussable = apf.KEYBOARD_MOUSE; // Each GUINODE can get the focus by default + this.visible = 2; //default value; + + this.minwidth = 1; + this.minheight = 1; + + /*this.minwidth = 5; + this.minheight = 5; + this.maxwidth = 10000; + this.maxheight = 10000;*/ + + + this.$booleanProperties["disable-keyboard"] = true; + + this.$booleanProperties["visible"] = true; + + /** + * @attribute {Boolean} draggable If true, the element can be dragged around the screen. + */ + /** + * @attribute {Boolean} resizable If true, the element can by resized by the user. + * + */ + + this.$supportedProperties.push("draggable", "resizable"); + + this.$supportedProperties.push( + "focussable", "zindex", "disabled", "tabindex", + "disable-keyboard", "contextmenu", "visible", "autosize", + "loadaml", "actiontracker", "alias", + "width", "left", "top", "height", "tooltip" + ); + + this.$setLayout = function(type, insert) { + if (!this.$drawn || !this.$pHtmlNode) + return false; + + if (this.parentNode) { + + if (this.parentNode.localName == "table") { + if (this.$disableCurrentLayout) + this.$disableCurrentLayout(); + this.parentNode.register(this, insert); + this.$disableCurrentLayout = null; + this.$layoutType = null; + return type == "table"; + }else + + + + if (this.parentNode.$box) { + if (this.$layoutType != this.parentNode) { + if (this.$disableCurrentLayout) + this.$disableCurrentLayout(); + this.parentNode.register(this, insert); + this.$disableCurrentLayout = null; + this.$layoutType = this.parentNode; + } + return type == this.parentNode.localName; + } //else + + } + + + if (!this.$anchoringEnabled) { + if (this.$disableCurrentLayout) + this.$disableCurrentLayout(); + this.$enableAnchoring(); + this.$disableCurrentLayout = this.$disableAnchoring; + this.$layoutType = null; + } + return type == "anchoring"; + + } + + this.addEventListener("DOMNodeInserted", function(e) { + if (e.currentTarget == this + && (this.parentNode.$box || "table" == this.parentNode.localName)) { + if (!e.$oldParent) this.$layoutType = null; + this.$setLayout(!e.$oldParent); + } + }); + + this.implement( + + apf.Anchoring + + + + ); + + // **** Convenience functions for gui nodes **** // + + + + // *** Geometry *** // + + /** + * Sets the difference between the left edge and the right edge of this + * element. + * + * Depending on the choosen layout method, the unit can be + * pixels, a percentage, or an expression. + * + * @chainable + * @param {Number | String} value The new width of this element. + */ + this.setWidth = function(value) { + this.setProperty("width", value, false, true); + return this; + }; + + /** + * Sets the different between the top edge and the bottom edge of this + * element. + * + * Depending on the choosen layout method the unit can be + * pixels, a percentage or an expression. + * + * @chainable + * @param {Number | String} value the new height of this element. + */ + this.setHeight = function(value) { + this.setProperty("height", value, false, true); + return this; + }; + + /** + * Sets the left position of this element. + * + * Depending on the choosen layout method the unit can be pixels, + * a percentage or an expression. + * + * @chainable + * @param {Number | String} value The new left position of this element. + */ + this.setLeft = function(value) { + this.setProperty("left", value, false, true); + return this; + }; + + /** + * Sets the top position of this element. + * + * Depending on the choosen layout method the unit can be pixels, + * a percentage or an expression. + * + * @chainable + * @param {Number | String} value The new top position of this element. + */ + this.setTop = function(value) { + this.setProperty("top", value, false, true); + return this; + }; + + if (!this.show) { + /** + * Makes the elements visible. + * @chainable + */ + this.show = function(){ + this.setProperty("visible", true, false, true); + return this; + }; + } + + if (!this.hide) { + /** + * Makes the elements invisible. + * @chainable + */ + this.hide = function(){ + this.setProperty("visible", false, false, true); + return this; + }; + } + + /** + * Retrieves the calculated width in pixels for this element. + */ + this.getWidth = function(){ + return (this.$ext || {}).offsetWidth; + }; + + /** + * Retrieves the calculated height in pixels for this element. + */ + this.getHeight = function(){ + return (this.$ext || {}).offsetHeight; + }; + + /** + * Retrieves the calculated left position in pixels for this element, + * relative to the offsetParent. + */ + this.getLeft = function(){ + return (this.$ext || {}).offsetLeft; + }; + + /** + * Retrieves the calculated top position in pixels for this element, + * relative to the offsetParent. + */ + this.getTop = function(){ + return (this.$ext || {}).offsetTop; + }; + + // *** Disabling *** // + + /** + * Activates the functions of this element. + * @chainable + */ + this.enable = function(){ + this.setProperty("disabled", false, false, true); + return this; + }; + + /** + * Deactivates the functions of this element. + * @chainable + */ + this.disable = function(){ + this.setProperty("disabled", true, false, true); + return this; + }; + + // *** z-Index *** // + + /** + * Moves this element to the lowest z ordered level. + * @chainable + */ + this.sendToBack = function(){ + this.setProperty("zindex", 0, false, true); + return this; + }; + + /** + * Moves this element to the highest z ordered level. + * @chainable + */ + this.bringToFront = function(){ + this.setProperty("zindex", apf.all.length + 1, false, true); + return this; + }; + + /** + * Moves this element one z order level deeper. + * @chainable + */ + this.sendBackwards = function(){ + this.setProperty("zindex", this.zindex - 1, false, true); + return this; + }; + + /** + * Moves this element one z order level higher. + * @chainable + */ + this.bringForward = function(){ + this.setProperty("zindex", this.zindex + 1, false, true); + return this; + }; + + + + this.hasFocus = function(){} + + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + var x = this.$aml; + + // will $pHtmlNode be deprecated soon? + // check used to be: + //if (!this.$pHtmlNode && this.parentNode) + if (this.parentNode) { + if (this.localName == "item" + && this.parentNode.hasFeature(apf.__MULTISELECT__)) //special case for item nodes, using multiselect rendering + this.$pHtmlNode = this.parentNode.$container; + else + this.$pHtmlNode = this.parentNode.$int; //@todo apf3.0 change this in the mutation events + } + + if (!this.$pHtmlNode) //@todo apf3.0 retry on DOMNodeInserted + return; + + this.$pHtmlDoc = this.$pHtmlNode.ownerDocument || document; + + if (this.$initSkin) + this.$initSkin(x); + + if (this.$draw) + this.$draw(); + + if (e.id) + this.$ext.setAttribute("id", e.id); + + if (typeof this.visible == "undefined") + this.visible = true; + + + + this.$drawn = true; + }, true); + + var f = function(e) { + if (!this.$pHtmlNode) //@todo apf3.0 retry on DOMInsert or whatever its called + return; + + this.$setLayout(); //@todo apf3.0 moving an element minwidth/height should be recalced + + //@todo apf3.0 set this also for skin change + if (this.$ext) { + var hasPres = (this.hasFeature(apf.__PRESENTATION__)) || false; + var type = this.$isLeechingSkin ? this.localName : "main"; + this.minwidth = Math.max(this.minwidth || 0, apf.getCoord(hasPres && parseInt(this.$getOption(type, "minwidth")), 0)); + this.minheight = Math.max(this.minheight || 0, apf.getCoord(hasPres && parseInt(this.$getOption(type, "minheight")), 0)); + if (this.maxwidth == undefined) + this.maxwidth = apf.getCoord(hasPres && parseInt(this.$getOption(type, "maxwidth")), 10000); + if (this.maxheight == undefined) + this.maxheight = apf.getCoord(hasPres && parseInt(this.$getOption(type, "maxheight")), 10000); + + //--#ifdef __WITH_CONTENTEDITABLE + //@todo slow?? + var diff = apf.getDiff(this.$ext); + this.$ext.style.minWidth = Math.max(0, this.minwidth - diff[0]) + "px"; + this.$ext.style.minHeight = Math.max(0, this.minheight - diff[1]) + "px"; + this.$ext.style.maxWidth = Math.max(0, this.maxwidth - diff[0]) + "px"; + this.$ext.style.maxHeight = Math.max(0, this.maxheight - diff[1]) + "px"; + + if (this.$altExt && apf.isGecko) { + this.$altExt.style.minHeight = this.$ext.style.minHeight; + this.$altExt.style.maxHeight = this.$ext.style.maxHeight; + this.$altExt.style.minWidth = this.$ext.style.minWidth; + this.$altExt.style.maxWidth = this.$ext.style.maxWidth; + } + //--#endif + } + + if (this.$loadAml) + this.$loadAml(this.$aml); //@todo replace by event + + + if (this.$focussable && typeof this.focussable == "undefined") + apf.GuiElement.propHandlers.focussable.call(this, true); + + + + if (setResizeEvent) + f2(); + + }; + + this.addEventListener("DOMNodeInsertedIntoDocument", f); + this.addEventListener("$skinchange", f); + + + var f2, setResizeEvent; + this.addEventListener("$event.resize", f2 = function(c) { + if (!this.$ext) { + setResizeEvent = true; + return; + } + + apf.layout.setRules(this.$ext, "resize", "var o = apf.all[" + this.$uniqueId + "];\ + if (o) o.dispatchEvent('resize');", true); + + apf.layout.queue(this.$ext); + //apf.layout.activateRules(this.$ext); + this.removeEventListener("$event.resize", f2); + }); + + + + this.addEventListener("contextmenu", function(e) { + + + if (!this.contextmenus) return; + + if (this.hasFeature(apf.__DATABINDING__)) { + var contextmenu; + var xmlNode = this.hasFeature(apf.__MULTISELECT__) + ? this.selected + : this.xmlRoot; + + var i, l, m, isRef, sel, menuId, cm, result; + for (i = 0, l = this.contextmenus.length; i < l; i++) { + isRef = (typeof (cm = this.contextmenus[i]) == "string"); + result = null; + if (!isRef && cm.match && xmlNode) {//@todo apf3.0 cache this statement + result = (cm.cmatch || (cm.cmatch = apf.lm.compile(cm.match, { + xpathmode: 3, + injectself: true + })))(xmlNode) + } + + if (isRef || xmlNode && result || !cm.match) { //!xmlNode && + menuId = isRef + ? cm + : cm.menu; + + var menu = cm.localName == "menu" ? cm : self[menuId]; + + if (!menu) { + + + return; + } + + menu.display(e.x, e.y, null, this, xmlNode); + + e.returnValue = false;//htmlEvent. + e.cancelBubble = true; + break; + } + } + + //IE6 compatiblity + /* + @todo please test that disabling this is OK + if (!apf.config.disableRightClick) { + document.oncontextmenu = function(){ + document.oncontextmenu = null; + e.cancelBubble = true; + return false; + } + }*/ + } + else { + var menu; + if (typeof this.contextmenus[0] == "string") + menu = self[this.contextmenus[0]]; + if (this.contextmenus[0].localName == "menu") + menu = this.contextmenus[0]; + else + menu = self[this.contextmenus[0].getAttribute("menu")]; + + if (!menu) { + + + return; + } + + menu.display(e.x, e.y, null, this); + + e.returnValue = false;//htmlEvent. + e.cancelBubble = true; + } + }); + +}).call(apf.GuiElement.prototype = new apf.AmlElement()); + +/* + * @for apf.amlNode + * @private + */ +apf.GuiElement.propHandlers = { + /** + * @attribute {Number} minwidth Sets or gets the minimum width for this element. + */ + /** + * @attribute {Number} maxwidth Sets or gets the maximum width for this element. + */ + /** + * @attribute {Number} minheight Sets or gets the minimum height for this element. + */ + /** + * @attribute {Number} maxheight Sets or gets the maximum height for this element. + */ + "minwidth": function(value){ this.$ext.style.minWidth = Math.max(0, value - apf.getWidthDiff(this.$ext)) + "px"; }, + "minheight": function(value){ this.$ext.style.minHeight = Math.max(0, value - apf.getHeightDiff(this.$ext)) + "px"; }, + "maxwidth": function(value){ this.$ext.style.maxWidth = Math.max(0, value - apf.getWidthDiff(this.$ext)) + "px"; }, + "maxheight": function(value){ this.$ext.style.maxHeight = Math.max(0, value - apf.getHeightDiff(this.$ext)) + "px"; }, + + + /** + * @attribute {Boolean} focussable Sets or gets whether this element can receive the focus. + * The focused element receives keyboard event. + */ + "focussable": function(value) { + this.focussable = typeof value == "undefined" || value; + + if (value == "container") { + this.$isWindowContainer = true; + this.focussable = true; + } + else + this.focussable = apf.isTrue(value); + + if (!this.hasFeature(apf.__FOCUSSABLE__)) //@todo should this be on the prototype + this.implement(apf.Focussable); + + if (this.focussable) { + apf.window.$addFocus(this, this.tabindex); + + if (value == "container") + this.$tabList.remove(this); + } + else { + apf.window.$removeFocus(this); + } + }, + + /** + * @attribute {Number} tabindex Sets or gets the pane index for this element. + */ + "tabindex": function(value) { + if (!this.hasFeature(apf.__FOCUSSABLE__)) + return; + + this.setTabIndex(parseInt(value) || null); + }, + + + /** + * @attribute {Number} zindex Sets or gets the z ordered layer in which this element is + * drawn. + */ + "zindex": function(value) { + this.$ext.style.zIndex = value; + }, + + /** + * @attribute {Boolean} visible Sets or gets whether this element is shown. + */ + "visible": function(value) { + if (apf.isFalse(value) || typeof value == "undefined") { + if (this.$ext) + this.$ext.style.display = "none"; + + if (apf.document.activeElement == this || this.canHaveChildren == 2 + && apf.isChildOf(this, apf.document.activeElement, false)) { + if (apf.config.allowBlur && this.hasFeature(apf.__FOCUSSABLE__)) + this.blur(); + else + apf.window.moveNext(); + } + + this.visible = false; + } + else { //if (apf.isTrue(value)) default + if (this.$ext) { + this.$ext.style.display = ""; //Some form of inheritance detection + if (!this.$ext.offsetHeight) + this.$ext.style.display = this.$display || "block"; + } + + + // if (apf.layout && this.$int) //apf.hasSingleRszEvent) + // apf.layout.forceResize(this.$int);//this.$int + + + this.visible = true; + } + }, + + /** + * @attribute {Boolean} disabled Sets or gets whether this element's functions are active. + * For elements that can contain other `apf.NODE_VISIBLE` elements, this + * attribute applies to all its children. + */ + "disabled": function(value) { + if (!this.$drawn) { + var _self = this; + //this.disabled = false; + + this.addEventListener("DOMNodeInsertedIntoDocument", + this.$updateDisabled || (this.$updateDisabled = function(e) { + apf.GuiElement.propHandlers.disabled.call(_self, _self.disabled); + })); + return; + } + else + apf.queue.remove("disable" + this.$uniqueId); + + //For child containers we only disable its children + if (this.canHaveChildren) { + //@todo Fix focus here first.. else it will jump whilst looping + if (value != -1) + value = this.disabled = apf.isTrue(value); + + var nodes = this.childNodes; + for (var node, i = 0, l = nodes.length; i < l; i++) { + node = nodes[i]; + if (node.nodeFunc == apf.NODE_VISIBLE) { + if (value && node.disabled != -1) + node.$disabled = node.disabled || false; + node.setProperty("disabled", value ? -1 : false); + } + } + + //this.disabled = undefined; + if (this.$isWindowContainer) + return; + } + + if (value == -1 || value == false) { + //value = true; + } + else if (typeof this.$disabled == "boolean") { + if (value === null) { + value = this.$disabled; + this.$disabled = null; + } + else { + this.$disabled = value || false; + return; + } + } + + if (apf.isTrue(value) || value == -1) { + this.disabled = false; + if (apf.document.activeElement == this) { + apf.window.moveNext(true); //@todo should not include window + if (apf.document.activeElement == this) + this.$blur(); + } + + if (this.hasFeature(apf.__PRESENTATION__)) + this.$setStyleClass(this.$ext, this.$baseCSSname + "Disabled"); + + if (this.$disable) + this.$disable(); + + + + this.disabled = value; + } + else { + if (this.hasFeature(apf.__DATABINDING__) && apf.config.autoDisable + && !(!this.$bindings || this.xmlRoot)) + return false; + + this.disabled = false; + + if (apf.document.activeElement == this) + this.$focus(); + + if (this.hasFeature(apf.__PRESENTATION__)) + this.$setStyleClass(this.$ext, null, [this.$baseCSSname + "Disabled"]); + + if (this.$enable) + this.$enable(); + + + } + }, + + /** + * @attribute {Boolean} enables Sets or gets whether this element's functions are active. + * For elements that can contain other `apf.NODE_VISIBLE` elements, this + * attribute applies to all its children. + */ + "enabled" : function(value) { + this.setProperty("disabled", !value); + }, + + /** + * @attribute {Boolean} disable-keyboard Sets or gets whether this element receives + * keyboard input. This allows you to disable keyboard independently from + * focus handling. + */ + "disable-keyboard": function(value) { + this.disableKeyboard = apf.isTrue(value); + }, + + /** + * @attribute {String} tooltip Sets or gets the text displayed when a user hovers with + * the mouse over the element. + */ + "tooltip" : function(value) { + this.$ext.setAttribute("title", (value || "") + (this.hotkey ? " (" + + (apf.isMac ? apf.hotkeys.toMacNotation(this.hotkey) : this.hotkey) + ")" : "")); + }, + + + /** + * @attribute {String} contextmenu Sets or gets the name of the menu element that will + * be shown when the user right clicks or uses the context menu keyboard + * shortcut. + * + * #### Example + * + * ```xml + * + * test + * test2 + * + * + * + * + * ``` + */ + "contextmenu": function(value) { + this.contextmenus = [value]; + }, + + + + /** + * @attribute {String} actiontracker Sets or gets the name of the [[apf.actiontracker action tracker]] that + * is used for this element and its children. If the actiontracker doesn't + * exist yet, it is created. + * + * #### Example + * + * In this example, the list uses a different action tracker than the two + * textboxes which determine their actiontracker based on the one that + * is defined on the bar. + * + * ```xml + * + * + * + * + * + * + * ``` + */ + "actiontracker": function(value) { + if (!value) { + this.$at = null; + } + else if (typeof value == "object") { + this.$at = value; + } + else { + + this.$at = typeof value == "string" && self[value] + ? apf.nameserver.get("actiontracker", value) || self[value].getActionTracker() + : apf.setReference(value, + apf.nameserver.register("actiontracker", + value, new apf.actiontracker())); + + if (!this.$at.name) + this.$at.name = value; + + } + }, + + + //Load subAML + /** + * @attribute {String} aml Sets or gets the {@link term.datainstruction data instruction} + * that loads new AML as children of this element. + */ + "aml": function(value) { + this.replaceMarkup(value); + } + + /* + * @attribute {String} sets this aml element to be editable + * that loads new aml as children of this element. + */ + // @todo Doc WTF? + + + +}; + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + +apf.__PRESENTATION__ = 1 << 9; + + +/** + * All elements inheriting from this {@link term.baseclass baseclass} have skinning features. A skin is a description + * of how the element is rendered. In the web browser, this is done using HTML + * elements and CSS. + * + * #### Remarks + * + * The skin is set using the `skin` attribute. The skin of each element can be + * changed at run time. Other than just changing the look of an element, a skin + * change can help the user to perceive information in a different way. For + * example, a list element has a default skin, but can also use the thumbnail + * skin to display thumbnails of the {@link term.datanode data nodes}. + * + * #### Example + * + * A skin for an element is always built up out of a standard set of parts: + * + * ```xml + * + * + * ... + * + * + * + * + * + * ... + * + * ... + * + * + * ``` + * + * The alias contains a name that contains alternative names for the skin. The + * style tags contain the CSS. The main tag contains the HTML elements that are + * created when the component is created. Any other skin items are used to render + * other elements of the widget. In this reference guide you will find these + * skin items described on the pages of each widget. + * + * @class apf.Presentation + * @define presentation + * @inherits apf.GuiElement + * @baseclass + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.5 + */ +apf.Presentation = function(){ + this.$init(true); +}; + +(function(){ + this.$regbase = this.$regbase | apf.__PRESENTATION__; + + // *** Properties and Attributes *** // + + this.$supportedProperties.push("skin"); + + /** + * @attribute {String} skinset Sets or gets the skinset for + * this element. If none are specified ,the `skinset` attribute + * of the app settings is used. When that's not defined, the default skinset + * is used. + * + * #### Example + * + * ```xml + * + * ``` + */ + this.$propHandlers["skinset"] = + + + /** + * @attribute {String} skin Sets or gets the name of the skin in the skinset that defines + * how this element is rendered. When a skin is changed, the full state of the + * element is kept, including its selection, all the + * AML attributes, loaded data, and focus and disabled states. + * + * #### Example + * + * In XML: + * + * ```xml + * + * ``` + * + * Or, in JavaScript: + * + * ```javascript + * lstExample.setAttribute("skin", "list"); + * ``` + */ + this.$propHandlers["skin"] = function(value) { + if (!this.$amlLoaded) //If we didn't load a skin yet, this will be done when we attach to a parent + return; + + if (!this.$skinTimer) { + var _self = this; + clearTimeout(this.$skinTimer); + this.$skinTimer = $setTimeout(function(){ + changeSkin.call(_self, _self.skin); + delete _self.$skinTimer; + }); + } + } + + + /** + * @attribute {String} style Sets or gets the CSS style applied to the this element. This can be a string containing one or more CSS rules. + */ + this.$propHandlers["style"] = function(value) { + if (!this.styleAttrIsObj && this.$amlLoaded) + this.$ext.setAttribute("style", value); + } + + /** + * @attribute {String} border Sets or gets border values. Set these sizes as a quarter of strings, in the usual top, right, bottom, left sequence, or pass an empty string to turn off borders. + */ + this.$propHandlers["border"] = function(value) { + if (!value) + this.$ext.style.borderWidth = ""; + else + this.$ext.style.borderWidth = apf.getBox(value).join("px ") + "px"; + } + + /** + * @attribute {String | Number} margin Sets or gets margin values. Set these sizes as a quarter of strings, in the usual top, right, bottom, left sequence, or pass an empty string to turn off margins. + */ + this.$propHandlers["margin"] = function(value) { + if (!value) + this.$ext.style.margin = ""; + else + this.$ext.style.margin = apf.getBox(value).join("px ") + "px"; + } + + /** + * @attribute {String} class Sets or gets the name of the CSS style class applied to this element. + */ + this.$propHandlers["class"] = function(value) { + this.$setStyleClass(this.$ext, value, this.$lastClassValue ? [this.$lastClassValue] : null); + this.$lastClassValue = value; + } + + + this.$forceSkinChange = function(skin, skinset) { + changeSkin.call(this, skin, skinset); + } + + //@todo objects don't always have an $int anymore.. test this + function changeSkin(skin, skinset) { + clearTimeout(this.$skinTimer); + + //var skinName = (skinset || this.skinset || apf.config.skinset) + // + ":" + (skin || this.skin || this.localName); + + + //Store selection + if (this.selectable) + var valueList = this.getSelection();//valueList; + + + //Store needed state information + var oExt = this.$ext, + oInt = this.$int, + pNode = this.$ext ? this.$ext.parentNode : this.$pHtmlNode, + beforeNode = oExt && oExt.nextSibling, + idExt = this.$ext && this.$ext.getAttribute("id"), + idInt = this.$int && this.$int.getAttribute("id"), + oldBase = this.$baseCSSname; + + if (oExt && oExt.parentNode) + oExt.parentNode.removeChild(oExt); + + //@todo changing skin will leak A LOT, should call $destroy here, with some extra magic + if (this.$destroy) + this.$destroy(true); + + //Load the new skin + this.skin = skin; + this.$loadSkin(skinset ? skinset + ":" + skin : null); + + //Draw + if (this.$draw) + this.$draw(true); + + if (idExt) + this.$ext.setAttribute("id", idExt); + + if (beforeNode || this.$ext && pNode != this.$ext.parentNode) + pNode.insertBefore(this.$ext, beforeNode); + + //Style + + //Border + + //Margin + + if (this.$ext) { + //Classes + var i, l, newclasses = [], + classes = (oExt.className || "").splitSafe("\\s+"); + for (i = 0; i < classes.length; i++) { + if (classes[i] && classes[i].indexOf(oldBase) != 0) + newclasses.push(classes[i].replace(oldBase, this.$baseCSSname)); + } + apf.setStyleClass(this.$ext, newclasses.join(" ")); + + //Copy events + var en, ev = apf.skins.events; + for (i = 0, l = ev.length; i < l; i++) { + en = ev[i]; + if (typeof oExt[en] == "function" && !this.$ext[en]) + this.$ext[en] = oExt[en]; + } + + //Copy css state (dunno if this is best) + this.$ext.style.left = oExt.style.left; + this.$ext.style.top = oExt.style.top; + this.$ext.style.width = oExt.style.width; + this.$ext.style.height = oExt.style.height; + this.$ext.style.right = oExt.style.right; + this.$ext.style.bottom = oExt.style.bottom; + this.$ext.style.zIndex = oExt.style.zIndex; + this.$ext.style.position = oExt.style.position; + this.$ext.style.display = oExt.style.display; + } + + //Widget specific + //if (this.$loadAml) + //this.$loadAml(this.$aml); + + if (idInt) + this.$int.setAttribute("id", idInt); + + if (this.$int && this.$int != oInt) { + var node, newNode = this.$int, nodes = oInt.childNodes; + for (var i = nodes.length - 1; i >= 0; i--) { + if ((node = nodes[i]).host) { + node.host.$pHtmlNode = newNode; + if (node.host.$isLeechingSkin) + setLeechedSkin.call(node.host); + } + newNode.insertBefore(node, newNode.firstChild); + } + //this.$int.onresize = oInt.onresize; + } + + + //DragDrop + if (this.hasFeature(apf.__DRAGDROP__)) { + if (document.elementFromPointAdd) { + document.elementFromPointRemove(oExt); + document.elementFromPointAdd(this.$ext); + } + } + + + //Check disabled state + if (this.disabled) + this.$disable(); //@todo apf3.0 test + + //Check focussed state + if (this.$focussable && apf.document.activeElement == this) + this.$focus(); //@todo apf3.0 test + + //Dispatch event + this.dispatchEvent("$skinchange", { + ext: oExt, + "int": oInt + }); + + + //Reload data + if (this.hasFeature(apf.__DATABINDING__) && this.xmlRoot) + this.reload(); + else + + if (this.value) + this.$propHandlers["value"].call(this, this.value); + + + //Set Selection + if (this.hasFeature(apf.__MULTISELECT__)) { + if (this.selectable) + this.selectList(valueList, true); + } + + + //Move layout rules + if (!apf.hasSingleRszEvent) { + apf.layout.activateRules(this.$ext); + if (this.$int) + apf.layout.activateRules(this.$int); + } + +/* + if (this.hasFeature(apf.__ANCHORING__)) + this.$recalcAnchoring(); + + + + if (this.hasFeature(apf.__ALIGNMENT__)) { + if (this.aData) + this.aData.oHtml = this.$ext; + + if (this.pData) { + this.pData.oHtml = this.$ext; + this.pData.pHtml = this.$int; + + var nodes = this.pData.childNodes; + for (i = 0; i < nodes.length; i++) + nodes[i].pHtml = this.$int; //Should this be recursive?? + } + } + +*/ + + if (this.draggable && this.$propHandlers["draggable"]) //@todo move these to the event below apf3.0) + this.$propHandlers["draggable"].call(this, this.draggable); + if (this.resizable && this.$propHandlers["resizable"]) + this.$propHandlers["resizable"].call(this, this.resizable); + + + + apf.layout.forceResize(this.$ext); + + }; + + + // *** Private methods *** // + + this.$setStyleClass = apf.setStyleClass; + + function setLeechedSkin(e) { + if (!this.$amlLoaded || e && (e.$isMoveWithinParent + || e.currentTarget != this || !e.$oldParent)) + return; + + this.$setInheritedAttribute(this, "skinset"); + + if (this.attributes.getNamedItem("skin")) + return; + + //e.relatedNode + var skinName, pNode = this.parentNode, skinNode; + if ((skinName = this.$canLeechSkin.dataType + == apf.STRING ? this.$canLeechSkin : this.localName) + && pNode.$originalNodes + && (skinNode = pNode.$originalNodes[skinName]) + && skinNode.getAttribute("inherit")) { + var link = skinNode.getAttribute("link"); + this.$isLeechingSkin = true; + if (link) { + this.$forceSkinChange(link); + } + else { + var skin = pNode.skinName.split(":"); + this.$forceSkinChange(skin[1], skin[0]); + } + } + else if (this.$isLeechingSkin) { + delete this.skin; + this.$isLeechingSkin = false; + this.$forceSkinChange(); + } + } + + //Skin Inheritance + //@todo Probably requires some cleanup + this.$initSkin = function(x) { + if (this.$canLeechSkin) { + this.addEventListener("DOMNodeInserted", setLeechedSkin); + } + + if (!this.skin) + this.skin = this.getAttribute("skin"); + + var skinName, pNode = this.parentNode, skinNode; + if (this.$canLeechSkin && !this.skin + && (skinName = this.$canLeechSkin.dataType == apf.STRING + ? this.$canLeechSkin + : this.localName) + && pNode && pNode.$originalNodes + && (skinNode = pNode.$originalNodes[skinName]) + && skinNode.getAttribute("inherit")) { + var link = skinNode.getAttribute("link"); + this.$isLeechingSkin = true; + if (link) { + this.skin = link; + this.$loadSkin(); + } + else { + this.$loadSkin(pNode.skinName); + } + } + else { + if (!this.skinset) + this.skinset = this.getAttribute("skinset"); + + this.$loadSkin(null, this.$canLeechSkin); + } + } + + /* + * Initializes the skin for this element when none has been set up. + * + * @param {String} skinName Identifier for the new skin (for example: 'default:List' or 'win'). + * @param {Boolean} [noError] + */ + this.$loadSkin = function(skinName, noError) { + //this.skinName || //where should this go and why? + this.baseSkin = skinName || (this.skinset + || this.$setInheritedAttribute("skinset")) + + ":" + (this.skin || this.localName); + + clearTimeout(this.$skinTimer); + + if (this.skinName) { + this.$blur(); + this.$baseCSSname = null; + } + + this.skinName = this.baseSkin; //Why?? + //this.skinset = this.skinName.split(":")[0]; + + this.$pNodes = {}; //reset the this.$pNodes collection + this.$originalNodes = apf.skins.getTemplate(this.skinName, true); + + if (!this.$originalNodes) { + var skin = this.skin; + if (skin) { + var skinset = this.skinName.split(":")[0]; + this.baseName = this.skinName = "default:" + skin; + this.$originalNodes = apf.skins.getTemplate(this.skinName); + + if (!this.$originalNodes && skinset != "default") { + this.baseName = this.skinName = skinset + ":" + this.localName; + this.$originalNodes = apf.skins.getTemplate(this.skinName, true); + } + } + + if (!this.$originalNodes) { + this.baseName = this.skinName = "default:" + this.localName; + this.$originalNodes = apf.skins.getTemplate(this.skinName); + } + + if (!this.$originalNodes) { + if (noError) { + return (this.baseName = this.skinName = + this.originalNode = null); + } + + throw new Error(apf.formatErrorString(1077, this, + "Presentation", + "Could not load skin: " + this.baseSkin)); + } + + //this.skinset = this.skinName.split(":")[0]; + } + + if (this.$originalNodes) + apf.skins.setSkinPaths(this.skinName, this); + }; + + this.$getNewContext = function(type, amlNode) { + + + this.$pNodes[type] = this.$originalNodes[type].cloneNode(true); + }; + + this.$hasLayoutNode = function(type) { + + + return this.$originalNodes[type] ? true : false; + }; + + this.$getLayoutNode = function(type, section, htmlNode) { + + + var node = this.$pNodes[type] || this.$originalNodes[type]; + if (!node) { + + return false; + } + + if (!section) + return htmlNode || apf.getFirstElement(node); + + var textNode = node.getAttribute(section); + if (!textNode) + return null; + + return (htmlNode + ? apf.queryNode(htmlNode, textNode) + : apf.getFirstElement(node).selectSingleNode(textNode)); + }; + + this.$getOption = function(type, section) { + type = type.toLowerCase(); //HACK: lowercasing should be solved in the comps. + + //var node = this.$pNodes[type]; + var node = this.$pNodes[type] || this.$originalNodes[type]; + if (!section || !node) + return node;//apf.getFirstElement(node); + var option = node.selectSingleNode("@" + section); + + return option ? option.nodeValue : ""; + }; + + this.$getExternal = function(tag, pNode, func, aml) { + if (!pNode) + pNode = this.$pHtmlNode; + if (!tag) + tag = "main"; + //if (!aml) + //aml = this.$aml; + + tag = tag.toLowerCase(); //HACK: make components case-insensitive + + this.$getNewContext(tag); + var oExt = this.$getLayoutNode(tag); + + var node; + if (node = (aml || this).getAttributeNode("style")) + oExt.setAttribute("style", node.nodeValue); + + //if (node = (aml || this).getAttributeNode("class")) + //this.$setStyleClass(oExt, (oldClass = node.nodeValue)); + + if (func) + func.call(this, oExt); + + oExt = apf.insertHtmlNode(oExt, pNode); + oExt.host = this; + if (node = (aml || this).getAttributeNode("bgimage")) + oExt.style.backgroundImage = "url(" + apf.getAbsolutePath( + this.mediaPath, node.nodeValue) + ")"; + + if (!this.$baseCSSname) + this.$baseCSSname = oExt.className.trim().split(" ")[0]; + + return oExt; + }; + + // *** Focus *** // + this.$focus = function(){ + if (!this.$ext) + return; + + this.$setStyleClass(this.oFocus || this.$ext, this.$baseCSSname + "Focus"); + }; + + this.$blur = function(){ + + if (this.renaming) + this.stopRename(null, true); + + + if (!this.$ext) + return; + + this.$setStyleClass(this.oFocus || this.$ext, "", [this.$baseCSSname + "Focus"]); + }; + + this.$fixScrollBug = function(){ + if (this.$int != this.$ext) + this.oFocus = this.$int; + else { + this.oFocus = + this.$int = + this.$ext.appendChild(document.createElement("div")); + + this.$int.style.height = "100%"; + this.$int.className = "focusbug" + } + }; + + // *** Caching *** // + /* + this.$setClearMessage = function(msg) {}; + this.$updateClearMessage = function(){} + this.$removeClearMessage = function(){};*/ +}).call(apf.Presentation.prototype = new apf.GuiElement()); + +apf.config.$inheritProperties["skinset"] = 1; + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + +apf.__VALIDATION__ = 1 << 6; + + + +//if checkequal then notnull = true +apf.validator = { + macro: { + + + //var temp + "pattern" : "value.match(", + "pattern_" : ")", + "custom" : "(", + "custom_" : ")", + "min" : "parseInt(value) >= ", + "max" : "parseInt(value) <= ", + "maxlength" : "value.toString().length <= ", + "minlength" : "value.toString().length >= ", + "notnull" : "value.toString().length > 0", + "checkequal" : "!(temp = ", + "checkequal_" : ").isValid() || temp.getValue() == value" + }, + + compile: function(options) { + var m = this.macro, s = ["var temp, valid = true; \ + if (!validityState) \ + validityState = new apf.validator.validityState(); "]; + + if (options.required) { + s.push("if (checkRequired && (!value || value.toString().trim().length == 0)) {\ + validityState.$reset();\ + validityState.valueMissing = true;\ + valid = false;\ + }") + } + + s.push("validityState.$reset();\ + if (value) {"); + + for (prop in options) { + if (!m[prop]) continue; + s.push("if (!(", m[prop], options[prop], m[prop + "_"] || "", ")){\ + validityState.$set('", prop, "');\ + valid = false;\ + }"); + } + + s.push("};validityState.valid = valid; return validityState;"); + return new Function('value', 'checkRequired', 'validityState', s.join("")); + } +}; + +/** + * Object containing information about the validation state. It contains + * properties that specify whether a certain validation was passed. + * Remarks: + * This is part of {@link http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#validitystatethe HTML 5 specification}. + */ +apf.validator.validityState = function(){ + this.valueMissing = false, + this.typeMismatch = false, + this.patternMismatch = false, + this.tooLong = false, + this.rangeUnderflow = false, + this.rangeOverflow = false, + this.stepMismatch = false, + this.customError = false, + this.valid = true, + + this.$reset = function(){ + for (var prop in this) { + if (prop.substr(0,1) == "$") + continue; + this[prop] = false; + } + this.valid = true; + }, + + this.$set = function(type) { + switch (type) { + case "min" : this.rangeUnderflow = true; break; + case "max" : this.rangeOverflow = true; break; + case "minlength" : this.tooShort = true; break; + case "maxlength" : this.tooLong = true; break; + case "pattern" : this.patternMismatch = true; break; + case "datatype" : this.typeMismatch = true; break; + case "notnull" : this.typeMismatch = true; break; + case "checkequal" : this.typeMismatch = true; break; + } + } +}; + +/** + * All elements inheriting from this {@link term.baseclass baseclass} have validation support. + * + * #### Example + * + * ```xml, demo + * + * + * + * Number + * + * Name + * + * Message + * + * + * + * Validate + * + * + * + * + * ``` + * + * @class apf.Validation + * @inherits apf.AmlElement + * @baseclass + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.5 + */ + /** + * @event invalid Fires when this component goes into an invalid state. + * + */ +apf.Validation = function(){ + this.$regbase = this.$regbase | apf.__VALIDATION__; + + /** + * Checks if this element's value is valid. + * + * @param {Boolean} [checkRequired] Specifies whether this check also adheres to the `'required'` rule. + * @returns {Boolean} Specifies whether the value is valid + * @see apf.ValidationGroup + * @see element.submitform + */ + this.isValid = function(checkRequired) { + if (!this.$vOptions) + return true; + + (this.$vOptions.isValid || (this.$vOptions.isValid + = apf.validator.compile(this.$vOptions))).call(this, + typeof this.getValue == "function" ? this.getValue(null, true) : null, + checkRequired, this.validityState || + (this.validityState = new apf.validator.validityState())); + + var valid = this.validityState.valid; + + + + this.dispatchEvent(!valid ? "invalid" : "valid", this.validityState); + + return valid; + }; + + /* + * @private + */ + this.setCustomValidity = function(message) { + //do stuff + } + + /* + * @private + * @todo This method should also scroll the element into view + */ + this.showMe = function(){ + var p = this.parentNode; + while (p) { + if (p.show) + p.show(); + p = p.parentNode; + } + }; + + + + /** + * Puts this element in the error state, optionally showing the + * error box if this element is invalid. + * + * @method validate + * @param {Boolean} [ignoreReq] Specifies whether this element required check is turned on. + * @param {Boolean} [nosetError] Specifies whether the error box is displayed if this component does not validate. + * @param {Boolean} [force] Specifies whether this element is in the error state, and doesn't check if the element's value is invalid. + * @return {Boolean} Indicates whether the value is valid + * @see apf.ValidationGroup + */ + this.validate = function(ignoreReq, nosetError, force) { + //if (!this.$validgroup) return this.isValid(); + + if (force || !this.isValid(!ignoreReq) && !nosetError) { + this.setError(); + return false; + } + else { + this.clearError(); + return true; + } + }; + + /* + * @private + */ + this.setError = function(value) { + if (!this.$validgroup) + this.$propHandlers["validgroup"].call(this, "vg" + this.parentNode.$uniqueId); + + var errBox = this.$validgroup.getErrorBox(this); + + if (!this.$validgroup.allowMultipleErrors) + this.$validgroup.hideAllErrors(); + + errBox.setMessage(this.invalidmsg || value); + + apf.setStyleClass(this.$ext, this.$baseCSSname + "Error"); + this.showMe(); //@todo scroll refHtml into view + + if (this.invalidmsg || value) + errBox.display(this); + + + + if (apf.document.activeElement && apf.document.activeElement != this) + this.focus(null, {mouse:true}); //arguable... + }; + + /* + * @private + */ + this.clearError = function(value) { + if (this.$setStyleClass) + this.$setStyleClass(this.$ext, "", [this.$baseCSSname + "Error"]); + + if (this.$validgroup) { + var errBox = this.$validgroup.getErrorBox(null, true); + if (!errBox || errBox.host != this) + return; + + errBox.hide(); + } + }; + + this.addEventListener("DOMNodeRemovedFromDocument", function(e) { + if (this.$validgroup) + this.$validgroup.unregister(this); + }); + + /** + * + * @attribute {Boolean} required Sets or gets whether a valid value for this element is required. + */ + /** + * @attribute {RegExp} pattern Sets or gets the pattern tested against the value of this element to determine it's validity. + */ + /** + * @attribute {String} datatype Sets or gets the datatype that the value of this element should adhere to. This can be any + * of a set of predefined types, or a simple type created by an XML Schema definition. + * + * Some possible values (all of which are [[String]]s) include: + * - `xsd:dateTime` + * - `xsd:time` + * - `xsd:date` + * - `xsd:gYearMonth` + * - `xsd:gYear` + * - `xsd:gMonthDay` + * - `xsd:gDay` + * - `xsd:gMonth` + * - `xsd:string` + * - `xsd:boolean` + * - `xsd:base64Binary` + * - `xsd:hexBinary` + * - `xsd:float` + * - `xsd:decimal` + * - `xsd:double` + * - `xsd:anyURI` + * - `xsd:integer` + * - `xsd:nonPositiveInteger` + * - `xsd:negativeInteger` + * - `xsd:long` + * - `xsd:int` + * - `xsd:short` + * - `xsd:byte` + * - `xsd:nonNegativeInteger` + * - `xsd:unsignedLong` + * - `xsd:unsignedInt` + * - `xsd:unsignedShort` + * - `xsd:unsignedByte` + * - `xsd:positiveInteger` + * - `apf:url` + * - `apf:website` + * - `apf:email` + * - `apf:creditcard` + * - `apf:expdate` + * - `apf:wechars` + * - `apf:phonenumber` + * - `apf:faxnumber` + * - `apf:mobile` + */ + /** + * @attribute {Number} min Sets or gets the minimal value for which the value of this element is valid. + */ + /** + * @attribute {Number} max Sets or gets the maximum value for which the value of this element is valid. + */ + /** + * @attribute {Number} minlength Sets or gets the minimal length allowed for the value of this element. + */ + /** + * @attribute {Number} maxlength Sets or gets the maximum length allowed for the value of this element. + */ + /** + * @attribute {Boolean} notnull Sets or gets whether the value is filled. This rule is checked realtime when the element loses the focus. + */ + /** + * @attribute {String} checkequal Sets or gets the id of the element to check if it has the same value as this element. + */ + /** + * @attribute {String} invalidmsg Sets or gets the message displayed when this element has an invalid value. Use a `;` character to seperate the title from the message. + */ + /** + * @attribute {String} validgroup Sets or gets the identifier for a group of items to be validated at the same time. This identifier can be new. It is inherited from a AML node upwards. + */ + /** + * @attribute {String} validtest Sets or gets the instruction on how to test for success. This attribute is generally used to check the value on the server. + * + * #### Example + * + * This example shows how to check the username on the server. In this case, + * `comm.loginCheck` is an async RPC function that checks the availability of the + * username. If it exists, it will return `0`--otherwise, it's `1`. The value variable + * contains the current value of the element (in this case the textbox). It + * can be used as a convenience variable. + * + * ```xml + * Username + * + * ``` + */ + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + //this.addEventListener(this.hasFeature(apf.__MULTISELECT__) ? "onafterselect" : "onafterchange", onafterchange); + /* Temp disabled, because I don't understand it (RLD) + this.addEventListener("beforechange", function(){ + if (this.xmlRoot && apf.getBoundValue(this) === this.getValue()) + return false; + });*/ + + // validgroup + if (!this.validgroup) + this.$setInheritedAttribute("validgroup"); + }); + + //1 = force no bind rule, 2 = force bind rule + this.$attrExcludePropBind = apf.extend({ + pattern: 1, + validtest: 3 + }, this.$attrExcludePropBind); + + this.$booleanProperties["required"] = true; + this.$supportedProperties.push("validgroup", "required", "datatype", + "pattern", "min", "max", "maxlength", "minlength", "validtest", + "notnull", "checkequal", "invalidmsg", "requiredmsg"); + + this.$fValidate = function(){ + if (this.liveedit) + return; + + if (!this.$validgroup) + this.validate(true); + else { + var errBox = this.$validgroup.getErrorBox(this); + if (!errBox.visible || errBox.host != this) + this.validate(true); + } + }; + this.addEventListener("blur", this.$fValidate); + + this.$propHandlers["validgroup"] = function(value) { + if (value) { + var vgroup; + if (typeof value != "string") { + this.$validgroup = value.name; + vgroup = value; + } + else { + + vgroup = apf.nameserver.get("validgroup", value); + + } + + this.$validgroup = vgroup || new apf.ValidationGroup(value); + this.$validgroup.register(this); + /* + @todo What about children, when created after start + See button login action + */ + } + else { + this.$validgroup.unregister(this); + this.$validgroup = null; + } + }; + + this.$propHandlers["pattern"] = function(value, prop) { + if (value.substr(0, 1) != "/") + value = "/" + value + "/"; + + (this.$vOptions || (this.$vOptions = {}))[prop] = value; + delete this.$vOptions.isValid; + }; + + + this.$propHandlers["required"] = + this.$propHandlers["custom"] = + this.$propHandlers["min"] = + this.$propHandlers["max"] = + this.$propHandlers["maxlength"] = + this.$propHandlers["minlength"] = + this.$propHandlers["notnull"] = + this.$propHandlers["checkequal"] = function(value, prop) { + (this.$vOptions || (this.$vOptions = {}))[prop] = value; + delete this.$vOptions.isValid; + }; + + //@todo rewrite this for apf3.0 - it should just execute a live markup + this.$propHandlers["validtest"] = function(value) { + var _self = this, rvCache = {}; + /** + * Removes the validation cache created by the validtest rule. + */ + this.removeValidationCache = function(){ + rvCache = {}; + } + + this.$checkRemoteValidation = function(){ + var value = this.getValue(); + if (typeof rvCache[value] == "boolean") return rvCache[value]; + if (rvCache[value] == -1) return true; + rvCache[value] = -1; + + apf.getData(this.validtest.toString(), { + xmlNode: this.xmlRoot, + value: this.getValue(), + callback: function(data, state, extra) { + if (state != apf.SUCCESS) { + if (state == apf.TIMEOUT && extra.retries < apf.maxHttpRetries) + return extra.tpModule.retry(extra.id); + else { + var commError = new Error(apf.formatErrorString(0, _self, + "Validating entry at remote source", + "Communication error: \n\n" + extra.message)); + + if (_self.dispatchEvent("error", apf.extend({ + error: commError, + state: status + }, extra)) !== false) + throw commError; + return; + } + } + + rvCache[value] = apf.isTrue(data);//instr[1] ? data == instr[1] : apf.isTrue(data); + + if (!rvCache[value]){ + if (!_self.hasFocus()) + _self.setError(); + } + else _self.clearError(); + } + }); + + return true; + }; + + (this.$vOptions || (this.$vOptions = {})).custom = "apf.lookup(" + this.$uniqueId + ").$checkRemoteValidation()"; + delete this.$vOptions.isValid; + }; +}; + + +apf.GuiElement.propHandlers["required"] = +apf.GuiElement.propHandlers["pattern"] = +apf.GuiElement.propHandlers["min"] = +apf.GuiElement.propHandlers["max"] = +apf.GuiElement.propHandlers["maxlength"] = +apf.GuiElement.propHandlers["minlength"] = +apf.GuiElement.propHandlers["notnull"] = +apf.GuiElement.propHandlers["checkequal"] = +apf.GuiElement.propHandlers["validtest"] = function(value, prop) { + this.implement(apf.Validation); + this.$propHandlers[prop].call(this, value, prop); +} + +/** + * This object allows for a set of AML elements to be validated. An element that + * is not valid shows an errorbox. + * + * #### Example + * + * ```xml + * + * Phone number + * + * + * Password + * + * + * ``` + * + * To check if the element has valid information entered, leaving the textbox + * (focussing another element) will trigger a check. Programmatically, a check + * can be done using the following code: + * + * + * ```javascript + * txtPhone.validate(); + * + * // Or, use the html5 syntax + * txtPhone.checkValidity(); + * ``` + * + * To check for the entire group of elements, use the validation group. For only + * the first non-valid element the errorbox is shown. That element also receives + * focus. + * + * ```javascript + * vgForm.validate(); + * ``` + * + * @class apf.ValidationGroup + * @inherits apf.Class + * @default_private + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.9 + */ +/** + * @event validation Fires when the validation group isn't validated. + */ +apf.ValidationGroup = function(name) { + this.$init(); + + this.childNodes = []; + + if (name) + apf.setReference(name, this); + + this.name = name || "validgroup" + this.$uniqueId; + + apf.nameserver.register("validgroup", this.name, this); + +}; + +(function(){ + /** + * When set to true, only visible elements are validated. + * @type Boolean + */ + this.validateVisibleOnly = false; + + /** + * When set to true, validation doesn't stop at the first invalid element. + * @type Boolean + */ + this.allowMultipleErrors = false; + + /** + * Adds an AML element to this validation group. + * @param o {apf.AmlElement} The AML element to add + */ + this.register = function(o) { + if (o.hasFeature(apf.__VALIDATION__)) + this.childNodes.push(o); + }; + + /** + * Removes a AML element from this validation group. + * @param o {apf.AmlElement} The AML element to remove + */ + this.unregister = function(o) { + this.childNodes.remove(o); + }; + + /** + * Returns a string representation of this object. + */ + this.toString = function(){ + return "[APF Validation Group]"; + }; + + //Shared among all validationgroups + var errbox; + /** + * Retrieves the {@link apf.errorbox} used for a specified element. + * + * @param {apf.AmlNode} o An AMLNode specifying the element for which the Errorbox should be found. If none is found, an Errorbox is created. Use the {@link apf.ValidationGroup.allowMultipleErrors} to influence when Errorboxes are created. + * @param {Boolean} no_create Boolean that specifies whether new Errorbox may be created when it doesn't exist already + * @return {apf.errorbox} The found (or created) Errorbox + */ + this.getErrorBox = function(o, no_create) { + if (this.allowMultipleErrors || !errbox && !no_create) { + errbox = new apf.errorbox(); + errbox.$pHtmlNode = o.$ext.parentNode; + errbox.skinset = apf.getInheritedAttribute(o.parentNode, "skinset"); //@todo use skinset here. Has to be set in presentation + errbox.dispatchEvent("DOMNodeInsertedIntoDocument"); + } + return errbox; + }; + + /** + * Hide all Errorboxes for the elements using this element as their validation group. + * + */ + this.hideAllErrors = function(){ + if (errbox && errbox.host) + errbox.host.clearError(); + }; + + function checkValidChildren(oParent, ignoreReq, nosetError) { + var found; + //Per Element + for (var v, i = 0; i < oParent.childNodes.length; i++) { + var oEl = oParent.childNodes[i]; + + if (!oEl) + continue; + if (!oEl.disabled + && (!this.validateVisibleOnly && oEl.visible || !oEl.$ext || oEl.$ext.offsetHeight) + && (oEl.hasFeature(apf.__VALIDATION__) && oEl.isValid && !oEl.isValid(!ignoreReq))) { + //|| !ignoreReq && oEl.required && (!(v = oEl.getValue()) || new String(v).trim().length == 0) + + if (!nosetError) { + if (!found) { + oEl.validate(true, null, true); + found = true; + if (!this.allowMultipleErrors) + return true; //Added (again) + } + else if (oEl.errBox && oEl.errBox.host == oEl) + oEl.errBox.hide(); + } + else if (!this.allowMultipleErrors) + return true; + } + if (oEl.canHaveChildren && oEl.childNodes.length) { + found = checkValidChildren.call(this, oEl, ignoreReq, nosetError) || found; + if (found && !this.allowMultipleErrors) + return true; //Added (again) + } + } + return found; + } + + + + /** + * + * @inheritDoc apf.ValidationGroup.isValid + * @method + */ + this.validate = + + /** + * Checks if (part of) the set of element's registered to this element are + * valid. When an element is found with an invalid value, the error state can + * be set for that element. + * + * @method isValid + * @param {Boolean} [ignoreReq] Specifies whether to adhere to the 'required' check. + * @param {Boolean} [nosetError Specifies whether to not set the error state of the element with an invalid value + * @param {apf.AmlElement} [tab] The tab for which the children will be checked. When not specified all elements of this validation group are checked. + * @return {Boolean} Specifies whether the checked elements are valid. + */ + this.isValid = function(ignoreReq, nosetError, tab) { + var found = checkValidChildren.call(this, tab || this, ignoreReq, + nosetError); + + if (tab) { + + if (tab.validation && !eval(tab.validation)) { + alert(tab.invalidmsg); + found = true; + } + + } + + //Global Rules + // + //if (!found) + //found = this.dispatchEvent("validation"); + + return !found; + }; +}).call(apf.ValidationGroup.prototype = new apf.Class()); + +apf.config.$inheritProperties["validgroup"] = 1; + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + +apf.__DATABINDING__ = 1 << 1; + + + +/** + * This is a baseclass that adds data binding features to this element. + * Databinding takes care of automatically going from data to representation and establishing a + * permanent link between the two. In this way data that is changed will + * change the representation as well. Furthermore, actions that are executed on + * the representation will change the underlying data. + * + * #### Example + * + * ```xml + * + * + * + * Item 1 + * Item 2 + * + * + * + * + * + * + * + * + * ``` + * + * @class apf.DataBinding + * @inherits apf.Presentation + * @baseclass + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.4 + * @default_private + */ +/** + * @event error Fires when a communication error has occured while + * making a request for this element. + * @cancelable Prevents the error from being thrown. + * @bubbles + * @param {Object} e The standard event object. It contains the following properties: + * - error ([[Error]]): the error object that is thrown when the event callback doesn't return false. + * - state ([[Number]]): the state of the call + * - `apf.SUCCESS`: The request was successfull + * - `apf.TIMEOUT`: The request has timed out. + * - `apf.ERROR `: An error has occurred while making the request. + * - `apf.OFFLINE`: The request was made while the application was offline. + * - userdata (`Mixed`): Data that the caller wanted to be available in the callback of the http request. + * - http ([[XMLHttpRequest]]): The object that executed the actual http request. + * - url ([[String]]): The url that was requested. + * - tpModule ([[apf.http]]): The teleport module that is making the request. + * - id ([[Number]]): The ID of the request. + * - message ([[String]]): The error message. + */ +/** + * @event beforeretrieve Fires before a request is made to retrieve data. + * @cancelable Prevents the data from being retrieved. + */ +/** + * @event afterretrieve Fires when the request to retrieve data returns both + * on success and failure. + */ +/** + * @event receive Fires when data is successfully retrieved + * @param {Object} e The standard event object. It contains the following properties: + * - data ([[String]]): the retrieved data + * + */ +apf.DataBinding = function(){ + this.$init(true); + + this.$loadqueue = + this.$dbTimer = null; + this.$regbase = this.$regbase | apf.__DATABINDING__; + this.$mainBind = "value"; + + this.$bindings = + this.$cbindings = + this.$attrBindings = false; + + //1 = force no bind rule, 2 = force bind rule + this.$attrExcludePropBind = apf.extend({ + model: 1, + each: 1 + //eachvalue : 1 //disabled because of line 1743 valueRule = in multiselect.js + }, this.$attrExcludePropBind); + + // *** Public Methods *** // + + /** + * Sets a value of an XMLNode based on an xpath statement executed on the data of this model. + * + * @param {String} xpath The xpath used to select a XMLNode + * @param {String} value The value to set + * @return {XMLNode} The changed XMLNode + */ + this.setQueryValue = function(xpath, value, type) { + var node = apf.createNodeFromXpath(this[type || 'xmlRoot'], xpath); + if (!node) + return null; + + apf.setNodeValue(node, value, true); + //apf.xmldb.setTextNode(node, value); + return node; + }; + + /** + * Queries the bound data for a string value + * + * @param {String} xpath The XPath statement which queries on the data this element is bound on. + * @param {String} type The node that is used as the context node for the query. It can be one of the following possible values: + * - `"selected"`: The selected data anode of this element. + * - `"xmlRoot"`: The root data node that this element is bound on. + * - `"indicator"`: The data node that is highlighted for keyboard navigation. + * @return {String} The value of the selected XML Node + * + */ + this.queryValue = function(xpath, type) { + /* @todo + * lstRev.query('revision/text()', 'selected'); + * lstRev.query('revision/text()', 'xmlRoot'); + * lstRev.query('revision/text()', 'indicator'); + */ + return apf.queryValue(this[type || 'xmlRoot'], xpath ); + }; + /** + * Queries the bound data for an array of string values + * + * @param {String} xpath The XPath statement which queries on the data this element is bound on. + * @param {String} type The node that is used as the context node for the query. It can be one of the following possible values: + * - `"selected"`: The selected data anode of this element. + * - `"xmlRoot"`: The root data node that this element is bound on. + * - `"indicator"`: The data node that is highlighted for keyboard navigation. + * @return {String} The value of the selected XML Node + */ + this.queryValues = function(xpath, type) { + return apf.queryValues(this[type || 'xmlRoot'], xpath ); + }; + + /** + * Executes an XPath statement on the data of this model + * + * @param {String} xpath The XPath statement which queries on the data this element is bound on. + * @param {String} type The node that is used as the context node for the query. It can be one of the following possible values: + * - `"selected"`: The selected data anode of this element. + * - `"xmlRoot"`: The root data node that this element is bound on. + * - `"indicator"`: The data node that is highlighted for keyboard navigation. + * @return {Mixed} An [[XMLNode]] or [[NodeList]] with the result of the selection + */ + this.queryNode = function(xpath, type) { + var n = this[type||'xmlRoot']; + return n ? n.selectSingleNode(xpath) : null; + }; + + /** + * Executes an XPath statement on the data of this model + * + * @param {String} xpath The XPath used to select the XMLNode(s) + * @param {String} type The node that is used as the context node for the query. It can be one of the following possible values: + * - `"selected"`: The selected data anode of this element. + * - `"xmlRoot"`: The root data node that this element is bound on. + * - `"indicator"`: The data node that is highlighted for keyboard navigation. + * @return {Mixed} An [[XMLNode]] or [[NodeList]] with the result of the selection + */ + this.queryNodes = function(xpath, type) { + var n = this[type||'xmlRoot']; + return n ? n.selectNodes(xpath) : []; + }; + + this.$checkLoadQueue = function(){ + // Load from queued load request + if (this.$loadqueue) { + if (!this.caching) + this.xmlRoot = null; + var q = this.load(this.$loadqueue[0], {cacheId: this.$loadqueue[1]}); + if (!q || q.dataType != apf.ARRAY || q != this.$loadqueue) + this.$loadqueue = null; + } + else return false; + }; + + //setProp + this.$execProperty = function(prop, xmlNode, undoObj) { + var attr = this.$attrBindings[prop]; + + //@todo this is a hacky solution for replaceNode support - Have to rethink this. + if (this.nodeType == 7) { + if (xmlNode != this.xmlRoot) + this.xmlRoot = xmlNode; + } + + + + + + + try { + + if (attr.cvalue.asyncs) { //if async + var _self = this; + return attr.cvalue.call(this, xmlNode, function(value) { + _self.setProperty(prop, value, true); + + + + }); + } + else { + var value = attr.cvalue.call(this, xmlNode); + } + + } + catch (e) { + apf.console.warn("[400] Could not execute binding for property " + + prop + "\n\n" + e.message); + return; + } + + + this.setProperty(prop, undoObj && undoObj.extra.range || value, true); //@todo apf3.0 range + + + }; + + //@todo apf3.0 contentEditable support + this.$applyBindRule = function(name, xmlNode, defaultValue, callback, oHtml) { + var handler = this.$attrBindings[name] + && this.$attrBindings[name].cvalue || this.$cbindings[name]; + + return handler ? handler.call(this, xmlNode, callback) : defaultValue || ""; + }; + + + + this.$hasBindRule = function(name) { + return this.$attrBindings[name] || this.$bindings + && this.$bindings[name]; + }; + + this.$getBindRule = function(name, xmlNode) { + return this.$attrBindings[name] || this.$bindings + && this.$bindings.getRule(name, xmlNode); + }; + + var ruleIsMatch = {"drag":1,"drop":1,"dragcopy":1} + this.$getDataNode = function(name, xmlNode, createNode, ruleList, multiple) { + var node, rule = this.$attrBindings[name]; + if (rule) { //@todo apf3.0 find out why drag and drop rules are already compiled here + if (rule.cvalue.type != 3) //@todo warn here? + return false; + + var func = rule.cvalue2 || rule.compile("value", { + xpathmode: multiple ? 4 : 3, + parsecode: 1, + injectself: ruleIsMatch[name] + }); + if (func && (node = func(xmlNode, createNode))) { + if (ruleList) + ruleList.push(rule); + + return node; + } + + return false; + } + + return this.$bindings + && this.$bindings.getDataNode(name, xmlNode, createNode, ruleList, multiple); + }; + + + /** + * Sets the model of the specified element. + * The model acts as a datasource for this element. + * + * @param {apf.model} The model this element is going to connect to. + * + */ + this.setModel = function(model) { + this.setAttribute("model", model, false, true); + }; + + + /** + * Gets the model which this element is connected to. + * The model acts as a datasource for this element. + * + * @param {Boolean} doRecur Specifies whether the model should be searched recursively up the data tree. + * @returns {apf.model} The model this element is connected to. + * @see apf.smartbinding + */ + this.getModel = function(doRecur) { + if (doRecur && !this.$model) + return this.dataParent ? this.dataParent.parent.getModel(true) : null; + + return this.$model; + }; + + /** + * Reloads the data in this element. + * @method + */ + this.reload = this.reload || function(){ + this.load(this.xmlRoot, {cacheId: this.cacheId, force: true}); + }; + + /** + * @event beforeload Fires before loading data in this element. + * @cancelable Prevents the data from being loaded. + * @param {XMLElement} xmlNode The node that is loaded as the root {@link term.datanode data node}. + * + */ + /** + * @event afterload Fires after loading data in this element. + * @param {XMLElement} xmlNode The node that is loaded as the root {@link term.datanode data node}. + */ + /** + * Loads data into this element using binding rules to transform the + * data into a presentation. + * + * #### Example + * + * ```xml + * + * + * + * + * + * + * + * + * + * ``` + * + * @param {XMLElement | String} [xmlNode] The content to load into this element. It can be one of the following values: + * - {XMLElement}: An XML element that's loaded into this element + * - {String}: Either an XML string, or, an instruction to load the data from a remote source + * - `null`: Clears this element from its data + * @param {Object} [options] Set of additional options to pass. Properties include: + * - [xmlNode] ([[XMLElement]]): The {@link term.datanode data node} that provides + * context to the data instruction. + * - [callback] ([[Function]]): The code executed when the data request returns + * - [properties] (`Mixed`): Custom properties available in the data instruction + * - [cacheId] ([[String]]): The xml element to which the binding rules are applied + * - [force] ([[Boolean]]): Specifies whether cache is checked before loading the data + * - [noClearMsg] ([[Boolean]]): Specifies whether a message is set when clear is called + */ + this.load = function(xmlNode, options) { + if (options) { + var cacheId = options.cacheId, + forceNoCache = options.force, + noClearMsg = options.noClearMsg; + } + if (cacheId && cacheId == this.cacheId && !forceNoCache) + return; + + + if (apf.popup.isShowing(this.$uniqueId)) + apf.popup.forceHide(); //This should be put in a more general position + + + // Convert first argument to an xmlNode we can use; + if (xmlNode) { + if (typeof xmlNode == "string") { + if (xmlNode.charAt(0) == "<") + xmlNode = apf.getXmlDom(xmlNode).documentElement; + else { + return apf.model.prototype.$loadFrom.call(this, xmlNode, options); + } + } + else if (xmlNode.nodeType == 9) { + xmlNode = xmlNode.documentElement; + } + else if (xmlNode.nodeType == 3 || xmlNode.nodeType == 4) { + xmlNode = xmlNode.parentNode; + } + else if (xmlNode.nodeType == 2) { + xmlNode = xmlNode.ownerElement + || xmlNode.parentNode + || xmlNode.selectSingleNode(".."); + } + } + + // If control hasn't loaded databinding yet, queue the call + if (this.$preventDataLoad || !this.$canLoadData + && ((!this.$bindings && (!this.$canLoadDataAttr || !this.each)) || !this.$amlLoaded) + && (!this.hasFeature(apf.__MULTISELECT__) || !this.each) + || this.$canLoadData && !this.$canLoadData()) { + + if (!this.caching || !this.hasFeature(apf.__CACHE__)) { + + //@todo this is wrong. It is never updated when there are only + //Property binds and then it just leaks xml nodes + this.xmlRoot = xmlNode; + + + this.setProperty("root", this.xmlRoot); + + } + + + + return this.$loadqueue = [xmlNode, cacheId]; + } + this.$loadqueue = null; + + // If no xmlNode is given we clear the control, disable it and return + if (this.dataParent && this.dataParent.xpath) + this.dataParent.parent.signalXmlUpdate[this.$uniqueId] = !xmlNode; + + if (!xmlNode && (!cacheId || !this.$isCached || !this.$isCached(cacheId))) { + + + this.clear(noClearMsg); + + + if (apf.config.autoDisable && this.$createModel === false) + this.setProperty("disabled", true); + + //@todo apf3.0 remove , true in clear above + //this.setProperty("selected", null); + + return; + } + + // If reloading current document, and caching is disabled, exit + if (!this.caching && !forceNoCache && xmlNode + && !this.$loadqueue && xmlNode == this.xmlRoot) + return; + + var disabled = this.disabled; + this.disabled = false; + + //Run onload event + if (this.dispatchEvent("beforeload", {xmlNode : xmlNode}) === false) + return false; + + + + this.clear(true, true); + + this.cacheId = cacheId; + + if (this.dispatchEvent("$load", { + forceNoCache: forceNoCache, + xmlNode: xmlNode + }) === false) { + //delete this.cacheId; + return; + } + + //Set usefull vars + this.documentId = apf.xmldb.getXmlDocId(xmlNode); + this.xmlRoot = xmlNode; + + + this.setProperty("root", this.xmlRoot); + + + + + // Draw Content + this.$load(xmlNode); + + + + // Check if subtree should be loaded + this.$loadSubData(xmlNode); + + if (this.$createModel === false) { + this.disabled = true; + this.setProperty("disabled", false); + } + else + this.disabled = disabled; + + // Run onafteronload event + this.dispatchEvent('afterload', {xmlNode : xmlNode}); + }; + + // @todo Doc + /* + * @binding load Determines how new data is loaded data is loaded into this + * element. Usually this is only the root node containing no children. + * + * #### Example + * + * This example shows a load rule in a text element. It gets its data from + * a list. When a selection is made on the list the data is loaded into the + * text element. + * + * ```xml + * + * + * + * + * + * + * + * + * message 1 + * message 2 + * + * + * + * + * + * + * + * + * + * + * ``` + * + */ + /** + * @attribute {String} get Sets or gets the {@link term.datainstruction data instruction} + * that is used to load data into the XML root of this component. + */ + this.$loadSubData = function(xmlRootNode) { + if (this.$hasLoadStatus(xmlRootNode) && !this.$hasLoadStatus(xmlRootNode, "potential")) + return; + + //var loadNode = this.$applyBindRule("load", xmlRootNode); + var rule = this.$getBindRule("load", xmlRootNode); + if (rule && (!rule[1] || rule[1](xmlRootNode))) { + + + this.$setLoadStatus(xmlRootNode, "loading"); + + if (this.$setClearMessage) + this.$setClearMessage(this["loading-message"], "loading"); + + //||apf.xmldb.findModel(xmlRootNode) + var mdl = this.getModel(true); + + + var amlNode = this; + if (mdl.$insertFrom(rule.getAttribute("get"), { + xmlNode: xmlRootNode, //@todo apf3.0 + insertPoint: xmlRootNode, //this.xmlRoot, + amlNode: this, + callback: function(){ + + amlNode.setProperty(amlNode.hasFeature(apf.__MULTISELECT__) + ? "selected" + : "root", xmlRootNode); + + } + }) === false + ) { + this.clear(true); + + if (apf.config.autoDisable) + this.setProperty("disabled", true); + + //amlNode.setProperty("selected", null); //@todo is this not already done in clear? + + } + } + }; + + //@todo this function is called way too much for a single load of a tree + //@todo should clear listener + /* + * Unloads data from this element and resets state displaying an empty message. + * The empty message is set on the {@link apf.GuiElement.msg}. + * + * @param {Boolean} [nomsg] Specifies whether to display the empty message. + * @param {Boolean} [doEvent] Specifies whether to send select events. + * @see baseclass.databinding.method.load + * @private + */ + this.clear = function(nomsg, doEvent, fakeClear) { + if (!this.$container) + return;//@todo apf3.0 + + if (this.clearSelection) + this.clearSelection(true);//!doEvent);//@todo move this to the $clear event in multiselect.js + + var lastHeight = this.$container.offsetHeight; + + if (this.dispatchEvent("$clear") !== false) + this.$container.innerHTML = ""; //@todo apf3.0 + + if (typeof nomsg == "string") { + var msgType = nomsg; + nomsg = false; + + //@todo apf3.0 please use attr. inheritance + if (!this[msgType + "-message"]) { + this.$setInheritedAttribute(msgType + "-message"); + } + } + this.$lastClearType = msgType || null; + + if (!nomsg && this.$setClearMessage) { + this.$setClearMessage(msgType + ? this[msgType + "-message"] + : this["empty-message"], msgType || "empty", lastHeight); + + //this.setProperty("selected", null); //@todo apf3.0 get the children to show loading... as well (and for each selected, null + //c[i].o.clear(msgType, doEvent); + } + else if (this.$removeClearMessage) + this.$removeClearMessage(); + + if (!fakeClear) + this.documentId = this.xmlRoot = this.cacheId = null; + + + if (!nomsg) { + if (this.hasFeature(apf.__MULTISELECT__)) //@todo this is all wrong + this.setProperty("length", 0); + //else + //this.setProperty("value", ""); //@todo redo apf3.0 + } + + }; + + this.clearMessage = function(msg) { + this.customMsg = msg; + this.clear("custom"); + }; + + //@todo optimize this + /** + * @private + */ + this.$setLoadStatus = function(xmlNode, state, remove) { + var group = this.loadgroup || "default"; + var re = new RegExp("\\|(\\w+)\\:" + group + ":(\\d+)\\|"); + var loaded = xmlNode.getAttribute("a_loaded") || ""; + + var m; + if (!remove && (m = loaded.match(re)) && m[1] != "potential" && m[2] != this.$uniqueId) + return; + + //remove old status if any + var ostatus = loaded.replace(re, "") + if (!remove) + ostatus += "|" + state + ":" + group + ":" + this.$uniqueId + "|"; + + xmlNode.setAttribute("a_loaded", ostatus); + }; + + /** + * @private + */ + this.$removeLoadStatus = function(xmlNode) { + this.$setLoadStatus(xmlNode, null, true); + }; + + /** + * @private + */ + this.$hasLoadStatus = function(xmlNode, state, unique) { + if (!xmlNode) + return false; + var ostatus = xmlNode.getAttribute("a_loaded"); + if (!ostatus) + return false; + + var group = this.loadgroup || "default"; + var re = new RegExp("\\|" + (state || "\\w+") + ":" + group + ":" + (unique ? this.$uniqueId : "\\d+") + "\\|"); + return ostatus.match(re) ? true : false; + }; + + /* + * @event beforeinsert Fires before data is inserted. + * @cancelable Prevents the data from being inserted. + * @param {XMLElement} xmlParentNode The parent in which the new data is inserted + */ + /** + * @event afterinsert Fires after data is inserted. + */ + + /** + * @private + */ + this.insert = function(xmlNode, options) { + if (typeof xmlNode == "string") { + if (xmlNode.charAt(0) == "<") { + + if (options.whitespace === false) + xmlNode = xmlNode.replace(/>[\s\n\r]*<"); + + xmlNode = apf.getXmlDom(xmlNode).documentElement; + } + else { + if (!options.insertPoint) + options.insertPoint = this.xmlRoot; + return apf.model.prototype.$insertFrom.call(this, xmlNode, options); + } + } + + var insertPoint = options.insertPoint || this.xmlRoot; + + if (this.dispatchEvent("beforeinsert", { + xmlParentNode: insertPoint + }) === false) + return false; + + //Integrate XMLTree with parentNode + if (typeof options.copyAttributes == "undefined") + options.copyAttributes = true; + + if (this.filterUnique) + options.filter = this.filterUnique; + + var newNode = apf.mergeXml(xmlNode, insertPoint, options); + + this.$isLoading = true; //Optimization for simpledata + + //Call __XMLUpdate on all listeners + apf.xmldb.applyChanges("insert", insertPoint); + + this.$isLoading = false; + + //Select or propagate new data + if (this.selectable && this.autoselect) { + if (this.xmlNode == newNode) + this.$selectDefault(this.xmlNode); + } + + else if (this.xmlNode == newNode) { + this.setProperty("root", this.xmlNode); + } + + + if (this.$hasLoadStatus(insertPoint, "loading")) + this.$setLoadStatus(insertPoint, "loaded"); + + this.dispatchEvent("afterinsert"); + + //Check Connections + //this one shouldn't be called because they are listeners anyway...(else they will load twice) + //if(this.selected) this.setConnections(this.selected, "select"); + }; + + /** + * @attribute {Boolean} render-root Sets or gets whether the XML element loaded into this + * element is rendered as well. The default is false. + * + * #### Example + * + * This example shows a tree which also renders the root element. + * + * ```xml + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * ``` + */ + this.$booleanProperties["render-root"] = true; + this.$supportedProperties.push("empty-message", "loading-message", + "offline-message", "render-root", "smartbinding", + "bindings", "actions"); + + /** + * @attribute {Boolean} render-root Sets or gets whether the root node of the data loaded + * into this element is rendered as well. + * @see apf.tree + */ + this.$propHandlers["render-root"] = function(value) { + this.renderRoot = value; + }; + + /** + * @attribute {String} empty-message Sets or gets the message displayed by this element + * when it contains no data. This property is inherited from parent nodes. + * When none is found, it is looked for on the appsettings element. Otherwise + * it defaults to the string "No items". + */ + this.$propHandlers["empty-message"] = function(value) { + this["empty-message"] = value; + + if (this.$updateClearMessage) + this.$updateClearMessage(this["empty-message"], "empty"); + }; + + /** + * @attribute {String} loading-message Sets or gets the message displayed by this + * element when it's loading. This property is inherited from parent nodes. + * When none is found, it is looked for on the appsettings element. Otherwise + * it defaults to the string "Loading...". + * + * #### Example + * + * This example uses property bindings to update the loading message. The + * position of the progressbar should be updated by the script taking care + * of loading the data. + * + * ```xml + * + * + * ``` + * + * #### Remarks + * + * Usually, a static loading message is displayed for only 100 milliseconds + * or so, whilst loading the data from the server. For instance, this is done + * when the load binding rule is used. In the code example below, a list + * binds on the selection of a tree displaying folders. When the selection + * changes, the list loads new data by extending the model. During the load + * of this new data, the loading message is displayed. + * + * ```xml + * + * + * ... + * + * + * + * ``` + */ + this.$propHandlers["loading-message"] = function(value) { + this["loading-message"] = value; + + if (this.$updateClearMessage) + this.$updateClearMessage(this["loading-message"], "loading"); + }; + + /** + * @attribute {String} offline-message Sets or gets the message displayed by this + * element when it can't load data because the application is offline. + * This property is inherited from parent nodes. When none is found it is + * looked for on the appsettings element. Otherwise it defaults to the + * string "You are currently offline...". + */ + this.$propHandlers["offline-message"] = function(value) { + this["offline-message"] = value; + + if (this.$updateClearMessage) + this.$updateClearMessage(this["offline-message"], "offline"); + }; + + /** + * @attribute {String} smartbinding Sets or gets the name of the SmartBinding for this + * element. + * + * A smartbinding is a collection of rules which define how data + * is transformed into representation, how actions on the representation are + * propagated to the data and it's original source, how drag&drop actions + * change the data and where the data is loaded from. Each of these are + * optionally defined in the smartbinding set and can exist independently + * of the smartbinding object. + * + * #### Example + * + * This example shows a fully specified smartbinding. Usually, only parts + * are used. This example shows a tree with files and folders. + * + * ```xml + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * ``` + * + * #### Remarks + * + * The smartbinding parts can also be assigned to an element by adding them + * directly as a child in aml. + * + * ```xml + * + * + * ... + * + * + * + * + * + * ### See Also + * + * There are several ways to be less verbose in assigning certain rules. For more information, see: + * + * * [[apf.bindings]] + * * [[apf.actions]] + * * [[apf.DragDrop]] + * + */ + this.$propHandlers["smartbinding"] = + + /** + * @attribute {String} actions Sets or gets the id of the actions element which + * provides the action rules for this element. Action rules are used to + * send changes on the bound data to a server. + * + * #### Example + * + * ```xml + * + * + * + * + * + * + * + * + * + * + * + * + * + * Undo + * ``` + */ + this.$propHandlers["actions"] = + + /** + * @attribute {String} bindings Sets or gets the id of the bindings element which + * provides the binding rules for this element. + * + * #### Example + * + * This example shows a set of binding rules that transform data into the + * representation of a list. In this case it displays the names of + * several email accounts, with after each account name the number of unread + * mails in that account. It uses JSLT to transform the caption. + * + * ```xml + * + * + * Account 1 + * + * + * + * + * Account 2 + * + * + * + * + * + * [text()] (#[mail[@read != 'true']]) + * + * + * + * ``` + * + * #### Remarks + * + * Bindings can also be assigned directly by putting the bindings tag as a + * child of this element. + * + * If the rule only contains a select attribute, it can be written in a + * short way by adding an attribute with the name of the rule to the + * element itself: + * + * ```xml + * + * ``` + */ + this.$propHandlers["bindings"] = function(value, prop) { + var local = "$" + prop + "Element"; + if (this[local]) + this[local].unregister(this); + + if (!value) + return; + + + + apf.nameserver.get(prop, value).register(this); + + + if (prop != "actions" && + this.$checkLoadQueue() === false && this.$amlLoaded) + 1+1; //@todo add reload queue. + //this.reload(); + }; + + + var eachBinds = {"caption":1, "icon":1, "select":1, "css":1, "sort":1, + "drop":2, "drag":2, "dragcopy":2, "eachvalue":1}; //Similar to apf.Class + + this.$addAttrBind = function(prop, fParsed, expression) { + //Detect if it uses an external model + if (fParsed.models) { + + if (this.hasFeature(apf.__MULTISELECT__)) { + + } + + } + + //Set listener for all models + var i, xpath, modelId, model, + paths = fParsed.xpaths, + list = {}; + //@todo when there is no model in xpath modelId == null... + for (i = 0; i < paths.length; i+=2) { + if (!list[(modelId = paths[i])]) + list[modelId] = 1; + else list[modelId]++ + } + + if (!this.$propsUsingMainModel) + this.$propsUsingMainModel = {}; + + var rule = (this.$attrBindings || (this.$attrBindings = {}))[prop] = { + cvalue: fParsed, + value: expression, + compile: apf.BindingRule.prototype.$compile, + models: [] + }; + + delete this.$propsUsingMainModel[prop]; + for (xpath, i = 0; i < paths.length; i+=2) { + modelId = paths[i]; + if (list[modelId] == -1) + continue; + + xpath = paths[i + 1]; + + if (modelId == "#" || xpath == "#") { + var m = (rule.cvalue3 || (rule.cvalue3 = apf.lm.compile(rule.value, { + xpathmode: 5 + }))).call(this, this.xmlRoot); + + //@todo apf3 this needs to be fixed in live markup + if (typeof m != "string") { + model = m.model && m.model.$isModel && m.model; + if (model) + xpath = m.xpath; + else if (m.model) { + model = typeof m.model == "string" ? apf.xmldb.findModel(m.model) : m.model; + xpath = apf.xmlToXpath(m.model, model.data) + (m.xpath ? "/" + m.xpath : ""); //@todo make this better + } + else { + //wait until model becomes available + this.addEventListener("prop." + prop, function(e) { + var m = (rule.cvalue3 || (rule.cvalue3 = apf.lm.compile(rule.value, { + xpathmode: 5 + }))).call(this, this.xmlRoot); + + if (m.model) { + this.removeEventListener("prop." + prop, arguments.callee); + var _self = this; + $setTimeout(function(){ + _self.$clearDynamicProperty(prop); + _self.$setDynamicProperty(prop, expression); + }, 10); + } + }); + continue; + } + } + else model = null; + } + else model = null; + + if (!model) { + if (modelId) { + + //@todo apf3.0 how is this cleaned up??? + //Add change listener to the data of the model + model = apf.nameserver.get("model", modelId) //is model creation useful here? + || apf.setReference(modelId, apf.nameserver.register("model", modelId, new apf.model())); + + } + else { + if (!this.$model && !this.$initingModel) + initModel.call(this); + + model = this.$model; + + if (!this.hasFeature(apf.__MULTISELECT__) + && eachBinds[prop] != 2 || !eachBinds[prop]) //@experimental - should not set this because model will load these attributes + this.$propsUsingMainModel[prop] = { + xpath: xpath, + optimize: list[modelId] == 1 + }; + } + } + + //@todo warn here if no model?? + if (model && (!this.hasFeature(apf.__MULTISELECT__) + && eachBinds[prop] != 2 || !eachBinds[prop])) { + //Create the attribute binding + //@todo: remove listenRoot = expression.indexOf("*[") > -1 -> because it doesnt make sense in certain context. recheck selection handling + model.$bindXmlProperty(this, prop, xpath, list[modelId] == 1); + rule.models.push(model); + } + + list[modelId] = -1; + } + + rule.xpath = xpath; + + this.$canLoadDataAttr = eachBinds[prop] == 1; //@todo apf3.0 remove + this.$checkLoadQueue(); + } + + this.$removeAttrBind = function(prop) { + //@todo apf3.0 + //$model.$unbindXmlProperty + var rule = this.$attrBindings[prop] + if (!rule) + return; + + delete this.$attrBindings[prop]; + delete this.$propsUsingMainModel[prop] + + var models = rule.models; + if (models.length) + for (var i = 0; i < models.length; i++) { + models[i].$unbindXmlProperty(this, prop); + } + else if (this.$model) + this.$model.$unbindXmlProperty(this, prop); + }; + + this.$initingModel; + function initModel(){ + this.$initingModel = true; + this.$setInheritedAttribute("model"); + } + + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + //Set empty message if there is no data + if (!this.model && this.$setClearMessage && !this.value) + this.$setClearMessage(this["empty-message"], "empty"); + + this.$amlLoaded = true; //@todo this can probably be removed + this.$checkLoadQueue(); + }); + + + + /** + * @attribute {String} model Sets or gets the name of the model to load data from, or a + * datainstruction to load data. + * + * #### Example + * + * ```xml + * + * + * + * + * + * + * + * ``` + * + * #### Example + * + * Here's an example loading from an XML source: + * + * ```xml + * + * + * + * + * + * + * ``` + * + * #### Example + * + * ```xml + * + * + * + * + * + * + * + * ``` + * + * #### Example + * + * This example shows a dropdown from which the user can select a country. + * The list of countries is loaded from a model. Usually this would be loaded + * from a separate url, but for clarity it's inlined. When the user selects + * a country in the dropdown the value of the item is stored in the second + * model (mdlForm) at the position specified by the ref attribute. In this + * case this is the country element. + * + * ```xml + * Name + * + * + * Country + * + * + * + * + * + * USA + * Great Britain + * The Netherlands + * + * + * + * + * + * + * + * + * + * ``` + * + * #### Remarks + * + * This attribute is inherited from a parent when not set. You can use this + * to tell sets of elements to use the same model. + * + * ```xml + * + * Name + * + * + * Happiness + * + * + * + * + * + * + * ``` + * + * When no model is specified the default model is chosen. The default + * model is the first model that is found without a name, or if all models + * have a name, the first model found. + * + * @see apf.DataBinding.model + */ + this.$propHandlers["model"] = function(value) { + //Unset model + if (!value && !this.$modelParsed) { + if (this.$model) { + this.clear(); + this.$model.unregister(this); + this.$model = null; + this.lastModelId = ""; + } + else if (this.dataParent) + this.dataParent.parent = null; //Should be autodisconnected by property binding + + return; + } + this.$initingModel = true; + + var fParsed; + //Special case for property binding + if ((fParsed = this.$modelParsed) && fParsed.type != 2) { + var found, pb = fParsed.props; + + if (this.dataParent) + this.dataParent = null; //Should be autodisconnected by property binding + + //Try to figure out who is the dataParent + for (var prop in pb) { + + + this.dataParent = { + parent: self[prop.split(".")[0]], + xpath: null, + model: this.$modelParsed.instruction + }; + + found = true; + break; // We currently only support one data parent + } + + if (found) { + //@todo this statement doesnt make sense + /*//Maybe a compound model is found + if (!this.dataParent && (pb = fParsed.xpaths && fParsed.xpaths[0])) { + this.dataParent = { + parent: self[pb.split(".")[0]], + xpath: fParsed.xpaths[1], + model: this.$modelParsed.instruction + }; + }*/ + + if (this.dataParent && !this.dataParent.signalXmlUpdate) + this.dataParent.signalXmlUpdate = {}; + } + + this.$modelParsed = null; + } + + //Analyze the data + var model; + if (typeof value == "object") { + if (value.dataType == apf.ARRAY) { //Optimization used for templating + + model = apf.nameserver.get("model", value[0]); + model.register(this, value[1]); + return; + + } + else if (value.$isModel) { // A model node is passed + //Convert model object to value; + model = value; + value = this.model = model.name; + if (!value) + model.setProperty("id", value = this.model = "model" + model.$uniqueId); + + //@todo why not set directly here? + } + else { //if (this.dataParent) { //Data came through data parent + if (this.dataParent) + this.model = this.dataParent.model; //reset this property + + model = apf.xmldb.findModel(value); + if (!model) //@todo very strange, this should never happen, but it does + return; + var xpath = apf.xmlToXpath(value, null, true) || "."; + + + + model.register(this, xpath); + return; + } + /*else { + //@todo Error ?? + }*/ + } + else if (value.indexOf("[::") > -1) { //@experimental + var model, pNode = this; + do { + pNode = pNode.parentNode + model = pNode.getAttribute("model"); + } + while (pNode.parentNode && pNode.parentNode.nodeType == 1 && (!model || model == value)); + + if (model && typeof model == "object") + model = model.id; + + this.$inheritProperties.model = 3; + if (model) { + value = value.replace(/\[\:\:/g, "[" + model + "::"); + } + else { + apf.console.warn("No found model on any of the parents for this element while trying to overload model: " + value); + return; + } + } + + //Optimize xmlroot position and set model async (unset the old one) + //@todo apf3.0 this could be optimized by using apf.queue and only when not all info is there... + clearTimeout(this.$dbTimer); + if (!this.$amlLoaded && this.nodeType == 1) { + var _self = this; + this.$dbTimer = $setTimeout(function(){ + if (!_self.$amlDestroyed) + apf.setModel(value, _self); + }); + } + else + apf.setModel(value, this); + }; + + + /** + * @attribute {String} viewport Sets or gets the way this element renders its data. + * + * The possible values include: + * - `"virtual"`: this element only renders data that it needs to display. + * - `"normal`"`: this element renders all data at startup. + * @experimental + */ + this.$propHandlers["viewport"] = function(value) { + if (value != "virtual") + return; + + this.implement(apf.VirtualViewport); + }; + +}; + + apf.DataBinding.prototype = new apf[apf.Presentation ? "Presentation" : "AmlElement"](); + + +apf.config.$inheritProperties["model"] = 1; +apf.config.$inheritProperties["empty-message"] = 1; +apf.config.$inheritProperties["loading-message"] = 1; +apf.config.$inheritProperties["offline-message"] = 1; +apf.config.$inheritProperties["noloading"] = 1; + +apf.Init.run("databinding"); + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +/** + * All elements inheriting from this {@link term.baseclass baseclass} can bind to data + * which contains multiple nodes. + * + * + * + * @class apf.MultiselectBinding + * @inherits apf.DataBinding + * @baseclass + * @default_private + * @allowchild item, choices + */ + +/* + * @define choices Container for item nodes which receive presentation. + * This element is part of the XForms specification. It is not necesary for + * the Ajax.org Markup Language. + * + * #### Example + * + * ```xml + * + * + * red + * blue + * green + * + * + * ``` + * @allowchild item + */ +apf.MultiselectBinding = function(){ + if (!this.setQueryValue) + this.implement(apf.DataBinding); + + this.$regbase = this.$regbase|apf.__MULTISELECT__; //We're pretending to have multiselect even though we might not. + + this.$init(function(){ + this.$selectTimer = {}; + }); +}; + +(function(){ + this.length = 0; + + //1 = force no bind rule, 2 = force bind rule + this.$attrExcludePropBind = apf.extend({ + caption: 2, + icon: 2, + eachvalue: 2, + select: 2, + css: 2, + sort: 2, + drag: 2, + drop: 2, + dragcopy: 2, + selected: 3, + //caret : 2, + each: 1, + "selection" : 3, //only databound when has an xpath + "selection-unique" : 3, //only databound when has an xpath + "selection-constructor" : 3 //only databound when has an xpath + }, this.$attrExcludePropBind); + + + /** + * Change the sorting order of this element. + * + * @param {Object} options The new sort options. These are applied incrementally. + * Any property that is not set is maintained unless the clear + * parameter is set to `true`. The following properties are available: + * - order ([[String]]) + * - [xpath] ([[String]]) + * - [type] ([[String]]) + * - [method] ([[String]]) + * - [getNodes] ([[Function]]): A function that retrieves a list of nodes. + * - [dateFormat] ([[String]]) + * - [getValue] ([[Function]]): A function that determines the string content based + * on an XML node as it's first argument. + * @param {Boolean} clear Removes the current sort options. + * @param {Boolean} noReload Specifies whether to reload the data of this component. + */ + this.resort = function(options, clear, noReload) { + if (!this.$sort) + this.$sort = new apf.Sort(); + + this.$sort.set(options, clear); + + if (this.clearAllCache) + this.clearAllCache(); + + if (noReload) + return; + + + /*if(this.hasFeature(apf.__VIRTUALVIEWPORT__)){ + this.$clearVirtualDataset(this.xmlRoot); + this.reload(); + + return; + }*/ + + + var _self = this; + (function sortNodes(xmlNode, htmlParent) { + if (!xmlNode) + return; + var sNodes = _self.$sort.apply( + apf.getArrayFromNodelist(xmlNode.selectNodes(_self.each))); + + for (var i = 0; i < sNodes.length; i++) { + if (_self.$isTreeArch || _self.$withContainer) { + var htmlNode = apf.xmldb.findHtmlNode(sNodes[i], _self); + + + + var container = _self.$findContainer(htmlNode); + + htmlParent.appendChild(htmlNode); + if (!apf.isChildOf(htmlNode, container, true)) + htmlParent.appendChild(container); + + sortNodes(sNodes[i], container); + } + else + htmlParent.appendChild(apf.xmldb.findHtmlNode(sNodes[i], _self)); + } + })(this.xmlRoot, this.$container); + + return options; + }; + + /** + * Change sorting from ascending to descending, and vice versa! + */ + this.toggleSortOrder = function(){ + return this.resort({"ascending" : !this.$sort.get().ascending}).ascending; + }; + + /** + * Retrieves the current sort options. + * + * @returns {Object} The current sort options. The following properties are available: + * - order ([[String]]) + * - xpath ([[String]]) + * - type ([[String]]) + * - method ([[String]]) + * - getNodes ([[Function]]): A function that retrieves a list of nodes. + * - dateFormat ([[String]]) + * - getValue ([[Function]]): A function that determines the string content based on + * an XML node as it's first argument. + * + */ + this.getSortSettings = function(){ + return this.$sort.get(); + }; + + + /* + * Optimizes load time when the xml format is very simple. + */ + // @todo Doc + this.$propHandlers["simpledata"] = function(value) { + if (value) { + this.getTraverseNodes = function(xmlNode) { + + if (this.$sort && !this.$isLoading) { + var nodes = apf.getArrayFromNodelist((xmlNode || this.xmlRoot).childNodes); + return this.$sort.apply(nodes); + } + + + return (xmlNode || this.xmlRoot).childNodes; + }; + + this.getFirstTraverseNode = function(xmlNode) { + return this.getTraverseNodes(xmlNode)[0];//(xmlNode || this.xmlRoot).childNodes[0]; + }; + + this.getLastTraverseNode = function(xmlNode) { + var nodes = this.getTraverseNodes(xmlNode);//(xmlNode || this.xmlRoot).childNodes; + return nodes[nodes.length - 1]; + }; + + this.getTraverseParent = function(xmlNode) { + if (!xmlNode.parentNode || xmlNode == this.xmlRoot) + return false; + + return xmlNode.parentNode; + }; + } + else { + delete this.getTraverseNodes; + delete this.getFirstTraverseNode; + delete this.getLastTraverseNode; + delete this.getTraverseParent; + } + }; + + /** + * Retrieves a node list containing the {@link term.datanode data nodes} which + * are rendered by this element. + * + * @param {XMLElement} [xmlNode] The parent element on which each query is applied. + * @return {NodeList} The node list containing the data nodes + */ + this.getTraverseNodes = function(xmlNode) { + + + + if (this.$sort) { + var nodes = apf.getArrayFromNodelist((xmlNode || this.xmlRoot).selectNodes(this.each)); + return this.$sort.apply(nodes); + } + + + return (xmlNode || this.xmlRoot).selectNodes(this.each); + }; + + /** + * Retrieves the first {@link term.datanode data node} which gets representation + * in this element. + * + * @param {XMLElement} [xmlNode] The parent element on which the each query is executed. + * @return {apf.AmlNode} The first represented {@link term.datanode data node} + */ + this.getFirstTraverseNode = function(xmlNode) { + + if (this.$sort) { + var nodes = (xmlNode || this.xmlRoot).selectNodes(this.each); + return this.$sort.apply(nodes)[0]; + } + + + return (xmlNode || this.xmlRoot).selectSingleNode(this.each); + }; + + /** + * Retrieves the last {@link term.datanode data node} which gets representation + * in this element. + * + * @param {XMLElement} [xmlNode] the parent element on which the each query is executed. + * @return {XMLElement} The last represented {@link term.datanode data node} + * + */ + this.getLastTraverseNode = function(xmlNode) { + var nodes = this.getTraverseNodes(xmlNode || this.xmlRoot); + return nodes[nodes.length-1]; + }; + + /** + * Determines whether a {@link term.datanode data node} is an each node. + * + * @param {XMLElement} [xmlNode] The parent element on which the each query is executed. + * @return {Boolean} Identifies whether the XML element is a each node. + * + */ + this.isTraverseNode = function(xmlNode) { + /* + Added optimization, only when an object has a tree architecture is it + important to go up to the each parent of the xmlNode, else the node + should always be based on the xmlroot of this component + */ + //this.$isTreeArch + var nodes = this.getTraverseNodes( + this.getTraverseParent(xmlNode) || this.xmlRoot); + for (var i = 0; i < nodes.length; i++) + if (nodes[i] == xmlNode) + return true; + return false; + }; + + /** + * Retrieves the next `each` node to be selected from a given `each` node. + * + * The method can do this in either direction and also return the Nth node for this algorithm. + * + * @param {XMLElement} xmlNode The starting point for determining the next selection. + * @param {Boolean} [up=false] The direction of the selection. + * @param {Number} [count=1] The distance in number of nodes. + * @return {XMLElement} The {@link term.datanode data node} to be selected next. + */ + this.getNextTraverseSelected = function(xmlNode, up, count) { + if (!xmlNode) + xmlNode = this.selected; + if (!count) + count = 1; + + var i = 0; + var nodes = this.getTraverseNodes(this.getTraverseParent(xmlNode) || this.xmlRoot); + while (nodes[i] && nodes[i] != xmlNode) + i++; + + var node = (up == null) + ? nodes[i + count] || nodes[i - count] + : (up ? nodes[i + count] : nodes[i - count]); + + //arguments[2] + return node || count && (i < count || (i + 1) > Math.floor(nodes.length / count) * count) + ? node + : (up ? nodes[nodes.length-1] : nodes[0]); + }; + + /** + * Retrieves the next `each` node. + * + * The method can do this in either direction and also return the Nth next node. + * + * @param {XMLElement} xmlNode The starting point for determining the next selection. + * @param {Boolean} [up=false] The direction of the selection. + * @param {Number} [count=1] The distance in number of nodes. + * @return {XMLElement} The {@link term.datanode data node} to be selected next. + */ + this.getNextTraverse = function(xmlNode, up, count) { + if (!count) + count = 1; + if (!xmlNode) + xmlNode = this.selected; + + var i = 0; + var nodes = this.getTraverseNodes(this.getTraverseParent(xmlNode) || this.xmlRoot); + while (nodes[i] && nodes[i] != xmlNode) + i++; + + var ind = i + (up ? -1 * count : count); + return nodes[ind < 0 ? 0 : ind]; + }; + + /** + * Retrieves the parent each node. + * + * In some cases the each rules has a complex form like 'children/item'. In + * those cases, the generated tree has a different structure from that of the XML + * data. For these situations, the `xmlNode.parentNode` property won't return + * the each parent; instead, this method will give you the right parent. + * + * @param {XMLElement} xmlNode The node for which the parent element will be determined. + * @return {XMLElement} The parent node or `null` if none was found. + */ + this.getTraverseParent = function(xmlNode) { + if (!xmlNode.parentNode || xmlNode == this.xmlRoot) + return false; + + //@todo this can be removed when we have a new xpath implementation + if (xmlNode.$regbase) + return xmlNode.parentNode; + + var x, id = xmlNode.getAttribute(apf.xmldb.xmlIdTag); + if (!id) { + //return false; + xmlNode.setAttribute(apf.xmldb.xmlIdTag, "temp"); + id = "temp"; + } + + /* + do { + xmlNode = xmlNode.parentNode; + if (xmlNode == this.xmlRoot) + return false; + if (this.isTraverseNode(xmlNode)) + return xmlNode; + } while (xmlNode.parentNode); + */ + + //This is not 100% correct, but good enough for now + + x = xmlNode.selectSingleNode("ancestor::node()[((" + + this.each + ")/@" + apf.xmldb.xmlIdTag + ")='" + + id + "']"); + + if (id == "temp") + xmlNode.removeAttribute(apf.xmldb.xmlIdTag); + return x; + }; + + if (!this.$findHtmlNode) { //overwritten by apf.Cache + /** + * Finds HTML presentation node in cache by ID. + * + * @param {String} id The id of the HTMLElement which is looked up. + * @return {HTMLElement} The HTMLElement found. When no element is found, `null` is returned. + * @private + */ + this.$findHtmlNode = function(id) { + return this.$pHtmlDoc.getElementById(id); + }; + } + + this.$setClearMessage = function(msg, className, lastHeight) { + if (this.more && this.$addMoreItem) this.$addMoreItem(); + if (!this.$empty) { + if (!this.$hasLayoutNode("empty")) + return; + + this.$getNewContext("empty"); + + var xmlEmpty = this.$getLayoutNode("empty"); + if (!xmlEmpty) return; + + this.$empty = apf.insertHtmlNode(xmlEmpty, this.$container); + } + else { + this.$container.appendChild(this.$empty); + } + + var empty = this.$getLayoutNode("empty", "caption", this.$empty); + + if (empty) + apf.setNodeValue(empty, msg || ""); + + this.$empty.setAttribute("id", "empty" + this.$uniqueId); + apf.setStyleClass(this.$empty, className, ["loading", "empty", "offline"]); + + //@todo apf3.0 cleanup? + var extH = apf.getStyle(this.$ext, "height"); + this.$empty.style.height = (lastHeight && (!extH || extH == "auto") && className != "empty") + ? (Math.max(10, (lastHeight + - apf.getHeightDiff(this.$empty) + - apf.getHeightDiff(this.$ext))) + "px") + : ""; + }; + + this.$updateClearMessage = function(msg, className) { + if (!this.$empty || this.$empty.parentNode != this.$container + || this.$empty.className.indexOf(className) == -1) + return; + + var empty = this.$getLayoutNode("empty", "caption", this.$empty); + if (empty) + apf.setNodeValue(empty, msg || ""); + } + + this.$removeClearMessage = function(){ + if (!this.$empty) + this.$empty = document.getElementById("empty" + this.$uniqueId); + if (this.$empty && this.$empty.parentNode) + this.$empty.parentNode.removeChild(this.$empty); + }; + + /* + * Set listeners, calls HTML creation methods and + * initializes select and focus states of object. + */ + this.$load = function(XMLRoot) { + //Add listener to XMLRoot Node + apf.xmldb.addNodeListener(XMLRoot, this); + + this.$isLoading = true; + + var length = this.getTraverseNodes(XMLRoot).length; + if (!this.renderRoot && !length) + return this.clear(null, null, true); //@todo apf3.0 this should clear and set a listener + + + //Traverse through XMLTree + var nodes = this.$addNodes(XMLRoot, null, null, this.renderRoot, null, 0, "load"); + + //Build HTML + this.$fill(nodes); + + this.$isLoading = false; + + //Select First Child + if (this.selectable) { + + //@todo apf3.0 optimize to not set selection when .selection or .selected is set on initial load + if (this["default"]) + this.select(this["default"]); + else if (this.autoselect) { + if (!this.selected) { + if (this.renderRoot) + this.select(XMLRoot, null, null, null, true); + else if (nodes.length) + this.$selectDefault(XMLRoot); + //else @todo apf3.0 this one doesnt seem needed + //this.clearSelection(); + } + } + else { + this.clearSelection(true); + var xmlNode = this.renderRoot + ? this.xmlRoot + : this.getFirstTraverseNode(); //should this be moved to the clearSelection function? + if (xmlNode) + this.setCaret(xmlNode); + + if (this.selected) + this.setProperty("selected", null); + if (this.choosen) + this.setProperty("choosen", null); + + } + } + + if (this.focussable) + apf.document.activeElement == this ? this.$focus() : this.$blur(); + + + if (length != this.length) + this.setProperty("length", length); + + }; + + var actionFeature = { + "insert" : 127,//11111110 + "replacenode" : 127,//11111110 + "attribute" : 255,//11111111 + "add" : 251,//11110111 + "remove" : 110, //01011110 + "redo-remove" : 79, //10011110 + "synchronize" : 127,//11111110 + "move-away" : 297,//11010111 + "move" : 141 //10011111 + }; + + /** + * @event xmlupdate Fires when XML of this element is updated. + * @param {Object} e The standard event object. The following properties are available: + * - action ([[String]]): The action that was executed on the XML. The following values are possible: + * - `text` : A text node is set + * - `attribute` : An attribute is set + * - `update`: An XML node is updated + * - `insert` : xml nodes are inserted + * - `add` : An XML node is added + * - `remove` : An XML node is removed (parent still set) + * - `redo`-remove`: An XML node is removed (parent not set) + * - `synchronize`: An unknown update + * - `move-away` : An XML node is moved (parent not set) + * - `move` An XML node is moved (parent still set) + * - xmlNode ([[XMLElement]]): The node that is subject to the update + * - result (`Mixed`): The result + * - UndoObj ([[apf.UndoData]]): The undo information + */ + /* + * Loops through parents of a changed node to find the first + * connected node. Based on the action, it will change, remove, + * or update the representation of the data. + */ + this.$xmlUpdate = function(action, xmlNode, listenNode, UndoObj, lastParent) { + if (!this.xmlRoot) + return; //@todo think about purging cache when xmlroot is removed + + var result, length, pNode, htmlNode, + startNode = xmlNode; + if (!listenNode) + listenNode = this.xmlRoot; + + if (action == "redo-remove") { + var loc = [xmlNode.parentNode, xmlNode.nextSibling]; + lastParent.appendChild(xmlNode); //ahum, i'm not proud of this one + var eachNode = this.isTraverseNode(xmlNode); + if (loc[0]) + loc[0].insertBefore(xmlNode, loc[1]); + else + lastParent.removeChild(xmlNode); + + if (!eachNode) + xmlNode = lastParent; + } + + //Get First ParentNode connected + do { + if (action == "add" && this.isTraverseNode(xmlNode) + && startNode == xmlNode) + break; //@todo Might want to comment this out for adding nodes under a eachd node + + if (xmlNode.getAttribute(apf.xmldb.xmlIdTag)) { + htmlNode = this.$findHtmlNode( + xmlNode.getAttribute(apf.xmldb.xmlIdTag) + + "|" + this.$uniqueId); + + if (xmlNode == listenNode && !this.renderRoot) { + if (xmlNode == this.xmlRoot && action != "insert" && action != "replacenode") { + //@todo apf3.0 - fix this for binding on properties + this.dispatchEvent("xmlupdate", { + action: action, + xmlNode: xmlNode, + UndoObj: UndoObj + }); + return; + } + break; + } + + if (htmlNode && actionFeature[action] & 2 + && !this.isTraverseNode(xmlNode)) + action = "remove"; //@todo why not break here? + + else if (!htmlNode && actionFeature[action] & 4 + && this.isTraverseNode(xmlNode)){ + action = "add"; + break; + } + + else if (htmlNode + && (startNode != xmlNode || xmlNode == this.xmlRoot)) { + if (actionFeature[action] & 1) + action = "update"; + else if (action == "remove") + return; + } + + if (htmlNode || action == "move") + break; + } + else if (actionFeature[action] & 8 && this.isTraverseNode(xmlNode)){ + action = "add"; + break; + } + + if (xmlNode == listenNode) { + if (actionFeature[action] & 128) //The change is not for us. + return; + + break; + } + xmlNode = xmlNode.parentNode; + } + while (xmlNode && xmlNode.nodeType != 9); + + + + + + // @todo Think about not having this code here + if (this.hasFeature(apf.__VIRTUALVIEWPORT__)) { + if (!this.$isInViewport(xmlNode)) //xmlNode is a eachd node + return; + } + + + //if(xmlNode == listenNode && !action.match(/add|synchronize|insert/)) + // return; //deleting nodes in parentData of object + + var foundNode = xmlNode; + if (xmlNode && xmlNode.nodeType == 9) + xmlNode = startNode; + + if (action == "replacenode") { + //var tmpNode; + //Case for replacing the xmlroot or its direct parent + if (UndoObj ? UndoObj.args[1] == this.xmlRoot : !this.xmlRoot.parentNode) + return this.load(UndoObj ? UndoObj.xmlNode : listenNode, {force: true}); + + //Case for replacing a node between the xmlroot and the traverse nodes + var nodes = this.getTraverseNodes(); + for (var i = 0, l = nodes.length; i < l; i++) { + if (apf.isChildOf(startNode, nodes[i])) + return this.load(this.xmlRoot, {force: true}); //This can be more optimized by using addNodes + } + //if ((tmpNode = this.getFirstTraverseNode()) && apf.isChildOf(startNode, tmpNode)) + } + + //Action Tracker Support - && xmlNode correct here??? - UndoObj.xmlNode works but fishy.... + if (UndoObj && xmlNode && !UndoObj.xmlNode) + UndoObj.xmlNode = xmlNode; + + //Check Move -- if value node isn't the node that was moved then only perform a normal update + if (action == "move" && foundNode == startNode) { + //if(!htmlNode) alert(xmlNode.getAttribute("id")+"|"+this.$uniqueId); + var isInThis = apf.isChildOf(this.xmlRoot, xmlNode.parentNode, true); //@todo this.getTraverseParent(xmlNode) + var wasInThis = apf.isChildOf(this.xmlRoot, UndoObj.extra.parent, true); + + //Move if both previous and current position is within this object + if (isInThis && wasInThis) + this.$moveNode(xmlNode, htmlNode, UndoObj.extra.oldParent); + else if (isInThis) //Add if only current position is within this object + action = "add"; + else if (wasInThis) //Remove if only previous position is within this object + action = "remove"; + } + else if (action == "move-away") { + var goesToThis = apf.isChildOf(this.xmlRoot, UndoObj.extra.parent, true); + if (!goesToThis) + action = "remove"; + } + + //Remove loading message + if (this.$removeClearMessage && this.$setClearMessage) { + if (this.getFirstTraverseNode()) + this.$removeClearMessage(); + else + this.$setClearMessage(this["empty-message"], "empty") + } + + //Check Insert + if (action == "insert" && (this.$isTreeArch || xmlNode == this.xmlRoot)) { + if (!xmlNode) + return; + + if (this.$hasLoadStatus(xmlNode) && this.$removeLoading) + this.$removeLoading(xmlNode); + + if (this.$container.firstChild && !apf.xmldb.getNode(this.$container.firstChild)) { + //Appearantly the content was cleared + this.$container.innerHTML = ""; + + if (!this.renderRoot) { + length = this.getTraverseNodes().length; + if (!length) + this.clear(); + } + } + + result = this.$addNodes(xmlNode, null, true, false, null, null, "insert");//this.$isTreeArch?? + + this.$fillParentHtml = (this.$getParentNode + ? this.$getParentNode(htmlNode) + : htmlNode); + this.$fillParent = xmlNode; + this.$fill(result); + + + + if (this.selectable && (length === 0 || !this.xmlRoot.selectSingleNode(this.each))) + return; + } + else if (action == "add") {// || !htmlNode (Check Add) + var parentHTMLNode; + pNode = this.getTraverseParent(xmlNode) || this.xmlRoot; + + if (pNode == this.xmlRoot) + parentHTMLNode = this.$container; + + if (!parentHTMLNode && this.$isTreeArch) { + parentHTMLNode = this.$findHtmlNode( + pNode.getAttribute(apf.xmldb.xmlIdTag) + "|" + this.$uniqueId); + } + + //This should be moved into a function (used in setCache as well) + + if (!parentHTMLNode && this.getCacheItem) + parentHTMLNode = this.getCacheItem(pNode.getAttribute(apf.xmldb.xmlIdTag) + || (pNode.getAttribute(apf.xmldb.xmlDocTag) + ? "doc" + pNode.getAttribute(apf.xmldb.xmlDocTag) + : false)); + + + //Only update if node is in current representation or in cache + if (parentHTMLNode || this.$isTreeArch + && pNode == this.xmlRoot) { //apf.isChildOf(this.xmlRoot, xmlNode) + parentHTMLNode = (this.$findContainer && parentHTMLNode && parentHTMLNode.nodeType == 1 + ? this.$findContainer(parentHTMLNode) + : parentHTMLNode) || this.$container; + + result = this.$addNodes(xmlNode, parentHTMLNode, true, true, + apf.xmldb.getHtmlNode(this.getNextTraverse(xmlNode), this)); + + if (parentHTMLNode) + this.$fill(result); + } + } + else if (action == "remove") { //Check Remove + //&& (!xmlNode || foundNode == xmlNode && xmlNode.parentNode + //if (!xmlNode || startNode != xmlNode) //@todo unsure if I can remove above commented out statement + //return; + //I've commented above code out, because it disabled removing a + //subnode of a node that through an each rule makes the traverse + //node no longer a traverse node. + + //Remove HTML Node + if (htmlNode) + this.$deInitNode(xmlNode, htmlNode); + else if (startNode == this.xmlRoot) { + return this.load(null, { + noClearMsg: !this.dataParent || !this.dataParent.autoselect + }); + } + } + else if (htmlNode) { + + if (this.$sort) + this.$moveNode(xmlNode, htmlNode); + + + this.$updateNode(xmlNode, htmlNode); + + //Transaction 'niceties' + if (action == "replacenode" && this.hasFeature(apf.__MULTISELECT__) + && this.selected && xmlNode.getAttribute(apf.xmldb.xmlIdTag) + == this.selected.getAttribute(apf.xmldb.xmlIdTag)) { + this.selected = xmlNode; + } + + //if(action == "synchronize" && this.autoselect) this.reselect(); + } + else if (action == "redo-remove") { //Check Remove of the data (some ancestor) that this component is bound on + var testNode = this.xmlRoot; + while (testNode && testNode.nodeType != 9) + testNode = testNode.parentNode; + + if (!testNode) { + //Set Component in listening state until data becomes available again. + var model = this.getModel(true); + + + + return model.$waitForXml(this); + } + } + + + + //For tree based nodes, update all the nodes up + pNode = xmlNode ? xmlNode.parentNode : lastParent; + if (this.$isTreeArch && !this.$preventRecursiveUpdate + && pNode && pNode.nodeType == 1) { + do { + htmlNode = this.$findHtmlNode(pNode.getAttribute( + apf.xmldb.xmlIdTag) + "|" + this.$uniqueId); + + if (htmlNode) + this.$updateNode(pNode, htmlNode); + } + while ((pNode = this.getTraverseParent(pNode)) && pNode.nodeType == 1); + } + + //Make sure the selection doesn't become corrupted + if (actionFeature[action] & 32 && this.selectable + && startNode == xmlNode + && (action != "insert" || xmlNode == this.xmlRoot)) { + + clearTimeout(this.$selectTimer.timer); + // Determine next selection + if (action == "remove" && apf.isChildOf(xmlNode, this.selected, true) + || xmlNode == this.$selectTimer.nextNode) { + this.$selectTimer.nextNode = this.getDefaultNext(xmlNode, this.$isTreeArch); + if (this.$selectTimer.nextNode == this.xmlRoot && !this.renderRoot) + this.$selectTimer.nextNode = null; + } + + //@todo Fix this by putting it after xmlUpdate when its using a timer + var _self = this; + this.$selectTimer.timer = $setTimeout(function(){ + _self.$checkSelection(_self.$selectTimer.nextNode); + _self.$selectTimer.nextNode = null; + }); + } + + + //Set dynamic properties that relate to the changed content + if (actionFeature[action] & 64) { + if (!length) + length = this.xmlRoot.selectNodes(this.each).length; + if (action == "remove") + length--; + if (length != this.length) + this.setProperty("length", length); + } + + + //Let's signal components that are waiting for xml to appear (@todo what about clearing the signalXmlUpdate) + if (this.signalXmlUpdate && actionFeature[action] & 16) { + var uniqueId; + for (uniqueId in this.signalXmlUpdate) { + if (parseInt(uniqueId, 10) != uniqueId) continue; //safari_old stuff + + var o = apf.lookup(uniqueId); + if (!this.selected) continue; + + xmlNode = this.selected.selectSingleNode(o.dataParent.xpath); + if (!xmlNode) continue; + + o.load(xmlNode); + } + } + + this.dispatchEvent("xmlupdate", { + action: action, + xmlNode: startNode, + traverseNode: xmlNode, + result: result, + UndoObj: UndoObj + }); + }; + + /* + * Loop through NodeList of selected Traverse Nodes + * and check if it has representation. If it doesn't + * representation is created via $add(). + */ + this.$addNodes = function(xmlNode, parent, checkChildren, isChild, insertBefore, depth, action) { + + + var htmlNode, lastNode, loopNode; + isChild = (isChild && (this.renderRoot && xmlNode == this.xmlRoot + || this.isTraverseNode(xmlNode))); + var nodes = isChild ? [xmlNode] : this.getTraverseNodes(xmlNode); + /*var loadChildren = nodes.length && this.$bindings["insert"] + ? this.$applyBindRule("insert", xmlNode) + : false; << UNUSED */ + + + var cId, cItem; + if (this.$isTreeArch && this.caching + && (!this.$bindings || !this.$bindings.each || !this.$bindings.each.filter) + && (cItem = this.cache[(cId = xmlNode.getAttribute(apf.xmldb.xmlIdTag))])) { + if (this.$subTreeCacheContext || this.$needsDepth) { + //@todo + //We destroy the current items, because currently we + //don't support multiple treecachecontexts + //and because datagrid needs to redraw depth + this.clearCacheItem(cId); + } + else { + this.$subTreeCacheContext = { + oHtml: cItem, + container: parent, + parentNode: null, + beforeNode: null + }; + + var htmlNode; + while (cItem.childNodes.length) + (parent || this.$container).appendChild(htmlNode = cItem.childNodes[0]); + + return nodes; + } + } + + + if (this.$isTreeArch && depth === null && action == "insert") { + depth = 0, loopNode = xmlNode; + while (loopNode && loopNode != this.xmlRoot) { + depth++; + loopNode = this.getTraverseParent(loopNode); + } + } + + for (var i = 0; i < nodes.length; i++) { + if (nodes[i].nodeType != 1) { + + continue; + } + + if (checkChildren) { + htmlNode = this.$findHtmlNode(nodes[i] + .getAttribute(apf.xmldb.xmlIdTag) + "|" + this.$uniqueId); + } + + if (!htmlNode) { + //Retrieve DataBind ID + var Lid = apf.xmldb.nodeConnect(this.documentId, nodes[i], null, this); + + //Add Children + var beforeNode = isChild + ? insertBefore + : (lastNode ? lastNode.nextSibling : null),//(parent || this.$container).firstChild); + parentNode = this.$add(nodes[i], Lid, isChild ? xmlNode.parentNode : xmlNode, + beforeNode ? parent || this.$container : parent, beforeNode, + (!beforeNode && i == nodes.length - 1), depth, nodes[i + 1], action);//Should use getTraverParent + + //Exit if component tells us its done with rendering + if (parentNode === false) { + //Tag all needed xmlNodes for future reference + // @todo apf3.0 code below looks harmful... hence commented out (Mike) + /*for (var j = i; j < nodes.length; j++) + apf.xmldb.nodeConnect(this.documentId, nodes[j], + null, this);*/ + break; + } + + //Parse Children Recursively -> optimize: don't check children that can't exist + //if(this.$isTreeArch) this.$addNodes(nodes[i], parentNode, checkChildren); + } + + if (checkChildren) + lastNode = htmlNode;// ? htmlNode.parentNode.parentNode : null; + } + + return nodes; + }; + + this.$handleBindingRule = function(value, prop) { + if (!value) + this[prop] = null; + + //@todo apf3.0 fix parsing + if (prop == "each") { + value = value.charAt(0) == "[" && value.charAt(value.length - 1) == "]" + ? value.replace(/^\[|\]$/g, "") + : value; + + if (value.match(/^\w+::/)) { + var model = value.split("::"); //@todo this is all very bad + if (!apf.xPathAxis[model[0]]) { + this.setProperty("model", model[0]); + this.each = model[1]; + } + else + this.each = value; + } + else + this.each = value; + + if (this.each == this.$lastEach) + return; + + this.$lastEach = value; + + if (!this.$model && !this.$initingModel) { + this.$initingModel = true; + this.$setInheritedAttribute("model"); + + return; //@experimental + } + + if (this.$checkLoadQueue() !== false) //@experimental + return; + } + + //@todo apf3.0 find a better heuristic (portal demo) + if (this.xmlRoot && !this.$bindRuleTimer && this.$amlLoaded) { + var _self = this; + apf.queue.add("reload" + this.$uniqueId, function(){ + + _self.reload(); + }); + } + }; + + this.$select = function(o) { + + if (this.renaming) + this.stopRename(null, true); + + + if (!o || !o.style) + return; + return this.$setStyleClass(o, "selected"); + }; + + this.$deselect = function(o) { + + if (this.renaming) { + this.stopRename(null, true); + + if (this.ctrlselect) + return false; + } + + + if (!o) + return; + return this.$setStyleClass(o, "", ["selected", "indicate"]); + }; + + this.$indicate = function(o) { + + if (this.renaming) + this.stopRename(null, true); + + + if (!o) + return; + return this.$setStyleClass(o, "indicate"); + }; + + this.$deindicate = function(o) { + + if (this.renaming) + this.stopRename(null, true); + + + if (!o) + return; + return this.$setStyleClass(o, "", ["indicate"]); + }; + + + /** + * @attribute {String} each Sets or gets the XPath statement that determines which + * {@link term.datanode data nodes} are rendered by this element (also known + * as {@link term.eachnode each nodes}. + * + * + * #### Example + * + * ```xml + * Country + * + * + * + * + * + * USA + * Great Brittain + * The Netherlands + * ... + * + * + * ``` + * + * + */ + this.$propHandlers["each"] = + + /** + * @attribute {String} caption Sets or gets the text displayed on the item. + * + * #### Example + * + * ```xml + * + * ``` + */ + this.$propHandlers["caption"] = + + /** + * @attribute {String} eachvalue Sets or gets the {@link term.expression} + * that determines the value for each data nodes in the dataset of the element. + * + * #### Example + * + * ```xml + * + * ``` + * + */ + this.$propHandlers["eachvalue"] = + + /** + * @attribute {String} icon Sets or gets the XPath statement that determines from + * which XML node the icon URL is retrieved. + * + * #### Example + * + * ```xml + * + * ``` + */ + this.$propHandlers["icon"] = + + /** + * @attribute {String} tooltip Sets or gets the XPath statement that determines from + * which XML node the tooltip text is retrieved. + * + * #### Example + * + * ```xml + * + * ``` + */ + this.$propHandlers["tooltip"] = this.$handleBindingRule; + + + /** + * @attribute {String} sort Sets or gets the XPath statement that selects the sortable value. + * + * #### Example + * + * ```xml + * + * ``` + * + */ + this.$propHandlers["sort"] = function(value) { + if (value) { + this.$sort = new apf.Sort() + this.$sort.set({ + getValue: apf.lm.compile(value) + }); + } + else { + this.$sort = null; + } + } + + + /** + * @attribute {String} match Sets or gets the XPath statement that determines whether + * this node is selectable. + * + * #### Example + * + * ```xml + * + * ``` + * + */ + //this.$propHandlers["select"] = + +}).call(apf.MultiselectBinding.prototype = new apf.DataBinding()); + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * The baseclass for all standard data binding rules. + * + * @class apf.StandardBinding + * @private + * @baseclass + * @inherits apf.DataBinding + */ +apf.StandardBinding = function(){ + this.$init(true); + + + if (apf.Validation) + this.implement(apf.Validation); + + + if (!this.setQueryValue) + this.implement(apf.DataBinding); + + if (!this.defaultValue) //@todo please use this in a sentence + this.defaultValue = ""; + + /** + * Load XML into this element + * @private + */ + this.$load = function(xmlNode) { + //Add listener to XMLRoot Node + apf.xmldb.addNodeListener(xmlNode, this); + //Set Properties + + + var b, lrule, rule, bRules, bRule, value; + if (b = this.$bindings) { + for (rule in b) { + lrule = rule.toLowerCase(); + if (this.$supportedProperties.indexOf(lrule) > -1) { + bRule = (bRules = b[lrule]).length == 1 + ? bRules[0] + : this.$getBindRule(lrule, xmlNode); + + value = bRule.value || bRule.match; + + + //Remove any bounds if relevant + this.$clearDynamicProperty(lrule); + + if (value.indexOf("{") > -1 || value.indexOf("[") > -1) + this.$setDynamicProperty(lrule, value); + else + + if (this.setProperty) + this.setProperty(lrule, value, true); + } + } + } + + + //Think should be set in the event by the Validation Class + if (this.errBox && this.isValid && this.isValid()) + this.clearError(); + }; + + /** + * Set xml based properties of this element + * @private + */ + this.$xmlUpdate = function(action, xmlNode, listenNode, UndoObj) { + //Clear this component if some ancestor has been detached + if (action == "redo-remove") { + var retreatToListenMode = false, model = this.getModel(true); + if (model) { + var xpath = model.getXpathByAmlNode(this); + if (xpath) { + xmlNode = model.data.selectSingleNode(xpath); + if (xmlNode != this.xmlRoot) + retreatToListenMode = true; + } + } + + if (retreatToListenMode || this.xmlRoot == xmlNode) { + + + //Set Component in listening state untill data becomes available again. + return model.$waitForXml(this); + } + } + + //Action Tracker Support + if (UndoObj && !UndoObj.xmlNode) + UndoObj.xmlNode = this.xmlRoot; + + //Set Properties + + + var b, lrule, rule, bRules, bRule, value; + if (b = this.$bindings) { + for (rule in b) { + lrule = rule.toLowerCase(); + if (this.$supportedProperties.indexOf(lrule) > -1) { + bRule = (bRules = b[lrule]).length == 1 + ? bRules[0] + : this.$getBindRule(lrule, xmlNode); + + value = bRule.value || bRule.match; + + + //Remove any bounds if relevant + this.$clearDynamicProperty(lrule); + + if (value.indexOf("{") > -1 || value.indexOf("[") > -1) + this.$setDynamicProperty(lrule, value); + else + + if (this.setProperty) + this.setProperty(lrule, value); + } + } + } + + + //@todo Think should be set in the event by the Validation Class + if (this.errBox && this.isValid && this.isValid()) + this.clearError(); + + this.dispatchEvent("xmlupdate", { + action: action, + xmlNode: xmlNode, + UndoObj: UndoObj + }); + }; + + //@todo apf3.0 this is wrong + /** + * @event $clear Clears the data loaded into this element resetting it's value. + */ + this.addEventListener("$clear", function(nomsg, do_event) { + if (this.$propHandlers && this.$propHandlers["value"]) { + this.value = -99999; //force resetting + this.$propHandlers["value"].call(this, ""); + } + }); +}; +apf.StandardBinding.prototype = new apf.DataBinding(); + +apf.Init.run("standardbinding"); + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + +apf.__MULTISELECT__ = 1 << 8; + + + +/** + * All elements inheriting from this {@link term.baseclass baseclass} have selection features. This includes handling + * for multiselect and several keyboard based selection interaction. It also + * takes care of {@link term.caret caret} handling when multiselect is enabled. Furthermore features + * for dealing with multinode component are included like adding and removing + * {@link term.datanode data nodes}. + * + * #### Example + * + * In this example the tree contains nodes that have a disabled flag set. These nodes cannot be selected. + * + * ```xml + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * ``` + * + * #### Example + * + * ```xml + * + * + * + * + * + * + * + * + * red + * green + * blue + * + * + * + * ``` + * + * @class apf.MultiSelect + * @baseclass + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.5 + * + * @inherits apf.MultiselectBinding + * + */ +/** + * + * @binding select Determines whether the {@link term.eachnode each node} can be selected. + * + */ + /** + * + * * @binding value Determines the way the value for the element is retrieved + * from the selected node. The `apf.MultiSelect.value` property contains this value. + * + */ +apf.MultiSelect = function(){ + this.$init(function(){ + this.$valueList = []; + this.$selectedList = []; + }); +}; + +//@todo investigate if selectedList can be deprecated +(function() { + this.$regbase = this.$regbase|apf.__MULTISELECT__; + + // *** Properties *** // + + // @todo Doc is that right? + /** + * The last selected item of this element. + * @type {XMLElement} + */ + this.sellength = 0; + this.selected = null; + this.$selected = null; + + /** + * The XML element that has the {@link term.caret caret}. + * @type {XMLElement} + */ + this.caret = null; + this.$caret = null; + + /** + * Specifies whether to use a {@link term.caret caret} in the interaction of this element. + * @type {Boolean} + */ + this.useindicator = true; + + + + /** + * Removes a {@link term.datanode data node} from the data of this element. + * + * #### Example + * + * A simple list showing products. This list is used in all the following examples. + * + * ```xml + * + * + * + * + * [@type].png + * + * + * + * + * + * + * + * + * + * + * + * + * ``` + * + * #### Example + * + * This example selects a product by its value and then removes the selection. + * + * ```xml + * + * ``` + * + * #### Example + * + * This example gets a product by its value and then removes it. + * + * ```xml + * + * var xmlNode = myList.findXmlNodeByValue("product20"); + * myList.remove(xmlNode); + * + * ``` + * + * #### Example + * + * This example retrieves all nodes from the list. All items with a length + * greater than 10 are singled out and removed. + * + * ```xml + * 10) + * removeList.push(list[i]); + * } + * myList.remove(removeList); + * } + * ]]> + * ``` + * + * #### Remarks + * + * Another way to trigger this method is by using the action attribute on a + * button. + * + * ```xml + * Remove item + * ``` + * + * Using the action methodology, you can let the original data source + * (usually the server) know that the user removed an item: + * + * ```xml + * + * + * + * + * ``` + * + * For undo, this action should be extended and the server should maintain a + * copy of the deleted item. + * + * ```xml + * + * + * + * + * Remove item + * + * ``` + * + * @action + * @param {NodeList | XMLElement} [nodeList] The {@link term.datanode data node}(s) to be removed. If none are specified, the current selection is removed. + * + * @return {Boolean} Indicates if the removal succeeded + */ + this.remove = function(nodeList) { + //Use the current selection if no xmlNode is defined + if (!nodeList) + nodeList = this.$valueList; + + //If we're an xml node let's convert + if (nodeList.nodeType) + nodeList = [nodeList]; + + //If there is no selection we'll exit, nothing to do + if (!nodeList || !nodeList.length) + return; + + + + var changes = []; + for (var i = 0; i < nodeList.length; i++) { + changes.push({ + action: "removeNode", + args: [nodeList[i]] + }); + } + + if (this.$actions["removegroup"]) + return this.$executeAction("multicall", changes, "removegroup", nodeList[0]); + else { + return this.$executeAction("multicall", changes, "remove", + nodeList[0], null, null, nodeList.length > 1 ? nodeList : null); + } + }; + + /** + * Adds a {@link term.datanode data node} to the data of this element. + * + * #### Example + * + * A simple list showing products. This list is used in all following examples. + * + * ```xml + * + * + * + * + * [@type].png + * + * + * + * + * + * + * + * + * + * + * + * + * ``` + * + * #### Example + * + * This example adds a product to this element selection. + * + * ```xml + * '); + * } + * ]]> + * ``` + * + * #### Example + * + * This example copys the selected product, changes its name, and then + * adds it. After selecting the new node, the user is offered a rename input + * box. + * + * ```xml + * + * ``` + * + * #### Remarks + * Another way to trigger this method is by using the action attribute on a + * button. + * + * ```xml + * + * + * + * + * + * + * + * + * + * Add new product + * ``` + * + * Using the action methodology you can let the original data source (usually the server) know that the user added an item. + * + * ```xml + * + * ``` + * + * For undo, this action should be extended as follows. + * + * ```xml + * + * + * + * + * + * + * + * + * + * Add new product + * + * ``` + * + * In some cases the server needs to create the new product before its + * added. This is done as follows. + * + * ```xml + * + * ``` + * Alternatively the template for the addition can be provided as a child of + * the action rule. + * ``` + * + * + * + * ``` + * + * @action + * @param {XMLElement} [xmlNode] The {@link term.datanode data node} which is added. If none is specified the action will use the action rule to try to retrieve a new node to add + * @param {XMLElement} [pNode] The parent node of the added {@link term.datanode data node} + * @param {XMLElement} [beforeNode] The position where the XML element should be inserted + * @return {XMLElement} The added {@link term.datanode data node} or false on failure + */ + this.add = function(xmlNode, pNode, beforeNode, userCallback) { + var rule; + + if (this.$actions) { + if (xmlNode && xmlNode.nodeType) + rule = this.$actions.getRule("add", xmlNode); + else if (typeof xmlNode == "string") { + if (xmlNode.trim().charAt(0) == "<") { + xmlNode = apf.getXml(xmlNode); + rule = this.$actions.getRule("add", xmlNode); + } + else { + var rules = this.$actions["add"]; + for (var i = 0, l = rules.length; i < l; i++) { + if (rules[i].getAttribute("type") == xmlNode) { + xmlNode = null; + rule = rules[i]; + break; + } + } + } + } + + if (!rule) + rule = (this.$actions["add"] || {})[0]; + } + else + rule = null; + + + + var refNode = this.$isTreeArch ? this.selected || this.xmlRoot : this.xmlRoot, + amlNode = this, + callback = function(addXmlNode, state, extra) { + if (state != apf.SUCCESS) { + var oError; + + oError = new Error(apf.formatErrorString(1032, amlNode, + "Loading xml data", + "Could not add data for control " + amlNode.name + + "[" + amlNode.tagName + "] \nUrl: " + extra.url + + "\nInfo: " + extra.message + "\n\n" + xmlNode)); + + if (extra.tpModule.retryTimeout(extra, state, amlNode, oError) === true) + return true; + + throw oError; + } + + /*if (apf.supportNamespaces && node.namespaceURI == apf.ns.xhtml) { + node = apf.getXml(node.xml.replace(/xmlns\=\"[^"]*\"/g, "")); + //@todo import here for webkit? + }*/ + + if (typeof addXmlNode != "object") + addXmlNode = apf.getXmlDom(addXmlNode).documentElement; + if (addXmlNode.getAttribute(apf.xmldb.xmlIdTag)) + addXmlNode.setAttribute(apf.xmldb.xmlIdTag, ""); + + var actionNode = amlNode.$actions && + amlNode.$actions.getRule("add", amlNode.$isTreeArch + ? amlNode.selected + : amlNode.xmlRoot); + if (!pNode) { + if (actionNode && actionNode.parent) { + pNode = (actionNode.cparent + || actionNode.compile("parent", { + xpathmode: 2, + injectself: true + }))(amlNode.$isTreeArch + ? amlNode.selected || amlNode.xmlRoot + : amlNode.xmlRoot); + } + else { + pNode = amlNode.$isTreeArch + ? amlNode.selected || amlNode.xmlRoot + : amlNode.xmlRoot + } + } + + if (!pNode) + pNode = amlNode.xmlRoot; + + //Safari issue not auto importing nodes: + if (apf.isWebkit && pNode.ownerDocument != addXmlNode.ownerDocument) + addXmlNode = pNode.ownerDocument.importNode(addXmlNode, true); + + + + if (amlNode.$executeAction("appendChild", + [pNode, addXmlNode, beforeNode], "add", addXmlNode) !== false + && amlNode.autoselect) + amlNode.select(addXmlNode); + + if (userCallback) + userCallback.call(amlNode, addXmlNode); + + return addXmlNode; + }; + + if (xmlNode) + return callback(xmlNode, apf.SUCCESS); + else { + if (rule.get) + return apf.getData(rule.get, {xmlNode: refNode, callback: callback}) + else { + + } + } + + return addXmlNode; + }; + + if (!this.setValue) { + /** + * Sets the value of this element. The value + * corresponds to an item in the list of loaded {@link term.datanode data nodes}. This + * element will receive the selection. If no {@link term.datanode data node} is found, the + * selection is cleared. + * + * @param {String} value The new value for this element. + * @see apf.MultiSelect.getValue + */ + this.setValue = function(value, disable_event) { + // @todo apf3.0 what does noEvent do? in this scope it's useless and + // doesn't improve codeflow with a global lookup and assignment + noEvent = disable_event; + this.setProperty("value", value, false, true); + noEvent = false; + }; + } + + /** + * Retrieves an {@link term.datanode data node} that has a value that corresponds to the + * string that is searched on. + * @param {String} value The value to match. + * @returns {XMLNode} The found node, or `false` + */ + this.findXmlNodeByValue = function(value) { + var nodes = this.getTraverseNodes(), + bindSet = this.$attrBindings["eachvalue"] + && "eachvalue" || this.$bindings["value"] + && "value" || this.$hasBindRule("caption") && "caption"; + + if (!bindSet) + return false; + + for (var i = 0; i < nodes.length; i++) { + if (this.$applyBindRule(bindSet, nodes[i]) == value) + return nodes[i]; + } + }; + + if (!this.getValue) { + /** + * Retrieves the value of this element. This is the value of the + * first selected {@link term.datanode data node}. + * + */ + this.getValue = function(xmlNode, noError) { + return this.value; + /* + if (!this.bindingRules && !this.caption) + return false; + + + + return this.$applyBindRule(this.$mainBind, xmlNode || this.selected, null, true) + || this.$applyBindRule("caption", xmlNode || this.selected, null, true); + */ + }; + } + + /** + * Select the current selection...again. + * + */ + this.reselect = function(){ // @todo Add support for multiselect + if (this.selected) this.select(this.selected, null, this.ctrlselect, + null, true);//no support for multiselect currently. + }; + + /** + * @event beforeselect Fires before a {@link apf.MultiSelect.select selection} is made + * @param {Object} e The standard event object. It contains the following properties: + * - `selected` ([[XMLElement]]): The {@link term.datanode data node} that will be selected + * - `selection` ([[Array]]): An array of {@link term.datanode data nodes} that will be selected + * - `htmlNode` ([[HTMLElement]]): The HTML element that visually represents the {@link term.datanode data node} + */ + /** + * @event afterselect Fires after a {@link apf.MultiSelect.select selection} is made + * @param {Object} e The standard event object. It contains the following properties: + * - `selected` ([[XMLElement]]): the {@link term.datanode data node} that was selected + * - `selection` ([[Array]](): an array of {@link term.datanode data node} that are selected + * - `htmlNode` ([[HTMLElement]](): the HTML element that visually represents the {@link term.datanode data node} + */ + /** + * Selects a single, or set, of {@link term.eachnode each nodes}. + * The selection can be visually represented in this element. + * + * @param {Mixed} xmlNode The identifier to determine the selection. It can be one of the following values: + * - ([[XMLElement]]): The {@link term.datanode data node} to be used in the selection as a start/end point or to toggle the selection on the node. + * - ([[HTMLElement]]): The HTML element node used as visual representation of {@link term.datanode data node}. + * Used to determine the {@link term.datanode data node} for selection. + * - ([[String]]): The value of the {@link term.datanode data node} to be selected. + * @param {Boolean} [ctrlKey] Indicates whether the [[keys: Ctrl]] key was pressed + * @param {Boolean} [shiftKey] Indicates whether the [[keys: Shift]] key was pressed + * @param {Boolean} [fakeselect] Indicates whether only visually a selection is made + * @param {Boolean} [force] Indicates whether reselect is forced + * @param {Boolean} [noEvent] Indicates whether to not call any event + * @return {Boolean} Indicates whether the selection could be made + * + */ + this.select = function(xmlNode, ctrlKey, shiftKey, fakeselect, force, noEvent, userAction) { + if (!this.selectable || userAction && this.disabled) + return; + + if (parseInt(fakeselect) == fakeselect) { + //Don't select on context menu + if (fakeselect == 2) { + fakeselect = true; + userAction = true; + } + else { + fakeselect = false; + userAction = true; + } + } + + if (this.$skipSelect) { + this.$skipSelect = false; + return; + } + + if (this.ctrlselect && !shiftKey) + ctrlKey = true; + + if (!this.multiselect) + ctrlKey = shiftKey = false; + + // Selection buffering (for async compatibility) + if (!this.xmlRoot) { + if (!this.$buffered) { + var f; + this.addEventListener("afterload", f = function(){ + this.select.apply(this, this.$buffered); + this.removeEventListener("afterload", f); + delete this.$buffered; + }); + } + + this.$buffered = Array.prototype.slice.call(arguments); + return; + } + + var htmlNode; + + // *** Type Detection *** // + if (!xmlNode) { + + + return false; + } + + if (typeof xmlNode != "object") { + var str = xmlNode; xmlNode = null; + if (typeof xmlNode == "string") + xmlNode = apf.xmldb.getNodeById(str); + + //Select based on the value of the xml node + if (!xmlNode) { + xmlNode = this.findXmlNodeByValue(str); + if (!xmlNode) { + this.clearSelection(noEvent); + return; + } + } + } + + if (!(typeof (xmlNode.style || "") == "object")) { + htmlNode = this.$findHtmlNode(xmlNode.getAttribute( + apf.xmldb.xmlIdTag) + "|" + this.$uniqueId); + } + else { + var id = (htmlNode = xmlNode).getAttribute(apf.xmldb.htmlIdTag); + while (!id && htmlNode.parentNode) + id = (htmlNode = htmlNode.parentNode).getAttribute( + apf.xmldb.htmlIdTag); + + xmlNode = apf.xmldb.getNodeById(id);//, this.xmlRoot); + } + + if (!shiftKey && !ctrlKey && !force && !this.reselectable + && this.$valueList.length <= 1 && this.$valueList.indexOf(xmlNode) > -1) + return; + + if (this.dispatchEvent('beforeselect', { + selected: xmlNode, + htmlNode: htmlNode, + ctrlKey: ctrlKey, + shiftKey: shiftKey, + force: force, + captureOnly: noEvent + }) === false) + return false; + + // *** Selection *** // + + var lastIndicator = this.caret; + this.caret = xmlNode; + + //Multiselect with SHIFT Key. + if (shiftKey) { + var range = this.$calcSelectRange( + this.$valueList[0] || lastIndicator, xmlNode); + + if (this.$caret) + this.$deindicate(this.$caret); + + this.selectList(range); + + this.$selected = + this.$caret = this.$indicate(htmlNode); + } + else if (ctrlKey) { //Multiselect with CTRL Key. + //Node will be unselected + if (this.$valueList.contains(xmlNode)) { + if (this.selected == xmlNode) { + this.$deselect(this.$findHtmlNode(this.selected.getAttribute( + apf.xmldb.xmlIdTag) + "|" + this.$uniqueId)); + + this.$deindicate(this.$caret); + + if (this.$valueList.length && !fakeselect) { + //this.$selected = this.$selectedList[0]; + this.selected = this.$valueList[0]; + } + } + else + this.$deselect(htmlNode, xmlNode); + + if (!fakeselect) { + this.$selectedList.remove(htmlNode); + this.$valueList.remove(xmlNode); + } + + if (htmlNode != this.$caret) + this.$deindicate(this.$caret); + + this.$selected = + this.$caret = this.$indicate(htmlNode); + } + // Node will be selected + else { + if (this.$caret) + this.$deindicate(this.$caret); + this.$caret = this.$indicate(htmlNode, xmlNode); + + this.$selected = this.$select(htmlNode, xmlNode); + this.selected = xmlNode; + + if (!fakeselect) { + this.$selectedList.push(htmlNode); + this.$valueList.push(xmlNode); + } + } + } + else if (fakeselect && htmlNode && this.$selectedList.contains(htmlNode)) {//Return if selected Node is htmlNode during a fake select + return; + } + else { //Normal Selection + //htmlNode && this.$selected == htmlNode && this.$valueList.length <= 1 && this.$selectedList.contains(htmlNode) + if (this.$selected) + this.$deselect(this.$selected); + if (this.$caret) + this.$deindicate(this.$caret); + if (this.selected) + this.clearSelection(true); + + this.$caret = this.$indicate(htmlNode, xmlNode); + this.$selected = this.$select(htmlNode, xmlNode); + this.selected = xmlNode; + + this.$selectedList.push(htmlNode); + this.$valueList.push(xmlNode); + } + + if (this.delayedselect && (typeof ctrlKey == "boolean")){ + var _self = this; + $setTimeout(function(){ + if (_self.selected == xmlNode) + _self.dispatchEvent("afterselect", { + selection: _self.$valueList, + selected: xmlNode, + caret: _self.caret, + captureOnly: noEvent + }); + }, 10); + } + else { + this.dispatchEvent("afterselect", { + selection: this.$valueList, + selected: xmlNode, + caret: this.caret, + captureOnly: noEvent + }); + } + + return true; + }; + + /** + * @event beforechoose Fires before a choice is made. + * @param {Object} e The standard event object. It contains the following properties: + * - `xmlNode` ([[XMLElement]]): The {@link term.datanode data node} that was choosen + * + */ + /** + * @event afterchoose Fires after a choice is made. + * @param {Object} e The standard event object. It contains the following properties: + * - `xmlNode` ([[XMLElement]]): The {@link term.datanode data node} that was choosen + */ + /** + * Chooses a selected item. This is done by double clicking on the item or + * pressing the Enter key. + * + * @param {Mixed} xmlNode The identifier to determine the selection. It can be one of the following values: + * - [[XMLElement]]: The {@link term.datanode data node} to be choosen + * - [[HTMLElement]]: The HTML element node used as visual representation of {@link term.datanode data node} + * Used to determine the {@link term.datanode data node} + * - [[String]] : The value of the {@link term.datanode data node} to be choosen + * + */ + this.choose = function(xmlNode, userAction) { + if (!this.selectable || userAction && this.disabled) return; + + if (this.dispatchEvent("beforechoose", {xmlNode : xmlNode}) === false) + return false; + + if (xmlNode && !(typeof (xmlNode.style || "") == "object")) + this.select(xmlNode); + + + if (this.hasFeature(apf.__DATABINDING__) + && this.dispatchEvent("afterchoose", {xmlNode : this.selected}) !== false) + this.setProperty("chosen", this.selected); + + }; + + /* + * Removes the selection of one or more selected nodes. + * + * @param {Boolean} [noEvent] Indicates whether or not to call any events + */ + // @todo Doc + this.clearSelection = function(noEvent, userAction) { + if (!this.selectable || userAction && this.disabled || !this.$valueList.length) + return; + + if (!noEvent) { + if (this.dispatchEvent("beforeselect", { + selection: [], + selected: null, + caret: this.caret + }) === false) + return false; + } + + //Deselect html nodes + var htmlNode; + for (var i = this.$valueList.length - 1; i >= 0; i--) { + htmlNode = this.$findHtmlNode(this.$valueList[i].getAttribute( + apf.xmldb.xmlIdTag) + "|" + this.$uniqueId); + this.$deselect(htmlNode); + } + + //Reset internal variables + this.$selectedList.length = 0; + this.$valueList.length = 0; + this.$selected = + this.selected = null; + + //Redraw indicator + if (this.caret) { + htmlNode = this.$findHtmlNode(this.caret.getAttribute( + apf.xmldb.xmlIdTag) + "|" + this.$uniqueId); + + this.$caret = this.$indicate(htmlNode); + } + + if (!noEvent) { + this.dispatchEvent("afterselect", { + selection: this.$valueList, + selected: null, + caret: this.caret + }); + } + }; + + /* + * Selects a set of items + * + * @param {Array} xmlNodeList the {@link term.datanode data nodes} that will be selected. + */ + //@todo Doc I think there are missing events here? + this.selectList = function(xmlNodeList, noEvent, selected, userAction) { + if (!this.selectable || userAction && this.disabled) return; + + if (this.dispatchEvent("beforeselect", { + selection: xmlNodeList, + selected: selected || xmlNodeList[0], + caret: this.caret, + captureOnly: noEvent + }) === false) + return false; + + this.clearSelection(true); + + for (var sel, i = 0; i < xmlNodeList.length; i++) { + //@todo fix select state in unserialize after removing + if (!xmlNodeList[i] || xmlNodeList[i].nodeType != 1) continue; + var htmlNode, + xmlNode = xmlNodeList[i]; + + //Type Detection + if (typeof xmlNode != "object") + xmlNode = apf.xmldb.getNodeById(xmlNode); + if (!(typeof (xmlNode.style || "") == "object")) + htmlNode = this.$pHtmlDoc.getElementById(xmlNode.getAttribute( + apf.xmldb.xmlIdTag) + "|" + this.$uniqueId); + else { + htmlNode = xmlNode; + xmlNode = apf.xmldb.getNodeById(htmlNode.getAttribute( + apf.xmldb.htmlIdTag)); + } + + if (!xmlNode) { + + continue; + } + + //Select Node + if (htmlNode) { + if (!sel && selected == htmlNode) + sel = htmlNode; + + this.$select(htmlNode, xmlNode); + this.$selectedList.push(htmlNode); + } + this.$valueList.push(xmlNode); + } + + this.$selected = sel || this.$selectedList[0]; + this.selected = selected || this.$valueList[0]; + + this.dispatchEvent("afterselect", { + selection: this.$valueList, + selected: this.selected, + caret: this.caret, + captureOnly: noEvent + }); + }; + + /** + * @event indicate Fires when an item becomes the indicator. + */ + + /** + * Sets the {@link term.caret caret} on an item to indicate to the user that the keyboard + * actions are done relevant to that item. Using the keyboard, + * a user can change the position of the indicator using the [[keys: Ctrl]] and arrow + * keys while not making a selection. When making a selection with the mouse + * or keyboard, the indicator is always set to the selected node. Unlike a + * selection there can be only one indicator item. + * + * @param {Mixed} xmlNode The identifier to determine the indicator. Its possible values include: + * - {XMLElement} The {@link term.datanode data node} to be set as indicator. + * - {HTMLElement} The HTML element node used as visual representation of + * {@link term.datanode data node}. Used to determine the {@link term.datanode data node}. + * - {String} The value of the {@link term.datanode data node} to be set as an indicator. + */ + this.setCaret = function(xmlNode) { + if (!xmlNode) { + if (this.$caret) + this.$deindicate(this.$caret); + this.caret = + this.$caret = null; + return; + } + + // *** Type Detection *** // + var htmlNode; + if (typeof xmlNode != "object") + xmlNode = apf.xmldb.getNodeById(xmlNode); + if (!(typeof (xmlNode.style || "") == "object")) { + htmlNode = this.$findHtmlNode(xmlNode.getAttribute( + apf.xmldb.xmlIdTag) + "|" + this.$uniqueId); + } + else { + var id = (htmlNode = xmlNode).getAttribute(apf.xmldb.htmlIdTag); + while (!id && htmlNode.parentNode && htmlNode.parentNode.nodeType == 1) + id = (htmlNode = htmlNode.parentNode).getAttribute( + apf.xmldb.htmlIdTag); + if (!id) alert(this.$int.outerHTML); + + xmlNode = apf.xmldb.getNodeById(id); + } + + if (this.$caret) { + //this.$deindicate(this.$findHtmlNode(this.caret.getAttribute( + //apf.xmldb.xmlIdTag) + "|" + this.$uniqueId)); + this.$deindicate(this.$caret); + } + + this.$caret = this.$indicate(htmlNode); + this.setProperty("caret", this.caret = xmlNode); + }; + + /* + * @private + */ + this.$setTempSelected = function(xmlNode, ctrlKey, shiftKey, down) { + clearTimeout(this.timer); + + if (this.$bindings.selectable) { + while (xmlNode && !this.$getDataNode("selectable", xmlNode)) { + xmlNode = this.getNextTraverseSelected(xmlNode, !down); + } + if (!xmlNode) return; + } + + if (!this.multiselect) + ctrlKey = shiftKey = false; + + if (ctrlKey || this.ctrlselect) { + if (this.$tempsel) { + this.select(this.$tempsel); + this.$tempsel = null; + } + + this.setCaret(xmlNode); + } + else if (shiftKey) { + if (this.$tempsel) { + this.$selectTemp(); + this.$deselect(this.$tempsel); + this.$tempsel = null; + } + + this.select(xmlNode, null, shiftKey); + } + else if (!this.bufferselect || this.$valueList.length > 1) { + this.select(xmlNode); + } + else { + var id = apf.xmldb.getID(xmlNode, this); + + this.$deselect(this.$tempsel || this.$selected); + this.$deindicate(this.$tempsel || this.$caret); + this.$tempsel = this.$indicate(document.getElementById(id)); + this.$select(this.$tempsel); + + var _self = this; + this.timer = $setTimeout(function(){ + _self.$selectTemp(); + }, 400); + } + }; + + /* + * @private + */ + this.$selectTemp = function(){ + if (!this.$tempsel) + return; + + clearTimeout(this.timer); + this.select(this.$tempsel); + + this.$tempsel = null; + this.timer = null; + }; + + /** + * Selects all the {@link term.eachnode each nodes} of this element + * + */ + this.selectAll = function(userAction) { + if (!this.multiselect || !this.selectable + || userAction && this.disabled || !this.xmlRoot) + return; + + var nodes = this.$isTreeArch + ? this.xmlRoot.selectNodes(".//" + + this.each.split("|").join("|.//")) + : this.xmlRoot.selectNodes(this.each); + + this.selectList(nodes); + }; + + /** + * Retrieves an Array or a document fragment containing all the selected + * {@link term.datanode data nodes} from this element. + * + * @param {Boolean} [xmldoc] Specifies whether the method should return a document fragment. + * @return {Mixed} The selection of this element. + */ + this.getSelection = function(xmldoc) { + var i, r; + if (xmldoc) { + r = this.xmlRoot + ? this.xmlRoot.ownerDocument.createDocumentFragment() + : apf.getXmlDom().createDocumentFragment(); + for (i = 0; i < this.$valueList.length; i++) + apf.xmldb.cleanNode(r.appendChild( + this.$valueList[i].cloneNode(true))); + } + else { + for (r = [], i = 0; i < this.$valueList.length; i++) + r.push(this.$valueList[i]); + } + + return r; + }; + + this.$getSelection = function(htmlNodes) { + return htmlNodes ? this.$selectedList : this.$valueList; + }; + + /** + * Selects the next {@link term.datanode data node} to be selected. + * + * @param {XMLElement} xmlNode The context {@link term.datanode data node}. + * @param {Boolean} [isTree] If `true`, indicates that this node is a tree, and should select children + */ + this.defaultSelectNext = function(xmlNode, isTree) { + var next = this.getNextTraverseSelected(xmlNode); + //if(!next && xmlNode == this.xmlRoot) return; + + //@todo Why not use this.$isTreeArch ?? + if (next || !isTree) + this.select(next ? next : this.getTraverseParent(xmlNode)); + else + this.clearSelection(true); + }; + + /** + * Selects the next {@link term.datanode data node} when available. + */ + this.selectNext = function(){ + var xmlNode = this.getNextTraverse(); + if (xmlNode) + this.select(xmlNode); + }; + + /** + * Selects the previous {@link term.datanode data node} when available. + */ + this.selectPrevious = function(){ + var xmlNode = this.getNextTraverse(null, -1); + if (xmlNode) + this.select(xmlNode); + }; + + /* + * @private + */ + this.getDefaultNext = function(xmlNode, isTree){ //@todo why is isTree an argument + var next = this.getNextTraverseSelected(xmlNode); + //if(!next && xmlNode == this.xmlRoot) return; + + return (next && next != xmlNode) + ? next + : (isTree + ? this.getTraverseParent(xmlNode) + : null); //this.getFirstTraverseNode() + }; + + /** + * Determines whether a node is selected. + * + * @param {XMLElement} xmlNode The {@link term.datanode data node} to be checked + * @return {Boolean} Identifies if the element is selected + */ + this.isSelected = function(xmlNode) { + if (!xmlNode) return false; + + for (var i = 0; i < this.$valueList.length; i++) { + if (this.$valueList[i] == xmlNode) + return this.$valueList.length; + } + + return false; + }; + + /* + * This function checks whether the current selection is still correct. + * Selection can become invalid when updates to the underlying data + * happen. For instance when a selected node is removed. + */ + this.$checkSelection = function(nextNode) { + if (this.$valueList.length > 1) { + //Fix selection if needed + for (var lst = [], i = 0, l = this.$valueList.length; i < l; i++) { + if (apf.isChildOf(this.xmlRoot, this.$valueList[i])) + lst.push(this.$valueList[i]); + } + + if (lst.length > 1) { + this.selectList(lst); + if (this.caret + && !apf.isChildOf(this.xmlRoot, this.caret)) { + this.setCaret(nextNode || this.selected); + } + return; + } + else if (lst.length) { + //this.clearSelection(true); //@todo noEvents here?? + nextNode = lst[0]; + } + } + + if (!nextNode) { + if (this.selected + && !apf.isChildOf(this.xmlRoot, this.selected)) { + nextNode = this.getFirstTraverseNode(); + } + else if (this.selected && this.caret + && !apf.isChildOf(this.xmlRoot, this.caret)) { + this.setCaret(this.selected); + } + else if (!this.selected) { + nextNode = this.xmlRoot + ? this.getFirstTraverseNode() + : null; + } + else { + return; //Nothing to do + } + } + + if (nextNode) { + if (this.autoselect) { + this.select(nextNode); + } + else { + this.clearSelection(); + this.setCaret(nextNode); + } + } + else + this.clearSelection(); + + //if(action == "synchronize" && this.autoselect) this.reselect(); + }; + + /** + * @attribute {Boolean} [multiselect] Sets or gets whether the user may select multiple items. Default is `true, but `false` for dropdown. + */ + /** + * @attribute {Boolean} [autoselect] Sets or gets whether a selection is made after data is loaded. Default is `true`, but `false` for dropdown. When the string 'all' is set, all {@link term.datanode data nodes} are selected. + */ + /** + * @attribute {Boolean} [selectable] Sets or gets whether the {@link term.datanode data nodes} of this element can be selected. Default is `true`. + */ + /** + * @attribute {Boolean} [ctrlselect] Sets or gets whether a selection is made as if the user is holding the [[keys: Ctrl]] key. When set to `true` each mouse selection will add to the current selection. Selecting an already selected element will deselect it. + */ + /** + * @attribute {Boolean} [allowdeselect] Sets or gets whether the user can remove the selection of this element. When set to `true` it is possible for this element to have no selected {@link term.datanode data node}. + */ + /** + * @attribute {Boolean} [reselectable] Sets or gets whether selected nodes can be selected again, and the selection events are called again. Default is `false`. When set to `false` a selected {@link term.datanode data node} cannot be selected again. + */ + /** + * @attribute {String} [default] Sets or gets the value that this component has when no selection is made. + */ + /** + * @attribute {String} [eachvalue] Sets or gets the {@link term.expression expression} that determines the value for each {@link term.datanode data nodes} in the dataset of the element. + * + */ + this.selectable = true; + if (typeof this.ctrlselect == "undefined") + this.ctrlselect = false; + if (typeof this.multiselect == "undefined") + this.multiselect = true; + if (typeof this.autoselect == "undefined") + this.autoselect = true; + if (typeof this.delayedselect == "undefined") + this.delayedselect = true; + if (typeof this.allowdeselect == "undefined") + this.allowdeselect = true; + this.reselectable = false; + + this.$booleanProperties["selectable"] = true; + //this.$booleanProperties["ctrlselect"] = true; + this.$booleanProperties["multiselect"] = true; + this.$booleanProperties["autoselect"] = true; + this.$booleanProperties["delayedselect"] = true; + this.$booleanProperties["allowdeselect"] = true; + this.$booleanProperties["reselectable"] = true; + + this.$supportedProperties.push("selectable", "ctrlselect", "multiselect", + "autoselect", "delayedselect", "allowdeselect", "reselectable", + "selection", "selected", "default", "value", "caret"); + + /** + * @attribute {String} [value] Sets or gets the value of the element that is selected. + * + */ + //@todo add check here + this.$propHandlers["value"] = function(value) { + if (this.$lastValue == value) { + delete this.$lastValue; + return; + } + + if (!this.$attrBindings["eachvalue"] && !this.$amlLoaded + && this.getAttribute("eachvalue")) { + var _self = this; + return apf.queue.add("value" + this.$uniqueId, function(){ + _self.$propHandlers["value"].call(_self, value); + }); + } + + + + if (value || value === 0 || this["default"]) + this.select(String(value) || this["default"]); + else + this.clearSelection(); + } + + this.$propHandlers["default"] = function(value, prop) { + if (!this.value || !this.$amlLoaded && !(this.getAttribute("value") + || this.getAttribute("selected") || this.getAttribute("selection"))) { + this.$propHandlers["value"].call(this, ""); + } + } + + /** + * @attribute {String} [value] Sets or gets the caret value of the element. + */ + //@todo fill this in + this.$propHandlers["caret"] = function(value, prop) { + if (value) + this.setCaret(value); + } + + + + //@todo optimize this thing. Also implement virtual dataset support. + /** + * @attribute {String} [selection] Sets or gets the {@link term.expression expression} that determines the selection for this element. A reference to an XML nodelist can be passed as well. + * + */ + this.$propHandlers["selection"] = + + /** + * @attribute {String} [selected] Sets or gets the {@link term.expression expression} that determines the selected node for this element. A reference to an XML element can be passed as well. + * + */ + this.$propHandlers["selected"] = function(value, prop) { + if (!value) value = this[prop] = null; + + if (prop == "selected" && typeof value != "string") { // && value == this.selected + if (value && value.nodeType != 1) + value = value.nodeValue; + else + //this.selected = null; //I don't remember why this is here. It removes the selected property without setting it again. (dropdown test) + return; + } + + + + if (this.$isSelecting) { + this.selection = this.$valueList; + return false; + } + + var nodes, bindSet, getValue, i, j, c, d; + //Update the selection + if (prop == "selection") { + if (typeof value == "object" && value == this.$valueList) { + var pNode; + //We're using an external model. Need to update bound nodeset + if ((c = this.$attrBindings[prop]) && c.cvalue.models) { //added check, @todo whats up with above assumption? + this.$isSelecting = true; //Prevent reentrance (optimization) + + bindSet = this.$attrBindings["eachvalue"] + && "eachvalue" || this.$bindings["value"] + && "value" || this.$hasBindRule("caption") && "caption"; + + if (!bindSet) + throw new Error("Missing bind rule set: eachvalue, value or caption");//@todo apf3.0 make this into a proper error + + //@todo this may be optimized by keeping a copy of the selection + var selNodes = this.$getDataNode(prop, this.xmlRoot); + nodes = value; + getValue = (d = this.$attrBindings["selection-unique"]) && d.cvalue; + + if (selNodes.length) { + pNode = selNodes[0].parentNode; + } + else { + var model, path; + if (c.cvalue.xpaths[0] == "#" || c.cvalue.xpaths[1] == "#") { + var m = (c.cvalue3 || (c.cvalue3 = apf.lm.compile(c.value, { + xpathmode: 5 + })))(this.xmlRoot); + + model = m.model && m.model.$isModel && m.model; + if (model) + path = m.xpath; + else if (m.model) { + model = apf.xmldb.findModel(m.model); + path = apf.xmlToXpath(m.model, model.data) + (m.xpath ? "/" + m.xpath : ""); //@todo make this better + } + else { + //No selection - nothing to do + } + } + else { + + model = apf.nameserver.get("model", c.cvalue.xpaths[0]); + + path = c.cvalue.xpaths[1]; + } + + if (!model || !model.data) { + this.$isSelecting = false; + return false; + } + + pNode = model.queryNode(path.replace(/\/[^\/]+$|^[^\/]*$/, "") || "."); + + if (!pNode) + throw new Error("Missing parent node"); //@todo apf3.0 make this into a proper error + } + + //Nodes removed + remove_loop: + for (i = 0; i < selNodes.length; i++) { + //Value is either determined by special property or in the + //same way as the value for the bound node. + value = getValue + ? getValue(selNodes[i]) + : this.$applyBindRule(bindSet, selNodes[i]); + + //Compare the value with the traverse nodes + for (j = 0; j < nodes.length; j++) { + if (this.$applyBindRule(bindSet, nodes[j]) == value) //@todo this could be cached + continue remove_loop; + } + + //remove node + apf.xmldb.removeNode(selNodes[i]); + } + + //Nodes added + add_loop: + for (i = 0; i < nodes.length; i++) { + //Value is either determined by special property or in the + //same way as the value for the bound node. + value = this.$applyBindRule(bindSet, nodes[i]); + + //Compare the value with the traverse nodes + for (j = 0; j < selNodes.length; j++) { + if (getValue + ? getValue(selNodes[j]) + : this.$applyBindRule(bindSet, selNodes[j]) == value) //@todo this could be cached + continue add_loop; + } + + //add node + var node = this.$attrBindings["selection-constructor"] + && this.$getDataNode("selection-constructor", nodes[i]) + || apf.getCleanCopy(nodes[i]); + apf.xmldb.appendChild(pNode, node); + } + + //@todo above changes should be via the actiontracker + this.$isSelecting = false; + } + + return; + } + this.selection = this.$valueList; + } + else { + this.selected = null; + } + + if (!this.xmlRoot) { + if (!this.$buffered) { + var f; + this.addEventListener("afterload", f = function(){ + this.removeEventListener("afterload", f); + this.$propHandlers["selected"].call(this, value, prop); + delete this.$buffered; + }); + this.$buffered = true; + } + this[prop] = null; + return false; + } + + if (!value || typeof value != "object") { + //this[prop] = null; + + if (this.$attrBindings[prop]) { + //Execute the selection query + nodes = this.$getDataNode(prop, this.xmlRoot); + if (nodes && (nodes.length || nodes.nodeType == 1)) { + this.setProperty("selection", nodes); + return; + } + + if (!nodes || nodes.length === 0) + return; + + //Current model, it's an init selection, we'll clear the bind + /*if (typeof value == "string" + && !this.$attrBindings[prop].cvalue.xpaths[0]) { + this.$removeAttrBind(prop); + }*/ + } + + if (!value) { + this.clearSelection(); + } + else { + this.select(value); + } + + return false; //Disable signalling the listeners to this property + } + else if (typeof value.length == "number") { + nodes = value; + if (!nodes.length) { + this.selected = null; + if (this.$valueList.length) { //dont clear selection when no selection exists (at prop init) + this.clearSelection(); + return false; //Disable signalling the listeners to this property + } + else return; + } + + //For when nodes are traverse nodes of this element + if (this.isTraverseNode(nodes[0]) + && apf.isChildOf(this.xmlRoot, nodes[0])) { + if (!this.multiselect) { + this.select(nodes[0]); + } + else { + //this[prop] = null; //?? + this.selectList(nodes); + } + return false; //Disable signalling the listeners to this property + } + + //if external model defined, loop through items and find mate by value + if (this.$attrBindings[prop]) { //Can assume an external model is in place + bindSet = this.$attrBindings["eachvalue"] + && "eachvalue" || this.$bindings["value"] + && "value" || this.$hasBindRule("caption") && "caption"; + + if (!bindSet) + throw new Error("Missing bind rule set: eachvalue, value or caption");//@todo apf3.0 make this into a proper error + + var tNodes = !this.each + ? this.getTraverseNodes() + : this.xmlRoot.selectNodes("//" + this.each.split("|").join("|//")); + + getValue = (c = this.$attrBindings["selection-unique"]) && c.cvalue; + var selList = []; + for (i = 0; i < nodes.length; i++) { + //Value is either determined by special property or in the + //same way as the value for the bound node. + value = getValue + ? getValue(nodes[i]) + : this.$applyBindRule(bindSet, nodes[i]); + + //Compare the value with the traverse nodes + for (j = 0; j < tNodes.length; j++) { + if (this.$applyBindRule(bindSet, tNodes[j]) == value) //@todo this could be cached + selList.push(tNodes[j]); + } + } + + //this[prop] = null; //??? + this.selectList(selList, true); //@todo noEvent to distinguish between user actions and not user actions... need to rethink this + return false; + } + + throw new Error("Show me which case this is"); + } + else if (this.$valueList.indexOf(value) == -1) { + //this.selected = null; + this.select(value); + } + }; + + + + this.$propHandlers["allowdeselect"] = function(value) { + if (value) { + var _self = this; + this.$container.onmousedown = function(e) { + if (!e) + e = event; + if (e.ctrlKey || e.shiftKey) + return; + + var srcElement = e.srcElement || e.target; + if (_self.allowdeselect && (srcElement == this + || srcElement.getAttribute(apf.xmldb.htmlIdTag))) + _self.clearSelection(); //hacky + } + } + else { + this.$container.onmousedown = null; + } + }; + + this.$propHandlers["ctrlselect"] = function(value) { + if (value != "enter") + this.ctrlselect = apf.isTrue(value); + } + + function fAutoselect(){ + this.selectAll(); + } + + this.$propHandlers["autoselect"] = function(value) { + if (value == "all" && this.multiselect) + this.addEventListener("afterload", fAutoselect); + else + this.removeEventListener("afterload", fAutoselect); + }; + + this.$propHandlers["multiselect"] = function(value) { + if (!value && this.$valueList.length > 1) + this.select(this.selected); + + //if (value) + //this.bufferselect = false; //@todo doesn't return to original value + }; + + // Select Bind class + + this.addEventListener("beforeselect", function(e) { + if (this.$bindings.selectable && !this.$getDataNode("selectable", e.selected)) + return false; + }, true); + + + + this.addEventListener("afterselect", function (e) { + + var combinedvalue = null; + + + //@todo refactor below + /*if (this.caret == this.selected || e.list && e.list.length > 1 && hasConnections) { + //Multiselect databinding handling... [experimental] + if (e.list && e.list.length > 1 && this.$getConnections().length) { //@todo this no work no more apf3.0 + var oEl = this.xmlRoot.ownerDocument.createElement(this.selected.tagName); + var attr = {}; + + //Fill basic nodes + var nodes = e.list[0].attributes; + for (var j = 0; j < nodes.length; j++) + attr[nodes[j].nodeName] = nodes[j].nodeValue; + + //Remove nodes + for (var prop, i = 1; i < e.list.length; i++) { + for (prop in attr) { + if (typeof attr[prop] != "string") continue; + + if (!e.list[i].getAttributeNode(prop)) + attr[prop] = undefined; + else if (e.list[i].getAttribute(prop) != attr[prop]) + attr[prop] = ""; + } + } + + //Set attributes + for (prop in attr) { + if (typeof attr[prop] != "string") continue; + oEl.setAttribute(prop, attr[prop]); + } + + //missing is childnodes... will implement later when needed... + + oEl.setAttribute(apf.xmldb.xmlIdTag, this.$uniqueId); + apf.MultiSelectServer.register(oEl.getAttribute(apf.xmldb.xmlIdTag), + oEl, e.list, this); + apf.xmldb.addNodeListener(oEl, apf.MultiSelectServer); + + combinedvalue = oEl; + } + }*/ + + + //Set caret property + this.setProperty("caret", e.caret); + + //Set selection length + if (this.sellength != e.selection.length) + this.setProperty("sellength", e.selection.length); + + //Set selection property + delete this.selection; + this.setProperty("selection", e.selection); + if (!e.selection.length) { + //Set selected property + this.setProperty("selected", e.selected); + + //Set value property + if (this.value) + this.setProperty("value", ""); + } + else { + //Set selected property + this.$chained = true; + if (!e.force && (!this.dataParent || !this.dataParent.parent + || !this.dataParent.parent.$chained)) { + var _self = this; + $setTimeout(function(){ + + if (_self.selected == e.selected) { + delete _self.selected; + _self.setProperty("selected", combinedvalue || e.selected); + } + + delete _self.$chained; + }, 10); + } + else { + + this.setProperty("selected", combinedvalue || e.selected); + + delete this.$chained; + } + + //Set value property + var valueRule = this.$attrBindings["eachvalue"] && "eachvalue" + || this.$bindings["value"] && "value" + || this.$hasBindRule("caption") && "caption"; + + if (valueRule) { + //@todo this will call the handler again - should be optimized + + this.$lastValue = this.$applyBindRule(valueRule, e.selected) + //this.$attrBindings["value"] && + if (this.$lastValue != + (valueRule != "value" && (this.xmlRoot + && this.$applyBindRule("value", this.xmlRoot, null, true)) + || this.value)) { + if (valueRule == "eachvalue" || this.xmlRoot != this) + this.change(this.$lastValue); + else + this.setProperty("value", this.$lastValue); + } + /*else { + this.setProperty("value", this.$lastValue); + }*/ + delete this.$lastValue; + } + } + + + + + }, true); + + + + +}).call(apf.MultiSelect.prototype = new apf.MultiselectBinding()); + + + +//@todo refactor below +/* + * @private + */ +/* +apf.MultiSelectServer = { + objects: {}, + + register: function(xmlId, xmlNode, selList, jNode) { + if (!this.$uniqueId) + this.$uniqueId = apf.all.push(this) - 1; + + this.objects[xmlId] = { + xml: xmlNode, + list: selList, + jNode: jNode + }; + }, + + $xmlUpdate: function(action, xmlNode, listenNode, UndoObj) { + if (action != "attribute") return; + + var data = this.objects[xmlNode.getAttribute(apf.xmldb.xmlIdTag)]; + if (!data) return; + + var nodes = xmlNode.attributes; + + for (var j = 0; j < data.list.length; j++) { + //data[j].setAttribute(UndoObj.name, xmlNode.getAttribute(UndoObj.name)); + apf.xmldb.setAttribute(data.list[j], UndoObj.name, + xmlNode.getAttribute(UndoObj.name)); + } + + //apf.xmldb.synchronize(); + } +}; +*/ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + +apf.__CHILDVALUE__ = 1 << 27; + + +apf.ChildValue = function(){ + if (!this.$childProperty) + this.$childProperty = "value"; + + this.$regbase = this.$regbase | apf.__CHILDVALUE__; + + var f, re = /^[\s\S]*?>(<\?lm)?([\s\S]*?)(?:\?>)?<[^>]*?>$/; + this.addEventListener("DOMCharacterDataModified", f = function(e) { + if (e && (e.currentTarget == this + || e.currentTarget.nodeType == 2 && e.relatedNode == this) + || this.$amlDestroyed) + return; + + if (this.getAttribute(this.$childProperty)) + return; + + //Get value from xml (could also serialize children, but that is slower + var m = this.serialize().match(re), + v = m && m[2] || ""; + if (m && m[1]) + v = "{" + v + "}"; + + this.$norecur = true; + + + if (v.indexOf("{") > -1 || v.indexOf("[") > -1) + this.$setDynamicProperty(this.$childProperty, v); + else + + if (this[this.$childProperty] != v) + this.setProperty(this.$childProperty, v); + + this.$norecur = false; + }); + + //@todo Should be buffered + this.addEventListener("DOMAttrModified", f); + this.addEventListener("DOMNodeInserted", f); + this.addEventListener("DOMNodeRemoved", f); + + this.addEventListener("$skinchange", function(e) { + this.$propHandlers[this.$childProperty].call(this, this.caption || ""); + }); + + this.$init(function(){ + this.addEventListener("prop." + this.$childProperty, function(e) { + if (!this.$norecur && !e.value && !this.getAttributeNode(this.$childProperty)) + f.call(this); + }); + }); + + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + var hasNoProp = typeof this[this.$childProperty] == "undefined"; + + //this.firstChild.nodeType != 7 && + if (hasNoProp + && !this.getElementsByTagNameNS(this.namespaceURI, "*", true).length + && (this.childNodes.length > 1 || this.firstChild + && (this.firstChild.nodeType == 1 + || this.firstChild.nodeValue.trim().length))) { + //Get value from xml (could also serialize children, but that is slower + var m = (this.$aml && this.$aml.xml || this.serialize()).match(re), + v = m && m[2] || ""; + if (m && m[1]) + v = "{" + v + "}"; + + + if (v.indexOf("{") > -1 || v.indexOf("[") > -1) + this.$setDynamicProperty(this.$childProperty, v); + else + + this.setProperty(this.$childProperty, apf.html_entity_decode(v)); //@todo should be xml entity decode + } + else if (hasNoProp) + this.$propHandlers[this.$childProperty].call(this, ""); + }); +}; + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + +apf.__DATAACTION__ = 1 << 25; + + +/** + * A [[term.baseclass baseclass]] that adds data action features to this element. + * @class apf.DataAction + */ +apf.DataAction = function(){ + this.$regbase = this.$regbase | apf.__DATAACTION__; + + // *** Public Methods *** // + + /** + * Gets the ActionTracker this element communicates with. + * + * @return {apf.actiontracker} + * @see apf.smartbinding + */ + this.getActionTracker = function(ignoreMe) { + if (!apf.AmlNode) + return apf.window.$at; + + var pNode = this, tracker = ignoreMe ? null : this.$at; + if (!tracker && this.dataParent && this.dataParent.parent) + tracker = this.dataParent.parent.$at; //@todo apf3.0 change this to be recursive?? + + while (!tracker) { + if (!pNode.parentNode && !pNode.$parentNode) { + var model; + return (model = this.getModel && this.getModel(true)) && model.$at || apf.window.$at; + } + + tracker = (pNode = pNode.parentNode || pNode.$parentNode).$at; + } + return tracker; + }; + + + + this.$actionsLog = {}; + this.$actions = false; + + /** + * @event locksuccess Fires when a lock request succeeds + * @bubbles + * @param {Object} e The standard event object, with the following properties: + * - state ([[Number]]): The return code of the lock request + * + */ + /** + * @event lockfailed Fires when a lock request failes + * @bubbles + * @param {Object} e The standard event object, with the following properties: + * - state ([[Number]]): The return code of the lock request + * + */ + /** + * @event unlocksuccess Fires when an unlock request succeeds + * @bubbles + * @param {Object} e The standard event object, with the following properties: + * - state ([[Number]]): The return code of the unlock request + * + */ + /** + * @event unlockfailed Fires when an unlock request fails + * @bubbles + * @param {Object} e The standard event object, with the following properties: + * - state ([[Number]]): The return code of the unlock request + * + */ + /* + * Starts the specified action, does optional locking and can be offline aware + * - or for optimistic locking it will record the timestamp (a setting + * ) + * - During offline work, optimistic locks will be handled by taking the + * timestamp of going offline + * - This method is always optional! The server should not expect locking to exist. + * + */ + this.$startAction = function(name, xmlContext, fRollback) { + if (this.disabled || this.liveedit && name != "edit") + return false; + + var actionRule = this.$actions && this.$actions.getRule(name, xmlContext); + if (!actionRule && apf.config.autoDisableActions && this.$actions) { + + + return false; + } + + var bHasOffline = typeof apf.offline != "undefined"; + + + if (this.dispatchEvent(name + "start", { + xmlContext: xmlContext + }) === false) + return false; + + + + this.$actionsLog[name] = xmlContext; + + return true; + }; + + + // @todo think about if this is only for rdb + this.addEventListener("xmlupdate", function(e) { + if (apf.xmldb.disableRDB != 2) + return; + + for (var name in this.$actionsLog) { + if (apf.isChildOf(this.$actionsLog[name], e.xmlNode, true)) { + //this.$stopAction(name, true); + this.$actionsLog[name].rollback.call(this, this.$actionsLog[name].xmlContext); + } + } + }); + + + this.$stopAction = function(name, isCancelled, curLock) { + delete this.$actionsLog[name]; + + + }; + + /* + * Executes an action using action rules set in the {@link apf.actions actions element}. + * + * @param {String} atAction The name of the action to be performed by the [[ActionTracker]]. Possible values include: + * - `"setTextNode"`: Sets the first text node of an XML element. For more information, see {@link core.xmldb.method.setTextNode} + * - `"setAttribute"`: Sets the attribute of an XML element. For more information, see {@link core.xmldb.method.setAttribute} + * - `"removeAttribute"`: Removes an attribute from an XML element. For more information, see {@link core.xmldb.method.removeAttribute} + * - `"setAttributes"`: Sets multiple attribute on an XML element. The arguments are in the form of `xmlNode, Array` + * - `"replaceNode"`: Replaces an XML child with another one. For more information, see {@link core.xmldb.method.replaceNode} + * - `"addChildNode"`: Adds a new XML node to a parent node. For more information, see {@link core.xmldb.method.addChildNode} + * - `"appendChild"`: Appends an XML node to a parent node. For more information, see {@link core.xmldb.method.appendChild} + * - `"moveNode"` : Moves an XML node from one parent to another. For more information, see {@link core.xmldb.method.moveNode} + * - `"removeNode"`: Removes a node from it's parent. For more information, see {@link core.xmldb.method.removeNode} + * - `" removeNodeList"`: Removes multiple nodes from their parent. For more information, see {@link core.xmldb.method.removeNodeList} + * - `"setValueByXpath"`: Sets the nodeValue of an XML node which is selected + * by an xpath statement. The arguments are in the form of `xmlNode, xpath, value` + * - `"multicall"`: Calls multiple of the above actions. The argument`s are an array + * of argument arrays for these actions each with a func` + * property, which is the name of the action. + * @param {Array} args the arguments to the function specified + * in atAction. + * @param {String} action the name of the action rule defined in + * actions for this element. + * @param {XMLElement} xmlNode the context for the action rules. + * @param {Boolean} [noevent] whether or not to call events. + * @param {XMLElement} [contextNode] the context node for action processing + * (such as RPC calls). Usually the same + * as xmlNode + * @return {Boolean} specifies success or failure + * @see apf.smartbinding + */ + this.$executeAction = function(atAction, args, action, xmlNode, noevent, contextNode, multiple) { + + + + + //Get Rules from Array + var rule = this.$actions && this.$actions.getRule(action, xmlNode); + if (!rule && this.$actions && apf.config.autoDisableActions + && "action|change".indexOf(action) == -1) { + apf.console.warn("Could not execute action '" + action + "'. \ + No valid action rule was found and auto-disable-actions is enabled"); + + return false; + } + + + + var newMultiple; + if (multiple) { + newMultiple = []; + for (var k = multiple.length - 1; k >= 0; k--) { + newMultiple.unshift({ + xmlActionNode: rule, // && rule[4], + amlNode: this, + selNode: multiple[k], + xmlNode: multiple[k] + }) + } + } + + //@todo apf3.0 Shouldn't the contextNode be made by the match + var ev = new apf.AmlEvent("before" + action.toLowerCase(), { + action: atAction, + args: args, + xmlActionNode: rule, + amlNode: this, + selNode: contextNode, + multiple: newMultiple || false + + }); + + //Call Event and cancel if it returns false + if (!noevent) { + //Allow the action and arguments to be changed by the event + if (this.dispatchEvent(ev.name, null, ev) === false) + return false; + + delete ev.currentTarget; + } + + //Call ActionTracker and return ID of Action in Tracker + var at = this.getActionTracker(); + if (!at)// This only happens at destruction of apf + return UndoObj; + + var UndoObj = at.execute(ev); + ev.xmlNode = UndoObj.xmlNode; + ev.undoObj = UndoObj; + + //Call After Event + if (!noevent) { //@todo noevent is not implemented for before. ??? + ev.name = "after" + action.toLowerCase(); + ev.cancelBubble = false; + delete ev.returnValue; + delete ev.currentTarget; + this.dispatchEvent(ev.name, null, ev); + } + + return UndoObj; + }; + + /* + * Executes an action based on the set name and the new value + * @param {String} atName the name of the action rule defined in actions for this element. + * @param {String} setName the name of the binding rule defined in bindings for this element. + * @param {XMLElement} xmlNode the xml element to which the rules are applied + * @param {String} value the new value of the node + */ + this.$executeSingleValue = function(atName, setName, xmlNode, value, getArgList) { + var xpath, args, rule = this.$getBindRule(setName, xmlNode); + + //recompile bindrule to create nodes + if (!rule) { + + return false; + } + + var compiled; + ["valuematch", "match", "value"].each(function(type) { + if (!rule[type] || compiled) + return; + + compiled = rule["c" + type]; //cvaluematch || (rule.value ? rule.cvalue : rule.cmatch); + if (!compiled) + compiled = rule.compile(type); + + if (compiled.type != 3) + compiled = null; + }); + + + + var atAction, model, node, + sel = compiled.xpaths, //get first xpath + shouldLoad = false; + + if (sel[0] == "#" || sel[1] == "#") { + var m = (rule.cvalue3 || (rule.cvalue3 = apf.lm.compile(rule.value, { + xpathmode: 5 + })))(xmlNode, apf.nameserver.lookup["all"]); + + model = m.model && m.model.$isModel && m.model; + if (model) { + node = model.queryNode(m.xpath); + xmlNode = model.data; + } + else if (m.model) { + model = apf.xmldb.findModel(m.model); + node = m.model.selectSingleNode(m.xpath); + xmlNode = m.model; + } + else { + + } + + sel[1] = m.xpath; + } + else { + + model = sel[0] && apf.nameserver.get("model", sel[0]) || this.$model, + node = model + ? model.queryNode(sel[1]) + : (xmlNode || this.xmlRoot).selectSingleNode(sel[1]); + if (model && !xmlNode) + xmlNode = model.data; //@experimental, after changing this, please run test/test_rename_edge.html + + } + + if (node) { + if (apf.queryValue(node) == value) return; // Do nothing if value is unchanged + + atAction = (node.nodeType == 1 || node.nodeType == 3 + || node.nodeType == 4) ? "setTextNode" : "setAttribute"; + args = (node.nodeType == 1) + ? [node, value] + : (node.nodeType == 3 || node.nodeType == 4 + ? [node.parentNode, value] + : [node.ownerElement || node.selectSingleNode(".."), node.nodeName, value]); + } + else { + atAction = "setValueByXpath"; + xpath = sel[1]; + + if (!this.$createModel || this.getModel() && !this.getModel().$createModel) { + throw new Error("Model data does not exist, and I am not " + + "allowed to create the element for xpath '" + + xpath + "' and element " + this.serialize(true)); + } + + if (!xmlNode) { + //Assuming this component is connnected to a model + if (!model) + model = this.getModel(); + if (model) { + if (!model.data) + model.load(""); + + xpath = (model.getXpathByAmlNode(this) || ".") + + (xpath && xpath != "." ? "/" + xpath : ""); + xmlNode = model.data; + } + else { + if (!this.dataParent) + return false; + + xmlNode = this.dataParent.parent.selected || this.dataParent.parent.xmlRoot; + if (!xmlNode) + return false; + + xpath = (this.dataParent.xpath || ".") + + (xpath && xpath != "." ? "/" + xpath : ""); + shouldLoad = true; + } + } + + args = [xmlNode, value, xpath]; + } + + if (getArgList) { + return { + action: atAction, + args: args + }; + } + + //Use Action Tracker + var result = this.$executeAction(atAction, args, atName, xmlNode); + + if (shouldLoad) + this.load(xmlNode.selectSingleNode(xpath)); + + return result; + }; + + /** + * Changes the value of this element. + * @action + * @param {String} [string] The new value of this element. + * + */ + this.change = function(value, force){ // @todo apf3.0 maybe not for multiselect?? - why is clearError handling not in setProperty for value + + if (this.errBox && this.errBox.visible && this.isValid && this.isValid()) + this.clearError(); + + + + //Not databound + if (!this.xmlRoot && !this.$createModel || !(this.$mainBind == "value" + && this.hasFeature(apf.__MULTISELECT__) + ? this.$attrBindings["value"] + : this.$hasBindRule(this.$mainBind))) { + + if (!force && value === this.value + || this.dispatchEvent("beforechange", {value : value}) === false) + return false; + + //@todo in theory one could support actions + //@todo disabled below, because it gives unexpected behaviour when + //form elements are used for layout and other UI alterations + /*this.getActionTracker().execute({ + action: "setProperty", + args: [this, "value", value, false, true], + amlNode: this + });*/ + this.setProperty("value", value); + + return this.dispatchEvent("afterchange", {value : value}); + + } + + var valueRule = this.$attrBindings["eachvalue"] && "eachvalue" + || this.$bindings["value"] && "value" + || this.$hasBindRule("caption") && "caption"; + + if (value === (valueRule != "value" && (this.xmlRoot + && this.$applyBindRule("value", this.xmlRoot, null, true)) + || this.value)) + return false; + + this.$executeSingleValue("change", this.$mainBind, this.xmlRoot, value); + + }; + + this.$booleanProperties["render-root"] = true; + this.$supportedProperties.push("create-model", "actions"); + + /** + * @attribute {Boolean} create-model Sets or gets whether the model this element connects + * to is extended when the data pointed to does not exist. Defaults to true. + * + * #### Example + * + * In this example, a model is extended when the user enters information in + * the form elements. Because no model is specified for the form elements, + * the first available model is chosen. At the start, it doesn't have any + * data; this changes when (for instance) the name is filled in. A root node + * is created, and under that a 'name' element with a textnode containing + * the entered text. + * + * ```xml + * + * Name + * + * + * Address + * + * + * Country + * + * Submit + * + * ``` + */ + this.$propHandlers["create-model"] = function(value) { + this.$createModel = value; + }; + + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + if (typeof this["create-model"] == "undefined" + && !this.$setInheritedAttribute("create-model")) { + this.$createModel = true; + } + }); +}; + +apf.config.$inheritProperties["create-model"] = 1; + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + +apf.__CACHE__ = 1 << 2; + + + +/** + * All elements inheriting from this {@link term.baseclass baseclass} have caching features. It takes care of + * storing, retrieving, and updating rendered data (in HTML form) + * to overcome the waiting time while rendering the contents every time the + * data is loaded. + * + * @class apf.Cache + * @baseclass + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.4 + */ +apf.Cache = function(){ + /* ******************************************************************** + PROPERTIES + *********************************************************************/ + this.cache = {}; + this.$subTreeCacheContext = null; + + this.caching = true; + this.$regbase = this.$regbase | apf.__CACHE__; + + /* ******************************************************************** + PUBLIC METHODS + *********************************************************************/ + + this.addEventListener("$load", function(e) { + if (!this.caching || e.forceNoCache) + return; + + // retrieve the cacheId + if (!this.cacheId) { + this.cacheId = this.$generateCacheId && this.$generateCacheId(e.xmlNode) + || e.xmlNode.getAttribute(apf.xmldb.xmlIdTag) + || apf.xmldb.nodeConnect(apf.xmldb.getXmlDocId(e.xmlNode), e.xmlNode);//e.xmlNode + } + + // Retrieve cached version of document if available + var fromCache = getCache.call(this, this.cacheId, e.xmlNode); + if (fromCache) { + if (fromCache == -1 || !this.getTraverseNodes) + return (e.returnValue = false); + + var nodes = this.getTraverseNodes(); + + //Information needs to be passed to the followers... even when cached... + if (nodes.length) { + if (this["default"]) + this.select(this["default"]); + else if (this.autoselect) + this.select(nodes[0], null, null, null, true); + } + else if (this.clearSelection) + this.clearSelection(); //@todo apf3.0 was setProperty("selected", null + + if (!nodes.length) { + // Remove message notifying user the control is without data + this.$removeClearMessage(); + this.$setClearMessage(this["empty-message"], "empty"); + } + + + //@todo move this to getCache?? + if (nodes.length != this.length) + this.setProperty("length", nodes.length); + + + return false; + } + }); + + this.addEventListener("$clear", function(){ + if (!this.caching) + return; + + /* + Check if we borrowed an HTMLElement + We should return it where it came from + + note: There is a potential that we can't find the exact location + to put it back. We should then look at it's position in the xml. + (but since I'm lazy it's not doing this right now) + There might also be problems when removing the xmlroot + */ + if (this.hasFeature(apf.__MULTISELECT__) + && this.$subTreeCacheContext && this.$subTreeCacheContext.oHtml) { + if (this.renderRoot) { + this.$subTreeCacheContext.parentNode.insertBefore( + this.$subTreeCacheContext.oHtml, this.$subTreeCacheContext.beforeNode); + } + else { + var container = this.$subTreeCacheContext.container || this.$container; + while (container.childNodes.length) + this.$subTreeCacheContext.oHtml.appendChild(container.childNodes[0]); + } + + this.documentId = this.xmlRoot = this.cacheId = this.$subTreeCacheContext = null; + } + else { + /* If the current item was loaded whilst offline, we won't cache + * anything + */ + if (this.$loadedWhenOffline) { + this.$loadedWhenOffline = false; + } + else { + // Here we cache the current part + var fragment = this.$getCurrentFragment(); + if (!fragment) return;//this.$setClearMessage(this["empty-message"]); + + fragment.documentId = this.documentId; + fragment.xmlRoot = this.xmlRoot; + + if (this.cacheId || this.xmlRoot) + setCache.call(this, this.cacheId || + this.xmlRoot.getAttribute(apf.xmldb.xmlIdTag) || "doc" + + this.xmlRoot.getAttribute(apf.xmldb.xmlDocTag), fragment); + } + } + }); + + /* + * Checks the cache for a cached item by ID. If the ID is found, the + * representation is loaded from cache and set active. + * + * @param {String} id The id of the cache element which is looked up. + * @param {Object} xmlNode + * @return {Boolean} If `true`, the cache element was found and set active + * @see baseclass.databinding.method.load + * @private + */ + function getCache(id, xmlNode) { + /* + Let's check if the requested source is actually + a sub tree of an already rendered part + */ + + if (xmlNode && this.hasFeature(apf.__MULTISELECT__) && this.$isTreeArch) { + var cacheItem, + htmlId = xmlNode.getAttribute(apf.xmldb.xmlIdTag) + "|" + this.$uniqueId, + node = this.$pHtmlDoc.getElementById(htmlId); + if (node) + cacheItem = id ? false : this.$container; //@todo what is the purpose of this statement? + else { + for (var prop in this.cache) { + if (this.cache[prop] && this.cache[prop].nodeType) { + node = this.cache[prop].getElementById(htmlId); + if (node) { + cacheItem = id ? prop : this.cache[prop]; //@todo what is the purpose of this statement? + break; + } + } + } + } + + if (cacheItem && !this.cache[id]) { + /* + Ok so it is, let's borrow it for a while + We can't clone it, because the updates will + get ambiguous, so we have to put it back later + */ + var oHtml = this.$findHtmlNode( + xmlNode.getAttribute(apf.xmldb.xmlIdTag) + "|" + this.$uniqueId); + this.$subTreeCacheContext = { + oHtml: oHtml, + parentNode: oHtml.parentNode, + beforeNode: oHtml.nextSibling, + cacheItem: cacheItem + }; + + this.documentId = apf.xmldb.getXmlDocId(xmlNode); + this.cacheId = id; + this.xmlRoot = xmlNode; + + //Load html + if (this.renderRoot) + this.$container.appendChild(oHtml); + else { + while (oHtml.childNodes.length) + this.$container.appendChild(oHtml.childNodes[0]); + } + + return true; + } + } + + + //Checking Cache... + if (!this.cache[id]) return false; + + //Get Fragment and clear Cache Item + var fragment = this.cache[id]; + + this.documentId = fragment.documentId; + this.cacheId = id; + this.xmlRoot = xmlNode;//fragment.xmlRoot; + + + this.setProperty("root", this.xmlRoot); + + + this.clearCacheItem(id); + + this.$setCurrentFragment(fragment); + + return true; + }; + + /* + * Sets cache element and its ID. + * + * @param {String} id The id of the cache element to be stored. + * @param {DocumentFragment} fragment The data to be stored. + * @private + */ + function setCache(id, fragment) { + if (!this.caching) return; + + this.cache[id] = fragment; + }; + + /* + * Finds HTML presentation node in cache by ID. + * + * @param {String} id The id of the HTMLElement which is looked up. + * @return {HTMLElement} The HTMLElement found. When no element is found, `null` is returned. + */ + this.$findHtmlNode = function(id) { + var node = this.$pHtmlDoc.getElementById(id); + if (node) return node; + + for (var prop in this.cache) { + if (this.cache[prop] && this.cache[prop].nodeType) { + node = this.cache[prop].getElementById(id); + if (node) return node; + } + } + + return null; + }; + + /** + * Removes an item from the cache. + * + * @param {String} id The id of the HTMLElement which is looked up. + * @param {Boolean} [remove] Specifies whether to destroy the Fragment. + * @see baseclass.databinding.method.clear + * @private + */ + this.clearCacheItem = function(id, remove) { + this.cache[id].documentId = + this.cache[id].cacheId = + this.cache[id].xmlRoot = null; + + if (remove) + apf.destroyHtmlNode(this.cache[id]); + + this.cache[id] = null; + }; + + /* + * Removes all items from the cache + * + * @see baseclass.databinding.method.clearCacheItem + * @private + */ + this.clearAllCache = function(){ + for (var prop in this.cache) { + if (this.cache[prop]) + this.clearCacheItem(prop, true); + } + }; + + /** + * Gets the cache item by its id + * + * @param {String} id The id of the HTMLElement which is looked up. + * @see baseclass.databinding.method.clearCacheItem + * @private + */ + this.getCacheItem = function(id) { + return this.cache[id]; + }; + + /* + * Checks whether a cache item exists by the specified id + * + * @param {String} id the id of the cache item to check. + * @see baseclass.databinding.method.clearCacheItem + * @private + */ + this.$isCached = function(id) { + return this.cache[id] || this.cacheId == id ? true : false; + }; + + if (!this.$getCurrentFragment) { + this.$getCurrentFragment = function(){ + var fragment = this.$container.ownerDocument.createDocumentFragment(); + + while (this.$container.childNodes.length) { + fragment.appendChild(this.$container.childNodes[0]); + } + + return fragment; + }; + + this.$setCurrentFragment = function(fragment) { + this.$container.appendChild(fragment); + + if (!apf.window.hasFocus(this) && this.blur) + this.blur(); + }; + } + + /** + * @attribute {Boolean} caching Sets or gets whether caching is enabled for this element. + */ + this.$booleanProperties["caching"] = true; + this.$supportedProperties.push("caching"); + + this.addEventListener("DOMNodeRemovedFromDocument", function(e) { + //Remove all cached Items + this.clearAllCache(); + }); +}; + +apf.GuiElement.propHandlers["caching"] = function(value) { + if (!apf.isTrue(value)) return; + + if (!this.hasFeature(apf.__CACHE__)) + this.implement(apf.Cache); +}; + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + +apf.__RENAME__ = 1 << 10; + + + +/** + * All elements inheriting from this {@link term.baseclass baseclass} have the rename features. Rename is triggered by + * pressing F2 on an item or by clicking once on an already selected item. This + * will show an input element in place where the user can change the name of the + * item to a new one. When the caption is changed the {@link term.datanode data node} is + * changed accordingly. + * + * #### Example + * + * This example shows a list containing products. Only products that have the + * editable attribute set to 1 can be renamed by the user. + * + * ```xml + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * ``` + * + * @class apf.Rename + * @baseclass + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.5 + */ +/** + * @event stoprename Fires when a rename action is cancelled. + * + */ +apf.Rename = function(){ + this.$regbase = this.$regbase|apf.__RENAME__; + + this.canrename = false; + this.$renameSubject = + this.renameTimer = + this.lastCursor = null; + + /** + * @attribute {Boolean} rename Sets or gets whether the user can start renaming rendered nodes in this element. + */ + this.$booleanProperties["canrename"] = true; + this.$booleanProperties["autorename"] = true; + this.$supportedProperties.push("canrename", "autorename"); + + + + /** + * Changes the data presented as the caption of a specified {@link term.datanode data node}. + * + * If none are specified, the indicated node is used. + * + * @action + * @param {XMLElement} xmlNode The element to change the caption of. + * @param {String} value The value to set as the caption of the {@link term.datanode data node}. + */ + this.rename = function(xmlNode, value) { + if (!xmlNode) + xmlNode = this.caret || this.selected; + + if (!xmlNode) return; + + return this.$executeSingleValue("rename", "caption", xmlNode, value); + }; + + // @todo Doc params + /** + * Starts the rename process with a delay, allowing for cancellation when + * necesary. Cancellation is necesary for instance, when double click was + * intended or a dragdrop operation. + * + */ + this.startDelayedRename = function(e, time, userAction) { + clearTimeout(this.renameTimer); + + if (e && (e.button == 2 || e.ctrlKey || e.shiftKey) + || userAction && this.disabled) + return; + + this.renameTimer = $setTimeout('apf.lookup(' + + this.$uniqueId + ').startRename()', time || 400); + }; + + // @todo Doc params + /** + * Starts the rename process by displaying an input box at the position + * of the item that can be renamed by the user. + * + */ + this.startRename = function(force, startEmpty, userAction) { + if (!force && (this.renaming || !this.canrename + || !this.$startAction("rename", this.caret + || this.selected, this.stopRename)) + || userAction && this.disabled) + return false; + + if (!this.hasFocus()) + this.focus(null, null, true); + + clearTimeout(this.renameTimer); + + var elCaption = this.$getCaptionElement + ? this.$getCaptionElement() + : this.$caret || this.$selected; + + if (!elCaption) + return this.stopRename(); + + this.renaming = true; + this.$renameSubject = this.caret || this.selected; + + var wdt = elCaption.offsetWidth; + this.lastCursor = elCaption.style.cursor; + elCaption.style.cursor = "text"; + elCaption.parentNode.replaceChild(this.$txt, elCaption); + elCaption.host = this; + + if (apf.isTrue(this.$getOption("main", "scalerename"))) { + var diff = apf.getWidthDiff(this.$txt); + this.$txt.style.width = (wdt - diff - 3) + "px"; + } + + this.$replacedNode = elCaption; + var xmlNode = this.$getCaptionXml + ? this.$getCaptionXml(this.$renameSubject) + : this.$getDataNode("caption", this.$renameSubject); + + //xmlNode.nodeType >= 2 && xmlNode.nodeType <= 4 + var value = startEmpty || !xmlNode + ? "" + : (xmlNode.nodeType != 1 + ? unescape(xmlNode.nodeValue) //decodeURI( - throws an error when using % in a non expected way + : (apf.isOnlyChild(xmlNode.firstChild, [3,4]) + ? apf.queryValue(xmlNode) + : this.$applyBindRule("caption", this.$renameSubject))) || ""; + + if (apf.hasContentEditable) { + if (this.$multiLineRename) + this.$txt.innerHTML = apf.htmlCleaner.prepare(value.trim() + .replace(//g, ">") + .replace(/\n/g, "
      ")); + else + this.$txt.innerHTML = value.replace(/" || ""; + } + else + this.$txt.value = value; + + this.$txt.unselectable = "Off"; + this.$txt.host = this; + + //this.$txt.focus(); + var txt = this.$txt; + var f = function(){ + try { + txt.focus(); + txt.select(); + } + catch (e) {} + }; + if (apf.isIE) f() + else $setTimeout(f); + }; + + // @todo Doc params + /** + * Stops the renaming process and changes the data according to the set value. + * Cancel the renaming process without changing data. + * + */ + this.stopRename = function(contextXml, success) { + clearTimeout(this.renameTimer); + + if (!this.renaming || contextXml && contextXml != this.$renameSubject + || !this.$replacedNode) + return false; + + this.renaming = false; + + if (this.$txt.parentNode && this.$txt.parentNode.nodeType == 1) { + if (apf.isIE8 || apf.isIE7Emulate) + this.$txt.blur(); + + this.$txt.parentNode.replaceChild(this.$replacedNode, this.$txt); + } + + if (this.$replacedNode) { + this.$replacedNode.style.cursor = this.lastCursor || ""; + this.$replacedNode.host = null; + } + + //apf.hasContentEditable ?? + if (this.$multiLineRename) { + var value = apf.html_entity_decode( + apf.htmlCleaner.parse(this.$txt.innerHTML, true) + .replace(/
      /g, "") + .replace(/<\/?p>/g, "")); + } + else { + var value = this.$txt[apf.hasContentEditable ? "innerText" : "value"] + .replace(/<.*?nobr>/gi, "").replace(/\n$/, ""); //last replace is for chrome + } + + if (!success || (this.$validateRename && !this.$validateRename(value))) { + this.dispatchEvent("stoprename"); + this.$stopAction("rename"); + } + else { + //this.$selected.innerHTML = this.$txt.innerHTML; + if (this.rename(this.$renameSubject, value) !== false) { + if (this.$replacedNode) + this.$replacedNode.innerHTML = value.replace(/"); + } + } + + if (!this.renaming) { + this.$renameSubject = null; + this.$replacedNode = null; + this.$txt.style.width = ""; + } + + return true; + }; + + + this.addEventListener("keydown", function(e) { + var key = e.keyCode; + + if (this.renaming) { + if (key == 27 || this.$multiLineRename && e.ctrlKey && key == 13 + || !this.$multiLineRename && key == 13) { + this.stopRename(null, key == 13 && !this.$autocomplete); + e.cancelBubble = true; + return false; + } + else if (apf.hasContentEditableContainerBug && key == 8 + && this.$txt.innerHTML == "
      ") { + e.preventDefault(); + } + + return; + } + + //F2 + if (key == 113) { + if (this.$tempsel) + this.$selectTemp(); + + if (this.caret != this.selected) { + if (this.multiselect || this.isSelected(this.caret)) { + this.selected = this.caret; + this.$selected = this.$caret; + } + else + this.select(this.caret, true); + } + + this.startRename(); + + return false; + } + }, true); + + + this.addEventListener("DOMNodeRemovedFromDocument", function(e) { + this.$txt.refCount--; + + if (!this.$txt.refCount) { + this.$txt.host = + this.$txt.onmouseover = + this.$txt.onmousedown = + this.$txt.select = + this.$txt.onfocus = + this.$txt.onblur = null; + } + this.$txt = null; + }); + + this.$init(apf.Rename.initEditableArea); +}; + +apf.Rename.initEditableArea = function(){ + if (!(this.$txt = document.getElementById("txt_rename"))) { + if (apf.hasContentEditable) { + this.$txt = document.createElement("DIV"); + this.$txt.contentEditable = true; + if (apf.isIE6) + this.$txt.style.width = "1px"; + //this.$txt.canHaveHTML = false; + } + else { + this.$txt = document.createElement("input"); + this.$txt.id = "txt_rename"; + this.$txt.autocomplete = false; + } + + + this.$txt.spellcheck = false; + this.$txt.refCount = 0; + this.$txt.id = "txt_rename"; + //this.$txt.style.whiteSpace = "nowrap"; + apf.importCssString("#txt_rename{white-space:nowrap}"); + this.$txt.onselectstart = function(e) { + (e || event).cancelBubble = true; + }; + + this.$txt.onmouseover = + this.$txt.onmouseout = + this.$txt.oncontextmenu = + //this.$txt.onkeydown = + this.$txt.onmouseup = + this.$txt.ondblclick = + this.$txt.onmousedown = function(e) { + apf.stopPropagation(e || event) + }; + + this.$txt.onkeyup = function(e) { + //(e || event).cancelBubble = true; + + if (!this.host.$autocomplete) + return; + + this.host.$lookup(this[apf.hasContentEditable ? "innerHTML" : "value"]); + } + + var sel; + this.$txt.select = function(){ + if (!apf.hasMsRangeObject) { + if (window.getSelection && document.createRange) { + var sel = window.getSelection(); + sel.removeAllRanges(); + var r = document.createRange(); + r.setStart(this.firstChild, 0); + var lastIndex = this.firstChild.nodeValue.lastIndexOf("."); + r.setEnd(this.firstChild, lastIndex > -1 ? lastIndex : this.firstChild.nodeValue.length); + sel.addRange(r) + } + else { + (sel || (sel = new apf.selection())).selectNode(this); + } + return; + } + + var r = document.selection.createRange(); + //r.moveEnd("character", this.$ext.innerText.length); + try { + r.moveToElementText(this); + + if (apf.isFalse(this.host.$getOption("main", "selectrename")) + || typeof this.host.$renameStartCollapse != "undefined") //@todo please deprecate renameStartCollapse + r.collapse(this.host.$renameStartCollapse); + } catch (e) {} //BUG!!!! + + r.select(); + }; + + + + this.$txt.onblur = function(){ + //if (apf.isGecko) + //return; //bug in firefox calling onblur too much + //if (apf.isChrome && !arguments.callee.caller) + //return; + + + + if (this.host.$autocomplete) + return; + + this.host.stopRename(null, true); + }; + } + + this.$txt.refCount++; +} + + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + +apf.__ALIGNMENT__ = 1 << 29; + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * Baseclass of an element that has one or two states and can be clicked on to + * trigger an action (_i.e._ {@link apf.button} or {@link apf.checkbox}). + * + * @class apf.BaseButton + * @baseclass + * @author Abe Ginner + * @version %I%, %G% + * @since 0.8 + * @inherits apf.StandardBinding + */ +/** + * @event click Fires when the user presses a mouse button while over this element...and then lets the mousebutton go. + */ +apf.BaseButton = function(){ + this.$init(true); +}; + +(function() { + + this.implement(apf.ChildValue); + + + this.$refKeyDown = // Number of keys pressed. + this.$refMouseDown = 0; // Mouse button down? + this.$mouseOver = // Mouse hovering over the button? + this.$mouseLeft = false; // Has the mouse left the control since pressing the button. + + // *** Properties and Attributes *** // + + /** + * @attribute {String} background Sets or gets a multistate background. The arguments + * are seperated by pipes (`'|'`) and are in the order of:'imagefilename|mapdirection|nrofstates|imagesize' + * + * - The `mapdirection` argument may have the value of `'vertical'` or `'horizontal'`. + * - The `nrofstates` argument specifies the number of states the iconfile contains: + * - 1: normal + * - 2: normal, hover + * - 3: normal, hover, down + * - 4: normal, hover, down, disabled + * - The `imagesize` argument specifies how high or wide each icon is inside the + * map, depending on the `mapdirection` argument. + * {: #multiStateDoc} + * + * #### Example + * + * Here's a three state picture where each state is 16px high, vertically spaced: + * + * ```xml + * background="threestates.gif|vertical|3|16" + * ``` + */ + this.$propHandlers["background"] = function(value) { + var oNode = this.$getLayoutNode("main", "background", this.$ext); + + if (!oNode) return; + + + if (value) { + var b = value.split("|"); + this.$background = b.concat(["vertical", 2, 16].slice(b.length - 1)); + + oNode.style.backgroundImage = "url(" + this.mediaPath + b[0] + ")"; + oNode.style.backgroundRepeat = "no-repeat"; + } + else { + oNode.style.backgroundImage = ""; + oNode.style.backgroundRepeat = ""; + this.$background = null; + } + }; + + // *** Keyboard Support *** // + + + this.addEventListener("keydown", function(e) { + var key = e.keyCode; + //var ctrlKey = e.ctrlKey; << UNUSED + //var shiftKey = e.shiftKey; << UNUSED + + switch (key) { + case 13: + if (this.localName != "checkbox") + this.$ext.onmouseup(e.htmlEvent, true); + break; + case 32: + if (!e.htmlEvent.repeat) { // Only when first pressed, not on autorepeat. + this.$refKeyDown++; + this.$updateState(e.htmlEvent); + } + return false; + } + }, true); + + this.addEventListener("keyup", function(e) { + var key = e.keyCode; + + switch (key) { + case 32: + this.$refKeyDown--; + + if (this.$refKeyDown < 0) { + this.$refKeyDown = 0; + return false; + } + + if (this.$refKeyDown + this.$refMouseDown == 0 && !this.disabled) + this.$ext.onmouseup(e, true); + + this.$updateState(e); + return false; + } + }, true); + + + // *** Private state handling methods *** // + + this.states = { + "Out" : 1, + "Over" : 2, + "Down" : 3 + }; + + this.$updateState = function(e, strEvent) { + if (e.reset) { //this.disabled || + this.$refKeyDown = 0; + this.$refMouseDown = 0; + this.$mouseOver = false; + return false; + } + + if (this.$refKeyDown > 0 + || (this.$refMouseDown > 0 && (this.$mouseOver || (!apf.isIE && this.$ext === e.currentTarget))) + || (this.isBoolean && this.value)) { + this.$setState("Down", e, strEvent); + } + else if (this.$mouseOver) { + this.$setState("Over", e, strEvent); + } + else + this.$setState("Out", e, strEvent); + }; + + this.$setupEvents = function() { + if (this.editable) + return; + + var _self = this; + + this.$ext.onmousedown = function(e) { + e = e || window.event; + + if (_self.$notfromext && (e.srcElement || e.target) == this) + return; + + _self.$refMouseDown = 1; + _self.$mouseLeft = false; + + if (_self.disabled) + return; + + if (!apf.isIE) { // && (apf.isGecko || !_self.submenu) Causes a focus problem for menus + if (_self.value) + apf.stopEvent(e); + else + apf.cancelBubble(e); + } + + _self.$updateState(e, "mousedown"); + }; + + this.$ext.onmouseup = function(e, force) { + e = e || window.event; + //if (e) e.cancelBubble = true; + if (_self.disabled || !force && ((!_self.$mouseOver && (!apf.isIE && this !== e.currentTarget)) || !_self.$refMouseDown)) + return; + + _self.$refMouseDown = 0; + _self.$updateState(e, "mouseup"); + + // If this is coming from a mouse click, we shouldn't have left the button. + if (_self.disabled || (e && e.type == "click" && _self.$mouseLeft == true)) + return false; + + // If there are still buttons down, this is not a real click. + if (_self.$refMouseDown + _self.$refKeyDown) + return false; + + if (_self.$clickHandler && _self.$clickHandler()) + _self.$updateState (e || event, "click"); + else + _self.dispatchEvent("click", {htmlEvent : e}); + + return false; + }; + + this.$ext.onmousemove = function(e) { + if ((!_self.$mouseOver || _self.$mouseOver == 2)) { + e = e || window.event; + + if (_self.$notfromext && (e.srcElement || e.target) == this) + return; + + _self.$mouseOver = true; + + if (!_self.disabled) + _self.$updateState(e, "mouseover"); + } + }; + + this.$ext.onmouseout = function(e) { + e = e || window.event; + + //Check if the mouse out is meant for us + var tEl = e.explicitOriginalTarget || e.toElement; + if (apf.isChildOf(this, tEl)) //this == tEl || + return; + + _self.$mouseOver = false; + _self.$refMouseDown = 0; + _self.$mouseLeft = true; + + if (!_self.disabled) + _self.$updateState(e, "mouseout"); + }; + + + + if (apf.hasClickFastBug) + this.$ext.ondblclick = this.$ext.onmouseup; + }; + + this.$doBgSwitch = function(nr) { + if (this.background && (this.$background[2] >= nr || nr == 4)) { + if (nr == 4) + nr = this.$background[2] + 1; + + var strBG = this.$background[1] == "vertical" + ? "0 -" + (parseInt(this.$background[3]) * (nr - 1)) + "px" + : "-" + (parseInt(this.$background[3]) * (nr - 1)) + "px 0"; + + this.$getLayoutNode("main", "background", + this.$ext).style.backgroundPosition = strBG; + } + }; + + // *** Focus Handling *** // + + this.$focus = function(){ + if (!this.$ext) + return; + + this.$setStyleClass(this.$ext, this.$baseCSSname + "Focus"); + }; + + this.$blur = function(e) { + if (!this.$ext) + return; //FIREFOX BUG! + + this.$setStyleClass(this.$ext, "", [this.$baseCSSname + "Focus"]); + /*this.$refKeyDown = 0; + this.$refMouseDown = 0; + this.$mouseLeft = true;*/ + + + /*if (this.submenu) { + if (this.value) { + this.$setState("Down", {}, "mousedown"); + this.$hideMenu(); + } + }*/ + + + if (e) + this.$updateState({});//, "onblur" + }; + + this.addEventListener("prop.disabled", function(e) { + this.$refKeyDown = + this.$refMouseDown = 0; + //this.$mouseOver = + //this.$mouseLeft = false; + }); + + /*** Clearing potential memory leaks ****/ + + this.$destroy = function(skinChange) { + if (!skinChange && this.$ext) { + this.$ext.onmousedown = this.$ext.onmouseup = this.$ext.onmouseover = + this.$ext.onmouseout = this.$ext.onclick = this.$ext.ondblclick = null; + } + }; + +}).call(apf.BaseButton.prototype = new apf.StandardBinding()); + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * The baseclass of elements that allows the user to select one or more items + * out of a list. + * + * @class apf.BaseList + * @baseclass + * + * @inherits apf.MultiSelect + * @inherits apf.Cache + * @inherits apf.DataAction + * @inheritsElsewhere apf.XForms + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.8 + * @default_private + * + */ +/** + * @binding caption Determines the caption of a node. + */ +/** + * @binding icon Determines the icon of a node. +* + * This binding rule is used + * to determine the icon displayed when using a list skin. The {@link baseclass.baselist.binding.image image binding} + * is used to determine the image in the thumbnail skin. + */ +/** + * @binding image Determines the image of a node. + * + * This binding rule is used + * to determine the image displayed when using a thumbnail skin. The {@link baseclass.baselist.binding.icon icon binding} + * is used to determine the icon in the list skin. + * + * #### Example + * + * In this example, the image URL is read from the thumbnail attribute of the data node. + * + * ```xml + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * ``` + * + */ +/** + * @binding css Determines a CSS class for a node. + * + * #### Example + * + * In this example a node is bold when the folder contains unread messages: + * + * ```xml + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * ``` + * + */ +/** + * @binding tooltip Determines the tooltip of a node. + */ +/** + * @event notunique Fires when the `more` attribute is set and an item is added that has a caption that already exists in the list. + * @param {Object} e The standard event object, with the following properties: + * - value ([[String]]): The value that was entered + */ +apf.BaseList = function(){ + this.$init(true); + + + this.$dynCssClasses = []; + + + this.listNodes = []; +}; + +(function() { + + this.implement( + + apf.Cache, + + + apf.DataAction, + + + apf.K + ); + + + // *** Properties and Attributes *** // + + this.$focussable = true; // This object can get the focus + this.$isWindowContainer = -1; + + this.multiselect = true; // Initially Disable MultiSelect + + /** + * @attribute {String} fill Sets or gets the set of items that should be loaded into this + * element. Items are seperated by a comma (`,`). Ranges are specified by a start and end value seperated by a dash (`-`). + * + * #### Example + * + * This example loads a list with items starting at 1980 and ending at 2050. It also loads several other items and ranges. + * + * ```xml + * + * + * + * + * + + * ``` + */ + this.$propHandlers["fill"] = function(value) { + if (value) + this.loadFillData(this.getAttribute("fill")); + else + this.clear(); + }; + + + + /** + * @attribute {String} mode Sets or gets the way this element interacts with the user. + * + * The following values are possible: + * + * - `check`: the user can select a single item from this element. The selected item is indicated. + * - `radio`: the user can select multiple items from this element. Each selected item is indicated. + */ + this.$mode = 0; + this.$propHandlers["mode"] = function(value) { + if ("check|radio".indexOf(value) > -1) { + if (!this.hasFeature(apf.__MULTICHECK__)) + this.implement(apf.MultiCheck); + + this.addEventListener("afterrename", $afterRenameMode); //what does this do? + + this.multicheck = value == "check"; //radio is single + this.$mode = this.multicheck ? 1 : 2; + } + else { + //@todo undo actionRules setting + this.removeEventListener("afterrename", $afterRenameMode); + //@todo unimplement?? + this.$mode = 0; + } + }; + + //@todo apf3.0 retest this completely + function $afterRenameMode(){ + } + + + + // *** Keyboard support *** // + + + + //Handler for a plane list + this.$keyHandler = function(e) { + var key = e.keyCode, + ctrlKey = e.ctrlKey, + shiftKey = e.shiftKey, + selHtml = this.$caret || this.$selected; + + if (e.returnValue == -1 || !selHtml || this.renaming) //@todo how about allowdeselect? + return; + + var selXml = this.caret || this.selected, + oExt = this.$ext, + // variables used in the switch statement below: + node, margin, items, lines, hasScroll, hasScrollX, hasScrollY; + + switch (key) { + case 13: + if (this.$tempsel) + this.$selectTemp(); + + if (this.ctrlselect == "enter") + this.select(this.caret, true); + + this.choose(this.selected); + break; + case 32: + if (ctrlKey || !this.isSelected(this.caret)) + this.select(this.caret, ctrlKey); + break; + case 109: + case 46: + //DELETE + if (this.disableremove) + return; + + if (this.$tempsel) + this.$selectTemp(); + + this.remove(); + break; + case 36: + //HOME + var node = this.getFirstTraverseNode(); + + + if (this.hasFeature(apf.__VIRTUALVIEWPORT__)) + return this.$viewport.scrollIntoView(node); + + + this.select(node, false, shiftKey); + this.$container.scrollTop = 0; + break; + case 35: + //END + var node = this.getLastTraverseNode(); + + + if (this.hasFeature(apf.__VIRTUALVIEWPORT__)) + return this.$viewport.scrollIntoView(node, true); + + + this.select(node, false, shiftKey); + this.$container.scrollTop = this.$container.scrollHeight; + break; + case 107: + //+ + if (this.more) + this.startMore(); + break; + case 37: + //LEFT + if (!selXml && !this.$tempsel) + return; + + node = this.$tempsel + ? apf.xmldb.getNode(this.$tempsel) + : selXml; + margin = apf.getBox(apf.getStyle(selHtml, "margin")); + items = selHtml.offsetWidth + ? Math.floor((oExt.offsetWidth + - (hasScroll ? 15 : 0)) / (selHtml.offsetWidth + + margin[1] + margin[3])) + : 1; + + //margin = apf.getBox(apf.getStyle(selHtml, "margin")); + + node = this.getNextTraverseSelected(node, false); + if (node) + this.$setTempSelected(node, ctrlKey, shiftKey, true); + else + return; + + selHtml = apf.xmldb.findHtmlNode(node, this); + if (selHtml.offsetTop < oExt.scrollTop) { + oExt.scrollTop = Array.prototype.indexOf.call(this.getTraverseNodes(), node) < items + ? 0 + : selHtml.offsetTop - margin[0]; + } + break; + case 38: + //UP + if (!selXml && !this.$tempsel) + return; + + node = this.$tempsel + ? apf.xmldb.getNode(this.$tempsel) + : selXml; + + margin = apf.getBox(apf.getStyle(selHtml, "margin")); + hasScroll = oExt.scrollHeight > oExt.offsetHeight; + items = selHtml.offsetWidth + ? Math.floor((oExt.offsetWidth + - (hasScroll ? 15 : 0)) / (selHtml.offsetWidth + + margin[1] + margin[3])) + : 1; + + node = this.getNextTraverseSelected(node, false, items); + if (node) + this.$setTempSelected (node, ctrlKey, shiftKey, true); + else + return; + + + if (this.hasFeature(apf.__VIRTUALVIEWPORT__)) + return this.$viewport.scrollIntoView(node); + + + selHtml = apf.xmldb.findHtmlNode(node, this); + if (selHtml.offsetTop < oExt.scrollTop) { + oExt.scrollTop = Array.prototype.indexOf.call(this.getTraverseNodes(), node) < items + ? 0 + : selHtml.offsetTop - margin[0]; + } + break; + case 39: + //RIGHT + if (!selXml && !this.$tempsel) + return; + + node = this.$tempsel + ? apf.xmldb.getNode(this.$tempsel) + : selXml; + margin = apf.getBox(apf.getStyle(selHtml, "margin")); + node = this.getNextTraverseSelected(node, true); + if (node) + this.$setTempSelected (node, ctrlKey, shiftKey); + else + return; + + selHtml = apf.xmldb.findHtmlNode(node, this); + if (selHtml.offsetTop + selHtml.offsetHeight + > oExt.scrollTop + oExt.offsetHeight) { + oExt.scrollTop = selHtml.offsetTop + - oExt.offsetHeight + selHtml.offsetHeight + + margin[0]; + } + break; + case 40: + //DOWN + if (!selXml && !this.$tempsel) + return; + + node = this.$tempsel + ? apf.xmldb.getNode(this.$tempsel) + : selXml; + + margin = apf.getBox(apf.getStyle(selHtml, "margin")); + hasScroll = oExt.scrollHeight > oExt.offsetHeight; + items = selHtml.offsetWidth + ? Math.floor((oExt.offsetWidth + - (hasScroll ? 15 : 0)) / (selHtml.offsetWidth + + margin[1] + margin[3])) + : 1; + + node = this.getNextTraverseSelected(node, true, items); + if (node) + this.$setTempSelected (node, ctrlKey, shiftKey); + else + return; + + + if (this.hasFeature(apf.__VIRTUALVIEWPORT__)) + return this.$viewport.scrollIntoView(node, true); + + + selHtml = apf.xmldb.findHtmlNode(node, this); + if (selHtml.offsetTop + selHtml.offsetHeight + > oExt.scrollTop + oExt.offsetHeight) { // - (hasScroll ? 10 : 0) + oExt.scrollTop = selHtml.offsetTop + - oExt.offsetHeight + selHtml.offsetHeight + + margin[0]; //+ (hasScroll ? 10 : 0) + } + break; + case 33: + //PGUP + if (!selXml && !this.$tempsel) + return; + + node = this.$tempsel + ? apf.xmldb.getNode(this.$tempsel) + : selXml; + + margin = apf.getBox(apf.getStyle(selHtml, "margin")); + hasScrollY = oExt.scrollHeight > oExt.offsetHeight; + hasScrollX = oExt.scrollWidth > oExt.offsetWidth; + items = Math.floor((oExt.offsetWidth + - (hasScrollY ? 15 : 0)) / (selHtml.offsetWidth + + margin[1] + margin[3])); + lines = Math.floor((oExt.offsetHeight + - (hasScrollX ? 15 : 0)) / (selHtml.offsetHeight + + margin[0] + margin[2])); + + node = this.getNextTraverseSelected(node, false, items * lines); + if (!node) + node = this.getFirstTraverseNode(); + if (node) + this.$setTempSelected (node, ctrlKey, shiftKey, true); + else + return; + + + if (this.hasFeature(apf.__VIRTUALVIEWPORT__)) + return this.$viewport.scrollIntoView(node); + + + selHtml = apf.xmldb.findHtmlNode(node, this); + if (selHtml.offsetTop < oExt.scrollTop) { + oExt.scrollTop = Array.prototype.indexOf.call(this.getTraverseNodes(), node) < items + ? 0 + : selHtml.offsetTop - margin[0]; + } + break; + case 34: + //PGDN + if (!selXml && !this.$tempsel) + return; + + node = this.$tempsel + ? apf.xmldb.getNode(this.$tempsel) + : selXml; + + margin = apf.getBox(apf.getStyle(selHtml, "margin")); + hasScrollY = oExt.scrollHeight > oExt.offsetHeight; + hasScrollX = oExt.scrollWidth > oExt.offsetWidth; + items = Math.floor((oExt.offsetWidth - (hasScrollY ? 15 : 0)) + / (selHtml.offsetWidth + margin[1] + margin[3])); + lines = Math.floor((oExt.offsetHeight - (hasScrollX ? 15 : 0)) + / (selHtml.offsetHeight + margin[0] + margin[2])); + + node = this.getNextTraverseSelected(selXml, true, items * lines); + if (!node) + node = this.getLastTraverseNode(); + if (node) + this.$setTempSelected (node, ctrlKey, shiftKey); + else + return; + + + if (this.hasFeature(apf.__VIRTUALVIEWPORT__)) + return this.$viewport.scrollIntoView(node, true); + + + selHtml = apf.xmldb.findHtmlNode(node, this); + if (selHtml.offsetTop + selHtml.offsetHeight + > oExt.scrollTop + oExt.offsetHeight) { // - (hasScrollY ? 10 : 0) + oExt.scrollTop = selHtml.offsetTop + - oExt.offsetHeight + selHtml.offsetHeight + + margin[0]; //+ 10 + (hasScrollY ? 10 : 0) + } + break; + + default: + if (key == 65 && ctrlKey) { + this.selectAll(); + } + else if (this.$hasBindRule("caption")) { + if (!this.xmlRoot || this.autorename) return; + + //this should move to a onkeypress based function + if (!this.lookup || new Date().getTime() + - this.lookup.date.getTime() > 300) { + this.lookup = { + str: "", + date: new Date() + }; + } + + this.lookup.str += String.fromCharCode(key); + + var nodes = this.getTraverseNodes(); //@todo start at current indicator + for (var v, i = 0; i < nodes.length; i++) { + v = this.$applyBindRule("caption", nodes[i]); + if (v && v.substr(0, this.lookup.str.length) + .toUpperCase() == this.lookup.str) { + + if (!this.isSelected(nodes[i])) { + this.select(nodes[i]); + } + + if (selHtml) { + this.$container.scrollTop = selHtml.offsetTop + - (this.$container.offsetHeight + - selHtml.offsetHeight) / 2; + } + return; + } + } + return; + } + break; + } + + this.lookup = null; + return false; + }; + + + + // *** Private databinding functions *** // + + this.$deInitNode = function(xmlNode, htmlNode) { + if (!htmlNode) return; + + //Remove htmlNodes from tree + htmlNode.parentNode.removeChild(htmlNode); + }; + + this.$updateNode = function(xmlNode, htmlNode, noModifier) { + //Update Identity (Look) + var elIcon = this.$getLayoutNode("item", "icon", htmlNode); + + if (elIcon) { + if (elIcon.nodeType == 1) { + elIcon.style.backgroundImage = "url(" + + apf.getAbsolutePath(this.iconPath, + this.$applyBindRule("icon", xmlNode)) + ")"; + } + else { + elIcon.nodeValue = apf.getAbsolutePath(this.iconPath, + this.$applyBindRule("icon", xmlNode)); + } + } + else { + //.style.backgroundImage = "url(" + this.$applyBindRule("image", xmlNode) + ")"; + var elImage = this.$getLayoutNode("item", "image", htmlNode); + if (elImage) { + if (elImage.nodeType == 1) { + elImage.style.backgroundImage = "url(" + + apf.getAbsolutePath(apf.hostPath, + this.$applyBindRule("image", xmlNode)) + ")"; + } + else { + elImage.nodeValue = apf.getAbsolutePath(apf.hostPath, + this.$applyBindRule("image", xmlNode)); + } + } + } + + var elCaption = this.$getLayoutNode("item", "caption", htmlNode); + if (elCaption) { + if (elCaption.nodeType == 1) { + + elCaption.innerHTML = this.$applyBindRule("caption", xmlNode); + } + else + elCaption.nodeValue = this.$applyBindRule("caption", xmlNode); + } + + + //@todo + + + htmlNode.title = this.$applyBindRule("title", xmlNode) || ""; + + + var cssClass = this.$applyBindRule("css", xmlNode); + + if (cssClass || this.$dynCssClasses.length) { + this.$setStyleClass(htmlNode, cssClass, this.$dynCssClasses); + if (cssClass && !this.$dynCssClasses.contains(cssClass)) { + this.$dynCssClasses.push(cssClass); + } + } + + + if (!noModifier && this.$updateModifier) + this.$updateModifier(xmlNode, htmlNode); + }; + + this.$moveNode = function(xmlNode, htmlNode) { + if (!htmlNode) return; + + var oPHtmlNode = htmlNode.parentNode; + var nNode = this.getNextTraverse(xmlNode); //@todo could optimize because getTraverseNodes returns array indexOf + var beforeNode = nNode + ? apf.xmldb.findHtmlNode(nNode, this) + : null; + + oPHtmlNode.insertBefore(htmlNode, beforeNode); + //if(this.emptyMessage && !oPHtmlNode.childNodes.length) this.setEmpty(oPHtmlNode); + }; + + this.$add = function(xmlNode, Lid, xmlParentNode, htmlParentNode, beforeNode) { + //Build Row + this.$getNewContext("item"); + var oItem = this.$getLayoutNode("item"), + elSelect = this.$getLayoutNode("item", "select"), + elIcon = this.$getLayoutNode("item", "icon"), + elImage = this.$getLayoutNode("item", "image"), + //elCheckbox = this.$getLayoutNode("item", "checkbox"), // NOT USED + elCaption = this.$getLayoutNode("item", "caption"); + + oItem.setAttribute("id", Lid); + + elSelect.setAttribute("onmouseover", "var o = apf.lookup(" + this.$uniqueId + + "); o.$setStyleClass(this, 'hover', null, true);"); + elSelect.setAttribute("onselectstart", "return false;"); + elSelect.setAttribute("style", (elSelect.getAttribute("style") || "") + + ";user-select:none;-moz-user-select:none;-webkit-user-select:none;"); + + if (this.hasFeature(apf.__RENAME__) || this.hasFeature(apf.__DRAGDROP__)) { + elSelect.setAttribute("ondblclick", "var o = apf.lookup(" + this.$uniqueId + "); " + + + "o.stopRename();" + + + " o.choose()"); + elSelect.setAttribute("onmouseout", "var o = apf.lookup(" + this.$uniqueId + ");\ + o.$setStyleClass(this, '', ['hover'], true);\ + this.hasPassedDown = false;"); + elSelect.setAttribute(this.itemSelectEvent || "onmousedown", + 'var o = apf.lookup(' + this.$uniqueId + ');\ + var xmlNode = apf.xmldb.findXmlNode(this);\ + var isSelected = o.isSelected(xmlNode);\ + this.hasPassedDown = true;\ + if (event.button == 2) \ + o.stopRename();\ + else if (!o.renaming && o.hasFocus() && isSelected == 1) \ + this.dorename = true;\ + if (event.button == 2 && isSelected)\ + return;\ + if (!o.hasFeature(apf.__DRAGDROP__) || !isSelected && !event.ctrlKey)\ + o.select(this, event.ctrlKey, event.shiftKey, -1)'); + elSelect.setAttribute("onmouseup", 'if (!this.hasPassedDown) return;\ + var o = apf.lookup(' + this.$uniqueId + ');' + + + 'if (o.hasFeature(apf.__RENAME__) && this.dorename)\ + o.startDelayedRename(event, null, true);' + + + 'this.dorename = false;\ + var xmlNode = apf.xmldb.findXmlNode(this);\ + var isSelected = o.isSelected(xmlNode);\ + if (o.hasFeature(apf.__DRAGDROP__))\ + o.select(this, event.ctrlKey, event.shiftKey, -1)'); + } //@todo add DRAGDROP ifdefs + else { + elSelect.setAttribute("onmouseout", "apf.setStyleClass(this, '', ['hover']);"); + elSelect.setAttribute("ondblclick", 'var o = apf.lookup(' + + this.$uniqueId + '); o.choose(null, true)'); + elSelect.setAttribute(this.itemSelectEvent + || "onmousedown", 'var o = apf.lookup(' + this.$uniqueId + + '); o.select(this, event.ctrlKey, event.shiftKey, -1)'); + } + + + + + if (this.$mode) { + var elCheck = this.$getLayoutNode("item", "check"); + if (elCheck) { + elCheck.setAttribute("onmousedown", + "var o = apf.lookup(" + this.$uniqueId + ");\ + o.checkToggle(this, true);\o.$skipSelect = true;"); + + if (apf.isTrue(this.$applyBindRule("checked", xmlNode))) { + this.$checkedList.push(xmlNode); + this.$setStyleClass(oItem, "checked"); + } + else if (this.isChecked(xmlNode)) + this.$setStyleClass(oItem, "checked"); + } + else { + + return false; + } + } + + + //Setup Nodes Identity (Look) + if (elIcon) { + if (elIcon.nodeType == 1) { + elIcon.setAttribute("style", "background-image:url(" + + apf.getAbsolutePath(this.iconPath, this.$applyBindRule("icon", xmlNode)) + + ")"); + } + else { + elIcon.nodeValue = apf.getAbsolutePath(this.iconPath, + this.$applyBindRule("icon", xmlNode)); + } + } + else if (elImage) { + if (elImage.nodeType == 1) { + if ((elImage.tagName || "").toLowerCase() == "img") { + elImage.setAttribute("src", apf.getAbsolutePath(apf.hostPath, this.$applyBindRule("image", xmlNode))); + } + else { + elImage.setAttribute("style", "background-image:url(" + + apf.getAbsolutePath(apf.hostPath, this.$applyBindRule("image", xmlNode)) + + ")"); + } + } + else { + if (apf.isSafariOld) { //@todo this should be changed... blrgh.. + var p = elImage.ownerElement.parentNode, + img = p.appendChild(p.ownerDocument.createElement("img")); + img.setAttribute("src", + apf.getAbsolutePath(apf.hostPath, this.$applyBindRule("image", xmlNode))); + } + else { + elImage.nodeValue = + apf.getAbsolutePath(apf.hostPath, this.$applyBindRule("image", xmlNode)); + } + } + } + + if (elCaption) { + + { + apf.setNodeValue(elCaption, + this.$applyBindRule("caption", xmlNode)); + } + } + oItem.setAttribute("title", this.$applyBindRule("tooltip", xmlNode) || ""); + + + var cssClass = this.$applyBindRule("css", xmlNode); + if (cssClass) { + this.$setStyleClass(oItem, cssClass); + if (cssClass) + this.$dynCssClasses.push(cssClass); + } + + + if (this.$addModifier && + this.$addModifier(xmlNode, oItem, htmlParentNode, beforeNode) === false) + return; + + if (htmlParentNode) + apf.insertHtmlNode(oItem, htmlParentNode, beforeNode); + else + this.listNodes.push(oItem); + }; + + this.addEventListener("$skinchange", function(e) { + if (this.more) + delete this.moreItem; + }); + + this.$fill = function(){ + if (this.more && !this.moreItem) { + this.$getNewContext("item"); + var Item = this.$getLayoutNode("item"), + elCaption = this.$getLayoutNode("item", "caption"), + elSelect = this.$getLayoutNode("item", "select"); + + Item.setAttribute("class", this.$baseCSSname + "More"); + elSelect.setAttribute("onmousedown", 'var o = apf.lookup(' + this.$uniqueId + + ');o.clearSelection();o.$setStyleClass(this, "more_down", null, true);'); + elSelect.setAttribute("onmouseout", 'apf.lookup(' + this.$uniqueId + + ').$setStyleClass(this, "", ["more_down"], true);'); + elSelect.setAttribute("onmouseup", 'apf.lookup(' + this.$uniqueId + + ').startMore(this, true)'); + + if (elCaption) + apf.setNodeValue(elCaption, + this.more.match(/caption:(.*)(;|$)/i)[1]); + this.listNodes.push(Item); + } + + apf.insertHtmlNodes(this.listNodes, this.$container); + this.listNodes.length = 0; + + if (this.more && !this.moreItem) { + this.moreItem = this.$container.lastChild; + } + + }; + + /** + * Adds a new item to the list, and lets the users type in the new name. + * + * This functionality is especially useful in the interface when + * the list mode is set to `check` or `radio`--for instance in a form. + */ + this.startMore = function(o, userAction) { + if (userAction && this.disabled) + return; + + this.$setStyleClass(o, "", ["more_down"]); + + var xmlNode; + if (!this.$actions["add"]) { + if (this.each && !this.each.match(/[\/\[]/)) { + xmlNode = "<" + this.each + (this.each.match(/^a:/) + ? " xmlns:a='" + apf.ns.aml + "'" + : "") + " custom='1' />"; + } + else { + + //return false; + xmlNode = ""; + } + } + + this.add(xmlNode, null, null, function(addedNode) { + this.select(addedNode, null, null, null, null, true); + if (this.morePos == "begin") + this.$container.insertBefore(this.moreItem, this.$container.firstChild); + else + this.$container.appendChild(this.moreItem); + + var undoLastAction = function(){ + this.getActionTracker().undo(this.autoselect ? 2 : 1); + + this.removeEventListener("stoprename", undoLastAction); + this.removeEventListener("beforerename", removeSetRenameEvent); + this.removeEventListener("afterrename", afterRename); + } + var afterRename = function(){ + //this.select(addedNode); + this.removeEventListener("afterrename", afterRename); + }; + var removeSetRenameEvent = function(e) { + this.removeEventListener("stoprename", undoLastAction); + this.removeEventListener("beforerename", removeSetRenameEvent); + + //There is already a choice with the same value + var xmlNode = this.findXmlNodeByValue(e.args[1]); + if (xmlNode || !e.args[1]) { + if (e.args[1] && this.dispatchEvent("notunique", { + value: e.args[1] + }) === false) { + this.startRename(); + + this.addEventListener("stoprename", undoLastAction); + this.addEventListener("beforerename", removeSetRenameEvent); + } + else { + this.removeEventListener("afterrename", afterRename); + + this.getActionTracker().undo();//this.autoselect ? 2 : 1); + if (!this.isSelected(xmlNode)) + this.select(xmlNode); + } + + return false; + } + }; + + this.addEventListener("stoprename", undoLastAction); + this.addEventListener("beforerename", removeSetRenameEvent); + this.addEventListener("afterrename", afterRename); + + + this.startDelayedRename({}, 1); + + }); + }; + + // *** Selection *** // + + this.$calcSelectRange = function(xmlStartNode, xmlEndNode) { + var r = [], + nodes = this.hasFeature(apf.__VIRTUALVIEWPORT__) + ? this.xmlRoot.selectNodes(this.each) + : this.getTraverseNodes(), + f, i; + for (f = false, i = 0; i < nodes.length; i++) { + if (nodes[i] == xmlStartNode) + f = true; + if (f) + r.push(nodes[i]); + if (nodes[i] == xmlEndNode) + f = false; + } + + if (!r.length || f) { + r = []; + for (f = false, i = nodes.length - 1; i >= 0; i--) { + if (nodes[i] == xmlStartNode) + f = true; + if (f) + r.push(nodes[i]); + if (nodes[i] == xmlEndNode) + f = false; + } + } + + return r; + }; + + this.$selectDefault = function(XMLRoot) { + this.select(this.getTraverseNodes()[0], null, null, null, true); + }; + + /** + * Generates a list of items based on a string. + * @param {String} str The description of the items. Items are seperated by a comma (`,`). Ranges are specified by a start and end value seperated by a dash (`-`). + * + * #### Example + * + * This example loads a list with items starting at 1980 and ending at 2050. + * + * #### ```xml + * lst.loadFillData("1980-2050"); + * lst.loadFillData("red,green,blue,white"); + * lst.loadFillData("None,100-110,1000-1100"); // 101, 102...110, 1000,1001, e.t.c. + * lst.loadFillData("1-10"); // 1 2 3 4 e.t.c. + * lst.loadFillData("01-10"); //01, 02, 03, 04, e.t.c. + * ``` + */ + this.loadFillData = function(str) { + var len, start, end, parts = str.splitSafe(","), data = []; + + for (var p, part, i = 0; i < parts.length; i++) { + if ((part = parts[i]).match(/^\d+-\d+$/)) { + p = part.split("-"); + start = parseInt(p[0]); + end = parseInt(p[1]); + + if (p[0].length == p[1].length) { + len = Math.max(p[0].length, p[1].length); + for (var j = start; j < end + 1; j++) { + data.push("" + (j + "").pad(len, "0") + ""); + } + } + else { + for (var j = start; j < end + 1; j++) { + data.push("" + j + ""); + } + } + } + else { + data.push("" + part + ""); + } + } + + //@todo this is all an ugly hack (copied from item.js line 486) + //this.$preventDataLoad = true;//@todo apf3.0 add remove for this + + this.$initingModel = true; + + this.each = "item"; + this.$setDynamicProperty("caption", "[label/text()|@caption|text()]"); + this.$setDynamicProperty("eachvalue", "[value/text()|@value|text()]"); + this.$canLoadDataAttr = false; + + this.load("" + data.join("") + ""); + }; + +}).call(apf.BaseList.prototype = new apf.MultiSelect()); + + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +/** + * Baseclass of a simple element. These are usually displaying elements + * (_i.e._ {@link apf.label}, {@link apf.img}) + * + * @class apf.BaseSimple + * @baseclass + * + * @inherits apf.StandardBinding + * @inherits apf.DataAction + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.8 + */ +apf.BaseSimple = function(){ + this.$init(true); +}; + +(function() { + + this.implement(apf.DataAction); + + + this.getValue = function(){ + return this.value; + }; + +}).call(apf.BaseSimple.prototype = new apf.StandardBinding()); + + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +/** + * The base class for state buttons. + * + * @class apf.BaseStateButtons + * @baseclass + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.8 + */ +apf.BaseStateButtons = function(){ + this.state = "normal"; + this.edit = false; + + var actions = { + "min" : ["minimized", "minimize", "restore"], + "max" : ["maximized", "maximize", "restore"], + "edit" : ["edit", "edit", "closeedit"], + "close" : ["closed", "close", "show"] + }; + this.$lastheight = null; + this.$lastpos = null; + + this.$lastState = {"normal":true}; + this.$booleanProperties["animate"] = true; + this.$supportedProperties.push("buttons", "animate", "state"); + + /** + * Close the window. It can be reopened by using {@link apf.GuiElement.show} + * @chainable + */ + this.close = function(){ // @todo show should unset closed + this.setProperty("state", this.state.split("|") + .pushUnique("closed").join("|"), false, true); + return this; + }; + + /** + * Minimize the window. The window will become the height of the title of + * the parent window. + * @chainable + */ + this.minimize = function(){ + this.setProperty("state", this.state.split("|") + .remove("maximized") + .remove("normal") + .pushUnique("minimized").join("|"), false, true); + return this; + }; + + /** + * Maximize the window. The window will become the width and height of the + * browser window. + * @chainable + */ + this.maximize = function(){ + this.setProperty("state", this.state.split("|") + .remove("minimized") + .remove("normal") + .pushUnique("maximized").join("|"), false, true); + return this; + }; + + /** + * Restore the size of the window. The window will become the width and + * height it had before it was minimized or maximized. + * @chainable + */ + this.restore = function(){ + this.setProperty("state", this.state.split("|") + .remove("minimized") + .remove("maximized") + .pushUnique("normal").join("|"), false, true); + return this; + }; + + /** + * Set the window into edit state. The configuration panel is shown. + * @chainable + */ + this.edit = function(value) { + this.setProperty("state", this.state.split("|") + .pushUnique("edit").join("|"), false, true); + return this; + }; + + /** + * Removes the edit state of this window. The configuration panel is hidden. + * @chainable + */ + this.closeedit = function(value) { + this.setProperty("state", this.state.split("|") + .remove("edit").join("|"), false, true); + return this; + }; + + this.$toggle = function(type) { + var c = actions[type][0]; + this[actions[type][this.state.indexOf(c) > -1 ? 2 : 1]](); + }; + + this.$propHandlers["refparent"] = function(value) { + if (typeof value == "string") + this.$refParent = self[value] && self[value].$ext || document.getElementById(value); + else this.$refParent = value; + } + + this.$propHandlers["maxconf"] = function(value) { + this.$maxconf = value.splitSafe(","); + } + + /** + * @attribute {String} state Sets or gets the state of the window. The state can be a + * combination of multiple states, seperated by a pipe (`'|'`) character. + * + * The possible values include: + * + * `"normal"`: The window has its normal size and position. This is the default value. + * `"minimized"`: The window is minimized. + * `"maximized"`: The window is maximized. + * `"edit"`: The window is in the edit state. + * `"closed"`: The window is closed. + */ + this.$propHandlers["state"] = function(value, prop, force, reenter, noanim) { + var _self = this; + if (!this.$amlLoaded) { //@todo I still think this is weird and should not be needed + apf.queue.add("state" + this.$uniqueId, function(){ + _self.$propHandlers["state"].call(_self, value, prop, force, reenter, noanim); + }); + return; + } + + if (value == 0) + value = "normal"; + + var i, pNode, position, l, t, + o = {}, + s = value.split("|"), + lastState = this.$lastState, + styleClass = []; + + for (i = 0; i < s.length; i++) + o[s[i]] = true; + o.value = value; + + if (!o.maximized && !o.minimized) + o.normal = true; + + if (!reenter && this.dispatchEvent("beforestatechange", { + from: lastState, + to: o}) === false) { + this.state = lastState.value; + return false; + } + + //Closed state + if (o.closed == this.visible) {//change detected + this.setProperty("visible", !o["closed"], false, true); + //@todo difference is, we're not clearing the other states, check the docking example + } + + //Restore state + if (o.normal != lastState.normal + || !o.normal && (o.minimized != lastState.minimized + || o.maximized != lastState.maximized)) { + + if (this.$lastheight != null) // this.aData && this.aData.hidden == 3 ?? + this.$ext.style.height = this.$lastheight;//(this.$lastheight - apf.getHeightDiff(this.$ext)) + "px"; + + if (this.$lastpos) { + apf.plane.hide(this.$uniqueId); + + if (this.animate && !noanim) { + //Pre remove paused event because of not having onresize + //if (apf.hasSingleRszEvent) + //delete apf.layout.onresize[apf.layout.getHtmlId(this.$pHtmlNode)]; + + var htmlNode = this.$ext; + position = apf.getStyle(htmlNode, "position"); + if (position != "absolute") { + l = parseInt(apf.getStyle(htmlNode, "left")) || 0; + t = parseInt(apf.getStyle(htmlNode, "top")) || 0; + } + else { + l = htmlNode.offsetLeft; + t = htmlNode.offsetTop; + } + + this.animstate = 1; + apf.tween.multi(htmlNode, { + steps: 15, + anim: apf.tween.easeInOutCubic, + interval: 10, + tweens: [ + {type: "left", from: l, to: this.$lastpos.px[0]}, + {type: "top", from: t, to: this.$lastpos.px[1]}, + {type: "width", from: this.$ext.offsetWidth, + to: this.$lastpos.px[2]}, + {type: "height", from: this.$ext.offsetHeight, + to: this.$lastpos.px[3]} + ], + oneach: function(){ + + if (apf.hasSingleRszEvent) + apf.layout.forceResize(_self.$int); + + }, + onfinish: function(){ + _self.$lastpos.parentNode.insertBefore(_self.$ext, _self.$lastpos.beforeNode); + + if (_self.$placeHolder) + _self.$placeHolder.parentNode.removeChild(_self.$placeHolder); + + _self.$propHandlers["state"].call(_self, value, null, + null, true, true); + } + }); + + return; + } + else if (!this.animate) { + apf.plane.hide(this.$uniqueId, true); + + _self.$lastpos.parentNode.insertBefore(_self.$ext, _self.$lastpos.beforeNode); + + if (_self.$placeHolder) + _self.$placeHolder.parentNode.removeChild(_self.$placeHolder); + } + + this.$ext.style.position = this.$lastpos.pos; + this.$ext.style.left = this.$lastpos.css[0]; + this.$ext.style.top = this.$lastpos.css[1]; + this.$ext.style.width = this.$lastpos.css[2]; + this.$ext.style.height = this.$lastpos.css[3]; + + pNode = this.$lastpos.parentNode; + pNode.style.width = this.$lastpos.parent[0]; + pNode.style.height = this.$lastpos.parent[1]; + pNode.style.overflow = this.$lastpos.parent[2]; + } + + + if (this.aData && this.aData.restore) + this.aData.restore(); + + + + if (apf.layout) + apf.layout.play(this.$pHtmlNode); + + + this.$lastheight = this.$lastpos = null; + + if (o.normal) + styleClass.push("", + this.$baseCSSname + "Max", + this.$baseCSSname + "Min"); + } + + if (o.minimized != lastState.minimized) { + if (o.minimized) { + styleClass.unshift( + this.$baseCSSname + "Min", + this.$baseCSSname + "Max", + this.$baseCSSname + "Edit"); + + + if (this.aData && this.aData.minimize) + this.aData.minimize(this.collapsedHeight); + + + if (!this.aData || !this.aData.minimize) { + this.$lastheight = this.$ext.style.height; //apf.getStyle(this.$ext, "height");//this.$ext.offsetHeight; + + this.$ext.style.height = Math.max(0, this.collapsedHeight + - apf.getHeightDiff(this.$ext)) + "px"; + } + + if (this.hasFocus()) + apf.window.moveNext(null, this, true); + //else if(apf.document.activeElement) + //apf.document.activeElement.$focus({mouse: true}); + } + else { + styleClass.push(this.$baseCSSname + "Min"); + + $setTimeout(function(){ + apf.window.$focusLast(_self); + }); + } + } + + if (o.maximized != lastState.maximized) { + if (o.maximized) { + styleClass.unshift( + this.$baseCSSname + "Max", + this.$baseCSSname + "Min", + this.$baseCSSname + "Edit"); + + pNode = this.$refParent; + if (!pNode) + pNode = (this.$ext.offsetParent == document.body + ? document.documentElement + : this.$ext.parentNode); + + this.animstate = 0; + var hasAnimated = false, htmlNode = this.$ext; + + var position = apf.getStyle(htmlNode, "position"); + if (position == "absolute") { + pNode.style.overflow = "hidden"; + l = htmlNode.offsetLeft; + t = htmlNode.offsetTop; + } + else { + var pos = apf.getAbsolutePosition(htmlNode); //pNode + l = pos[0];//parseInt(apf.getStyle(htmlNode, "left")) || 0; + t = pos[1];//parseInt(apf.getStyle(htmlNode, "top")) || 0; + } + + this.$lastpos = { + css: [this.$ext.style.left, this.$ext.style.top, + this.$ext.style.width, this.$ext.style.height, + this.$ext.style.margin, this.$ext.style.zIndex], + px: [l, t, this.$ext.offsetWidth, + this.$ext.offsetHeight], + parent: [pNode.style.width, pNode.style.height, + pNode.style.overflow], + pos: htmlNode.style.position, + parentNode: pNode, + beforeNode: this.$ext.nextSibling + }; + + if (this.parentNode.$layout) { + if (!this.$placeHolder) + this.$placeHolder = document.createElement("div"); + this.$placeHolder.style.position = this.$lastpos.pos; + this.$placeHolder.style.left = this.$lastpos.css[0]; + this.$placeHolder.style.top = this.$lastpos.css[1]; + this.$placeHolder.style.width = this.$lastpos.px[2] + "px"; + this.$placeHolder.style.height = this.$lastpos.px[3] + "px"; + this.$placeHolder.style.margin = this.$lastpos.css[4]; + this.$placeHolder.style.zIndex = this.$lastpos.css[5]; + this.$pHtmlNode.insertBefore(this.$placeHolder, this.$ext); + + htmlNode.style.position = "absolute"; + } + + document.body.appendChild(htmlNode); + htmlNode.style.left = l + "px"; + htmlNode.style.top = t + "px"; + + function setMax(){ + //While animating dont execute this function + if (_self.animstate) + return; + + var w, h, pos, box, pDiff; + if (_self.maxconf) { + w = _self.$maxconf[0]; + h = _self.$maxconf[1]; + + pos = [_self.$maxconf[2] == "center" + ? (apf.getWindowWidth() - w)/2 + : _self.$maxconf[2], + _self.$maxconf[3] == "center" + ? (apf.getWindowHeight() - h)/3 + : _self.$maxconf[3]]; + } + else { + w = !apf.isIE && pNode == document.documentElement + ? window.innerWidth + : pNode.offsetWidth, + h = !apf.isIE && pNode == document.documentElement + ? window.innerHeight + : pNode.offsetHeight; + } + + if (!pos) { + pos = pNode != htmlNode.offsetParent + ? apf.getAbsolutePosition(pNode, htmlNode.offsetParent) + : [0, 0]; + } + + if (position != "absolute") { + var diff = apf.getDiff(pNode); + w -= diff[0] + (!_self.$refParent && apf.isIE8 ? 4 : 0);//@todo dirty hack! + h -= diff[0] + (!_self.$refParent && apf.isIE8 ? 4 : 0);//@todo dirty hack! + } + //@todo dirty hack! + else if (!_self.$refParent && apf.isIE8) { + w -= 4; + h -= 4; + } + + box = _self.$refParent ? [0,0,0,0] : marginBox; + pDiff = apf.getDiff(pNode); + + pNode.style.width = (pNode.offsetWidth - pDiff[0]) + "px"; + pNode.style.height = (pNode.offsetHeight - pDiff[1]) + "px"; + + if (!hasAnimated && _self.$maxconf && _self.$maxconf[4]) + apf.plane.show(htmlNode, false, null, null, { + color: _self.$maxconf[4], + opacity: _self.$maxconf[5], + animate: _self.animate, + protect: _self.$uniqueId + }); + + if (_self.animate && !hasAnimated) { + _self.animstate = 1; + hasAnimated = true; + apf.tween.multi(htmlNode, { + steps: 15, + anim: apf.tween.easeInOutCubic, + interval: 10, + tweens: [ + {type: "left", from: l, to: pos[0] - box[3]}, + {type: "top", from: t, to: pos[1] - box[0]}, + {type: "width", from: _self.$lastpos.px[2], + to: (w + box[1] + box[3] - apf.getWidthDiff(_self.$ext))}, + {type: "height", from: _self.$lastpos.px[3], + to: (h + box[0] + box[2] - apf.getHeightDiff(_self.$ext))} + ], + oneach: function(){ + + if (apf.hasSingleRszEvent) + apf.layout.forceResize(_self.$int); + + }, + onfinish: function(){ + _self.animstate = 0; + + _self.dispatchEvent("afterstatechange", { + from: lastState, + to: o + }); + + + if (apf.hasSingleRszEvent) + apf.layout.forceResize(_self.$int); + + } + }); + } + else if (!_self.animstate) { + htmlNode.style.left = (pos[0] - box[3]) + "px"; + htmlNode.style.top = (pos[1] - box[0]) + "px"; + + var diff = apf.getDiff(_self.$ext); + htmlNode.style.width = (w + - diff[0] + box[1] + box[3]) + "px"; + htmlNode.style.height = (h + - diff[1] + box[0] + box[2]) + "px"; + } + } + + + if (apf.layout) + apf.layout.pause(this.$pHtmlNode, setMax); + + } + else { + styleClass.push(this.$baseCSSname + "Max"); + } + } + + if (o.edit != lastState.edit) { + if (o.edit) { + styleClass.unshift( + this.$baseCSSname + "Edit", + this.$baseCSSname + "Max", + this.$baseCSSname + "Min"); + + if (this.btnedit) + oButtons.edit.innerHTML = "close"; //hack + + this.dispatchEvent('editstart'); + } + else { + if (this.dispatchEvent('editstop') === false) + return false; + + styleClass.push(this.$baseCSSname + "Edit"); + if (styleClass.length == 1) + styleClass.unshift(""); + + if (this.btnedit) + oButtons.edit.innerHTML = "edit"; //hack + } + } + + if (styleClass.length || o.closed != lastState.closed) { + if (styleClass.length) + this.$setStyleClass(this.$ext, styleClass.shift(), styleClass); + + if (o.edit) { //@todo apf3.0 + this.dispatchEvent("prop.visible", {value:true}); + + if (_self.oSettings) + apf.layout.forceResize(_self.oSettings); + + } + + //@todo research why this is not symmetrical + if (!o.maximized || !this.animate || lastState.maximized && _self.animate) { + _self.dispatchEvent("afterstatechange", { + from: lastState, + to: o}); + } + + this.$lastState = o; + + + if (this.aData && !o.maximized) { //@todo is this the most optimal position? + this.$purgeAlignment(); + } + + + + if (!this.animate && apf.hasSingleRszEvent && apf.layout) + apf.layout.forceResize(_self.$int); + + } + }; + + var marginBox, hordiff, verdiff, oButtons = {} + /** + * @attribute {String} buttons Sets or gets the buttons that the window displays. This + * can be multiple values seperated by a pipe (`'|'`) character. + * + * The possible values include: + * + * `"min"`: The button that minimizes the window. + * `"max"`: The button that maximizes the window. + * `"close"`: The button that closes the window. + * `"edit"`: The button that puts the window into the edit state. + */ + this.$propHandlers["buttons"] = function(value) { + + if (!this.$hasLayoutNode("button")) + return; + + var buttons = value && (value = value.replace(/(\|)\||\|$/, "$1")).split("|") || [], + nodes = this.$buttons.childNodes, + re = value && new RegExp("(" + value + ")"), + found = {}, + idleNodes = []; + + //Check if we can 'remove' buttons + for (var i = 0; i < nodes.length; i++) { + if (nodes[i].nodeType != 1 || nodes[i].tagName != "DIV") //@todo temp hack + continue; + + if (nodes[i].getAttribute("button") && (!value + || !nodes[i].className || !nodes[i].className.match(re))) { + nodes[i].style.display = "none"; + this.$setStyleClass(nodes[i], "", ["min", "max", "close", "edit"]); + idleNodes.push(nodes[i]); + } + else { + found[RegExp.$1] = nodes[i]; + } + } + + //Create new buttons if needed + for (i = 0; i < buttons.length; i++) { + if (!buttons[i]) + continue; + + if (found[buttons[i]]) { + this.$buttons.insertBefore(found[buttons[i]], this.$buttons.firstChild); + continue; + } + + var btn = idleNodes.pop(); + if (!btn) { + this.$getNewContext("button"); + btn = this.$getLayoutNode("button"); + btn.setAttribute("button", "button"); + setButtonEvents.call(this, btn); + btn = apf.insertHtmlNode(btn, this.$buttons); + } + + this.$setStyleClass(btn, buttons[i], ["min", "max", "close", "edit"]); + btn.onclick = new Function("apfLookup(" + this.$uniqueId + ").$toggle('" + + buttons[i] + "')"); + btn.style.display = "block"; + oButtons[buttons[i]] = btn; + this.$buttons.insertBefore(btn, this.$buttons.firstChild); + } + + marginBox = apf.getBox(apf.getStyle(this.$ext, "borderWidth")); + }; + + function setButtonEvents(btn) { + //@todo can this cancelBubble just go? + //event.cancelBubble = true; \ + btn.setAttribute("onmousedown", + "var o = apf.all[" + this.$uniqueId + "];\ + o.$setStyleClass(this, 'down', null, true);\ + apf.cancelBubble(event, o); \ + var o = apf.findHost(this).$ext;\ + if (o.onmousedown) o.onmousedown(event);\ + apf.cancelBubble(event, o);\ + apf.window.$mousedown(event);"); + btn.setAttribute("onmouseup", + "var o = apf.all[" + this.$uniqueId + "];\ + o.$setStyleClass(this, '', ['down'], true);"); + btn.setAttribute("onmouseover", + "var o = apf.all[" + this.$uniqueId + "];\ + o.$setStyleClass(this, 'hover', null, true);"); + btn.setAttribute("onmouseout", + "var o = apf.all[" + this.$uniqueId + "];\ + o.$setStyleClass(this, '', ['hover', 'down'], true);"); + btn.setAttribute("ondblclick", "apf.stopPropagation(event);"); + } + + this.$initButtons = function(oExt) { + this.animate = apf.enableAnim; + + this.collapsedHeight = this.$getOption("Main", "collapsed-height"); + + var oButtons = this.$getLayoutNode("main", "buttons", oExt); + if (!oButtons || apf.isIphone || !this.getAttribute("buttons") + || !this.$hasLayoutNode("button")) + return; + + var len = (this.getAttribute("buttons") || "").split("|").length; + for (var btn, i = 0; i < len; i++) { + this.$getNewContext("button"); + btn = oButtons.appendChild(this.$getLayoutNode("button")); + btn.setAttribute("button", "button"); + setButtonEvents.call(this, btn); + } + }; + + this.addEventListener("DOMNodeRemovedFromDocument", function(e) { + for (var name in oButtons) { + oButtons[name].onclick = null; + } + }); +}; + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * Baseclass of a paged element. + * + * @class apf.BaseTab + * @baseclass + * @allowchild tab + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.8 + * @inherits apf.Presentation + * + */ +/** + * @event beforeswitch Fires before this element switches to another tab. + * @cancelable Prevents the tab to become active. + * @param {Object} e The standard event object. It contains the following properties: + * - previous ([[String]] or [[Number]]): The name or number of the current tab. + * - previousId ([[Number]]): The number of the current tab. + * - previousPage ([[apf.tab]]): The current tab. + * - next ([[String]] or [[Number]]): The name or number of the tab the will become active. + * - nextId ([[Number]]): The number of the tab the will become active. + * - nextPage ([[apf.tab]]): The tab the will become active. + */ +/** + * @event afterswitch Fires after this element has switched to another tab. + * @param {Object} e The standard event object. It contains the following properties: + * - previous ([[String]] or [[Number]]): The name or number of the previous tab. + * - previousId ([[Number]]): The number of the previous tab. + * - previousPage ([[apf.tab]]): The previous tab. + * - next ([[String]] or [[Number]]): The name or number of the current tab. + * - nextId ([[Number]]): The number of the the current tab. + * - nextPage ([[apf.tab]]): The the current tab. + */ +apf.BaseTab = function(){ + this.$init(true); +}; + +(function() { + this.isPaged = true; + this.$focussable = apf.KEYBOARD; + this.length = 0; + this.isLoading = {}; + this.inited = + this.ready = false; + this.$scroll = true; + + /** + * Sets the current tab of this element. + * @param {String | Number} tab The name or number of the tab which is made active. + * @param {Function} callback The function called after setting the tab. Especially handy when using the `src` attribute. + */ + this.set = function(tab, callback, noEvent) { + if (noEvent || this.src && !this.$findPage(tab, {})) { + return this.$propHandlers["activepage"].call( + this, tab, null, null, callback, noEvent); + } + + if (this.activepage == (tab.name || tab)) + return callback && callback(this.getPage(tab)); + + this.$lastCallback = callback; + this.setProperty("activepage", tab); + }; + + // *** Properties and Attributes *** // + + this.$supportedProperties.push("activepage", "activepagenr", "length", + "src", "loading", "trans-in", "trans-out"); + + /** + * @property {Number} [SCROLL_LEFT=1] The constant representing the "scroll left" button + * @readonly + */ + /** + * @property {Number} [SCROLL_RIGHT=2] The constant representing the "scroll right" button + * @readonly + */ + /** + * @property {Number} [SCROLL_BOTH=4] The constant representing the "scroll left" and "scroll right" buttons + * @readonly + */ + /** + * @attribute {Number} activepagenr Sets or gets the child number of the active tab. + * + * #### Example + * + * This example uses property binding to maintain consistency between a + * dropdown which is used as a menu, and a pages element + * + * ```xml + * + * Home + * General + * Advanced + * + * + * + * + *

      Home Page

      + *
      + * + *

      General Page

      + *
      + * + *

      Advanced Page

      + *
      + *
      + * ``` + */ + this.$propHandlers["activepagenr"] = + + /** + * @attribute {String} activepage Sets or gets the name of the active tab. + * + * #### Example + * + * ```xml + * + * + * ... + * + * + * ... + * + * + * ... + * + * + * ``` + */ + this.$propHandlers["activepage"] = function(next, prop, force, callback, noEvent) { + if (!this.inited || apf.isNot(next) || next == -1) return; + + if (!callback) { + callback = this.$lastCallback; + delete this.$lastCallback; + } + + var tab, info = {}; + tab = this.$findPage(next, info); + + if (!tab) { + if (this.src) { + if (this.isLoading[next]) + return; + + if (this.$findPage("loading", {})) + this.$propHandlers["activepage"].call(this, "loading"); + + this.setProperty("loading", true); + this.isLoading[next] = true; + + tab = this.ownerDocument.createElementNS(apf.ns.apf, "tab"); + tab.setAttribute("id", next); + this.appendChild(tab); + + var _self = this; + tab.insertMarkup(this.src, { + tab: next, + //@todo apf3.0 change callback arguments in xinclude + callback: function(options) { + delete _self.isLoading[next]; + + if (!options.xmlNode) { + var oError = new Error(apf.formatErrorString(0, null, + "Loading new tab", "Could not load new tab: " + + _self.src)); + + _self.setProperty("loading", false); + + if (this.dispatchEvent("error", apf.extend({ + error: oError, + bubbles: true + }, options)) === false) + return true; + + throw oError; + } + else { + //for success + _self.setProperty("activepage", next); + + //Needs to be after set + if (callback) + callback(options.amlNode); + + _self.setProperty("loading", false); + } + } + }); + return; + } + + + + return false; + } + + if (tab.parentNode != this) { + + + return false; + } + + if (!tab.visible || tab.disabled) { + + + return false; + } + + //If tab is given as first argument, let's use its position + if (next.tagName) { + next = info.position; + this.activepage = tab.name || next;//tab.type || + } + + //Call the onbeforeswitch event; + if (!noEvent) { + var oEvent = { + previous: this.activepage, + previousId: this.activepagenr, + previousPage: this.$activepage, + next: next, + nextId: info.position, + nextPage: tab + }; + + if (this.dispatchEvent("beforeswitch", oEvent) === false) { + //Loader support + if (this.hideLoader) + this.hideLoader(); + + return false; + } + } + + //Maintain an activepagenr property (not reentrant) + this.activepagenr = info.position; + this.setProperty("activepagenr", info.position); + + //Deactivate the current tab, if any, and activate the new one + if (this.$activepage) + this.$activepage.$deactivate(); + + tab.$activate(); + + + + this.$activepage = tab; + + //this.scrollIntoView(tab); + + + //Loader support + if (this.hideLoader) { + if (tab.$rendered !== false) { + this.hideLoader(); + } + else { + //Delayed rendering support + tab.addEventListener("afterrender", function(){ + this.parentNode.hideLoader(); + }); + } + } + + if (!noEvent) { + if (tab.$rendered !== false) + this.dispatchEvent("afterswitch", oEvent); + else { + //Delayed rendering support + tab.addEventListener("afterrender", function(){ + this.parentNode.dispatchEvent("afterswitch", oEvent); + }); + } + } + + if (typeof callback == "function") + callback(tab); + + return true; + }; + + /** + * @attribute {String} buttons Sets or gets the modifier for pane tab buttons, seperated by a `|` character + * + * Possible values include: + * - `close`: The button has a close button inside it + * - `scale`: The buttons are scaled to make room for more buttons + * - `scroll`: When the buttons take too much space, scroll buttons are displayed + */ + this.$propHandlers["buttons"] = function(value) { + //this.buttons = value; + this.$scale = value.indexOf("scale") > -1; + this.$scroll = !this.$scale; + this.$order = value.indexOf("order") > -1; + + + //@todo skin change + //@todo buttons on the side + if (this.$scale) { + this.$maxBtnWidth = parseInt(this.$getOption("button", "maxwidth")) || 150; + this.$minBtnWidth = parseInt(this.$getOption("button", "minwidth")) || 10; + this.$setStyleClass(this.$buttons, "scale"); + this.addEventListener("resize", scalersz); + + // this.minwidth = this.$minBtnWidth * this.getPages().length + 10; + // this.$ext.style.minWidth = Math.max(0, this.minwidth - apf.getWidthDiff(this.$ext)) + "px"; + } + else { + this.$setStyleClass(this.$buttons, "", ["scale"]); + this.removeEventListener("resize", scalersz); + } + + }; + + + function visCheck(){ + scalersz.call(this) + } + + this.anims = "add|remove|sync"; + + //Add an element + function animAddTab(pane, callback) { + var t = pane.$button; + + var animateWidth = (t.offsetWidth + - apf.getWidthDiff(t)) < parseInt(apf.getStyle(t, "maxWidth")); + + if (animateWidth) { + var p = pane.parentNode.getPages()[0] == pane + ? null + : pane.previousSibling.$button; + var tb = p + ? (p.offsetWidth - apf.getWidthDiff(p)) + : parseInt(apf.getStyle(t, "maxWidth")); + t.style.maxWidth = "0px"; + } + + t.style.marginTop = (t.offsetHeight + 2) + "px"; + + function animateToTop(){ + t.style.marginTop = "0px"; + + setTimeout(function(){ + t.style[apf.CSSPREFIX + "TransitionProperty"] = ""; + t.style[apf.CSSPREFIX + "TransitionDuration"] = ""; + t.style[apf.CSSPREFIX + "TimingFunction"] = ""; + + t.style.marginTop = ""; + + if (animateWidth) + t.style.maxWidth = ""; + + callback(pane); + }, 150); + } + + setTimeout(function(){ + t.style[apf.CSSPREFIX + "TransitionProperty"] = "margin-top, max-width"; + t.style[apf.CSSPREFIX + "TransitionDuration"] = "100ms, 50ms"; + t.style[apf.CSSPREFIX + "TimingFunction"] = "cubic-bezier(.10, .10, .25, .90), cubic-bezier(.10, .10, .25, .90)"; + + if (animateWidth) { + t.style.maxWidth = tb + "px"; + setTimeout(animateToTop, 50); + } + else animateToTop(); + }); + } + + //Remove an element + function animRemoveTab(pane, isLast, isContracted, callback, isOnly) { + var t = pane.$button; + var tb = t.offsetHeight; + + var diff = t.offsetWidth; + + t.style[apf.CSSPREFIX + "TransitionProperty"] = "margin-top, max-width, padding"; + t.style[apf.CSSPREFIX + "TransitionDuration"] = (isOnly ? ".2" : ".15") + "s, .1s, .1s"; + t.style[apf.CSSPREFIX + "TimingFunction"] = "linear, ease-out, ease-out"; + + t.style.marginTop = (tb + 2) + "px"; + + var p = t.parentNode; + if (apf.isGecko) p = p.parentNode; + + p.style[apf.CSSPREFIX + "TransitionProperty"] = "padding-right"; + p.style[apf.CSSPREFIX + "TransitionDuration"] = ".2s"; + p.style[apf.CSSPREFIX + "TimingFunction"] = "ease-out"; + + if (isLast) + p.style.paddingRight = ""; + else { + var cur = parseInt(apf.getStyle(p, "paddingRight")); + p.style.paddingRight = (cur + diff - 21) + "px"; + } + + function end(){ + setTimeout(function(){ + p.style[apf.CSSPREFIX + "TransitionProperty"] = ""; + p.style[apf.CSSPREFIX + "TransitionDuration"] = ""; + p.style[apf.CSSPREFIX + "TimingFunction"] = ""; + + t.style[apf.CSSPREFIX + "TransitionProperty"] = ""; + t.style[apf.CSSPREFIX + "TransitionDuration"] = ""; + t.style[apf.CSSPREFIX + "TimingFunction"] = ""; + + t.style.display = "none"; + + callback(pane); + }, 150); + } + + if (!isLast && isContracted) { + t.style.minWidth = "20px" + t.style.maxWidth = "0px"; + t.style.padding = 0; + + end(); + } + else { + setTimeout(function(){ + t.style.minWidth = "20px" + t.style.maxWidth = "0px"; + t.style.padding = 0; + + end(); + }, isOnly ? 150 : 100); + } + } + + this.$scaleinit = function(node, type, callback, force) { + var _self = this; + + var pg = this.getPages(); + var l = pg.length; + if (!l) return; + + // this.minwidth = this.$minBtnWidth * l + 10; //@todo padding + margin of button container + // this.$ext.style.minWidth = Math.max(0, this.minwidth - apf.getWidthDiff(this.$ext)) + "px"; + + if (force && !this.$ext.offsetWidth && !this.$ext.offsetHeight + || this.anims.indexOf(type) == -1 || this.skipAnimOnce) { + scalersz.call(this); + + this.skipAnimOnce = false; + + if (type == "add") + node.dispatchEvent("afteropen"); + else if (type == "remove") { + if (node.dispatchEvent("afterclose") !== false) + callback(); + } + + return; + } + + if (!apf.window.vManager.check(this, "tabscale", visCheck)) + return; + + if (!type) + return scalersz.call(this); + + function btnMoHandler(e) { + var pos = apf.getAbsolutePosition(this); + if (e.clientX <= pos[0] || e.clientY <= pos[1] + || e.clientX >= pos[0] + this.offsetWidth + || e.clientY >= pos[1] + this.offsetHeight) { + apf.removeListener(_self.$buttons, "mouseout", btnMoHandler); + delete _self.$waitForMouseOut; + _self.$scaleinit(null, "sync"); +// } +// else if (_self.$waitForMouseOut) +// _self.$waitForMouseOut = 2; + } + } + + if (type == "add") { + animAddTab(node, function(){ + node.dispatchEvent("afteropen"); + }); + } + else if (type == "sync") { + scalersz.call(this); + } + else if (type == "remove") { + var onfinish = function(){ + if (node.dispatchEvent("afterclose") === false) + return; + + callback(); + + if (!isLast && isContracted) { + var pages = _self.getPages(); + for (var i = 0, l = pages.length; i < l; i++) { + var tab = pages[i]; + tab.$button.style.minWidth = ""; + tab.$button.style.maxWidth = ""; + } + } + + if (_self.$waitForMouseOut == 2) { + apf.removeListener(_self.$buttons, "mouseout", btnMoHandler); + delete _self.$waitForMouseOut; + } + else if (isLast) + delete _self.$waitForMouseOut; + }; + + var pages = this.getPages(); + + var lNode = pages[pages.length - 1]; + while (lNode && (!lNode.$button || lNode.$button.style.top)) { + lNode = lNode.previousSibling; + } + if (!lNode) return; + + var isLast = lNode == node; + var isContracted = (node.$button.offsetWidth - apf.getWidthDiff(node.$button) + != parseInt(apf.getStyle(node.$button, "maxWidth"))); + + if (!isLast && isContracted) { + for (var i = 0, l = pages.length; i < l; i++) { + var tab = pages[i]; + tab.$button.style.minWidth = + tab.$button.style.maxWidth = (tab.$button.offsetWidth + - (apf.isGecko ? 0 : apf.getWidthDiff(tab.$button))) + + "px"; + } + } + + var isCur = this.$activepage == node; + + //Set activetab if the current one is lost + if (_self.nextTabInLine) { + _self.set(_self.nextTabInLine); + delete _self.nextTabInLine; + } + else if (_self.$activepage == node) { + var ln = node.nextSibling; + while (ln && (!ln.$first || !ln.visible)) + ln = ln.nextSibling; + var rn = node.previousSibling; + while (rn && (!rn.$last || !rn.visible)) + rn = rn.previousSibling; + if (ln || rn) + _self.set(ln || rn); + } + + if (isCur) { + apf.setStyleClass(node.$button, "curbtn"); + node.$button.style.zIndex = 0; + } + + if (pages.length == 1) + (node.relPage || node).$ext.style.display = "none"; + + animRemoveTab(node, isLast, isContracted, onfinish, pages.length == 1); + + this.$waitForMouseOut = true; + if (!isLast) + apf.addListener(_self.$buttons, "mouseout", btnMoHandler); + } + } + + /* + * Update the size of the pane container + */ + function scalersz(e, excl) { + if (!this.length && !this.getPages().length || this.$waitForMouseOut) + return; + + var p = apf.isGecko ? this.$buttons.parentNode : this.$buttons; + + p.style[apf.CSSPREFIX + "TransitionProperty"] = "padding-right"; + p.style[apf.CSSPREFIX + "TransitionDuration"] = ".2s"; + p.style[apf.CSSPREFIX + "TimingFunction"] = "ease-out"; + + if (apf.isGecko) { + p.style.paddingRight = apf.getWidthDiff(this.$buttons) + "px"; + } + else { + p.style.paddingRight = ""; + } + + setTimeout(function(){ + p.style[apf.CSSPREFIX + "TransitionProperty"] = ""; + p.style[apf.CSSPREFIX + "TransitionDuration"] = ""; + p.style[apf.CSSPREFIX + "TimingFunction"] = ""; + }, 250); + } + + + // *** Public methods *** // + + + + /** + * Retrieves an array of all the tab elements of this element. + * @returns {Array} An array of all the {apf.tab} elements + */ + this.getPages = function(){ + var r = [], nodes = this.childNodes; + if (!nodes) return r; + for (var i = 0, l = nodes.length; i < l; i++) { + if ("tab|case".indexOf(nodes[i].localName) > -1 && nodes[i].visible !== false) + r.push(nodes[i]); + } + return r; + }; + + /** + * Retrieves a tab element by its name or child number. + * @param {String | Number} nameOrId The name or child number of the tab element to retrieve. + * @return {apf.tab} The found tab element. + */ + this.getPage = function(nameOrId) { + if (apf.isNot(nameOrId)) + return this.$activepage; + else + return this.$findPage(nameOrId); + }; + + /** + * Adds a new tab element + * @param {String} [caption] The text displayed on the button of the tab + * @param {String} [name] The name of the tab which is can be referenced by + * @param {String} [type] The type of the tab + * @param {apf.tab} [insertBefore] The tab to insert ahead of; `null` means to put it at the end + * @param {Function} [callback] A callback to call and pass the new tab to + * @return {apf.tab} The created tab element. + */ + this.add = function(caption, name, type, before, callback) { + var tab = this.ownerDocument.createElementNS(apf.ns.aml, "tab"); + if (name) + tab.setAttribute("id", name); + if (type) + tab.setAttribute("type", type); + if (caption) + tab.setAttribute("caption", caption); + + if (callback) + callback(tab); + + this.insertBefore(tab, before); + + + //this.scrollIntoView(tab); + + return tab; + }; + + /** + * Removes a tab element from this element. This function destroys ALL children + * of this tab. To simple remove the tab from the DOM tree, use the + * [[apf.AmlNode.removeNode]] method. + * + * @param {Mixed} nameOrId The name or child number of the tab element to remove + * @return {apf.tab} The removed tab element + */ + this.remove = function(nameOrId, force, noAnimation) { + var tab = typeof nameOrId == "object" + ? nameOrId + : this.$findPage(nameOrId); + if (!tab) + return false; + + var e = {tab: tab}; + if (typeof force == "object") { + e.htmlEvent = force; + force = false; + } + + if (!force && this.dispatchEvent("close", e) === false) + return; + + if (this.$scale && !noAnimation) { + this.$scaleinit(tab, "remove", function(){ + //tab.removeNode(); + tab.destroy(true, true); + }, true); + } + else + + { + //tab.removeNode(); + if (tab.dispatchEvent("afterclose") !== false) + tab.destroy(true, true); + + + //@todo this is wrong, we can also use removeChild + //this.setScrollerState(); + + } + + return tab; + }; + + + /* + var SCROLLANIM = { + scrollOn: false, + steps: 15, + interval: 10, + size: 0, + left: 0, + control: { + stop: false + }, + stopHandle: function() { + bAnimating = false; + } + }, + SCROLL_OFF = 0x0001, + SCROLL_HOVER = 0x0002, + SCROLL_DOWN = 0x0004, + SCROLL_DIS = 0x0008, + SCROLL_L_STATE = SCROLL_OFF, + SCROLL_R_STATE = SCROLL_OFF, + SCROLL_LEFT = 0x0001, + SCROLL_RIGHT = 0x0002, + SCROLL_BOTH = 0x0004, + bAnimating = false, + scrollTimer = null, + keepScrolling = false, + globalDir = SCROLL_LEFT; +*/ + function getButtonsWidth() { + var cId = "cache_" + this.$buttons.childNodes.length; + if (SCROLLANIM[cId]) + return SCROLLANIM[cId]; + + var iWidth = 0; + for (var i = 0, l = this.$buttons.childNodes.length; i < l; i++) { + if (typeof this.$buttons.childNodes[i].offsetWidth != "undefined") + iWidth += this.$buttons.childNodes[i].offsetWidth; + } + + return SCROLLANIM[cId] = iWidth; + } + + function setButtonState(dir, state) { + var bBoth = dir & SCROLL_BOTH; + if (bBoth) + dir = SCROLL_LEFT; + var oBtn = this[dir & SCROLL_LEFT ? "oLeftScroll" : "oRightScroll"]; + if (!(state & SCROLL_DIS)) { + if (dir & SCROLL_LEFT) + SCROLL_L_STATE = state; + else + SCROLL_R_STATE = state; + } + + if (state & SCROLL_OFF) + apf.setStyleClass(oBtn, "", ["disabled", "hover", "down"]); + else if (state & SCROLL_HOVER) + apf.setStyleClass(oBtn, "hover", ["disabled", "down"]); + else if (state & SCROLL_DOWN) + apf.setStyleClass(oBtn, "down", ["disabled", "hover"]); + else if (state & SCROLL_DIS) + apf.setStyleClass(oBtn, "disabled", ["hover", "down"]); + + if (bBoth) + setButtonState(SCROLL_RIGHT, state); + } + + /** + * Sets the state scroller buttons: `enabled`, `disabled` or completely `hidden`, + * depending on the state of the pane buttons + * + * @param {Boolean} [bOn] Indicates whether to turn the scroll buttons on or off + * @param {Number} [iBtns] Specifies the buttons to set the state of. Can be [[apf.BaseTab.SCROLL_LEFT]], [[apf.BaseTab.SCROLL_RIGHT]] or [[apf.BaseTab.SCROLL_BOTH]] + * + */ + this.setScrollerState = function(bOn, iBtns) { + if (!this.ready || !this.$hasButtons || !this.oScroller) return; + + if (typeof bOn == "undefined") { + var scrollerWidth = this.oScroller.offsetWidth + || parseInt(apf.getStyle(this.oScroller, "width").replace(/(px|em|%)/, "")); + bOn = ((getButtonsWidth.call(this) + scrollerWidth) > this.$ext.offsetWidth); + iBtns = SCROLL_BOTH; + } + + if (iBtns & SCROLL_BOTH && bOn !== SCROLLANIM.scrollOn) { + // in case of HIDING the scroller: check if the anim stuff has reverted + SCROLLANIM.scrollOn = bOn; + if (!bOn) { + this.$buttons.style.left = SCROLLANIM.left + "px"; + this.oScroller.style.display = "none"; + } + //else + // TODO: scroll active pane into view if it becomes hidden beneath scroller node(s) + } + else { + this.oScroller.style.display = ""; + } + + this.oScroller.style.display = (iBtns & SCROLL_BOTH && !bOn) + ? "none" + : ""; + if (typeof iBtns == "undefined") + iBtns = SCROLL_BOTH; + if (!bOn) { + if ((iBtns & SCROLL_LEFT) || (iBtns & SCROLL_BOTH)) + setButtonState.call(this, SCROLL_LEFT, SCROLL_DIS); + if ((iBtns & SCROLL_RIGHT) || (iBtns & SCROLL_BOTH)) + setButtonState.call(this, SCROLL_RIGHT, SCROLL_DIS); + } + }; + + /** + * Corrects the state of the scroller buttons when the state of external + * components change, like on a resize event of a window. + * + */ + this.correctScrollState = function() { + if (!this.ready || !this.$hasButtons || !this.oScroller) return; + this.setScrollerState(); + }; + + /** + * Retrieves the utmost left or right boundaries of the pane buttons strip that + * can be scrolled to. The tabs cannot scroll any further than these boundaries + * + * @param {Number} dir Determines which boundary side to look at, either [[apf.BaseTab.SCROLL_LEFT]] or [[apf.BaseTab.SCROLL_RIGHT]] + * @param {Boolean} [useCache] Used only when tabs are draggable. Not implemented. + * @returns {Number} + */ + function getAnimationBoundary(dir, useCache) { + if (SCROLLANIM.size <= 0) { + SCROLLANIM.left = this.$buttons.offsetLeft; + SCROLLANIM.size = Math.round(this.firstChild.$button.offsetWidth); + } + if (dir & SCROLL_LEFT) { + return SCROLLANIM.left; + } + else if (dir & SCROLL_RIGHT) { + // TODO: support Drag n Drop of tabs... + //if (typeof useCache == "undefined") useCache = false; + //if (!tabcontrol.drag) tabcontrol.drag = {}; + //if (useCache && tabcontrol.drag.boundCache) + // return tabcontrol.drag.boundCache; + var oNode = this.$buttons.childNodes[this.$buttons.childNodes.length - 1]; + + return this.$ext.offsetWidth - (oNode.offsetLeft + oNode.offsetWidth + + (this.oScroller.offsetWidth + 4));// used to be tabcontrol.drag.boundCache; + } + } + + /** + * @event scroll Executed when the user presses one of the two scroll buttons + * (left or right). + * + * If the pane-buttons strip can be scrolled, the + * respective behavior is called. + * + * @param {Event} e An event object, usually a mousedown event from a scroller-button + * @param {Number} dir The direction of the scroll, either [[apf.BaseTab.SCROLL_LEFT]] or [[apf.BaseTab.SCROLL_RIGHT]] + * + */ + this.scroll = function(e, dir) { + if (!this.ready || !this.$hasButtons || !this.oScroller) return; + if (!e) + e = window.event; + if (typeof e["type"] == "unknown") //scope expired (prolly GC'ed) + e = {type: "click"}; + if (bAnimating && e.type != "dblclick") return; + var bAnimating = true; + + if (typeof dir == "undefined") + dir = SCROLL_LEFT; + + //apf.tween.clearQueue(this.$buttons, true); + var iCurrentLeft = this.$buttons.offsetLeft, + size = e["delta"] ? Math.round(e.delta * 36) : SCROLLANIM.size, + //get maximum left offset for either direction + iBoundary = getAnimationBoundary.call(this, dir), + _self = this; + if (dir & SCROLL_LEFT) { + setButtonState(SCROLL_LEFT, SCROLL_DOWN); + setButtonState(SCROLL_RIGHT, SCROLL_OFF); + if (iCurrentLeft === iBoundary) { + this.setScrollerState(false, SCROLL_LEFT); + return apf.tween.single(this.$buttons, { + steps: SCROLLANIM.steps, + interval: 20, + from: iCurrentLeft, + to: iCurrentLeft + 12, + type: "left", + anim: apf.tween.EASEOUT, + onstop: SCROLLANIM.stopHandle, + onfinish: function(oNode) { + apf.tween.single(oNode, { + steps: SCROLLANIM.steps, + interval: SCROLLANIM.interval, + from: iCurrentLeft + 12, + to: iCurrentLeft, + type: "left", + anim: apf.tween.EASEIN, + onstop: SCROLLANIM.stopHandle, + onfinish: function() { + bAnimating = false; + if (e.name == "mousescroll") + setButtonState(SCROLL_LEFT, SCROLL_OFF); + } + }); + } + }); + } + //one scroll animation scrolls by a SCROLLANIM.size px. + var iTargetLeft = iCurrentLeft + (e.type == "dblclick" ? size * 3 : size); + if (iTargetLeft > iBoundary) + iTargetLeft = iBoundary; + + if (iTargetLeft === iBoundary) + this.setScrollerState(false, SCROLL_LEFT); + this.setScrollerState(true, SCROLL_RIGHT); + + //start animated scroll to the left + apf.tween.single(this.$buttons, { + steps: SCROLLANIM.steps, + interval: SCROLLANIM.interval, + control: SCROLLANIM.control, + from: iCurrentLeft, + to: iTargetLeft, + type: "left", + anim: apf.tween.NORMAL, + onstop: SCROLLANIM.stopHandle, + onfinish: function() { + bAnimating = false; + if (e.name == "mousescroll") + setButtonState(SCROLL_LEFT, SCROLL_OFF); + if (keepScrolling) + _self.scroll(e, globalDir); + } + }); + } + else if (dir & SCROLL_RIGHT) { + this.setScrollerState(true); + setButtonState(SCROLL_RIGHT, SCROLL_DOWN); + setButtonState(SCROLL_LEFT, SCROLL_OFF); + if (iCurrentLeft === iBoundary) { + this.setScrollerState(false, SCROLL_RIGHT); + return apf.tween.single(this.$buttons, { + steps: SCROLLANIM.steps, + interval: 20, + from: iCurrentLeft, + to: iCurrentLeft - 24, + type: "left", + anim: apf.tween.EASEOUT, + onstop: SCROLLANIM.stopHandle, + onfinish: function(oNode, options) { + apf.tween.single(oNode, { + steps: SCROLLANIM.steps, + interval: SCROLLANIM.interval, + from: iCurrentLeft - 24, + to: iCurrentLeft, + type: "left", + anim: apf.tween.EASEIN, + onstop: SCROLLANIM.stopHandle, + onfinish: function() { + bAnimating = false; + if (e.name == "mousescroll") + setButtonState(SCROLL_RIGHT, SCROLL_OFF); + } + }); + } + }); + } + //one scroll animation scrolls by a SCROLLANIM.size px. + var iTargetLeft = iCurrentLeft - (e.type == "dblclick" ? size * 3 : size); + //make sure we don't scroll more to the right than the + //maximum left: + if (iTargetLeft < iBoundary) + iTargetLeft = iBoundary; + //start animated scroll to the right + apf.tween.single(this.$buttons, { + steps: SCROLLANIM.steps, + interval: SCROLLANIM.interval, + control: SCROLLANIM.control, + from: iCurrentLeft, + to: iTargetLeft, + type: "left", + anim: apf.tween.NORMAL, + onstop: SCROLLANIM.stopHandle, + onfinish: function() { + bAnimating = false; + if (e.name == "mousescroll") + setButtonState(SCROLL_RIGHT, SCROLL_OFF); + if (keepScrolling) + _self.scroll(e, globalDir); + } + }); + } + }; + + /** + * If a pane tab is outside of the user's view, this function scrolls that + * tabpage into view smoothly. + * + * @param {apf.tab} oPage The tab to scroll into view + * + */ + this.scrollIntoView = function(oPage) { + bAnimating = false; + if (!this.ready || !this.$hasButtons || !this.oScroller || !oPage.$drawn) + return; + bAnimating = true; + if (this.$buttons.offsetWidth < this.$ext.offsetWidth) + return this.setScrollerState(false); + + var iTabLeft = oPage.$button.offsetLeft, + iTabWidth = oPage.$button.offsetWidth, + iCurrentLeft = this.$buttons.offsetLeft; + + if (SCROLLANIM.size <= 0) { + SCROLLANIM.left = this.$buttons.offsetLeft; + var p = this.firstChild; + while (!p.$button) + p = p.nextSibling; + SCROLLANIM.size = Math.round(p.$button.offsetWidth); + } + this.$buttons.style.left = iCurrentLeft; + + var iRealWidth = this.$ext.offsetWidth, + iScrollCorr = this.oScroller.offsetWidth + 4, + iTargetLeft = null, + dir; + + if ((iTabLeft + iTabWidth) > ((iRealWidth - iScrollCorr) - iCurrentLeft)) { //scroll to the right + iTargetLeft = (-(iTabLeft - SCROLLANIM.left) + + (iRealWidth - iTabWidth - iScrollCorr)); + dir = SCROLL_RIGHT; + } + else if ((iCurrentLeft + iTabLeft) < SCROLLANIM.left) { //sroll to the left + iTargetLeft = SCROLLANIM.left - iTabLeft; + dir = SCROLL_LEFT; + } + + if (iTargetLeft !== null) { + this.setScrollerState(true); + setButtonState(SCROLL_RIGHT, dir & SCROLL_RIGHT ? SCROLL_DOWN : SCROLL_OFF); + setButtonState(SCROLL_LEFT, dir & SCROLL_LEFT ? SCROLL_DOWN : SCROLL_OFF); + apf.tween.clearQueue(this.$buttons, true); + + apf.tween.single(this.$buttons, { + steps: SCROLLANIM.steps, + interval: SCROLLANIM.interval, + from: iCurrentLeft, + to: iTargetLeft, + type: "left", + anim: apf.tween.NORMAL, + onstop: SCROLLANIM.stopHandle, + onfinish: function() { + bAnimating = false; + setButtonState(SCROLL_RIGHT, SCROLL_OFF); + setButtonState(SCROLL_LEFT, SCROLL_OFF); + } + }); + } + else + bAnimating = false; + }; + + + + // *** DOM Hooks *** // + + this.addEventListener("DOMNodeRemoved", function(e) { + var amlNode = e.currentTarget; + if (e.$doOnlyAdmin || e.relatedNode != this + || amlNode.localName != "tab") + return; + + if ((this.activepage || this.activepage == 0) && this.activepage != -1) { + if (!this.getPage(this.nextTabInLine)) + this.nextTabInLine = null; + + if (this.nextTabInLine) + this.set(this.nextTabInLine); + + if (!this.nextTabInLine && this.$activepage == amlNode) { + var ln = amlNode.nextSibling; + while (ln && (!ln.$first || !ln.visible)) + ln = ln.nextSibling; + var rn = amlNode.previousSibling; + while (rn && (!rn.$last || !rn.visible)) + rn = rn.previousSibling; + + if (this.firstChild == amlNode && ln) + ln && ln.$first(); + if (this.lastChild == amlNode && rn) + rn && rn.$last(); + + if (ln || rn) + this.set(ln || rn); + else { + amlNode.$deactivate(); + + + //this.setScrollerState(); + + this.$activepage = + this.activepage = + this.activepagenr = null; + this.setProperty("activepage", null); + } + } + else { + + //if (this.$scroll) + //this.setScrollerState(); + + + if (this.$scale) + this.$scaleinit(); + + } + + delete this.nextTabInLine; + } + + + this.setProperty("length", this.getPages().length - 1); + + }); + + this.addEventListener("DOMNodeInserted",function(e) { + var amlNode = e.currentTarget; + + if (amlNode.localName != "tab" || e.relatedNode != this || amlNode.nodeType != 1) + return; + + var pages = this.getPages(); + + if (!e.$beforeNode) { + var lastChild, pg = pages; + if (lastChild = pg[pg.length - 2]) + lastChild.$last(true); + amlNode.$last(); + } + + var p2, p = pages[0]; //@todo $beforeNode doesnt have to be a tab + if (amlNode == p) { + if (p2 = this.getPage(1)) + p2.$first(true); + amlNode.$first(); + } + + if (this.$activepage) { + var info = {}; + this.$findPage(this.$activepage, info); + + if (this.activepagenr != info.position) { + if (parseInt(this.activepage) == this.activepage) { + this.activepage = info.position; + this.setProperty("activepage", info.position); + } + this.activepagenr = info.position; + this.setProperty("activepagenr", info.position); + } + } + else if (!this.activepage && !this.$activepage + && !amlNode.render || amlNode.$rendered) { + this.set(amlNode); + } + + + if (this.$scale && amlNode.visible && !e.$isMoveWithinParent) + this.$scaleinit(amlNode, "add"); + else + + { + amlNode.dispatchEvent("afteropen"); + } + + + this.setProperty("length", this.getPages().length); + + }); + + // *** Private state handling functions *** // + + this.$findPage = function(nameOrId, info) { + var node, nodes = this.childNodes; + + if (nameOrId.localName) { + for (var t = 0, i = 0, l = nodes.length; i < l; i++) { + node = nodes[i]; + if ("tab|case".indexOf(node.localName) > -1 && (++t) && node == nameOrId) { + if (info) + info.position = t - 1; + return node; + } + } + } + else { + for (var t = 0, i = 0, l = nodes.length; i < l; i++) { + node = nodes[i]; + if ("tab|case".indexOf(node.localName) > -1 && (t++ == nameOrId + || node.name == nameOrId)) { + if (info) + info.position = t - 1; + return node; + } + } + } + + return null; + }; + + this.$enable = function(){ + var nodes = this.childNodes; + for (var i = 0, l = nodes.length; i < l; i++) { + if (nodes[i].enable) + nodes[i].enable(); + } + }; + + this.$disable = function(){ + var nodes = this.childNodes; + for (var i = 0, l = nodes.length; i < l; i++) { + if (nodes[i].disable) + nodes[i].disable(); + } + }; + + // *** Keyboard support *** // + + + + + + + + // *** Init *** // + + this.$loadChildren = function(callback) { + var tab = false, + _self = this, + i, j, l, node, nodes; + + this.inited = true; + + if (this.$hasButtons) { + this.$buttons = this.$getLayoutNode("main", "buttons", this.$ext); + this.$buttons.setAttribute("id", this.$uniqueId + "_buttons"); + + if (apf.isGecko && !this.$gotContainer) { + var div = this.$ext.appendChild(document.createElement("div")); + div.style.backgroundImage = apf.getStyle(this.$buttons, "backgroundImage"); + div.style.backgroundColor = apf.getStyle(this.$buttons, "backgroundColor"); + div.style.position = "absolute"; + div.style.left = 0; + div.style.top = 0; + div.style.right = 0; + div.style.overflow = "hidden"; + div.style.height = this.$buttons.offsetHeight + "px"; + div.appendChild(this.$buttons); + this.$buttons.style.width = "100%"; + div.style.paddingRight = apf.getWidthDiff(this.$buttons) + "px"; + + this.$gotContainer = true; + } + } + + this.oPages = this.$getLayoutNode("main", "pages", this.$ext); + + + // add scroller node(s) + /*this.oScroller = this.$getLayoutNode("main", "scroller", this.oPages); + if (this.oScroller) { + function startTimer(e, dir) { + clearTimeout(scrollTimer); + globalDir = dir; + scrollTimer = $setTimeout(function() { + keepScrolling = true; + _self.scroll(e, dir); + }, 500); + } + function stopTimer() { + clearTimeout(scrollTimer); + keepScrolling = false; + } + + this.oScroller.onmouseout = function(e) { + SCROLLANIM.control.stop = true; + setButtonState(SCROLL_BOTH, SCROLL_OFF); + }; + + + /*apf.addEventListener("mousescroll", function(e) { + var found = (e.target == _self.$buttons); + while (!found && e.target != document.body) { + e.target = e.target.offsetParent; + found = (e.target == _self.$buttons); + } + if (!found) return; + var dir = e.delta > 0 ? SCROLL_LEFT : SCROLL_RIGHT; + e.delta = Math.abs(e.delta); + _self.scroll(e, dir); + });* / + + + this.oLeftScroll = apf.getNode(this.oScroller, [0]); + this.oRightScroll = apf.getNode(this.oScroller, [1]); + + ["oLeftScroll", "oRightScroll"].forEach(function(sBtn) { + var dir = sBtn == "oLeftScroll" ? SCROLL_LEFT : SCROLL_RIGHT, + revDir = sBtn == "oLeftScroll" ? SCROLL_RIGHT : SCROLL_LEFT; + + _self[sBtn].ondbclick = + _self[sBtn].onmousedown = function(e) { + SCROLLANIM.control.stop = false; + var state = dir & SCROLL_LEFT ? SCROLL_L_STATE : SCROLL_R_STATE; + if (this.className.indexOf("disabled") != -1 + || state & SCROLL_DOWN) return; + e = e || event; + _self.scroll(e, dir); + startTimer(e, dir); + if (!apf.isSafariOld) + this.onmouseout(); + }; + _self[sBtn].onmouseover = function() { + SCROLLANIM.control.stop = false; + var state = dir & SCROLL_LEFT ? SCROLL_L_STATE : SCROLL_R_STATE; + if (this.className.indexOf("disabled") != -1 + || state & SCROLL_DOWN) return; + setButtonState(dir, SCROLL_HOVER); + setButtonState(revDir, SCROLL_OFF); + globalDir = dir; + }; + _self[sBtn].onmouseout = function() { + var state = dir & SCROLL_LEFT ? SCROLL_L_STATE : SCROLL_R_STATE; + if (this.className.indexOf("disabled") != -1 + || state & SCROLL_DOWN) return; + setButtonState(dir, SCROLL_OFF); + }; + _self[sBtn].onmouseup = function() { + if (this.className.indexOf("disabled") == -1) { + setButtonState(dir, SCROLL_OFF); + } + stopTimer(); + SCROLLANIM.control.stop = true; + }; + }); + } + + + apf.layout.setRules(this.$ext, this.$uniqueId + "_tabscroller", + "var o = apf.all[" + this.$uniqueId + "]; o && o.correctScrollState()"); + apf.layout.queue(this.$ext);*/ + + + + //Skin changing support + if (this.$int) { + //apf.AmlParser.replaceNode(this.oPages, oPages); + this.$int = this.oPages; + tab = true; + + //@todo apf3.0 skin change? + nodes = this.childNodes; + for (i = 0; i < nodes.length; i++) { + node = nodes[i]; + if (node.nodeType != 1) + continue; + node.$draw(true); + if (node.$skinchange) + node.$skinchange(); + node.$loadAml(); + } + } + else { + this.$int = this.oPages; + + //Build children + nodes = this.getPages(); + if (nodes.length) { + nodes[0].$first(); + (node = nodes[nodes.length - 1]).$last(); + } + } + + //Set active tab + if (node) { + this.activepage = (typeof this.activepage != "undefined" + ? this.activepage + : this.activepagenr) || 0; + tab = this.getPage(this.activepage); + if (!tab.render || tab.$rendered) + this.$propHandlers.activepage.call(this, this.activepage); + } + else { + this.isPages = false; + } + + + this.setProperty("length", this.getPages().length); + + + this.ready = true; + + /*window.setTimeout(function() { + _self.setScrollerState(); + }, 0);*/ + + + if (!this.activepage && this.getAttribute("src")) { + this.src = this.getAttribute("src"); + this.$propHandlers["activepage"].call(this); + } + }; + + this.$destroy = function(bSkinChange) { + if (bSkinChange || !this.oScroller) + return; + + + /*apf.layout.removeRule(this.$ext, this.$uniqueId + "_tabscroller"); + + [this.oLeftScroll, this.oRightScroll].forEach(function(oBtn) { + oBtn.onmousedown = oBtn.ondblclick = oBtn.onmouseover = + oBtn.onmouseout = oBtn.onmouseup = null; + });*/ + + }; +}).call(apf.BaseTab.prototype = new apf.Presentation()); + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * Baseclass of elements that allows the user to select one or more items + * from a tree based element. + * + * @class apf.BaseTree + * @baseclass + * + * @inherits apf.MultiSelect + * @inheritsElsewhere apf.XForms + * @inherits apf.Cache + * @inherits apf.DataAction + * @inherits apf.Rename + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.8 + * @default_private + * + */ +apf.BaseTree = function(){ + this.$init(true); + + + this.$dynCssClasses = []; + + + this.$nodes = []; +}; + +(function() { + + this.implement( + + + apf.Rename, + + + apf.DataAction, + + + apf.Cache, + + apf.K + ); + + + // *** Properties and Attributes *** // + + //Options + this.$isTreeArch = true; // This element has a tree architecture. + this.$focussable = true; // This object can get the focus. + this.multiselect = false; // Initially multiselect is disabled. + this.bufferselect = true; + + this.startcollapsed = true; + this.$animType = apf.tween.NORMAL; + this.$animOpenStep = 3; + this.$animCloseStep = 1; + this.$animSpeed = 10; + + var HAS_CHILD = 1 << 1, + IS_CLOSED = 1 << 2, + IS_LAST = 1 << 3, + IS_ROOT = 1 << 4; + + var treeState = this.$treeState = {}; + this.$treeState[0] = ""; + this.$treeState[HAS_CHILD] = "min"; + this.$treeState[HAS_CHILD | IS_CLOSED] = "plus"; + this.$treeState[IS_LAST] = "last"; + this.$treeState[IS_LAST | HAS_CHILD] = "minlast"; + this.$treeState[IS_LAST | HAS_CHILD | IS_CLOSED] = "pluslast"; + this.$treeState[IS_ROOT] = "root"; + + // *** Properties and Attributes *** // + + /** + * @attribute {Boolean} openadd Sets or gets whether the tree expands the parent to which a node is added. Defaults to `true`. + */ + /** + * @attribute {Boolean} startcollapsed Sets or gets whether the tree collapses all nodes that contain children on load. Defaults to `true`. + */ + /** + * @attribute {Boolean} nocollapse Sets or gets whether the user cannot collapse a node. Defaults to `false`. + */ + /** + * @attribute {Boolean} singleopen Sets or gets whether the tree will expand a node by a single click. Defaults to `false`. + */ + /** + * @attribute {Boolean} prerender Sets or gets whether the tree will render all the nodes at load. Defaults to `true`. + */ + /** + * @attribute {Boolean} disableremove Sets or gets whether the tree disallows removing nodes with the keyboard, by pressing [[keys: Del]]. Defaults to `false`. + */ + this.$booleanProperties["openadd"] = true; + this.$booleanProperties["startcollapsed"] = true; + this.$booleanProperties["nocollapse"] = true; + this.$booleanProperties["singleopen"] = true; + this.$booleanProperties["animation"] = true; + this.$booleanProperties["prerender"] = true; + this.$booleanProperties["removecontainer"] = true; + this.$booleanProperties["dragroot"] = true; + this.$booleanProperties["disableremove"] = true; + + this.$supportedProperties.push("openadd", "startcollapsed", "nocollapse", + "singleopen", "prerender", "removecontainer", "animation", "dragroot", + "disableremove"); + + this.openadd = true; + this.startcollapsed = 1; + this.prerender = true; + this.disableremove = false; + + // *** Public Methods *** // + + /** + * Expands all items in the tree. + */ + this.expandAll = function(){ + if (!this.xmlRoot) + return; + + var xpath = this.each.split('|') + .join('[' + this.each.replace(/\|/g, " or ") + ']|.//'), + _self = this; + (function(node) { + var nodes = node.selectNodes(xpath); + //for (var i = nodes.length - 1; i >= 0; i--) { + for (var o, i = 0; i < nodes.length; i++) { + if (o = apf.xmldb.getHtmlNode(nodes[i], _self)) + _self.slideToggle(o, 1, true); + arguments.callee(nodes[i]); + } + })(this.xmlRoot); + }; + + /** + * Collapses all items in the tree. + */ + this.collapseAll = function(){ + if (!this.xmlRoot) + return; + + var pNodes = this.xmlRoot.selectNodes(".//" + this.each + .split('|').join('[' + this.each.replace(/\|/g, " or ") + ']|.//')); + + for (var o, i = pNodes.length - 1; i >=0; i--) { + if (o = apf.xmldb.getHtmlNode(pNodes[i], this)) + this.slideToggle(o, 2, true); + } + }; + + /** + * Collapse a single node in the tree. + * - xmlNode ([[XMLNode]]): The node to collapse + */ + this.collapse = function(xmlNode) { + if (!this.xmlRoot) + return; + + if (this.isCollapsed(xmlNode)) + return; + var htmlNode = apf.xmldb.getHtmlNode(xmlNode, this); + if (!htmlNode) + return; + this.slideToggle(htmlNode, 2, true); + }; + + /** + * Selects a node and expands each parent of it. + * - xmlNode ([[XMLNode]]): The node to expand + */ + this.expandAndSelect = function(xmlNode) { + if (!this.xmlRoot) + return; + + var _self = this; + if ((function _recur(loopNode) { + var pNode = _self.getTraverseParent(loopNode); + if (pNode == _self.xmlRoot) + return true; + + if (!pNode || _recur(pNode) === false) + return false; + + _self.slideToggle(apf.xmldb.getHtmlNode(pNode, _self), 1, true); + })(xmlNode) !== false) + this.select(xmlNode); + }; + + /** + * Loads a list of folders. + * paths {[String]} Array of strings in the form of `'folder[1]/folder[2]'` representing a list of folders + * onFinished {Function} A callback to be called when finished + */ + this.expandList = function (paths, onFinished) { + var _self = this; + var root = this.xmlRoot; + + // recursive load function + function expand(currentSelector, allSelectors) { + var selectorNode = root.selectSingleNode(currentSelector); + + // if the node could not be found, + // just tell the consumer that it has expanded + if (!selectorNode) { + return hasExpanded(currentSelector); + } + + // first expand the item passed in + _self.slideToggle(apf.xmldb.getHtmlNode(selectorNode, _self), 1, true, null, function () { + // the number of times the callback has fired, prevent it from executing forever + var timesRan = 0; + + // the callback fires, but we might be waiting for data from the server + var callback = function () { + // check whether the node is loaded + if (!_self.$hasLoadStatus(root.selectSingleNode(currentSelector), "loaded")) { + // if not, retry after a second (max 3 times) + if (++timesRan < 3) { + return setTimeout(function () { + _self.slideToggle(apf.xmldb.getHtmlNode(selectorNode, _self), 1, true, null, callback); + }, 1000); + } + else { + // still failing? call 'hasExpanded' for this one and all its children + // cause we're ignoring everything from now; + // and we need the callback to be fired anyway + var allAncestors = allSelectors.filter(function (s) { + return s.indexOf(currentSelector + "/") === 0; + }); + + hasExpanded(currentSelector); + allAncestors.forEach(function (sel) { + hasExpanded(sel); + }); + + return null; + } + } + + // notify + hasExpanded(); + + // when finished, find all the other selectors that start with the current selector + // plus a slash to make it really really sure + // plus we check whether it's a child and not a grand child + var childSelectors = allSelectors.filter(function (s) { + return s.indexOf(currentSelector + "/") === 0 + && currentSelector.split("/").length + 1 === s.split("/").length; + }); + + // then expand each of the child items + childSelectors.forEach(function (selector) { + expand(selector, allSelectors); + }); + }; + callback(); + }); + } + + // function to be called when an item has expanded, used to determine whether we finished + var expandCount = 0; + function hasExpanded() { + // if we have expanded all items, invoke the callback + if (++expandCount === paths.length) { + onFinished(); + } + } + + // find all rootNodes (nodes without a slash in them) + var rootNodes = paths.filter(function (p) { return p.split("/").length === 1; }); + + // expand all root nodes, expand will recursively expand all child items + rootNodes.forEach(function (node) { + expand(node, paths); + }); + }; + + /* + * @notimplemented + * @todo who's volunteering? + * @private + */ + this.selectPath = function(path) {}; + + // *** Sliding functions *** // + + /* + * @private + */ + this.slideToggle = function(htmlNode, force, immediate, userAction, callback) { + callback = typeof callback === "function" ? callback : function () {}; + + if (this.nocollapse || userAction && this.disabled) + return callback(); + + if (!htmlNode) + htmlNode = this.$selected; + + if (!htmlNode) + return callback(); + + var id = htmlNode.getAttribute(apf.xmldb.htmlIdTag); + while (!id && htmlNode.parentNode) + id = (htmlNode = htmlNode.parentNode) + .getAttribute(apf.xmldb.htmlIdTag); + + var container = this.$getLayoutNode("item", "container", htmlNode); + if (!container) return callback(); + + if (apf.getStyle(container, "display") == "block") { + if (force == 1) { + if (callback) callback(); + return; + } + htmlNode.className = htmlNode.className.replace(/min/, "plus"); + this.slideClose(container, apf.xmldb.getNode(htmlNode), immediate, callback); + } + else { + if (force == 2) { + if (callback) callback(); + return; + } + htmlNode.className = htmlNode.className.replace(/plus/, "min"); + this.slideOpen(container, apf.xmldb.getNode(htmlNode), immediate, callback); + } + }; + + this.isCollapsed = function(xmlNode) { + return (apf.getStyle(this.$getLayoutNode("item", "container", + apf.xmldb.getHtmlNode(xmlNode, this)), "display") == "none"); + } + + var lastOpened = {}; + /* + * @event expand Fires when a tree leaf is expanded from collapsed view to + * reveal its children leaves. + * @private + */ + this.slideOpen = function(container, xmlNode, immediate, callback) { + if (!xmlNode) + xmlNode = this.selected; + + var htmlNode = apf.xmldb.getHtmlNode(xmlNode, this); + if (!container) + container = this.$findContainer(htmlNode); + + //We don't slide open elements without children. + if ((!container.childNodes.length || container.firstChild.nodeType == 3 + && container.firstChild.nodeValue.trim() == "") + && !this.$getBindRule("insert", xmlNode) + && !this.getTraverseNodes(xmlNode).length) + return callback && callback(); + + if (this.singleopen) { + var pNode = this.getTraverseParent(xmlNode), + p = (pNode || this.xmlRoot).getAttribute(apf.xmldb.xmlIdTag); + if (lastOpened[p] && lastOpened[p][1] != xmlNode + && this.getTraverseParent(lastOpened[p][1]) == pNode) + this.slideToggle(lastOpened[p][0], 2);//lastOpened[p][1]); + lastOpened[p] = [htmlNode, xmlNode]; + } + + if (!this.nocollapse) + container.style.display = "block"; + + if (!this.prerender && this.$hasLoadStatus(xmlNode, "potential") + && !container.childNodes.length) { + this.$extend(xmlNode, container, immediate, callback); + return; + } + + if (immediate || container.scrollHeight > 1000) { + var _scrollTop = container.scrollHeight + - container.offsetHeight - diff - (apf.isGecko ? 16 : 0); + container.scrollTop = _scrollTop == 0 ? 100 : 0; + if (!this.nocollapse && container != this.$container) { + container.style.height = "auto"; + container.style.overflow = "visible"; + } + + if (this.$hasLoadStatus(xmlNode, "potential")) + return this.$extend(xmlNode, container, immediate, callback); + + this.dispatchEvent("expand", {xmlNode: xmlNode}); + return callback && callback(); + } + + var _self = this; + var prevHeight = container.style.height; + container.style.overflow = "visible"; + if (!apf.isIE7) { + container.style.height = apf.hasHeightAutoDrawBug ? "100%" : "auto"; + } + var height = container.scrollHeight; + container.style.overflow = "hidden"; + container.style.height = prevHeight; + + function finishSlide() { + if (xmlNode && _self.$hasLoadStatus(xmlNode, "potential")) { + $setTimeout(function(){ + if (container != this.$container) { + container.style.height = container.scrollHeight + "px"; + container.style.overflow = "hidden"; + } + _self.$extend(xmlNode, container, null, callback); + }); + if (container != this.$container) { + if (!apf.isIE7) { + container.style.height = apf.hasHeightAutoDrawBug ? "100%" : "auto"; + } + container.style.overflow = "visible"; + } + } + else if (container != this.$container) { + container.style.overflow = "visible"; + if (!apf.isIE7) { + container.style.height = apf.hasHeightAutoDrawBug ? "100%" : "auto"; + } + _self.dispatchEvent("expand", {xmlNode: xmlNode}); + } + } + + if (!this.animation) { + var diff = apf.getHeightDiff(container), + oInt = container; + + // This fixes a bug that was introduced in Chrome 20 + container.style.height = "10px"; + oInt.scrollTop = 0; + // End fix + container.style.height = Math.max((height), 0) + "px"; + _scrollTop = oInt.scrollHeight + - oInt.offsetHeight - diff - (apf.isGecko ? 16 : 0); + oInt.scrollTop = _scrollTop == 0 ? 100 : 0; + finishSlide(); + } + else { + apf.tween.single(container, { + type: 'scrollheight', + from: container.offsetHeight, + to: height, + anim: this.$animType, + steps: this.$animOpenStep, + interval: this.$animSpeed, + onfinish: function(container) { + finishSlide(); + } + }); + } + }; + + /* + * @event collapse Fires when a tree leaf is collapsed from expanded view to + * conceal its children leaves. + * @private + */ + this.slideClose = function(container, xmlNode, immediate) { + if (this.nocollapse) + return; + + if (!xmlNode) + xmlNode = this.selected; + + if (this.singleopen) { + var p = (this.getTraverseParent(xmlNode) || this.xmlRoot) + .getAttribute(apf.xmldb.xmlIdTag); + lastOpened[p] = null; + } + + if (!container) { + var htmlNode = apf.xmldb.getHtmlNode(xmlNode, this); + container = this.$findContainer(htmlNode); + } + + if (container != this.$container) { + container.style.height = container.offsetHeight; + container.style.overflow = "hidden"; + } + + if (immediate) { + if (container != this.$container) + container.style.height = 0; + container.style.display = "none"; + this.dispatchEvent("collapse", {xmlNode: xmlNode}); + return; + } + + var _self = this; + apf.tween.single(container, { + type: 'scrollheight', + from: container.scrollHeight, + to: 0, + anim: this.$animType, + steps: this.$animCloseStep, + interval: this.$animSpeed, + onfinish: function(container, data) { + container.style.display = "none"; + _self.dispatchEvent("collapse", {xmlNode: xmlNode}); + } + }); + }; + + // *** Databinding Support *** // + + this.$isStartCollapsed = function(xmlNode) { + return this.$hasBindRule("collapsed") + ? (this.$getDataNode("collapsed", xmlNode) ? true : false) + : (this.$hasBindRule("expanded") + ? (this.$getDataNode("expanded", xmlNode) ? false : true) + : this.startcollapsed); + } + + //@todo apf3.x refactor + this.$add = function(xmlNode, Lid, xmlParentNode, htmlParentNode, beforeNode, isLast, depth, nextNode, action) { + if (this.$isTreeArch && this.$needsDepth && typeof depth == "undefined") { + var loopNode = xmlParentNode; depth = 0; + while (loopNode != this.xmlRoot) { + depth++; + loopNode = loopNode.parentNode; + } + } + + var loadChildren = this.$getBindRule("insert", xmlNode) ? true : false, + traverseNodes = this.getTraverseNodes(xmlNode), + hasTraverseNodes = traverseNodes.length ? true : false, + hasChildren = loadChildren || hasTraverseNodes, + startcollapsed = this.$isStartCollapsed(xmlNode), + state = (hasChildren ? HAS_CHILD : 0) | (startcollapsed && hasChildren + || loadChildren ? IS_CLOSED : 0) | (isLast ? IS_LAST : 0), + + htmlNode = this.$initNode(xmlNode, state, Lid, depth), + container = this.$getLayoutNode("item", "container", htmlNode), + eachLength; + + if (!startcollapsed && !this.nocollapse) + container.setAttribute("style", "overflow:visible;height:auto;display:block;"); + + var msg, removeContainer = (!this.removecontainer || hasChildren); + + //TEMP on for dynamic subloading + if (!hasChildren || loadChildren) + container.setAttribute("style", "display:none;"); + + //Dynamic SubLoading (Insertion) of SubTree + if (!this.prerender) + eachLength = traverseNodes.length; + + if (hasChildren && !this.prerender && eachLength > 2 && startcollapsed + || loadChildren && (!this.$hasLoadStatus(xmlNode) + || this.$hasLoadStatus(xmlNode, "potential"))) + this.$setLoading(xmlNode, container); + else if (!hasTraverseNodes && (msg = this.$applyBindRule("empty", xmlNode))) { + this.$setEmptyMessage(container, msg); + } + + if ((!htmlParentNode || htmlParentNode == this.$container) + && xmlParentNode == this.xmlRoot && !beforeNode + || action == "insert") { + this.$nodes.push(htmlNode); + if (!apf.isChildOf(htmlNode, container, true) && removeContainer) + this.$nodes.push(container); + + if (action != "insert") { + this.$setStyleClass(htmlNode, "root"); + this.$setStyleClass(container, "root"); + } + } + else { + if (!htmlParentNode) { + htmlParentNode = apf.xmldb.getHtmlNode(xmlNode.parentNode, this); + htmlParentNode = htmlParentNode + ? this.$getLayoutNode("item", "container", htmlParentNode) + : this.$container; + } + + if (htmlParentNode == this.$container) { + this.$setStyleClass(htmlNode, "root"); + this.$setStyleClass(container, "root"); + } + + var next; + if (action != "load" && action != "extend") { + if (!beforeNode && (next = this.getNextTraverse(xmlNode))) + beforeNode = apf.xmldb.getHtmlNode(next, this); + } + if (beforeNode && beforeNode.parentNode != htmlParentNode) + beforeNode = null; + + if (htmlParentNode.style + && this.getTraverseNodes(xmlNode.parentNode).length == 1) + this.$removeEmptyMessage(htmlParentNode); + + //alert("|" + htmlNode.nodeType + "-" + htmlParentNode.nodeType + "-" + beforeNode + ":" + container.nodeType); + //Insert Node into Tree + if (htmlParentNode.style) { + var isChildOfHtmlNode = !apf.isChildOf(htmlNode, container, true) + htmlNode = apf.insertHtmlNode(htmlNode, htmlParentNode, beforeNode); + if (isChildOfHtmlNode && removeContainer) + var container = apf.insertHtmlNode(container, + htmlParentNode, beforeNode); + else + var container = this.$getLayoutNode("item", "container", htmlNode); + } + else { + htmlParentNode.insertBefore(htmlNode, beforeNode); + if (!apf.isChildOf(htmlNode, container, true) && removeContainer) + htmlParentNode.insertBefore(container, beforeNode); + } + + //Fix parent if child is added to drawn parentNode + if (htmlParentNode.style) { + if (this.openadd && htmlParentNode != this.$container + && htmlParentNode.style.display != "block") { + if (!this.$isStartCollapsed(xmlParentNode)) + this.slideOpen(htmlParentNode, xmlParentNode, true); + } + + if (!this.$fillParent) + this.$fillParent = xmlParentNode; + + var next = nextNode == undefined ? this.getNextTraverse(xmlNode, true) : nextNode; + + var html; + if (next && (html = apf.xmldb.getHtmlNode(next, this))) //should use each here + this.$fixItem(next, html); + } + } + + if ((this.prerender || eachLength < 3 || !startcollapsed) && (xmlNode.namespaceURI != apf.ns.apf || xmlNode.localName != "item")) { + this.$addNodes(xmlNode, container, false, null, null, (depth || 0) + 1); //checkChildren ??? + } + /*else { + this.$setLoadStatus(xmlNode, "potential"); + }*/ + + return container; + }; + + this.$fill = function(){ + if (this.$useiframe) + this.$pHtmlDoc = this.oDoc; + + if (this.$nodes.length) { + apf.insertHtmlNodes(this.$nodes, this.$fillParentHtml || this.$container); + this.$nodes.length = 0; + delete this.$fillParentHtml; + } + + if (this.$fillParent) { + this.$fixItem(this.$fillParent, apf.xmldb.getHtmlNode(this.$fillParent, this)); + delete this.$fillParent; + } + }; + + this.$getParentNode = function(htmlNode) { + return htmlNode + ? this.$getLayoutNode("item", "container", htmlNode) + : this.$container; + }; + + this.$fixItem = function(xmlNode, htmlNode, isDeleting, oneLeft, noChildren) { + if (!htmlNode) return; + + if (isDeleting) { + //if isLast fix previousSibling + var prevSib; + if (prevSib = this.getNextTraverse(xmlNode, true)) + this.$fixItem(prevSib, this.$findHtmlNode(prevSib + .getAttribute(apf.xmldb.xmlIdTag) + "|" + + this.$uniqueId), null, true); + + //if no sibling fix parent + if (!this.emptyMessage && xmlNode.parentNode && xmlNode.parentNode.selectNodes(this.each).length == 1) + this.$fixItem(xmlNode.parentNode, this.$findHtmlNode( + xmlNode.parentNode.getAttribute(apf.xmldb.xmlIdTag) + + "|" + this.$uniqueId), null, false, true); + } + else { + var container = this.$getLayoutNode("item", "container", htmlNode), + hasChildren = false; + if (noChildren) + hasChildren = false; + else if (this.getTraverseNodes(xmlNode).length > 0) + hasChildren = true; + else if (this.$hasLoadStatus(xmlNode, "potential")) + hasChildren = true; + else + hasChildren = false; + + var isClosed = hasChildren && apf.getStyle(container, "display") == "none"; //htmlNode.className.indexOf("min") == -1;//container.style.display != "block", + isLast = this.getNextTraverse(xmlNode, null, oneLeft ? 2 : 1) + ? false + : true, + state = (hasChildren ? HAS_CHILD : 0) + | (isClosed ? IS_CLOSED : 0) | (isLast ? IS_LAST : 0); + this.$setStyleClass(this.$getLayoutNode("item", "class", htmlNode), + treeState[state], ["min", "plus", "last", "minlast", "pluslast"]); + this.$setStyleClass(this.$getLayoutNode("item", "container", htmlNode), + treeState[state], ["min", "plus", "last", "minlast", "pluslast"]); + + if (this.$getLayoutNode("item", "openclose", htmlNode)) + this.$getLayoutNode("item", "openclose", htmlNode) + .setAttribute("children", hasChildren); + + if (container) { + if (!hasChildren) + container.style.display = "none"; + else if (!isClosed) + container.style.display = "block"; + } + } + }; + + this.$deInitNode = function(xmlNode, htmlNode) { + //Lookup container + var containerNode = this.$getLayoutNode("item", "container", htmlNode), + pContainer = htmlNode.parentNode; + + //Remove htmlNodes from tree + if (containerNode) + containerNode.parentNode.removeChild(containerNode); + pContainer.removeChild(htmlNode); + + //Datagrid?? + if (this.$withContainer) + htmlNode.parentNode.removeChild(htmlNode.nextSibling); + + //Fix Images (+, - and lines) + if (xmlNode.parentNode != this.xmlRoot) + this.$fixItem(xmlNode, htmlNode, true); + + var msg; + if (!pContainer.childNodes.length && (msg = this.$applyBindRule("empty", xmlNode))) + this.$setEmptyMessage(pContainer, msg); + + //Fix look (tree thing) + this.$fixItem(xmlNode, htmlNode, true); + //this.$fixItem(xmlNode.parentNode, apf.xmldb.findHtmlNode(xmlNode.parentNode, this)); + /*throw new Error(); + if (xmlNode.previousSibling) //should use each here + this.$fixItem(xmlNode.previousSibling, apf.xmldb.findHtmlNode(xmlNode.previousSibling, this));*/ + }; + + this.$moveNode = function(xmlNode, htmlNode, oldXmlParent) { + if (!apf.debug && !htmlNode) + return; + + var container; + if (this.$hasLoadStatus(xmlNode.parentNode, "potential")) { + container = this.$getLayoutNode("item", "container", htmlNode); + htmlNode.parentNode.removeChild(htmlNode); + container.parentNode.removeChild(container); + this.$extend(xmlNode.parentNode); + return; + } + + var nSibling = this.getNextTraverse(xmlNode), + beforeNode = nSibling + ? apf.xmldb.getHtmlNode(nSibling, this) + : null; + + var next = htmlNode.nextSibling; + if (next && next.tagName != htmlNode.tagName) + next = next.nextSibling; + if (next && beforeNode == next) + return; + + var oPHtmlNode = htmlNode.parentNode, + tParent = this.getTraverseParent(xmlNode), + pHtmlNode = apf.xmldb.getHtmlNode(tParent, this), + //if(!pHtmlNode) return; + + pContainer = pHtmlNode + ? this.$getLayoutNode("item", "container", pHtmlNode) + : this.$container; + + container = this.$getLayoutNode("item", "container", htmlNode); + + if (pContainer != oPHtmlNode && this.getTraverseNodes(xmlNode.parentNode).length == 1) + this.$removeEmptyMessage(pContainer); + + pContainer.insertBefore(htmlNode, beforeNode); + if (container) + pContainer.insertBefore(container, beforeNode); + + /*if (!this.startcollapsed) { + pContainer.style.display = "block"; + pContainer.style.height = "auto"; + }*/ + + var msg; + if (!this.getTraverseNodes(oldXmlParent).length && (msg = this.$applyBindRule("empty", oldXmlParent))) + this.$setEmptyMessage(oPHtmlNode, msg); + +// if (this.openadd && pHtmlNode != this.$container && pContainer.style.display != "block") +// this.slideOpen(pContainer, pHtmlNode, true); + + //Fix look (tree thing) + this.$fixItem(xmlNode, htmlNode); + + this.$fixItem(tParent, apf.xmldb.getHtmlNode(tParent, this)); + this.$updateNode(oldXmlParent, apf.xmldb.getHtmlNode(oldXmlParent, this)); + var next; + if (next = this.getNextTraverse(xmlNode, true)) { //should use each here + this.$fixItem(next, apf.xmldb.getHtmlNode(next, this)); + } + }; + + //??? + this.$setLoading = function(xmlNode, container) { + this.$setLoadStatus(xmlNode, "potential"); + + var len = this.getTraverseNodes(xmlNode).length; + if (!len || len > 20) { + this.$getNewContext("loading"); + apf.insertHtmlNode(this.$getLayoutNode("loading"), container); + } + }; + + //??? + this.$removeLoading = function(xmlNode) { + if (!xmlNode) return; + + if (this.$timers) + clearTimeout(this.$timers[xmlNode.getAttribute(apf.xmldb.xmlIdTag)]); + + var htmlNode = apf.xmldb.getHtmlNode(xmlNode, this); + if (htmlNode) { + this.$getLayoutNode("item", "container", htmlNode).innerHTML = ""; + this.$setStyleClass(htmlNode, "", ["loading"]); + } + }; + + //check databinding for how this is normally implemented + this.$extend = function(xmlNode, container, immediate, callback) { + if (!this.$hasLoadStatus(xmlNode, "potential")) + return; + + var rule = this.$getBindRule("insert", xmlNode), + _self = this, + xmlContext = rule && rule.match + ? (rule.cmatch || rule.compile("match"))(xmlNode) + : xmlNode; + + if (rule && xmlContext) { + this.$setLoadStatus(xmlNode, "loading"); + + var _self = this; + //(this.$timers || (this.$timers = {}))[xmlNode.getAttribute(apf.xmldb.xmlIdTag)] = $setTimeout(function(){; + _self.$setStyleClass(apf.xmldb.getHtmlNode(xmlNode, _self), "loading"); + //}, 100); + + if (this.dispatchEvent("beforeinsert", { + xmlNode: xmlNode + }) === false) + return; + + if (rule.get) { + + + this.getModel().$insertFrom(rule.getAttribute("get"), { + xmlNode: xmlContext, + insertPoint: xmlContext, + amlNode: this, + callback: function(data, state, extra) { + if (state != apf.SUCCESS) { + _self.$setLoadStatus(xmlNode, "potential"); + _self.$removeLoading(xmlNode); + _self.slideToggle(apf.xmldb.getHtmlNode(xmlNode, _self), 2, true); + } + else { + _self.slideOpen(null, xmlNode); + } + + if (callback) + callback(data, state, extra); + } + }); + } + else { + if (this.$applyBindRule("insert", xmlNode)) + this.insert(data, {insertPoint: xmlContext}); + } + } + else if (!this.prerender) { + this.$setLoadStatus(xmlNode, "loaded"); + this.$removeLoading(xmlNode); + xmlUpdateHandler.call(this, { + action: "insert", + xmlNode: xmlNode, + result: this.$addNodes(xmlNode, container, true, null, null, null, "extend"), //checkChildren ??? + anim: !immediate + }); + } + }; + + function xmlUpdateHandler(e) { + /* + Display the animation if the item added is + * Not in the cache + - Being insterted using xmlUpdate + - there is at least 1 child inserted + */ + + if (e.action == "move-away") + this.$fixItem(e.xmlNode, apf.xmldb.findHtmlNode(e.xmlNode, this), true); + + if (e.action != "insert") return; + + var htmlNode = this.$findHtmlNode(e.xmlNode.getAttribute( + apf.xmldb.xmlIdTag) + "|" + this.$uniqueId); + if (!htmlNode) return; + + //this.$hasLoadStatus(e.xmlNode, "loading") + if (e.action == "insert" && e.result.length > 0) { + if (this.$hasLoadStatus(e.xmlNode, "loaded", true)) { + var container = this.$getLayoutNode("item", "container", htmlNode); + this.slideOpen(container, e.xmlNode);//, e.$anim ? false : true + } + else if (this.$hasLoadStatus(e.xmlNode, "potential", true)) { + this.$setLoadStatus(e.xmlNode, "loaded"); + } + } + else + this.$fixItem(e.xmlNode, htmlNode); + + //Can this be removed?? (because it was added in the insert function) + //if (this.$hasLoadStatus(e.xmlNode, "loading")) + //this.$setLoadStatus(e.xmlNode, "loaded"); + } + + this.addEventListener("xmlupdate", xmlUpdateHandler); + + // *** Keyboard Support *** // + + + this.addEventListener("beforerename", function(){ + if (this.$tempsel) { + clearTimeout(this.timer); + this.select(this.$tempsel); + + this.$tempsel = null; + this.timer = null; + } + }); + + + this.scrollIntoView = function(sNode, onTop) { + var selHtml = apf.xmldb.getHtmlNode(sNode, this), top; + if (!selHtml) + return; + + top = apf.getAbsolutePosition(selHtml, this.$container)[1]; + + if (onTop) { + if (top <= this.$container.scrollTop) + this.$container.scrollTop = top; + } + else { + if (top > this.$container.scrollTop + this.$container.offsetHeight) + this.$container.scrollTop = top - this.$container.offsetHeight + selHtml.offsetHeight; + } + } + + + this.addEventListener("keydown", function(e) { + var key = e.keyCode, + ctrlKey = e.ctrlKey, + shiftKey = e.shiftKey, + selHtml = this.$caret || this.$selected, + pos, top, el, node, nodes, sNode, pNode, container; + + if (e.returnValue == -1 || !selHtml || this.renaming) //@todo how about allowdeselect? + return; + + var selXml = this.caret || this.selected, + oExt = this.$container; + + switch (key) { + case 13: + if (this.$tempsel) + this.$selectTemp(); + + if (this.ctrlselect == "enter") + this.select(this.caret, true); + + this.choose(selHtml); + break; + case 32: + if (this.$tempsel) + this.$selectTemp(); + + + if (this.$mode && !ctrlKey) { + var sel = this.getSelection(); + if (!sel.length || !this.multiselect) + this.checkToggle(this.caret, true); + else + this.checkList(sel, this.isChecked(this.selected), true, false, true); + } + else + + if (ctrlKey || !this.isSelected(this.caret)) + this.select(this.caret, true); + return false; + case 46: + if (this.disableremove) + return; + + if (this.$tempsel) + this.$selectTemp(); + + //DELETE + //this.remove(); + this.remove(); //this.mode != "check" + break; + case 36: + //HOME + this.$setTempSelected(this.getFirstTraverseNode(), false, shiftKey); + oExt.scrollTop = 0; + return false; + case 35: + //END + var lastNode = this.getLastTraverseNode(); + while (!this.isCollapsed(lastNode)) + lastNode = this.getLastTraverseNode(lastNode); + + this.$setTempSelected(lastNode, false, shiftKey, true); + oExt.scrollTop = oExt.scrollHeight; + return false; + case 37: + //LEFT + if (this.$tempsel) + this.$selectTemp(); + if (this.caret.selectSingleNode(this.each) + && !this.isCollapsed(this.caret)) + this.slideToggle(this.$caret || this.$selected, 2) + else if ((pNode = this.getTraverseParent(this.caret)) + && pNode != this.xmlRoot) + this.select(pNode) + return false; + case 107: //+ + case 187: //+ + case 39: + //RIGHT + if (this.$tempsel) + this.$selectTemp(); + + if (this.$hasLoadStatus(this.caret, "potential") + || this.getFirstTraverseNode(this.caret)) + this.slideToggle(this.$caret || this.$selected, 1) + break; + case 109: + case 189: + //- + if (this.getFirstTraverseNode(this.caret)) + this.slideToggle(this.$caret || this.$selected, 2) + break; + case 38: + //UP + if (!selXml && !this.$tempsel) + return; + + node = this.$tempsel + ? apf.xmldb.getNode(this.$tempsel) + : selXml; + + sNode = this.getNextTraverse(node, true); + if (sNode && sNode != node) { + nodes = this.getTraverseNodes(sNode); + + do { + container = this.$getLayoutNode("item", "container", + this.$findHtmlNode(apf.xmldb.getID(sNode, this))); + if (container && apf.getStyle(container, "display") == "block" + && nodes.length) { + sNode = nodes[nodes.length-1]; + } + else { + break; + } + } + while (sNode && (nodes = this.getTraverseNodes(sNode)).length); + } + else if (this.getTraverseParent(node) == this.xmlRoot) { + this.dispatchEvent("selecttop"); + return; + } + else + sNode = this.getTraverseParent(node); + + if (sNode && sNode.nodeType == 1) + this.$setTempSelected(sNode, ctrlKey, shiftKey, true); + else + return false; + + selHtml = apf.xmldb.getHtmlNode(sNode, this); + top = apf.getAbsolutePosition(selHtml, this.$container)[1] + //- (selHtml.offsetHeight); + if (top <= oExt.scrollTop) + oExt.scrollTop = top; + + return false; + case 40: + //DOWN + if (!selXml && !this.$tempsel) + return; + + node = this.$tempsel + ? apf.xmldb.getNode(this.$tempsel) + : selXml; + + sNode = this.getFirstTraverseNode(node); + if (sNode) { + container = this.$getLayoutNode("item", "container", + this.$findHtmlNode(apf.xmldb.getID(node, this))); + if (container && apf.getStyle(container, "display") != "block") + sNode = null; + } + + while (!sNode) { + pNode = this.getTraverseParent(node); + if (!pNode) break; + + var i = 0; + nodes = this.getTraverseNodes(pNode); + while (nodes[i] && nodes[i] != node) + i++; + sNode = nodes[i+1]; + node = pNode; + } + + if (sNode && sNode.nodeType == 1) + this.$setTempSelected(sNode, ctrlKey, shiftKey); + else + return false; + + selHtml = apf.xmldb.getHtmlNode(sNode, this); + top = apf.getAbsolutePosition(selHtml, this.$container)[1] + + (selHtml.offsetHeight); + if (top > oExt.scrollTop + oExt.offsetHeight) + oExt.scrollTop = top - oExt.offsetHeight; + return false; + case 33: //@todo + //PGUP + pos = apf.getAbsolutePosition(this.$container); + el = document.elementFromPoint(pos[0] + this.$container.offsetWidth + - 2, pos[1] + 2); + sNode = apf.xmldb.findXmlNode(el); + if (sNode == this.selected) { + oExt.scrollTop -= oExt.offsetHeight - apf.getHeightDiff(oExt); + el = document.elementFromPoint(pos[0] + this.$container.offsetWidth + - 2, pos[1] + 2); + sNode = apf.xmldb.findXmlNode(el); + } + this.select(sNode); + + selHtml = apf.xmldb.getHtmlNode(sNode, this); + top = apf.getAbsolutePosition(selHtml, this.$container)[1] + - (selHtml.offsetHeight); + if (top <= oExt.scrollTop) + oExt.scrollTop = top; + break; + case 34: //@todo + //PGDN + pos = apf.getAbsolutePosition(this.$container); + el = document.elementFromPoint(pos[0] + this.$container.offsetWidth + - 2, pos[1] + this.$ext.offsetHeight - 4); + sNode = apf.xmldb.findXmlNode(el); + if (sNode == this.selected) { + oExt.scrollTop += oExt.offsetHeight - apf.getHeightDiff(oExt); + el = document.elementFromPoint(pos[0] + this.$container.offsetWidth + - 2, pos[1] + this.$ext.offsetHeight - 4); + sNode = apf.xmldb.findXmlNode(el); + } + this.select(sNode); + + selHtml = apf.xmldb.getHtmlNode(sNode, this); + top = apf.getAbsolutePosition(selHtml, this.$container)[1] + + (selHtml.offsetHeight); + if (top > oExt.scrollTop + oExt.offsetHeight) + oExt.scrollTop = top - oExt.offsetHeight; + break; + default: + if (this.celledit) { + if (!ctrlKey && !e.altKey && (key > 46 && key < 112 || key > 123)) + this.startRename(null, true); + return; + } + else if (key == 65 && ctrlKey) { + this.selectAll(); + return false; + } + //@todo make this work with the sorted column + else if (this.caption || (this.bindingRules || {})["caption"]) { + if (!this.xmlRoot) return; + + //this should move to a onkeypress based function + if (!this.lookup || new Date().getTime() + - this.lookup.date.getTime() > 300) + this.lookup = { + str: "", + date: new Date() + }; + + this.lookup.str += String.fromCharCode(key); + + var nodes = this.getTraverseNodes(); //@todo start at current indicator + for (var v, i = 0; i < nodes.length; i++) { + v = this.$applyBindRule("caption", nodes[i]); + if (v && v.substr(0, this.lookup.str.length) + .toUpperCase() == this.lookup.str) { + + if (!this.isSelected(nodes[i])) + this.select(nodes[i]); + + if (selHtml) + this.$container.scrollTop = selHtml.offsetTop + - (this.$container.offsetHeight + - selHtml.offsetHeight) / 2; + return; + } + } + return; + } + break; + } + }, true); + + + // *** Rename Support *** // + + + this.$getCaptionElement = function(){ + if (!this.$selected) return false; + var x = this.$getLayoutNode("item", "caption", this.$selected); + return x.nodeType == 1 ? x : x.parentNode; + }; + + + // *** Selection Support *** // + /* + nodes = this.hasFeature(apf.__VIRTUALVIEWPORT__) + ? this.xmlRoot.selectNodes(this.$isTreeArch + ? this.each + : ".//" + this.each.split('|').join('|.//')) + : + */ + this.$calcSelectRange = function(xmlStartNode, xmlEndNode) { + var r = [], + f = false, + i = 0, + pNodeStart = this.getTraverseParent(xmlStartNode), + pNodeEnd = this.getTraverseParent(xmlEndNode), + nodes = this.getTraverseNodes(pNodeStart); + + for (; i < nodes.length; i++) { + if (nodes[i] == xmlStartNode) + f = true; + if (f) + r.push(nodes[i]); + if (nodes[i] == xmlEndNode) + f = false; + } + + if (!r.length || f) { + r = []; + for (f = false, i = nodes.length - 1; i >= 0; i--) { + if (nodes[i] == xmlStartNode) + f = true; + if (f) + r.push(nodes[i]); + if (nodes[i] == xmlEndNode) + f = false; + } + } + + return r; + }; + + this.$findContainer = function(htmlNode) { + return this.$getLayoutNode("item", "container", htmlNode); + }; + + this.$selectDefault = function(xmlNode) { + var firstNode = this.getFirstTraverseNode(xmlNode); + if (!firstNode) + return; + + if (this.select(firstNode, null, null, null, true)) { + return true; + } + else { + var nodes = this.getTraverseNodes(xmlNode); + for (var i = 0; i < nodes.length; i++) { + if (this.$selectDefault(nodes[i])) + return true; + } + } + }; + + this.$setEmptyMessage = function(htmlNode, msg) { + this.$getNewContext("empty"); + var xmlEmpty = this.$getLayoutNode("empty"); + if (!xmlEmpty) return; + + var empty = apf.insertHtmlNode(xmlEmpty, htmlNode); + empty.setAttribute("empty", "true"); + var caption = this.$getLayoutNode("empty", "caption", empty); + + if (caption) + apf.setNodeValue(caption, msg || ""); + + if (htmlNode.style) + this.slideOpen(htmlNode, null, true); + else if (this.nocollapse) + htmlNode.setAttribute("style", "display:inline-block;"); + else + htmlNode.setAttribute("style", "overflow:visible;height:auto;display:block;"); + + } + + this.$removeEmptyMessage = function(htmlNode) { + var cNode = htmlNode.firstElementChild || htmlNode.firstChild; + if (!cNode) + return; + + do { + if (cNode.getAttribute && cNode.getAttribute("empty")) { //@todo hack + htmlNode.removeChild(cNode); + return; + } + cNode = cNode.nextSibling; + } + while (cNode); + } + + // *** Init *** // + + /** + * @event click Fires when the user presses a mousebutton while over this + * element, and then lets the mousebutton go + * + */ + this.$drawBase = function(){ + //@todo apf3.0 checkmode, radiomode + /*if (!this.getAttribute("skin")) { + var mode = this.getAttribute("mode"); + this.skinName = null; + this.skin = mode + "tree"; + this.$loadSkin(); + }*/ + + //Build Main Skin + this.$ext = this.$getExternal(); + this.$container = this.$getLayoutNode("main", "container", this.$ext); + this.opencloseaction = this.$getOption("main", "openclose"); + + //Need fix... + //this.$ext.style.MozUserSelect = "none"; + + if (apf.hasCssUpdateScrollbarBug && !this.mode) + this.$fixScrollBug(); + + var _self = this; + this.$ext.onclick = function(e) { + _self.dispatchEvent("click", {htmlEvent : e || event}); + }; + this.$ext.onmousedown = function(e) { + _self.dispatchEvent("mousedown", {htmlEvent : e || event}); + }; + this.$ext.onmouseover = function(e) { + _self.dispatchEvent("mouseover", {htmlEvent : e || event}); + }; + this.$ext.onmouseout = function(e) { + _self.dispatchEvent("mouseout", {htmlEvent : e || event}); + }; + this.$ext.onmousemove = function(e) { + _self.dispatchEvent("mousemove", {htmlEvent : e || event}); + }; + }; + + this.addEventListener("DOMNodeInsertedIntoDocument", function(){ + if (this.nocollapse) + this.startcollapsed = false; + else if (this.startcollapsed === 1) + this.startcollapsed = !apf.isFalse(this.$getOption("main", "startcollapsed")); + }); + + this.addEventListener("DOMNodeRemovedFromDocument", function(){ + this.$ext.onclick = null; + + apf.destroyHtmlNode(this.oDrag); + this.oDrag = null; + }); + +}).call(apf.BaseTree.prototype = new apf.MultiSelect()); + + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + +apf.__DELAYEDRENDER__ = 1 << 11 + + + +/** + * All elements inheriting from this {@link term.baseclass baseclass} have delayed + * rendering features. + * + * Any element that is (partially) hidden at startup has the + * possibility to delay rendering its childNodes by setting `render="runtime"` on + * the element. These elements include `window`, `pane`, `pages`, `form` and c`ontainer`. + * For instance, a pane tab in a container is initally hidden and does not + * need to be rendered. When the pane button is pressed to activate the tab, + * the tab is rendered and then displayed. This can dramatically decrease + * the startup time of the application. + * + * #### Example + * + * In this example the button isn't rendered until the advanced pane becomes active. + * + * ```xml + * + * + * ... + * + * + * OK + * + * + * ``` + * @class apf.DelayedRender + * @baseclass + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.8.9 + */ +/** + * @event beforerender Fires before elements are rendered. Use this event to display a loader. + * @cancelable Prevents rendering of the childNodes + */ +/** + * @event afterrender Fires after elements are rendered. Use this event to hide a loader. + * + */ +/** + * @attribute {String} render Sets or gets when the contents of this element is rendered. + * + * Possible values include: + * + * - init: elements are rendered during the initialization of the application. + * - runtime: elements are rendered when the user requests them. + */ +/** + * @attribute {Boolean} use-render-delay Sets or gets whether there's a short delay between showing this element and rendering its contents. + * + * If `true`, the elements are rendered immediately. Otherwise, there is a delay between showing this element and the actual rendering, + * allowing the browsers' render engine to draw (for instance, a loader). + * + */ +apf.DelayedRender = function(){ + this.$regbase = this.$regbase | apf.__DELAYEDRENDER__; + this.$rendered = false; + + /* + * Renders the children of this element. + * + * @param {Boolean} [usedelay] Specifies whether a delay is added between calling + * this function and the actual rendering. This allows the browsers' + * render engine to draw (for instance a loader). + */ + this.$render = function(usedelay) { + if (this.$rendered) + return; + + if (this.dispatchEvent("beforerender") === false) + return; + + if (this["render-delay"] || usedelay) + $setTimeout("apf.lookup(" + this.$uniqueId + ").$renderparse()", 10); + else + this.$renderparse(); + }; + + this.$renderparse = function(){ + if (this.$rendered) + return; + + // Hide render pass from sight for inner callstack + // redrawing browsers like firefox + this.$ext.style.visibility = "hidden"; + + var domParser = this.ownerDocument.$domParser; + domParser.parseFromXml(this.$aml, { + amlNode: this, + doc: this.ownerDocument, + //nodelay : true, + delayedRender: true + }); + domParser.$continueParsing(this); + + this.$rendered = true; + + this.dispatchEvent("afterrender"); + this.addEventListener("$event.afterrender", function(cb) { + cb.call(this); + }); + + this.$ext.style.visibility = ""; + }; + + /*var _self = this; + if (apf.window.vManager.check(this, "delayedrender", function(){ + _self.$render(); + })) this.$render();*/ + + var f; + this.addEventListener("prop.visible", f = function(){ + if (arguments[0].value) { + + this.$render(); + + + this.removeEventListener("prop.visible", f); + } + }); +}; + +apf.GuiElement.propHandlers["render"] = function(value) { + if (!this.hasFeature(apf.__DELAYEDRENDER__) && value == "runtime") { + this.implement(apf.DelayedRender); + + if (this.localName != "tab") { + this.visible = false; + this.$ext.style.display = "none"; + } + + if (typeof this["render-delay"] == "undefined") + this.$setInheritedAttribute("render-delay"); + } +}; + +apf.config.$inheritProperties["render-delay"] = 1; + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + +apf.__DRAGDROP__ = 1 << 5; + + + +/** + * All elements inheriting from this {@link term.baseclass baseclass} have drag & drop + * features. + * + * This baseclass operates on the bound data of this element. + * When a rendered item is dragged and dropped, the bound data is moved or + * copied from one element to another, or to the same element but at a different + * position. This is possible because the rendered item has a + * {@link term.smartbinding bidirectional connection} to the data. Drag & drop can + * be turned on with a simple boolean, or by specifying detailed rules to set + * which data can be dragged and dropped and where. + * + * + * #### Example + * + * This is a simple example, enabling drag & drop for a list: + * + * ```xml + * + * ``` + * + * + * #### Example + * + * This example shows a smartbinding that represents files and folders. It uses a + * {@link term.datainstruction data instruction} to communicate to the webdav + * server when an item is copied or moved. + * + * ```xml + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * ``` + * + * #### Example + * + * This example shows a small mail application. The tree element displays a root + * node, accounts and folders in a tree. The datagrid contains the mails. This + * rule specifies which data nodes can be dropped where. Folders can be dropped + * in folders and accounts. Mails can be dropped in folders. + * + * ```xml + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *``` + * + * @class apf.DragDrop + * @baseclass + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.5 + * @define dragdrop + * @allowchild drop, drag + * @define drag + */ +/** + * @event dragdata Fires before a drag & drop operation is started to determine the data that is dragged. + * @param {Object} e The standard event object. It contains the following property: + * - `data` ([[XMLElement]]): The default data for the drag & drop operation + */ +/** + * @event dragstart Fires before a drag operation is started. + * @cancelable Prevents the drag operation to start. + * @param {Object} e The standard event object. It contains the following properties: + * - `data` ([[XMLElement]]): The data for the drag & drop operation + * - `selection` ([[XMLElement]]): The selection at the start of the drag operation + * - `indicator` ([[HTMLElement]]): The HTML element that is shown while dragging the data + * - `host` ([[apf.AmlElement]]): The AML source element. + */ +/** + * @event dragover Fires when the users drags over this AML element. + * @cancelable Prevents the possibility to drop. + * @param {Object} e The standard event object. It contains the following properties: + * {XMLElement} data The data for the drag & drop operation + * {XMLElement} selection The selection at the start of the drag operation + * {HTMLElement} indicator The HTML element that is shown while dragging the data + * {apf.AmlElement} host the AML source element. + */ +/** + * @event dragout Fires when the user moves away from this AML element. + * @param {Object} e The standard event object. It contains the following properties: + * {XMLElement} data the data for the drag & drop operation + * {XMLElement} selection the selection at the start of the drag operation + * {HTMLElement} indicator the HTML element that is shown while dragging the data + * {apf.AmlElement} host the aml source element. + */ +/** + * @event dragdrop Fires when the user drops an item on this aml element. + * @cancelable Prevents the possibility to drop. + * @param {Object} e The standard event object. It contains the following properties: + * {XMLElement} data The data for the drag & drop operation + * {XMLElement} selection The selection at the start of the drag operation + * {HTMLElement} indicator The html element that is shown while dragging the data + * {apf.AmlElement} host The AML source element. + * {Boolean} candrop Specifies whether the data can be inserted at the point hovered over by the user + * + * + */ +/** + * @attribute {String} match An XPath statement querying the + * {@link term.datanode data node} that is + * dragged. If the query matches a node it + * is allowed to be dropped. The XPath is + * automatically prefixed by `'self::'`. + */ +/** + * @attribute {String} copy A JavaScript expression that determines + * whether the dragged element is a copy or + * a move. Use event.ctrlKey to use the Ctrl + * key to determine whether the element is copied. + * + */ +/** + * @attribute {String} match An XPath statement querying the + * {@link term.datanode data node} that is + * dragged. If the query matches a node it + * is allowed to be dropped. The XPath is + * automatically prefixed by `'self::'`. + */ +/** + * @attribute {String} target An XPath statement determining the new + * parent of the dropped {@link term.datanode data node}. + * The XPath is automatically prefixed by `'self::'`. + */ +/** + * @attribute {String} action The action to perform when the + * {@link term.datanode data node} is inserted. + * The possible values include: + * + * - `tree-append`: Appends the {@link term.datanode data node} to the element its dropped on. + * - `list-append`: Appends the {@link term.datanode data node} to the root element of this element. + * - `insert-before`: Inserts the {@link term.datanode data node} before the elements its dropped on. + */ +/** + * @attribute {String} copy A JavaScript expression that determines + * whether the drop is a copy or a move. + * Use event.ctrlKey to use the [[keys: Ctrl]] key to + * determine whether the element is copied. + */ +apf.DragDrop = function(){ + this.$regbase = this.$regbase | apf.__DRAGDROP__; + + this.$dragInited = false; + + /* ********************** + Actions + ***********************/ + + /** + * Copies a {@link term.datanode data node} to the bound data of this element. + * + * @action + * @param {XMLElement} xmlNode The {@link term.datanode data node} which is copied. + * @param {XMLElement} [pNode] The new parent element of the copied + * {@link term.datanode data node}. If none is + * specified the root element of the data + * loaded in this element is used. + * @param {XMLElement} [beforeNode] The position where the {@link term.datanode data node} + * is inserted. + */ + this.copy = function(nodeList, pNode, beforeNode, isMove) { + if (nodeList.nodeType) + nodeList = [nodeList]; + + var exec, + changes = [], + i = 0, + l = nodeList.length; + for (; i < l; i++) { + changes.push({ + action: isMove ? "moveNode" : "appendChild", + args: [pNode, isMove + ? nodeList[i] + : nodeList[i] = nodeList[i].cloneNode(true), beforeNode] + }); + } + + if (this.$actions[(isMove ? "movegroup" : "copygroup")]) { + exec = this.$executeAction("multicall", changes, + (isMove ? "movegroup" : "copygroup"), nodeList[0]); + } + else { + exec = this.$executeAction("multicall", changes, + (isMove ? "move" : "copy"), nodeList[0], null, null, + nodeList.length > 1 ? nodeList : null); + } + + if (exec !== false) + return nodeList; + + return false; + }; + + /** + * Moves a {@link term.datanode data node} to the bound data of this element. + * + * @action + * @param {XMLElement} xmlNode The {@link term.datanode data node} which is copied. + * @param {XMLElement} [pNode] The new parent element of the moved + * {@link term.datanode data node}. If none + * specified the root element of the data + * loaded in this element is used. + * @param {XMLElement} [beforeNode] The position where the + * {@link term.datanode data node} is inserted. + */ + this.move = function(nodeList, pNode, beforeNode) { + return this.copy(nodeList, pNode, beforeNode, true); + }; + + /** + * Determines whether the user is allowed to drag the passed + * {@link term.datanode data node}. + * + * For instance, imagine a mail application with a root + * node, accounts and folders in a tree, and mails in a datagrid. The rules + * would specify you can drag & drop folders within an account, and emails between + * folders, but not on accounts or the root. + * + * @param {XMLElement} dataNode The {@link term.datanode data node} subject to the test. + * @return {Boolean} The result of the test + * @see apf.DragDrop.isDragAllowed + */ + this.isDragAllowed = function(x, data) { + + + if (!this.dragroot && this.xmlRoot.firstChild == x[0]) + return false; + + if (this.disabled || !x || !x.length || !x[0]) + return false; + + if (this.drag || this.dragcopy) { + if (data) + data.merge(x); + return true; + } + + /*var rules = this.$bindings["drag"] + || this.$attrBindings && this.$attrBindings["drag"]; + if (!rules || !rules.length) + return false;*/ + + var d, + ruleList = [], + j = 0, + l = x.length; + for (; j < l; j++) { + d = this.$getDataNode("drag", x[j], null, ruleList); + if (!d) return false; //It's all or nothing + if (data) + data.push(d); + } + + return ruleList.length ? ruleList : false; + }; + + /** + * Determines whether the user is allowed to drop the passed + * {@link term.datanode data node}. + * + * For instance, imagine a mail application with a root + * node, accounts and folders in a tree, and mails in a datagrid. The rules + * would specify you can drag & drop folders within an account, and emails between + * folders, but not on accounts or the root. + * + * @param {XMLElement} dataNode The {@link term.datanode data node} subject + * to the test. + * @param {XMLElement} target The {@link term.datanode data node} on which + * the dragged data node is dropped. + * @return {Boolean} The result of the test + * @see apf.DragDrop.isDragAllowed + */ + this.isDropAllowed = function(x, target) { + + + if (this.disabled || !x || !x.length || !target) //!x[0] ??? + return false; + + if (!this.dragroot == false && this.xmlRoot.firstChild == x[0]) + return false; + + for (var i = x.length - 1; i >= 0; i--) + if (apf.isChildOf(x[i], target, true)) + return false; + + var data, tgt, hasDropRule = this.$attrBindings && this.$attrBindings["drop"]; + if (this.drop && (!hasDropRule || hasDropRule.value == "true")) { + this.$setDynamicProperty("drop", this.hasFeature(apf.__MULTISELECT__) + ? "[" + this.each + "]" + : "[node()]"); //@todo apf3.0 make sure each is without {} + hasDropRule = true; + } + + if (hasDropRule) { + for (var j = 0, l = x.length; j < l; j++) { + data = this.$getDataNode("drop", x[j]); + if (!data) + break; + } + if (j == l && target && !apf.isChildOf(data, target, true)) + return [target, null]; + } + + var rules = this.$bindings["drop"]; + if (!rules || !rules.length) + return false; + + //@todo this can be optimized when needed + var rule, strTgt, + i = 0, + rl = rules.length; + for (; i < rl; i++) { + rule = this.$bindings.getRuleIndex("drop", i); + + for (var j = 0, l = x.length; j < l; j++) { + data = rule.cvalue ? rule.cvalue(x[j]) : rule.cmatch(x[j]); + if (!data) + break; + } + if (j != l) + continue; + + strTgt = rule.target;//node.getAttribute("target"); + if (!strTgt || strTgt == ".") { + //op = node.getAttribute("action") + //|| (this.$isTreeArch ? "tree-append" : "list-append"); + tgt = target;/*(op == "list-append" || target == this.xmlRoot + ? this.xmlRoot + : null);*/ + } + else { + tgt = (rule.ctarget || rule.compile("target"))(target); + } + + if (tgt && !apf.isChildOf(data, tgt, true)) + return [tgt, rule]; + } + + return false; + }; + + this.$dragDrop = function(xmlReceiver, xmlNodeList, rule, defaction, isParent, srcRule, event, forceCopy) { + /* + Possibilities: + + tree-append [default]: xmlNode.appendChild(movedNode); + list-append : xmlNode.parentNode.appendChild(movedNode); + insert-before : xmlNode.parentNode.insertBefore(movedNode, xmlNode); + */ + var action = rule && rule.action;//node && node.getAttribute("action"); + + if (action) + action = (rule.caction || rule.compile("action"))(xmlNodeList[0]); + else + action = defaction; + + // @todo apf3.0 action not known here yet... should be moved down? + if (action == "tree-append" && isParent) + return false; + + if (!event) + event = {}; + + //copy convenience variables + var context = { + internal: apf.DragServer.dragdata && apf.DragServer.dragdata.host == this, + ctrlKey: event.ctrlKey, + keyCode: event.keyCode + }, + //@todo apf3.0 below should actually be compileNode with with_options + ifcopy = rule && rule.copy;//.getAttribute("copy"); + + if (typeof forceCopy == "boolean") + ifcopy = forceCopy; + else if (ifcopy) { + context.event = event || {}; + ifcopy = !apf.isFalse((rule.ccopy || rule.compile("copy"))(xmlNodeList[0], context)); + } + else if (typeof this.dragcopy == "boolean" || typeof this.dropcopy == "boolean") { //@todo apf3.0 boolean here? + if (this.dropcopy) { + ifcopy = this.dropcopy; + } + else if (this.dragcopy) { + ifcopy = event.ctrlKey; + } + else { + //@todo read this from src + var copyRule = this.$attrBindings && this.$attrBindings["dragcopy"]; + if (copyRule) { + ifcopy = !apf.isFalse((copyRule.cvalue2 + || copyRule.compile("value", { + withopt: true + }))(xmlNodeList[0], context)); + } + } + } + + if (!ifcopy && srcRule) { //Implemented one copy is all copy + for (var i = 0, l = srcRule.length; i < l; i++) { + ifcopy = typeof srcRule[i] == "object" && srcRule[i].copy + ? !apf.isFalse((srcRule[i].ccopy || srcRule[i].compile("copy"))(xmlNodeList[0], context)) + : event.ctrlKey; + if (ifcopy) break; + } + } + + var sNode, + actRule = ifcopy ? "copy" : "move", + parentXpath = rule ? rule.getAttribute("parent") : null; //@todo apf3.0 Should be lm syntax + switch (action) { + case "list-append": + xmlReceiver = (isParent + ? xmlReceiver + : this.getTraverseParent(xmlReceiver)); + if (parentXpath) { + if (xmlReceiver.selectSingleNode(parentXpath)) + xmlReceiver = xmlReceiver.selectSingleNode(parentXpath); + else { + xmlReceiver.appendChild(xmlReceiver.ownerDocument.createElement(parentXpath)); + xmlReceiver = xmlReceiver.selectSingleNode(parentXpath); + } + } + sNode = this[actRule](xmlNodeList, xmlReceiver); + break; + case "insert-before": + sNode = isParent + ? this[actRule](xmlNodeList, xmlReceiver) + : this[actRule](xmlNodeList, xmlReceiver.parentNode, xmlReceiver); + break; + case "tree-append": + if (parentXpath) { + if (xmlReceiver.selectSingleNode(parentXpath)) + xmlReceiver = xmlReceiver.selectSingleNode(parentXpath); + else { + xmlReceiver.appendChild(xmlReceiver.ownerDocument.createElement(parentXpath)); + xmlReceiver = xmlReceiver.selectSingleNode(parentXpath); + } + } + sNode = this[actRule](xmlNodeList, xmlReceiver); + break; + } + + if (this.selectable && sNode) { + this.selectList(sNode);//, null, null, null, true); + this.setCaret(sNode[0]); + this.focus(); + } + + return sNode; + }; + + /* ********************** + Init + ***********************/ + + /* + * Loads the dragdrop rules from the dragdrop element + * + * @param {Array} rules The rules array created using {@link core.apf.method.getrules} + * @param {XMLElement} [node] The reference to the drag & drop element + * @see SmartBinding + * @private + */ + this.enableDragDrop = function(){ + + + //Set cursors + //SHOULD come from skin + this.icoAllowed = "";//this.xmlDragDrop.getAttribute("allowed"); + this.icoDenied = "";//this.xmlDragDrop.getAttribute("denied"); + + //Setup External Object + this.$ext.dragdrop = false; + + var _self = this; + + this.$ext[apf.isIphone ? "ontouchstart" : "onmousedown"] = function(e) { + if (_self.disabled) + return; + + e = e || window.event; + + + var fEl, + srcEl = e.originalTarget || e.srcElement || e.target, + multiselect = _self.hasFeature(apf.__MULTISELECT__); + if (multiselect && srcEl == _self.$container) + return; + _self.dragging = 0; + + try{ //Firefox can crash here because of some chrome permission issue + if (!apf.isIphone && _self.allowdeselect + && (srcEl == this || srcEl.getAttribute(apf.xmldb.htmlIdTag) + && _self.$getLayoutNode("item", "select", this) != this)) + return; //This broke making a selection with the mouse in rename: _self.clearSelection(); //@todo hacky - should detect what element has the select from the skin + }catch(e) {return;} + + //MultiSelect must have carret behaviour AND deselect at clicking white + if (_self.$findValueNode) + fEl = _self.$findValueNode(srcEl); + var el = (fEl + ? apf.xmldb.getNode(fEl) + : apf.xmldb.findXmlNode(srcEl)); + if (multiselect && (!_self.selected || !el || el == _self.xmlRoot)) + return; + + if (_self.isDragAllowed(multiselect ? _self.$getSelection() : el)) { + + + apf.DragServer.start(_self, srcEl, e); + } + + //e.cancelBubble = true; + }; + + this.$ext[apf.isIphone ? "ontouchmove" : "onmousemove"] = function(e) { + if (this.host.dragging != 1 || _self.disabled) return; + }; + + + { + this.$ext.onmouseup = function(){ + if (_self.disabled) + return; + + this.host.dragging = 0; + }; + + this.$ext.ondragcopy = + this.$ext.ondragstart = function(){return false;}; + } + + if (document.elementFromPointAdd) + document.elementFromPointAdd(this.$ext); + + if (this.$initDragDrop && !this.$dragInited) { + this.$initDragDrop(); + this.$dragInited = 2; + } + else { + this.$dragInited = true; + } + }; + + function disableDragDrop(){ + this.$dragInited = false; //@todo solve oExt event conflicts + + + { + this.$ext.onmousedown = this.$ext.onmousemove + = this.$ext.onmouseup = null; + } + + if (document.elementFromPointRemove) + document.elementFromPointRemove(this.$ext); + } + + this.implement( + + this.hasFeature(apf.__MULTISELECT__) + ? apf.MultiselectDragDrop : + + apf.StandardDragDrop); + + //this.$booleanProperties["drag"] = true; + //this.$booleanProperties["dragcopy"] = true; + this.$supportedProperties.push("drop", "drag", "dragcopy"); + + /** + * @attribute {Boolean} drag Sets or gets whether the element allows dragging of its items. + * + * #### Example + * + * ```xml + * + * + * item 1 + * item 2 + * item 3 + * + *``` + * + */ + /** + * @attribute {Boolean} dragcopy whether dragged items are copied. + * + * #### Example + * + * ```xml + * + * + * + * + * + * + * + * + * + * ``` + * + * #### Example + * + * Items are only copied when the user holds the [[keys: Ctrl]] key + * + * ```xml + * + * item 1 + * item 2 + * item 3 + * + * ``` + */ + /** + * @attribute {Boolean} drop Sets or gets whether the element allows items to be dropped. + * + * #### Example + * + * + * ```xml + * + * item 1 + * item 2 + * item 3 + * + * ``` + * @attribute {String} dragdrop Sets or gets the name of the dragdrop element for this element. + * + * ```xml + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * ``` + */ + this.$propHandlers["dragcopy"] = + this.$propHandlers["dropcopy"] = + this.$propHandlers["drag"] = + this.$propHandlers["drop"] = function(value, prop) { + this[prop] = apf.isTrue(value); + + if (this.$dragInited && prop == "drag" && value && this.$dragInited != 2) { + this.$initDragDrop(); + this.$dragInited = 2; + return; + } + + if (prop == "dragcopy" || prop == "dropcopy") + return; + + if (!value && !this.drag && !this.drop && !this.$bindings + && (this.$attrBindings && (!this.$attrBindings["drag"] || !this.$attrBindings["drop"]))) + disableDragDrop.call(this); + else if (value && !this.$dragInited) + this.enableDragDrop(); + }; + + this.addEventListener("DOMNodeRemovedFromDocument", function(e) { + disableDragDrop.call(this); + + if (this.oDrag) { + apf.destroyHtmlNode(this.oDrag); + this.oDrag = null; + } + }); +}; + +apf.GuiElement.propHandlers["dragcopy"] = +apf.GuiElement.propHandlers["dropcopy"] = +apf.GuiElement.propHandlers["drop"] = +apf.GuiElement.propHandlers["drag"] = function(value, prop) { + if (!apf.isFalse(value)) { + if (!this.hasFeature(apf.__DRAGDROP__)) { + this.implement(apf.DragDrop); + this.enableDragDrop(); + } + + this[prop] = apf.isTrue(value); + } +}; + +/* + * Central object for dragdrop handling. + * @private + */ +apf.DragServer = { + Init: function(){ + + + apf.addEventListener("hotkey", function(e) { + if (apf.window.dragging && e.keyCode == 27) { + if (document.body.lastHost && document.body.lastHost.dragOut) + document.body.lastHost.dragOut(apf.dragHost); + + return apf.DragServer.stopdrag(); + } + }); + }, + + start: function(amlNode, srcEl, e, customNode) { + if (document.elementFromPointReset) + document.elementFromPointReset(); + + amlNode.dragging = 1; + + var d = window.document; + d = (!d.compatMode || d.compatMode == "CSS1Compat") + ? d.html || d.documentElement + : d.body + + var scrollX = (apf.isIE ? d.scrollLeft : window.pageXOffset), + scrollY = (apf.isIE ? d.scrollTop : window.pageYOffset), + oParent = amlNode.$ext.offsetParent, + pos + while (oParent && oParent != d && oParent.tagName != "BODY") { + scrollX -= oParent.scrollLeft; + scrollY -= oParent.scrollTop; + oParent = oParent.offsetParent; + } + + //The coordinates need to be relative to the html element that + //represents the xml data node. + if (!srcEl && customNode) { + pos = [0, 0]; + } + else { + var loopEl = srcEl, lastId; + while (loopEl && loopEl.nodeType == 1 + && !(lastId = loopEl.getAttribute(apf.xmldb.htmlIdTag))) { + loopEl = loopEl.parentNode; + } + if (!lastId) + return; + pos = apf.getAbsolutePosition(loopEl); + } + + //Set coordinates object + apf.DragServer.coordinates = { + srcElement: srcEl, + doc: d, + scrollX: scrollX, + scrollY: scrollY, + offsetX: e.clientX - pos[0], + offsetY: e.clientY - pos[1], + clientX: e.pageX ? e.pageX - window.pageXOffset : e.clientX, + clientY: e.pageY ? e.pageY - window.pageYOffset : e.clientY + }; + + //Create Drag Data Object + var selection = customNode || amlNode.hasFeature(apf.__MULTISELECT__) + ? amlNode.getSelection() + : [amlNode.xmlRoot], + data = [], + srcRules = amlNode.isDragAllowed(selection, data); + if (!srcRules) return; + + if (amlNode.hasEventListener("dragdata")) + data = amlNode.dispatchEvent("dragdata", {data : data}); + + /*for(var i = 0, l = data.length; i < l; i++) { + data[i] = apf.getCleanCopy(data[i]); + }*/ + + this.dragdata = { + rules: srcRules, + selection: selection, + data: data, + indicator: amlNode.$showDragIndicator(selection, this.coordinates), + host: amlNode + }; + + //EVENT - cancelable: ondragstart + if (amlNode.dispatchEvent("dragstart", this.dragdata) === false) + return false;//(this.amlNode.$tempsel ? select(this.amlNode.$tempsel) : false); + + amlNode.dragging = 2; + + apf.dragMode = true; + document.onmousemove = this.onmousemove; + document.onmouseup = this.onmouseup; + }, + + stop: function(runEvent, success, e) { + if (this.last) this.dragout(); + + this.dragdata.host.dispatchEvent("dragstop", apf.extend(this.dragdata, { + success: success + })); + + //Reset Objects + this.dragdata.host.dragging = 0; + this.dragdata.host.$hideDragIndicator(success); + + /*if (runEvent && this.dragdata.host.$dragstop) + this.dragdata.host.$dragstop();*/ + + apf.dragMode = false; + document.onmousemove = + document.onmouseup = null; + + this.dragdata = null; + }, + + dragover: function(o, el, e) { + var _self = this, + originalEl = el; + + function checkPermission(targetEl) { + return o.isDropAllowed && o.xmlRoot + ? o.isDropAllowed(_self.dragdata.data, targetEl) + : apf.isTrue(apf.getInheritedAttribute(o, "", function(p) { + if (p.drop) { + o = p; + if (o == apf.DragServer.last) + return false; + return true; + } + })); + } + + e = e || window.event; + + //@todo optimize by not checking the same node dragged over twice in a row + var fEl; + if (o.$findValueNode) + fEl = o.$findValueNode(el); + + if (this.lastFel && this.lastFel == fEl + || !this.lastFel && this.last == o) //optimization + return; + + //Check Permission + var elSel = (fEl + ? apf.xmldb.getNode(fEl) + : apf.xmldb.findXmlNode(el)), + candrop = checkPermission(elSel || o.xmlRoot); + + if (this.last && this.last != o) + this.dragout(this.last, e); + + this.last = o; + this.lastFel = fEl; + + if (!candrop) { + if (o && o.$dragover) { + var parentNode = (elSel || o.xmlRoot).parentNode; + if (parentNode && (el = apf.xmldb.findHtmlNode(parentNode, o))) { + if (o.$findValueNode) + fEl = o.$findValueNode(el); + + elSel = (fEl + ? apf.xmldb.getNode(fEl) + : apf.xmldb.findXmlNode(el)); + + candrop = checkPermission(parentNode); + this.lastFel = el; + + + if (!candrop) + return; + } + else + return; + } + else + return; + } + + //EVENT - cancelable: ondragover + if (o.dispatchEvent("dragover", this.dragdata, { + target: (elSel || o.xmlRoot), + lastEl: o.lastel, + originalEl: originalEl + }) === false) + candrop = false; + + //Set Cursor + var srcEl = e.originalTarget || e.srcElement || e.target; + /*srcEl.style.cursor = (candrop ? o.icoAllowed : o.icoDenied); + if (srcEl.onmouseout != this.m_out) { + srcEl.$onmouseout = srcEl.onmouseout; + srcEl.onmouseout = this.m_out; + } + o.$ext.style.cursor = (candrop ? o.icoAllowed : o.icoDenied);*/ + + //REQUIRED INTERFACE: __dragover() + if (o && o.$dragover) + o.$dragover(el, this.dragdata, candrop); + }, + + dragout: function(o, e) { + //if (this.last == o) + //return false; + + this.lastFel = null; + + //EVENT: ondragout + if (o) { + this.dragdata.htmlEvent = e; + o.dispatchEvent("dragout", this.dragdata); + } + + //REQUIRED INTERFACE: __dragout() + if (this.last && this.last.$dragout) + this.last.$dragout(null, this.dragdata); + + //Reset Cursor + //o.$ext.style.cursor = "default"; + this.last = null; + }, + + dragdrop: function(o, el, srcO, e) { + var _self = this; + + function checkPermission(targetEl) { + return o.isDropAllowed && o.xmlRoot + ? o.isDropAllowed(_self.dragdata.data, targetEl) + : apf.isTrue(apf.getInheritedAttribute(o, "", function(p) { + if (p.drop) { + o = p; + return true; + } + })); + } + + //Check Permission + var isParent, lastTop, + elSel = (o.$findValueNode + ? apf.xmldb.getNode(o.$findValueNode(el)) + : apf.xmldb.findXmlNode(el)), + candrop = checkPermission(elSel || o.xmlRoot); + + if (this.dragdata.indicator) { + lastTop = this.dragdata.indicator.style.top; + this.dragdata.indicator.style.top = "10000px"; + } + + if (!candrop) { + if (o && o.$dragover) { + var parentNode = (elSel || o.xmlRoot).parentNode, + htmlParentNode; + if (parentNode && (htmlParentNode = apf.xmldb.findHtmlNode(parentNode, o))) { + isParent = true; + candrop = checkPermission(parentNode); + el = htmlParentNode; + } + } + } + + //EVENT - cancelable: ondragdrop + if (candrop) { + if (o.dispatchEvent("dragdrop", apf.extend({candrop : candrop, htmlEvent : e, top: lastTop}, + this.dragdata)) === false) { + candrop = false; + } + else { + if (!o.xmlRoot) { + var m = o.getModel + ? o.getModel(true) + : + + apf.nameserver.get("model", o.model) + + if (m) + m.load(this.dragdata.data[0]) + //else warn?? + return true; + } + else { + var action = candrop[1] + && candrop[1].action + || (o.$isTreeArch ? "tree-append" : "list-append"); + if (action == "list-append" && (!o.$isTreeArch && o == this.dragdata.host)) + candrop = false; + } + } + } + + if (this.dragdata.indicator) + this.dragdata.indicator.style.top = lastTop; + + //Exit if not allowed + if (!candrop) { + this.dragout(o, e); + return false; + } + + if (o.$dragDrop) { + //Move XML + var rNode = o.$dragDrop(candrop[0], this.dragdata.data, candrop[1], + action, isParent || candrop[0] == o.xmlRoot, this.dragdata.rules, e); + this.dragdata.resultNode = rNode; + } + + if (o.$dragdrop) { + o.$dragdrop(el, apf.extend({ + htmlEvent: e, + xmlNode: rNode + }, this.dragdata), candrop); + } + + //Reset Cursor + //o.$ext.style.cursor = "default"; + this.last = null; + this.lastFel = null; + + return true; + }, + + /* ********************** + Mouse Movements + ***********************/ + + onmousemove: function(e) { + if (!apf.DragServer.dragdata) return; + e = e || window.event; + + + var dragdata = apf.DragServer.dragdata, + c = { + clientX: e.pageX ? e.pageX - window.pageXOffset : e.clientX, + clientY: e.pageY ? e.pageY - window.pageYOffset : e.clientY + }; + + if (!dragdata.started + && Math.abs(apf.DragServer.coordinates.clientX - c.clientX) < 6 + && Math.abs(apf.DragServer.coordinates.clientY - c.clientY) < 6) + return; + + if (!dragdata.started) { + if (dragdata.host.$dragstart) + dragdata.host.$dragstart(null, dragdata); + dragdata.started = true; + } + + //dragdata.indicator.style.top = e.clientY+"px"; + //dragdata.indicator.style.left = e.clientX+"px"; + + if (dragdata.indicator) { + var storeIndicatorTopPos = dragdata.indicator.style.top; + //console.log("INDICATOR BEFORE: "+dragdata.indicator.style.top+" "+dragdata.indicator.style.left); + //get Element at x, y + dragdata.indicator.style.display = "block"; + dragdata.indicator.style.top = "10000px"; + } + apf.DragServer.dragdata.x = e.pageX ? e.pageX - (!apf.isIE + ? window.pageXOffset + : 0) : c.clientX; + apf.DragServer.dragdata.y = e.pageY ? e.pageY - (!apf.isIE + ? window.pageYOffset + : 0) : c.clientY; + var el = document.elementFromPoint(apf.DragServer.dragdata.x, + apf.DragServer.dragdata.y); + if (!el) { + el = document.elementFromPoint(apf.DragServer.dragdata.x, + apf.DragServer.dragdata.y); + } + + if (dragdata.indicator) + dragdata.indicator.style.top = storeIndicatorTopPos; + //console.log("INDICATOR AFTER: "+dragdata.indicator.style.top+" " + //+dragdata.indicator.style.left+" "+apf.DragServer.dragdata.x+" "+apf.DragServer.dragdata.y); + //Set Indicator + dragdata.host.$moveDragIndicator(c); + + //get element and call events + var receiver = apf.findHost(el); + + //Run Events + if (receiver) + apf.DragServer.dragover(receiver, el, e); + else if (apf.DragServer.last) + apf.DragServer.dragout(apf.DragServer.last, e); + + apf.DragServer.lastTime = new Date().getTime(); + }, + + onmouseup: function(e) { + e = e || window.event; + + + var c = { + clientX: e.pageX ? e.pageX - window.pageXOffset : e.clientX, + clientY: e.pageY ? e.pageY - window.pageYOffset : e.clientY + }; + + if (!apf.DragServer.dragdata.started + && Math.abs(apf.DragServer.coordinates.clientX - c.clientX) < 6 + && Math.abs(apf.DragServer.coordinates.clientY - c.clientY) < 6) { + apf.DragServer.stop(true, null, e) + return; + } + + //get Element at x, y + var indicator = apf.DragServer.dragdata.indicator, + storeIndicatorTopPos = indicator.style.top; + //apf.console.info("INDICATOR UP BEFORE: "+indicator.style.top+" "+indicator.style.left); + if (indicator) + indicator.style.top = "10000px"; + + apf.DragServer.dragdata.x = e.pageX ? e.pageX - (!apf.isIE + ? window.pageXOffset + : 0) : c.clientX; + apf.DragServer.dragdata.y = e.pageY ? e.pageY - (!apf.isIE + ? window.pageYOffset + : 0) : c.clientY; + + var el = document.elementFromPoint(apf.DragServer.dragdata.x, + apf.DragServer.dragdata.y); + if (!el) { + el = document.elementFromPoint(apf.DragServer.dragdata.x, + apf.DragServer.dragdata.y); + } + + indicator.style.top = storeIndicatorTopPos; + //apf.console.info("INDICATOR UP AFTER: "+indicator.style.top+" "+indicator.style.left); + + //get element and call events + var host = apf.findHost(el); + + //Run Events + if (apf.DragServer.host && host != apf.DragServer.host) + apf.DragServer.dragout(apf.DragServer.host, e); + var success = apf.DragServer.dragdrop(host, el, apf.DragServer.dragdata.host, e); + apf.DragServer.stop(true, success, e); + } +}; + +/* + * @private + */ +apf.MultiselectDragDrop = function() { + // *** Drag & Drop *** // + + this.diffX = + this.diffY = 0; + this.multiple = false; + this.lastDragNode = null; + this.lastel = null; + + this.$showDragIndicator = function(sel, e) { + var srcEl = e.originalTarget || e.srcElement || e.target; + + this.multiple = sel.length > 1; + + if (this.multiple) { + this.diffX = e.scrollX; + this.diffY = e.scrollY; + } + else { + var itemNode = apf.xmldb.findHtmlNode(sel[0], this); + this.diffX = -1 * (e.offsetX - parseInt(apf.getStyleRecur(itemNode, "padding-left").replace(/px$/, "") - 10)); + this.diffY = -1 * e.offsetY; + } + + var prefix = this.oDrag.className.split(" ")[0] + //@todo the class should be removed here + this.$setStyleClass(this.oDrag, (this.multiple + ? prefix + "_multiple" : "") + (this["class"] ? " " + this["class"] : ""), [prefix + "_multiple"]); + + if (this.multiple) { + document.body.appendChild(this.oDrag); + return this.oDrag; + } + else if (this.localName == "datagrid") { + if (this.lastDragNode) + apf.destroyHtmlNode(this.lastDragNode); + + sel = this.$selected || this.$caret; + var oDrag = sel.cloneNode(true); + oDrag.removeAttribute("onmousedown");oDrag.onmousedown = null; + oDrag.removeAttribute("onmouseup");oDrag.onmouseup = null; + oDrag.removeAttribute("onmouseout");oDrag.onmouseout = null; + oDrag.removeAttribute("ondblclick");oDrag.ondblclick = null; + document.body.appendChild(oDrag); + + oDrag.style.position = "absolute"; + oDrag.style.width = sel.offsetWidth + "px"; + oDrag.style.display = "none"; + oDrag.removeAttribute("id"); + + this.$setStyleClass(oDrag, "draggrid"); + var nodes = sel.childNodes; + var dragnodes = oDrag.childNodes; + for (var i = nodes.length - 1; i >= 0; i--) { + if (dragnodes[i].nodeType == 1) + dragnodes[i].style.width = apf.getStyle(nodes[i], "width"); + } + //@todo apf3.0 remove all the event handlers of the children. + return (this.lastDragNode = oDrag); + } + else { + var sel = this.$selected || this.$caret, + width = apf.getStyle(this.oDrag, "width"); + + if (!sel) + return; + + // if (!width || width == "auto") + // this.oDrag.style.width = (sel.offsetWidth - apf.getWidthDiff(this.oDrag)) + "px"; + this.$updateNode(this.selected, this.oDrag); + } + + apf.window.zManager.set("drag", this.oDrag); + + return this.oDrag; + }; + + this.$hideDragIndicator = function(success) { + var oDrag = this.lastDragNode || this.oDrag, _self = this; + if (!this.multiple && !success && oDrag.style.display == "block") { + if (!this.$selected && !this.$caret) + return; + + var pos = apf.getAbsolutePosition(this.$selected || this.$caret); + apf.tween.multi(oDrag, { + anim: apf.tween.easeInOutCubic, + steps: apf.isIE ? 15 : 20, + interval: 15, + tweens: [ + {type: "left", from: oDrag.offsetLeft, to: (pos[0] + parseInt(apf.getStyleRecur(this.$selected, "padding-left").replace(/px$/, "")))}, + {type: "top", from: oDrag.offsetTop, to: pos[1]} + ], + onfinish: function(){ + if (_self.lastDragNode) { + apf.destroyHtmlNode(_self.lastDragNode); + _self.lastDragNode = null; + } + else { + _self.oDrag.style.display = "none"; + } + } + }); + } + else if (this.lastDragNode) { + apf.destroyHtmlNode(this.lastDragNode); + this.lastDragNode = null; + } + else { + this.oDrag.style.display = "none"; + } + }; + + this.$moveDragIndicator = function(e) { + var oDrag = this.lastDragNode || this.oDrag; + oDrag.style.left = (e.clientX + this.diffX) + "px";// - this.oDrag.startX + oDrag.style.top = (e.clientY + this.diffY + (this.multiple ? 15 : 0)) + "px";// - this.oDrag.startY + }; + + this.addEventListener("$skinchange", function(){ + this.$initDragDrop(); + }); + + this.$initDragDrop = function(){ + if (!this.$hasLayoutNode("dragindicator")) + return; + + this.oDrag = apf.insertHtmlNode( + this.$getLayoutNode("dragindicator"), document.body); + + apf.window.zManager.set("drag", this.oDrag); + + this.oDrag.style.position = "absolute"; + this.oDrag.style.cursor = "default"; + this.oDrag.style.display = "none"; + }; + + this.$findValueNode = function(el) { + if (!el) return null; + + while (el && el.nodeType == 1 + && !el.getAttribute(apf.xmldb.htmlIdTag)) { + if (this.$isTreeArch && el.previousSibling + && el.previousSibling.nodeType == 1) //@todo hack!! apf3.0 fix this. + el = el.previousSibling; + else + el = el.parentNode; + } + + return (el && el.nodeType == 1 && el.getAttribute(apf.xmldb.htmlIdTag)) + ? el + : null; + }; + + + this.$dragout = function(el, dragdata, extra) { + if (this.lastel) + this.$setStyleClass(this.lastel, "", ["dragDenied", "dragInsert", + "dragAppend", "selected", "indicate"]); + + var sel = this.$getSelection(true); + for (var i = 0, l = sel.length; i < l; i++) + this.$setStyleClass(sel[i], "selected", ["dragDenied", + "dragInsert", "dragAppend", "indicate"]); + + this.$setStyleClass(this.$ext, "", [this.$baseCSSname + "Drop"]); + + this.lastel = null; + }; + + if (!this.$dragdrop) + this.$dragdrop = this.$dragout; + + this.$dragover = function(el, dragdata, extra) { + this.$setStyleClass(this.$ext, this.$baseCSSname + "Drop"); + + var sel = this.$getSelection(true); + for (var i = 0, l = sel.length; i < l; i++) + this.$setStyleClass(sel[i], "", ["dragDenied", + "dragInsert", "dragAppend", "selected", "indicate"]); + + if (this.lastel) + this.$setStyleClass(this.lastel, "", ["dragDenied", + "dragInsert", "dragAppend", "selected", "indicate"]); + + var action = extra[1] && extra[1].action; + this.lastel = this.$findValueNode(el); + if (this.$isTreeArch && action == "list-append") { + var htmlNode = apf.xmldb.findHtmlNode(this.getTraverseParent(apf.xmldb.getNode(this.lastel)), this); + + this.lastel = htmlNode + ? this.$getLayoutNode("item", "container", htmlNode) + : this.$container; + + this.$setStyleClass(this.lastel, "dragInsert"); + } + else { + this.$setStyleClass(this.lastel, extra + ? (action == "insert-before" + ? "dragInsert" + : "dragAppend") + : "dragDenied"); + } + }; + +}; + +/* + * @private + */ +apf.StandardDragDrop = function() { + this.$showDragIndicator = function(sel, e) { + var x = e.offsetX + 22, + y = e.offsetY; + + this.oDrag.startX = x; + this.oDrag.startY = y; + + + document.body.appendChild(this.oDrag); + //this.oDrag.getElementsByTagName("DIV")[0].innerHTML = this.selected.innerHTML; + //this.oDrag.getElementsByTagName("IMG")[0].src = this.selected.parentNode.parentNode.childNodes[1].firstChild.src; + var oInt = this.$getLayoutNode("main", "caption", this.oDrag); + if (oInt.nodeType != 1) + oInt = oInt.parentNode; + + oInt.innerHTML = this.$applyBindRule("caption", this.xmlRoot) || ""; + + return this.oDrag; + }; + + this.$hideDragIndicator = function(){ + this.oDrag.style.display = "none"; + }; + + this.$moveDragIndicator = function(e) { + this.oDrag.style.left = (e.clientX - this.oDrag.startX + + document.documentElement.scrollLeft) + "px"; + this.oDrag.style.top = (e.clientY - this.oDrag.startY + + document.documentElement.scrollTop) + "px"; + }; + + //@todo falsely assuming only attributes are used for non multiselect widgets + this.$initDragDrop = function(){ + if (!this.getAttribute("drag")) + return; + + this.oDrag = document.body.appendChild(this.$ext.cloneNode(true)); + + apf.window.zManager.set("drag", this.oDrag); + + this.oDrag.style.position = "absolute"; + this.oDrag.style.cursor = "default"; + this.oDrag.style.filter = "progid:DXImageTransform.Microsoft.Alpha(opacity=50)"; + this.oDrag.style.MozOpacity = 0.5; + this.oDrag.style.opacity = 0.5; + this.oDrag.style.display = "none"; + }; +}; + +apf.DragServer.Init(); + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + +apf.__FOCUSSABLE__ = 1 << 26; + +/** + * All elements inheriting from this {@link term.baseclass baseclass} have focussable + * features + * + * @class apf.Focussable + * @baseclass + * + */ + +apf.Focussable = function(){ + this.$regbase = this.$regbase | apf.__FOCUSSABLE__; + if (this.disabled == undefined) + this.disabled = false; + + /** + * Sets the position in the list that determines the sequence + * of elements when using the pane key to move between them. + * @chainable + * @param {Number} tabindex The position in the list + */ + this.setTabIndex = function(tabindex) { + apf.window.$removeFocus(this); + apf.window.$addFocus(this, tabindex); + return this; + }; + + /** + * Gives this element the focus. This means that keyboard events + * are sent to this element. + * @chainable + */ + this.focus = function(noset, e, nofix) { + if (!noset) { + if (this.$isWindowContainer > -1) { + apf.window.$focusLast(this, e, true); + } + else { + apf.window.$focus(this, e); + + + } + + return this; + } + + if (this.$focus && !this.editable && (!e || !e.mouse || this.$focussable == apf.KEYBOARD_MOUSE)) + this.$focus(e); + + this.dispatchEvent("focus", apf.extend({ + bubbles: true + }, e)); + return this; + }; + + /** + * Removes the focus from this element. + * @chainable + */ + this.blur = function(noset, e) { + + if ((e && !apf.isChildOf(e.fromElement, e.toElement)) && apf.popup.isShowing(this.$uniqueId) && e.toElement.localName != "menu") + apf.popup.forceHide(); //This should be put in a more general position + + + if (this.$blur) + this.$blur(e); + + if (!noset) + apf.window.$blur(this); + + this.dispatchEvent("blur", apf.extend({ + bubbles: !e || !e.cancelBubble + }, e)); + return this; + }; + + /** + * Determines whether this element has the focus + * @returns {Boolean} Indicates whether this element has the focus + */ + this.hasFocus = function(){ + return apf.document.activeElement == this || this.$isWindowContainer + && (apf.document.activeElement || {}).$focusParent == this; + }; +}; + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + +apf.__INTERACTIVE__ = 1 << 21; + + + +/** + * All elements inheriting from this {@link term.baseclass baseclass} have interactive features, making an + * element draggable and resizable. + * + * #### Example + * + * ```xml + * + * ``` + * + * @class apf.Interactive + * @baseclass + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 1.0 + * + * @see apf.appsettings.outline + * @see apf.appsettings.resize-outline + * @see apf.appsettings.drag-outline + */ +/** + * @attribute {Boolean} draggable Sets or gets whether an element is draggable. The user will + * able to move the element around while holding the mouse button down on the + * element. + * + * #### Example + * + * ```xml + * + * ``` + */ +/** + * @attribute {Boolean} resizable Sets or gets whether an element is resizable. + * + * The user will able + * to resize the element by grabbing one of the four edges of the element and + * pulling it in either direction. Grabbing the corners allows users to + * resize horizontally and vertically at the same time. The right bottom corner + * is special, because it offers an especially big grab area. The size of this + * area can be configured in the skin of the element. + * + * #### Example + * + * ```xml + * + * ``` + */ +/** + * @attribute {Number} minwidth Sets or gets the minimum horizontal size the element can get when resizing. + */ +/** + * @attribute {Number} minheight Sets or gets the minimum vertical size the element can get when resizing. + */ +/** + * @attribute {Number} maxwidth Sets or gets the maximum horizontal size the element can get when resizing. + */ +/** + * @attribute {Number} maxheight Sets or gets the maximum vertical size the element can get when resizing. + * + */ +/** + * @event drag Fires when the widget has been dragged. + */ +/** + * @event resizestart Fires before the widget is resized. + * @cancelable Prevents this resize action to start. + * @param {Object} e The standard event object. It contains the following property: + * - type ([[String]]): the type of resize. This is a combination of the four directions--`"n"`, `"s"`, `"e"`, `"w"`. + */ +/** + * @event resize Fires when the widget has been resized. + * + */ +apf.Interactive = function(){ + var nX, nY, rX, rY, startPos, lastCursor = null, l, t, r, b, lMax, tMax, lMin, + tMin, w, h, we, no, ea, so, rszborder, rszcorner, marginBox, + verdiff, hordiff, _self = this, posAbs, oX, oY, overThreshold, + dragOutline, resizeOutline, myPos, startGeo; + + this.$regbase = this.$regbase | apf.__INTERACTIVE__; + + this.$dragStart = function(e, reparent) { + var nativeEvent = e || event; + if (!reparent && nativeEvent.button == 2) + return; + + + { + dragStart.apply(nativeEvent.srcElement || this, arguments); + } + } + + this.$propHandlers["draggable"] = function(value) { + if (apf.isFalse(value)) + this.draggable = value = false; + else if (apf.isTrue(value)) + this.draggable = value = true; + + var o = this.editable ? this.$ext : this.oDrag || this.$ext; + if (value) + apf.addListener(o, "mousedown", this.$dragStart); + else + apf.removeListener(o, "mousedown", this.$dragStart); + + //deprecated?? + if (o.interactive & 1) + return; + o.interactive = (o.interactive||0)+1; + + //this.$ext.style.position = "absolute"; + }; + + this.$propHandlers["resizable"] = function(value) { + if (apf.isFalse(value)) + this.resizable = false; + else if (apf.isTrue(value)) + this.resizable = "true"; + + this.$ext.style.cursor = ""; + + var o = this.oResize || this.$ext; + if (o.interactive & 2) + return; + + if (!_self.editable) { + apf.addListener(o, "mousedown", function(){ + resizeStart.apply(o, arguments); + }); + + apf.addListener(o, "mousemove", function(){ + resizeIndicate.apply(o, arguments); + }); + } + + o.interactive = (o.interactive||0)+2; + + //this.$ext.style.position = "absolute"; + + rszborder = this.$getOption && parseInt(this.$getOption("Main", "resize-border")) || 3; + rszcorner = this.$getOption && parseInt(this.$getOption("Main", "resize-corner")) || 12; + marginBox = apf.getBox(apf.getStyle(this.$ext, "borderWidth")); + }; + + /* + this.$propHandlers["minwidth"] = + this.$propHandlers["maxwidth"] = + this.$propHandlers["minheight"] = + this.$propHandlers["maxheight"] = function(value, prop) { + if (this.aData) + this.aData[prop] = parseInt(value); + } + if (this.aData) { + this.aData.minwidth = this.minwidth; + this.aData.minheight = this.minheight; + }*/ + + this.$cancelInteractive = function(){ + document.onmouseup(null, true); + } + + function dragStart(e, reparent) { + if (!e) e = event; + + if (!reparent && (!_self.draggable || apf.dragMode))//_self.editable || + return; + + + dragOutline = false; + + + if (_self.dispatchEvent("beforedragstart", {htmlEvent: e}) === false) + return; + + apf.dragMode = true; + if (reparent) { + _self.dispatchEvent("beforedrag") + overThreshold = true; + } + else + overThreshold = false; + + + apf.popup.forceHide(); + + + posAbs = "absolute|fixed".indexOf(apf.getStyle(_self.$ext, "position")) > -1; + if (!posAbs) { + _self.$ext.style.position = posAbs //(posAbs = _self.dragSelection) + ? "absolute" : "relative"; + } + if (_self.editable) + posAbs = true; + + //@todo not for docking + + if (posAbs && !_self.aData) { + apf.plane.show(dragOutline + ? oOutline + : _self.$ext, e.reappend);//, true + } + + + var ext = (reparent || (oOutline && oOutline.self)) && dragOutline //little dirty hack to detect outline set by visualselect + ? oOutline + : _self.$ext; + var pos = posAbs + ? apf.getAbsolutePosition(ext, ext.offsetParent, true) + : [parseInt(apf.getStyle(ext, "left")) || 0, + parseInt(apf.getStyle(ext, "top")) || 0]; + + + startGeo = [ext.style.left, ext.style.top, ext.style.right, + ext.style.bottom, ext.style.width, ext.style.height]; + + + nX = pos[0] - (oX = e.clientX); + nY = pos[1] - (oY = e.clientY); + + //if (_self.hasFeature && _self.hasFeature(apf.__ANCHORING__)) + //_self.$disableAnchoring(); + + if (!(reparent || (oOutline && oOutline.self))) { + + { + if (_self.$ext.style.right) { + _self.$ext.style.left = pos[0] + "px"; + _self.$ext.style.right = ""; + } + if (_self.$ext.style.bottom) { + _self.$ext.style.top = pos[1] + "px"; + _self.$ext.style.bottom = ""; + } + } + } + + document.onmousemove = dragMove; + document.onmouseup = function(e, cancel) { + document.onmousemove = document.onmouseup = null; + + + if (posAbs && !_self.aData) + apf.plane.hide(); + + + var htmlNode = dragOutline + ? oOutline + : _self.$ext; + + if (overThreshold && !_self.$multidrag) { + + if (cancel) { + var ext = _self.$ext; + ext.style.left = startGeo[0]; + ext.style.top = startGeo[1]; + ext.style.right = startGeo[2]; + ext.style.bottom = startGeo[3]; + ext.style.width = startGeo[4]; + ext.style.height = startGeo[5]; + + if (_self.dispatchEvent) + _self.dispatchEvent("dragcancel", { + htmlNode: htmlNode, + htmlEvent: e + }); + } + else + + + if (_self.setProperty) { + updateProperties(); + } + else if (dragOutline) { + _self.$ext.style.left = l + "px"; + _self.$ext.style.top = t + "px"; + } + } + + l = t = w = h = null; + + if (!posAbs) + _self.$ext.style.position = "relative"; + + if (_self.showdragging) + apf.setStyleClass(_self.$ext, "", ["dragging"]); + + if (posAbs && dragOutline && !oOutline.self) //little dirty hack to detect outline set by visualselect + oOutline.style.display = "none"; + + apf.dragMode = false; + + if (!cancel && _self.dispatchEvent && overThreshold) + _self.dispatchEvent("afterdrag", { + htmlNode: htmlNode, + htmlEvent: e + }); + }; + + if (reparent) + document.onmousemove(e); + //else if (apf.isIE) + //apf.window.$mousedown(e); + + return false; + }; + + function dragMove(e) { + if (!e) e = event; + + //if (_self.dragSelection) + //overThreshold = true; + + if (!overThreshold && _self.showdragging) + apf.setStyleClass(_self.$ext, "dragging"); + + // usability rule: start dragging ONLY when mouse pointer has moved delta x pixels + var dx = e.clientX - oX, + dy = e.clientY - oY, + distance; + + if (!overThreshold + && (distance = dx*dx > dy*dy ? dx : dy) * distance < 2) + return; + + //Drag outline support + else if (!overThreshold) { + if (dragOutline + && oOutline.style.display != "block") + oOutline.style.display = "block"; + + if (_self.dispatchEvent && _self.dispatchEvent("beforedrag", {htmlEvent: e}) === false) { + document.onmouseup(); + return; + } + } + + var oHtml = dragOutline + ? oOutline + : _self.$ext; + + oHtml.style.left = (l = e.clientX + nX) + "px"; + oHtml.style.top = (t = e.clientY + nY) + "px"; + + if (_self.realtime) { + var change = _self.$stick = {}; + _self.$showDrag(l, t, oHtml, e, change); + + if (typeof change.l != "undefined") + l = change.l, oHtml.style.left = l + "px"; + if (typeof change.t != "undefined") + t = change.t, oHtml.style.top = t + "px"; + } + + overThreshold = true; + }; + + this.$resizeStart = resizeStart; + function resizeStart(e, options) { + if (!e) e = event; + + //|| _self.editable + if (!_self.resizable + || String(_self.height).indexOf("%") > -1 && _self.parentNode.localName == "vbox" //can't resize percentage based for now + || String(_self.width).indexOf("%") > -1 && _self.parentNode.localName == "hbox") //can't resize percentage based for now + return; + + + resizeOutline = false; + + + var ext = _self.$ext; + if (!resizeOutline) { + var diff = apf.getDiff(ext); + hordiff = diff[0]; + verdiff = diff[1]; + } + + //@todo This is probably not gen purpose + startPos = apf.getAbsolutePosition(ext);//, ext.offsetParent); + startPos.push(ext.offsetWidth); + startPos.push(ext.offsetHeight); + myPos = apf.getAbsolutePosition(ext, ext.offsetParent, true); + + + startGeo = [ext.style.left, ext.style.top, ext.style.right, + ext.style.bottom, ext.style.width, ext.style.height]; + + + var sLeft = 0, + sTop = 0, + x = (oX = e.clientX) - startPos[0] + sLeft + document.documentElement.scrollLeft, + y = (oY = e.clientY) - startPos[1] + sTop + document.documentElement.scrollTop, + resizeType; + + if (options && options.resizeType) { + posAbs = "absolute|fixed".indexOf(apf.getStyle(ext, "position")) > -1; + resizeType = options.resizeType; + } + else { + resizeType = getResizeType.call(ext, x, y); + } + rX = x; + rY = y; + + if (!resizeType) + return; + + if (_self.dispatchEvent && _self.dispatchEvent("beforeresize", { + type: resizeType, + setType: function(type) { + resizeType = type; + } + }) === false) { + //if (apf.isIE) + //apf.window.$mousedown(e); //@todo is this necessary? + return; + } + + + apf.popup.forceHide(); + + + //if (_self.hasFeature && _self.hasFeature(apf.__ANCHORING__)) + //_self.$disableAnchoring(); + + apf.dragMode = true; + overThreshold = false; + + we = resizeType.indexOf("w") > -1; + no = resizeType.indexOf("n") > -1; + ea = resizeType.indexOf("e") > -1; + so = resizeType.indexOf("s") > -1; + + if (!_self.minwidth) _self.minwidth = 0; + if (!_self.minheight) _self.minheight = 0; + if (!_self.maxwidth) _self.maxwidth = 10000; + if (!_self.maxheight) _self.maxheight = 10000; + + if (posAbs) { + lMax = myPos[0] + startPos[2]; + tMax = myPos[1] + startPos[3]; + lMin = myPos[0] + startPos[2]; + tMin = myPos[1] + startPos[3]; + } + + + if (posAbs) { + apf.plane.show(resizeOutline + ? oOutline + : ext);//, true + } + + + var iMarginLeft; + + + { + if (ext.style.right) { + ext.style.left = myPos[0] + "px"; + + //console.log(myPos[0]); + //ext.style.right = ""; + } + if (ext.style.bottom) { + ext.style.top = myPos[1] + "px"; + //ext.style.bottom = ""; + } + } + + if (!options || !options.nocursor) { + if (lastCursor === null) + lastCursor = document.body.style.cursor;//apf.getStyle(document.body, "cursor"); + document.body.style.cursor = getCssCursor(resizeType) + "-resize"; + } + + document.onmousemove = resizeMove; + document.onmouseup = function(e, cancel) { + document.onmousemove = document.onmouseup = null; + + + if (posAbs) + apf.plane.hide(); + + + clearTimeout(timer); + + if (resizeOutline) { + var diff = apf.getDiff(_self.$ext); + hordiff = diff[0]; + verdiff = diff[1]; + } + + + if (cancel) { + var ext = _self.$ext; + ext.style.left = startGeo[0]; + ext.style.top = startGeo[1]; + ext.style.right = startGeo[2]; + ext.style.bottom = startGeo[3]; + ext.style.width = startGeo[4]; + ext.style.height = startGeo[5]; + + if (_self.dispatchEvent) + _self.dispatchEvent("resizecancel"); + } + else + + doResize(e || event, true); + + if (_self.setProperty) + updateProperties(); + + document.body.style.cursor = lastCursor || ""; + lastCursor = null; + + if (resizeOutline) + oOutline.style.display = "none"; + + apf.dragMode = false; + + if (!cancel && _self.dispatchEvent) + _self.dispatchEvent("afterresize", { + l: l, t: t, w: w+hordiff, h: h+verdiff + }); + + l = t = w = h = null; + }; + + //if (apf.isIE) + //apf.window.$mousedown(e); + + return false; + } + + function updateProperties(left, top, width, height, hdiff, vdiff, right, bottom) { + if (typeof left == "undefined") { + left = l, top = t, width = w, height = h, + vdiff = verdiff, hdiff = hordiff; + } + else posAbs = true; + + var hasLeft = _self.left || _self.left === 0; + var hasRight = _self.right || _self.right === 0; + var hasBottom = _self.bottom || _self.bottom === 0; + var hasTop = _self.top || _self.top === 0; + + if (posAbs) { + var htmlNode = (oOutline && oOutline.style.display == "block") + ? oOutline + : _self.$ext; + + if (hasRight && !(right || right === 0)) + right = apf.getHtmlRight(htmlNode); + + if (hasBottom && !(bottom || bottom === 0)) + bottom = apf.getHtmlBottom(htmlNode); + + if (hasRight) { + _self.setProperty("right", right, 0, _self.editable); + if (!_self.left) + htmlNode.style.left = ""; + } + + if (hasBottom) { + _self.setProperty("bottom", bottom, 0, _self.editable); + if (!_self.top) + htmlNode.style.top = ""; + } + + if ((left || left === 0) && (!hasRight || hasLeft)) + _self.setProperty("left", left, 0, _self.editable); + if ((top || top === 0) && (!hasBottom || hasTop)) + _self.setProperty("top", top, 0, _self.editable); + } + + if (hdiff != undefined && width && (!hasLeft || !hasRight)) + _self.setProperty("width", width + hdiff, 0, _self.editable) + if (vdiff != undefined && height && (!hasTop || !hasBottom)) + _self.setProperty("height", height + vdiff, 0, _self.editable); + } + this.$updateProperties = updateProperties; + + var min = Math.min, max = Math.max, lastTime, timer; + function resizeMove(e) { + if (!e) e = event; + + //if (!e.button) + //return this.onmouseup(); + + // usability rule: start dragging ONLY when mouse pointer has moved delta x pixels + /*var dx = e.clientX - oX, + dy = e.clientY - oY, + distance; + + if (!overThreshold + && (distance = dx*dx > dy*dy ? dx : dy) * distance < 4) + return;*/ + + clearTimeout(timer); + if (lastTime && new Date().getTime() + - lastTime < (resizeOutline ? 6 : apf.mouseEventBuffer)) { + var z = { + clientX: e.clientX, + clientY: e.clientY + } + timer = $setTimeout(function(){ + doResize(z); + }, 10); + return; + } + lastTime = new Date().getTime(); + + doResize(e); + + //overThreshold = true; + } + + function doResize(e, force) { + var oHtml = resizeOutline && !force + ? oOutline + : _self.$ext; + + var sLeft = document.documentElement.scrollLeft, + sTop = document.documentElement.scrollTop; + + if (we) { + if (posAbs) + oHtml.style.left = (l = max((lMin - _self.maxwidth), + min((lMax - _self.minwidth), + myPos[0] + e.clientX - oX + sLeft))) + "px"; + oHtml.style.width = (w = min(_self.maxwidth - hordiff, + max(hordiff, _self.minwidth, + startPos[2] - (e.clientX - oX) + sLeft + ) - hordiff)) + "px"; //@todo + } + + if (no) { + if (posAbs) + oHtml.style.top = (t = max((tMin - _self.maxheight), + min((tMax - _self.minheight), + myPos[1] + e.clientY - oY + sTop))) + "px"; + oHtml.style.height = (h = min(_self.maxheight - verdiff, + max(verdiff, _self.minheight, + startPos[3] - (e.clientY - oY) + sTop + ) - verdiff)) + "px"; //@todo + } + + if (ea) + oHtml.style.width = (w = min(_self.maxwidth - hordiff, + max(hordiff, _self.minwidth, + e.clientX - startPos[0] + (startPos[2] - rX) + sLeft) + - hordiff)) + "px"; + + if (so) + oHtml.style.height = (h = min(_self.maxheight - verdiff, + max(verdiff, _self.minheight, + e.clientY - startPos[1] + (startPos[3] - rY) + sTop) + - verdiff)) + "px"; + + //@todo apf3.0 this is execution wise inefficient + if (_self.parentNode && _self.parentNode.localName == "table") { + updateProperties(); + apf.layout.processQueue(); + } + + if (_self.realtime) { + var change = _self.$stick = {}; + + //@todo calc l and t once at start of resize (subtract borders) + _self.$showResize(l || apf.getHtmlLeft(oHtml), t || apf.getHtmlTop(oHtml), + w && w + hordiff || oHtml.offsetWidth, + h && h + verdiff || oHtml.offsetHeight, e, change, we, no, ea, so); + + if (posAbs && we && typeof change.l != "undefined") + oHtml.style.left = (l = max((lMin - _self.maxwidth), min((lMax - _self.minwidth), change.l))) + "px"; + + if (posAbs && no && typeof change.t != "undefined") + oHtml.style.top = (t = max((tMin - _self.maxheight), min((tMax - _self.minheight), change.t))) + "px"; + + if (typeof change.w != "undefined") + oHtml.style.width = (w = min(_self.maxwidth - hordiff, + max(hordiff, _self.minwidth, + change.w) - hordiff)) + "px"; + if (typeof change.h != "undefined") + oHtml.style.height = (h = min(_self.maxheight - verdiff, + max(verdiff, _self.minheight, + change.h) - verdiff)) + "px"; + } + + + if (apf.hasSingleRszEvent) + apf.layout.forceResize(_self.$int); + + } + + function getResizeType(x, y) { + var cursor = "", + tcursor = ""; + posAbs = "absolute|fixed".indexOf(apf.getStyle(_self.$ext, "position")) > -1; + if (_self.resizable == "true" || _self.resizable == "vertical" || _self.resizable.indexOf('top') > -1 || _self.resizable.indexOf('bottom') > -1) { + if (y < rszborder + marginBox[0] && _self.resizable.indexOf('bottom') == -1) + cursor = posAbs ? "n" : ""; + else if (y > this.offsetHeight - (rszcorner || rszborder) && _self.resizable.indexOf('top') == -1) //marginBox[0] - marginBox[2] - + cursor = "s"; + } + + if (_self.resizable == "true" || _self.resizable == "horizontal" || _self.resizable.indexOf('left') > -1 || _self.resizable.indexOf('right') > -1) { + if (x < (cursor ? rszcorner : rszborder) + marginBox[0] && _self.resizable.indexOf('right') == -1) + cursor += tcursor + (posAbs ? "w" : ""); + else if (x > this.offsetWidth - (cursor || tcursor ? rszcorner : rszborder) && _self.resizable.indexOf('left') == -1) //marginBox[1] - marginBox[3] - + cursor += tcursor + "e"; + } + + return cursor; + } + + var originalCursor; + function resizeIndicate(e) { + if (!e) e = event; + + if (!_self.resizable || _self.editable || document.onmousemove) + return; + + //@todo This is probably not gen purpose + var pos = apf.getAbsolutePosition(_self.$ext),//, _self.$ext.offsetParent + sLeft = 0, + sTop = 0, + x = e.clientX - pos[0] + sLeft + document.documentElement.scrollLeft, + y = e.clientY - pos[1] + sTop + document.documentElement.scrollTop; + + if (!originalCursor) + originalCursor = apf.getStyle(this, "cursor"); + + var cursor = getResizeType.call(_self.$ext, x, y); + + this.style.cursor = cursor + ? getCssCursor(cursor) + "-resize" + : originalCursor || "default"; + }; + + function getCssCursor(cursor) { + var cssCursor = cursor; + if (apf.isWebkit) { + if (cursor == "se" || cursor == "nw") + cssCursor = "nwse"; + else if (cursor == "sw" || cursor == "ne") + cssCursor = "nesw"; + else if (cursor == "s" || cursor == "n") + cssCursor = "ns"; + else if (cursor == "e" || cursor == "w") + cssCursor = "ew"; + } + + return cssCursor; + } + + var oOutline; + + + /*this.addEventListener("DOMNodeRemovedFromDocument", function(e) { + oOutline.refCount--; + + if (!oOutline.refCount) { + //destroy + } + });*/ +}; + +apf.GuiElement.propHandlers["resizable"] = function(value) { + this.implement(apf.Interactive); + this.$propHandlers["resizable"].apply(this, arguments); +} + +apf.GuiElement.propHandlers["draggable"] = function(value) { + this.implement(apf.Interactive); + this.$propHandlers["draggable"].apply(this, arguments); +}; + +apf.Init.run("interactive"); + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + +apf.__MEDIA__ = 1 << 20; + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + +apf.__MULTICHECK__ = 1 << 22; + + + +/** + * All elements inheriting from this {@link term.baseclass baseclass} have checkable items. + * + * @class apf.MultiCheck + * @baseclass + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 3.0 + * + * + */ +// @todo type detection, errors (see functions in multiselect) +apf.MultiCheck = function(){ + this.$regbase = this.$regbase | apf.__MULTICHECK__; + + // *** Properties *** // + + this.multicheck = true; + this.checklength = 0; + this.$checkedList = []; + + // *** Public Methods *** // + + /** + * @event beforecheck Fires before a check is made + * @param {Object} e The standard event object, with the following properties: + * - `xmlNode` ([[XMLElement]]): the {@link term.datanode data node} that will be checked. + */ + /** + * @event aftercheck Fires after a check is made + * @param {Object} e The standard event object, with the following properties: + * - `xmlNode` ([[XMLElement]]): the {@link term.datanode data node} that was checked. + * + */ + /** + * Checks a single, or a set of, elements. + * + * The checking can be visually represented in this element. + * The element can be checked, partialy checked, or unchecked + * + * @param {Mixed} xmlNode The identifier to determine the selection. + * @return {Boolean} Indicates whether the selection could not be made (`false`) + */ + this.check = function(xmlNode, userAction) { + if (userAction && this.disabled + || this.$checkedList.indexOf(xmlNode) > -1) + return; + + if (userAction + && this.$executeSingleValue("check", "checked", xmlNode, "true") !== false) + return; + + if (this.dispatchEvent("beforecheck", {xmlNode : xmlNode}) === false) + return false; + + if (!this.multicheck && this.$checkedList.length) + this.clearChecked(true); + + this.$checkedList.push(xmlNode); + + + + this.$setStyleClass(apf.xmldb.getHtmlNode(xmlNode, this), + "checked", ["partial"]); + +// this.dispatchEvent("aftercheck", { +// list : this.$checkedList, +// xmlNode : xmlNode +// }); + }; + + /** + * @event beforeuncheck Fires before a uncheck is made + * @param {Object} e The standard event object, with the following properties: + * - `xmlNode` ([[XMLElement]]): the {@link term.datanode data node} that will be unchecked. + * + */ + /** + * @event afteruncheck Fires after a uncheck is made + * @param {Object} e The standard event object, with the following properties: + * - `xmlNode` ([[XMLElement]]): the {@link term.datanode data node} that was unchecked. + * + */ + /** + * Unchecks a single, or set of, elements. + * + * @param {Mixed} xmlNode The identifier to determine the selection. + * @return {Boolean} Indicates if the selection could be made (`false`) + */ + this.uncheck = function(xmlNode, userAction) { + if (userAction && this.disabled + || this.$checkedList.indexOf(xmlNode) == -1) + return; + + if (userAction + && this.$executeSingleValue("check", "checked", xmlNode, "false") !== false) + return; + + + + if (this.dispatchEvent("beforeuncheck", { + xmlNode: xmlNode + }) === false) + return false; + + this.$checkedList.remove(xmlNode); + this.$setStyleClass(apf.xmldb.getHtmlNode(xmlNode, this), + "", ["checked", "partial"]); + + this.dispatchEvent("afteruncheck", { + list: this.$checkedList, + xmlNode: xmlNode + }); + }; + + /** + * Toggles between a check and uncheck of a single, or set of, elements. + * + * @param {Mixed} xmlNode The identifier to determine the selection. + * + */ + this.checkToggle = function(xmlNode, userAction) { + if (userAction && this.disabled) + return; + + if (xmlNode.style) { + var htmlNode = xmlNode, + id = htmlNode.getAttribute(apf.xmldb.htmlIdTag); + while (!id && htmlNode.parentNode) + id = (htmlNode = htmlNode.parentNode) + .getAttribute(apf.xmldb.htmlIdTag); + xmlNode = apf.xmldb.getNode(htmlNode) + } + + if (this.$checkedList.indexOf(xmlNode) > -1) + this.uncheck(xmlNode, userAction); + else + this.check(xmlNode, userAction); + }; + + /** + * Checks a set of items. + * + * @param {Array} xmlNodeList The {@link term.datanode data nodes} that will be selected. + * @param {Boolean} uncheck If `true`, checks the items + * @param {Boolean} noClear If `true`, does not also clears the selection + * @param {Boolean} noEvent Indicates whether to call any events + * @event beforecheck Fires before a check is made + * @param {Object} e + * + * @event aftercheck Fires after a check is made + * @param {Object} e + * {XMLElement} xmlNode the {@link term.datanode data node} that is deselected. + */ + this.checkList = function(xmlNodeList, uncheck, noClear, noEvent, userAction) { + //if (apf.isIE < 8) + if (!xmlNodeList.indexOf) + xmlNodeList = apf.getArrayFromNodelist(xmlNodeList); + //@todo is this need for ie8 and/or other browsers + + if (userAction) { + if (this.disabled) + return; + + var changes = []; + for (var c, i = 0; i < xmlNodeList.length; i++) { + c = this.$executeSingleValue("check", "checked", xmlNodeList[i], uncheck ? "false" : "true", true) + if (c === false) break; + changes.push(c); + } + + if (changes.length) { + return this.$executeAction("multicall", changes, "checked", + xmlNodeList[0], null, null, + xmlNodeList.length > 1 ? xmlNodeList : null); + } + } + + if (userAction && this.disabled) return; + + if (!noEvent && this.dispatchEvent("beforecheck", { + list: xmlNodeList + }) === false) + return false; + + if (!uncheck && !noClear) + this.clearChecked(true); + + if (!this.multicheck) + xmlNodeList = [xmlNodeList[0]]; + + var i; + if (uncheck) { + for (i = xmlNodeList.length - 1; i >= 0; i--) { + this.$checkedList.remove(xmlNodeList[i]); + this.$setStyleClass( + apf.xmldb.getHtmlNode(xmlNodeList[i], this), "", ["checked"]); + } + } + else { + for (i = xmlNodeList.length - 1; i >= 0; i--) { + this.$checkedList.push(xmlNodeList[i]); + this.$setStyleClass( + apf.xmldb.getHtmlNode(xmlNodeList[i], this), "checked"); + } + } + + + + if (!noEvent) + this.dispatchEvent("aftercheck", { + list: xmlNodeList + }); + }; + + /** + * Removes the selection of one or more checked nodes. + * + * @param {Boolean} [noEvent] Indicates whether to call any events + */ + this.clearChecked = function(noEvent) { + if (!noEvent && this.dispatchEvent("beforeuncheck", { + xmlNode: this.$checkedList + }) === false) + return false; + + for (var i = this.$checkedList.length - 1; i >= 0; i--) { + this.$setStyleClass( + apf.xmldb.getHtmlNode(this.$checkedList[i], this), "", ["checked"]); + } + + this.$checkedList.length = 0; + + if (!noEvent) { + this.dispatchEvent("afteruncheck", { + list: this.$checkedList + }); + } + }; + + /** + * Determines whether a node is checked. + * + * @param {XMLElement} xmlNode The {@link term.datanode data node} to be checked. + * @return {Boolean} Whether the element is selected. + */ + this.isChecked = function(xmlNode) { + return this.$checkedList.indexOf(xmlNode) > -1; + }; + + /** + * Retrieves an array or a document fragment containing all the checked + * {@link term.datanode data nodes} from this element. + * + * @param {Boolean} [xmldoc] Specifies whether the method should return a document fragment. + * @return {Mixed} The selection of this element. + */ + this.getChecked = function(xmldoc) { + var i, r; + if (xmldoc) { + r = this.xmlRoot + ? this.xmlRoot.ownerDocument.createDocumentFragment() + : apf.getXmlDom().createDocumentFragment(); + for (i = 0; i < this.$checkedList.length; i++) + apf.xmldb.cleanNode(r.appendChild( + this.$checkedList[i].cloneNode(true))); + } + else { + for (r = [], i = 0; i < this.$checkedList.length; i++) + r.push(this.$checkedList[i]); + } + + return r; + }; + + /** + * Checks all the {@link term.eachnode each nodes} of this element + * + */ + this.checkAll = function(userAction) { + if (!this.multicheck || userAction && this.disabled || !this.xmlRoot) + return; + + var nodes = this.$isTreeArch + ? this.xmlRoot.selectNodes(".//" + + this.each.split("|").join("|.//")) + : this.getTraverseNodes(); + + this.checkList(nodes); + }; + + this.addEventListener("beforeload", function(){ + if (!this.$hasBindRule("checked")) //only reset state when check state isnt recorded + this.clearChecked(true); + }); + + this.addEventListener("afterload", function(){ + if (!this.$hasBindRule("checked") && this.$checkedList.length) //only reset state when check state isnt recorded + this.checkList(this.$checkedList, false, true, false); //@todo could be optimized (no event calling) + }); + + this.addEventListener("xmlupdate", function(e) { + if (e.action == "attribute" || e.action == "text" + || e.action == "synchronize" || e.action == "update") { + //@todo list support! + var c1 = apf.isTrue(this.$applyBindRule("checked", e.xmlNode)); + var c2 = this.isChecked(e.xmlNode); + if (c1 != c2) { + if (c1) { + this.check(e.xmlNode); + } + else { + this.uncheck(e.xmlNode); + } + } + } + }); + + + this.addEventListener("aftercheck", function(){ + //@todo inconsistent because setting this is in event callback + if (this.checklength != this.$checkedList.length) + this.setProperty("checklength", this.$checkedList.length); + }); + + this.addEventListener("afteruncheck", function(){ + //@todo inconsistent because setting this is in event callback + if (this.checklength != this.$checkedList.length) + this.setProperty("checklength", this.$checkedList.length); + }); + +}; + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * Element which specifies the ways the application can communicate to remote + * data sources. + * + * + * #### Example + * + * Here's an example of the RPC module with the CGI protocol. + * + * ```xml + * + * + * + * + * + * + * + * + * + * + * + * + * + * //This function is called when the search returns + * function processSearch(data, state, extra) { + * alert(data) + * } + * + * //Execute a search for the product car + * comm.searchProduct('car', 10); + * + * ``` + * + * #### Example + * + * Example of the RPC module with the SOAP protocol. + * + * ```xml + * + * + * + * + * + * + * + * + * + * + * + * + * + * //This function is called when the search returns + * function processSearch(data, state, extra) { + * alert(data) + * } + * + * //Execute a search for the product car + * comm.searchProduct('car', 10); + * + * ``` + * + * #### Example + * + * Writing to a file with a WebDAV connector + * + * ```xml + * + * + * + * // write the text 'bar' to a file on the server called 'foo.txt' + * myWebDAV.write('http://my-webdav-server.com/dav_files/foo.txt', 'bar'); + * + * ``` + * + * #### Example + * + * XMPP connector with new message notification + * + * ```xml + * + * + * + * // This function is called when a message has arrived + * function messageReceived(from) { + * alert('Received message from ' + from); + * } + * + * // Send a message to John + * myXMPP.sendMessage('john@my-jabber-server.com', 'A test message', '', + * apf.xmpp.MSG_CHAT); + * + * ``` + * + * @class apf.Teleport + * @define teleport + * @inherits apf.AmlElement + * @allowchild {teleport} + * + * @default_private + */ +/** + * @attribute {String} url The location of the server that is + * recipient of the RPC messages. + */ +/** + * @attribute {String} [route-server] String specifying the URL to the route script. + * The route script will receive the route information in three extra headers: + * - `X-Route-Request`: Containing the destination URL + * - `X-Proxy-Request`: Containing the destination URL + * - `X-Compress-Response`: Set to `'gzip'` + */ +/** + * @attribute {Boolean} [autoroute] Indicates whether the call should be routed + * through a proxy when a permission + * error occurs due to the same domain policy. + */ +/** + * @attribute {Number} [timeout] The number of milliseconds after + * which the call is considered timed out. + * + */ +apf.Teleport = function(){ + this.$init(true); +}; + +apf.__TELEPORT__ = 1 << 28; + +(function() { + this.$parsePrio = "002"; + + this.$regbase = this.$regbase | apf.__TELEPORT__; + + this.$booleanProperties["autoroute"] = true; + + this.$supportedProperties.push("url", "timeout", "protocol", "route-server", + "autoroute"); + + this.$propHandlers["url"] = function(value) { + var url = new apf.url(value); + + // do some extra startup/ syntax error checking + if (!url.protocol) { + return apf.console.error(apf.formatErrorString(0, this, + "Communication (Teleport) initialization error", + "Invalid server url provided: '" + value + "'")); + } + + this.$host = url.host; + this.$rootPath = url.path; + this.$server = value.replace(new RegExp(this.$rootPath + "$"), ""); + }; + + this.$propHandlers["timeout"] = function(value) { + this.timeout = parseInt(value) || 10000; + }; + + this.$propHandlers["protocol"] = function(value) { + var proto = value.toLowerCase(); + if (!apf[proto]) { + throw new Error(apf.formatErrorString(1025, null, "Teleport baseclass", + "Could not find Ajax.org Teleport RPC Component '" + proto + "'", this)); + } + this.implement(apf[proto]); + }; + + /** + * Returns a string representation of this object. + */ + this.toString = function(){ + return "[Ajax.org Teleport Component : " + (this.name || "") + + " (" + this.type + ")]"; + }; + + this.addEventListener("DOMNodeInsertedIntoDocument", function() { + var error; + if (this.type && this.type == "socket") { + // Implement Socket Module + if (!apf.socket) + error = "Socket"; + else + this.implement(apf.socket); + } + else { + // Implement HTTP Module + if (!apf.http) + error = "HTTP"; + else + this.implement(apf.http); + } + if (error) { + throw new Error(apf.formatErrorString(1024, null, "Teleport baseclass", + "Could not find Ajax.org Teleport " + error + " Component", this.$aml)); + } + + if (this.id) + apf.$asyncObjects[this.id] = 1; + }); +}).call(apf.Teleport.prototype = new apf.AmlElement()); + + + + + +apf.Init.run("teleport"); + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + +apf.__TRANSACTION__ = 1 << 3; + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + +apf.__VIRTUALVIEWPORT__ = 1 << 19; + + + +/** + * All elements inheriting from this {@link term.baseclass baseclass} can have a virtual viewport. + * + * @experimental This code has never been run. + * @constructor + * @baseclass + * @private + * + * @author Ruben Daniels (ruben AT ajax DOT org) & Mike de Boer + * @version %I%, %G% + * @since 1.0 + */ +apf.VirtualViewport = function(){ + this.$init(true); + + this.$regbase = this.$regbase | apf.__VIRTUALVIEWPORT__; + + this.virtualVTimer = null; + this._xmlUpdate = this.$xmlUpdate; + + apf.setStyleClass(this.$ext, "virtual"); + + this.$deInitNode = function(xmlNode, htmlNode) { + /* + Not the htmlNode is deleted, but the viewport is rerendered from this node on. + If viewport is too high either the render starting point is adjusted and + a complete rerender is requested, or the last empty elements are hidden + */ + this.$viewport.redraw();//very unoptimized + }; + + this.$moveNode = function(xmlNode, htmlNode) { + /* + Do a remove when removed from current viewport + Do an add when moved to current viewport + Do a redraw from the first of either when both in viewport + */ + this.$viewport.redraw();//very unoptimized + }; + + this.emptyNode = apf.xmldb.getXml(""); + this.$addEmpty = this.$add; + this.$add = function(xmlNode, Lid, xmlParentNode, htmlParentNode, beforeNode) { + //find new slot + var htmlNode = this.$pHtmlDoc.getElementById(Lid); + + if (!htmlNode) + return; + + //execute update + this.$updateNode(xmlNode, htmlNode);//, noModifier); + }; + + this.$fill = function(){ + + }; + + this.clear = function(nomsg, do_event) { + if (this.clearSelection) + this.clearSelection(!do_event); + + //this.documentId = this.xmlRoot = this.cacheId = null; + + if (typeof nomsg == "string") { + var msgType = nomsg; + nomsg = false; + + //@todo apf3.0 please use attr. inheritance + if (!this[msgType + "-message"]) + this.$setInheritedAttribute(msgType + "-message"); + } + + if (!nomsg) { + this.$viewport.offset = 0; + this.$viewport.length = 0; + this.$viewport.resize(0); + if (this.$viewport.sb) + this.$viewport.sb.$update(); + + if (this.$setClearMessage) { + this.$setClearMessage(msgType + ? this[msgType + "-message"] + : this["empty-message"], msgType || "empty"); + } + } + else if (this.$removeClearMessage) + this.$removeClearMessage(); + + this.$viewport.cache = null; + }; + + var _self = this; + this.$viewport = new apf.$viewportVirtual(this); + + this.getViewport = function(){ + return this.$viewport; + } + + this.$isInViewport = function(xmlNode, struct) { + /*var marker = xmlNode.selectSingleNode("preceding-sibling::a_marker"); + var start = marker ? marker.getAttribute("end") : 0; + + if (!struct && this.$viewport.offset + this.$viewport.limit < start + 1) + return false; + + var position = start; + var nodes = (marker || xmlNode).selectNodes("following-sibling::" + + this.each.split("|").join("following-sibling::")); + + for (var i = 0; i < nodes.length; i++) { + ++position; + if (nodes[i] == xmlNode) + break; + } + + if (struct) struct.position = position; + + if (this.$viewport.offset > position + || this.$viewport.offset + this.$viewport.limit < position) + return false; + + return true;*/ + var nodes = this.getTraverseNodes(); + for (var i = 0, l = nodes.length; i < l; i++){ + if (nodes[i] == xmlNode) + return true; + } + + return false; + }; + + this.scrollTo = function(xmlNode, last) { + var sPos = {}; + this.$isInViewport(xmlNode, sPos); + this.$viewport.change(sPos.position + (last ? this.$viewport.limit - 1 : 0)); + }; + + /** + * @todo this one should be optimized + */ + this.getFirstTraverseNode = function(xmlNode) { + return this.getTraverseNodes(xmlNode)[0]; + }; + + + + this.$xmlUpdate = function(){ + this.$viewport.cache = null; + this.$viewport.length = this.xmlRoot.selectNodes(this.each).length; //@todo fix this for virtual length + this.$viewport.sb.$update(this.$container); + this._xmlUpdate.apply(this, arguments); + }; + + this.$load = function(XMLRoot) { + //Add listener to XMLRoot Node + apf.xmldb.addNodeListener(XMLRoot, this); + + //Reserve here a set of nodeConnect id's and add them to our initial marker + //Init virtual dataset here + + this.$updateTraverseCache(XMLRoot, true); + + if (!this.renderRoot && !this.$cachedTraverseList.length) + return this.clear(); + + //this.$removeClearMessage(); + + + + //Prepare viewport + this.$viewport.cache = null; + this.$viewport.offset = 0; + this.$viewport.length = this.$cachedTraverseList.length; //@todo fix this for virtual length + if (this.$viewport.length < this.$viewport.limit) + this.$viewport.resize(this.$viewport.length); + this.$viewport.prepare(); + //this.$viewport.change(0); + + //Traverse through XMLTree + var nodes = this.$addNodes(XMLRoot, null, null, this.renderRoot); + + //Build HTML + //this.$fill(nodes); + + //Select First Child + if (this.selectable) { + if (this.autoselect) { + if (nodes.length) + this.$selectDefault(XMLRoot); + + else + this.setProperty("selected", null); //@todo review this + + } + else { + this.clearSelection(true); + var xmlNode = this.getFirstTraverseNode(); //should this be moved to the clearSelection function? + if (xmlNode) + this.setCaret(xmlNode); + + this.setProperty("selected", null); //@todo review this + this.setProperty("chosen", null); + + } + } + + if (this.$focussable) + apf.window.hasFocus(this) ? this.$focus() : this.$blur(); + + this.$viewport.setScrollTop(0, true); + }; + + this.$loadSubData = function(){}; //We use the same process for subloading, it shouldn't be done twice + + + + this.$updateTraverseCache = function(xmlNode, force) { + if (force || !this.$cachedTraverseList || this.$cachedTraverseList.name != this.each) { + this.$cachedTraverseList = (xmlNode || this.xmlRoot).selectNodes(this.each); + this.$cachedTraverseList.name = this.each; + } + }; + + /** + * Retrieves a nodelist containing the {@link term.datanode data nodes} which are rendered by + * this element. + * + * @param {XMLElement} [xmlNode] the parent element on which the each query is applied. + */ + var getTraverseNodes = this.getTraverseNodes = function(xmlNode) { + if (!this.xmlRoot) + return; + + if (this.$viewport.cache) + return this.$viewport.cache; + + //caching statement here + this.$updateTraverseCache(xmlNode); + + var start = this.$viewport.offset, + end = Math.min(this.$cachedTraverseList.length, start + this.$viewport.limit); + + + + //Special case for fully loaded virtual dataset + var list = []; + for (var i = start; i < end; i++) { + list.push(this.$cachedTraverseList[i]); + } + + + return this.$sort ? this.$sort.apply(list) : list; + + + + }; + + var baseNTS = this.getNextTraverseSelected; + this.getNextTraverseSelected = function(xmlNode, up, count) { + if (!xmlNode) + xmlNode = this.selected; + if (!count) + count = 1; + + this.getTraverseNodes = apf.MultiselectBinding.prototype.getTraverseNodes; + var node = baseNTS.call(this, xmlNode, up, count); + this.getTraverseNodes = getTraverseNodes; + + return node; + +// if (node && node != xmlNode) +// return node; + + //@todo treeArch support + //this.getTraverseNodes() +// var nodes = apf.MultiselectBinding.prototype.getTraverseNodes.call(_self), i = 0; +// while (nodes[i] && nodes[i] != xmlNode) +// i++; + +// if (up) +// i = -1 * (nodes.length - i - 1); + +// this.$viewport.change(Math.max(0, this.$viewport.offset + i +// + (up ? count : -1 * count)), null, true, true); + + //nodes = this.getTraverseNodes(); +// return nodes[up ? nodes.length - 1 : 0]; + }; + + //@todo keyboard handlers for pgup/pgdown should measure items instead of assuming fixed height + + //Init + this.caching = false; //for now, because the implications are unknown +}; + +apf.$viewportVirtual = function(amlNode) { + this.amlNode = amlNode; + + var _self = this; + this.amlNode.addEventListener("mousescroll", function(e) { + if (!_self.scrollbar || _self.scrollbar.horizontal) + return; + + if (e.returnValue === false) + return; + + var div = _self.getScrollHeight() - _self.getHeight(); + if (div) { + _self.setScrollTop(_self.getScrollTop() + + (-1 * e.delta * Math.min(45, _self.getHeight()/10)), false, true) + + e.preventDefault(); + } + }); + + apf.addListener(this.$getHtmlHost(), "scroll", function(){ + _self.setScrollTop(_self.getScrollTop()); + }); + + amlNode.addEventListener("resize", function(){ + _self.$findNewLimit(); + }); + + amlNode.addEventListener("afterload", function(){ + var itemHeight = _self.$getItemHeight(); + _self.$findNewLimit(); + + if (itemHeight == 1000) + _self.$findNewLimit(); + }); + + if (!amlNode.scrollbar) { + this.sb = new apf.scrollbar(); + + this.sb.parentNode = new apf.Class().$init(); + this.sb.parentNode.$container = amlNode.$pHtmlNode; + this.sb.parentNode.$int = amlNode.$pHtmlNode; + this.sb.dispatchEvent("DOMNodeInsertedIntoDocument"); + + this.sb.attach(this); + } + + /* @todo + * - Fix bug in optimization + * - Fix flickering with larger viewport + * - Get templates to work + * - Firefox has problems with the scrollbar + * / Fix scrolling of items bigger than viewport (limit is too tight sometimes) + * - Improve pgup/pgdown + * - Fix multigrid lists (thumbnail) + * - Fix FF html conversion (insertHtmlNodes) + * - Optimize grow function to use fill + */ + +// apf.layout.setRules(amlNode.$container, "scrollbar", "\ +// var s = apf.all[" + _self.sb.$uniqueId + "];\ +// s.$update();\ +// ", true); +// apf.layout.queue(amlNode.$container); + +}; + +(function(){ + this.offset = 0; + this.limit = 2; + this.length = 0; + this.host = this; + this.cache = null; + this.inited = false; + this.virtual = true; + + this.setScrollbar = function(scrollbar, onscroll) { + this.scrollbar = scrollbar; + + this.amlNode.addEventListener("scroll", onscroll); + } + + this.isVisible = function(){ + var htmlNode = this.$getHtmlHost(); + return htmlNode.offsetHeight || htmlNode.offsetWidth ? true : false; + } + + this.focus = function(){ + if (this.amlNode.focus && this.amlNode.$isWindowContainer !== true) + this.amlNode.focus(); + } + + this.getScrollTop = function(){ + var htmlNode = this.$getHtmlHost(); + return (this.offset * this.$getItemHeight()) + htmlNode.scrollTop; + } + + this.getScrollLeft = function(){ + var htmlNode = this.$getHtmlHost(); + return htmlNode.scrollLeft; + } + + this.getScrollHeight = function(){ + return (this.length) * this.$getItemHeight(); + } + + this.getScrollWidth = function(){ + var htmlNode = this.$getHtmlHost(); + return (apf.isIE && htmlNode.lastChild + ? htmlNode.lastChild.offsetLeft + + htmlNode.lastChild.offsetWidth + + apf.getBox(apf.getStyle(htmlNode, "padding"))[1] + + (parseInt(apf.getStyle(htmlNode, "marginRight")) || 0) + : htmlNode.scrollWidth); + } + + this.getHeight = function(){ + var htmlNode = this.$getHtmlHost(); + return htmlNode.tagName == "HTML" || htmlNode.tagName == "BODY" + ? apf.getWindowHeight() + : apf.getHtmlInnerHeight(htmlNode); + } + + this.getWidth = function(){ + var htmlNode = this.$getHtmlHost(); + return htmlNode.tagName == "HTML" || htmlNode.tagName == "BODY" + ? apf.getWindowHeight() + : apf.getHtmlInnerWidth(htmlNode); + } + + this.setScrollTop = function(value, preventEvent, byUser) { + var htmlNode = this.$getHtmlHost(); + var itemHeight = this.$getItemHeight(); + + this.change(Math.floor(value / itemHeight)); + + htmlNode.scrollTop = value - (this.offset * itemHeight); + + if (!preventEvent) { + this.amlNode.dispatchEvent("scroll", { + direction: "vertical", + byUser: byUser, + viewport: this, + scrollbar: this.scrollbar + }); + } + } + + this.setScrollLeft = function(value, preventEvent, byUser) { + var htmlNode = this.$getHtmlHost(); + + htmlNode.scrollLeft = value; + + if (!preventEvent) { + this.amlNode.dispatchEvent("scroll", { + direction: "horizontal", + byUser: byUser, + viewport: this, + scrollbar: this.scrollbar + }); + } + } + + this.scrollIntoView = function(xmlNode, toBottom) { + var _self = this.amlNode; + var htmlNode = apf.xmldb.findHtmlNode(xmlNode, _self); + if (htmlNode && htmlNode.offsetTop - _self.$container.scrollTop > 0 + && htmlNode.offsetTop + htmlNode.offsetHeight + - _self.$container.scrollTop < _self.$container.offsetHeight) + return; + + if (this.amlNode.$sharedScrollbarMove) + this.amlNode.$sharedScrollbarMove(); + + var nr = apf.getChildNumber(xmlNode, + apf.MultiselectBinding.prototype.getTraverseNodes.call(_self)); + var itemHeight = this.$getItemHeight(); + + this.setScrollTop(nr * itemHeight + (toBottom ? itemHeight - this.getHeight() : 0)); + } + + // *** Private *** // + + //Assume all items have the same height; + //@todo this can be optimized by caching + this.$getItemHeight = function(){ + if (this.amlNode.each && this.amlNode.xmlRoot) { + var nodes = this.amlNode.getTraverseNodes(); + if (nodes.length) { + var htmlNode = apf.xmldb.findHtmlNode(nodes[0], this.amlNode); + if (htmlNode) + return this.$lastItemHeight = htmlNode.offsetHeight; + } + } + + return this.$lastItemHeight || 1000; + } + + this.$getHtmlHost = function(){ + var htmlNode = this.amlNode.$int || this.amlNode.$container; + return (htmlNode.tagName == "BODY" || htmlNode.tagName == "HTML" + ? (apf.isSafari || apf.isChrome ? document.body : htmlNode.parentNode) + : htmlNode); + } + + // *** Implementation *** // + + this.draw = function(){ + this.inited = true; + var limit = this.limit; this.limit = 0; + this.resize(limit, true); + } + + this.redraw = function(){ + this.change(this.offset, this.limit, true); + } + + // set id's of xml to the viewport + this.prepare = function(){ + if (!this.inited) + this.draw(); + + var _self = this.amlNode; + var nodes = _self.getTraverseNodes(); + if (!nodes) + return; + + var len = nodes.length; + var docId = apf.xmldb.getXmlDocId(_self.xmlRoot), + hNodes = _self.$container.childNodes, hNode; + for (var j = 0, i = 0, l = hNodes.length; i < l; i++) { + if (hNodes[i].nodeType != 1) continue; + + if (j >= len) + hNodes[i].style.display = "none"; //Will ruin tables & lists + else { + hNode = hNodes[i]; + _self.$deselect(hNode); + hNode.style.display = "block"; //Will ruin tables & lists + apf.xmldb.nodeConnect(docId, nodes[j], hNode, _self); + } + + j++; + } + }; + + /** + * Note: this function only supports single dimension items (also no grid, like thumbnails) + */ + this.resize = function(limit, updateScrollbar) { + this.cache = null; + + var _self = this.amlNode; + var i; + //Viewport shrinks + if (limit < this.limit) { + var nodes = _self.$container.childNodes; + for (i = nodes.length - 1; i >= 0; i--) { + if (nodes[i].nodeType != 1) continue; + _self.$container.removeChild(nodes[i]); + if (--this.limit == limit) break; + } + } + //Viewport grows + else if (limit > this.limit) { + for (i = this.limit; i < limit; i++) { + _self.$addEmpty(_self.emptyNode, "", _self.xmlRoot, _self.$container); + } + } + else + return; + + this.limit = limit; + + if (updateScrollbar && this.sb) + this.sb.$update(this.$container); + }; + + this.$findNewLimit = function(){ + if (!this.amlNode.xmlRoot || !this.amlNode.$ext.offsetHeight) + return; + + var limit = Math.ceil(this.getHeight() / this.$getItemHeight() + 2); + if (this.amlNode.$cachedTraverseList + && this.amlNode.$cachedTraverseList.length < limit) + limit = this.amlNode.$cachedTraverseList.length; + + if (limit != this.limit) { + this.resize(limit); + this.redraw(); + } + }; + + /** + * @todo This method should be optimized by checking if there is + * overlap between the new offset and the old one + */ + this.change = function(offset, limit, force) { + var offsetN; + var _self = this.amlNode; + + if (offset > this.length - this.limit) + offsetN = Math.floor(this.length - this.limit); + else + offsetN = Math.floor(offset); + + if (offsetN < 0) + offsetN = 0; + + if (!limit) + limit = this.limit; + + if (!force) + force = apf.isGecko; + + var scrollTop = this.getScrollTop(); + + this.cache = null; + var diff = offsetN - this.offset, + oldLimit = this.limit; + if (diff * diff >= this.limit*this.limit) //there is no overlap + diff = false; + this.offset = offsetN; + + if (diff > 0) { //get last node before resize + var lastNode = _self.$container.lastChild; + if (lastNode.nodeType != 1) + lastNode = lastNode.previousSibling; + } + + //Traverse through XMLTree + var nodes = _self.getTraverseNodes(); + if (!nodes || !nodes.length) + return; + + if (nodes.length < this.limit) { + if (offset > 0) + alert("shouldnt get here"); + else + this.resize(nodes.length); + } + + var docId = apf.xmldb.getXmlDocId(_self.xmlRoot), + hNodes = _self.$container.childNodes, + xmlNode, htmlNode, xmlPos, sel, len, j, i; + + //remove nodes from the beginning + if (diff > 0) { + xmlPos = oldLimit - diff; + len = hNodes.length, + sel = _self.$getSelection(); + for (j = 0, i = 0; j < diff && i < len; i++) { + htmlNode = _self.$container.firstChild; + if (htmlNode.nodeType == 1) { + j++; + xmlNode = nodes[xmlPos++]; + if (xmlNode) { + apf.xmldb.nodeConnect(docId, xmlNode, htmlNode, _self); + _self.$updateNode(xmlNode, htmlNode);//, noModifier); + if (sel.indexOf(xmlNode) > -1) + _self.$select(htmlNode); + else + _self.$deselect(htmlNode); + htmlNode.style.display = "block"; + } + else { + htmlNode.style.display = "none"; + } + } + + _self.$container.appendChild(htmlNode); + } + } + //remove nodes from the end + else if (diff < 0) { + diff = diff * -1; + xmlPos = 0; //should be adjusted for changing limit + sel = _self.$getSelection(); + for (j = 0, i = hNodes.length-1; j < diff && i >= 0; i++) { + htmlNode = _self.$container.lastChild; + if (htmlNode.nodeType == 1) { + j++; + xmlNode = nodes[xmlPos++]; + apf.xmldb.nodeConnect(docId, xmlNode, htmlNode, _self); + _self.$updateNode(xmlNode, htmlNode);//, noModifier); + if (sel.indexOf(xmlNode) > -1) + _self.$select(htmlNode); + else + _self.$deselect(htmlNode); + htmlNode.style.display = "block"; + } + + _self.$container.insertBefore(htmlNode, _self.$container.firstChild); + } + } + //Recalc all nodes + else if (force || diff === false) { + len = hNodes.length; + sel = _self.$getSelection(); + for (j = 0, i = 0; i < len; i++) { + htmlNode = hNodes[i]; + if (htmlNode.nodeType == 1) { + xmlNode = nodes[j++]; + apf.xmldb.nodeConnect(docId, xmlNode, htmlNode, _self); + _self.$updateNode(xmlNode, htmlNode);//, noModifier); + + if (sel.indexOf(xmlNode) > -1) + _self.$select(htmlNode); + else + _self.$deselect(htmlNode); + } + } + } + + if (!_self.$selected && sel && sel.length) + _self.$selected = apf.xmldb.findHtmlNode(sel[0], _self); + + var htmlNode = this.$getHtmlHost(); + var itemHeight = this.$getItemHeight(); + htmlNode.scrollTop = scrollTop - (this.offset * itemHeight); + }; +}).call(apf.$viewportVirtual.prototype); + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + +apf.__XFORMS__ = 1 << 17; + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +apf.clipboard = new apf.Class().$init(); +apf.clipboard.store = null; +apf.clipboard.empty = true; +apf.clipboard.copied = null; +apf.clipboard.put = function(item) { + this.store = item; + this.setProperty("data", item); + this.setProperty("empty", item ? false : true); +}; +apf.clipboard.clear = function(){ + this.setProperty("data", null); + this.setProperty("empty", true); +} +apf.clipboard.get = function(){ + return this.store; +}; + + +apf.clipboard.$highlightSelection = function(amlNode, nodes, unset) { + for (var i = 0, l = nodes.length; i < l; i++) { + apf.setStyleClass(apf.xmldb.getHtmlNode(nodes[i], amlNode), (unset ? '' : 'cut'), ['cut']); + } +} +apf.clipboard.copySelection = function(amlNode) { + var nodes = this.get() || []; + this.$highlightSelection(amlNode, nodes, true); + this.put(amlNode.getSelection().map(function (node) { + return apf.xmldb.getCleanCopy(node); + })); + this.copied = true; +}; +apf.clipboard.cutSelection = function(amlNode) { + var nodes = this.get() || []; + this.$highlightSelection(amlNode, nodes, true); + this.put(nodes = amlNode.getSelection()); + this.$highlightSelection(amlNode, nodes); + this.copied = false; +}; +apf.clipboard.pasteSelection = function(amlNode, selected) { + var copied, nodes = this.get(); + if (!nodes) return; + + if (!selected) + selected = amlNode.selected || amlNode.getFirstTraverseNode(); + + if (amlNode.hasFeature(apf.__DRAGDROP__)) { + var candrop = amlNode.isDropAllowed(apf.clipboard.data, selected); + if (!candrop) + return false; + var action = candrop[1] && candrop[1].action + || (amlNode.$isTreeArch ? "tree-append" : "list-append"); + + copied = nodes.slice(0); + amlNode.$dragDrop(selected, copied, candrop && candrop[1], action, + null, null, null, this.copied); + + //amlNode.copy(nodes, selected, undefined, !this.copied); + } + else { + if (nodes[0].parentNode) { + for (var i = 0, l = nodes.length; i < l; i++) { + apf.xmldb.moveNode(selected, nodes[i]); + } + } + else { + copied = []; + for (var i = 0, l = nodes.length; i < l; i++) { + copied[i] = apf.xmldb.appendChild(selected, nodes[i]); + } + } + } + + if (!this.copied) { + this.$highlightSelection(amlNode, nodes, true); + apf.clipboard.clear(); + } + + // amlNode.selectList(copied || nodes); +}; + + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * Object representing the window of the AML application. The semantic is + * similar to that of a window in the browser, except that this window is not + * the same as the JavaScript global object. It handles the focussing within + * the document and several other events such as exit and the keyboard events. + * + * @class apf.window + * @inherits apf.Class + * @default_private + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.8 + */ +/** + * @event blur Fires when the browser window loses focus. + */ +/** + * @event focus Fires when the browser window receives focus. + * + * + */ +apf.window = function(){ + this.$uniqueId = apf.all.push(this); + this.apf = apf; + + /** + * Returns a string representation of this object. + */ + this.toString = function(){ + return "[apf.window]"; + }; + + /** + * Retrieves the primary {@link apf.actiontracker action tracker} of the application. + */ + this.getActionTracker = function(){ + return this.$at + }; + + /* + * @private + */ + this.loadCodeFile = function(url) { + //if(apf.isWebkit) return; + if (self[url]) + apf.importClass(self[url], true, this.win); + else + apf.include(url);//, this.document); + }; + + + + /** + * Show the browser window. + */ + this.show = function(){ + if (apf.isDeskrun) + jdwin.Show(); + }; + + /** + * Hide the browser window. + */ + this.hide = function(){ + if (apf.isDeskrun) { + jdwin.Hide(); + } + else { + this.loaded = false; + if (this.win) + this.win.close(); + } + }; + + /** + * Focus the browser window. + */ + this.focus = function(){ + if (apf.isDeskrun) + jdwin.SetFocus(); + else + window.focus(); + }; + + /** + * Set the icon of the browser window. + * @param {String} url The location of the _.ico_ file. + */ + this.setIcon = function(url) { + if (apf.isDeskrun) + jdwin.icon = parseInt(url) == url ? parseInt(url) : url; + }; + + /** + * Set the title of the browser window. + * @param {String} value The new title of the window. + */ + this.setTitle = function(value) { + this.title = value || ""; + + if (apf.isDeskrun) + jdwin.caption = value; + else + document.title = (value || ""); + }; + + /* + * @private + */ + this.loadAml = function(x) { + if (x[apf.TAGNAME] == "deskrun") + this.loadDeskRun(x); + /*else { + + }*/ + }; + + + + // *** Focus Internals *** // + + + this.vManager = new apf.visibilitymanager(); + + + + this.zManager = new apf.zmanager(); + + + + + this.$tabList = []; + + this.$addFocus = function(amlNode, tabindex, isAdmin) { + if (!isAdmin) { + amlNode.addEventListener("DOMNodeInserted", moveFocus); + amlNode.addEventListener("DOMNodeRemoved", removeFocus); + + if (amlNode.$isWindowContainer > -2) { + amlNode.addEventListener("focus", trackChildFocus); + amlNode.addEventListener("blur", trackChildFocus); + + amlNode.$focusParent = amlNode; + + if (amlNode.$isWindowContainer > -1) { + if (!amlNode.$tabList) + amlNode.$tabList = [amlNode]; + + this.$tabList.push(amlNode); + return; + } + else { + amlNode.$tabList = [amlNode]; + } + } + } + + var fParent = findFocusParent(amlNode), + list = fParent.$tabList; + + + + if (!amlNode.$isWindowContainer) + amlNode.$focusParent = fParent; + else + amlNode.$focusParent2 = fParent; + + if (list[tabindex]) + list.insertIndex(amlNode, tabindex); + else if (tabindex || parseInt(tabindex) === 0) + list[tabindex] = amlNode; + else + list.push(amlNode); + }; + + this.$removeFocus = function(amlNode) { + if (!amlNode.$focusParent) + return; + + amlNode.$focusParent.$tabList.remove(amlNode); + + if (!amlNode.$isWindowContainer) { + amlNode.removeEventListener("DOMNodeInserted", moveFocus); + amlNode.removeEventListener("DOMNodeRemoved", removeFocus); + } + + if (amlNode.$isWindowContainer > -2) { + amlNode.removeEventListener("focus", trackChildFocus); + amlNode.removeEventListener("blur", trackChildFocus); + } + }; + + var focusLoopDetect; + this.$focus = function(amlNode, e, force) { + var aEl = this.activeElement; + if (aEl == amlNode && !force) + return; //or maybe when force do $focus + + + + this.$settingFocus = amlNode; + + if (!e) + e = {}; + + e.toElement = amlNode; + e.fromElement = aEl; + + if (aEl && aEl != amlNode && focusLoopDetect != aEl) { + focusLoopDetect = aEl; + + aEl.blur(true, e); + + + + if (focusLoopDetect != aEl) + return false; + } + + if (amlNode.$focussable != apf.MENU || !apf.activeElement) { + apf.activeElement = + this.document.activeElement = + this.document.documentElement.$lastFocussed = amlNode; + } + + (apf.window.activeElement = amlNode).focus(true, e); + + this.$settingFocus = null; + + apf.dispatchEvent("movefocus", { + toElement: amlNode + }); + + + + + + + }; + + this.$blur = function(amlNode) { + var aEl = this.activeElement; + if (aEl != amlNode) + return false; + + + + aEl.$focusParent.$lastFocussed = null; + + if (aEl.$focussable != apf.MENU) { + apf.activeElement = + this.document.activeElement = null; + } + + apf.window.activeElement = null; + + apf.dispatchEvent("movefocus", { + fromElement: amlNode + }); + + + }; + + var lastFocusParent; + + this.$focusDefault = function(amlNode, e) { + var fParent = findFocusParent(amlNode); + this.$focusLast(fParent, e); + }; + + this.$focusRoot = function(e) { + var docEl = apf.document.documentElement; + if (this.$focusLast(docEl, e) === false) { + //docEl.$lastFocussed = null; + //this.moveNext(null, apf.document.documentElement, true, e); + } + }; + + this.$focusLast = function(amlNode, e, ignoreVisible) { + var lf = amlNode.$lastFocussed; + + if (lf && lf.parentNode && lf.$focussable === true + && (ignoreVisible || lf.$ext.offsetHeight)) { + this.$focus(lf, e, true); + } + else { //Let's find the object to focus first + var next, node = amlNode, skip; + while (node) { + if (!skip && node.focussable !== false && node.$focussable === true && !node.$tabList + && (ignoreVisible || node.$ext && node.$ext.offsetHeight) && node.disabled < 1) { + this.$focus(node, e, true); + break; + } + + //Walk sub tree + if ((next = !skip && node.firstChild || !(skip = false) && node.nextSibling)) { + node = next; + if (node.$isWindowContainer > 0) + skip = true; + } + else if (node == amlNode) { + if (node.$isWindowContainer) + this.$focus(node, e, true); + return; + } + else { + do { + node = node.parentNode; + } while (node && !node.nextSibling && node != amlNode + && !node.$isWindowContainer) + + if (node == amlNode) { + if (node.$isWindowContainer) + this.$focus(node, e, true); + return; //do nothing + } + + if (node) { + if (node.$isWindowContainer) { + this.$focus(node, e, true); + break; + } + + node = node.nextSibling; + } + } + } + + if (!node) + this.$focus(apf.document.documentElement);//return false;// + + /*@todo get this back from SVN + var node, list = amlNode.$tabList; + for (var i = 0; i < list.length; i++) { + node = list[i]; + if (node.focussable !== false && node.$focussable === true + && (ignoreVisible || node.$ext.offsetHeight)) { + this.$focus(node, e, true); + return; + } + } + + this.$focus(apf.document.documentElement);*/ + } + }; + + function trackChildFocus(e) { + if (e.name == "blur") { + if (e.srcElement != this && this.$blur) + this.$blur(); + return; + } + + if (e.srcElement != this && this.$focus && (!e || !e.mouse || this.$focussable == apf.KEYBOARD_MOUSE)) + this.$focus(); + + if (e.srcElement == this || e.trackedChild) { + e.trackedChild = true; + return; + } + + this.$lastFocussed = e.srcElement; + + if (this.localName && this.localName.indexOf("window") > -1) + e.trackedChild = true; + } + + function findFocusParent(amlNode) { + var node = amlNode; + do { + node = node.parentNode; + } while (node && !node.$isWindowContainer); + //(!node.$focussable || node.focussable === false) + + return node || apf.document.documentElement; + } + + //Dom handler + //@todo make this look at the dom tree insertion point to determine tabindex + function moveFocus(e) { + if (e && e.currentTarget != this) + return; + + if (this.$isWindowContainer) + apf.window.$tabList.pushUnique(this); + else + apf.window.$addFocus(this, this.tabindex, true) + } + + //Dom handler + function removeFocus(e) { + if (e && (e.currentTarget != this || e.$doOnlyAdmin)) + return; + + //@todo apf3.0 this should be fixed by adding domremovenode events to all children + var list = this.$focusParent.$tabList; + var nodes = this.childNodes; + for (var i = 0, l = nodes.length; i < l; i++) { + list.remove(nodes[i]); //@todo assuming no windows here + } + + if (apf.window.activeElement == this) + apf.window.moveNext(); + + if (this.$isWindowContainer) { + apf.window.$tabList.remove(this); //@todo this can't be right + return; + } + + if (!this.$focusParent) + return; + + list.remove(this); + //this.$focusParent = null; //@experimental to not execute this + } + + // *** Focus API *** // + + /** + * Determines whether a given AML element has the focus. + * @param {apf.AmlElement} The element to check + * @returns {Boolean} Indicates whether the element has focus. + */ + this.hasFocus = function(amlNode) { + return this.activeElement == amlNode; + }; + + /* + * @private + */ + this.moveNext = function(shiftKey, relObject, switchWindows, e) { + if (switchWindows && apf.window.activeElement) { + var p = apf.window.activeElement.$focusParent; + if (p.visible && p.modal) + return false; + } + + var dir, start, next, + amlNode = relObject || apf.window.activeElement, + fParent = amlNode + ? (switchWindows && amlNode.$isWindowContainer + && amlNode.$isWindowContainer != -1 + ? apf.window + : e && e.innerList ? amlNode.$focusParent : amlNode.$focusParent2 || amlNode.$focusParent) + : apf.document.documentElement, + list = fParent.$tabList; + + if (amlNode && (switchWindows || amlNode != apf.document.documentElement)) { + start = (list || []).indexOf(amlNode); + if (start == -1) { + + + return; + } + } + else { + start = -1; + } + + if (this.activeElement == amlNode + && list.length == 1 || list.length == 0) + return false; + + dir = (shiftKey ? -1 : 1); + next = start; + if (start < 0) + start = 0; + do { + next += dir; + + if (next >= list.length) + next = 0; + else if (next < 0) + next = list.length - 1; + + if (start == next && amlNode) { + if (list[0].$isWindowContainer) + this.$focus(list[0], e); + + return false; //No visible enabled element was found + } + + amlNode = list[next]; + } + while (amlNode && ( + amlNode.disabled > 0 + || amlNode == apf.window.activeElement + || (switchWindows ? !amlNode.visible : amlNode.$ext && !amlNode.$ext.offsetHeight) + || amlNode.focussable === false + || switchWindows && !amlNode.$tabList.length + )); + + if (!amlNode) + return; + + if (fParent == apf.window && amlNode.$isWindowContainer != -2) { + this.$focusLast(amlNode, {mouse:true}, switchWindows); + } + else { + (e || (e = {})).shiftKey = shiftKey; + this.$focus(amlNode, e); + } + + + }; + + /* + * @private + */ + this.focusDefault = function(){ + + + if (this.moveNext() === false) + this.moveNext(null, apf.document.documentElement, true) + }; + + + + // *** Set Window Events *** // + + apf.addListener(window, "beforeunload", function(){ + return apf.dispatchEvent("exit"); + }); + + //@todo apf3.x why is this loaded twice + apf.addListener(window, "unload", function(){ + if (!apf) + return; + + apf.window.isExiting = true; + }); + + + + // *** Keyboard and Focus Handling *** // + + apf.addListener(document, "contextmenu", function(e) { + if (!e) + e = event; + + + var pos, ev, + amlNode = apf.findHost(e.srcElement || e.target) + || apf.window.activeElement + || apf.document && apf.document.documentElement; + + if (amlNode && amlNode.localName == "menu") //The menu is already visible + return false; + + + //if (amlNode && amlNode.localName == "menu") + //amlNode = amlNode.parentNode; + + if (apf.contextMenuKeyboard) { + if (amlNode) { + pos = amlNode.selected + ? apf.getAbsolutePosition(amlNode.$selected) + : apf.getAbsolutePosition(amlNode.$ext || amlNode.$pHtmlNode); + } + else { + pos = [0, 0]; + } + + ev = { + x: pos[0] + 10 + document.documentElement.scrollLeft, + y: pos[1] + 10 + document.documentElement.scrollTop, + amlNode: amlNode, + htmlEvent: e + } + } + else { + if (e.htmlEvent) { + ev = e; + } + else { + ev = { //@todo probably have to deduct the border of the window + x: e.clientX + document.documentElement.scrollLeft, + y: e.clientY + document.documentElement.scrollTop, + htmlEvent: e + } + } + } + + ev.bubbles = true; //@todo discuss this, are we ok with bubbling? + + apf.contextMenuKeyboard = null; + + if ((amlNode || apf).dispatchEvent("contextmenu", ev) === false + || ev.returnValue === false) { + if (e.preventDefault) + e.preventDefault(); + return false; + } + + + if (apf.config.disableRightClick) { + if (e.preventDefault) + e.preventDefault(); + return false; + } + }); + + apf.addListener(document, "mouseup", function(e) { + if (!e) e = event; + + apf.dispatchEvent("mouseup", { + htmlEvent: e + }); + }); + + var ta = {"INPUT":1, "TEXTAREA":1, "SELECT":1, "EMBED":1, "OBJECT":1}; + apf.addListener(document, "mousedown", this.$mousedown = function(e) { + + if (!e) e = event; + var p, + amlNode = apf.findHost(e.srcElement || e.target); + /*cEditable = amlNode && amlNode.liveedit + + ;*/ + + apf.popup.$mousedownHandler(amlNode, e); + + if (amlNode === false) + amlNode = apf.window.activeElement; + + var eventTarget = amlNode; + + while (amlNode && !amlNode.focussable) + amlNode = amlNode.parentNode; + + //Make sure the user cannot leave a modal window + if ((!amlNode || ((!amlNode.$focussable || amlNode.focussable === false) + && amlNode.canHaveChildren != 2 && !amlNode.$focusParent)) + && apf.config.allowBlur) { + lastFocusParent = null; + if (apf.window.activeElement) + apf.window.activeElement.blur(); + } + else if (amlNode) { //@todo check this for documentElement apf3.0 + if ((p = apf.window.activeElement + && apf.window.activeElement.$focusParent || lastFocusParent) + && p.visible && p.modal && amlNode.$focusParent != p + && amlNode.$isWindowContainer != -1) { + apf.window.$focusLast(p, {mouse: true, ctrlKey: e.ctrlKey}); + } + else if (!amlNode && apf.window.activeElement) { + apf.window.$focusRoot(); + } + else if (amlNode.$isWindowContainer == -1) { + if (amlNode.$tabList.length) + apf.window.moveNext(null, amlNode.$tabList[0], null, {mouse: true, innerList: true}); + else + apf.window.$focus(amlNode); + } + else if ((amlNode.disabled == undefined || amlNode.disabled < 1) + && amlNode.focussable !== false) { + if (amlNode.$focussable) { // === apf.KEYBOARD_MOUSE + apf.window.$focus(amlNode, {mouse: true, ctrlKey: e.ctrlKey}); + } + else if (amlNode.canHaveChildren == 2) { + if (!apf.config.allowBlur || !apf.window.activeElement + || apf.window.activeElement.$focusParent != amlNode) + apf.window.$focusLast(amlNode, {mouse: true, ctrlKey: e.ctrlKey}); + } +// else { +// if (!apf.config.allowBlur || amlNode != apf.document.documentElement) +// apf.window.$focusDefault(amlNode, {mouse: true, ctrlKey: e.ctrlKey}); +// } + } + else { + // Disabled this to prevent menus from becoming unclickable + // apf.window.$focusDefault(amlNode, {mouse: true, ctrlKey: e.ctrlKey}); + } + + + } + + amlNode = eventTarget; + + + apf.dispatchEvent("mousedown", { + htmlEvent: e, + amlNode: amlNode || apf.document.documentElement + }); + + //Non IE/ iPhone selection handling + if (apf.isIE || apf.isIphone) + return; + + var canSelect = !((!apf.document + && (!apf.isParsingPartial || amlNode) + || apf.dragMode) && !ta[e.target && e.target.tagName]); + + if (canSelect && amlNode) { + if (!e.target && e.srcElement) + e.target = {}; + var isTextInput = (ta[e.target.tagName] + || e.target.contentEditable == "true") && !e.target.disabled //@todo apf3.0 need to loop here? + || amlNode.$isTextInput + && amlNode.$isTextInput(e) && amlNode.disabled < 1; + + //(!amlNode.canHaveChildren || !apf.isChildOf(amlNode.$int, e.srcElement)) + if (!apf.config.allowSelect && !isTextInput + && amlNode.nodeType != amlNode.NODE_PROCESSING_INSTRUCTION + && !amlNode.textselect) //&& (!amlNode.$int || amlNode.$focussable) //getElementsByTagNameNS(apf.ns.xhtml, "*").length + canSelect = false; + } + + if (!canSelect && e.button != 2) { // && !cEditable + if (e.preventDefault) + e.preventDefault(); + + try{ + if (document.activeElement && document.activeElement.contentEditable == "true") //@todo apf3.0 need to loop here? + document.activeElement.blur(); + }catch(e) {} + } + }); + + //IE selection handling + apf.addListener(document, "selectstart", function(e) { + if (!apf.isIE) + return; + + if (!e) e = event; + + var amlNode = apf.findHost(e.srcElement); + var canSelect = !(!apf.document + && (!apf.isParsingPartial || amlNode) + || apf.dragMode); + + if (canSelect) { + //(!amlNode.canHaveChildren || !apf.isChildOf(amlNode.$int, e.srcElement)) + if (!apf.config.allowSelect + && (amlNode && amlNode.nodeType != amlNode.NODE_PROCESSING_INSTRUCTION + && !amlNode.textselect)) //&& !amlNode.$int // getElementsByTagNameNS(apf.ns.xhtml, "*").length + canSelect = false; + } + + if (!canSelect) { + e.returnValue = false; + return false; + } + }); + + // Keyboard forwarding to focussed object + apf.addListener(document, "keyup", this.$keyup = function(e) { + if (!e) e = event; + + + var ev = { + keyCode: e.keyCode, + ctrlKey: e.ctrlKey, + shiftKey: e.shiftKey, + metaKey: e.metaKey, + altKey: e.altkey, + htmlEvent: e, + bubbles: true //@todo is this much slower? + }; + + var aEl = apf.document && apf.window.activeElement; + if ((aEl && !aEl.disableKeyboard + ? aEl.dispatchEvent("keyup", ev) + : apf.dispatchEvent("keyup", ev)) === false) { + apf.preventDefault(e); + return false; + } + + }); + + + var wheel = this.$mousewheel = function wheel(e) { + if (!e) + e = event; + + var delta = null; + if (e.wheelDelta) { + delta = e.wheelDelta / 120; + if (apf.isOpera) + delta *= -1; + } + else if (e.detail) { + delta = -e.detail / 3; + } + + if (delta !== null) { + //Fix for scrolling too much + if (apf.isIE) { + var el = e.srcElement || e.target; + while (el && el.scrollHeight <= el.offsetHeight) + el = el.parentNode || el.$parentNode; + + if (el && el.nodeType == 9) + el = el.documentElement; + + if (!el || el.nodeType != 1) return; + + if (el && el.tagName == "BODY" && "auto|scroll".indexOf(apf.getStyle(el, "overflowY")) == -1) + el = document.documentElement; + + if (el && "auto|scroll".indexOf(apf.getStyle(el, "overflowY")) > -1) { + var max, dist = 0.35 * el.offsetHeight * delta; + if (delta < 0) { + if (el && el.scrollTop >= (max = el.scrollHeight - el.offsetHeight + apf.getVerBorders(el)) + dist) { + el.scrollTop = max; + e.returnValue = false; + } + } + else { + if (el && el.scrollTop <= dist) { + el.scrollTop = 0; + e.returnValue = false; + } + } + } + } + + var ev = { + delta: delta, + target: e.target || e.srcElement, + button: e.button, + ctrlKey: e.ctrlKey, + shiftKey: e.shiftKey, + metaKey: e.metaKey, + altKey: e.altKey, + bubbles: true, + htmlEvent: e + }; + + var amlNode = apf.findHost(e.srcElement || e.target); + var res = (amlNode || apf).dispatchEvent("mousescroll", ev); + if (res === false || ev.returnValue === false) { + if (e.preventDefault) + e.preventDefault(); + + e.returnValue = false; + } + } + } + + if (document.addEventListener) + document.addEventListener('DOMMouseScroll', wheel, false); + + window.onmousewheel = + document.onmousewheel = wheel; //@todo 2 keer events?? + + + //var browserNavKeys = {32:1,33:1,34:1,35:1,36:1,37:1,38:1,39:1,40:1} + + apf.addListener(document, "keyup", function(e) { + e = e || event; + + if (e.ctrlKey && e.keyCode == 9 && apf.window.activeElement) { + var w = apf.window.activeElement.$focusParent; + if (w.modal) { + if (e.preventDefault) + e.preventDefault(); + return false; + } + + apf.window.moveNext(e.shiftKey, + apf.window.activeElement.$focusParent, true); + + w = apf.window.activeElement.$focusParent; + if (w && w.bringToFront) + w.bringToFront(); + + if (e.preventDefault) + e.preventDefault(); + return false; + } + }); + + //@todo optimize this function + apf.addListener(document, "keydown", this.$keydown = function(e) { + e = e || event; + + + + + if (e.keyCode == 93) + apf.contextMenuKeyboard = true; + + + var amlNode = apf.window.activeElement, //apf.findHost(e.srcElement || e.target), + htmlNode = (e.explicitOriginalTarget || e.srcElement || e.target), + isTextInput = (ta[htmlNode.tagName] + || htmlNode.contentEditable || htmlNode.contentEditable == "true") //@todo apf3.0 need to loop here? + && !htmlNode.disabled + || amlNode && amlNode.$isTextInput + && amlNode.$isTextInput(e) && amlNode.disabled < 1; + + + + var eInfo = { + ctrlKey: e.ctrlKey, + metaKey: e.metaKey, + shiftKey: e.shiftKey, + altKey: e.altKey, + keyCode: e.keyCode, + htmlEvent: e, + isTextInput: isTextInput, + bubbles: true + }; + + delete eInfo.currentTarget; + + //Keyboard forwarding to focussed object + var aEl = amlNode; //isTextInput ? amlNode : + if ((aEl && !aEl.disableKeyboard && !aEl.editable + ? aEl.dispatchEvent("keydown", eInfo) + : apf.dispatchEvent("keydown", eInfo)) === false) { + apf.stopEvent(e); + if (apf.canDisableKeyCodes) { + try { + e.keyCode = 0; + } + catch (e) {} + } + return false; + } + + //Focus handling + else if ((!apf.config.disableTabbing || apf.window.activeElement) && e.keyCode == 9) { + //Window focus handling + if (e.ctrlKey && apf.window.activeElement) { + var w = apf.window.activeElement.$focusParent; + if (w.modal) { + if (e.preventDefault) + e.preventDefault(); + return false; + } + + apf.window.moveNext(e.shiftKey, + apf.window.activeElement.$focusParent, true); + + w = apf.window.activeElement.$focusParent; + if (w && w.bringToFront) + w.bringToFront(); + } + //Element focus handling + else if (!apf.window.activeElement || apf.window.activeElement.tagName != "menu") { + apf.window.moveNext(e.shiftKey); + } + + if (e.preventDefault) + e.preventDefault(); + return false; + } + + + //Disable backspace behaviour triggering the backbutton behaviour + var altKey = apf.isMac ? e.metaKey : e.altKey; + if (apf.config.disableBackspace + && e.keyCode == 8// || (altKey && (e.keyCode == 37 || e.keyCode == 39))) + && !isTextInput) { + if (apf.canDisableKeyCodes) { + try { + e.keyCode = 0; + } + catch (e) {} + } + e.returnValue = false; + } + + //Disable space behaviour of scrolling down the tab + /*if(Application.disableSpace && e.keyCode == 32 && e.srcElement.tagName.toLowerCase() != "input"){ + e.keyCode = 0; + e.returnValue = false; + }*/ + + //Disable F5 refresh behaviour + if (apf.config.disableF5 && (e.keyCode == 116 || e.keyCode == 117)) { + if (apf.canDisableKeyCodes) { + try { + e.keyCode = 0; + } + catch (e) {} + } + else { + e.preventDefault(); + e.stopPropagation(); + } + //return false; + } + + + /*if (browserNavKeys[e.keyCode] && apf.window.activeElement + && apf.config.autoDisableNavKeys) + e.returnValue = false;*/ + + if (e.keyCode == 27) + e.returnValue = false; + + if (!apf.config.allowSelect + && e.shiftKey && (e.keyCode > 32 && e.keyCode < 41) + && !isTextInput) { + e.returnValue = false; + } + + //apf.dispatchEvent("keydown", null, eInfo); + + if (e.returnValue === false && e.preventDefault) + e.preventDefault(); + + return e.returnValue; + + }); + + apf.document = {}; + this.init = function(strAml) { + + if (apf.actiontracker) { + this.$at = new apf.actiontracker(); + this.$at.name = "default"; + + apf.nameserver.register("actiontracker", "default", this.$at); + + } + + + + + + + + //Put this in callback in between the two phases + + + this.$domParser = new apf.DOMParser(); + this.document = apf.document = this.$domParser.parseFromString(strAml, + "text/xml", { + + timeout: apf.config.initdelay, + + callback: function(doc) { + //@todo apf3.0 + + //Call the onload event (prevent recursion) + if (apf.parsed != 2) { + //@todo apf3.0 onload is being called too often + var inital = apf.parsed; + apf.parsed = 2; + apf.dispatchEvent("parse", { //@todo apf3.0 document + initial: inital + }); + apf.parsed = true; + } + + if (!apf.loaded) { + + + + //Set the default selected element + if (!apf.window.activeElement && (!apf.config.allowBlur + || apf.document.documentElement + && apf.document.documentElement.editable)) + apf.window.focusDefault(); + + + apf.loaded = true; + $setTimeout(function() { + apf.dispatchEvent("load"); + apf.addEventListener("$event.load", function(cb) { + cb(); + }); + }); + } + + //END OF ENTIRE APPLICATION STARTUP + + + + + } + }); //async + }; + + + + /* + * @private + */ + this.destroy = function(){ + + }; +}; +apf.window.prototype = new apf.Class().$init(); +apf.window = new apf.window(); + + + + + + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +/** + * Compatibility layer for Gecko based browsers. + * @private + */ +apf.runGecko = function(){ + if (apf.runNonIe) + apf.runNonIe(); + + /* *************************************************************************** + XSLT + ****************************************************************************/ + + + //XMLDocument.selectNodes + HTMLDocument.prototype.selectNodes = XMLDocument.prototype.selectNodes = function(sExpr, contextNode) { + try { + var oResult = this.evaluate(sExpr, (contextNode || this), + this.createNSResolver(this.documentElement), + 7, null); //XpathResult.ORDERED_NODE_ITERATOR_TYPE + } + catch (ex) { + var msg = ex.message; + if (ex.code == ex.INVALID_EXPRESSION_ERR) + msg = msg.replace(/the expression/i, "'" + sExpr + "'"); + throw new Error(ex.lineNumber, "XPath error: " + msg); + } + + var nodeList = new Array(oResult.snapshotLength); + nodeList.expr = sExpr; + for (var i = nodeList.length - 1; i >= 0; i--) + nodeList[i] = oResult.snapshotItem(i); + return nodeList; + }; + + //Element.selectNodes + Text.prototype.selectNodes = + Attr.prototype.selectNodes = + Element.prototype.selectNodes = function(sExpr) { + return this.ownerDocument.selectNodes(sExpr, this); + }; + + //XMLDocument.selectSingleNode + HTMLDocument.prototype.selectSingleNode = + XMLDocument.prototype.selectSingleNode = function(sExpr, contextNode) { + try { + var oResult = this.evaluate(sExpr, (contextNode || this), + this.createNSResolver(this.documentElement), + 9, null); //XpathResult.FIRST_ORDERED_NODE_TYPE + } + catch (ex) { + var msg = ex.message; + if (ex.code == ex.INVALID_EXPRESSION_ERR) + msg = msg.replace(/the expression/i, "'" + sExpr + "'"); + throw new Error(ex.lineNumber, "XPath error: " + msg); + } + + return oResult.singleNodeValue; + }; + + //Element.selectSingleNode + Text.prototype.selectSingleNode = + Attr.prototype.selectSingleNode = + Element.prototype.selectSingleNode = function(sExpr) { + return this.ownerDocument.selectSingleNode(sExpr, this); + }; + + + + var serializer = new XMLSerializer(); + var o = document.createElement("div"); + apf.insertHtmlNodes = function(nodeList, htmlNode, beforeNode, s) { + var frag, l, node, i; + if (nodeList) { + frag = document.createDocumentFragment(); + for (i = nodeList.length - 1; i >= 0; i--) { + node = nodeList[i]; + frag.insertBefore(node, frag.firstChild); + } + } + + o.innerHTML = typeof s == "string" ? s : apf.html_entity_decode(serializer.serializeToString(frag)) + .replace(/<([^>]+)\/>/g, "<$1>"); + + frag = document.createDocumentFragment(); + for (i = 0, l = o.childNodes.length; i < l; i++) { + node = o.childNodes[0]; + frag.appendChild(node); + } + + if (beforeNode) + htmlNode.insertBefore(frag, beforeNode); + htmlNode.appendChild(frag); + }; + + apf.insertHtmlNode = function(xmlNode, htmlNode, beforeNode, s) { + if (htmlNode.nodeType != 11 && !htmlNode.style) + return htmlNode.appendChild(xmlNode); + + if (!s) { + s = apf.html_entity_decode(xmlNode.serialize + ? xmlNode.serialize(true) + : ((xmlNode.nodeType == 3 || xmlNode.nodeType == 4 || xmlNode.nodeType == 2) + ? xmlNode.nodeValue + : serializer.serializeToString(xmlNode))); + } + + o.innerHTML = s.replace(/<([^>]+)\/>/g, "<$1>"); + + if (beforeNode) + htmlNode.insertBefore(o.firstChild, beforeNode); + else + htmlNode.appendChild(o.firstChild); + + return beforeNode ? beforeNode.previousSibling : htmlNode.lastChild; + }; + + /* ******** Error Compatibility ********************************************** + Error Object like IE + ****************************************************************************/ + function Error(nr, msg) { + + + this.message = msg; + this.nr = nr; + } + + apf.getHtmlLeft = function(oHtml) { + return (oHtml.offsetLeft + + (parseInt(apf.getStyle(oHtml.parentNode, "borderLeftWidth")) || 0)); + }; + + apf.getHtmlRight = function(oHtml) { + var p; + return (((p = oHtml.offsetParent).tagName == "BODY" + ? apf.getWindowWidth() + : p.offsetWidth) + - oHtml.offsetLeft - oHtml.offsetWidth + - (2 * (parseInt(apf.getStyle(p, "borderLeftWidth")) || 0)) + - (parseInt(apf.getStyle(p, "borderRightWidth")) || 0)); + }; + + apf.getHtmlTop = function(oHtml) { + return (oHtml.offsetTop + + (parseInt(apf.getStyle(oHtml.parentNode, "borderTopWidth")) || 0)); + }; + + apf.getHtmlBottom = function(oHtml) { + var p; + return (((p = oHtml.offsetParent).tagName == "BODY" + ? apf.getWindowHeight() + : p.offsetHeight) + - oHtml.offsetTop - oHtml.offsetHeight + - (2 * (parseInt(apf.getStyle(p, "borderTopWidth")) || 0)) + - (parseInt(apf.getStyle(p, "borderBottomWidth")) || 0)); + }; + + apf.getBorderOffset = function(oHtml) { + return [-1 * (parseInt(apf.getStyle(oHtml, "borderLeftWidth")) || 0), + -1 * (parseInt(apf.getStyle(oHtml, "borderTopWidth")) || 0)]; + }; +}; + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +/** + * Compatibility layer for Internet Explorer browsers. + * @private + */ +apf.runIE = function(){ + /* ******** XML Compatibility ************************************************ + Extensions to the xmldb + ****************************************************************************/ + var hasIE7Security = false, + hasIESecurity = false; + + + + + + apf.getHttpReq = hasIESecurity + ? function(){ + if (apf.availHTTP.length) + return apf.availHTTP.pop(); + + + + return new XMLHttpRequest(); + } + : function(){ + if (apf.availHTTP.length) + return apf.availHTTP.pop(); + + + + return new ActiveXObject("microsoft.XMLHTTP"); + }; + + apf.getXmlDom = hasIESecurity + ? function(message, noError) { + var xmlParser = getDOMParser(message, noError); + return xmlParser; + } + : function(message, noError, preserveWhiteSpaces) { + var xmlParser = new ActiveXObject("microsoft.XMLDOM"); + xmlParser.setProperty("SelectionLanguage", "XPath"); + if (preserveWhiteSpaces) + xmlParser.preserveWhiteSpace = true; + + if (message) { + if (apf.cantParseXmlDefinition) + message = message.replace(/\] \]/g, "] ]") + .replace(/^<\?[^>]*\?>/, "");//replace xml definition for IE5.0 + + xmlParser.loadXML(message); + + + if (!noError) + this.xmlParseError(xmlParser); + } + + return xmlParser; + }; + + apf.xmlParseError = function(xml) { + var xmlParseError = xml.parseError; + if (xmlParseError != 0) { + /* + http: //msdn.microsoft.com/library/en-us/xmlsdk30/htm/xmobjpmexmldomparseerror.asp?frame=true + + errorCode Contains the error code of the last parse error. Read-only. + filepos Contains the absolute file position where the error occurred. Read-only. + line Specifies the line number that contains the error. Read-only. + linepos Contains the character position within the line where the error occurred. Read-only. + reason Explains the reason for the error. Read-only. + srcText Returns the full text of the line containing the error. Read-only. + url Contains the URL of the XML document containing the last error. Read-only. + */ + throw new Error(apf.formatErrorString(1050, null, + "XML Parse error on line " + xmlParseError.line, + xmlParseError.reason + "Source Text:\n" + + xmlParseError.srcText.replace(/\t/gi, " ") + )); + } + + return xml; + }; + + /** + * This method retrieves the current value of a property on a HTML element + * @param {HTMLElement} el the element to read the property from + * @param {String} prop the property to read + * @returns {String} + */ + apf.getStyle = function(el, prop) { + return el.currentStyle[prop]; + }; + + apf.insertHtmlNodes = function(nodeList, htmlNode, beforeNode, s) { + var str; + if (nodeList) { + for (str = [], i = 0, l = nodeList.length; i < l; i++) + str[i] = nodeList[i].xml; + } + str = s || apf.html_entity_decode(str.join("")); + + if (apf.isIE < 7) + str = str.replace(/style="background-image:([^"]*)"/g, + "find='$1' style='background-image:$1'"); + + try { + (beforeNode || htmlNode).insertAdjacentHTML(beforeNode + ? "beforebegin" + : "beforeend", str); + } + catch (e) { + //IE table hack + document.body.insertAdjacentHTML("beforeend", "" + + str + "
      "); + + var x = document.body.lastChild.firstChild.firstChild; + for (i = x.childNodes.length - 1; i >= 0; i--) + htmlNode.appendChild(x.childNodes[apf.hasDynamicItemList ? 0 : i]); + } + + //Fix IE image loading bug + if (apf.isIE < 7) { + $setTimeout(function(){ + var nodes = htmlNode.getElementsByTagName("*"); + for (var s, i = 0, l = nodes.length; i < l; i++) { + if (s = nodes[i].getAttribute("find")) + nodes[i].style.backgroundImage = s.trim(); //@todo apf3.0 why is this needed? + } + }); + } + }; + + /* I have no idea what below code should do + + if (pNode.nodeType == 11) { + id = xmlNode.getAttribute("id"); + if (!id) + throw new Error(apf.formatErrorString(1049, null, "xmldb", "Inserting Cache Item in Document Fragment without an ID")); + + document.body.insertAdjacentHTML(beforeNode ? "beforebegin" : "beforeend", strHTML); + pNode.appendChild(document.getElementById(id)); + }*/ + apf.insertHtmlNode = function(xmlNode, htmlNode, beforeNode, str) { + if (htmlNode.nodeType != 11 && !htmlNode.style) + return htmlNode.appendChild(xmlNode); + + var pNode = beforeNode || htmlNode; + + if (!str) + str = apf.html_entity_decode(xmlNode.serialize + ? xmlNode.serialize(true) + : xmlNode.xml || xmlNode.outerHTML || xmlNode.nodeValue); + try { + pNode.insertAdjacentHTML(beforeNode + ? "beforeBegin" + : "beforeEnd", str); + } + catch (e) { + + + pNode.insertAdjacentHTML("afterEnd", str); + return pNode.nextSibling; + } + + if (beforeNode) + return beforeNode.previousSibling; + else + return htmlNode.lastChild.nodeType == 1 + ? htmlNode.lastChild + : htmlNode.lastChild.previousSibling; + + }; + + apf.getHtmlLeft = function(oHtml) { + return (oHtml.offsetLeft + - (apf.isIE > 7 && parseInt(oHtml.parentNode.currentStyle["borderLeftWidth"]) || 0)); + }; + + apf.getHtmlRight = function(oHtml) { + var p; + return (((p = oHtml.offsetParent).tagName == "BODY" + ? apf.getWindowWidth() + : p.offsetWidth) + - oHtml.offsetLeft - oHtml.offsetWidth + - (apf.isIE < 8 && parseInt(p.currentStyle["borderLeftWidth"]) || 0) + - (parseInt(p.currentStyle["borderRightWidth"]) || 0)); + }; + + apf.getHtmlTop = function(oHtml) { + return (oHtml.offsetTop + - (apf.isIE > 7 && parseInt(oHtml.offsetParent.currentStyle["borderTopWidth"]) || 0)); + }; + + apf.getHtmlBottom = function(oHtml) { + var p; + return (((p = oHtml.offsetParent).tagName == "BODY" + ? apf.getWindowHeight() + : p.offsetHeight) + - oHtml.offsetTop - oHtml.offsetHeight + - (apf.isIE < 8 && parseInt(p.currentStyle["borderTopWidth"]) || 0) + - (parseInt(p.currentStyle["borderBottomidth"]) || 0)); + }; + + apf.getBorderOffset = function(oHtml) { + return apf.isIE < 8 && [0,0] || [parseInt(oHtml.currentStyle["borderLeftWidth"]) || 0, + parseInt(oHtml.currentStyle["borderTopWidth"]) || 0] + }; + + apf.getOpacity = function(oHtml) { + return parseInt(((oHtml.currentStyle["filter"] || "").match(/alpha\(opacity=(\d*)\)/) || [0,0])[1]) / 100; + }; + + apf.setOpacity = function(oHtml, value) { + oHtml.style.filter = value == 1 + ? "" + : "alpha(opacity=" + Math.round(value * 100) + ")"; + }; + + + + + apf.importClass(apf.runXpath, true, self); + +}; + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +/** + * @private + */ +apf.runNonIe = function (){ + + + DocumentFragment.prototype.getElementById = function(id) { + return this.childNodes.length ? this.childNodes[0].ownerDocument.getElementById(id) : null; + }; + + + + // *** XML Serialization *** // + if (XMLDocument.prototype.__defineGetter__) { + //XMLDocument.xml + XMLDocument.prototype.__defineGetter__("xml", function(){ + return (new XMLSerializer()).serializeToString(this); + }); + XMLDocument.prototype.__defineSetter__("xml", function(){ + throw new Error(apf.formatErrorString(1042, null, "XML serializer", "Invalid assignment on read-only property 'xml'.")); + }); + + //Node.xml + Node.prototype.__defineGetter__("xml", function(){ + if (this.nodeType == 3 || this.nodeType == 4 || this.nodeType == 2) + return this.nodeValue; + return (new XMLSerializer()).serializeToString(this); + }); + + //Node.xml + Element.prototype.__defineGetter__("xml", function(){ + return (new XMLSerializer()).serializeToString(this); + }); + } + + /* ******** HTML Interfaces ************************************************** + insertAdjacentHTML(), insertAdjacentText() and insertAdjacentElement() + ****************************************************************************/ + if (typeof HTMLElement!="undefined") { + if (!HTMLElement.prototype.insertAdjacentElement) { + Text.prototype.insertAdjacentElement = + HTMLElement.prototype.insertAdjacentElement = function(where,parsedNode) { + switch (where.toLowerCase()) { + case "beforebegin": + this.parentNode.insertBefore(parsedNode,this); + break; + case "afterbegin": + this.insertBefore(parsedNode,this.firstChild); + break; + case "beforeend": + this.appendChild(parsedNode); + break; + case "afterend": + if (this.nextSibling) + this.parentNode.insertBefore(parsedNode,this.nextSibling); + else + this.parentNode.appendChild(parsedNode); + break; + } + }; + } + + if (!HTMLElement.prototype.insertAdjacentHTML) { + Text.prototype.insertAdjacentHTML = + HTMLElement.prototype.insertAdjacentHTML = function(where,htmlStr) { + var r = this.ownerDocument.createRange(); + r.setStartBefore(apf.isWebkit + ? document.body + : (self.document ? document.body : this)); + var parsedHTML = r.createContextualFragment(htmlStr); + this.insertAdjacentElement(where, parsedHTML); + }; + } + + if (!HTMLBodyElement.prototype.insertAdjacentHTML) //apf.isWebkit) + HTMLBodyElement.prototype.insertAdjacentHTML = HTMLElement.prototype.insertAdjacentHTML; + + if (!HTMLElement.prototype.insertAdjacentText) { + Text.prototype.insertAdjacentText = + HTMLElement.prototype.insertAdjacentText = function(where,txtStr) { + var parsedText = document.createTextNode(txtStr); + this.insertAdjacentElement(where,parsedText); + }; + } + + //HTMLElement.removeNode + HTMLElement.prototype.removeNode = function(){ + if (!this.parentNode) return; + + this.parentNode.removeChild(this); + }; + + //Currently only supported by Gecko + if (HTMLElement.prototype.__defineSetter__) { + //HTMLElement.innerText + HTMLElement.prototype.__defineSetter__("innerText", function(sText) { + var s = "" + sText; + this.innerHTML = s.replace(/\&/g, "&") + .replace(//g, ">"); + }); + + HTMLElement.prototype.__defineGetter__("innerText", function(){ + return this.innerHTML.replace(/<[^>]+>/g,"") + .replace(/\s\s+/g, " ").replace(/^\s+|\s+$/g, " "); + }); + + HTMLElement.prototype.__defineGetter__("outerHTML", function(){ + return (new XMLSerializer()).serializeToString(this); + }); + } + } + + /* ******** XML Compatibility ************************************************ + Giving the Mozilla XML Parser the same interface as IE's Parser + ****************************************************************************/ + var ASYNCNOTSUPPORTED = false; + + //Test if Async is supported + try { + XMLDocument.prototype.async = true; + ASYNCNOTSUPPORTED = true; + } catch (e) {/*trap*/} + + Document.prototype.onreadystatechange = null; + Document.prototype.parseError = 0; + + Array.prototype.item = function(i){return this[i];}; + Array.prototype.expr = ""; + + /*try{ + XMLDocument.prototype.readyState = 0; + }catch(e){}*/ + + XMLDocument.prototype.$clearDOM = function(){ + while (this.hasChildNodes()) + this.removeChild(this.firstChild); + }; + + XMLDocument.prototype.$copyDOM = function(oDoc) { + this.$clearDOM(); + + if (oDoc.nodeType == 9 || oDoc.nodeType == 11) { + var oNodes = oDoc.childNodes; + + for (var i = 0; i < oNodes.length; i++) + this.appendChild(this.importNode(oNodes[i], true)); + } + else if (oDoc.nodeType == 1) + this.appendChild(this.importNode(oDoc, true)); + }; + + //XMLDocument.loadXML(); + XMLDocument.prototype.loadXML = function(strXML) { + apf.xmldb.setReadyState(this, 1); + var sOldXML = this.xml || this.serialize(); + var oDoc = (new DOMParser()).parseFromString(strXML, "text/xml"); + apf.xmldb.setReadyState(this, 2); + this.$copyDOM(oDoc); + apf.xmldb.setReadyState(this, 3); + apf.xmldb.loadHandler(this); + return sOldXML; + }; + + Node.prototype.getElementById = function(id) {}; + + HTMLElement.prototype.replaceNode = + Element.prototype.replaceNode = function(xmlNode) { + if (!this.parentNode) return; + + this.parentNode.insertBefore(xmlNode, this); + this.parentNode.removeChild(this); + }; + + //XMLDocument.load + XMLDocument.prototype.$load = XMLDocument.prototype.load; + XMLDocument.prototype.load = function(sURI) { + var oDoc = document.implementation.createDocument("", "", null); + oDoc.$copyDOM(this); + this.parseError = 0; + apf.xmldb.setReadyState(this, 1); + + try { + if (this.async == false && ASYNCNOTSUPPORTED) { + var tmp = new XMLHttpRequest(); + tmp.open("GET", sURI, false); + tmp.overrideMimeType("text/xml"); + tmp.send(null); + apf.xmldb.setReadyState(this, 2); + this.$copyDOM(tmp.responseXML); + apf.xmldb.setReadyState(this, 3); + } else + this.$load(sURI); + } + catch (objException) { + this.parseError = -1; + } + finally { + apf.xmldb.loadHandler(this); + } + + return oDoc; + }; + + + + + + /** + * This method retrieves the current value of a property on a HTML element + * @param {HTMLElement} el the element to read the property from + * @param {String} prop the property to read + * @returns {String} + */ + var getStyle = apf.getStyle = function(el, prop) { + try{ + return (window.getComputedStyle(el, "") || {})[prop] || ""; + }catch(e) {} + }; + + //XMLDocument.setProperty + HTMLDocument.prototype.setProperty = + XMLDocument.prototype.setProperty = function(x,y) {}; + + /* ******** XML Compatibility ************************************************ + Extensions to the xmldb + ****************************************************************************/ + apf.getHttpReq = function(){ + if (apf.availHTTP.length) + return apf.availHTTP.pop(); + return new XMLHttpRequest(); + }; + + apf.getXmlDom = function(message, noError, preserveWhiteSpaces) { + var xmlParser; + if (message) { + if (preserveWhiteSpaces === false) + message = message.replace(/>[\s\n\r]*<"); + + xmlParser = new DOMParser(); + xmlParser = xmlParser.parseFromString(message, "text/xml"); + + + if (!noError) + this.xmlParseError(xmlParser); + } + else { + xmlParser = document.implementation.createDocument("", "", null); + } + + return xmlParser; + }; + + apf.xmlParseError = function(xml) { + //if (xml.documentElement.tagName == "parsererror") { + if (xml.getElementsByTagName("parsererror").length) { + var nodeValue = xml.documentElement.firstChild.nodeValue; + + if (nodeValue != null) { + var str = nodeValue.split("\n"), + linenr = str[2].match(/\w+ (\d+)/)[1], + message = str[0].replace(/\w+ \w+ \w+: (.*)/, "$1"); + } else { + if (nodeValue = xml.documentElement.firstChild.getElementsByTagName('div')[0].firstChild.nodeValue) { + var linenr = nodeValue.match(/line\s(\d*)/)[1] || "N/A", + message = nodeValue.match(/column\s\d*:(.*)/)[1] || "N/A"; + } + else { + var linenr = "N/A", + message = "N/A"; + } + } + + var srcText = xml.documentElement.lastChild.firstChild,//.split("\n")[0]; + srcMsg = ""; + if (srcText && srcText.nodeValue) { + srcMsg = "\nSource Text : " + srcText.nodeValue.replace(/\t/gi, " ") + } + throw new Error(apf.formatErrorString(1050, null, + "XML Parse Error on line " + linenr, message + srcMsg)); + } + + return xml; + }; + + + apf.xmldb.setReadyState = function(oDoc, iReadyState) { + oDoc.readyState = iReadyState; + if (oDoc.onreadystatechange != null && typeof oDoc.onreadystatechange == "function") + oDoc.onreadystatechange(); + }; + + apf.xmldb.loadHandler = function(oDoc) { + if (!oDoc.documentElement || oDoc.documentElement.tagName == "parsererror") + oDoc.parseError = -1; + + apf.xmldb.setReadyState(oDoc, 4); + }; + + // + //Fix XML Data-Island Support Problem with Form Tag + apf.Init.add(function(){ + var i, nodes = document.getElementsByTagName("form"); + for (i = 0; i < nodes.length; i++) + nodes[i].removeNode(); + nodes = document.getElementsByTagName("xml"); + for (i = 0; i < nodes.length; i++) + nodes[i].removeNode(); + nodes = null; + }); + + /*window.onerror = function(message, filename, linenr) { + if (++ERROR_COUNT > MAXMSG) return; + filename = filename ? filename.match(/\/([^\/]*)$/)[1] : "[Mozilla Library]"; + new Error("---- APF Error ----\nProcess : Javascript code in '" + filename + "'\nLine : " + linenr + "\nMessage : " + message); + return false; + }*/ + + if (document.body) + document.body.focus = function(){}; + + + + apf.getOpacity = function(oHtml) { + return apf.getStyle(oHtml, "opacity"); + }; + + apf.setOpacity = function(oHtml, value) { + oHtml.style.opacity = value; + }; +}; + + + + + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +/** + * Compatibility layer for Webkit based browsers. + * @private + */ +apf.runWebkit = function(){ + + + + if (XMLHttpRequest.prototype.sendAsBinary === undefined) { + if (window.ArrayBuffer) { + /** + * Binary support for Chrome 7+ which implements [ECMA-262] typed arrays + * + * For more information, see . + */ + XMLHttpRequest.prototype.sendAsBinary = function(string) { + var bytes = Array.prototype.map.call(string, function(c) { + return c.charCodeAt(0) & 0xff; + }); + this.send(new Uint8Array(bytes).buffer); + }; + } + } + + + + + + + HTMLDocument.prototype.selectNodes = XMLDocument.prototype.selectNodes = function(sExpr, contextNode) { + if (sExpr.substr(0,2) == "//") + sExpr = "." + sExpr; + + try { + var oResult = this.evaluate(sExpr, (contextNode || this), + this.createNSResolver(this.documentElement), + 7, null);//XPathResult.ORDERED_NODE_SNAPSHOT_TYPE + } + catch (ex) { + try { + var oResult = this.evaluate("child::" + sExpr, (contextNode || this), + this.createNSResolver(this.documentElement), + 7, null);//XPathResult.ORDERED_NODE_SNAPSHOT_TYPE + } + catch (ex) { + throw new Error("XPath error: " + ex.message + "\nLine: " + ex.lineNumber + "\nExpression: '" + sExpr + "'"); + } + } + + var nodeList = new Array(oResult.snapshotLength); + nodeList.expr = sExpr; + for (var i = nodeList.length - 1; i >= 0; i--) + nodeList[i] = oResult.snapshotItem(i); + return nodeList; + }; + + //Element.selectNodes + Text.prototype.selectNodes = + Attr.prototype.selectNodes = + Element.prototype.selectNodes = function(sExpr) { + return this.ownerDocument.selectNodes(sExpr, this); + }; + + //XMLDocument.selectSingleNode + HTMLDocument.prototype.selectSingleNode = XMLDocument.prototype.selectSingleNode = function(sExpr, contextNode) { + var nodeList = this.selectNodes("(" + sExpr + ")[1]", contextNode ? contextNode : null); + return nodeList.length > 0 ? nodeList[0] : null; + }; + + //Element.selectSingleNode + Text.prototype.selectSingleNode = + Attr.prototype.selectSingleNode = + Element.prototype.selectSingleNode = function(sExpr) { + return this.ownerDocument.selectSingleNode(sExpr, this); + }; + + + + var serializer = new XMLSerializer(); + apf.insertHtmlNodes = function(nodeList, htmlNode, beforeNode, s) { + var node, frag, a, i, l; + if (nodeList) { + frag = document.createDocumentFragment(); + a = [], i = 0, l = nodeList.length; + for (; i < l; i++) { + if (!(node = nodeList[i])) continue; + frag.appendChild(node); + } + } + + (beforeNode || htmlNode).insertAdjacentHTML(beforeNode + ? "beforebegin" + : "beforeend", s || apf.html_entity_decode(serializer.serializeToString(frag)) + .replace(/<([^>]+)\/>/g, "<$1>")); + }; + + apf.insertHtmlNode = function(xmlNode, htmlNode, beforeNode, s) { + if (htmlNode.nodeType != 11 && !htmlNode.style) + return htmlNode.appendChild(xmlNode); + + if (!s) { + s = apf.html_entity_decode(xmlNode.serialize + ? xmlNode.serialize(true) + : ((xmlNode.nodeType == 3 || xmlNode.nodeType == 4 || xmlNode.nodeType == 2) + ? xmlNode.nodeValue + : serializer.serializeToString(xmlNode))); + } + + (beforeNode || htmlNode).insertAdjacentHTML(beforeNode + ? "beforebegin" + : "beforeend", s.match(/<(IMG|LINK|META|BR|HR|BASEFONT)[^\/>]*/i) ? s.replace(/<([^>]+)\/>/g, "<$1 />") : s.replace(/<([^>]+)\/>/g, "<$1>")); + + return beforeNode ? beforeNode.previousSibling : htmlNode.lastChild; + }; + + apf.getHtmlLeft = function(oHtml) { + return oHtml.offsetLeft; + }; + + apf.getHtmlRight = function(oHtml) { + var p; + return (((p = oHtml.offsetParent).tagName == "BODY" + ? apf.getWindowWidth() + : p.offsetWidth) + - oHtml.offsetLeft - oHtml.offsetWidth + - (parseInt(apf.getStyle(p, "borderLeftWidth")) || 0) + - (parseInt(apf.getStyle(p, "borderRightWidth")) || 0)); + }; + + apf.getHtmlTop = function(oHtml) { + return oHtml.offsetTop + }; + + apf.getHtmlBottom = function(oHtml) { + var p; + return (((p = oHtml.offsetParent).tagName == "BODY" + ? apf.getWindowHeight() + : p.offsetHeight) + - oHtml.offsetTop - oHtml.offsetHeight + - (parseInt(apf.getStyle(p, "borderTopWidth")) || 0) + - (parseInt(apf.getStyle(p, "borderBottomWidth")) || 0)); + }; + + apf.getBorderOffset = function(oHtml) { + return [0,0]; + }; + + if (apf.runNonIe) + apf.runNonIe(); +}; + + + + + + + + + + +/* + * Crypt.Barrett, a class for performing Barrett modular reduction computations in + * JavaScript. + * + * Requires BigInt.js. + * + * Copyright 2004-2005 David Shapiro. + * + * You may use, re-use, abuse, copy, and modify this code to your liking, but + * please keep this header. + * + * Thanks! + * + * @author Dave Shapiro + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +apf.crypto.Base64 = (function() { + + var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + + // public method for encoding + function encode(data) { + var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, ac = 0, enc = "", + tmp_arr = []; + + if (!data) + return data; + + data = apf.crypto.UTF8.encode(data + ""); + + do { // pack three octets into four hexets + o1 = data.charCodeAt(i++); + o2 = data.charCodeAt(i++); + o3 = data.charCodeAt(i++); + + bits = o1 << 16 | o2 << 8 | o3; + + h1 = bits >> 18 & 0x3f; + h2 = bits >> 12 & 0x3f; + h3 = bits >> 6 & 0x3f; + h4 = bits & 0x3f; + + // use hexets to index into b64, and append result to encoded string + tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + + b64.charAt(h4); + } + while (i < data.length); + + enc = tmp_arr.join(""); + + switch (data.length % 3) { + case 1: + enc = enc.slice(0, -2) + '=='; + break; + case 2: + enc = enc.slice(0, -1) + '='; + break; + } + + return enc; + } + + // public method for decoding + function decode(data) { + var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, ac = 0, tmp_arr = []; + + if (!data) { + return data; + } + + data += ""; + + do { // unpack four hexets into three octets using index points in b64 + h1 = b64.indexOf(data.charAt(i++)); + h2 = b64.indexOf(data.charAt(i++)); + h3 = b64.indexOf(data.charAt(i++)); + h4 = b64.indexOf(data.charAt(i++)); + + bits = h1 << 18 | h2 << 12 | h3 << 6 | h4; + + o1 = bits>>16 & 0xff; + o2 = bits>>8 & 0xff; + o3 = bits & 0xff; + + if (h3 == 64) + tmp_arr[ac++] = String.fromCharCode(o1); + else if (h4 == 64) + tmp_arr[ac++] = String.fromCharCode(o1, o2); + else + tmp_arr[ac++] = String.fromCharCode(o1, o2, o3); + } + while (i < data.length); + + return apf.crypto.UTF8.decode(tmp_arr.join("")); + } + + return { + decode: decode, + encode: encode + }; + +})(); + +apf.crypto.UTF8 = { + // private method for UTF-8 encoding + encode: function (string) { + // Encodes an ISO-8859-1 string to UTF-8 + // + // version: 905.1217 + // discuss at: http://phpjs.org/functions/utf8_encode + // + original by: Webtoolkit.info (http://www.webtoolkit.info/) + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + improved by: sowberry + // + tweaked by: Jack + // + bugfixed by: Onno Marsman + // + improved by: Yves Sucaet + // + bugfixed by: Onno Marsman + // * example 1: utf8_encode('Kevin van Zonneveld'); + // * returns 1: 'Kevin van Zonneveld' + string = (string + "").replace(/\r\n/g, "\n").replace(/\r/g, "\n"); + + var tmp_arr = [], + start = 0, + end = 0, + c1, enc; + + for (var n = 0, l = string.length; n < l; n++) { + c1 = string.charCodeAt(n); + enc = null; + + if (c1 < 128) { + end++; + } + else if ((c1 > 127) && (c1 < 2048)) { + enc = String.fromCharCode((c1 >> 6) | 192) + + String.fromCharCode((c1 & 63) | 128); + } + else { + enc = String.fromCharCode((c1 >> 12) | 224) + + String.fromCharCode(((c1 >> 6) & 63) | 128) + + String.fromCharCode((c1 & 63) | 128); + } + if (enc !== null) { + if (end > start) + tmp_arr.push(string.substring(start, end)); + tmp_arr.push(enc); + start = end = n + 1; + } + } + + if (end > start) + tmp_arr.push(string.substring(start, string.length)); + + return tmp_arr.join(""); + }, + + // private method for UTF-8 decoding + decode: function (str_data) { + // Converts a UTF-8 encoded string to ISO-8859-1 + // + // version: 905.3122 + // discuss at: http://phpjs.org/functions/utf8_decode + // + original by: Webtoolkit.info (http://www.webtoolkit.info/) + // + input by: Aman Gupta + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + improved by: Norman "zEh" Fuchs + // + bugfixed by: hitwork + // + bugfixed by: Onno Marsman + // + input by: Brett Zamir (http://brett-zamir.me) + // + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // * example 1: utf8_decode('Kevin van Zonneveld'); + // * returns 1: 'Kevin van Zonneveld' + var tmp_arr = [], i = 0, ac = 0, c1 = 0, c2 = 0, c3 = 0; + + str_data += ""; + + while (i < str_data.length) { + c1 = str_data.charCodeAt(i); + if (c1 < 128) { + tmp_arr[ac++] = String.fromCharCode(c1); + i++; + } + else if ((c1 > 191) && (c1 < 224)) { + c2 = str_data.charCodeAt(i+1); + tmp_arr[ac++] = String.fromCharCode(((c1 & 31) << 6) | (c2 & 63)); + i += 2; + } + else { + c2 = str_data.charCodeAt(i+1); + c3 = str_data.charCodeAt(i+2); + tmp_arr[ac++] = String.fromCharCode(((c1 & 15) << 12) + | ((c2 & 63) << 6) | (c3 & 63)); + i += 3; + } + } + + return tmp_arr.join(''); + } + +}; + + + + + + +/* + * BigInt, a suite of routines for performing multiple-precision arithmetic in + * JavaScript. + * + * Copyright 1998-2005 David Shapiro. + * + * You may use, re-use, abuse, + * copy, and modify this code to your liking, but please keep this header. + * Thanks! + * + * @author Dave Shapiro + * @author Ian Bunning + * + * IMPORTANT THING: Be sure to set maxDigits according to your precision + * needs. Use the setMaxDigits() function to do this. See comments below. + * + * Tweaked by Ian Bunning + * Alterations: + * Fix bug in function biFromHex(s) to allow + * parsing of strings of length != 0 (mod 4) + * + * Changes made by Dave Shapiro as of 12/30/2004: + * + * The BigInt() constructor doesn't take a string anymore. If you want to + * create a BigInt from a string, use biFromDecimal() for base-10 + * representations, biFromHex() for base-16 representations, or + * biFromString() for base-2-to-36 representations. + * + * biFromArray() has been removed. Use biCopy() instead, passing a BigInt + * instead of an array. + * + * The BigInt() constructor now only constructs a zeroed-out array. + * Alternatively, if you pass , it won't construct any array. See the + * biCopy() method for an example of this. + * + * Be sure to set maxDigits depending on your precision needs. The default + * zeroed-out array ZERO_ARRAY is constructed inside the setMaxDigits() + * function. So use this function to set the variable. DON'T JUST SET THE + * VALUE. USE THE FUNCTION. + * + * ZERO_ARRAY exists to hopefully speed up construction of BigInts(). By + * precalculating the zero array, we can just use slice(0) to make copies of + * it. Presumably this calls faster native code, as opposed to setting the + * elements one at a time. I have not done any timing tests to verify this + * claim. + * Max number = 10^16 - 2 = 9999999999999998; + * 2^53 = 9007199254740992; + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +apf.crypto.MD5 = { + /* + * Configurable variables. You may need to tweak these to be compatible with + * the server-side, but the defaults work in most cases. + */ + hexcase: 0, /* hex output format. 0 - lowercase; 1 - uppercase */ + b64pad : "", /* base-64 pad character. "=" for strict RFC compliance */ + chrsz: 8, /* bits per input character. 8 - ASCII; 16 - Unicode */ + + /** + * These are the functions you'll usually want to call + * They take string arguments and return either hex or base-64 encoded strings + * + * Example: + * var hash = apf.crypto.MD5.hex_md5("uzza"); //fddb7463a72e6b000abf631f558cf034 + */ + + hex_md5: function(s) { + return this.binl2hex(this.core_md5(this.str2binl(s), s.length * this.chrsz)); + }, + b64_md5: function(s) { + return this.binl2b64(this.core_md5(this.str2binl(s), s.length * this.chrsz)); + }, + str_md5: function(s) { + return this.binl2str(this.core_md5(this.str2binl(s), s.length * this.chrsz)); + }, + hex_hmac_md5: function(key, data) { + return this.binl2hex(this.core_hmac_md5(key, data)); + }, + b64_hmac_md5: function(key, data) { + return this.binl2b64(this.core_hmac_md5(key, data)); + }, + str_hmac_md5: function(key, data) { + return this.binl2str(this.core_hmac_md5(key, data)); + }, + /** + * Calculate the MD5 of an array of little-endian words, and a bit length + */ + core_md5: function(x, len) { + /* append padding */ + x[len >> 5] |= 0x80 << ((len) % 32); + x[(((len + 64) >>> 9) << 4) + 14] = len; + + var a = 1732584193, b = -271733879, c = -1732584194, d = 271733878; + + for (var i = 0; i < x.length; i += 16) { + var olda = a, oldb = b, oldc = c, oldd = d; + + a = this.md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936); + d = this.md5_ff(d, a, b, c, x[i+ 1], 12, -389564586); + c = this.md5_ff(c, d, a, b, x[i+ 2], 17, 606105819); + b = this.md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330); + a = this.md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897); + d = this.md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426); + c = this.md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341); + b = this.md5_ff(b, c, d, a, x[i+ 7], 22, -45705983); + a = this.md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416); + d = this.md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417); + c = this.md5_ff(c, d, a, b, x[i+10], 17, -42063); + b = this.md5_ff(b, c, d, a, x[i+11], 22, -1990404162); + a = this.md5_ff(a, b, c, d, x[i+12], 7 , 1804603682); + d = this.md5_ff(d, a, b, c, x[i+13], 12, -40341101); + c = this.md5_ff(c, d, a, b, x[i+14], 17, -1502002290); + b = this.md5_ff(b, c, d, a, x[i+15], 22, 1236535329); + + a = this.md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510); + d = this.md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632); + c = this.md5_gg(c, d, a, b, x[i+11], 14, 643717713); + b = this.md5_gg(b, c, d, a, x[i+ 0], 20, -373897302); + a = this.md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691); + d = this.md5_gg(d, a, b, c, x[i+10], 9 , 38016083); + c = this.md5_gg(c, d, a, b, x[i+15], 14, -660478335); + b = this.md5_gg(b, c, d, a, x[i+ 4], 20, -405537848); + a = this.md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438); + d = this.md5_gg(d, a, b, c, x[i+14], 9 , -1019803690); + c = this.md5_gg(c, d, a, b, x[i+ 3], 14, -187363961); + b = this.md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501); + a = this.md5_gg(a, b, c, d, x[i+13], 5 , -1444681467); + d = this.md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784); + c = this.md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473); + b = this.md5_gg(b, c, d, a, x[i+12], 20, -1926607734); + + a = this.md5_hh(a, b, c, d, x[i+ 5], 4 , -378558); + d = this.md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463); + c = this.md5_hh(c, d, a, b, x[i+11], 16, 1839030562); + b = this.md5_hh(b, c, d, a, x[i+14], 23, -35309556); + a = this.md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060); + d = this.md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353); + c = this.md5_hh(c, d, a, b, x[i+ 7], 16, -155497632); + b = this.md5_hh(b, c, d, a, x[i+10], 23, -1094730640); + a = this.md5_hh(a, b, c, d, x[i+13], 4 , 681279174); + d = this.md5_hh(d, a, b, c, x[i+ 0], 11, -358537222); + c = this.md5_hh(c, d, a, b, x[i+ 3], 16, -722521979); + b = this.md5_hh(b, c, d, a, x[i+ 6], 23, 76029189); + a = this.md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487); + d = this.md5_hh(d, a, b, c, x[i+12], 11, -421815835); + c = this.md5_hh(c, d, a, b, x[i+15], 16, 530742520); + b = this.md5_hh(b, c, d, a, x[i+ 2], 23, -995338651); + + a = this.md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844); + d = this.md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415); + c = this.md5_ii(c, d, a, b, x[i+14], 15, -1416354905); + b = this.md5_ii(b, c, d, a, x[i+ 5], 21, -57434055); + a = this.md5_ii(a, b, c, d, x[i+12], 6 , 1700485571); + d = this.md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606); + c = this.md5_ii(c, d, a, b, x[i+10], 15, -1051523); + b = this.md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799); + a = this.md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359); + d = this.md5_ii(d, a, b, c, x[i+15], 10, -30611744); + c = this.md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380); + b = this.md5_ii(b, c, d, a, x[i+13], 21, 1309151649); + a = this.md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070); + d = this.md5_ii(d, a, b, c, x[i+11], 10, -1120210379); + c = this.md5_ii(c, d, a, b, x[i+ 2], 15, 718787259); + b = this.md5_ii(b, c, d, a, x[i+ 9], 21, -343485551); + + a = this.safe_add(a, olda); + b = this.safe_add(b, oldb); + c = this.safe_add(c, oldc); + d = this.safe_add(d, oldd); + } + return [a, b, c, d]; + }, + /* + * These functions implement the four basic operations the algorithm uses. + */ + md5_cmn: function(q, a, b, x, s, t) { + return this.safe_add(this.bit_rol(this.safe_add(this.safe_add(a, q), + this.safe_add(x, t)), s),b); + }, + md5_ff: function(a, b, c, d, x, s, t) { + return this.md5_cmn((b & c) | ((~b) & d), a, b, x, s, t); + }, + md5_gg: function(a, b, c, d, x, s, t) { + return this.md5_cmn((b & d) | (c & (~d)), a, b, x, s, t); + }, + md5_hh: function(a, b, c, d, x, s, t) { + return this.md5_cmn(b ^ c ^ d, a, b, x, s, t); + }, + md5_ii: function(a, b, c, d, x, s, t) { + return this.md5_cmn(c ^ (b | (~d)), a, b, x, s, t); + }, + /** + * Calculate the HMAC-MD5, of a key and some data + */ + core_hmac_md5: function(key, data) { + var bkey = this.str2binl(key), + ipad = Array(16), + opad = Array(16); + if (bkey.length > 16) + bkey = this.core_md5(bkey, key.length * this.chrsz); + + for (var i = 0; i < 16; i++) { + ipad[i] = bkey[i] ^ 0x36363636; + opad[i] = bkey[i] ^ 0x5C5C5C5C; + } + + return this.core_md5(opad.concat( + this.core_md5(ipad.concat(this.str2binl(data)), 512 + data.length * this.chrsz) + ), 512 + 128); + }, + /** + * Add integers, wrapping at 2^32. This uses 16-bit operations internally + * to work around bugs in some JS interpreters. + */ + safe_add: function(x, y) { + var lsw = (x & 0xFFFF) + (y & 0xFFFF), + msw = (x >> 16) + (y >> 16) + (lsw >> 16); + return (msw << 16) | (lsw & 0xFFFF); + }, + /** + * Bitwise rotate a 32-bit number to the left. + */ + bit_rol: function(num, cnt) { + return (num << cnt) | (num >>> (32 - cnt)); + }, + /** + * Convert a string to an array of little-endian words + * If chrsz is ASCII, characters >255 have their hi-byte silently ignored. + */ + str2binl: function(str) { + var bin = [], i, + mask = (1 << this.chrsz) - 1; + for (i = 0; i < str.length * this.chrsz; i += this.chrsz) + bin[i >> 5] |= (str.charCodeAt(i / this.chrsz) & mask) << (i%32); + return bin; + }, + /** + * Convert an array of little-endian words to a string + */ + binl2str: function(bin) { + var str = [], i, + mask = (1 << this.chrsz) - 1; + for (i = 0; i < bin.length * 32; i += this.chrsz) + str.push(String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask)); + return str.join(""); + }, + /** + * Convert an array of little-endian words to a hex string. + */ + binl2hex: function(binarray) { + var hex_tab = this.hexcase ? "0123456789ABCDEF" : "0123456789abcdef", + str = [], i; + for (i = 0; i < binarray.length * 4; i++) { + str.push(hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) + + hex_tab.charAt((binarray[i>>2] >> ((i%4)*8 )) & 0xF)); + } + return str.join(""); + }, + /** + * Convert an array of little-endian words to a base-64 string + */ + binl2b64: function(binarray) { + var pane = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", + str = [], i; + for (i = 0; i < binarray.length * 4; i += 3) { + var triplet = (((binarray[i >> 2] >> 8 * ( i %4)) & 0xFF) << 16) + | (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 ) + | ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF); + for (var j = 0; j < 4; j++) { + if (i * 8 + j * 6 > binarray.length * 32) + str.push(this.b64pad); + else + str.push(pane.charAt((triplet >> 6*(3-j)) & 0x3F)); + } + } + return str.join(""); + } +}; + + + + + + +/* + * RSA, a suite of routines for performing RSA public-key computations in + * JavaScript. + * + * Requires BigInt.js and Barrett.js. + * + * Copyright 1998-2005 David Shapiro. + * + * You may use, re-use, abuse, copy, and modify this code to your liking, but + * please keep this header. + * + * Thanks! + * + * @author Dave Shapiro + */ + + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +(function(global) { + +function rotate_left(n,s) { + var t4 = ( n<>>(32-s)); + return t4; +}; + +/* +function lsb_hex(val) { // Not in use; needed? + var str=""; + var i; + var vh; + var vl; + + for ( i=0; i<=6; i+=2 ) { + vh = (val>>>(i*4+4))&0x0f; + vl = (val>>>(i*4))&0x0f; + str += vh.toString(16) + vl.toString(16); + } + return str; +}; +*/ + +function cvt_hex(val) { + var str=""; + var i; + var v; + + for ( i=7; i>=0; i-- ) { + v = (val>>>(i*4))&0x0f; + str += v.toString(16); + } + return str; +}; + +global.SHA1 = function(str) { + // Calculate the sha1 hash of a string + // + // version: 905.3122 + // discuss at: http://phpjs.org/functions/sha1 + // + original by: Webtoolkit.info (http://www.webtoolkit.info/) + // + namespaced by: Michael White (http://getsprink.com) + // + input by: Brett Zamir (http://brett-zamir.me) + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // - depends on: utf8_encode + // * example 1: sha1('Kevin van Zonneveld'); + // * returns 1: '54916d2e62f65b3afa6e192e6a601cdbe5cb5897' + var blockstart, i, j, W = new Array(80), + H0 = 0x67452301, + H1 = 0xEFCDAB89, + H2 = 0x98BADCFE, + H3 = 0x10325476, + H4 = 0xC3D2E1F0, + A, B, C, D, E, temp; + + str = apf.crypto.UTF8.encode(str); + var str_len = str.length, + word_array = []; + + for (i = 0; i < str_len - 3; i += 4) { + j = str.charCodeAt(i) << 24 | str.charCodeAt(i + 1) << 16 | + str.charCodeAt(i + 2) << 8 | str.charCodeAt(i + 3); + word_array.push(j); + } + + switch (str_len % 4) { + case 0: + i = 0x080000000; + break; + case 1: + i = str.charCodeAt(str_len - 1) << 24 | 0x0800000; + break; + case 2: + i = str.charCodeAt(str_len - 2) << 24 | str.charCodeAt(str_len - 1) + << 16 | 0x08000; + break; + case 3: + i = str.charCodeAt(str_len - 3) << 24 | str.charCodeAt(str_len - 2) + << 16 | str.charCodeAt(str_len - 1) << 8 | 0x80; + break; + } + + word_array.push( i ); + + while ((word_array.length % 16) != 14) + word_array.push( 0 ); + + word_array.push(str_len >>> 29); + word_array.push((str_len << 3) & 0x0ffffffff); + + for (blockstart = 0; blockstart < word_array.length; blockstart += 16) { + for (i = 0; i < 16; i++) + W[i] = word_array[blockstart + i]; + for (i = 16; i <= 79; i++) + W[i] = rotate_left(W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16], 1); + + A = H0; + B = H1; + C = H2; + D = H3; + E = H4; + + for (i = 0; i <= 19; i++) { + temp = (rotate_left(A, 5) + ((B & C) | (~B & D)) + E + W[i] + + 0x5A827999) & 0x0ffffffff; + E = D; + D = C; + C = rotate_left(B, 30); + B = A; + A = temp; + } + + for (i = 20; i <= 39; i++) { + temp = (rotate_left(A, 5) + (B ^ C ^ D) + E + W[i] + 0x6ED9EBA1) + & 0x0ffffffff; + E = D; + D = C; + C = rotate_left(B, 30); + B = A; + A = temp; + } + + for (i = 40; i <= 59; i++) { + temp = (rotate_left(A, 5) + ((B & C) | (B & D) | (C & D)) + E + W[i] + + 0x8F1BBCDC) & 0x0ffffffff; + E = D; + D = C; + C = rotate_left(B, 30); + B = A; + A = temp; + } + + for (i = 60; i <= 79; i++) { + temp = (rotate_left(A, 5) + (B ^ C ^ D) + E + W[i] + 0xCA62C1D6) + & 0x0ffffffff; + E = D; + D = C; + C = rotate_left(B, 30); + B = A; + A = temp; + } + + H0 = (H0 + A) & 0x0ffffffff; + H1 = (H1 + B) & 0x0ffffffff; + H2 = (H2 + C) & 0x0ffffffff; + H3 = (H3 + D) & 0x0ffffffff; + H4 = (H4 + E) & 0x0ffffffff; + } + + temp = cvt_hex(H0) + cvt_hex(H1) + cvt_hex(H2) + cvt_hex(H3) + cvt_hex(H4); + return temp.toLowerCase(); +}; + +})(apf.crypto); + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/** + * @constructor + * @parser + * + * @author Rik Arends + * @version %I%, %G% + * @since 3.0 + */ +apf.lm = new (function(){ + + var statement_lut = { // all js statements to see its NOT an expression + "var": 1, "for": 1, "while": 1, "do": 1, "if": 1, "else": 1, + "switch": 1, "case": 1, "break": 1, "continue": 1, "default": 1, + "function":2, "return": 1, "try": 1, "catch": 1, "throw":1, + "debugger": 1, "alert": 1, "confirm": 1,"setTimeout": 1,"setInterval": 1,"delete": 1, "export": 1, "import": 1, + "label": 1, "foreach":1, "each": 1, "eachrev":1, "foreachrev":1, "node": 1, "local": 1, "yield": 1, + "let":1, "finally":1, "delete":1 + }, + type_lut = { // used for optimizing the parse regexp + "\n": 1, "\r\n": 1, "==":2, "++":2, "--":2, '"': 5, "'": 5, + "": 6, "/*": 6, "//": 6, "*/": 6, "{": 7, "}": 8, + "[": 9, "]": 10, "(": 11, ")": 12, "<": 13, ">": 14, "+=":2, + "-=":2, "/=":2, "*=":2, "!=":2 + }, + type_close = { // handy + "{": "}", "[": "]", "(": ")", "{{":"}" + }, + xpath_axes = { // used to detect xpath axes or model + "ancestor": 1, "ancestor-or-self": 1, "attribute": 1, "child": 1, + "descendant": 1, "descendant-or-self": 1, "following": 1, + "following-sibling": 1, "namespace": 1, "parent": 1, "preceding": 1, + "self": 1 + }, + misc_tok = { // misc token lookup + ";":1, ",":2, "^":3, "=":4, "+=":4, "-=":4, "/=":4, "*=":4, "/":5, ":":6 + }, + xpath_lut_code = { // which autoxpath to use when doing macro({xpath}) + "~": "_val(_n,", "%": "_nod(_n,", "*": "_nods(_n,", "#": "_cnt(_n,", "$": "_lng(" + }, + xpath_lut_text = { // which autoxpath to use when doing xpath macros in textmode + "~": "_val(_n,", "%": "_xml(_n,", "*": "_xmls(_n,", "#": "_cnt(_n,", "$": "_lng(" + }, + xpath_lut_attr = { // xpath lut for node attributes + "~": "_val(_n,", "%": "_val(_n,", "*": "_val(_n,", "#": "_cnt(_n,", "$": "_lng(" + }, + xpath_lut_node, + xpath_lut_node_normal = { // normal xpath lookup + "~": "_val(_n,", "%": "_xml(_n,", "*": "_xmls(_n,", "#": "_cnt(_n,", "$": "_lng(" + }, + xpath_lut_node_langedit = { // language edit xpath lookup + "~": "_val(_n,", "%": "_xml(_n,", "*": "_xmls(_n,", "#": "_cnt(_n,", "$": "_lnged(" + }, + pre_regexp = { + "[":1, "(":1, ",":1, "=":1, "return":1, "throw":1 + }, + pre_xpath = { + "else":1, "return":1, "delete":1 + }, + pre_plain = { + "do":1, "else":1, "try":1 + }, + op_lut = { // obj.prop += operator lut + "=" : "_asn(", "+=": "_add(", "-=": "_sub(", "/=": "_div(", "*=": "_mul(" + }, + new_block = { + "+":1, "%":1, "-":1, "/":1, "=":1, "(":1, "?":1, "|":1, "^":1, "[":1, + "&":1, "*":1, "!":1, ":":1, "<":1, ",":1 + }, + out_context_word = { // token preceeding a word signalling a new output + "{":1, "} ":1, ")":1, ") ":1, ";":1, "\n":1, "else":1 + }, + out_context_paren = { // token preceeding a paren signalling a new output + "{":1, ";":1, "\n":1, "else":1 + }, // special markers: ') ' tail of xpath macro. ') ' func def, tok=') ' its not an if while etc. + markup_in_code_lut = { + "} ":1, ") ":1,// the } used when it wasnt a code-expression + "(":1, /*")":1,*/ ";":1, "&":1, "^":1, "|":1, ",":1, '"':1, "'":1, "=":1, + "!=":2,"+=":2, "-=":2, "/=":2, "*=":2, "?":1, "{":1, "}":1, ">":1, "[":1, + /*"]":1,*/ "+":1, ":":1, "else":1, "return":1 + }, + block_autoappend = { // token preceeding block signalling auto append + '"':1, "'":1, ">":1, "]":1, "}":1 + }, + unesc_lut = { // unescape in code and xpath mode + "\\\"": "\"", "\\\'": "\'", "\\{": "{", "\\}": "}", "\\[": "[", + "\\]": "]", "\\(":"(", "\\)":")", "\\\\":"\\" + }, + call_exclusion = { + "alert": 1, "confirm" :1, "setTimeout":1, "setInterval":1, "switch":1, + "call":1, "return":1, "throw":1, "case":1, "catch":1, + "abs":1,"acos":1,"asin":1,"atan":1,"atan2":1,"ceil":1, + "cos":1,"exp":1,"floor":1,"log":1,"max":1,"min":1, + "pow":1,"random":1,"round":1,"sin":1,"sqrt":1,"tan":1,"lin":1,"linear":1, + "idx":1,"sort":1,"typeof":1 + }, + is_out_space = { + " ":1, "\n":1 + }, + newline_notallowed = { + "{":1, ";":1, "(":1, "\n":1 + },//@todo !verify and document! character escaping system + unesc_str = { // unescape in string mode + "\\{": "{", "\\}": "}", "\\[": "[", "\\]": "]", "\\(": "(", "\\)": ")" + }, + unesc_txt = { // unescape in text mode + "\\{" : "{", "\\}" : "}", "\\[" : "[", "\\]" : "]", "\\(" : "(", + "\\)" : ")", "\\\\": "\\\\\\\\", "\\" :"\\\\", "\\<" : "<", "\\>" : ">" + }, + xml_code_operators = { // word to operand lookup table for easy use in xml + "lte": "<=", "gte": ">=", "lt": "<", "gt": ">", "and": "&&", "or": "||", + "andbin": "&", "orbin": "|", "LTE": "<=", "GTE": ">=", "LT": "<", + "GT": ">", "AND": "&&", "OR": "||", "ANDBIN": "&", "ORBIN": "|" + }, + xpath_macro = { // which autoxpath to use when doing macro({xpath}) + 0 : "_val(_n,", + 1 : "_valcr(_n,_cr,", + 2 : "_nod(_n,", + 3 : "_nodcr(_n,_cr,", + 4 : "_nods(_n,", + 5 : "_xpt(_n,", + 6 : "_valst(_n,", + 7 : "_valed(_n,", + 8 : "_valattr(_n,", + "foreach" : "_nods(_n,", + "each" : "_nods(_n,", + "foreachrev": "_nods(_n,", + "eachrev" : "_nods(_n,", + "xabs" : "_valst(_n,", + // "edit" : "_argwrap(_n,", + // "edit" : "_val(_n,", // toggled by liveedit + "local" : "_nod(_n,", + "tagName" : "_nod(_n,", + "localName" : "_nod(_n,", + "xml" : "_xmlq(", + "_call" : "_val(_n," + }, + xpath_model = { // which autoxpath to use when doing macro({xpath}) + "_val(_n," : "_valm(", + "_valcr(_n,_cr,": "_valcr(0,_cr,", + "_nod(_n," : "_nodm(", + "_nodcr(_n,_cr,": "_nodcr(0,_cr,", + "_nods(_n," : "_nodsm(", + "_argwrap(_n," : "_argwrapm(", + "_xml(_n," : "_xml(0,", + "_xmls(_n," : "_xmls(0,", + "_cnt(_n," : "_cntm(", + "_xpt(_n," : "_xptm(", + "_valst(_n," : "_valm(", + "_valed(_n," : "_valed(0,", + "_lng(" : "_lng(", + "_lnged(" : "_lnged(" + }, + parserx = /(\r?[\n]|\/\*|\*\/|\/\/|\<\!\-\-|\-\-\>|[=\!+\/\*-]=|\+\+|\-\-|["'{(\[\])}\]\<\>]|$)|([ \t]+)|([a-zA-Z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF.$_][\w.$_]*)|(\d[x\d.]*)|(\\?[\w._?,:;!=+-\\\/^&|*"'[\]{}()%$#@~`<>]?)/g, + selfrx = /(^|\|)(?!\@|text\(\)|\.\.|[\w\-\:]+?\:\:)/g, // inject self regexp + macro_o = {}, + macro_c = {}, + macro_m = {}, + // config vars + c_async_lut = apf.$asyncObjects || { // used to figure out if the thing before the. is an async obj + "comm" :1, + "rpc" :1, + "http" :1, + "apf.ajax" :1 + }, + c_process_async, + c_xpathmode, // guess 'node' as the type for {} o_xpathpairs, 1 = node, 2 = nodes + c_elemxpath, // which xpath macro to use inside an element + c_statexpath, // which xpath to use for the stateful value + c_injectself, // add self:: in some o_xpathpairs + c_propassign, // support property assigns + c_export, // export function to some object + // outputs + o, ol, // output and output len + o_asyncs, // number of async calls + o_xpathpairs, // all xpaths and their models in pairs + o_props, // the js properties found + o_segs, // segments at groundlevel + o_xpaths, // xpaths at groundlevel + o_models, // number of xpaths with models + // temp and state vars + s = [], sl, // scopestack and scopestack len + bt = [], // backtrack lut + bts = [], // backtrack string stack + parse_mode, // the parse parse_mode + scope, // ol of a scope begni + segment, // the ol of a segment begin + start_tok, // the token a string or comment was started with + str,str_len, // length of the input string + line_no, // line number we are at + nesting, // nesting count + // last state vars + last_tok, // last token + last_type, // last type + last_dot, // . pos when last token was a word + last_model, // last model found + last_prop, // last property found + last_cmt_mode, // the parse mode outside the comment + last_cmt_tok, // last token before comment + last_cmt_type, // last type before comment + last_line, // offset of last newline + last_ns, // last namespace found + last_word; // last word in code mode + // macros used in code() + macro_o["if"] = "if(", + macro_c["if"] = ")", + macro_o["while"] = "while(", + macro_c["while"] = ")", + macro_o["for"] = "for(", + macro_c["for"] = ")", + macro_o["switch"] = "switch(", + macro_c["switch"] = ")", + macro_o["catch"] = "catch(", + macro_c["catch"] = ")", + macro_c["function"] = ") "; + + macro_o.foreach = + macro_o.each = "\nfor(var _t=_t||[],_t=(_t.push(_n,0,(", + macro_c.foreach = + macro_c.each = ")||[]),_t);(_n=_t[_t.length-1][_t[_t.length-2]++])||(_t.length-=2,_n=_t.pop(),0);)", + macro_o.foreachrev = + macro_o.eachrev = "\nfor(var _t=_t||[],_t=(_t.push(_n,0,(", + macro_c.foreachrev = + macro_c.eachrev = ")||[]),_t);(_n=_t[_t.length-1][_t[_t.length-1].length-(_t[_t.length-2]++)-1])||(_t.length-=2,_n=_t.pop(),0);)", + + macro_o.local = "\nfor(var _t=_t||[],_t=(_t.push(_n,((_n=_local(", + macro_c.local = ")),1)),_t);(_t[_t.length-1]--&&_n)||(_t.length--,_n=_t.pop(),0);)", + macro_o._editlm = "_valedx(true, ", // only serves to switch default xpath in edit([xpath]) + macro_o._editnormal = "_valedx(false, ", // only serves to switch default xpath in edit([xpath]) + macro_c.edit = ")", + macro_o.xabs = " ( ", + macro_c.xabs = " ) ", + + macro_o.localName = "_localName(_n", + macro_c.localName = ")", + macro_o.output = "_o.join(''", + macro_c.output = ")", + macro_o.reset = "(_o=[],l=0", + macro_c.reset = ")", + macro_o.index = "apf.getChildNumber.call(apf", + macro_c.index = ")", + macro_o.item = "(_t[_t.length-1][_t[_t.length-2]-1]", + macro_c.item = ")", + macro_o.first = "(_t[_t.length-2]==1", + macro_c.first = ")", + macro_o.last = "(_t[_t.length-2]==_t[_t.length-1].length", + macro_c.last = ")", + macro_o.total = "(_t[_t.length-1].length", + macro_c.total = ")", + macro_o.pos = "(_t[_t.length-2]-1", + macro_c.pos = ")", + + macro_o.tagName = "_tagName(_n", + macro_c.tagName = ")", + macro_o._nodeValue = "_nodeValue(_n", + macro_c._nodeValue = ")", + macro_c.async = "])", + macro_c.precall = "])", + macro_c._call = ")"; + + var call_args_lut = { + _call: ".call(_n", + localName: macro_o.localName, + tagName: macro_o.tagName, + nodeValue: macro_o.nodeValue, + index: macro_o.index + }, + + // centralized code fragments used in parser/generator + cf_block_o = "(function(){var _o=[],_l=0;\n", + cf_block_c = ";return _l==1?_o[0]:_o.join('');}).call(this)", + cf_async_o = "_async(_n,_c,_a,_w,_f,this,", + cf_async_m = "',_a[++_a.i]||[", + cf_obj_output = "_r=", + cf_mode_output, + cf_str_output = "_o[_l++]=", + cf_def_output = "", + cf_func_o = "{var _o=[],_l=0,_n=this;\n", + cf_func_c = ";\nreturn _l==1?_o[0]:_o.join('');}", + + // compile chunks used in compile/match + cc_async_o = "(_a=_a||{}).i=0;try{\n", + cc_async_c = "}catch(_e){if(_e.x)return;throw(_e);}\n", + //cc_async_o = "(_a=_a||{}).i=0;", + //cc_async_c = "", + cc_pc_o = "(_a=_a||{}).i=0;try{_precall(_w);", + cc_pc_c = "}catch(_e){if(_e.x)return;throw(_e);}", + cc_opt_o = "with(_w){", + cc_opt_c = "}", + cc_v_blk_o = "var _o=[],_l=0;_o[_l++]=", + cc_v_blk_ob = "var _o=[],_l=0;\n", + cc_v_blk_c = ";\nreturn _ret(_l==1?_o[0]:_o.join(''));", + cc_v_blk_cb = ";\n_c(_ret(_l==1?_o[0]:_o.join('')),apf.SUCCESS,apf.$lmx);apf.$lmx=null;", + cc_v_ret_o = "return _ret(", + cc_v_ret_c = ");", + cc_v_cb_o = "_c(_ret(", + cc_v_cb_c = "),apf.SUCCESS,apf.$lmx);apf.$lmx=null;\n", + + cc_o_blk_o = "var _r=", + cc_o_blk_ob = "var _r;", + + cc_o_blk_c = ";\nreturn _r;", + cc_o_blk_cb = ";\n_c(_r,apf.SUCCESS,apf.$lmx);apf.$lmx=null;", + cc_o_blk_ce = ";\n_c(0,apf.SUCCESS,apf.$lmx);apf.$lmx=null;;", + cc_o_ret_o = "return ", + cc_o_ret_c = "", + cc_o_cb_o = "_c(", + cc_o_cb_c = ",apf.SUCCESS);", + cc_f_async_o = "var _f=function(_n,_c,_w,_a){", + cc_f_opt_o = "var _f=function(_n,_w){", + cc_f_o = "var _f=function(_n){", + cc_fc_async_o = "var _f=function(_n,_c,_w,_cr,_a){", + cc_fc_opt_o = "var _f=function(_n,_w,_cr,){", + cc_fc_o = "var _f=function(_n,_cr){", + cc_fe_async_o = "var _f=function(event,_c,_w,_a,_n){", + cc_fe_opt_o = "var _f=function(event,_w,_n){", + cc_fe_o = "var _f=function(event,_n){", + cc_f_c = "}", + cc_f_match_o = "var _f=function(_m){", + + cc_m_m_blk = ";\nif(_n=_r){if(!_n.nodeType)_n=_m;", + cc_m_m_value_o = ";\nif(_n=", + cc_m_m_value_c = "){if(!_n.nodeType)_n=_m;", + cc_m_v_string = "\nreturn ", + cc_m_v_o = "\nreturn _ret(", + cc_m_v_c = ");", + cc_m_n_string = "\nreturn _n;", + cc_m_n_o = "\nreturn (_r = (", + // decision point for compileMatch node-mode for the return type + cc_m_n_c = "))?(_r.nodeType?_r:_n):(_r===null?null:_n);", + + cc_m_o = "var _r, _n = _m;", + cc_m_brk = ";\n_n = _m;", + cc_m_v_ret = "\nreturn _ret(_nodeValue(_n));" , + cc_m_n_ret = "\nreturn _n;" , + cc_m_c = "\n}"; + + function switchToBlock(no_output){ // used to switch expression mode to block mode + var u, v; + if (o[scope-1] == "{{") + u = scope-1; // scan for our root expression block to switch to block + else + for (v = sl - 2, u = 0; v >= 0 && o[u=(s[v] & 0xfffffff) - 1] != "{{"; v -=2 ){}; + + if (!no_output && ol > u + 1) // inject auto output unless no output or nothing to output in buffer + o[u] = cf_block_o + cf_str_output + else + o[u] = cf_block_o; + parse_mode = 1; + } + + function parser(tok, rx_lut, rx_white, rx_word, rx_num, rx_misc, pos) { + var u, v, w, + type = rx_lut ? type_lut[rx_lut] : (rx_white ? 0 : (rx_word ? 3 : (rx_num ? 4 : (tok ? 2 : 15)))); + switch (parse_mode) { + case 0: // ===================== expression parse_mode ========================= + case 1: // ========================== block parse_mode ========================= + switch (type) { + case 0: // -------- whitespace -------- + if ((last_type == 3 && last_tok!='$') || last_type == 4) + o[ol++] = " "; + else if (xpath_lut_code[last_tok]) + last_type = 0;// make last_type visible to xpathmode select + break; + case 1: // -------- newline -------- + line_no++, + last_line = pos; + if (o[ol-1] != "\n" && !newline_notallowed[last_tok]) + o[ol++] = "\n"; + if (xpath_lut_code[last_tok]) + last_type = 0;// make last_type visible to xpathmode select + break; + case 2: // -------- misc -------- + if (v = misc_tok[tok]) { + switch (v) { + case 1: // ';' + if (!s[sl-1]) {// close = macro + o[ol++] = ")", + sl -= 2; + } + + if (!parse_mode) { // dont do ; inject newline instead + if (o[ol-1] != "\n" && last_tok != "{" && last_tok != ";") + o[ol++] = "\n"; + } + else if (!sl || s[sl - 1]) // dont inject ; if we are in nested assignment macros + o[ol++] = ";"; + break; + case 2: // ',' + if (!s[sl - 1]) { // close = macro + o[ol++] = ")", + sl -= 2; + } + o[ol++] = ","; + break; + case 3: //'^' // dont output + if (o[ol-1] == "\n" || o[ol - 1] == ";" || last_tok=="{" + || last_tok == "} " || ol == scope) { // dont output-shortcut requirements + if (!parse_mode) + switchToBlock(); + o[ol++] = " "; // two spaces make it modify the output-ifs outcome + } + else + o[ol++] = "^"; + break; + case 4: //'= += -= assignment macro mode + if (last_tok!='<' && last_tok!='>'){ + // we should only switch to block when we are not in a ( ) scope + if (!parse_mode && o[scope-1]!='(') + switchToBlock(true); + o[ol++] = tok; + // lets scan in reverse to see if we have an output or a non-output + + for (v = ol; v >= scope && !statement_lut[o[v]] && !((o[v] == " " + || o[v] == (nesting ? cf_str_output : cf_mode_output)) && (o[v]="",1)); v--){}; + + if (last_type == 3 && last_dot>0 && last_tok.charAt(0)!="."){ // prop = macro + if (c_propassign) { + ol -= 2; + while (is_out_space[o[ol]]) + ol--; + w = last_tok; + o[ol++] = op_lut[tok], o[ol++] = w.slice(0,last_dot), + o[ol++] = ",'", o[ol++] = w.slice(last_dot+1), + o[ol++] = "',", s[sl++] = scope | (parse_mode << 28), + s[sl++] = ""; // notabene, this stored item is checked everywhere + } + } + }else{ + o[ol++] = tok; + }break; + case 5: // '/' // regexp mode + if (pre_regexp[last_tok]) { + s[sl++] = scope | (parse_mode << 28); + s[sl++] = o[ol++] = tok; + scope = segment = ol - 1; + nesting++, parse_mode = 5, start_tok = tok; + } + else + o[ol++] = "/"; + break; + case 6: // ':' // switch to {x:1} object mode + if (sl > 2 && s[sl - 1] == "{{" && (ol < scope + 4 && last_type == 5) + || (ol < scope + 3 && (last_type == 3 || last_type == 4))) { + o[scope-1] = s[sl-1] = "{" + parse_mode = (v = s[sl - 2]) >> 28; + s[sl-2] = v & 0xfffffff, + nesting--; + } + else if (o[ol - 3] == "case" || (last_type == 5 && last_word == "case")) + tok = ";"; //fixes auto output problem + o[ol++] = ":"; + break; + default: + o[ol++] = tok; + break; + } + } + else + o[ol++] = unesc_lut[tok] || tok; + break; + case 3: // -------- word -------- + case 4: // ------- number ------- + if ( v = xml_code_operators[tok] ){ + o[ol++] = tok = v, type = 2; + } else { + v = u = w = 0;// last_word used for case 'bla bla': + last_dot = (last_word = tok).lastIndexOf("."); + if (tok.charAt(0) != '.' // .obj shouldnt trigger block + && ((v = (u = ((out_context_word[last_tok] // check if we need to switch + || o[ol - 1] == "\n") && !new_block[last_tok])) + && !s[sl - 1].indexOf("{") && ol > scope) + || (w = statement_lut[tok])) && !parse_mode){ // check statement + if (w == 2 && s[sl - 1].indexOf("{")) w = 0; // (function() shouldnt trigger blockmode + switchToBlock(w); // pass in statement_lut[tok] as outputflag + } + if (u && !s[sl - 1]) { // assign macro close + o[ol-1] == "\n" && (o[ol - 1] = ""), o[ol++] = ")", + o[ol++] = "\n", v = 1, sl -= 2; + } + if (v && parse_mode && !statement_lut[tok] && !call_exclusion[tok]) // inject output + o[ol++] = (nesting ? cf_str_output : cf_mode_output); + + if (last_dot > 0 && tok.charAt(0) != ".") // store property + o_props[o[ol++] = last_prop = tok] = 1; + else o[ol++] = tok; + } + break; + case 5: // -------- stringquotes -------- + if ((v = (u = ((out_context_word[last_tok] || o[ol - 1]== "\n" ) + && !new_block[last_tok])) && !s[sl - 1].indexOf("{") + && ol > scope) && !parse_mode) // check if we need to switch to block mode + switchToBlock(); + + if (u && !s[sl - 1]) { // close = macro + o[ol - 1] == "\n" && (o[ol - 1] = ""), o[ol++] = ")", + o[ol++] = "\n", v = 1, sl -= 2; + } + if (v) { // generate output + o[ol++] = (o[ol-2] != "\n" && block_autoappend[last_tok]) + ? "+" + : (nesting ? cf_str_output : cf_mode_output); + } + else if (block_autoappend[last_tok]) + o[ol++] = "+"; + + s[sl++] = scope | (parse_mode << 28), s[sl++] = o[ol++] = tok; + scope = segment = ol - 1, nesting++, parse_mode = 5, start_tok = tok; + break; + case 6: // -------- comment -------- + if (tok == "*/" || tok== "-->") + throw { + t: "Unmatched comment "+tok, + p: pos + }; + last_cmt_mode = parse_mode, last_cmt_tok = last_tok, + last_cmt_type = last_type, parse_mode = 6, start_tok = tok; + break; + case 7: // -------- { -------- + if (o[ol - 1] == ") " || (o[ol - 2] == ") " && ol--)) { // ') ' is function def + if (s[sl - 1] != "(" && s[sl - 1] != "[") { + s[sl++] = scope | (parse_mode << 28), + s[sl++] = "{{", o[ol++] = cf_func_o, + scope = ol, parse_mode = 1, nesting++, o[ol++] = ""; // make the scope check pass + } + else { + s[sl++] = scope, s[sl++] = o[ol++] = tok, scope = ol; + parse_mode = 1; + }// for do else..etc below + } + else if ((macro_o[s[sl + 1]] && last_tok == ") ") || pre_plain[last_tok]) { + s[sl++] = scope, s[sl++] = o[ol++] = tok, scope = ol; + o[ol++] = ""; + } + else { + if ((v = (u = ((out_context_word[last_tok]||o[ol - 1] == "\n") + && !new_block[last_tok])) + && !s[sl - 1].indexOf("{") && ol > scope) && !parse_mode) + switchToBlock(); // block mode detection + + if (u && !s[sl - 1]) { // close = macro + o[ol - 1] == "\n" && (o[ol - 1] = ""), + o[ol++] = ")", o[ol++] = "\n", v = 1, sl -= 2; + } + if (v) { // inject output, +''+ is when between two { } { } (supposedly) + o[ol++] = (o[ol - 2] != "\n" && block_autoappend[last_tok]) + ? "+''+" + : (nesting ? cf_str_output : cf_mode_output); + } + else if (block_autoappend[last_tok]) // inject append + o[ol++] = (last_tok == "}") ? "+''+" : "+"; + + s[sl++] = scope | (parse_mode << 28), s[sl++] = o[ol++] = "{{"; + + if (!nesting && scope != ol) // count output segments on nesting 0 + o_segs++; + + nesting++, segment = scope = ol, parse_mode = 0; + } + break; + case 8: // -------- } -------- + if (!s[sl - 1]) // close = macro + o[ol++] = ")", o[ol++] = "\n",sl -= 2; + + if (type_close[v = s[--sl]] != (o[ol++] = tok)) + throw { + t: "Cannot close " + v + " with " + tok, + p: pos + }; + + if (v == "{{") { // closing code block + if (scope == ol - 1) { + if ( (s[sl - 1] >> 28) <= 1) // empty code in code + o[scope-1] = "{", o[ol - 1] = "}"; + else // empty code elsewhere + o[scope - 1] = o[ol - 1] = "'"; + } + else { + if (!parse_mode) { // expression wraps in () + o[scope - 1] = "(", + o[ol - 1] = ")"; + } + else { // codeblock wraps in (function(){})() + if (o[scope - 1] == cf_func_o) { + if (scope == ol - 2) + o[scope - 1] = "{", o[ol - 1] = "}"; + else + o[ol - 1] = cf_func_c; + } + else + o[ol - 1] = cf_block_c; + } + } + parse_mode = (v=s[--sl])>>28, scope = v&0x0fffffff; + segment = ol, nesting--; + + if (!nesting) // count segs on nesting level 0 + o_segs++; + + if (parse_mode == 7) // attribute hack + o[ol++] = "+\"\\\"", parse_mode = 4; + } else scope = s[--sl]; // was object def or if (){} + + break; + case 9: // -------- [ -------- + if (((last_type == 3 && !pre_xpath[last_tok] && last_tok!='$') || last_tok == ")" || last_tok == "]") && o[ol - 1] != "\n") { + o[ol++] = "[", s[sl++] = scope | (parse_mode << 28), //was array index + s[sl++] = tok, segment = scope = ol; + } + else { + last_model = null; + + if ((w = xpath_lut_code[last_tok])) { + ol--, last_tok = o[ol-1]; // xpath with *%$# + } + else { + w = xpath_macro[s[sl - 1]] || xpath_macro[nesting ? 0 : c_xpathmode]; + } + if ((v = (u = ((out_context_word[last_tok] || o[ol - 1] == "\n") + && !new_block[last_tok])) && !s[sl - 1].indexOf("{") + && (ol > scope || s[sl - 1].length == 1)) && !parse_mode) + switchToBlock(); // check if we need to switch to block mode + + if (u && !s[sl - 1]) { // close = macro + o[ol - 1] == "\n" && (o[ol - 1] = ""), o[ol++] = ")", + o[ol++] = "\n", v = 1, sl -= 2; + } + + if (v) { // inject output + o[ol++] = (o[ol - 2] != "\n" && block_autoappend[last_tok]) + ? "+" + : (nesting ? cf_str_output : cf_mode_output); + } + else if (block_autoappend[last_tok]) // inject append + o[ol++] = "+"; + + if (!nesting && ol!=scope) + o_segs++; + // store scope in bt for reparse of array + nesting++, s[sl++] = scope|(parse_mode<<28), s[sl++] = o[ol++] = w, + segment = scope = ol, bt[scope] = pos, parse_mode = 3; + } + break; + case 10: // -------- ] -------- + if (!s[sl-1]) // close = macro + o[ol++]=")",sl -=2; + + if ( type_close[v = s[--sl]] != (o[ol++] = tok)) + throw { + t: "Cannot close " + v + " with " + tok, + p: pos + }; + + scope = s[--sl]&0xfffffff; // clean scope of possible parse_mode 1 + break; + case 11: // -------- ( -------- + if ( ((v = (u=((out_context_paren[last_tok]||o[ol-1]=="\n") && + !new_block[last_tok])) && !s[sl-1].indexOf("{") && + ol>scope)) && !parse_mode) + switchToBlock(); + + if (u && !s[sl-1]) // close = macro + o[ol-1]=="\n"&&(o[ol-1]=""),o[ol++]=")", o[ol++]="\n",v = 1,sl -=2; + + if (v && parse_mode) // inject output + o[ol++] = (nesting?cf_str_output:cf_mode_output), last_type = 0; + + if (w = macro_o[last_tok]) { + if (o[ol-1]==" ") ol--; // support func () + o[ol-1] = w, s[sl++] = scope, s[sl++] = last_tok, scope = segment = ol; + } + else { + if (last_type == 3) { // word( + if (last_dot < 0) { // no dot + v = 0; + if (last_tok == "function" || o[ol - 3] == "function" || o[ol - 4] == "function") { + s[sl++] = scope, s[sl++] = "function", //func def + o[ol++] = "(", scope = segment = ol; + //TODO! check the depth with which functions are made global + if (last_tok!="function" && c_export && sl==4) { + o[v=(o[ol - 4] == "function")?(ol-4):(ol-5)] = + "var "+last_tok+" = "+c_export+"."+last_tok+" = function"; + o[v+2] = ""; + } + } + else { // its a call and not a new + if (!call_exclusion[last_tok] && o[ol-3]!="new") { + o[ol++] = ".call(_n", s[sl++] = scope, + s[sl++] = "_call", scope = segment = ol; + } + else { // its an excluded call + s[sl++] = scope, s[sl++] = o[ol++] = tok, + scope = segment = ol; + } + } + } + else { + if (last_dot > 1 && c_process_async && (c_async_lut[v = last_tok.substring(0,last_dot)] || c_async_lut[v = last_tok])) {// its an async call + if (o[--ol] == " ") + ol--; + o[ol++] = cf_async_o, o[ol++] = v, o[ol++] = ",'"; + o[ol++] = last_tok.slice(last_dot + 1); + o[ol++] = cf_async_m, s[sl++] = scope, s[sl++] = "async", + scope = segment = ol, o_asyncs++; + } + else { // its a obj.prop() type call + if (last_tok.indexOf('.')!=last_dot) // obj.prop.call(); + o_props[last_tok.slice(0,last_dot)] = 1; + + s[sl++] = scope, s[sl++] = o[ol++] = tok, + scope = segment = ol; + } + } + } + else { // function object call + s[sl++] = scope, s[sl++] = o[ol++] = tok, + scope = segment = ol; + } // dont store calls as props + if (last_tok == last_prop) + delete o_props[last_tok]; + } + break; + case 12: // -------- ) -------- + if (!s[sl - 1]) { // close = macro + o[ol-1] == "\n" && (o[ol-1] = ""), o[ol++] = ")", + o[ol++]="\n", v = 1, sl -= 2; + } + + if (w = macro_c[v = s[--sl]]) { // closing a macro + if (v != "_call") + tok = ") "; // make sure any [ ] doesnt get interpreted as array index + if ((u = call_args_lut[v]) && u != o[ol - 1]) + o[scope - 1] = u + ",";// do , insertion for argless macros + o[ol++] = w; // write close-end of macro + } + else if (type_close[v] != (o[ol++] = tok)) { + throw { + t: "Cannot close " + v + " with " + tok, + p: pos + }; + } + scope = s[--sl] & 0xfffffff; // scope should be unimpacted + break; + case 13: // -------- < -------- + // check if < is markup or not + if (ol == scope || markup_in_code_lut[last_tok] || o[ol - 1] == "\n"){ + if ((v = (u = ((out_context_word[last_tok] || o[ol - 1] == "\n") + && !new_block[last_tok])) && !s[sl - 1].indexOf("{") + && ol > scope) && !parse_mode) + switchToBlock(); // switch to block mode + + if (u && !s[sl - 1]) { // close = macro + o[ol - 1] == "\n" && (o[ol - 1] = ""), o[ol++] = ")", + o[ol++] = "\n", v = 1, sl -= 2; + } + if (v) { + o[ol++] = (o[ol - 2] != "\n" && block_autoappend[last_tok]) + ? "+''+" + : (nesting ? cf_str_output : cf_mode_output); + } + else if (block_autoappend[last_tok]) + o[ol++] = "+"; + // start markup mode with the markup-stack counting + last_ns = null, o[ol++] = '"', o[ol++] = "<", nesting++, + s[sl++] = scope | (parse_mode << 28), sl += 3, + s[sl - 2] = s[sl - 1] = 0; + + segment = scope = ol - 1, parse_mode = 4; + } + else + o[ol++] = "<"; + break; + case 14: // -------- < -------- + o[ol++] = ">"; + break; + case 15: // end + if (sl && !s[sl - 1]) { // close = macro + o[ol - 1] == "\n" && (o[ol - 1] = ""), o[ol++] = ")", + o[ol++] = "\n", v = 1, sl -= 2; + } + break; + } + break; + case 2: // ========================== text parse_mode ========================== + switch (type) { + case 1: // -------- newline -------- + line_no++, last_line = pos; + if (ol != scope && ol != segment) // only output when not first + o[ol++] = "\\n"; + break; + case 2: // -------- misc -------- + if (ol == segment) // segment connectors + o[ol] = (ol++ == scope) ? "\"" : "+\""; + + o[ol++] = unesc_txt[tok] || tok; + break; + case 3: // word + if (ol == segment) + o[ol] = (ol++ == scope) ? "\"" : "+\""; + if (tok.charAt(tok.length-1)=='$'){ + o[ol++] = tok.slice(0,-1); + o[ol++] = tok = '$';// fix word$[xpath] + }else o[ol++] = tok; + break; + case 5: // -------- stringquotes -------- + if (ol == segment) + o[ol] = (ol++ == scope) ? "\"" : "+\""; + + o[ol++] = (tok == '"') ? "\\\"" : "'"; + break; + case 7: // -------- { -------- code mode + if (ol == segment) { + if (ol != scope ) + o[ol++] = "+"; + } + else + o[ol++] = "\"+", nesting || o_segs++; + s[sl++] = scope | 0x20000000, s[sl++] = o[ol++] = "{{", + nesting++, segment = scope = ol, parse_mode = 0; + break; + case 9: // -------- [ -------- xpath mode + last_model = null; // get xpath macro + if ((w = xpath_lut_text[last_tok]) && o[ol - 1] == last_tok) { + if (--ol - 1 == scope) + ol --; // remove first "" + } + else // only select c_xpathmode when nesting == 0 + w = xpath_macro[(nesting || scope != ol) ? 0 : c_xpathmode]; + + if (ol != scope) { + o[ol] = (ol++ == segment) ? "+" : (nesting || o_segs++, "\"+"); + + if (!nesting) + o_segs++; + } + + s[sl++] = scope | 0x20000000, s[sl++] = o[ol++] = w, + segment = scope = ol, nesting++, parse_mode = 3; + break; + case 15: // -------- end -------- + if (sl) + throw { + t: "Unclosed " + s[sl-1] + " found at end in textmode", + p: pos + }; + if (ol != scope && ol != segment) + o[ol++] = "\"", nesting || o_segs++; + break; + default: // -------- default -------- + if (ol == segment) + o[ol] = (ol++ == scope) ? "\"" : "+\""; + o[ol++] = tok; + } + break; + case 3: // ========================== xpath parse_mode ========================= + switch(type) { + case 0: // -------- whitespace -------- + if (ol != scope){ // strip initial spaces\l + if (ol == segment) + o[ol++] = "+\""; + o[ol++] = tok; + } + break; + case 1: // -------- newline -------- + line_no++, last_line = pos; + break; + case 2: // -------- misc -------- + if (tok == ":" && last_tok == ":" && !xpath_axes[w = o[ol - 2]] + && ((v = s[sl - 2]) >> 28) != 6) { // found model::xpath split + if (o[ol - 2] == '+"') // model is calculated + o[ol - 2] = o[ol - 1] = "", last_model = "#"; + else { + o[ol - 1] = '"'; + if (segment == scope) // model is normal name + last_model = o.slice(segment + 1, ol - 1).join(""); + else // model is calculated + last_model = "#"; + } + if (!(w = xpath_model[o[scope - 1]])) + throw { + t: "Invalid model found for: "+o[scope-1], + p: pos + }; + + o[scope - 1] = w, o[ol++] = ",", segment = scope = ol; + } + else { + if (tok == "," && (v = (s[sl - 2] >> 28)) <= 1) { // xpath is an array in code + ol = scope-1, u = str.slice(bt[scope] + 1, pos + 1); + // fix up stack to not be an xpath but an array + last_type = 9, parse_mode = v, o[ol++] = last_tok = "["; + s[sl - 2] = (s[sl - 2] & 0xfffffff) | (parse_mode << 28), + s[sl - 1] = last_tok, segment = scope = ol, nesting--; + + if (!nesting) + o_xpaths--; + if (u.length > 1) { // ignore [, optimized escaping + bts.push(str); // push str so str always is the string in replace + (str = u).replace(parserx, parser); // reparse it + str = bts.pop(); // pop it again + } + } + else { + if (ol == segment) + o[ol] = (ol++ == scope) ? "\"" : "+\""; + o[ol++] = unesc_lut[tok] || tok; + } + } + break; + case 3: // word + if (ol == segment) + o[ol] = (ol++ == scope) ? "\"" : "+\""; + if (tok.charAt(tok.length-1)=='$'){ + o[ol++] = tok.slice(0,-1); + o[ol++] = tok = '$';// fix word$[xpath] + }else o[ol++] = tok; + break + case 5: // -------- stringquotes -------- + if (ol == segment) + o[ol] = (ol++ == scope) ? "\"" : "+\""; + if (s[sl - 1] == "[") // strings only are used in [ ] + s[sl - 1] = tok; + else if (s[sl - 1] == tok) // close string + s[sl - 1] = "["; + + if (tok == '"') + o[ol++] = "\\"; + o[ol++] = tok; + break; + case 7: // -------- { -------- + if (ol == segment) { + if (ol != scope) + o[ol++] = "+''+"; + } + else + o[ol++] = "\"+"; + + s[sl++] = scope | 0x30000000, s[sl++] = o[ol++] = "{{", + nesting++, segment = scope = ol, parse_mode = 0; + + if (last_model && s[sl - 3] != xpath_lut_text["$"]) { + o_xpathpairs.push(last_model, "#"); + last_model = null, o_models++; + } + break; + case 9: // -------- [ -------- + // lets see if we are an xpath + if (s[sl - 1] == "'" || s[sl - 1] == '"' || + ((last_type != 3 || last_tok=='$') && last_tok != ")" && last_tok != "]") ) { + if (last_model) + o_xpathpairs.push(last_model, "#"), o_models++; + last_model = null; + + if ((w = xpath_lut_text[last_tok]) && o[ol - 1] == last_tok) + ol--; + else + w = xpath_macro[0]; + + if (ol == segment) { + if (ol != scope) + o[ol++] = "+"; + } + else o[ol++] = "\"+"; + + s[sl++] = scope | 0x30000000, s[sl++] = o[ol++] = w, nesting++, + segment = scope = ol, parse_mode = 3; + } + else { + if (ol == segment) + o[ol] = (ol++ == scope) ? "\"" : "+\""; + + s[sl++] = scope|0x60000000, s[sl++] = o[ol++] = "["; // keep track of [, abuse mode 6 + } + break; + case 10: // -------- ] -------- + sl--, parse_mode = (w = s[--sl]) >> 28, w = w & 0x0fffffff; + + if (parse_mode == 6){ // was part of [] internally to xpath, see above + if (s[sl + 1] != "[") + throw { + t: "In xpath, cannot close " + s[sl + 1] + " with " + tok, + p: pos + }; + if (ol == segment) + o[ol] = (ol++ == scope) ? "\"" : "+\""; + + o[ol++] = "]"; + parse_mode = 3; + } + else { + if (ol == scope ) { + if ((s[sl] >> 28) <= 1) // empty array in code + o[scope - 1] = "[", o[ol++] = "]"; + else // empty xpath elsewhere + o[scope - 1] = o[ol++] = "\"" ; + segment = ol; + } + else { + //if( s[sl+1] != '[' ) + // throw {t:"Unclosed string in xpath"+s[sl+1], p: pos}; + if (ol != segment) + o[ol++] = "\""; + if (segment == scope){ // we might have an xpath name + v = o.slice(segment + 1, ol - 1).join(""); + if (c_injectself && o[scope - 1] != "," // inject self + && v != (u = v.replace(selfrx, "$1self::")) + && s[sl + 1] != xpath_lut_text["$"]) { + o[scope+1] = v = u; + for (u = scope + 2; u < ol - 1; u++) + o[u] = ""; + } + } + else { + if ((u = o[scope - 1]) != ",") { + v = "#"; + if (c_injectself)// inject dyn self if dyn xpath + o[scope - 1] = u + "_injself(", o[ol++] = ")"; + } + else + v = ""; + } + if (s[sl + 1] != xpath_lut_text["$"] && v) { + o_xpathpairs.push(last_model, v); // only store if not _lng + if (last_model) + o_models++; + } + o[ol++] = ") ", segment = ol; // close xpath with ') ' marker + //logw("CLOSING XPATH"+o.join('#')+nesting); + if (parse_mode == 7) // attribute assign in xml mode + o[ol++] = "+\"\\\"", parse_mode = 4; + } + // lets output an xpath if we werent a language symbol + nesting--, last_model = null; + if (!nesting) + o_segs++, o_xpaths++; + } + scope = w; + break; + case 11: // -------- ( -------- + if (ol == segment) + o[ol] = (ol++ == scope) ? "\"" : "+\""; + s[sl++] = scope | 0x30000000, // keep track of () in xpath + s[sl++] = o[ol++] = "(";//, last_model = null; + break; + case 12: // -------- ) -------- + if (ol == segment) + o[ol] = (ol++ == scope) ? "\"" : "+\""; + + if (type_close[v = s[--sl]] != (o[ol++] = tok)) + throw { + t: "Cannot close " + v + " with " + tok, + p: pos + }; + + scope = s[--sl] & 0xfffffff; + break; + case 15: // -------- end -------- + throw { + t: "Unexpected end whilst parsing xpath", + p: pos + }; + break; + default: // -------- default -------- + if (ol == segment) + o[ol] = (ol++ == scope) ? "\"" : "+\""; + o[ol++] = tok; + break; + } + break; + case 4: // =========================== xml parse_mode ========================== + switch (type) {// stack: '<'sl+4,outside=0, ''sl-2,outside=1 '/>'sl-4,outside=1 + case 0: // -------- whitespace -------- + if (ol == segment) + o[ol++] = "+\""; + + o[ol++] = " ", last_type = 0; + break; + case 1: // -------- newline -------- + if (ol == segment) + o[ol++] = "+\""; + + line_no++, last_line = pos, o[ol++] = "\\n", last_type = 1; + break; + case 2: // -------- misc -------- + if (ol == segment) + o[ol++] = "+\""; + if (tok == "/" && last_tok == "<") { + sl -= 4; // -------- + if (ol == segment) + o[ol++] = "+\""; + + o[ol++] = tok; + if (last_tok != "<") { + if (last_tok == "/") { + sl -= 4; // self close tag /> drops stack -4 + if (s[sl + 2]) + throw { + t: "Unexpected / whilst parsing xml", + p: pos + } + if (o[ol - 3] == "<") // remove empty from output + ol -= 2, o[ol - 1] = ""; + } + else + sl -= 2; // nets stackdepth of 2 + if (s[sl]) { // end of xml mode + nesting--, o[ol++] = "\"", scope = s[sl], segment = ol, + parse_mode = scope >> 28, scope = scope & 0x0fffffff; + } + else + s[sl - 1] = 1; // we are outside a tag, flag it on the stack + } + else // remove empty <> from output + ol--, o[ol - 1] = ""; + break; + case 9: // -------- [ -------- xpath mode + last_model = null; + + if (last_tok == "!" && o[ol - 2] == "<" && !s[sl - 1]) { // CDATA mode + o[ol++] = tok, s[sl++] = scope | (parse_mode << 28); + s[sl++] = "]]>", scope = segment = ol - 1; + nesting++, parse_mode = 5; + } + else { + if (s[sl - 1]) { // we are outside a tag + if ((v = xpath_lut_node[last_tok])) + ol --; + else + v = xpath_macro[c_elemxpath]; + + s[sl++] = scope | 0x40000000 + } + else { + s[sl++] = scope | 0x40000000 + if ((v = xpath_lut_attr[last_tok])) { + ol--; + if (o[ol - 1] == "=") + last_tok = "="; + } + else + v = xpath_macro[last_ns ? c_statexpath : 8]; + + if (last_tok == "=")//0x7 flags xpath-in-missing-quotes + o[ol++] = "\\\"", s[sl - 1] = scope | 0x70000000; + } + o[ol] = (ol++ == segment) ? "+''+" : "\"+"; + nesting++, s[sl++] = o[ol++] = v, + segment = scope = ol, parse_mode = 3; + } + break; + case 7: // -------- { -------- code mode + if ( !s[sl - 1] && last_tok == "=") // 0x7 flags code-in-missing-quotes + o[ol++] = "\\\"", s[sl++] = scope | 0x70000000; + else + s[sl++] = scope | 0x40000000 + + o[ol] = (ol++ == segment) ? "+''+" : "\"+"; + s[sl++] = o[ol++] = "{{", nesting++; + segment = scope = ol, parse_mode = 0; + break; + default: + if (ol == segment) + o[ol++] = "+\""; + o[ol++] = tok; + break; + case 15: // -------- end -------- + throw { + t: "Unexpected end whilst parsing xml", + p: pos + }; + break; + }break + case 5: // ========================== string parse_mode ======================== + switch (type) { + case 1: // -------- newline -------- + line_no++, last_line = pos; + if (ol == segment) + o[ol] = (ol++ == scope) ? "\"" : "+\""; + o[ol++] = "\\n"; + break; + case 2: // -------- misc -------- + if (tok == "/" && s[sl - 1] == "/") { // regexp closing character + o[ol++] = "/", scope = s[sl -= 2], segment = ol, + parse_mode = scope >> 28, + scope = scope & 0x0fffffff, nesting--; + } + else { + if (ol == segment) + o[ol] = (ol++ == scope) ? "\"" : "+\""; + o[ol++] = (s[sl - 1] != "/" && unesc_str[tok]) || tok; + } + break; + case 3: // word + if (ol == segment) + o[ol] = (ol++ == scope) ? "" : "+\""; + if (tok.charAt(tok.length-1)=='$'){ + o[ol++] = tok.slice(0,-1); + o[ol++] = tok = '$';// fix word$[xpath] + }else o[ol++] = tok; + break + case 5: // -------- stringquotes -------- + if (s[sl - 1] == tok) { // closed by matching quote + if (scope != segment) // string is segmented, output ) + o[ol] = (ol++ != segment) ? (tok + ")") : ")"; + else + o[ol++] = tok; // else just close + scope = s[sl -= 2], segment = ol, parse_mode = scope >> 28; + scope = scope & 0x0fffffff, nesting--; + } + else { + if (ol == segment) + o[ol] = (ol++ == scope) ? "\"" : "+\""; + o[ol++] = tok == '"' ? "\\\"" : tok; + } + break; + case 6: // -------- default -------- + if (s[sl - 1] == "/" && tok == "*/") { // caught faux comment in regexp /a*/, is close + o[ol++] = "*/", scope = s[sl -= 2], segment = ol, + parse_mode = scope >> 28, scope = scope & 0x0fffffff, nesting--; + } + else { + if (ol == segment) + o[ol] = (ol++ == scope) ? "" : "+\""; + o[ol++] = tok; + } + break; + case 7: // -------- { -------- code mode + if (s[sl - 1] != "'" && s[sl - 1] != "/") { + if (s[sl - 1] == '"') + o[scope] = '("'; + if (ol == segment) { + if (ol != scope) + o[ol++] = "+"; + } + else + o[ol++] = "\"+"; + s[sl++] = scope | 0x50000000, o[ol++] = s[sl++] = "{{", + nesting++, segment = scope = ol, parse_mode = 0; + } + else + o[ol++] = tok; + break; + case 9: // -------- [ -------- xpath mode + if (s[sl - 1] != "'" && s[sl - 1] != "/" // ignore in '' and CDATA[, else xpath + && (s[sl - 1] == '"' && (o[scope] = '("') || ol != scope + 2 + || last_tok != "CDATA") ) { + last_model = null; + if ((w = xpath_lut_text[last_tok]) && o[ol - 1] == last_tok) + ol--; + else + w = xpath_macro[0] + + if (ol != scope) + o[ol] = (ol++ == segment) ? "+" : "\"+"; + + s[sl++] = scope | 0x50000000, s[sl++] = o[ol++] = w, + segment = scope = ol, nesting++, parse_mode = 3; + } + else + o[ol++] = tok; + break; + case 14: // -------- > -------- + if (ol == segment) + o[ol] = (ol++ == scope) ? "" : "+\""; + o[ol++] = tok; + + if (s[sl - 1] == "]]>" && last_tok == "]" && o[ol - 3]=="]") { // check if CDATA close + scope = s[sl -= 2], parse_mode = scope >> 28; + scope = scope & 0x0fffffff, nesting--; + sl -= 4; // close the tag since we came from XML mode + if (s[sl]) // was last tag, jump up the stack one more. + nesting--, o[ol++] = "\"", scope = s[sl], segment = ol, + parse_mode = scope >> 28, scope = scope & 0x0fffffff; + else + s[sl - 1] = 1; + } + break; + case 15: // -------- end -------- + throw { + t: "Unexpected end whilst parsing string", + p: pos + }; + break; + default: // -------- default -------- + if (ol == segment) + o[ol] = (ol++ == scope) ? "" : "+\""; + o[ol++] = tok; + break; + } + break; + case 6: // ========================= comment parse_mode ======================== + switch (type) { + case 1: // -------- newline -------- + line_no++, last_line = pos; + if (start_tok == "//") + parse_mode = last_cmt_mode, + tok = last_tok = last_cmt_tok, + type = last_type = last_cmt_type; + break; + case 6: // -------- comment -------- + if ((start_tok == "/*" && tok == "*/") + || (start_tok == "")) { + parse_mode = last_cmt_mode, + tok = last_tok = last_cmt_tok, + type = last_type = last_cmt_type; + } + break; + case 15: // -------- end -------- + if (start_tok != "//"){ + throw { + t: "Unexpected end whilst parsing comment", + p: pos + } + } else { + parse_mode = last_cmt_mode, + tok = last_tok = last_cmt_tok, + type = last_type = last_cmt_type; + if (sl && !s[sl - 1]) { // close = macro + o[ol - 1] == "\n" && (o[ol - 1] = ""), o[ol++] = ")", + o[ol++] = "\n", v = 1, sl -= 2; + } + }; + break; + } + break; + } + if (type > 1) + last_tok = tok, last_type = type; + } + + this.lastCode = function(){ + if (typeof(o) == "object") + return o.join(""); + return o; + }; + + function handleError(e, last_line, part, linenr) { + // TODO: make a proper APF exception with this information: + if (e.t) { + throw new Error(apf.formatErrorString(0, null, + "Parsing live markup source", + "Error whilst parsing: " + e.t + " on line:"+ line_no + + " col:" + (e.p - last_line - 2) + + (part ? (" part: " + part) : "") + "\n" + str)); + } + else { + throw new Error(apf.formatErrorString(0, null, + "Compiling live markup function on line " + linenr, + "Error whilst compiling: " + e.message + //+ "\nStack Trace:\n" + e.stack + + "\nInput:\n" + str + + "\nGenerated:\n" + apf.lm.lastCode())); + } + } + + /** + * description of the method. + * Remarks: + * function{type:1,xpaths:[ model,name], props: ['obj.propname','obj2.otherpropname'], asyncs=1} + * this is a normal compiled function with extra properties + * if the xpath model and/or name is '#' it means it is a runtime calculated modelname or xpath. + * obj{type:2, str:str} it was single string by cfg option !alwayscode + * obj{type:3, xpaths:[ model, name ] } it was a single xpath by cfg simplexpath + * + * @param {String} str the code to compile + * @param {Object} options + * Properties: + * {Boolean} withopt creates with(_w){ code using an options block. (reqd for precall) + * {Boolean} precall wraps 1 async call into precallstore. call with _w._pc = 1 to precall, second time to execute. + * {Boolean} alwayscb always call callback function, even if not async + * {Boolean} nostring even generate code for a simple string + * {Number} xpathmode default type of root level xpath in code mode + * Possible values: + * 0: value + * 1: value with createnode + * 2: node + * 3: node with createnode + * 4: nodes + * 5: xpathobj returns a {model:model,xpath:xpath} object from xpaths + * {Boolean} parsecode start in codemode. if 0 its textmode. + * {Boolean} nostate dont' use _valst macro on [xpath] in namespaced xml. + * {Boolean} liveedit use the _valed macro for [xpath] in namespaced xml. + * {Boolean} langedit use of language items in namespaced xml text. + * {Boolean} injectself injects self:: to suitable xpaths + * {Boolean} event its an event thats being compiled, results in no returnvalue for this function. + * and the first argument is now an 'e' for the event object. + * {Boolean} funcglobal all functions defined in LM are made global + + * + * @return {Function} returns a function with extra properties + * Properties: + * {Number} type description + * Possible values: + * 1 Function return type + * 2 Parsed data is a pure string + * 3 Function return type, but its a single xpath + * 4 Function return type, but single propxs + * {Array} xpaths array of [model,xpath, model,xpath] pairs if model + * or xpath is '#', its dynamic if model is null its a local xpath + * {Number} models number of models + * {Array} props description + * {Number} asyncs description + * {String] str optional, returned with type 2 + */ + var cache = {}, + emptyCfg = {}; + this.resetCache = function(){ + cache = {}; + }; + var lmcache_rx = /^\s*~~(c\d+)~~/; + this.compile = function(istr, cfg) { + if (!cfg) + cfg = emptyCfg; + if (istr == null || !istr.length) { + return (cfg.nostring || cfg.event)?function(){return istr}:{ + type: 2, + str: istr + }; + } + // lets see if we need to fetch precompiled cachemarker + var c, f, is_single_prop; + if (istr.charAt(0)=="~" && (c=istr.match(lmcache_rx))){ + if (c=apf.lm_exec[c[1]]) return c; + alert("ERROR, undefined live markup cache marker found:"+istr); + return {type:2,str:istr}; + } + + var key = (cfg.xpathmode | (cfg.withopt && 0x10) | (cfg.precall && 0x20) + | (cfg.alwayscb && 0x40) | (cfg.nostring && 0x80) | (cfg.parsecode && 0x100) + | (cfg.nostate && 0x200) | (cfg.liveedit && 0x400)| (cfg.langedit && 0x800) + | (cfg.injectself && 0x1000) | (cfg.event && 0x2000) | (cfg.funcglobal && 0x4000)) + istr; + + if (c = cache[key]) + return c; + + + c_injectself = cfg.injectself, c_xpathmode = cfg.xpathmode||0, + c_statexpath = cfg.nostate ? 0 : 6, c_elemxpath = 0; + c_export = cfg.funcglobal?"self":(cfg.withopt?"_w":null); + c_process_async = !cfg.event; + + xpath_macro.edit = cfg.liveedit ? "_argwrap(_n," : "_argwrap(_n,";//"_val(_n,"; + macro_o.edit = cfg.liveedit ? macro_o._editlm : macro_o._editnormal; + + xpath_lut_node = cfg.langedit ? xpath_lut_node_langedit : xpath_lut_node_normal; + + o_props = {}, o_xpathpairs = [], s = [], o = ["","","",""], str = istr, + str_len = str.length; + ol = scope = segment = o.length, + o_segs = o_xpaths = o_asyncs = o_models = nesting = line_no = last_type = last_line = 0; + + if (cfg.parsecode) { + parse_mode = 0, sl = 2, s[0] = ol, s[1] = "{{", last_tok = "{", + cf_mode_output = cfg.event ? "" : (c_xpathmode <= 1 ? cf_str_output : cf_obj_output); + } + else + parse_mode = 2, sl = last_tok = 0, cf_mode_output = cf_str_output; + + if (cfg.nothrow) { + str.replace(parserx, parser); + } + else { + try { + str.replace(parserx, parser); + } + catch (e) { + handleError(e, last_line); + return null; + } + } + + if (cfg.parsecode) { + if (nesting || s[sl - 1].length == 1) + handleError({ + t: "Unclosed " + s[sl-1] + " found at end in codemode", + p: str_len + },last_line); + if (segment!=ol) + o_segs++ + }else if( (ol==7 || ol==8) && o_segs == 1) { + is_single_prop = 0; + for (c in o_props)is_single_prop++; + if (is_single_prop!=1)is_single_prop = 0; + } + if ((!cfg.nostring && !cfg.event)&& (parse_mode == 2 && segment == 4 || ol == 4)) { + return { + type: 2, + str: o.slice(5, -1).join("").replace(/\\n/g, "\n").replace(/\\"/g, '"') + }; // string only + } + if (o_asyncs || cfg.alwayscb) { + + if (cfg.event) { // event + if (parse_mode == 1) + o[3] = ""; + o[ol++] = cc_o_blk_ce; + } + else if (c_xpathmode) { // object return + if (parse_mode == 1) { + o[3] = (o[3] != cf_block_o) ? cc_o_blk_o : cc_o_blk_ob, + o[ol++] = cc_o_blk_cb; + } + else + o[3] = cc_o_cb_o, o[ol++] = cc_o_cb_c; + } + else { // value return + if (parse_mode == 1) + o[3] = (o[3] != cf_block_o) ? cc_v_blk_o : cc_v_blk_ob, + o[ol++] = cc_v_blk_cb; + else + o[3] = cc_v_cb_o, o[ol++] = cc_v_cb_c; + } + + if (o_asyncs) { + // for parse_mode == 1 we can squeeze in before [3] and cb close + // else we put var _r= in 3 and put our ending last and put + // the cb at the end + if (parse_mode==1) { + if (cfg.precall) + o[2] = cc_pc_o, o[ol-1] = cc_pc_c + o[ol-1]; + else + o[2] = cc_async_o, o[ol-1] = cc_async_c + o[ol-1]; + }else{ + o[ol++] = o[3] + '_r' + o[ol-2]; + if (cfg.precall) + o[2] = cc_pc_o, o[3] = cc_o_blk_o, o[ol-2] = cc_pc_c; + else + o[2] = cc_async_o, o[3] = cc_o_blk_o, o[ol-2] = cc_async_c; + } + } + + if (cfg.withopt) + o[1] = cc_opt_o, o[ol++] = cc_opt_c; + + o[0] = cfg.event + ? cc_fe_async_o + : ((c_xpathmode == 1 || c_xpathmode == 3) ? cc_fc_async_o : cc_f_async_o); + o[ol++] = cc_f_c; + } + else { + if (cfg.event) { // event + if (parse_mode == 1) + o[3] = ""; + } + else if (c_xpathmode) { // object return + if (parse_mode == 1) { + o[3] = (o[3] != cf_block_o) ? cc_o_blk_o : cc_o_blk_ob, + o[ol++] = cc_o_blk_c; + } + else + o[3] = cc_o_ret_o, o[ol++] = cc_o_ret_c; + } + else { // value return + if (parse_mode == 1) { + o[3] = (o[3] != cf_block_o) ? cc_v_blk_o : cc_v_blk_ob, + o[ol++] = cc_v_blk_c; + } + else + o[3] = cc_v_ret_o, o[ol++] = cc_v_ret_c; + } + if (cfg.withopt) + o[2] = cc_opt_o, o[ol++] = cc_opt_c; + + o[0] = cfg.event + ? (cfg.withopt ? cc_fe_opt_o : cc_fe_o) + : (cfg.withopt + ? ((c_xpathmode == 1 || c_xpathmode == 3) ? cc_fc_opt_o : cc_f_opt_o) + : ((c_xpathmode == 1 || c_xpathmode == 3) ? cc_fc_o : cc_f_o)); + o[ol++] = cc_f_c; + } + + var code = "with(apf.nameserver.lookup.all){\n" + o.join("") + "\n}"; + + if (cfg.nothrow) { + f = apf.lm_exec.compile(code); + } + else { + try { + f = apf.lm_exec.compile(code); + } + catch (e) { + if (!apf.isIE) { + var oErr = window.onerror; + window.onerror = function(x,y,line) { + window.onerror = oErr; + handleError(e, last_line, null, line); + return true; + } + apf.include("", "", null, o.join("")); + window.onerror = oErr; + } + else { + handleError(e,last_line); + } + return null; + } + } + f.type = (o_segs == 1 && o_xpaths == 1) ? 3 : (is_single_prop?4:1); + f.xpaths = o_xpathpairs, f.models = o_models, + f.props = o_props, f.asyncs = o_asyncs; + + cache[key] = f; + return f; + }; + + /** + * description of the method. + * Remarks: + * @param {String} str the code to compile + * @param {Object} options + * Properties: + * {Boolean} node tries to return a node, used as a dual-compile with 'normal mode' + * + * @return {Function} returns a function with extra properties + * Properties: + * {Number} type description + * Possible values: + * 1 Function return type + * 2 Parsed data is a pure string + * 3 Function return type, but its a single xpath + * {Array} xpaths array of [model,xpath, model,xpath] pairs if model + * or xpath is '#', its dynamic if model is null its a local xpath + * {Number} models number of models + * {Array} props description + * {Number} asyncs description + * {String] str optional, returned with type 2 + */ + + this.compileMatch = function(strarray, cfg) { + if (!cfg) + cfg = emptyCfg; + + o_props = {}, o_xpathpairs = [], o = [cc_f_match_o, cc_m_o], s = [], + nesting = 0, ol = o.length, xpath_lut_node = xpath_lut_node_normal; + + for (var st, ob, i = 0, j = strarray.length; i < j; i += 2) { + if (str = strarray[i]) { + str_len = s.length, c_xpathmode = 2; + if (i) + o[ol++] = cc_m_brk; + o[ol++] = ""; + s[0] = ob = ol = scope = segment = o.length, cf_mode_output = cf_obj_output; + line_no = last_type = o_segs = o_xpaths = o_asyncs = parse_mode = last_line = 0; + sl = 2, s[1] = "{{", last_tok = "{"; + c_injectself = 1; + + if (cfg.nothrow) { + str.replace(parserx, parser); + } + else { + try { + str.replace(parserx, parser); + } + catch (e) { + handleError(e,last_line); + return null; + } + } + + if (nesting || s[sl - 1].length == 1) + handleError({ + t: "Unclosed " + s[sl - 1] + " found at end in codemode", + p: str_len + }); + + if (o_asyncs) + handleError({t:"Asynchronous calls not supported in match/value"}); + + if (parse_mode == 1) { // block mode + o[ob - 1] = (o[ob - 1] != cf_block_o) ? cf_mode_output : "", + o[ol++] = cc_m_m_blk; + } + else // value mode + o[ob-1] = cc_m_m_value_o, o[ol++] = cc_m_m_value_c; + } + if (str = strarray[i + 1]) { + str_len = s.length; + if (!strarray[i] && i) + o[ol++] = cc_m_brk; + o[ol++] = ""; + ob = ol = scope = segment = o.length, cf_mode_output = cf_str_output; + c_xpathmode = c_injectself = last_tok = sl = line_no = o_segs = o_xpaths = + last_type = o_asyncs = last_line = 0; + if (cfg.node) + c_xpathmode = 2; + parse_mode = 2, c_injectself = 0; + + if (cfg.nothrow) { + str.replace(parserx, parser); + } + else { + try { + str.replace(parserx, parser); + } + catch (e) { + handleError(e,last_line); + return null; + } + } + + if (o_asyncs) + handleError({t:"Asynchronous calls not supported in match/value"}); + + if (cfg.node) { + if (parse_mode == 2 && segment == ob || ol == ob) + o[ob-1] = cc_m_n_string; + else + o[ob-1] = cc_m_n_o, o[ol++] = cc_m_n_c; + }else{ + if (parse_mode == 2 && segment == ob || ol == ob) + o[ob-1] = cc_m_v_string; + else + o[ob-1] = cc_m_v_o, o[ol++] = cc_m_v_c; + } + + if (strarray[i]) + o[ol++] = cc_m_c; + else + break; + } + else { + if (!strarray[i]) + handleError({t:"Both match and value are empty"}); + + if (cfg.node) + o[ol++] = cc_m_n_ret; + else + o[ol++] = cc_m_v_ret; + + c_xpathmode = 2; + + o[ol++] = cc_m_c; + } + } + o[ol++] = cc_f_c; + + var f; + if (cfg.nothrow) { + f = apf.lm_exec.compile(o.join("")); + } + else { + try{ + f = apf.lm_exec.compile(o.join("")); + } + catch (e) { + handleError(e,last_line); + return null; + } + } + + f.type = 1, f.xpaths = o_xpathpairs, + f.props = o_props, f.asyncs = o_asyncs; + return f; + }; + + this.setWarnLevel = function(lvl) { + apf.lm_exec.setWarnLevel(lvl); + }; + + this.parseExpression = function(istr, cfg) { + if (!cfg) + cfg = emptyCfg; + + o_props = {}, o_xpathpairs = [], o = [], s = [], + nesting = 0, xpath_lut_node = xpath_lut_node_normal; + str = istr, str_len = str.length; + ob = ol = scope = segment = o.length, cf_mode_output = cf_str_output; + c_xpathmode = c_injectself = last_tok = sl = line_no = o_segs = o_xpaths = + last_type = o_asyncs = last_line = 0; + parse_mode = 2; + + if (cfg.nothrow) { + str.replace(parserx, parser); + } + else { + try { + str.replace(parserx, parser); + } + catch (e) { + handleError(e,last_line); + return null; + } + } + return o.join(''); + } + + +})(); + +// apf lm_exec makes sure there is no scope pollution for eval'ed live markup. +apf.lm_exec = new (function(){ + + var wlvl = 1; // 0: no warnings 1: language/models missing, 2:nodes missing, 3:all failed xpaths + + //warning functions + this.setWarnLevel = function(lvl) { + wlvl = lvl; + }; + + function wxpath(x, t) { + apf.console.warn("Live Markup warning in " + t + ", no results for xpath: '" + x + "'"); + } + + function wnode(x, t) { + apf.console.warn("Live Markup warning in " + t + ", xpath on null node: '" + x + "'"); + } + + function wmodel(m, x, t) { + apf.console.log("Live Markup warning in " + t + ", xpath on empty model: '" + m + "' xpath: '" + x + "'"); + } + + function wlang(x, t) { + apf.console.log("Live Markup warning in " + t + ", language symbol not found: '" + x + "'"); + } + + // xml parse function used by all livemarkup objects + function xmlParse(str) { + var n = apf.getXmlDom("<_apflmlist_>" + str + ""); + if (!n || !(n = n.documentElement)) + return null; + return (n.firstChild == n.lastChild) ? n.firstChild : n; + } + + // value of node by xpath + function __val(n, x) { + if (!n) + return ("") + return apf.escapeXML((n = (!n.nodeType && n || (n = n.selectSingleNode(x)) //!= 1 + && (n.nodeType != 1 && n || (n = n.firstChild) && n.nodeType!=1 && n))) + && n.nodeValue || ("")); + } + + var __valattrrx = /(["'])/g; + function __valattrrp(m,a) { + return m=='"'?""":"'"; + } + function __valattr(n, x) { + if (!n) + return ("") + return apf.escapeXML((n = (n.nodeType != 1 && n || (n = n.selectSingleNode(x)) + && (n.nodeType != 1 && n || (n = n.firstChild) && n.nodeType!=1 && n))) + && n.nodeValue.replace(__valattrrx,__valattrrp) || ("")); + } + + + // value of model node by xpath + function __valm(m, x) { + var n; + if (!m || !(n = (m.charAt && ((m.charAt(0) == "<" && xmlParse(m)) + || ((n = apf.nameserver.lookup.model[m]) && n.data))) + || (m.$isModel ? m.data : (m.charAt ? 0 : m)))) + return (""); + return (n = (n.nodeType != 1 && n || (n = n.selectSingleNode(x)) + && (n.nodeType != 1 && n || (n = n.firstChild) && n.nodeType!=1 && n))) + && n.nodeValue || (""); + } + + function __nod(n, x){ // node by xpath + return n ? n.selectSingleNode(x) : (null); + } + + function _nods(n, x){ // array of nodes by xpath + return n ? n.selectNodes(x) : ([]); + } + + function __nodm(m, x){ // node of model by xpath + var n; + if (!m || !(n = (m.charAt && ((m.charAt(0) == "<" && xmlParse(m)) + || ((n = apf.nameserver.lookup.model[m]) && n.data))) + || (m.$isModel ? m.data : (m.charAt ? 0 : m)))) + return (null); + + return n.selectSingleNode(x); + } + + function _nodsm(m, x){ // array of nodes from model by xpath + var n; + if (!m || !(n = (m.charAt && ((m.charAt(0) == "<" && xmlParse(m)) + || ((n = apf.nameserver.lookup.model[m]) && n.data))) + || (m.$isModel ? m.data : (m.charAt ? 0 : m)))) + return ([]); + + return n.selectNodes(x); + } + + function __cnt(n, x){ // count nodes by xpath + return n ? n.selectNodes(x).length:(0); + } + + function __cntm(m, x){ // count nodes from model by xpath + var n; + if (!m || !(n = (m.charAt && ((m.charAt(0) == "<" && xmlParse(m)) + || ((n = apf.nameserver.lookup.model[m]) && n.data))) + || (m.$isModel ? m.data : (m.charAt ? 0 : m)))) + return (0); + + return n.selectNodes(x).length; + } + + function _xpt(n, x){ // return the query wrapped in an object + return { + xpath: x, + toString: function(){ + return "LM Xpath object: " + this.x + } + }; + } + + function _xptm(m, x){ // return the query with model wrapped in an object + if (m && !m.$isModel) { + var node = m; + m = apf.xmldb.findModel(m); + x = apf.xmlToXpath(node, m.data) + "/" + x; + } + + return { + model: m, + xpath: x, + toString: function(){ + return "LM Xpath object with model: " + this.x + } + }; + } + + //----- the following functions are combined model and normal mode ------ + + function _xml(n, m, x){ // serialize node by xpath via .xml + if (n) x = m; + else if (!m || !(n=(m.charAt && ((m.charAt(0)=="<" && xmlParse(m)) || + ((n = apf.nameserver.lookup.model[m]) && n.data))) || + (m.$isModel?m.data:(m.charAt?0:m)))) + return (""); + + return (n && (n = n.selectSingleNode(x))) && n.xml || + (""); + } + + function _xmls(n, m, x){ // serialize nodes by xpath with .xml concatenated + if (n) x = m; + else if (!m || !(n=(m.charAt && ((m.charAt(0)=="<" && xmlParse(m)) || + ((n = apf.nameserver.lookup.model[m]) && n.data))) || + (m.$isModel?m.data:(m.charAt?0:m)))) + return (""); + for (var i = 0,j = ((n=n.selectNodes(x))).length,o = [];i' + ((n?__val(n,m):__valm(m,x)) || " ") + ''; + } + +// function _edit(n, opts) { +// return '' + ((n?__val(n,m):__valm(m,x)) || " ") + ''; +// } + + function _argwrap(n,x) { + return [n,x]; + } + + function _argwrapm(m,x) { + return [0,m,x]; + } + + function _valedx(editMode, args, opt){ // wrap a value with editable div + args[3] = opt; + args[4] = editMode; + return _valed.apply(this, args); + } + + function _valed(n, m, x, options, editMode){ // wrap a value with editable div + var res = (n?__val(n,m):__valm(m,x)); + + if (options && options.multiline && options.editor != "richtext") + res = res.replace(/\n/g, "
      "); + + if (editMode !== false) { + var value = res || options && options.initial || " "; + if (!options || !options.richtext) + value = apf.htmlentities(value); + if (options && options.multiline) + value = value + .replace(/<br ?\/?>/g, "
      ") + .replace(/<(\/?div)>/g, "<$1>"); + + return '' + value + + '
    3. element + tree.insertElement(name, attributes); + tree.framesetOk = false; + }; + + modes.inBody.startTagPlaintext = function(name, attributes) { + if (tree.openElements.inButtonScope('p')) + this.endTagP('p'); + tree.insertElement(name, attributes); + tree.tokenizer.setState(Tokenizer.PLAINTEXT); + }; + + modes.inBody.startTagHeading = function(name, attributes) { + if (tree.openElements.inButtonScope('p')) + this.endTagP('p'); + if (tree.currentStackItem().isNumberedHeader()) { + tree.parseError('unexpected-start-tag', {name: name}); + tree.popElement(); + } + tree.insertElement(name, attributes); + }; + + modes.inBody.startTagA = function(name, attributes) { + var activeA = tree.elementInActiveFormattingElements('a'); + if (activeA) { + tree.parseError("unexpected-start-tag-implies-end-tag", {startName: "a", endName: "a"}); + tree.adoptionAgencyEndTag('a'); + if (tree.openElements.contains(activeA)) + tree.openElements.remove(activeA); + tree.removeElementFromActiveFormattingElements(activeA); + } + tree.reconstructActiveFormattingElements(); + tree.insertFormattingElement(name, attributes); + }; + + modes.inBody.startTagFormatting = function(name, attributes) { + tree.reconstructActiveFormattingElements(); + tree.insertFormattingElement(name, attributes); + }; + + modes.inBody.startTagNobr = function(name, attributes) { + tree.reconstructActiveFormattingElements(); + if (tree.openElements.inScope('nobr')) { + tree.parseError("unexpected-start-tag-implies-end-tag", {startName: 'nobr', endName: 'nobr'}); + this.processEndTag('nobr'); + // XXX Need tests that trigger the following + tree.reconstructActiveFormattingElements(); + } + tree.insertFormattingElement(name, attributes); + }; + + modes.inBody.startTagButton = function(name, attributes) { + if (tree.openElements.inScope('button')) { + tree.parseError('unexpected-start-tag-implies-end-tag', {startName: 'button', endName: 'button'}); + this.processEndTag('button'); + tree.insertionMode.processStartTag(name, attributes); + } else { + tree.framesetOk = false; + tree.reconstructActiveFormattingElements(); + tree.insertElement(name, attributes); + } + }; + + modes.inBody.startTagAppletMarqueeObject = function(name, attributes) { + tree.reconstructActiveFormattingElements(); + tree.insertElement(name, attributes); + tree.activeFormattingElements.push(Marker); + tree.framesetOk = false; + }; + + modes.inBody.endTagAppletMarqueeObject = function(name) { + if (!tree.openElements.inScope(name)) { + tree.parseError("unexpected-end-tag", {name: name}); + } else { + tree.generateImpliedEndTags(); + if (tree.currentStackItem().localName != name) { + tree.parseError('end-tag-too-early', {name: name}); + } + tree.openElements.popUntilPopped(name); + tree.clearActiveFormattingElements(); + } + }; + + modes.inBody.startTagXmp = function(name, attributes) { + if (tree.openElements.inButtonScope('p')) + this.processEndTag('p'); + tree.reconstructActiveFormattingElements(); + tree.processGenericRawTextStartTag(name, attributes); + tree.framesetOk = false; + }; + + modes.inBody.startTagTable = function(name, attributes) { + if (tree.compatMode !== "quirks") + if (tree.openElements.inButtonScope('p')) + this.processEndTag('p'); + tree.insertElement(name, attributes); + tree.setInsertionMode('inTable'); + tree.framesetOk = false; + }; + + modes.inBody.startTagVoidFormatting = function(name, attributes) { + tree.reconstructActiveFormattingElements(); + tree.insertSelfClosingElement(name, attributes); + tree.framesetOk = false; + }; + + modes.inBody.startTagParamSourceTrack = function(name, attributes) { + tree.insertSelfClosingElement(name, attributes); + }; + + modes.inBody.startTagHr = function(name, attributes) { + if (tree.openElements.inButtonScope('p')) + this.endTagP('p'); + tree.insertSelfClosingElement(name, attributes); + tree.framesetOk = false; + }; + + modes.inBody.startTagImage = function(name, attributes) { + // No, really... + tree.parseError('unexpected-start-tag-treated-as', {originalName: 'image', newName: 'img'}); + this.processStartTag('img', attributes); + }; + + modes.inBody.startTagInput = function(name, attributes) { + var currentFramesetOk = tree.framesetOk; + this.startTagVoidFormatting(name, attributes); + for (var key in attributes) { + // input type=hidden doesn't change framesetOk + if (attributes[key].nodeName == 'type') { + if (attributes[key].nodeValue.toLowerCase() == 'hidden') + tree.framesetOk = currentFramesetOk; + break; + } + } + }; + + modes.inBody.startTagIsindex = function(name, attributes) { + tree.parseError('deprecated-tag', {name: 'isindex'}); + tree.selfClosingFlagAcknowledged = true; + if (tree.form) + return; + var formAttributes = []; + var inputAttributes = []; + var prompt = "This is a searchable index. Enter search keywords: "; + for (var key in attributes) { + switch (attributes[key].nodeName) { + case 'action': + formAttributes.push({nodeName: 'action', + nodeValue: attributes[key].nodeValue}); + break; + case 'prompt': + prompt = attributes[key].nodeValue; + break; + case 'name': + break; + default: + inputAttributes.push({nodeName: attributes[key].nodeName, + nodeValue: attributes[key].nodeValue}); + } + } + inputAttributes.push({nodeName: 'name', nodeValue: 'isindex'}); + this.processStartTag('form', formAttributes); + this.processStartTag('hr'); + this.processStartTag('label'); + this.processCharacters(new CharacterBuffer(prompt)); + this.processStartTag('input', inputAttributes); + this.processEndTag('label'); + this.processStartTag('hr'); + this.processEndTag('form'); + }; + + modes.inBody.startTagTextarea = function(name, attributes) { + // XXX Form element pointer checking here as well... + tree.insertElement(name, attributes); + tree.tokenizer.setState(Tokenizer.RCDATA); + tree.originalInsertionMode = tree.insertionModeName; + tree.shouldSkipLeadingNewline = true; + tree.framesetOk = false; + tree.setInsertionMode('text'); + }; + + modes.inBody.startTagIFrame = function(name, attributes) { + tree.framesetOk = false; + this.startTagRawText(name, attributes); + }; + + modes.inBody.startTagRawText = function(name, attributes) { + tree.processGenericRawTextStartTag(name, attributes); + }; + + modes.inBody.startTagSelect = function(name, attributes) { + tree.reconstructActiveFormattingElements(); + tree.insertElement(name, attributes); + tree.framesetOk = false; + var insertionModeName = tree.insertionModeName; + if (insertionModeName == 'inTable' || + insertionModeName == 'inCaption' || + insertionModeName == 'inColumnGroup' || + insertionModeName == 'inTableBody' || + insertionModeName == 'inRow' || + insertionModeName == 'inCell') { + tree.setInsertionMode('inSelectInTable'); + } else { + tree.setInsertionMode('inSelect'); + } + }; + + modes.inBody.startTagMisplaced = function(name, attributes) { + tree.parseError('unexpected-start-tag-ignored', {name: name}); + }; + + modes.inBody.endTagMisplaced = function(name) { + // This handles elements with end tags in other insertion modes. + tree.parseError("unexpected-end-tag", {name: name}); + }; + + modes.inBody.endTagBr = function(name) { + tree.parseError("unexpected-end-tag-treated-as", {originalName: "br", newName: "br element"}); + tree.reconstructActiveFormattingElements(); + tree.insertElement(name, []); + tree.popElement(); + }; + + modes.inBody.startTagOptionOptgroup = function(name, attributes) { + if (tree.currentStackItem().localName == 'option') + tree.popElement(); + tree.reconstructActiveFormattingElements(); + tree.insertElement(name, attributes); + }; + + modes.inBody.startTagOther = function(name, attributes) { + tree.reconstructActiveFormattingElements(); + tree.insertElement(name, attributes); + }; + + modes.inBody.endTagOther = function(name) { + var node; + for (var i = tree.openElements.length - 1; i > 0; i--) { + node = tree.openElements.item(i); + if (node.localName == name) { + tree.generateImpliedEndTags(name); + if (tree.currentStackItem().localName != name) + tree.parseError('unexpected-end-tag', {name: name}); + // todo optimize + tree.openElements.remove_openElements_until(function(x) {return x === node;}); + break; + } + if (node.isSpecial()) { + tree.parseError('unexpected-end-tag', {name: name}); + break; + } + } + }; + + modes.inBody.startTagMath = function(name, attributes, selfClosing) { + tree.reconstructActiveFormattingElements(); + attributes = tree.adjustMathMLAttributes(attributes); + attributes = tree.adjustForeignAttributes(attributes); + tree.insertForeignElement(name, attributes, "http://www.w3.org/1998/Math/MathML", selfClosing); + // Need to get the parse error right for the case where the token + // has a namespace not equal to the xmlns attribute + }; + + modes.inBody.startTagSVG = function(name, attributes, selfClosing) { + tree.reconstructActiveFormattingElements(); + attributes = tree.adjustSVGAttributes(attributes); + attributes = tree.adjustForeignAttributes(attributes); + tree.insertForeignElement(name, attributes, "http://www.w3.org/2000/svg", selfClosing); + // Need to get the parse error right for the case where the token + // has a namespace not equal to the xmlns attribute + }; + + modes.inBody.endTagP = function(name) { + if (!tree.openElements.inButtonScope('p')) { + tree.parseError('unexpected-end-tag', {name: 'p'}); + this.startTagCloseP('p', []); + this.endTagP('p'); + } else { + tree.generateImpliedEndTags('p'); + if (tree.currentStackItem().localName != 'p') + tree.parseError('unexpected-implied-end-tag', {name: 'p'}); + tree.openElements.popUntilPopped(name); + } + }; + + modes.inBody.endTagBody = function(name) { + if (!tree.openElements.inScope('body')) { + tree.parseError('unexpected-end-tag', {name: name}); + return; + } + + /// @todo Emit parse error on end tags other than the ones listed in http://www.w3.org/TR/html5/tree-construction.html#parsing-main-inbody + // ['dd', 'dt', 'li', 'optgroup', 'option', 'p', 'rp', 'rt', 'tbody', 'td', 'tfoot', 'th', 'thead', 'tr', 'body', 'html'] + if (tree.currentStackItem().localName != 'body') { + tree.parseError('expected-one-end-tag-but-got-another', { + expectedName: tree.currentStackItem().localName, + gotName: name + }); + } + tree.setInsertionMode('afterBody'); + }; + + modes.inBody.endTagHtml = function(name) { + if (!tree.openElements.inScope('body')) { + tree.parseError('unexpected-end-tag', {name: name}); + return; + } + + /// @todo Emit parse error on end tags other than the ones listed in http://www.w3.org/TR/html5/tree-construction.html#parsing-main-inbody + // ['dd', 'dt', 'li', 'optgroup', 'option', 'p', 'rp', 'rt', 'tbody', 'td', 'tfoot', 'th', 'thead', 'tr', 'body', 'html'] + if (tree.currentStackItem().localName != 'body') { + tree.parseError('expected-one-end-tag-but-got-another', { + expectedName: tree.currentStackItem().localName, + gotName: name + }); + } + tree.setInsertionMode('afterBody'); + tree.insertionMode.processEndTag(name); + }; + + modes.inBody.endTagBlock = function(name) { + if (!tree.openElements.inScope(name)) { + tree.parseError('unexpected-end-tag', {name: name}); + } else { + tree.generateImpliedEndTags(); + if (tree.currentStackItem().localName != name) { + tree.parseError('end-tag-too-early', {name: name}); + } + tree.openElements.popUntilPopped(name); + } + }; + + modes.inBody.endTagForm = function(name) { + var node = tree.form; + tree.form = null; + if (!node || !tree.openElements.inScope(name)) { + tree.parseError('unexpected-end-tag', {name: name}); + } else { + tree.generateImpliedEndTags(); + if (tree.currentStackItem() != node) { + tree.parseError('end-tag-too-early-ignored', {name: 'form'}); + } + tree.openElements.remove(node); + } + }; + + modes.inBody.endTagListItem = function(name) { + if (!tree.openElements.inListItemScope(name)) { + tree.parseError('unexpected-end-tag', {name: name}); + } else { + tree.generateImpliedEndTags(name); + if (tree.currentStackItem().localName != name) + tree.parseError('end-tag-too-early', {name: name}); + tree.openElements.popUntilPopped(name); + } + }; + + modes.inBody.endTagHeading = function(name) { + if (!tree.openElements.hasNumberedHeaderElementInScope()) { + tree.parseError('unexpected-end-tag', {name: name}); + return; + } + tree.generateImpliedEndTags(); + if (tree.currentStackItem().localName != name) + tree.parseError('end-tag-too-early', {name: name}); + + tree.openElements.remove_openElements_until(function(e) { + return e.isNumberedHeader(); + }); + }; + + modes.inBody.endTagFormatting = function(name, attributes) { + if (!tree.adoptionAgencyEndTag(name)) + this.endTagOther(name, attributes); + }; + + modes.inCaption = Object.create(modes.base); + + modes.inCaption.start_tag_handlers = { + html: 'startTagHtml', + caption: 'startTagTableElement', + col: 'startTagTableElement', + colgroup: 'startTagTableElement', + tbody: 'startTagTableElement', + td: 'startTagTableElement', + tfoot: 'startTagTableElement', + thead: 'startTagTableElement', + tr: 'startTagTableElement', + '-default': 'startTagOther' + }; + + modes.inCaption.end_tag_handlers = { + caption: 'endTagCaption', + table: 'endTagTable', + body: 'endTagIgnore', + col: 'endTagIgnore', + colgroup: 'endTagIgnore', + html: 'endTagIgnore', + tbody: 'endTagIgnore', + td: 'endTagIgnore', + tfood: 'endTagIgnore', + thead: 'endTagIgnore', + tr: 'endTagIgnore', + '-default': 'endTagOther' + }; + + modes.inCaption.processCharacters = function(data) { + modes.inBody.processCharacters(data); + }; + + modes.inCaption.startTagTableElement = function(name, attributes) { + tree.parseError('unexpected-end-tag', {name: name}); + var ignoreEndTag = !tree.openElements.inTableScope('caption'); + tree.insertionMode.processEndTag('caption'); + if (!ignoreEndTag) tree.insertionMode.processStartTag(name, attributes); + }; + + modes.inCaption.startTagOther = function(name, attributes, selfClosing) { + modes.inBody.processStartTag(name, attributes, selfClosing); + }; + + modes.inCaption.endTagCaption = function(name) { + if (!tree.openElements.inTableScope('caption')) { + // context case + assert.ok(tree.context); + tree.parseError('unexpected-end-tag', {name: name}); + } else { + // AT this code is quite similar to endTagTable in inTable + tree.generateImpliedEndTags(); + if (tree.currentStackItem().localName != 'caption') { + // @todo this is confusing for implied end tag + tree.parseError('expected-one-end-tag-but-got-another', { + gotName: "caption", + expectedName: tree.currentStackItem().localName + }); + } + tree.openElements.popUntilPopped('caption'); + tree.clearActiveFormattingElements(); + tree.setInsertionMode('inTable'); + } + }; + + modes.inCaption.endTagTable = function(name) { + tree.parseError("unexpected-end-table-in-caption"); + var ignoreEndTag = !tree.openElements.inTableScope('caption'); + tree.insertionMode.processEndTag('caption'); + if (!ignoreEndTag) tree.insertionMode.processEndTag(name); + }; + + modes.inCaption.endTagIgnore = function(name) { + tree.parseError('unexpected-end-tag', {name: name}); + }; + + modes.inCaption.endTagOther = function(name) { + modes.inBody.processEndTag(name); + }; + + modes.inCell = Object.create(modes.base); + + modes.inCell.start_tag_handlers = { + html: 'startTagHtml', + caption: 'startTagTableOther', + col: 'startTagTableOther', + colgroup: 'startTagTableOther', + tbody: 'startTagTableOther', + td: 'startTagTableOther', + tfoot: 'startTagTableOther', + th: 'startTagTableOther', + thead: 'startTagTableOther', + tr: 'startTagTableOther', + '-default': 'startTagOther' + }; + + modes.inCell.end_tag_handlers = { + td: 'endTagTableCell', + th: 'endTagTableCell', + body: 'endTagIgnore', + caption: 'endTagIgnore', + col: 'endTagIgnore', + colgroup: 'endTagIgnore', + html: 'endTagIgnore', + table: 'endTagImply', + tbody: 'endTagImply', + tfoot: 'endTagImply', + thead: 'endTagImply', + tr: 'endTagImply', + '-default': 'endTagOther' + }; + + modes.inCell.processCharacters = function(data) { + modes.inBody.processCharacters(data); + }; + + modes.inCell.startTagTableOther = function(name, attributes, selfClosing) { + if (tree.openElements.inTableScope('td') || tree.openElements.inTableScope('th')) { + this.closeCell(); + tree.insertionMode.processStartTag(name, attributes, selfClosing); + } else { + // context case + tree.parseError('unexpected-start-tag', {name: name}); + } + }; + + modes.inCell.startTagOther = function(name, attributes, selfClosing) { + modes.inBody.processStartTag(name, attributes, selfClosing); + }; + + modes.inCell.endTagTableCell = function(name) { + if (tree.openElements.inTableScope(name)) { + tree.generateImpliedEndTags(name); + if (tree.currentStackItem().localName != name.toLowerCase()) { + tree.parseError('unexpected-cell-end-tag', {name: name}); + tree.openElements.popUntilPopped(name); + } else { + tree.popElement(); + } + tree.clearActiveFormattingElements(); + tree.setInsertionMode('inRow'); + } else { + tree.parseError('unexpected-end-tag', {name: name}); + } + }; + + modes.inCell.endTagIgnore = function(name) { + tree.parseError('unexpected-end-tag', {name: name}); + }; + + modes.inCell.endTagImply = function(name) { + if (tree.openElements.inTableScope(name)) { + this.closeCell(); + tree.insertionMode.processEndTag(name); + } else { + // sometimes context case + tree.parseError('unexpected-end-tag', {name: name}); + } + }; + + modes.inCell.endTagOther = function(name) { + modes.inBody.processEndTag(name); + }; + + modes.inCell.closeCell = function() { + if (tree.openElements.inTableScope('td')) { + this.endTagTableCell('td'); + } else if (tree.openElements.inTableScope('th')) { + this.endTagTableCell('th'); + } + }; + + + modes.inColumnGroup = Object.create(modes.base); + + modes.inColumnGroup.start_tag_handlers = { + html: 'startTagHtml', + col: 'startTagCol', + '-default': 'startTagOther' + }; + + modes.inColumnGroup.end_tag_handlers = { + colgroup: 'endTagColgroup', + col: 'endTagCol', + '-default': 'endTagOther' + }; + + modes.inColumnGroup.ignoreEndTagColgroup = function() { + return tree.currentStackItem().localName == 'html'; + }; + + modes.inColumnGroup.processCharacters = function(buffer) { + var leadingWhitespace = buffer.takeLeadingWhitespace(); + if (leadingWhitespace) + tree.insertText(leadingWhitespace); + if (!buffer.length) + return; + var ignoreEndTag = this.ignoreEndTagColgroup(); + this.endTagColgroup('colgroup'); + if (!ignoreEndTag) tree.insertionMode.processCharacters(buffer); + }; + + modes.inColumnGroup.startTagCol = function(name, attributes) { + tree.insertSelfClosingElement(name, attributes); + }; + + modes.inColumnGroup.startTagOther = function(name, attributes, selfClosing) { + var ignoreEndTag = this.ignoreEndTagColgroup(); + this.endTagColgroup('colgroup'); + if (!ignoreEndTag) tree.insertionMode.processStartTag(name, attributes, selfClosing); + }; + + modes.inColumnGroup.endTagColgroup = function(name) { + if (this.ignoreEndTagColgroup()) { + // context case + assert.ok(tree.context); + tree.parseError('unexpected-end-tag', {name: name}); + } else { + tree.popElement(); + tree.setInsertionMode('inTable'); + } + }; + + modes.inColumnGroup.endTagCol = function(name) { + tree.parseError("no-end-tag", {name: 'col'}); + }; + + modes.inColumnGroup.endTagOther = function(name) { + var ignoreEndTag = this.ignoreEndTagColgroup(); + this.endTagColgroup('colgroup'); + if (!ignoreEndTag) tree.insertionMode.processEndTag(name) ; + }; + + modes.inForeignContent = Object.create(modes.base); + + modes.inForeignContent.processStartTag = function(name, attributes, selfClosing) { + if (['b', 'big', 'blockquote', 'body', 'br', 'center', 'code', 'dd', 'div', 'dl', 'dt', 'em', 'embed', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'hr', 'i', 'img', 'li', 'listing', 'menu', 'meta', 'nobr', 'ol', 'p', 'pre', 'ruby', 's', 'small', 'span', 'strong', 'strike', 'sub', 'sup', 'table', 'tt', 'u', 'ul', 'var'].indexOf(name) != -1 + || (name == 'font' && attributes.some(function(attr){ return ['color', 'face', 'size'].indexOf(attr.nodeName) >= 0 }))) { + tree.parseError('unexpected-html-element-in-foreign-content', {name: name}); + while (tree.currentStackItem().isForeign() + && !tree.currentStackItem().isHtmlIntegrationPoint() + && !tree.currentStackItem().isMathMLTextIntegrationPoint()) { + tree.openElements.pop(); + } + tree.insertionMode.processStartTag(name, attributes, selfClosing); + return; + } + if (tree.currentStackItem().namespaceURI == "http://www.w3.org/1998/Math/MathML") { + attributes = tree.adjustMathMLAttributes(attributes); + } + if (tree.currentStackItem().namespaceURI == "http://www.w3.org/2000/svg") { + name = tree.adjustSVGTagNameCase(name); + attributes = tree.adjustSVGAttributes(attributes); + } + attributes = tree.adjustForeignAttributes(attributes); + tree.insertForeignElement(name, attributes, tree.currentStackItem().namespaceURI, selfClosing); + }; + + modes.inForeignContent.processEndTag = function(name) { + var node = tree.currentStackItem(); + var index = tree.openElements.length - 1; + if (node.localName.toLowerCase() != name) + tree.parseError("unexpected-end-tag", {name: name}); + + while (true) { + if (index === 0) + break; + if (node.localName.toLowerCase() == name) { + while (tree.openElements.pop() != node); + break; + } + index -= 1; + node = tree.openElements.item(index); + if (node.isForeign()) { + continue; + } else { + tree.insertionMode.processEndTag(name); + break; + } + } + }; + + modes.inForeignContent.processCharacters = function(buffer) { + var characters = buffer.takeRemaining(); + characters = characters.replace(/\u0000/g, function(match, index){ + // @todo position + tree.parseError('invalid-codepoint'); + return '\uFFFD'; + }); + if (tree.framesetOk && !isAllWhitespaceOrReplacementCharacters(characters)) + tree.framesetOk = false; + tree.insertText(characters); + }; + + modes.inHeadNoscript = Object.create(modes.base); + + modes.inHeadNoscript.start_tag_handlers = { + html: 'startTagHtml', + basefont: 'startTagBasefontBgsoundLinkMetaNoframesStyle', + bgsound: 'startTagBasefontBgsoundLinkMetaNoframesStyle', + link: 'startTagBasefontBgsoundLinkMetaNoframesStyle', + meta: 'startTagBasefontBgsoundLinkMetaNoframesStyle', + noframes: 'startTagBasefontBgsoundLinkMetaNoframesStyle', + style: 'startTagBasefontBgsoundLinkMetaNoframesStyle', + head: 'startTagHeadNoscript', + noscript: 'startTagHeadNoscript', + "-default": 'startTagOther' + }; + + modes.inHeadNoscript.end_tag_handlers = { + noscript: 'endTagNoscript', + br: 'endTagBr', + '-default': 'endTagOther' + }; + + modes.inHeadNoscript.processCharacters = function(buffer) { + var leadingWhitespace = buffer.takeLeadingWhitespace(); + if (leadingWhitespace) + tree.insertText(leadingWhitespace); + if (!buffer.length) + return; + // FIXME error message + tree.parseError("unexpected-char-in-frameset"); + this.anythingElse(); + tree.insertionMode.processCharacters(buffer); + }; + + modes.inHeadNoscript.processComment = function(data) { + modes.inHead.processComment(data); + }; + + modes.inHeadNoscript.startTagBasefontBgsoundLinkMetaNoframesStyle = function(name, attributes) { + modes.inHead.processStartTag(name, attributes); + }; + + modes.inHeadNoscript.startTagHeadNoscript = function(name, attributes) { + // FIXME error message + tree.parseError("unexpected-start-tag-in-frameset", {name: name}); + }; + + modes.inHeadNoscript.startTagOther = function(name, attributes) { + // FIXME error message + tree.parseError("unexpected-start-tag-in-frameset", {name: name}); + this.anythingElse(); + tree.insertionMode.processStartTag(name, attributes); + }; + + modes.inHeadNoscript.endTagBr = function(name, attributes) { + // FIXME error message + tree.parseError("unexpected-end-tag-in-frameset", {name: name}); + this.anythingElse(); + tree.insertionMode.processEndTag(name, attributes); + }; + + modes.inHeadNoscript.endTagNoscript = function(name, attributes) { + tree.popElement(); + tree.setInsertionMode('inHead'); + }; + + modes.inHeadNoscript.endTagOther = function(name, attributes) { + // FIXME error message + tree.parseError("unexpected-end-tag-in-frameset", {name: name}); + }; + + modes.inHeadNoscript.anythingElse = function() { + tree.popElement(); + tree.setInsertionMode('inHead'); + }; + + + modes.inFrameset = Object.create(modes.base); + + modes.inFrameset.start_tag_handlers = { + html: 'startTagHtml', + frameset: 'startTagFrameset', + frame: 'startTagFrame', + noframes: 'startTagNoframes', + "-default": 'startTagOther' + }; + + modes.inFrameset.end_tag_handlers = { + frameset: 'endTagFrameset', + noframes: 'endTagNoframes', + '-default': 'endTagOther' + }; + + modes.inFrameset.processCharacters = function(data) { + tree.parseError("unexpected-char-in-frameset"); + }; + + modes.inFrameset.startTagFrameset = function(name, attributes) { + tree.insertElement(name, attributes); + }; + + modes.inFrameset.startTagFrame = function(name, attributes) { + tree.insertSelfClosingElement(name, attributes); + }; + + modes.inFrameset.startTagNoframes = function(name, attributes) { + modes.inBody.processStartTag(name, attributes); + }; + + modes.inFrameset.startTagOther = function(name, attributes) { + tree.parseError("unexpected-start-tag-in-frameset", {name: name}); + }; + + modes.inFrameset.endTagFrameset = function(name, attributes) { + if (tree.currentStackItem().localName == 'html') { + // context case + tree.parseError("unexpected-frameset-in-frameset-innerhtml"); + } else { + tree.popElement(); + } + + if (!tree.context && tree.currentStackItem().localName != 'frameset') { + // If we're not in context mode an the current node is not a "frameset" element (anymore) then switch + tree.setInsertionMode('afterFrameset'); + } + }; + + modes.inFrameset.endTagNoframes = function(name) { + modes.inBody.processEndTag(name); + }; + + modes.inFrameset.endTagOther = function(name) { + tree.parseError("unexpected-end-tag-in-frameset", {name: name}); + }; + + modes.inTable = Object.create(modes.base); + + modes.inTable.start_tag_handlers = { + html: 'startTagHtml', + caption: 'startTagCaption', + colgroup: 'startTagColgroup', + col: 'startTagCol', + table: 'startTagTable', + tbody: 'startTagRowGroup', + tfoot: 'startTagRowGroup', + thead: 'startTagRowGroup', + td: 'startTagImplyTbody', + th: 'startTagImplyTbody', + tr: 'startTagImplyTbody', + style: 'startTagStyleScript', + script: 'startTagStyleScript', + input: 'startTagInput', + form: 'startTagForm', + '-default': 'startTagOther' + }; + + modes.inTable.end_tag_handlers = { + table: 'endTagTable', + body: 'endTagIgnore', + caption: 'endTagIgnore', + col: 'endTagIgnore', + colgroup: 'endTagIgnore', + html: 'endTagIgnore', + tbody: 'endTagIgnore', + td: 'endTagIgnore', + tfoot: 'endTagIgnore', + th: 'endTagIgnore', + thead: 'endTagIgnore', + tr: 'endTagIgnore', + '-default': 'endTagOther' + }; + + modes.inTable.processCharacters = function(data) { + if (tree.currentStackItem().isFosterParenting()) { + var originalInsertionMode = tree.insertionModeName; + tree.setInsertionMode('inTableText'); + tree.originalInsertionMode = originalInsertionMode; + tree.insertionMode.processCharacters(data); + } else { + tree.redirectAttachToFosterParent = true; + modes.inBody.processCharacters(data); + tree.redirectAttachToFosterParent = false; + } + }; + + modes.inTable.startTagCaption = function(name, attributes) { + tree.openElements.popUntilTableScopeMarker(); + tree.activeFormattingElements.push(Marker); + tree.insertElement(name, attributes); + tree.setInsertionMode('inCaption'); + }; + + modes.inTable.startTagColgroup = function(name, attributes) { + tree.openElements.popUntilTableScopeMarker(); + tree.insertElement(name, attributes); + tree.setInsertionMode('inColumnGroup'); + }; + + modes.inTable.startTagCol = function(name, attributes) { + this.startTagColgroup('colgroup', []); + tree.insertionMode.processStartTag(name, attributes); + }; + + modes.inTable.startTagRowGroup = function(name, attributes) { + tree.openElements.popUntilTableScopeMarker(); + tree.insertElement(name, attributes); + tree.setInsertionMode('inTableBody'); + }; + + modes.inTable.startTagImplyTbody = function(name, attributes) { + this.startTagRowGroup('tbody', []); + tree.insertionMode.processStartTag(name, attributes); + }; + + modes.inTable.startTagTable = function(name, attributes) { + tree.parseError("unexpected-start-tag-implies-end-tag", + {startName: "table", endName: "table"}); + tree.insertionMode.processEndTag('table'); + if (!tree.context) tree.insertionMode.processStartTag(name, attributes); + }; + + modes.inTable.startTagStyleScript = function(name, attributes) { + modes.inHead.processStartTag(name, attributes); + }; + + modes.inTable.startTagInput = function(name, attributes) { + for (var key in attributes) { + if (attributes[key].nodeName.toLowerCase() == 'type') { + if (attributes[key].nodeValue.toLowerCase() == 'hidden') { + tree.parseError("unexpected-hidden-input-in-table"); + tree.insertElement(name, attributes); + // XXX associate with form + tree.openElements.pop(); + return; + } + break; + } + } + this.startTagOther(name, attributes); + }; + + modes.inTable.startTagForm = function(name, attributes) { + tree.parseError("unexpected-form-in-table"); + if (!tree.form) { + tree.insertElement(name, attributes); + tree.form = tree.currentStackItem(); + tree.openElements.pop(); + } + }; + + modes.inTable.startTagOther = function(name, attributes, selfClosing) { + tree.parseError("unexpected-start-tag-implies-table-voodoo", {name: name}); + tree.redirectAttachToFosterParent = true; + modes.inBody.processStartTag(name, attributes, selfClosing); + tree.redirectAttachToFosterParent = false; + }; + + modes.inTable.endTagTable = function(name) { + if (tree.openElements.inTableScope(name)) { + tree.generateImpliedEndTags(); + if (tree.currentStackItem().localName != name) { + tree.parseError("end-tag-too-early-named", {gotName: 'table', expectedName: tree.currentStackItem().localName}); + } + + tree.openElements.popUntilPopped('table'); + tree.resetInsertionMode(); + } else { + assert.ok(tree.context); + tree.parseError('unexpected-end-tag', {name: name}); + } + }; + + modes.inTable.endTagIgnore = function(name) { + tree.parseError("unexpected-end-tag", {name: name}); + }; + + modes.inTable.endTagOther = function(name) { + tree.parseError("unexpected-end-tag-implies-table-voodoo", {name: name}); + // Make all the special element rearranging voodoo kick in + tree.redirectAttachToFosterParent = true; + // Process the end tag in the "in body" mode + modes.inBody.processEndTag(name); + tree.redirectAttachToFosterParent = false; + }; + + modes.inTableText = Object.create(modes.base); + + modes.inTableText.flushCharacters = function() { + var characters = tree.pendingTableCharacters.join(''); + if (!isAllWhitespace(characters)) { + tree.redirectAttachToFosterParent = true; + tree.reconstructActiveFormattingElements(); + tree.insertText(characters); + tree.framesetOk = false; + tree.redirectAttachToFosterParent = false; + } else { + tree.insertText(characters); + } + tree.pendingTableCharacters = []; + }; + + modes.inTableText.processComment = function(data) { + this.flushCharacters(); + tree.setInsertionMode(tree.originalInsertionMode); + tree.insertionMode.processComment(data); + }; + + modes.inTableText.processEOF = function(data) { + this.flushCharacters(); + tree.setInsertionMode(tree.originalInsertionMode); + tree.insertionMode.processEOF(); + }; + + modes.inTableText.processCharacters = function(buffer) { + var characters = buffer.takeRemaining(); + characters = characters.replace(/\u0000/g, function(match, index){ + // @todo position + tree.parseError("invalid-codepoint"); + return ''; + }); + if (!characters) + return; + tree.pendingTableCharacters.push(characters); + }; + + modes.inTableText.processStartTag = function(name, attributes, selfClosing) { + this.flushCharacters(); + tree.setInsertionMode(tree.originalInsertionMode); + tree.insertionMode.processStartTag(name, attributes, selfClosing); + }; + + modes.inTableText.processEndTag = function(name, attributes) { + this.flushCharacters(); + tree.setInsertionMode(tree.originalInsertionMode); + tree.insertionMode.processEndTag(name, attributes); + }; + + modes.inTableBody = Object.create(modes.base); + + modes.inTableBody.start_tag_handlers = { + html: 'startTagHtml', + tr: 'startTagTr', + td: 'startTagTableCell', + th: 'startTagTableCell', + caption: 'startTagTableOther', + col: 'startTagTableOther', + colgroup: 'startTagTableOther', + tbody: 'startTagTableOther', + tfoot: 'startTagTableOther', + thead: 'startTagTableOther', + '-default': 'startTagOther' + }; + + modes.inTableBody.end_tag_handlers = { + table: 'endTagTable', + tbody: 'endTagTableRowGroup', + tfoot: 'endTagTableRowGroup', + thead: 'endTagTableRowGroup', + body: 'endTagIgnore', + caption: 'endTagIgnore', + col: 'endTagIgnore', + colgroup: 'endTagIgnore', + html: 'endTagIgnore', + td: 'endTagIgnore', + th: 'endTagIgnore', + tr: 'endTagIgnore', + '-default': 'endTagOther' + }; + + modes.inTableBody.processCharacters = function(data) { + modes.inTable.processCharacters(data); + }; + + modes.inTableBody.startTagTr = function(name, attributes) { + tree.openElements.popUntilTableBodyScopeMarker(); + tree.insertElement(name, attributes); + tree.setInsertionMode('inRow'); + }; + + modes.inTableBody.startTagTableCell = function(name, attributes) { + tree.parseError("unexpected-cell-in-table-body", {name: name}); + this.startTagTr('tr', []); + tree.insertionMode.processStartTag(name, attributes); + }; + + modes.inTableBody.startTagTableOther = function(name, attributes) { + // XXX any ideas on how to share this with endTagTable + if (tree.openElements.inTableScope('tbody') || tree.openElements.inTableScope('thead') || tree.openElements.inTableScope('tfoot')) { + tree.openElements.popUntilTableBodyScopeMarker(); + this.endTagTableRowGroup(tree.currentStackItem().localName); + tree.insertionMode.processStartTag(name, attributes); + } else { + // context case + tree.parseError('unexpected-start-tag', {name: name}); + } + }; + + modes.inTableBody.startTagOther = function(name, attributes) { + modes.inTable.processStartTag(name, attributes); + }; + + modes.inTableBody.endTagTableRowGroup = function(name) { + if (tree.openElements.inTableScope(name)) { + tree.openElements.popUntilTableBodyScopeMarker(); + tree.popElement(); + tree.setInsertionMode('inTable'); + } else { + tree.parseError('unexpected-end-tag-in-table-body', {name: name}); + } + }; + + modes.inTableBody.endTagTable = function(name) { + if (tree.openElements.inTableScope('tbody') || tree.openElements.inTableScope('thead') || tree.openElements.inTableScope('tfoot')) { + tree.openElements.popUntilTableBodyScopeMarker(); + this.endTagTableRowGroup(tree.currentStackItem().localName); + tree.insertionMode.processEndTag(name); + } else { + // context case + tree.parseError('unexpected-end-tag', {name: name}); + } + }; + + modes.inTableBody.endTagIgnore = function(name) { + tree.parseError("unexpected-end-tag-in-table-body", {name: name}); + }; + + modes.inTableBody.endTagOther = function(name) { + modes.inTable.processEndTag(name); + }; + + modes.inSelect = Object.create(modes.base); + + modes.inSelect.start_tag_handlers = { + html: 'startTagHtml', + option: 'startTagOption', + optgroup: 'startTagOptgroup', + select: 'startTagSelect', + input: 'startTagInput', + keygen: 'startTagInput', + textarea: 'startTagInput', + script: 'startTagScript', + '-default': 'startTagOther' + }; + + modes.inSelect.end_tag_handlers = { + option: 'endTagOption', + optgroup: 'endTagOptgroup', + select: 'endTagSelect', + caption: 'endTagTableElements', + table: 'endTagTableElements', + tbody: 'endTagTableElements', + tfoot: 'endTagTableElements', + thead: 'endTagTableElements', + tr: 'endTagTableElements', + td: 'endTagTableElements', + th: 'endTagTableElements', + '-default': 'endTagOther' + }; + + modes.inSelect.processCharacters = function(buffer) { + var data = buffer.takeRemaining(); + data = data.replace(/\u0000/g, function(match, index){ + // @todo position + tree.parseError("invalid-codepoint"); + return ''; + }); + if (!data) + return; + tree.insertText(data); + }; + + modes.inSelect.startTagOption = function(name, attributes) { + // we need to imply if " + name + "
      "; + }); + + res._hasBody && res.write(html.join("")); + res.end(); + return; + } + + fs.readFile(filename, "binary", function(err, file) { + if (err) { + res.writeHead(500, { "Content-Type": "text/plain" }); + res.write(err + "\n"); + res.end(); + return; + } + + var contentType = mime.lookup(filename) || "text/plain"; + res.writeHead(200, { "Content-Type": contentType }); + res.write(file, "binary"); + res.end(); + }); + }); +}).listen(port, ip); + +function error(res, status, message, error) { + console.error(error || message); + res.writeHead(status, { "Content-Type": "text/plain" }); + res.write(message); + res.end(); +} + +function save(req, res, filePath) { + var data = ""; + req.on("data", function(chunk) { + data += chunk; + }); + req.on("error", function() { + error(res, 404, "Could't save file"); + }); + req.on("end", function() { + try { + fs.writeFileSync(filePath, data); + } + catch (e) { + return error(res, 404, "Could't save file", e); + } + res.statusCode = 200; + res.end("OK"); + }); +} + +function getLocalIps() { + var os = require("os"); + + var interfaces = os.networkInterfaces ? os.networkInterfaces() : {}; + var addresses = []; + for (var k in interfaces) { + for (var k2 in interfaces[k]) { + var address = interfaces[k][k2]; + if (address.family === "IPv4" && !address.internal) { + addresses.push(address.address); + } + } + } + return addresses; +} + +console.log("http://" + (ip == "0.0.0.0" ? getLocalIps()[0] : ip) + ":" + port); + diff --git a/node_modules/ace/static.py b/node_modules/ace/static.py new file mode 100755 index 00000000..7a2faf91 --- /dev/null +++ b/node_modules/ace/static.py @@ -0,0 +1,298 @@ +#!/usr/bin/env python +"""static - A stupidly simple WSGI way to serve static (or mixed) content. + +(See the docstrings of the various functions and classes.) + +Copyright (C) 2006-2009 Luke Arno - http://lukearno.com/ + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to: + +The Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. + +Luke Arno can be found at http://lukearno.com/ + +""" + +import mimetypes +import rfc822 +import time +import string +import sys +from os import path, stat, getcwd +from fnmatch import fnmatch +from wsgiref import util +from wsgiref.validate import validator +from wsgiref.headers import Headers +from wsgiref.simple_server import make_server +from optparse import OptionParser + +try: from pkg_resources import resource_filename, Requirement +except: pass + +try: import kid +except: pass + + +class MagicError(Exception): pass + + +class StatusApp: + """Used by WSGI apps to return some HTTP status.""" + + def __init__(self, status, message=None): + self.status = status + if message is None: + self.message = status + else: + self.message = message + + def __call__(self, environ, start_response, headers=[]): + if self.message: + Headers(headers).add_header('Content-type', 'text/plain') + start_response(self.status, headers) + if environ['REQUEST_METHOD'] == 'HEAD': + return [""] + else: + return [self.message] + + +class Cling(object): + """A stupidly simple way to serve static content via WSGI. + + Serve the file of the same path as PATH_INFO in self.datadir. + + Look up the Content-type in self.content_types by extension + or use 'text/plain' if the extension is not found. + + Serve up the contents of the file or delegate to self.not_found. + """ + + block_size = 16 * 4096 + index_file = 'index.html' + not_found = StatusApp('404 Not Found') + not_modified = StatusApp('304 Not Modified', "") + moved_permanently = StatusApp('301 Moved Permanently') + method_not_allowed = StatusApp('405 Method Not Allowed') + success_no_content = StatusApp('204 No Content', "") + server_error = StatusApp('500 Internal Server Error') + + def __init__(self, root, **kw): + """Just set the root and any other attribs passes via **kw.""" + self.root = root + for k, v in kw.iteritems(): + setattr(self, k, v) + + def __call__(self, environ, start_response): + """Respond to a request when called in the usual WSGI way.""" + path_info = environ.get('PATH_INFO', '') + full_path = self._full_path(path_info) + if not self._is_under_root(full_path): + return self.not_found(environ, start_response) + if path.isdir(full_path): + if full_path[-1] <> '/' or full_path == self.root: + location = util.request_uri(environ, include_query=False) + '/' + if environ.get('QUERY_STRING'): + location += '?' + environ.get('QUERY_STRING') + headers = [('Location', location)] + return self.moved_permanently(environ, start_response, headers) + else: + full_path = self._full_path(path_info + self.index_file) + try: + sz = int(environ['CONTENT_LENGTH']) + except: + sz = 0 + if environ['REQUEST_METHOD'] == 'PUT' and sz > 0: + for putglob in self.puttable: + if fnmatch(path_info, putglob): + data = environ['wsgi.input'].read(sz) + try: + with open(full_path, "wb") as f: f.write(data) + return self.success_no_content(environ, start_response) + except: + print sys.exc_info()[1] + return self.server_error(environ, start_response) + if environ['REQUEST_METHOD'] not in ('GET', 'HEAD'): + headers = [('Allow', 'GET, HEAD')] + return self.method_not_allowed(environ, start_response, headers) + content_type = self._guess_type(full_path) + try: + etag, last_modified = self._conditions(full_path, environ) + headers = [('Date', rfc822.formatdate(time.time())), + ('Last-Modified', last_modified), + ('ETag', etag)] + if_modified = environ.get('HTTP_IF_MODIFIED_SINCE') + if if_modified and (rfc822.parsedate(if_modified) + >= rfc822.parsedate(last_modified)): + return self.not_modified(environ, start_response, headers) + if_none = environ.get('HTTP_IF_NONE_MATCH') + if if_none and (if_none == '*' or etag in if_none): + return self.not_modified(environ, start_response, headers) + file_like = self._file_like(full_path) + headers.append(('Content-Type', content_type)) + start_response("200 OK", headers) + if environ['REQUEST_METHOD'] == 'GET': + return self._body(full_path, environ, file_like) + else: + return [''] + except (IOError, OSError), e: + print e + return self.not_found(environ, start_response) + + def _full_path(self, path_info): + """Return the full path from which to read.""" + return self.root + path_info + + def _is_under_root(self, full_path): + """Guard against arbitrary file retrieval.""" + if (path.abspath(full_path) + path.sep)\ + .startswith(path.abspath(self.root) + path.sep): + return True + else: + return False + + def _guess_type(self, full_path): + """Guess the mime type using the mimetypes module.""" + return mimetypes.guess_type(full_path)[0] or 'text/plain' + + def _conditions(self, full_path, environ): + """Return a tuple of etag, last_modified by mtime from stat.""" + mtime = stat(full_path).st_mtime + return str(mtime), rfc822.formatdate(mtime) + + def _file_like(self, full_path): + """Return the appropriate file object.""" + return open(full_path, 'rb') + + def _body(self, full_path, environ, file_like): + """Return an iterator over the body of the response.""" + way_to_send = environ.get('wsgi.file_wrapper', iter_and_close) + return way_to_send(file_like, self.block_size) + + +def iter_and_close(file_like, block_size): + """Yield file contents by block then close the file.""" + while 1: + try: + block = file_like.read(block_size) + if block: yield block + else: raise StopIteration + except StopIteration, si: + file_like.close() + return + + +def cling_wrap(package_name, dir_name, **kw): + """Return a Cling that serves from the given package and dir_name. + + This uses pkg_resources.resource_filename which is not the + recommended way, since it extracts the files. + + I think this works fine unless you have some _very_ serious + requirements for static content, in which case you probably + shouldn't be serving it through a WSGI app, IMHO. YMMV. + """ + resource = Requirement.parse(package_name) + return Cling(resource_filename(resource, dir_name), **kw) + + +def command(): + usage = "%prog [--help] [-d DIR] [-l [HOST][:PORT]] [-p GLOB[,GLOB...]]" + parser = OptionParser(usage=usage, version="static 0.3.6") + parser.add_option("-d", "--dir", dest="rootdir", default=".", + help="Root directory to serve. Defaults to '.' .", metavar="DIR") + parser.add_option("-l", "--listen", dest="listen", default="127.0.0.1:8888", + help="Listen on this interface (given by its hostname or IP) and port."+ + " HOST defaults to 127.0.0.1. PORT defaults to 8888. "+ + "Leave HOST empty to listen on all interfaces (INSECURE!).", + metavar="[HOST][:PORT]") + parser.add_option("-p", "--puttable", dest="puttable", default="", + help="Comma or space-separated list of request paths for which to"+ + " permit PUT requests. Each path is a glob pattern that may "+ + "contain wildcard characters '*' and/or '?'. "+ + "'*' matches any sequence of characters, including the empty"+ + " string. '?' matches exactly 1 arbitrary character. "+ + "NOTE: Both '*' and '?' match slashes and dots. "+ + "I.e. --puttable=* makes every file under DIR writable!", + metavar="GLOB[,GLOB...]") + parser.add_option("--validate", dest="validate", action="store_true", + default=False, + help="Enable HTTP validation. You don't need this unless "+ + "you're developing static.py itself.") + + options, args = parser.parse_args() + if len(args) > 0: + parser.print_help(sys.stderr) + sys.exit(1) + + parts = options.listen.split(":") + if len(parts) == 1: + try: # if the the listen argument consists only of a port number + port = int(parts[0]) + host = None + except: # could not parse as port number => must be a host IP or name + host = parts[0] + port = None + elif len(parts) == 2: + host, port = parts + else: + sys.exit("Invalid host:port specification.") + + if not host: + host = '0.0.0.0' + if not port: + port = 8888 + try: + port = int(port) + if port <= 0 or port > 65535: raise ValueError + except: + sys.exit("Invalid host:port specification.") + + puttable = set(path.abspath(p) for p in + options.puttable.replace(","," ").split()) + if puttable and host not in ('127.0.0.1', 'localhost'): + print("Permitting PUT access for non-localhost connections may be unwise.") + + options.rootdir = path.abspath(options.rootdir) + + for p in puttable: + if not p.startswith(options.rootdir): + sys.exit("puttable path '%s' not under root '%s'" % (p, options.rootdir)) + + # cut off root prefix from puttable paths + puttable = set(p[len(options.rootdir):] for p in puttable) + + app = Cling(options.rootdir, puttable=puttable) + + if options.validate: + app = validator(app) + + try: + print "Serving %s to http://%s:%d" % (options.rootdir, host, port) + if puttable: + print("The following paths (relative to server root) may be "+ + "OVERWRITTEN via HTTP PUT.") + for p in puttable: + print p + make_server(host, port, app).serve_forever() + except KeyboardInterrupt, ki: + print "Ciao, baby!" + except: + sys.exit("Problem initializing server: %s" % sys.exc_info()[1]) + + +if __name__ == '__main__': + command() + diff --git a/node_modules/ace/tool/Readme.md b/node_modules/ace/tool/Readme.md new file mode 100644 index 00000000..28dd5166 --- /dev/null +++ b/node_modules/ace/tool/Readme.md @@ -0,0 +1,26 @@ +Helper Scripts for Ace +====================== + +To use this you need to install node.js. and run `npm install` in this directory. + + +# add_mode.js + + Run +``` +node add_mode.js ModeName "extension1|extension2|^FullName" +``` + to create all the files needed for a new mode named `ModeName` + this adds stubs for: + `ace/mode/mode_name.js` + `ace/mode/mode_name_hightlight_rules.js` + `ace/snippets/mode_name.js` + `ace/demo/kitchen_sink/docs/mode_name.extension1` + and adds entry for the new mode to `ace/ext/modelist.js` + + +# tmlanguage.js + +``` +node tmlanguage.js ./templates/dummy.JSON-tmLanguage +``` \ No newline at end of file diff --git a/node_modules/ace/tool/add_mode.js b/node_modules/ace/tool/add_mode.js new file mode 100644 index 00000000..879b9204 --- /dev/null +++ b/node_modules/ace/tool/add_mode.js @@ -0,0 +1,106 @@ +var fs = require('fs'); +var lib = require('./lib'); +var path = require('path'); + +function main(displayName, extRe) { + var name = lib.snakeCase(displayName).replace(/[^\w]/g, ""); + + /** demo **/ + var demoFileExt = extRe.split("|")[0] || name; + var demoFileName = demoFileExt[0] == "^" ? demoFileExt.substr(1) : name + "." + demoFileExt; + var demoFilePath = lib.AceRoot + "demo/kitchen-sink/docs/" + demoFileName; + fs.writeFileSync(demoFilePath, "TODO add a nice demo!\nTry to keep it short!", "utf8"); + console.log("Created demo file at: " + path.normalize(demoFilePath)); + + /** mode **/ + var template = fs.readFileSync(__dirname + "/templates/mode.js", "utf8"); + var modePath = lib.AceLib + "ace/mode/" + name + ".js"; + var text = lib.fillTemplate(template, { + languageHighlightFilename: name, + languagename: name, + lineCommentStart: "TODO", + blockCommentStart: "TODO", + blockCommentEnd: "TODO" + }); + fs.writeFileSync(modePath, text); + console.log("Created mode file at: " + path.normalize(modePath)); + + /** highlight rules **/ + template = fs.readFileSync(__dirname + "/templates/highlight_rules.js", "utf8"); + var hlPath = lib.AceLib + "ace/mode/" + name + "_highlight_rules.js"; + template = template.replace(/\/\* THIS[\s\S]*?\*{3}\/\s*/, ""); + text = lib.fillTemplate(template, { + language: name, + languageTokens: '{\n\ + start: [{\n\ + token: "string.start",\n\ + regex: \'"\',\n\ + next: "qstring"\n\ + }],\n\ + qstring: [{\n\ + token: "escape",\n\ + regex: /\\\\./,\n\ + }, {\n\ + token: "string.end",\n\ + regex: \'"\',\n\ + next: "start"\n\ + }],\n\ + }' + }); + fs.writeFileSync(hlPath, text); + console.log("Created mode file at: " + path.normalize(hlPath)); + + /** snippets **/ + template = fs.readFileSync(__dirname + "/templates/snippets.js", "utf8"); + var snipetsPath = lib.AceLib + "ace/snippets/" + name + ".js"; + text = lib.fillTemplate(template, { + languagename: name, + snippets: "" + }); + fs.writeFileSync(snipetsPath, text); + console.log("Created snippets file at: " + path.normalize(snipetsPath)); + + /** modelist **/ + var modelistPath = lib.AceLib + "ace/ext/modelist.js"; + var modelist = fs.readFileSync(modelistPath, "utf8").replace(/\r\n?/g, "\n"); + modelist = modelist.replace(/(supportedModes = {\n)([\s\S]*?)(\n^};)/m, function(_, m1, m2, m3) { + var langs = m2.split(/,\n/); + var offset = langs[0].trim().indexOf("["); + var padding = Array(Math.max(offset - displayName.length - 1, 0) + 1).join(" "); + var newLang = " " + displayName + ":" + padding + "[\"" + extRe + "\"]"; + langs = langs.concat(newLang).map(function(x) { + return { + value: x, + id: x.match(/[^"':\s]+/)[0].toLowerCase() + }; + }); + langs[langs.length - 1].isNew = true; + + langs = langs.filter(function(x) { + console.log(x.id, displayName) + return x.id != displayName.toLowerCase() || x.isNew; + }); + langs = langs.sort(function(a, b) { + return a.id.localeCompare(b.id); + }).map(function(x) { + return x.value; + }); + + return m1 + langs.join(",\n") + m3; + }); + fs.writeFileSync(modelistPath, modelist, "utf8"); + console.log("Updated modelist at: " + path.normalize(modelistPath)); +} + +if (!module.parent) { + var args = process.argv.slice(2); + var displayName = args[0]; + var extRe = args[1]; + if (!displayName || ! extRe) { + console.log("Usage: ModeName ext1|ext2"); + process.exit(1); + } +} else { + module.exports = main; +} + diff --git a/node_modules/ace/tool/lib.js b/node_modules/ace/tool/lib.js new file mode 100644 index 00000000..e72194d7 --- /dev/null +++ b/node_modules/ace/tool/lib.js @@ -0,0 +1,78 @@ +var plist = require("plist"); +var util = require("util"); +var url = require("url"); + +var https = require("https"); +var http = require("http"); + +exports.parsePlist = function(xmlOrJSON, callback) { + var json; + if (xmlOrJSON[0] == "<") { + plist.parseString(xmlOrJSON, function(_, result) { + json = result[0]; + }); + } else { + xmlOrJSON = xmlOrJSON.replace(/^\s*\/\/.*/gm, ""); + json = JSON.parse(xmlOrJSON) + } + callback && callback(json); + return json; +}; + +exports.formatJSON = function(object, initialIndent) { + return util.inspect(object, false, 40).replace(/^/gm, initialIndent||""); +}; + + +exports.fillTemplate = function(template, replacements) { + return template.replace(/%(.+?)%/g, function(str, m) { + return replacements[m] || ""; + }); +}; + +exports.hyphenate = function(str) { + return str.replace(/([A-Z])/g, "-$1").replace(/[_\s\-]+/g, "-").toLowerCase(); +}; + +exports.camelCase = function(str) { + return str.replace(/[\-_\s]+(.?)/g, function(x, y) {return y.toUpperCase()}); +}; + +exports.snakeCase = function(str) { + return str.replace(/([a-z])([A-Z])/g, "$1-$2").replace(/[_\s\-]+/g, "_").toLowerCase(); +}; + +exports.quoteString = function(str) { + return '"' + str.replace(/\\/, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\\n") + '"'; +}; + + +exports.restoreJSONComments = function(objStr) { + return objStr.replace(/^(\s*)comment: '(.*)'/gm, function(_, i, c) { + return i + "//" + c.replace(/\\n(\\t)*/g, "\n" + i + "//") + "\n" + i; + }).replace(/ \/\/ ERROR/g, '", // ERROR'); +}; + + +exports.download = function(href, callback) { + var options = url.parse(href); + var protocol = options.protocol === "https:" ? https : http; + console.log("connecting to " + options.host + " " + options.path); + var request = protocol.get(options, function(res) { + var data = ""; + res.setEncoding("utf-8"); + + res.on("data", function(chunk) { + data += chunk; + }); + + res.on("end", function(){ + callback(data); + }); + }); +}; + + +exports.AceRoot = __dirname + "/../"; +exports.AceLib = __dirname + "/../lib/"; + diff --git a/node_modules/ace/tool/mode_creator.html b/node_modules/ace/tool/mode_creator.html new file mode 100644 index 00000000..259ba64e --- /dev/null +++ b/node_modules/ace/tool/mode_creator.html @@ -0,0 +1,101 @@ + + + + + + + Ace Mode Creator + + + + + + + +
      + + + + + + + + + + \ No newline at end of file diff --git a/node_modules/ace/tool/mode_creator.js b/node_modules/ace/tool/mode_creator.js new file mode 100644 index 00000000..7a2aea59 --- /dev/null +++ b/node_modules/ace/tool/mode_creator.js @@ -0,0 +1,259 @@ +define(function(require, exports, module) { + +/** creates globals intentionally to make things easily accessible from console **/ + +require("ace/ext/language_tools"); +require("ace/config").setDefaultValues("editor", { + enableBasicAutocompletion: true, + enableSnippets: true +}); +var net = require("ace/lib/net"); +var Range = require("ace/range").Range; +var util = require("demo/kitchen-sink/util"); +var layout = require("demo/kitchen-sink/layout"); +var modelist = require("ace/ext/modelist"); +var doclist = require("demo/kitchen-sink/doclist"); +var TokenTooltip = require("demo/kitchen-sink/token_tooltip").TokenTooltip; + +var EditSession = require("ace/edit_session").EditSession; +var UndoManager = require("ace/undomanager").UndoManager; + +var DebugTokenizer = require("ace/tokenizer_dev").Tokenizer; +var Tokenizer = require("ace/tokenizer").Tokenizer; + +// createEditor +var splitEditor = window.splitEditor = util.createSplitEditor("editor"); + +var editor1 = window.editor1 = splitEditor.editor0; +var editor2 = window.editor2 = splitEditor.editor1; +new TokenTooltip(editor2); + +var timeout = null; +var schedule = function() { + if (timeout != null) { + clearTimeout(timeout); + } + timeout = setTimeout(run, 800); +}; + + +var setAutorunEnabled = function(val) { + if (val) + editor1.on('change', schedule); + else + editor1.removeEventListener('change', schedule); +}; + +util.bindCheckbox("autorunEl", setAutorunEnabled); + + +var docEl = document.getElementById("doc"); +util.fillDropdown(docEl, doclist.docs); +util.bindDropdown("doc", function(value) { + doclist.loadDoc(value, function(session) { + if (session) { + editor2.setSession(session); + updateSaveButtonState(null, editor2); + } + }); +}); + +var modeEl = document.getElementById("modeEl"); +util.fillDropdown(modeEl, modelist.modes); +var modeSessions = {}; + +util.bindDropdown(modeEl, function(value) { + if (modeSessions[value]) { + editor1.setSession(modeSessions[value]); + schedule(); + return; + } + var hp = "./lib/ace/mode/" + value + "_highlight_rules.js"; + net.get(hp, function(text) { + var session = new EditSession(text); + session.setUndoManager(new UndoManager()); + + modeSessions[value] = session; + session.setMode("ace/mode/javascript", function() { + if (session.getLine(0).match(/^\s*\//)) + session.toggleFoldWidget(0); // fold licence comment + }); + + editor1.setSession(modeSessions[value]); + updateSaveButtonState(null, editor1); + schedule(); + }); +}); + +document.getElementById("syncToMode").onclick = function() { + docEl.value = modelist.modesByName[modeEl.value].desc; + docEl.onchange(); + run(); +}; + +editor1.saveButton = document.getElementById("saveButton1"); +editor2.saveButton = document.getElementById("saveButton2"); +editor1.saveButton.editor = editor1; +editor2.saveButton.editor = editor2; + +editor1.saveButton.onclick = function() { + doclist.saveDoc({ + path: "./lib/ace/mode/" + modeEl.value + "_highlight_rules.js", + session: editor1.session + }, function(err) { + handleSaveResult(err, editor1); + }); +}; +editor1.commands.bindKey({ + win: "Ctrl-S", mac: "Cmd-s" +}, editor1.saveButton.onclick); +editor2.saveButton.onclick = function() { + doclist.saveDoc(docEl.value, function(err) { + handleSaveResult(err, editor2); + }); +}; +editor2.commands.bindKey({ + win: "Ctrl-S", mac: "Cmd-s" +}, editor2.saveButton.onclick); +function updateSaveButtonState(e, editor){ + editor.saveButton.disabled = editor.session.getUndoManager().isClean(); +} +editor1.on("input", updateSaveButtonState); +editor2.on("input", updateSaveButtonState); + +function handleSaveResult(err, editor) { + if (err) { + return log( + "Write access to this file is disabled.\n"+ + "To enable saving your changes to disk, clone the Ace repository\n"+ + "and run the included web server with the --allow-write option\n"+ + "`node static.js --allow-write` or `static.py --puttable=*`" + ); + } + editor.session.getUndoManager().markClean(); + updateSaveButtonState(null, editor); +} + +document.getElementById("perfTest").onclick = function() { + var lines = editor2.session.doc.getAllLines(); + if (!lines.length) + return; + while (lines.length < 1000) { + lines = lines.concat(lines); + } + + var tk = new Tokenizer(currentRules); + var testPerf = function(lines, tk) { + var state = "start"; + for (var i=0, l = lines.length; i + + + + + + Ace Profile util + + + + +
      + + + +
      +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + + +
      + + + + +
      + +
      + + + +
      + + + +
      + + + +
      + + + +
      + + + +
      + + + +
      + + + +
      + + + +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + +
      + + + +
      + + + +
      + + + +
      + + + +
      + + + +
      + + + +
      + + + +
      + + + +
      + + + +
      + + + +
      + + + +
      + + + +
      + + + +
      + + + +
      + + + +
      + +
      +
      + +
      +
      +
      +
      + + + + + + + + + diff --git a/node_modules/ace/tool/regexp_tokenizer.js b/node_modules/ace/tool/regexp_tokenizer.js new file mode 100644 index 00000000..ef302e9a --- /dev/null +++ b/node_modules/ace/tool/regexp_tokenizer.js @@ -0,0 +1,114 @@ +/***** regexp tokenizer */ +require("amd-loader"); +var lib = require("./lib"); + +var Tokenizer = require(lib.AceLib+ "ace/tokenizer").Tokenizer; +var Tokenizer = require(lib.AceLib + "ace/tokenizer_dev").Tokenizer; // todo can't use tokenizer because of max token count +var TextHighlightRules = require(lib.AceLib + "ace/mode/text_highlight_rules").TextHighlightRules; + +var r = new TextHighlightRules() +r.$rules = { + start: [ + {token: "anchor", regex: /[\^\$]|\\[bBAZzG]/, merge:false}, + {token: "backRef", regex: /\\([1-9]|k(<\w+\b[+-]?\d>|'\w+\b[+-]?\d'))/, merge:false}, + {include: "charTypes", merge:false}, + {token: "charclass", regex: /\[\^?/, push: "charclass", merge:false}, + {token: "alternation", regex: /\|/, merge:false}, + {include: "quantifiers", merge:false}, + {include: "groups", merge:false}, + {include: "xGroup", merge:true} + ], + charTypes: [ + {token: "char", regex: /\\([tvnrbfae]|[0-8]{1,3}|x[\dA-Fa-f]{2}|x7[\dA-Fa-f]{7})/, merge:false}, // todo \cx + {token: "charType", regex: /\.|\\[wWsSdDhH]/, merge:false}, + {token: "charProperty", regex: /\\p{\w+}/, merge:false}, + {token: "char", regex: /\\./, merge:false}, + ], + quantifiers: [ + {token: "quantifier", regex: /([?*+]|{\d+\b,?\d*}|{,\d+})[?+]?/, merge:false} + ], + charclass: [ + {include: "charTypes", merge:false}, + {token: "charclass.start", regex: /\[\^?/, push: "charclass", merge:false}, + {token: "charclass.end", regex: /\]/, next: "pop", merge:false} + ], + groups: [ + {token: "group", regex: /[(]([?](#|[imx\-]+:?|:|=|!|<=||<\w+>|'\w+'|))?|[)]/, + onMatch: function(val, state, stack) { + if (!stack.groupNumber) + stack.groupNumber = 1; + + var isStart = val !== ")"; + var t = {depth:0,type: isStart ? "group.start" : "group.end", value: val}; + t.groupType = val[2]; + + if (val == "(") { + t.number = stack.groupNumber++; + t.isGroup = true + } else if (t.groupType == "'" || (t.groupType == "<" && val.slice(-1) == ">")) { + t.name = val.slice(2, -1) + t.isGroup = true + } else if (t.groupType == ":") { + t.isGroup = true + } + + if (t.groupType && val.indexOf("x") != -1) { + var minus = val.indexOf("-"); + if (minus == -1 || minus > val.indexOf("x")) + stack.xGroup = t; + else + stack.xGroup = null; + } else if (!isStart && stack.xGroup && stack.xGroup == stack[0]) { + if (stack.xGroup.value.slice(-1) == ":") + stack.xGroup = null; + } + + if (isStart) { + if (stack.groupDepth) { + stack[0].hasChildren = true + } + stack.groupDepth = (stack.groupDepth||0)+1; + stack.unshift(t) + } else { + stack.groupDepth --; + t.start = stack.shift(t) + t.start.end = t + } + return [t] + }, merge:false + } + ], + xGroup: [ + {token: "text", regex:/\s+/, onMatch: function(val, state, stack) { + return stack.xGroup ? [] : "text" + }, merge: true}, + {token: "text", regex: /#/, onMatch: function(val, state, stack) { + if (stack.xGroup) { + this.next = "comment"; + stack.unshift(state); + return []; + } + this.next = ""; + return "text"; + }, merge: true} + ], + comment: [{ + regex: "[^\n\r]*|^", token: "", onMatch: function(val, state, stack) { + this.next = stack.shift(); + return []; + } + }] +} +r.normalizeRules() +var tmReTokenizer = new Tokenizer(r.getRules()); + +function tokenize(str) { + return tmReTokenizer.getLineTokens(str).tokens; +} + +function toStr(tokens) { return tokens.map(function(x){return x.value}).join("")} + + +exports.tokenize = tokenize; +exports.toStr = toStr; +exports.tmReTokenizer = tmReTokenizer; \ No newline at end of file diff --git a/node_modules/ace/tool/regexp_tokenizer_test.js b/node_modules/ace/tool/regexp_tokenizer_test.js new file mode 100644 index 00000000..aa09ff12 --- /dev/null +++ b/node_modules/ace/tool/regexp_tokenizer_test.js @@ -0,0 +1,30 @@ +require("amd-loader"); +var assert = require("assert"); + +var tk = require("./regexp_tokenizer"); +var tokenize = tk.tokenize; +var toStr = tk.toStr; + +var logTokens = function(tokens) { + tokens.forEach(function(x) { + delete x.end + delete x.start + }) + console.log(tokens) +} + +assert.equal(toStr( + tokenize("(?x)c + +\n\ + # comment\n\ + (?-x) # (?x: 1 \n\ + (2) [ ] # a \n\ + 3 4) c#" + )), + "(?x)c++(?-x) # (?x:1(2)[ ]34) c#" + ) +assert.equal(toStr( + tokenize("(?x)\n\ + u # comment\n\ + ")), + "(?x)u" + ) diff --git a/node_modules/ace/tool/release.sh b/node_modules/ace/tool/release.sh new file mode 100644 index 00000000..6dc830e1 --- /dev/null +++ b/node_modules/ace/tool/release.sh @@ -0,0 +1,74 @@ +pause() { + while true; do + read -p "$1 " yn + case $yn in + [Yy]* ) break;; + [Nn]* ) exit;; + * ) echo "Please answer yes or no.";; + esac + done +} + +read -p "enter version number for the build " VERSION_NUM + +cd `dirname $0`/.. +SOURCE=`pwd` + +node -e " + var fs = require('fs'); + var version = '$VERSION_NUM'; + function replaceVersion(str) { + return str.replace(/(['\"]?version['\"]?\s*[:=]\s*['\"])[\\d.\\w\\-]+(['\"])/, function(_, m1, m2) { + return m1 + version + m2; + }); + } + function update(path, replace) { + var pkg = fs.readFileSync(path, 'utf8'); + pkg = (replace || replaceVersion)(pkg); + fs.writeFileSync(path, pkg, 'utf8'); + } + update('package.json'); + update('build/package.json'); + update('./lib/ace/ext/menu_tools/generate_settings_menu.js'); + update('ChangeLog.txt', function(str) { + var date='"`date +%Y.%m.%d`"'; + return date + ' Version ' + version + '\n' + str.replace(/^\d+.*/, '').replace(/^\n/, ''); + }); +" + +pause "versions updated. do you want to start build script? [y/n]" + +node Makefile.dryice.js full +cd build +git add . +git commit --all -m "package `date +%d.%m.%y`" + + +echo "build task completed." +pause "continue creating the tag for v$VERSION_NUM [y/n]" +if [[ ${VERSION_NUM} != *"-"* ]]; then + git tag "v"$VERSION_NUM +fi + +pause "continue pushing to github? [y/n]" + +git push --progress --tags "origin" HEAD:gh-pages HEAD:master + +echo "build repository updated" + +pause "continue update ace repo? [y/n]" +cd .. + + +echo "new commit added" +pause "continue creating the tag for v$VERSION_NUM [y/n]" +if [[ ${VERSION_NUM} != *"-"* ]]; then + git tag "v"$VERSION_NUM +fi + +pause "continue pushing to github? [y/n]" + +git push --progress --tags "origin" HEAD:gh-pages HEAD:master +echo "All done!" +pause "May I go now? [y/n]" + diff --git a/node_modules/ace/tool/templates/dummy.JSON-tmLanguage b/node_modules/ace/tool/templates/dummy.JSON-tmLanguage new file mode 100644 index 00000000..cb58b29b --- /dev/null +++ b/node_modules/ace/tool/templates/dummy.JSON-tmLanguage @@ -0,0 +1,45 @@ +// [PackageDev] target_format: plist, ext: tmLanguage +{ + "name": "Dummy", + "scopeName": "source.dummy", + "fileTypes": ["dummy"], + "patterns": [ + { + "include": "#string" + }, { + "include": "#escapes" + } + ], + "repository": { + "escapes": { + "patterns": [ + { + "match": "\\\\[nrt\\\\\\$\\\"']", + "name": "keyword.dummy" + } + ] + }, + "string": { + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.dummy" + } + }, + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.dummy" + } + }, + "contentName": "meta.string-contents.quoted.double.dummy", + "name": "string.quoted.double.dummy", + "end": "'''", + "begin": "'''", + "patterns": [ + { + "include": "#escapes" + } + ], + "comment": "This is a comment" + } + } +} \ No newline at end of file diff --git a/node_modules/ace/tool/templates/highlight_rules.js b/node_modules/ace/tool/templates/highlight_rules.js new file mode 100644 index 00000000..db8f5630 --- /dev/null +++ b/node_modules/ace/tool/templates/highlight_rules.js @@ -0,0 +1,58 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +/* This file was autogenerated from %name% (uuid: %uuid%) */ +/**************************************************************************************** + * IT MIGHT NOT BE PERFECT ...But it's a good start from an existing *.tmlanguage file. * + * fileTypes * + ****************************************************************************************/ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + +var %language%HighlightRules = function() { + // regexp must not have capturing parentheses. Use (?:) instead. + // regexps are ordered -> the first match is used + + this.$rules = %languageTokens% + + this.normalizeRules(); +}; + +%language%HighlightRules.metaData = %metaData% + + +oop.inherits(%language%HighlightRules, TextHighlightRules); + +exports.%language%HighlightRules = %language%HighlightRules; +}); \ No newline at end of file diff --git a/node_modules/ace/tool/templates/mode.js b/node_modules/ace/tool/templates/mode.js new file mode 100644 index 00000000..1cdabf15 --- /dev/null +++ b/node_modules/ace/tool/templates/mode.js @@ -0,0 +1,58 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2012, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +/* + THIS FILE WAS AUTOGENERATED BY mode.tmpl.js +*/ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("../lib/oop"); +var TextMode = require("./text").Mode; +var %language%HighlightRules = require("./%languageHighlightFilename%_highlight_rules").%language%HighlightRules; +// TODO: pick appropriate fold mode +var FoldMode = require("./folding/cstyle").FoldMode; + +var Mode = function() { + this.HighlightRules = %language%HighlightRules; + this.foldingRules = new FoldMode(); +}; +oop.inherits(Mode, TextMode); + +(function() { + // this.lineCommentStart = "%lineCommentStart%"; + // this.blockComment = {start: "%blockCommentStart%", end: "%blockCommentEnd%"}; + // Extra logic goes here. + this.$id = "ace/mode/%languageHighlightFilename%" +}).call(Mode.prototype); + +exports.Mode = Mode; +}); \ No newline at end of file diff --git a/node_modules/ace/tool/templates/snippets.js b/node_modules/ace/tool/templates/snippets.js new file mode 100644 index 00000000..6752d1db --- /dev/null +++ b/node_modules/ace/tool/templates/snippets.js @@ -0,0 +1,7 @@ +define(function(require, exports, module) { +"use strict"; + +exports.snippetText = require("../requirejs/text!./%modeName%.snippets"); +exports.scope = "%modeName%"; + +}); diff --git a/node_modules/ace/tool/templates/theme.css b/node_modules/ace/tool/templates/theme.css new file mode 100644 index 00000000..8515d0c3 --- /dev/null +++ b/node_modules/ace/tool/templates/theme.css @@ -0,0 +1,60 @@ +/* THIS THEME WAS AUTOGENERATED BY Theme.tmpl.css (UUID: %uuid%) */ + +.%cssClass% .ace_gutter { + background: %gutterBg%; + color: %gutterFg%; +} + +.%cssClass% .ace_print-margin { + width: 1px; + background: %printMargin%; +} + +.%cssClass% { + background-color: %background%; + color: %foreground%; +} + +.%cssClass% .ace_cursor { + color: %cursor%; +} + +.%cssClass% .ace_marker-layer .ace_selection { + background: %selection%; +} + +.%cssClass%.ace_multiselect .ace_selection.ace_start { + box-shadow: 0 0 3px 0px %background%; + border-radius: 2px; +} + +.%cssClass% .ace_marker-layer .ace_step { + background: %step%; +} + +.%cssClass% .ace_marker-layer .ace_bracket { + margin: -1px 0 0 -1px; + border: 1px solid %bracket%; +} + +.%cssClass% .ace_marker-layer .ace_active-line { + background: %active_line%; +} + +.%cssClass% .ace_gutter-active-line { + background-color: %active_line%; +} + +.%cssClass% .ace_marker-layer .ace_selected-word { + %selected_word_highlight% +} + +.%cssClass% .ace_fold { + background-color: %fold%; + border-color: %foreground%; +} + + + + + diff --git a/node_modules/ace/tool/templates/theme.js b/node_modules/ace/tool/templates/theme.js new file mode 100644 index 00000000..8e99f710 --- /dev/null +++ b/node_modules/ace/tool/templates/theme.js @@ -0,0 +1,39 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + +exports.isDark = %isDark%; +exports.cssClass = "%cssClass%"; +exports.cssText = %css%; + +var dom = require("../lib/dom"); +dom.importCssString(exports.cssText, exports.cssClass); +}); diff --git a/node_modules/ace/tool/tmlanguage.js b/node_modules/ace/tool/tmlanguage.js new file mode 100644 index 00000000..0e458330 --- /dev/null +++ b/node_modules/ace/tool/tmlanguage.js @@ -0,0 +1,697 @@ +require("amd-loader"); + +var fs = require("fs"); +var util = require("util"); +var lib = require("./lib"); +var pathlib = require("path"); +var parseLanguage = lib.parsePlist; + +var tk = require("./regexp_tokenizer"); +var tokenize = tk.tokenize; +var toStr = tk.toStr; + +function last(array) {return array[array.length - 1]} + +function convertHexEscape(tokens) { + var inChClass = false; + tokens.forEach(function(t) { + if (t.type == "charclass") + inChClass = true; + else if (t.type == "charclass.end") + inChClass = false; + else if (t.type == "charType"){ + if (t.value == "\\h") { + t.type = "text"; + t.value = inChClass ? "\\da-fA-F" : "[\\da-fA-F]"; + } + else if (t.value == "\\H") { + if (inChClass) { + console.warn("can't convert \\H in charclass"); + return; + } + t.type = "text"; + t.value = "[^\\da-fA-F]"; + } + } + }); + return tokens; +} + +function convertNewLinesTo$(str) { + var tokens = tokenize(str); + for (var i = 0; i < tokens.length; i++) { + var t= tokens[i]; + if (t.type == "char" && t.value == "\\n") { + var p = tokens[i + 1] || {}; + if (p.type != "quantifier") { + t.value = "$"; + while (p.value == "\\n" || p.type == "quantifier") { + p.value = ""; + p = tokens[++i + 1] || {}; + } + } else if (/\?|\*|{,|{0,/.test(p.value)) { + t.value = p.value = ""; + } else + p.value = ""; + } + } + return toStr(tokens).replace(/[$]+/g, "$"); +} + +function convertCharacterTypes(str) { + var tokens = tokenize(str); + tokens = convertHexEscape(tokens); + + var warn = false; + tokens.forEach(function(t){ + if (t.type == "quantifier") { + var val = t.value; + if (val.slice(-1) == "+" && val.length > 1) { + t.value = val.slice(0, -1); + warn = val; + } + } + }); + if (warn) + console.log("converted possesive quantifier " + warn + " to *"); + return toStr(tokens); +} + +function removeInlineFlags(str, rule) { + var tokens = tokenize(str); + var caseInsensitive = false; + tokens.forEach(function(t, i) { + if (t.type == "group.start" && /[imsx]/.test(t.value)) { + if (/i/.test(t.value)) + caseInsensitive = true; + t.value = t.value.replace(/[imsx\-]/g, ""); + var next = tokens[i + 1]; + if (next && next.type == "group.end") { + t.value = next.value = ""; + } + } + }); + if (caseInsensitive && rule) + rule.caseInsensitive = true; + return toStr(tokens); +} + +function convertToNonCapturingGroups(str) { + var tokens = tokenize(str); + tokens.forEach(function(t, i) { + if (t.type == "group.start" && t.value == "(") + t.value += "?:"; + }); + return toStr(tokens); +} + +function simplifyNonCapturingGroups(str) { + var tokens = tokenize(str); + var t = tokens[0] || {}; + if (t.type == "group.start" && t.value == "(?:" + && t.end == last(tokens)) { + t.value = t.end.value = ""; + } + var i = 0; + function iter(f) { + for (i = 0; i < tokens.length; i++) + f(tokens[i]); + } + function iterGroup(end, f) { + for (var i1 = i + 1; i1 < tokens.length; i1++) { + var t = tokens[i1]; + if (t == end) + break; + var index = f && f(t); + if (index > i1) + i1 = index; + } + return i1; + } + + iter(function (t) { + if (t.type == "group.start" && t.value == "(?:") { + if (!t.end) + return console.error("malformed regex: " + str); + + var canRemove = true; + var next = tokens[tokens.indexOf(t.end, i) + 1]; + if (next && next.type == "quantifier") + return; + iterGroup(t.end, function(t) { + if (t.type == "alternation") + canRemove = false; + else if (t.type == "group.start" && t.end) + return iterGroup(t.end); + }); + if (canRemove) + t.value = t.end.value = ""; + } + }); + + return toStr(tokens); +} + +function removeLookBehinds(str) { + var tokens = tokenize(str); + var toRemove = null; + tokens.forEach(function(t, i) { + if (!toRemove && t.type == "group.start" && / i) + i = i1; + } + function lst(t) {return t[t.length - 1]} + function iter(f) { + for (i = 0; i < tokens.length; i++) + f(tokens[i]); + } + function iterGroup(end, f) { + for (var i1 = i + 1; i1 < tokens.length; i1++) { + var t = tokens[i1]; + if (t == end) + break; + f(t); + } + } + function peek() { return tokens[i + 1] || {}} + + // groupify + iter(function(t){ + if (t.type == "group.start") { + tryClose(); + isStart = true; + if (!t.hasChildren || t.isSpecial) + skip(t); + } else if (t.type == "group.end") { + isStart = true; + tryClose(); + } else if (t.type == "alternation") { + isStart = true; + tryClose(); + } else if (t.type != "anchor" && t.type != "quantifier"){ + tryOpen(); + } + }); + tryClose(); + + // remove redundand groups + var names = [defaultName]; + iter(function(t){ + if (t.type == "group.start" && !t.isSpecial) { + var captureName = captures[t.number]; + + if (!t.hasChildren) { + t.tokenName = captureName || lst(names); + skip(t); + } else { + var hasCapture = false; + iterGroup(t.end, function(t1) { + if (t1.type == "group.start" && captures[t1.number]) + hasCapture = true; + }); + if (hasCapture) { + t.value = "(?:"; + if (captureName) { + names.push(captureName); + t.isTokenGroup = true; + } + } else { + t.tokenName = captureName || lst(names); + iterGroup(t.end, function(t1) { + if (t1.value == "(") + t1.value = "(?:"; + }); + } + } + } else if (t.type == "group.end") { + if (t.start.isTokenGroup) + names.pop(); + } + }); + + // wrap capturing groups with quantifier + iter(function(t){ + if (t.type == "group.end" && t.start.value == "(" && peek().type == "quantifier") { + peek().value += ")"; + t.start.value += "(?:"; + } + }); + + names = []; + tokens.forEach(function(t) { + if (t.value == "(" || t.value == "((?:" ) + t.tokenName && names.push(t.tokenName); + }); + return { + names: names, + regex: toStr(tokens) + }; +} + +/***** converter */ + +function logDebug(string, obj) { + console.log(string, obj); +} + + +// tmLanguage processor + +// for tracking token states +var states = {start: []}; + +function processRules(rules){ + if (rules.patterns) + states.start = processPatterns(rules.patterns); + if (rules.repository) + processRepository(rules.repository); + return states; +} +function processRepository(r) { + for (var key in r) { + var p = r[key]; + if (p.begin) + var stateObj = [processPattern(r[key])]; + else if (p.patterns && !p.repository) + var stateObj = processPatterns(p.patterns); + else + var stateObj = [processPattern(r[key])]; + + if (stateObj) + states["#" + key] = stateObj; + } +} +function processPatterns(pl) { + return pl.map(processPattern); +} +function processPattern(p) { + if (p.end == "(?!\\G)" && p.patterns && p.patterns.length == 1) { + var rule = processPattern(p.patterns[0]); + } + else if (p.begin != null && p.end != null) { + convertBeginEndBackrefs(p); + + var rule = simpleRule(p.begin, p.name, p.beginCaptures || p.captures); + + var next = processPatterns(p.patterns || []); + var endRule = simpleRule(p.end, p.name, p.endCaptures || p.captures); + endRule.next = "pop"; + if (p.applyEndPatternLast) + next.push(endRule); + else + next.unshift(endRule); + + if (p.name || p.contentName) + next.push({defaultToken: p.name || p.contentName}); + + rule.push = next; + + rule = removeIncludeSelf(rule); + } + else if (p.match) { + var rule = simpleRule(p.match, p.name, p.captures); + } + else if (p.include) { + var rule = {include: p.include}; + } + else { + var rule = {todo: p}; + } + + if (p.comment) + rule.comment = (rule.comment || "") + p.comment; + + if (p.repository) + processRepository(p.repository); + return rule; +} +function simpleRule(regex, name, captures) { + name = name || "text"; + var rule = {token: "", regex: ""}; + + var origRegex = regex; + regex = transformRegExp(origRegex, rule); + if (captures) { + var tokenArray = []; + Object.keys(captures).forEach(function(x){ + tokenArray[x] = captures[x] && captures[x].name; + }); + + if (tokenArray.length == 1) { + name = tokenArray[0]; + } else { + var fixed = fixGroups(tokenArray, name, regex); + name = fixed.names; + regex = fixed.regex; + if (name.length == 1) + name = name[0]; + } + } + + if (typeof name == "string") + regex = convertToNonCapturingGroups(regex); + + regex = simplifyNonCapturingGroups(regex); + + try {new RegExp(regex);} catch(e) { + rule.TODO = "FIXME: regexp doesn't have js equivalent"; + rule.originalRegex = origRegex; + + // lookbehinds are mostly used to force ordering + // regex = removeLookBehinds(regex); + } + rule.token = name; + rule.regex = regex; + return rule; +} + +function removeIncludeSelf(rule) { + if (!rule.push) + return rule; + var hasSelfInclude = false; + var escapeRule = null; + var complexSelfInclude = false; + rule.push.forEach(function(sub) { + if (sub.include == "$self") { + hasSelfInclude = true; + } else if (sub.defaultToken) { + return; + } else if (sub.next == "pop") { + escapeRule = sub; + } else + complexSelfInclude = true; + }); + + if (hasSelfInclude) { + console.warn("can't convert include $self"); + return {todo: rule}; + + if (complexSelfInclude) { + console.warn("can't convert include $self"); + rule.toDo = "include $self not fully supported"; + return rule; + } + console.warn("include $self not fully supported"); + delete rule.push; + delete escapeRule.next; + rule.includeSelf = true; + escapeRule.includeSelf = true; + return [rule, escapeRule]; + } + return rule; +} + +// regex transformation + +function removeXFlag(str) { + var tokens = tokenize(str); + return toStr(tokens); +} + +function transformRegExp(str, rule) { + str = convertNewLinesTo$(str); + + str = removeInlineFlags(str, rule); + + str = str.replace(/(\\[xu]){([a-fA-F\d]+)}/g, '$1$2'); + + str = convertCharacterTypes(str, rule); + + checkForNamedCaptures(str); + + return str; +} + +// +function extractPatterns(tmRules) { + return processRules(tmRules); +} + + +function detectLoops(states) { + var data = {}; + var keys = Object.keys(states); + var flattenedStates = {}; + function addRef(item, name) { + if (item.refs.indexOf(name) == -1) + item.refs.push(name); + } + function anonStateId(name, next) { + var i = 0, old = name; + while (flattenedStates[name] || states[name]) { + name = old + "_" + i++; + } + // console.log(old, name) + return name; + } + function addState(key, rules) { + if (rules && !flattenedStates[key]) + flattenedStates[key] = rules; + return rules || flattenedStates[key]; + } + + + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; + var state = addState(key, states[key]); + + var item = data[key] || (data[key] = {/* name: key, */ refs: []}); + state.forEach(function(rule) { + var next = rule.push || rule.next; + if (next == "pop") { + // nothing + } else if (typeof next == "string") { + addRef(item, next); + } else if (next) { + var anonId = anonStateId(key, next); + addState(anonId, next); + if (rule.push) + addRef(item, anonId); + keys.push(anonId); + } else if (rule.include) { + addRef(item, rule.include); + } + }); + } + + + var cycles = []; + function addPath(start, path) { + var node = data[start]; + path.push(start); + if (!node || !node.refs) + console.log(start); + var i = path.indexOf(start); + if (i > -1 && i != path.length - 1 || start == "$self" || start == "$base") { + if (i != -1) + path = path.slice(i); + for (var j = 0; j < cycles.length; j++) { + if (cycles[j] + "" == path + "") + return; + } + return cycles.push(path); + } + + if (!node || !node.refs || !node.refs.length || path.length>30) + return; + node.refs.forEach(function(x) { + addPath(x, path.concat()); + }); + } + addPath("start", []); + + console.error(cycles.join("\n")); +} + + +function test(fileName) { + console.log("testing highlighter"); + try { + var module = require(fileName); + var Mode = module[Object.keys(module)[0]]; + var mode = new Mode(); + mode.getTokenizer().getLineTokens("hello world"); + } catch(e) { + console.log(e); + } +} + +function guessComment(patterns) { + var comment = {}; + for (var i in patterns) { + var state = patterns[i]; + state.forEach(function(r) { + if (typeof r.token == "string") { + if (/\bcomment\b/.test(r.token)) { + comment.line = r.regex; + } + } + }); + } + + return comment; +} + +// cli stuff +var modeTemplate = fs.readFileSync(__dirname + "/templates/mode.js", "utf8"); +var modeHighlightTemplate = fs.readFileSync(__dirname + "/templates/highlight_rules.js", "utf8"); + +function fetchAndConvert(name) { + console.log("Converting " + name); + if (/^http/.test(name)) { + if (/:\/\/github.com/.test(name)) { + name = name.replace(/\/blob\//, "/").replace("github.com", "raw.github.com"); + } + return lib.download(name, function(data) { + convertTmLanguage(name, data); + }); + } + var path = /^(\/|\w:)/.test(name) ? name : process.cwd() + "/" + name; + var langStr = fs.readFileSync(path, "utf8"); + convertTmLanguage(name, langStr); +} + + +function convertTmLanguage(name, langStr) { + parseLanguage(langStr, function(language) { + var highlighterFilename = lib.snakeCase(language.name).replace(/[^\w]/g, ""); + var languageNameSanitized = lib.camelCase(language.name).replace(/[^\w]/g, ""); + + require("./add_mode")(languageNameSanitized, (language.fileTypes || []).join("|")); + + var highlighterFile = pathlib.normalize(lib.AceLib + "ace/mode/" + highlighterFilename + "_highlight_rules.js"); + var modeFile = pathlib.normalize(lib.AceLib + "ace/mode/" + highlighterFilename + ".js"); + + if (devMode) { + console.log(util.inspect(language.patterns, false, 4)); + console.log(util.inspect(language.repository, false, 4)); + } + + var patterns = extractPatterns(language); + detectLoops(patterns); + + // var uuid = language.uuid + delete language.uuid; + delete language.patterns; + delete language.repository; + + var comment = guessComment(patterns); + var languageMode = lib.fillTemplate(modeTemplate, { + language: languageNameSanitized, + languageHighlightFilename: highlighterFilename, + lineCommentStart: JSON.stringify(comment.line || "//"), + blockCommentStart: JSON.stringify(comment.start || "/*"), + blockCommentEnd: JSON.stringify(comment.end || "*/") + }); + + var languageHighlightRules = lib.fillTemplate(modeHighlightTemplate, { + language: languageNameSanitized, + languageTokens: lib.formatJSON(patterns, " ").trim(), + uuid: language.uuid, + name: name, + metaData: lib.formatJSON(language, " ").trim() + }); + + if (devMode) { + console.log(languageMode); + console.log(languageHighlightRules); + console.log("Not writing, 'cause we're in dev mode, baby."); + } + else { + fs.writeFileSync(highlighterFile, languageHighlightRules); + fs.writeFileSync(modeFile, languageMode); + console.log("created file " + highlighterFile); + test(modeFile); + } + }); +} + +if (!module.parent) { + var args = process.argv.splice(2); + var devMode = args[0] == "--dev"; + if (devMode) + args.shift(); + if (args.length < 1) { + console.error("Usage: node tmlanguage.js [--dev] path/or/url/to/syntax.file ..."); + process.exit(1); + } + args.forEach(fetchAndConvert); +} else { + exports.fetchAndConvert = fetchAndConvert; +} diff --git a/node_modules/ace/tool/tmsnippets.js b/node_modules/ace/tool/tmsnippets.js new file mode 100644 index 00000000..febc7946 --- /dev/null +++ b/node_modules/ace/tool/tmsnippets.js @@ -0,0 +1,82 @@ +var fs = require('fs') +var plist = require('plist') + +var snippets = []; +var path = process.argv[2] || process.cwd(); +function readSnippet(path, name) { + if (name) + path += name + console.log(name) + if (!/\.(tmSnippet|sublime-snippet|plist)$/i.test(path)) + return + console.log(name) + var plistString = fs.readFileSync(path, "utf8"); + plist.parseString(plistString, function(_, plist){ + snippets.push(plist) + }) +} + +// read +function readDir(path) { + if (fs.statSync(path).isDirectory()) { + path += "/" + fs.readdirSync(path).forEach(function(name) { + if (/snippets/i.test(name)) + readSnippetsInDir(path + name) + else + readDir(path + name) + }) + } +} +function readSnippetsInDir(path) { + if (fs.statSync(path).isDirectory()) { + path += "/" + snippets.push(path) + fs.readdirSync(path).forEach(function(name) { + readSnippet(path, name) + }) + } else { + readSnippet(path) + } +} +readDir(path) +// transform +snippets = snippets.map(function(s) { + if (s.length == 1) + s = s[0] + if (s.scope) + s.scope = s.scope.replace(/source\./g, "") + delete s.uuid + return s +}) + +// stringify +var indent = "" +var text = JSON.stringify(snippets, null, 1) + // .replace(/(\n\s*)"(\w+)"\:/g, "$1$2:") + .replace(/(\n\s*)\},\n\s*{/g, "$1}, {") + .replace(/\[\n\s*\{\n/g, "[{\n").replace(/(\n\s*)\}\n\s*\]/g, "$1}]") + .replace(/\[\n\s*[^\[\{\}\]]{0,100}\]/g, function(x){return x.replace(/\n\s*/g, " ")}) + .replace(/\:\s*\{\n\s*(.*)\n\s*\}/g, ": {$1}") + .split(/\n\s*/).map(function(x){ + if (x[0] == "}" || x[0] == "]") + indent = indent.substr(1) + + if (x.slice(-1) == "{" || x.slice(-1) == "[") { + indent += "\t" + return indent.substr(1) + x + } + return indent +x + }).join("\n") + .replace(/\\[\\tnr]/g, function(a){ + if (a[1] == "\\") + return a + else if (a[1] == "t") + return "\t" + else + return "\\n"+"\\" + "\n" + }) + +fs.writeFileSync(path += "/./ace.snippets.js", text) + +console.log(path) \ No newline at end of file diff --git a/node_modules/ace/tool/tmtheme.js b/node_modules/ace/tool/tmtheme.js new file mode 100755 index 00000000..c784eec7 --- /dev/null +++ b/node_modules/ace/tool/tmtheme.js @@ -0,0 +1,412 @@ +var fs = require("fs"); +var path = require("path"); +var util = require("util"); +var cssParse = require("css-parse"); +var cssStringify = require("css-stringify"); + +var parseString = require("plist").parseString; +function parseTheme(themeXml, callback) { + parseString(themeXml, function(_, theme) { + callback(theme[0]) + }); +} + +var unsupportedScopes = { }; + +var supportedScopes = { + "keyword": "keyword", + "keyword.operator": "keyword.operator", + "keyword.other.unit": "keyword.other.unit", + + "constant": "constant", + "constant.language": "constant.language", + "constant.library": "constant.library", + "constant.numeric": "constant.numeric", + "constant.character" : "constant.character", + "constant.character.escape" : "constant.character.escape", + "constant.character.entity": "constant.character.entity", + "constant.other" : "constant.other", + + "support": "support", + "support.function": "support.function", + "support.function.dom": "support.function.dom", + "support.function.firebug": "support.firebug", + "support.function.constant": "support.function.constant", + "support.constant": "support.constant", + "support.constant.property-value": "support.constant.property-value", + "support.class": "support.class", + "support.type": "support.type", + "support.other": "support.other", + + "function": "function", + "function.buildin": "function.buildin", + + "storage": "storage", + "storage.type": "storage.type", + + "invalid": "invalid", + "invalid.illegal": "invalid.illegal", + "invalid.deprecated": "invalid.deprecated", + + "string": "string", + "string.regexp": "string.regexp", + + "comment": "comment", + "comment.documentation": "comment.doc", + "comment.documentation.tag": "comment.doc.tag", + + "variable": "variable", + "variable.language": "variable.language", + "variable.parameter": "variable.parameter", + + "meta": "meta", + "meta.tag.sgml.doctype": "xml-pe", + "meta.tag": "meta.tag", + "meta.selector": "meta.selector", + + "entity.other.attribute-name": "entity.other.attribute-name", + "entity.name.function": "entity.name.function", + "entity.name": "entity.name", + "entity.name.tag": "entity.name.tag", + + "markup.heading": "markup.heading", + "markup.heading.1": "markup.heading.1", + "markup.heading.2": "markup.heading.2", + "markup.heading.3": "markup.heading.3", + "markup.heading.4": "markup.heading.4", + "markup.heading.5": "markup.heading.5", + "markup.heading.6": "markup.heading.6", + "markup.list": "markup.list", + + "collab.user1": "collab.user1" +}; + +var fallbackScopes = { + "keyword": "meta", + "support.type": "storage.type", + "variable": "entity.name.function" +}; + +function extractStyles(theme) { + var globalSettings = theme.settings[0].settings; + + var colors = { + "printMargin": "#e8e8e8", + "background": parseColor(globalSettings.background), + "foreground": parseColor(globalSettings.foreground), + "gutter": "#e8e8e8", + "selection": parseColor(globalSettings.selection), + "step": "rgb(198, 219, 174)", + "bracket": parseColor(globalSettings.invisibles), + "active_line": parseColor(globalSettings.lineHighlight), + "cursor": parseColor(globalSettings.caret), + + "invisible": "color: " + parseColor(globalSettings.invisibles) + ";" + }; + + for (var i=1; i.css rules, + // (because some exist, for collab1 and ace_indentation_guide + try { + var outThemeCss = fs.readFileSync(outputDirectory + "/" + name + ".css"); + var oldRules = cssParse(outThemeCss).stylesheet.rules; + var newRules = cssParse(css).stylesheet.rules; + + + for (var i = 0; i < newRules.length; i++) { + var newSelectors = newRules[i].selectors; + + for (var j = 0; j < oldRules.length; j++) { + var oldSelectors = oldRules[j].selectors; + newSelectors = newSelectors.filter(function(s) { + return oldSelectors.indexOf(s) == -1; + }) + if (!newSelectors.length) + break; + } + if (newSelectors.length) { + newRules[i].selectors = newSelectors; + console.log("Adding NEW rule: ", newRules[i]) + oldRules.splice(i, 0, newRules[i]); + } + } + + oldRules = normalizeStylesheet(oldRules); + + css = cssStringify({stylesheet: {rules: oldRules}}, { compress: false }); + } catch(e) { + console.log("Creating new file: " + name + ".css") + css = cssStringify(cssParse(css), { compress: false }); + } + + var js = fillTemplate(jsTemplate, { + name: name, + css: 'require("../requirejs/text!./' + name + '.css")', // quoteString(css), // + cssClass: "ace-" + hyphenate(name), + isDark: styles.isDark + }); + + fs.writeFileSync(outputDirectory + "/" + name + ".js", js); + fs.writeFileSync(outputDirectory + "/" + name + ".css", css); + }) +} + +if (process.argv.length > 1) { + var args = process.argv.splice(2); + if (args.length < 3) { + console.error("Usage: node tmtheme.js [theme_name, path/to/theme.tmTheme path/to/output/directory]"); + process.exit(1); + } + var name = args[0]; + var themePath = args[1]; + var outputDirectory = args[2]; + convertTheme(name, themePath, outputDirectory); +} else { + for (var name in themes) { + convertBuiltinTheme(name); + } +} + +var sortedUnsupportedScopes = {}; +for (var u in unsupportedScopes) { + var value = unsupportedScopes[u]; + if (sortedUnsupportedScopes[value] === undefined) { + sortedUnsupportedScopes[value] = []; + } + sortedUnsupportedScopes[value].push(u); +} + +console.log("I found these unsupported scopes:"); +console.log(sortedUnsupportedScopes); +console.log("It's safe to ignore these, but they may affect your syntax highlighting if your mode depends on any of these rules."); +console.log("Refer to the docs on ace.ajax.org for information on how to add a scope to the CSS generator."); + + +/*** TODO: generate images for indent guides in node + +var indentGuideColor = "#2D2D2D" +var canvas = document.createElement("canvas") +canvas.width = 1; canvas.height = 2; +var ctx = canvas.getContext("2d") +imageData = ctx.getImageData(0,0,1,2) + +function getColor(color) { + ctx.fillStyle = color; + ctx.fillRect(0,0,1,2); + return Array.slice(ctx.getImageData(0,0,1,2).data).slice(0,4) +} +bgColor = getComputedStyle(ace.renderer.scroller).backgroundColor +var a = [].concat(getColor(bgColor), getColor(indentGuideColor)); +a.forEach(function(val,i){imageData.data[i] = val}) + +ctx.putImageData(imageData,0,0) +image = canvas.toDataURL("png") + +var rule = "."+ace.renderer.$theme +" .ace_indent-guide {\n\ + background: url(" + image +") right repeat-y;\n\ +}" +console.log(rule) +require("ace/lib/dom").importCssString(rule) + +*/ diff --git a/node_modules/ace/tool/tmthemes/Active4D.tmTheme b/node_modules/ace/tool/tmthemes/Active4D.tmTheme new file mode 100644 index 00000000..4ffa60d9 --- /dev/null +++ b/node_modules/ace/tool/tmthemes/Active4D.tmTheme @@ -0,0 +1,407 @@ + + + + + name + Active4D + settings + + + settings + + background + #FFFFFF + caret + #000000 + foreground + #3B3B3B + invisibles + #BFBFBF + lineHighlight + #00000012 + selection + #BAD6FD + + + + name + Embedded source + scope + text.html source.active4d + settings + + background + #E2E9FF5E + + + + name + Plain XML text + scope + text.xml + settings + + foreground + #000000 + + + + name + Line comment + scope + comment.line + settings + + fontStyle + + foreground + #AF82D4 + + + + name + Block comment + scope + comment.block + settings + + foreground + #AF82D4 + + + + name + String + scope + string + settings + + fontStyle + + foreground + #666666 + + + + name + Interpolated entity + scope + string.interpolated variable + settings + + fontStyle + bold + foreground + #66CCFF + + + + name + Number + scope + constant.numeric + settings + + foreground + #A8017E + + + + name + User-defined constant + scope + constant.character, constant.other + settings + + + + name + Date/time literal + scope + constant.other.date, constant.other.time + settings + + fontStyle + bold + foreground + #66CCFF + + + + name + Built-in constant + scope + constant.language + settings + + foreground + #A535AE + + + + name + Local variable + scope + variable.other.local + settings + + fontStyle + bold + foreground + #6392FF + + + + name + Variable + scope + variable + settings + + fontStyle + bold + foreground + #0053FF + + + + name + Table/field + scope + variable.other.table-field + settings + + foreground + #6988AE + + + + name + Keyword + scope + keyword + settings + + fontStyle + bold + foreground + #006699 + + + + name + Operator + scope + keyword.operator + settings + + + + name + Storage + scope + storage + settings + + foreground + #FF5600 + + + + name + Type name + scope + entity.name.type + settings + + foreground + #21439C + + + + name + Inherited class + scope + entity.other.inherited-class + settings + + + + name + Function name + scope + entity.name.function + settings + + foreground + #21439C + + + + name + Function argument + scope + variable.parameter + settings + + + + name + Tag container + scope + meta.tag + settings + + foreground + #7A7A7A + + + + name + Tag name + scope + entity.name.tag + settings + + foreground + #016CFF + + + + name + Tag attribute + scope + entity.other.attribute-name + settings + + foreground + #963DFF + + + + name + Command/method + scope + support.function + settings + + fontStyle + bold + foreground + #45AE34 + + + + name + Named constant + scope + support.constant + settings + + foreground + #B7734C + + + + name + Library class/type + scope + support.type, support.class + settings + + foreground + #A535AE + + + + name + Library variable + scope + support.variable + settings + + foreground + #A535AE + + + + name + Invalid + scope + invalid + settings + + background + #990000 + foreground + #FFFFFF + + + + name + diff header + scope + meta.diff + settings + + background + #656565 + foreground + #FFFFFF + + + + name + diff line range + scope + meta.diff.range + settings + + background + #1B63FF + foreground + #FFFFFF + + + + name + diff deleted line + scope + markup.deleted.diff + settings + + background + #FF7880 + foreground + #000000 + + + + name + diff inserted line + scope + markup.inserted.diff + settings + + background + #98FF9A + foreground + #000000 + + + + name + diff unchanged line + scope + source.diff + settings + + foreground + #5E5E5E + + + + uuid + 7D2863D0-473C-47A0-B03B-92880559EBA9 + + diff --git a/node_modules/ace/tool/tmthemes/All Hallows Eve.tmTheme b/node_modules/ace/tool/tmthemes/All Hallows Eve.tmTheme new file mode 100644 index 00000000..47a67978 --- /dev/null +++ b/node_modules/ace/tool/tmthemes/All Hallows Eve.tmTheme @@ -0,0 +1,277 @@ + + + + + author + David Heinemeier Hansson + name + All Hallow's Eve + settings + + + settings + + background + #000000 + caret + #FFFFFF + foreground + #FFFFFF + invisibles + #404040 + lineHighlight + #333300 + selection + #73597EE0 + + + + name + Text base + scope + text + settings + + background + #434242 + foreground + #FFFFFF + + + + name + Source base + scope + source + settings + + background + #000000 + foreground + #FFFFFF + + + + name + Comment + scope + comment + settings + + foreground + #9933CC + + + + name + Constant + scope + constant + settings + + foreground + #3387CC + + + + name + Keyword + scope + keyword + settings + + fontStyle + + foreground + #CC7833 + + + + name + Pre-processor Line + scope + meta.preprocessor.c + settings + + fontStyle + + foreground + #D0D0FF + + + + name + Pre-processor Directive + scope + keyword.control.import + settings + + fontStyle + + + + + name + Function name + scope + entity.name.function + settings + + fontStyle + + + + + name + Function argument + scope + variable.parameter + settings + + fontStyle + italic + + + + name + Block comment + scope + source comment.block + settings + + background + #9B9B9B + foreground + #FFFFFF + + + + name + String + scope + string + settings + + foreground + #66CC33 + + + + name + String escapes + scope + string constant.character.escape + settings + + foreground + #AAAAAA + + + + name + String (executed) + scope + string.interpolated + settings + + background + #CCCC33 + foreground + #000000 + + + + name + Regular expression + scope + string.regexp + settings + + foreground + #CCCC33 + + + + name + String (literal) + scope + string.literal + settings + + foreground + #CCCC33 + + + + name + String escapes (executed) + scope + string.interpolated constant.character.escape + settings + + foreground + #555555 + + + + name + Type name + scope + entity.name.type + settings + + fontStyle + underline + + + + name + Class inheritance + scope + entity.other.inherited-class + settings + + fontStyle + italic underline + + + + name + Tag name + scope + entity.name.tag + settings + + fontStyle + underline + + + + name + Tag attribute + scope + entity.other.attribute-name + settings + + fontStyle + + + + + name + Support function + scope + support.function + settings + + fontStyle + + foreground + #C83730 + + + + uuid + 37F22BDC-B2F4-11D9-850C-000A95A89C98 + + diff --git a/node_modules/ace/tool/tmthemes/Amy.tmTheme b/node_modules/ace/tool/tmthemes/Amy.tmTheme new file mode 100644 index 00000000..b3258c46 --- /dev/null +++ b/node_modules/ace/tool/tmthemes/Amy.tmTheme @@ -0,0 +1,557 @@ + + + + + name + Amy + author + William D. Neumann + settings + + + settings + + background + #200020 + caret + #7070FF + foreground + #D0D0FF + invisibles + #BFBFBF + lineHighlight + #80000040 + selection + #80000080 + + + + name + Comment + scope + comment.block + settings + + background + #200020 + fontStyle + italic + foreground + #404080 + + + + name + String + scope + string + settings + + foreground + #999999 + + + + name + Built-in constant + scope + constant.language + settings + + foreground + #707090 + + + + name + Integer + scope + constant.numeric + settings + + foreground + #7090B0 + + + + name + Int32 constant + scope + constant.numeric.integer.int32 + settings + + fontStyle + bold + + + + name + Int64 constant + scope + constant.numeric.integer.int64 + settings + + fontStyle + italic + + + + name + Nativeint constant + scope + constant.numeric.integer.nativeint + settings + + fontStyle + bold italic + + + + name + Floating-point constant + scope + constant.numeric.floating-point.ocaml + settings + + fontStyle + underline + + + + name + Character constant + scope + constant.character + settings + + fontStyle + + foreground + #666666 + + + + name + Boolean constant + scope + constant.language.boolean + settings + + foreground + #8080A0 + + + + name + Built-in constant + scope + constant.language + settings + + + + name + User-defined constant + scope + constant.other + settings + + + + name + Variable + scope + variable.language, variable.other + settings + + fontStyle + + foreground + #008080 + + + + name + Keyword + scope + keyword + settings + + foreground + #A080FF + + + + name + Keyword operator + scope + keyword.operator + settings + + foreground + #A0A0FF + + + + name + Keyword decorator + scope + keyword.other.decorator + settings + + foreground + #D0D0FF + + + + name + Floating-point infix operator + scope + keyword.operator.infix.floating-point.ocaml + settings + + fontStyle + underline + + + + name + Floating-point prefix operator + scope + keyword.operator.prefix.floating-point.ocaml + settings + + fontStyle + underline + + + + name + Compiler directives + scope + keyword.other.directive + settings + + fontStyle + + foreground + #C080C0 + + + + name + Line-number directives + scope + keyword.other.directive.line-number + settings + + fontStyle + underline + foreground + #C080C0 + + + + name + Control keyword + scope + keyword.control + settings + + foreground + #80A0FF + + + + name + Storage + scope + storage + settings + + foreground + #B0FFF0 + + + + name + Variants + scope + entity.name.type.variant + settings + + foreground + #60B0FF + + + + name + Polymorphic variants + scope + storage.type.variant.polymorphic, entity.name.type.variant.polymorphic + settings + + fontStyle + italic + foreground + #60B0FF + + + + name + Module definitions + scope + entity.name.type.module + settings + + foreground + #B000B0 + + + + name + Module type definitions + scope + entity.name.type.module-type.ocaml + settings + + fontStyle + underline + foreground + #B000B0 + + + + name + Support modules + scope + support.other + settings + + foreground + #A00050 + + + + name + Class name + scope + entity.name.type.class + settings + + foreground + #70E080 + + + + name + Class type + scope + entity.name.type.class-type + settings + + fontStyle + + foreground + #70E0A0 + + + + name + Inherited class + scope + entity.other.inherited-class + settings + + + + name + Function name + scope + entity.name.function + settings + + foreground + #50A0A0 + + + + name + Function argument + scope + variable.parameter + settings + + foreground + #80B0B0 + + + + name + Token definition (ocamlyacc) + scope + entity.name.type.token + settings + + fontStyle + + foreground + #3080A0 + + + + name + Token reference (ocamlyacc) + scope + entity.name.type.token.reference + settings + + fontStyle + + foreground + #3CB0D0 + + + + name + Non-terminal definition (ocamlyacc) + scope + entity.name.function.non-terminal + settings + + foreground + #90E0E0 + + + + name + Non-terminal reference (ocamlyacc) + scope + entity.name.function.non-terminal.reference + settings + + foreground + #C0F0F0 + + + + name + Tag name + scope + entity.name.tag + settings + + foreground + #009090 + + + + name + Tag attribute + scope + entity.other.attribute-name + settings + + + + name + Library function + settings + + background + #200020 + + + + name + Library constant + scope + support.constant + settings + + background + #200020 + + + + name + Library class/type + scope + support.type, support.class + settings + + + + name + Library variable + scope + support.other.variable + settings + + + + name + Invalid - illegal + scope + invalid.illegal + settings + + background + #FFFF00 + fontStyle + bold + foreground + #400080 + + + + name + Invalid - depricated + scope + invalid.deprecated + settings + + background + #CC66FF + foreground + #200020 + + + + name + Camlp4 code + scope + source.camlp4.embedded + settings + + background + #40008054 + + + + name + Camlp4 temp (parser) + scope + source.camlp4.embedded.parser.ocaml + settings + + fontStyle + + + + + name + Punctuation + scope + punctuation + settings + + foreground + #805080 + + + + uuid + 3C01FADD-7592-49DD-B7A5-1B82CA4E57B5 + + diff --git a/node_modules/ace/tool/tmthemes/Blackboard.tmTheme b/node_modules/ace/tool/tmthemes/Blackboard.tmTheme new file mode 100644 index 00000000..18bb72e3 --- /dev/null +++ b/node_modules/ace/tool/tmthemes/Blackboard.tmTheme @@ -0,0 +1,350 @@ + + + + + name + Blackboard + author + Domenico Carbotta + settings + + + settings + + background + #0C1021 + caret + #FFFFFFA6 + foreground + #F8F8F8 + invisibles + #FFFFFF40 + lineHighlight + #FFFFFF0F + selection + #253B76 + + + + name + Comment + scope + comment + settings + + fontStyle + + foreground + #AEAEAE + + + + name + Constant + scope + constant + settings + + fontStyle + + foreground + #D8FA3C + + + + name + Entity + scope + entity + settings + + fontStyle + + foreground + #FF6400 + + + + name + Keyword + scope + keyword + settings + + fontStyle + + foreground + #FBDE2D + + + + name + Storage + scope + storage + settings + + fontStyle + + foreground + #FBDE2D + + + + name + String + scope + string, meta.verbatim + settings + + fontStyle + + foreground + #61CE3C + + + + name + Support + scope + support + settings + + fontStyle + + foreground + #8DA6CE + + + + name + Variable + scope + variable + settings + + fontStyle + + + + + name + Invalid – Deprecated + scope + invalid.deprecated + settings + + fontStyle + italic + foreground + #AB2A1D + + + + name + Invalid – Illegal + scope + invalid.illegal + settings + + background + #9D1E15 + foreground + #F8F8F8 + + + + name + Superclass + scope + entity.other.inherited-class + settings + + fontStyle + italic + foreground + #FF6400 + + + + name + String interpolation + scope + string constant.other.placeholder + settings + + fontStyle + + foreground + #FF6400 + + + + name + meta.function-call.py + scope + meta.function-call.py + settings + + fontStyle + + foreground + #BECDE6 + + + + name + meta.tag + scope + meta.tag, meta.tag entity + settings + + foreground + #7F90AA + + + + name + entity.name.section + scope + entity.name.section + settings + + fontStyle + + foreground + #FFFFFF + + + + name + OCaml variant + scope + keyword.type.variant + settings + + foreground + #D5E0F3 + + + + name + OCaml operator + scope + source.ocaml keyword.operator.symbol + settings + + foreground + #F8F8F8 + + + + name + OCaml infix operator + scope + source.ocaml keyword.operator.symbol.infix + settings + + fontStyle + + foreground + #8DA6CE + + + + name + OCaml prefix operator + scope + source.ocaml keyword.operator.symbol.prefix + settings + + fontStyle + + foreground + #8DA6CE + + + + name + OCaml f-p infix operator + scope + source.ocaml keyword.operator.symbol.infix.floating-point + settings + + fontStyle + underline + + + + name + OCaml f-p prefix operator + scope + source.ocaml keyword.operator.symbol.prefix.floating-point + settings + + fontStyle + underline + + + + name + OCaml f-p constant + scope + source.ocaml constant.numeric.floating-point + settings + + fontStyle + underline + + + + name + LaTeX environment + scope + text.tex.latex meta.function.environment + settings + + background + #FFFFFF08 + + + + name + LaTeX environment (nested) + scope + text.tex.latex meta.function.environment meta.function.environment + settings + + background + #7A96FA08 + + + + name + Latex support + scope + text.tex.latex support.function + settings + + fontStyle + + foreground + #FBDE2D + + + + name + PList unquoted string + scope + source.plist string.unquoted, source.plist keyword.operator + settings + + foreground + #FFFFFF + + + + uuid + A2C6BAA7-90D0-4147-BBF5-96B0CD92D109 + + diff --git a/node_modules/ace/tool/tmthemes/Brilliance Black.tmTheme b/node_modules/ace/tool/tmthemes/Brilliance Black.tmTheme new file mode 100644 index 00000000..560c825b --- /dev/null +++ b/node_modules/ace/tool/tmthemes/Brilliance Black.tmTheme @@ -0,0 +1,2619 @@ + + + + + author + Thomas Aylott + comment + Thomas Aylott ㊷ subtleGradient.com + name + Brilliance Black + settings + + + settings + + background + #0D0D0DFA + caret + #3333FF + foreground + #EEEEEE + invisibles + #CCCCCC1A + lineHighlight + #00008033 + selection + #0010B499 + + + + name + Thomas Aylott ㊷ + scope + meta.thomas_aylott + settings + + background + #FFFFFF + fontStyle + bold + foreground + #000000 + + + + name + subtleGradient.com + scope + meta.subtlegradient + settings + + background + #FFFFFF + fontStyle + underline + foreground + #555555 + + + + name + ~ String + scope + string -meta.tag -meta.doctype -string.regexp -string.literal -string.interpolated -string.quoted.literal -string.unquoted, variable.parameter.misc.css, text string source string, string.unquoted string, string.regexp string, string.interpolated string, meta.tag source string + settings + + background + #803D0033 + foreground + #FFFC80 + + + + name + ~ String Punctuation + scope + punctuation.definition.string -meta.tag + settings + + foreground + #803D00 + + + + name + ~ String Punctuation II + scope + string.regexp punctuation.definition.string, string.quoted.literal punctuation.definition.string, string.quoted.double.ruby.mod punctuation.definition.string + settings + + foreground + #FFF80033 + + + + name + ~ String Literal + scope + string.quoted.literal, string.quoted.double.ruby.mod + settings + + background + #43800033 + foreground + #FFF800 + + + + name + ~ String Unquoted + scope + string.unquoted -string.unquoted.embedded, string.quoted.double.multiline, meta.scope.heredoc + settings + + foreground + #FFBC80 + + + + name + ~ String Interpolated + scope + string.interpolated + settings + + background + #1A1A1A + foreground + #FFFC80 + + + + name + ~ String RegEx + scope + string.regexp + settings + + background + #43800033 + foreground + #FFF800 + + + + name + ~ String RegEx Group 1 + scope + string.regexp.group + settings + + background + #43800033 + + + + name + ~ String RegEx Group 2 + scope + string.regexp.group string.regexp.group + settings + + background + #43800033 + foreground + #FFFFFF66 + + + + name + ~ String RegEx Group 3 + scope + string.regexp.group string.regexp.group string.regexp.group + settings + + background + #43800033 + foreground + #FFFFFF66 + + + + name + ~ String RegEx Group 4 + scope + string.regexp.group string.regexp.group string.regexp.group string.regexp.group + settings + + background + #43800033 + foreground + #FFFFFF66 + + + + name + ~ String RegEx Character-Class + scope + string.regexp.character-class + settings + + background + #43800033 + foreground + #86FF00 + + + + name + ~ String RegEx Arbitrary-Repitition + scope + string.regexp.arbitrary-repitition + settings + + background + #43800033 + foreground + #00FFF8 + + + + name + ~ String RegEx Definition Keyword + scope + string.regexp punctuation.definition.string keyword.other + settings + + fontStyle + + foreground + #803D00 + + + + name + ~ Meta Group Assertion Regexp + scope + meta.group.assertion.regexp + settings + + background + #0086FF33 + + + + name + ~ Meta Assertion + scope + meta.assertion, meta.group.assertion keyword.control.group.regexp, meta.group.assertion punctuation.definition.group + settings + + foreground + #0086FF + + + + name + ~ Number + scope + constant.numeric + settings + + foreground + #C6FF00 + + + + name + ~ Character constant + scope + constant.character + settings + + foreground + #86FF00 + + + + name + ~ Built-in constant + scope + constant.language, keyword.other.unit, constant.other.java, constant.other.unit + settings + + foreground + #07FF00 + + + + name + ~ Built-in constant+ + scope + constant.language.pseudo-variable + settings + + background + #04800033 + foreground + #07FF00 + + + + name + ~ User-defined constant + scope + constant.other, constant.block + settings + + foreground + #00FF79 + + + + name + ~ Library constant + scope + support.constant, constant.name + settings + + foreground + #00FFF8 + + + + name + ————————————————— + settings + + + + name + √ pre-defined variable + scope + variable.other.readwrite.global.pre-defined, variable.language + settings + + background + #00807C33 + foreground + #00FF79 + + + + name + √ Constant Variable + scope + variable.other.constant + settings + + foreground + #00FFF8 + + + + name + √ Library variable + scope + support.variable + settings + + background + #00807C33 + foreground + #00FFF8 + + + + name + √ global Variable + scope + variable.other.readwrite.global + settings + + background + #00438033 + foreground + #00807C + + + + name + √ Variable + scope + variable.other, variable.js, punctuation.separator.variable + settings + + foreground + #31A6FF + + + + name + √ class Variable + scope + variable.other.readwrite.class + settings + + background + #0008FF33 + foreground + #0086FF + + + + name + √ instance Variable + scope + variable.other.readwrite.instance + settings + + foreground + #406180 + + + + name + √ Normal Variables + scope + variable.other.php, variable.other.normal + settings + + foreground + #406180 + + + + name + √ Variable Punctuation + scope + punctuation.definition, punctuation.separator.variable + settings + + foreground + #00000080 + + + + name + ————————————————— + settings + + + + name + ¢ Storage + scope + storage -storage.modifier + settings + + foreground + #7E0080 + + + + name + ¢ Entity Name Preprocessor + scope + other.preprocessor, entity.name.preprocessor + settings + + background + #803D0033 + + + + name + ~ variable.language.this.js.prototype + scope + variable.language.this.js + settings + + foreground + #666666 + + + + name + ¢ Storage Modifier + scope + storage.modifier + settings + + foreground + #803D00 + + + + name + ¢ Class name + scope + entity.name.class, entity.name.type.class, entity.name.type.module + settings + + foreground + #FF0000 + + + + name + ¢ Class + scope + meta.class -meta.class.instance, declaration.class, meta.definition.class, declaration.module + settings + + background + #FF000033 + foreground + #870000 + + + + name + ¢ Library class/type + scope + support.type, support.class + settings + + background + #87000033 + foreground + #FF0000 + + + + name + ¢ Instance + scope + entity.name.instance, entity.name.type.instance + settings + + foreground + #FF3D44 + + + + name + ¢ Instance.constructor + scope + meta.class.instance.constructor + settings + + background + #831E5133 + + + + name + ¢ Inherited class + scope + entity.other.inherited-class, entity.name.module + settings + + background + #80000433 + foreground + #FF0086 + + + + name + ¢ Class Method + scope + meta.definition.method + settings + + foreground + #FF0086 + + + + name + ¢ Function Declaration + scope + meta.function, meta.property.function, declaration.function + settings + + + + name + ¢ Function Declaration Name + scope + entity.name.function, entity.name.preprocessor + settings + + foreground + #FF0086 + + + + name + ¢ Function Declaration Parameters + scope + variable.parameter.function + settings + + foreground + #9799FF + + + + name + ¢ Function Declaration Parameters + scope + variable.parameter -variable.parameter.misc.css, meta.definition.method meta.definition.param-list, meta.function.method.with-arguments variable.parameter.function + settings + + foreground + #9799FF + + + + name + ¢ Function Declaration Parameters Punctuation + scope + punctuation.definition.parameters, variable.parameter.function punctuation.separator.object + settings + + foreground + #800004 + + + + name + â„¢ Function Call + scope + keyword.other.special-method, meta.function-call entity.name.function -(meta.function-call meta.function), support.function - variable + settings + + foreground + #782EC1 + + + + name + â„¢ Library Function Call + scope + meta.function-call support.function - variable + settings + + fontStyle + + foreground + #9D3EFF + + + + name + â„¢ Library Function Name + scope + support.function + settings + + background + #603F8033 + foreground + #603F80 + + + + name + â„¢ Function Call Arguments Punctuation + scope + punctuation.section.function, meta.brace.curly.function, meta.function-call punctuation.section.scope.ruby, meta.function-call punctuation.separator.object + settings + + fontStyle + + foreground + #BC80FF + + + + name + â„¢ Function Punctuation + scope + meta.group.braces.round punctuation.section.scope, +meta.group.braces.round meta.delimiter.object.comma, +meta.group.braces.curly.function meta.delimiter.object.comma, +meta.brace.round + settings + + fontStyle + bold + foreground + #BC80FF + + + + name + â„¢ Function Call Without Arguments + scope + meta.function-call.method.without-arguments, meta.function-call.method.without-arguments entity.name.function + settings + + foreground + #A88FC0 + + + + name + ————————————————— + settings + + + + name + â„¢ Keyword Control + scope + keyword.control + settings + + foreground + #F800FF + + + + name + â„¢ Keyword + scope + keyword + settings + + + + name + â„¢ Keyword other + scope + keyword.other + settings + + foreground + #7900FF + + + + name + â„¢ Regex Keyword + scope + source.regexp keyword.operator + settings + + + + name + â„¢ Keyword Operator + scope + keyword.operator, declaration.function.operator, meta.preprocessor.c.include, punctuation.separator.operator + settings + + foreground + #0000CE + + + + name + â„¢ Keyword Operator Assignment + scope + keyword.operator.assignment + settings + + background + #00009A33 + foreground + #0000CE + + + + name + â„¢ Keyword Operator Arithmetic + scope + keyword.operator.arithmetic + settings + + foreground + #2136CE + + + + name + â„¢ Keyword Operator Logical + scope + keyword.operator.logical + settings + + background + #00009A33 + foreground + #3759FF + + + + name + â„¢ Keyword Operator Comparison + scope + keyword.operator.comparison + settings + + foreground + #7C88FF + + + + name + meta.class.instance.constructor keyword.operator.new + scope + meta.class.instance.constructor keyword.operator.new + settings + + foreground + #800043 + + + + name + ————————————————— + settings + + + + name + ✘ HTML + settings + + + + name + ✘ Tag Doctype + scope + meta.doctype, meta.tag.sgml-declaration.doctype, meta.tag.sgml.doctype + settings + + background + #333333 + foreground + #CCCCCC + + + + name + ✘ Tag + scope + meta.tag + settings + + foreground + #333333 + + + + name + ✘ Tag Structure + scope + meta.tag.structure, meta.tag.segment + settings + + background + #333333BF + foreground + #666666 + + + + name + ✘ Tag Block + scope + meta.tag.block, meta.tag.xml, meta.tag.key + settings + + background + #4C4C4C33 + foreground + #4C4C4C + + + + name + ✘ Tag Inline + scope + meta.tag.inline + settings + + background + #803D0033 + foreground + #FF7900 + + + + name + meta.tag.inline source + scope + meta.tag.inline source + settings + + background + #803D0033 + + + + name + ✘ Tag Other + scope + meta.tag.other, entity.name.tag.style, entity.name.tag.script, meta.tag.block.script, source.js.embedded punctuation.definition.tag.html, source.css.embedded punctuation.definition.tag.html + settings + + background + #80000433 + foreground + #FF0007 + + + + name + ✘ Tag Form + scope + meta.tag.form, meta.tag.block.form + settings + + background + #00438033 + foreground + #0086FF + + + + name + ✘ Tag Meta + scope + meta.tag.meta + settings + + background + #3C008033 + foreground + #F800FF + + + + name + ✘ Tag Block Head + scope + meta.section.html.head + settings + + background + #121212 + + + + name + ✘ Tag Block Form + scope + meta.section.html.form + settings + + background + #0043801A + + + + name + ✘ XML Tag + scope + meta.tag.xml + settings + + foreground + #666666 + + + + name + ✘ Tag name + scope + entity.name.tag + settings + + foreground + #FFFFFF4D + + + + name + ✘ Tag attribute + scope + entity.other.attribute-name, meta.tag punctuation.definition.string + settings + + foreground + #FFFFFF33 + + + + name + ✘ Tag value + scope + meta.tag string -source -punctuation, text source text meta.tag string -punctuation + settings + + foreground + #FFFFFF66 + + + + name + ————————————————— + settings + + + + name + text meta.paragraph + scope + text meta.paragraph + settings + + foreground + #999999 + + + + name + M markup + scope + markup markup -(markup meta.paragraph.list) + settings + + background + #33333333 + foreground + #FFF800 + + + + name + M HR + scope + markup.hr + settings + + background + #FFFFFF + foreground + #000000 + + + + name + M heading + scope + markup.heading + settings + + fontStyle + + foreground + #FFFFFF + + + + name + M bold + scope + markup.bold + settings + + fontStyle + bold + foreground + #95D4FF80 + + + + name + M italic + scope + markup.italic + settings + + fontStyle + italic + + + + name + M strike + settings + + + + name + M add + settings + + + + name + M del + settings + + + + name + M underline + scope + markup.underline + settings + + fontStyle + underline + + + + name + M reference + scope + meta.reference, markup.underline.link + settings + + fontStyle + + foreground + #0086FF + + + + name + M reference name + scope + entity.name.reference + settings + + background + #00438033 + foreground + #00FFF8 + + + + name + M underline link + scope + meta.reference.list markup.underline.link, text.html.textile markup.underline.link + settings + + fontStyle + underline + foreground + #00FFF8 + + + + name + M raw block + scope + markup.raw.block + settings + + background + #80808040 + + + + name + M quote block + scope + markup.quote + settings + + background + #FFFFFF1A + + + + name + M list + scope + markup.list meta.paragraph + settings + + fontStyle + + foreground + #FFFFFF + + + + name + ————————————————— + settings + + + + name + Markdown + scope + text.html.markdown + settings + + background + #FFFFFF + foreground + #000000 + + + + name + text.html.markdown meta.paragraph + scope + text.html.markdown meta.paragraph + settings + + foreground + #000000 + + + + name + text.html.markdown markup.list meta.paragraph + scope + text.html.markdown markup.list meta.paragraph + settings + + foreground + #555555 + + + + name + text.html.markdown markup.heading + scope + text.html.markdown markup.heading + settings + + fontStyle + bold + foreground + #000000 + + + + name + text.html.markdown string + scope + text.html.markdown string + settings + + foreground + #8A5420 + + + + name + ————————————————— + settings + + + + name + § CSS + scope + source.css + settings + + + + name + § Selector + scope + meta.selector + settings + + foreground + #666666 + + + + name + Property Value Parens + scope + source.css meta.scope.property-list meta.property-value punctuation.definition.arguments, +source.css meta.scope.property-list meta.property-value punctuation.separator.arguments + settings + + fontStyle + + foreground + #006680 + + + + name + § Pseudo-Element + scope + entity.other.attribute-name.pseudo-element + settings + + foreground + #4F00FF + + + + name + § Pseudo-Class + scope + entity.other.attribute-name.pseudo-class, entity.other.attribute-name.tag.pseudo-class + settings + + foreground + #7900FF + + + + name + § Class + scope + meta.selector entity.other.attribute-name.class + settings + + foreground + #F800FF + + + + name + § ID + scope + meta.selector entity.other.attribute-name.id + settings + + foreground + #FF0086 + + + + name + § Tag + scope + meta.selector entity.name.tag + settings + + fontStyle + + foreground + #FF0007 + + + + name + § Tag Wildcard + scope + entity.name.tag.wildcard, entity.other.attribute-name.universal + settings + + fontStyle + bold + foreground + #FF7900 + + + + name + § Attribute + scope + source.css entity.other.attribute-name.attribute + settings + + foreground + #C25A00 + + + + name + § Attribute-Match + scope + source.css meta.attribute-selector keyword.operator.comparison + settings + + foreground + #673000 + + + + name + § meta.scope.property-list + scope + meta.scope.property-list + settings + + fontStyle + bold + foreground + #333333 + + + + name + § meta.property-name + scope + meta.property-name + settings + + fontStyle + + foreground + #999999 + + + + name + § support.type.property-name + scope + support.type.property-name + settings + + background + #0D0D0D + fontStyle + + foreground + #FFFFFF + + + + name + § meta.property-value + scope + meta.property-value + settings + + background + #19191980 + fontStyle + + foreground + #999999 + + + + name + ————————————————— + settings + + + + name + LaTeX + scope + text.latex + settings + + + + name + L Markup Raw + scope + text.latex markup.raw + settings + + background + #000000 + + + + name + L support.function + scope + text.latex support.function -support.function.textit -support.function.emph + settings + + foreground + #BC80FF + + + + name + L support.function.section + scope + text.latex support.function.section + settings + + foreground + #FFFFFFBF + + + + name + L entity.name.section + scope + text.latex entity.name.section -meta.group -keyword.operator.braces + settings + + background + #FFFFFF + fontStyle + + foreground + #000000 + + + + name + L constant.language.general + scope + text.latex constant.language.general + settings + + + + name + L keyword.operator.delimiter + scope + text.latex keyword.operator.delimiter + settings + + background + #00000080 + + + + name + L keyword.operator.brackets + scope + text.latex keyword.operator.brackets + settings + + foreground + #999999 + + + + name + L keyword.operator.braces + scope + text.latex keyword.operator.braces + settings + + fontStyle + + foreground + #666666 + + + + name + L meta.footnote + scope + meta.footnote + settings + + background + #00008033 + foreground + #0008FF4D + + + + name + L meta.label.reference + scope + text.latex meta.label.reference + settings + + background + #FFFFFF0D + fontStyle + + + + + name + L keyword.control.ref + scope + text.latex keyword.control.ref + settings + + background + #260001 + foreground + #FF0007 + + + + name + L variable.parameter.label.reference + scope + text.latex variable.parameter.label.reference + settings + + background + #400002 + foreground + #FFBC80 + + + + name + L keyword.control.cite + scope + text.latex keyword.control.cite + settings + + background + #260014 + foreground + #FF0086 + + + + name + L variable.parameter.cite + scope + variable.parameter.cite + settings + + background + #400022 + foreground + #FFBFE1 + + + + name + L variable.parameter.label + scope + text.latex variable.parameter.label + settings + + foreground + #FFFFFF80 + + + + name + L markup + scope + meta.function markup + settings + + foreground + #CDCDCD + + + + name + L meta.group.braces + scope + text.latex meta.group.braces + settings + + foreground + #33333333 + + + + name + L meta.environment.list + scope + text.latex meta.environment.list + settings + + background + #00000080 + fontStyle + + foreground + #33333333 + + + + name + L meta.environment.list 2 + scope + text.latex meta.environment.list meta.environment.list + settings + + background + #00000080 + foreground + #33333333 + + + + name + L meta.environment.list 3 + scope + text.latex meta.environment.list meta.environment.list meta.environment.list + settings + + background + #000000 + foreground + #33333333 + + + + name + L meta.environment.list 4 + scope + text.latex meta.environment.list meta.environment.list meta.environment.list meta.environment.list + settings + + foreground + #33333333 + + + + name + L meta.environment.list 5 + scope + text.latex meta.environment.list meta.environment.list meta.environment.list meta.environment.list meta.environment.list + settings + + foreground + #33333333 + + + + name + L meta.environment.list 6 + scope + text.latex meta.environment.list meta.environment.list meta.environment.list meta.environment.list meta.environment.list meta.environment.list + settings + + foreground + #33333333 + + + + name + L meta.end-document + scope + text.latex meta.end-document, text.latex meta.begin-document, meta.end-document.latex support.function, meta.end-document.latex variable.parameter, meta.begin-document.latex support.function, meta.begin-document.latex variable.parameter + settings + + background + #CCCCCC + foreground + #000000 + + + + name + ————————————————— + settings + + + + name + meta.brace.erb.return-value + scope + meta.brace.erb.return-value + settings + + background + #00805533 + foreground + #00FFAA + + + + name + source.ruby.rails.embedded.return-value.one-line + scope + source.ruby.rails.embedded.return-value.one-line + settings + + background + #8080801A + + + + name + meta.brace.erb + scope + punctuation.section.embedded -(source string source punctuation.section.embedded), meta.brace.erb.html + settings + + background + #00FFF81A + foreground + #00FFF8 + + + + name + source.ruby.rails.embedded.one-line + scope + source.ruby.rails.embedded.one-line + settings + + background + #00FFF81A + + + + name + String Embedded Source + scope + source string source punctuation.section.embedded + settings + + foreground + #406180 + + + + name + source.js.embedded + scope + source.js.embedded + settings + + background + #0D0D0D + + + + name + â—Š Source + scope + source + settings + + fontStyle + + + + + name + â—Š meta.brace.erb + scope + meta.brace.erb + settings + + background + #000000 + + + + name + â—Š Source String Source + scope + source string source + settings + + background + #33333380 + foreground + #FFFFFF + + + + name + â—Š Source String Interpolated Source + scope + source string.interpolated source + settings + + background + #00000099 + foreground + #999999 + + + + name + â—Š Source Embeded Source + scope + source source, source.java.embedded + settings + + background + #3333331A + + + + name + â—Š Text + scope + text -text.xml.strict + settings + + foreground + #FFFFFF + + + + name + â—Š Text Source + scope + text source, meta.scope.django.template + settings + + background + #000000 + foreground + #CCCCCC + + + + name + â—Š Text Source Text String + settings + + + + name + â—Š Text String Source + scope + text string source + settings + + foreground + #999999 + + + + name + â—Š Text Source String Source + settings + + + + name + â—Š Text String Source String Source + scope + text string source string source + settings + + + + name + ————————————————— + settings + + + + name + Invalid + scope + invalid -invalid.SOMETHING + settings + + background + #FF0007 + fontStyle + bold + foreground + #330004 + + + + name + Invalid Value + scope + invalid.SOMETHING + settings + + fontStyle + underline + foreground + #FF3600 + + + + name + Syntax + scope + meta.syntax + settings + + foreground + #333333 + + + + name + comment + scope + comment -comment.line + settings + + background + #33333333 + foreground + #4C4C4C + + + + name + comment.line + scope + comment.line + settings + + fontStyle + italic + foreground + #4C4C4C + + + + name + Comment Punctuation + scope + comment punctuation + settings + + + + name + ✘ HTML Comment + scope + text comment.block -source + settings + + fontStyle + italic + + + + name + ————————————————— + settings + + + + name + D Diff Add + scope + markup.inserted + settings + + background + #00401E + foreground + #40FF9A + + + + name + D Diff Delete + scope + markup.deleted + settings + + background + #400022 + foreground + #FF40A3 + + + + name + D Diff Changed + scope + markup.changed + settings + + background + #803D00 + foreground + #FFFF55 + + + + name + text.subversion-commit meta.scope.changed-files + scope + text.subversion-commit meta.scope.changed-files, text.subversion-commit meta.scope.changed-files.svn meta.diff.separator + settings + + background + #000000 + foreground + #FFFFFF + + + + name + text.subversion-commit + scope + text.subversion-commit + settings + + background + #FFFFFF + foreground + #000000 + + + + name + ————————————————— + settings + + + + name + meta.delimiter + scope + punctuation.terminator, meta.delimiter, punctuation.separator.method + settings + + background + #FFFFFF03 + fontStyle + bold + foreground + #7F7F7F + + + + name + meta.delimiter.statement.js + scope + punctuation.terminator.statement, meta.delimiter.statement.js + settings + + background + #00000080 + + + + name + meta.delimiter.object.js + scope + meta.delimiter.object.js + settings + + background + #00000040 + + + + name + Bold String Quotes + scope + string.quoted.single.brace, string.quoted.double.brace + settings + + fontStyle + bold + foreground + #803D00 + + + + name + ————————————————— + settings + + + + name + ß Blog Post / Email Message + scope + text.blog, text.mail + settings + + background + #DCDCDC + foreground + #333333 + + + + name + ß Post Content + scope + text.blog text, text.mail text + settings + + background + #000000 + foreground + #CCCCCC + + + + name + ß Post Header Keys + scope + meta.header.blog keyword.other, meta.header.mail keyword.other + settings + + background + #00FFF81A + fontStyle + + foreground + #06403E + + + + name + ß Post Header Values + scope + meta.header.blog string.unquoted.blog, meta.header.mail string.unquoted + settings + + background + #FFFF551A + foreground + #803D00 + + + + name + ————————————————— + settings + + + + name + OCAML + settings + + + + name + entity.name.type.module + scope + source.ocaml entity.name.type.module + settings + + foreground + #FF0000 + + + + name + support.other.module + scope + source.ocaml support.other.module + settings + + background + #83000033 + foreground + #FF0000 + + + + name + entity.name.type.variant + scope + entity.name.type.variant + settings + + foreground + #00FFF8 + + + + name + entity.name.tag, meta.record.definition + scope + source.ocaml entity.name.tag, source.ocaml meta.record.definition + settings + + foreground + #00FF79 + + + + name + ———————— PUNCTUATION ———————— + settings + + + + name + punctuation.separator.parameters + scope + punctuation.separator.parameters + settings + + fontStyle + bold + foreground + #FFFFFF + + + + name + meta.brace.pipe + scope + meta.brace.pipe + settings + + background + #33333333 + fontStyle + + foreground + #4C4C4C + + + + name + Misc Punctuation + scope + meta.brace.erb, source.ruby.embedded.source.brace, punctuation.section.dictionary, punctuation.terminator.dictionary, punctuation.separator.object, punctuation.separator.statement, punctuation.separator.key-value.css + settings + + fontStyle + bold + foreground + #666666 + + + + name + Curly Punctuation + scope + punctuation.section.scope.curly, punctuation.section.scope + settings + + fontStyle + bold + foreground + #999999 + + + + name + Object Punctuation + scope + punctuation.separator.objects, +meta.group.braces.curly meta.delimiter.object.comma, +punctuation.separator.key-value -meta.tag, +source.ocaml punctuation.separator.match-definition + + settings + + fontStyle + bold + foreground + #0C823B + + + + name + Function Punctuation + scope + punctuation.separator.parameters.function.js,punctuation.definition.function, punctuation.separator.function-return, punctuation.separator.function-definition, punctuation.definition.arguments, punctuation.separator.arguments + settings + + foreground + #800043 + + + + name + Array Punctuation + scope + meta.group.braces.square punctuation.section.scope, meta.group.braces.square meta.delimiter.object.comma, meta.brace.square, punctuation.separator.array, punctuation.section.array, punctuation.definition.array, punctuation.definition.constant.range + settings + + background + #803D001A + fontStyle + bold + foreground + #7F5E40 + + + + name + Array, Range + scope + meta.structure.array -punctuation.definition.array, meta.definition.range -punctuation.definition.constant.range + settings + + background + #803D001A + + + + name + meta.brace.curly meta.group + scope + meta.brace.curly meta.group.css + settings + + background + #00000080 + fontStyle + + + + + name + º meta.source.embedded + scope + meta.source.embedded, entity.other.django.tagbraces + settings + + background + #00000080 + foreground + #666666 + + + + name + º meta.group.braces.round JS + scope + source.js meta.group.braces.round, meta.scope.heredoc + settings + + + + name + º Even + scope + source.ruby meta.even-tab, source.ruby meta.even-tab.group2, source.ruby meta.even-tab.group4, source.ruby meta.even-tab.group6, source.ruby meta.even-tab.group8, source.ruby meta.even-tab.group10, source.ruby meta.even-tab.group12 + + settings + + background + #00000080 + + + + name + º meta.block.slate + scope + meta.block.slate + settings + + foreground + #666666 + + + + name + º meta.block.content.slate + scope + meta.block.content.slate + settings + + foreground + #CCCCCC + + + + name + Function Group1 + scope + meta.function meta.group.braces.curly.function -(meta.group meta.group), meta.function meta.odd-tab.group1 + settings + + + + name + Group1 + scope + meta.odd-tab.group1, meta.group.braces, meta.block.slate, text.xml.strict meta.tag, meta.paren-group, meta.section + settings + + background + #0A0A0A + + + + name + Group2 + scope + meta.even-tab.group2, meta.group.braces meta.group.braces, meta.block.slate meta.block.slate, text.xml.strict meta.tag meta.tag, meta.group.braces meta.group.braces, meta.paren-group meta.paren-group, meta.section meta.section + settings + + background + #0E0E0E + + + + name + Group3 + scope + meta.odd-tab.group3, meta.group.braces meta.group.braces meta.group.braces , meta.block.slate meta.block.slate meta.block.slate , text.xml.strict meta.tag meta.tag meta.tag, meta.group.braces meta.group.braces meta.group.braces, meta.paren-group meta.paren-group meta.paren-group, meta.section meta.section meta.section + settings + + background + #111111 + + + + name + Group4 + scope + meta.even-tab.group4, meta.group.braces meta.group.braces meta.group.braces meta.group.braces , meta.block.slate meta.block.slate meta.block.slate meta.block.slate , text.xml.strict meta.tag meta.tag meta.tag meta.tag, meta.group.braces meta.group.braces meta.group.braces meta.group.braces, meta.paren-group meta.paren-group meta.paren-group meta.paren-group, meta.section meta.section meta.section meta.section + settings + + background + #151515 + + + + name + Group5 + scope + meta.odd-tab.group5, meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces , meta.block.slate meta.block.slate meta.block.slate meta.block.slate meta.block.slate , text.xml.strict meta.tag meta.tag meta.tag meta.tag meta.tag, meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces, meta.paren-group meta.paren-group meta.paren-group meta.paren-group meta.paren-group, meta.section meta.section meta.section meta.section meta.section + settings + + background + #191919 + + + + name + Group6 + scope + meta.even-tab.group6, meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces , meta.block.slate meta.block.slate meta.block.slate meta.block.slate meta.block.slate meta.block.slate , text.xml.strict meta.tag meta.tag meta.tag meta.tag meta.tag meta.tag, meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces, meta.paren-group meta.paren-group meta.paren-group meta.paren-group meta.paren-group meta.paren-group, meta.section meta.section meta.section meta.section meta.section meta.section + settings + + background + #1C1C1C + + + + name + Group7 + scope + meta.odd-tab.group7, meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces , meta.block.slate meta.block.slate meta.block.slate meta.block.slate meta.block.slate meta.block.slate meta.block.slate , text.xml.strict meta.tag meta.tag meta.tag meta.tag meta.tag meta.tag meta.tag, meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces, meta.paren-group meta.paren-group meta.paren-group meta.paren-group meta.paren-group meta.paren-group meta.paren-group, meta.section meta.section meta.section meta.section meta.section meta.section meta.section + settings + + background + #1F1F1F + + + + name + Group8 + scope + meta.even-tab.group8, meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces , meta.block.slate meta.block.slate meta.block.slate meta.block.slate meta.block.slate meta.block.slate meta.block.slate meta.block.slate , text.xml.strict meta.tag meta.tag meta.tag meta.tag meta.tag meta.tag meta.tag meta.tag, meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces, meta.paren-group meta.paren-group meta.paren-group meta.paren-group meta.paren-group meta.paren-group meta.paren-group meta.paren-group, meta.section meta.section meta.section meta.section meta.section meta.section meta.section meta.section + settings + + background + #212121 + + + + name + Group9 + scope + meta.odd-tab.group9, meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces , meta.block.slate meta.block.slate meta.block.slate meta.block.slate meta.block.slate meta.block.slate meta.block.slate meta.block.slate meta.block.slate , text.xml.strict meta.tag meta.tag meta.tag meta.tag meta.tag meta.tag meta.tag meta.tag meta.tag, meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces, meta.paren-group meta.paren-group meta.paren-group meta.paren-group meta.paren-group meta.paren-group meta.paren-group meta.paren-group meta.paren-group, meta.section meta.section meta.section meta.section meta.section meta.section meta.section meta.section meta.section + settings + + background + #242424 + + + + name + Group10 + scope + meta.even-tab.group10 + settings + + background + #1F1F1F + + + + name + Group11 + scope + meta.odd-tab.group11 + settings + + background + #151515 + + + + name + ———————— END ———————— + settings + + + + name + IE6 + scope + meta.property.vendor.microsoft.trident.4, +meta.property.vendor.microsoft.trident.4 support.type.property-name, +meta.property.vendor.microsoft.trident.4 punctuation.terminator.rule + settings + + fontStyle + + foreground + #1B95E2 + + + + name + IE7 + scope + meta.property.vendor.microsoft.trident.5, +meta.property.vendor.microsoft.trident.5 support.type.property-name, +meta.property.vendor.microsoft.trident.5 punctuation.separator.key-value, +meta.property.vendor.microsoft.trident.5 punctuation.terminator.rule + settings + + fontStyle + + foreground + #F5C034 + + + + uuid + 24847CB3-23BC-4BF9-861B-E39661A6DA71 + + diff --git a/node_modules/ace/tool/tmthemes/Brilliance Dull.tmTheme b/node_modules/ace/tool/tmthemes/Brilliance Dull.tmTheme new file mode 100644 index 00000000..39f90ae2 --- /dev/null +++ b/node_modules/ace/tool/tmthemes/Brilliance Dull.tmTheme @@ -0,0 +1,2243 @@ + + + + + author + Thomas Aylott + comment + by Thomas Aylott subtleGradient.com + name + Brilliance Dull + settings + + + settings + + background + #050505FA + caret + #7979B7 + foreground + #CDCDCD + invisibles + #CDCDCD1A + lineHighlight + #0000801A + selection + #2E2EE64D + + + + name + Thomas Aylott ㊷ + scope + meta.thomas_aylott + settings + + background + #FFFFFF + fontStyle + bold + foreground + #000000 + + + + name + subtleGradient.com + scope + meta.subtlegradient + settings + + background + #FFFFFF + fontStyle + underline + foreground + #555555 + + + + name + —————————————————— + scope + meta.subtlegradient + settings + + background + #FFFFFF + foreground + #E6E6E6 + + + + name + ~ String + scope + string -meta.tag -meta.doctype -string.regexp -string.literal -string.interpolated -string.quoted.literal -string.unquoted, variable.parameter.misc.css, text string source string, string.unquoted string, string.regexp string + settings + + background + #803D0033 + foreground + #D2D1AB + + + + name + ~ String Punctuation + scope + punctuation.definition.string -meta.tag + settings + + foreground + #533F2C + + + + name + ~ String Punctuation II + scope + string.regexp punctuation.definition.string, string.quoted.literal punctuation.definition.string, string.quoted.double.ruby.mod punctuation.definition.string + settings + + foreground + #FFF80033 + + + + name + ~ String Literal + scope + string.quoted.literal, string.quoted.double.ruby.mod + settings + + background + #43800033 + foreground + #A6A458 + + + + name + ~ String Unquoted + scope + string.unquoted -string.unquoted.embedded, string.quoted.double.multiline, meta.scope.heredoc + settings + + foreground + #D2BEAB + + + + name + ~ String Interpolated + scope + string.interpolated + settings + + background + #1A1A1A + foreground + #D2D1AB + + + + name + ~ String RegEx + scope + string.regexp + settings + + background + #43800033 + foreground + #A6A458 + + + + name + ~ String RegEx Group 1 + scope + string.regexp.group + settings + + background + #43800033 + + + + name + ~ String RegEx Group 2 + scope + string.regexp.group string.regexp.group + settings + + background + #43800033 + foreground + #FFFFFF66 + + + + name + ~ String RegEx Group 3 + scope + string.regexp.group string.regexp.group string.regexp.group + settings + + background + #43800033 + foreground + #FFFFFF66 + + + + name + ~ String RegEx Group 4 + scope + string.regexp.group string.regexp.group string.regexp.group string.regexp.group + settings + + background + #43800033 + foreground + #FFFFFF66 + + + + name + ~ String RegEx Character-Class + scope + string.regexp.character-class + settings + + background + #43800033 + foreground + #80A659 + + + + name + ~ String RegEx Arbitrary-Repitition + scope + string.regexp.arbitrary-repitition + settings + + background + #43800033 + foreground + #56A5A4 + + + + name + source.regexp keyword + scope + source.regexp keyword.operator + settings + + foreground + #A75980 + + + + name + ~ String RegEx Comment + scope + string.regexp comment + settings + + fontStyle + italic + foreground + #FFFFFF + + + + name + ~ Meta Group Assertion Regexp + scope + meta.group.assertion.regexp + settings + + background + #0086FF33 + + + + name + ~ Meta Assertion + scope + meta.assertion, meta.group.assertion keyword.control.group.regexp + settings + + foreground + #5780A6 + + + + name + ~ Number + scope + constant.numeric + settings + + foreground + #95A658 + + + + name + ~ Character constant + scope + constant.character + settings + + foreground + #80A659 + + + + name + ~ Built-in constant + scope + constant.language, keyword.other.unit, constant.other.java, constant.other.unit + settings + + foreground + #59A559 + + + + name + ~ Built-in constant+ + scope + constant.language.pseudo-variable + settings + + background + #04800033 + foreground + #59A559 + + + + name + ~ User-defined constant + scope + constant.other, constant.block + settings + + foreground + #57A57D + + + + name + ~ Library constant + scope + support.constant, constant.name + settings + + foreground + #56A5A4 + + + + name + ————————————————— + settings + + + + name + √ pre-defined variable + scope + variable.language, variable.other.readwrite.global.pre-defined + settings + + foreground + #5E6B6B + + + + name + √ Constant Variable + scope + variable.other.constant + settings + + foreground + #56A5A4 + + + + name + √ Library variable + scope + support.variable + settings + + background + #00807C33 + foreground + #56A5A4 + + + + name + √ global Variable + scope + variable.other.readwrite.global + settings + + background + #00438033 + foreground + #2B5252 + + + + name + √ Variable + scope + variable.other, variable.js + settings + + foreground + #5780A6 + + + + name + √ class Variable + scope + variable.other.readwrite.class + settings + + background + #0007FF33 + foreground + #5780A6 + + + + name + √ instance Variable + scope + variable.other.readwrite.instance + settings + + foreground + #555F69 + + + + name + √ Normal Variables + scope + variable.other.php, variable.other.normal + settings + + foreground + #555F69 + + + + name + √ Variable Punctuation + scope + punctuation.definition -punctuation.definition.comment, punctuation.separator.variable + settings + + foreground + #00000080 + + + + name + ————————————————— + settings + + + + name + ¢ Storage + scope + storage -storage.modifier + settings + + foreground + #A77D58 + + + + name + ¢ Entity Name Preprocessor + scope + other.preprocessor, entity.name.preprocessor + settings + + background + #803D0033 + + + + name + ~ variable.language.this.js.prototype + scope + variable.language.this.js + settings + + foreground + #666666 + + + + name + ¢ Storage Modifier + scope + storage.modifier + settings + + foreground + #533F2C + + + + name + ¢ Class name + scope + entity.name.class, entity.name.type.class, entity.name.type.module + settings + + foreground + #A7595A + + + + name + ¢ Class + scope + meta.class -meta.class.instance, declaration.class, meta.definition.class, declaration.module + settings + + background + #29161780 + foreground + #532D2D + + + + name + ¢ Library class/type + scope + support.type, support.class + settings + + background + #80000433 + foreground + #A7595A + + + + name + ¢ Instance + scope + entity.name.instance + settings + + foreground + #A7595A + + + + name + ¢ Instance.constructor + scope + meta.class.instance.constructor + settings + + background + #80004333 + + + + name + ¢ Inherited class + scope + entity.other.inherited-class, entity.name.module + settings + + background + #80000433 + foreground + #A75980 + + + + name + ¢ Class Method + scope + object.property.function, meta.definition.method + settings + + foreground + #A75980 + + + + name + ¢ Function + scope + meta.function -(meta.tell-block), meta.property.function, declaration.function + settings + + background + #80004333 + foreground + #532D40 + + + + name + ¢ Function name + scope + entity.name.function, entity.name.preprocessor + settings + + foreground + #A75980 + + + + name + ————————————————— + settings + + + + name + â„¢ Keyword + scope + keyword + settings + + foreground + #A459A5 + + + + name + â„¢ Keyword.control + scope + keyword.control + settings + + background + #3C008033 + foreground + #A459A5 + + + + name + â„¢ Special Function + scope + keyword.other.special-method, meta.function-call entity.name.function -(meta.function-call meta.function), support.function - variable + settings + + foreground + #8D809D + + + + name + â„¢ Library function + scope + support.function - variable + settings + + foreground + #634683 + + + + name + â„¢ Keyword.operator + scope + keyword.operator, declaration.function.operator, meta.preprocessor.c.include + settings + + fontStyle + bold + foreground + #7979B7 + + + + name + â„¢ keyword.operator.comparison + scope + keyword.operator.comparison + settings + + fontStyle + + foreground + #9899C8 + + + + name + â„¢ Function argument + scope + variable.parameter -variable.parameter.misc.css, meta.definition.method meta.definition.param-list, meta.function.method.with-arguments variable.parameter.function + settings + + background + #3C008033 + foreground + #ABACD2 + + + + name + ————————————————— + settings + + + + name + ✘ HTML + settings + + + + name + ✘ Tag Doctype + scope + meta.doctype, meta.tag.sgml-declaration.doctype, meta.tag.sgml.doctype + settings + + background + #333333 + foreground + #CDCDCD + + + + name + ✘ Tag + scope + meta.tag + settings + + foreground + #333333 + + + + name + ✘ Tag Structure + scope + meta.tag.structure, meta.tag.segment + settings + + background + #333333BF + foreground + #666666 + + + + name + ✘ Tag Block + scope + meta.tag.block, meta.tag.xml, meta.tag.key + settings + + background + #4C4C4C33 + foreground + #4C4C4C + + + + name + ✘ Tag Inline + scope + meta.tag.inline + settings + + background + #803D0033 + foreground + #A77D58 + + + + name + meta.tag.inline source + scope + meta.tag.inline source + settings + + background + #803D0033 + + + + name + ✘ Tag Other + scope + meta.tag.other, entity.name.tag.style, source entity.other.attribute-name -text.html.basic.embedded , entity.name.tag.script, meta.tag.block.script + settings + + background + #80000433 + foreground + #A7595A + + + + name + ✘ Tag Form + scope + meta.tag.form, meta.tag.block.form + settings + + background + #00438033 + foreground + #5780A6 + + + + name + ✘ Tag Meta + scope + meta.tag.meta + settings + + background + #3C008033 + foreground + #A459A5 + + + + name + ✘ Tag Block Head + scope + meta.section.html.head + settings + + background + #121212 + + + + name + ✘ Tag Block Form + scope + meta.section.html.form + settings + + background + #0043801A + + + + name + ✘ XML Tag + scope + meta.tag.xml + settings + + foreground + #666666 + + + + name + ✘ Tag name + scope + entity.name.tag + settings + + foreground + #FFFFFF4D + + + + name + ✘ Tag attribute + scope + entity.other.attribute-name, meta.tag punctuation.definition.string + settings + + foreground + #FFFFFF33 + + + + name + ✘ Tag value + scope + meta.tag string -source -punctuation, text source text meta.tag string -punctuation + settings + + foreground + #FFFFFF66 + + + + name + ————————————————— + settings + + + + name + M markdown + settings + + + + name + M markup + scope + markup markup -(markup meta.paragraph.list) + settings + + background + #33333333 + foreground + #A6A458 + + + + name + M HR + scope + markup.hr + settings + + background + #FFFFFF + foreground + #000000 + + + + name + M heading + scope + markup.heading + settings + + background + #33333380 + foreground + #666666 + + + + name + M bold + scope + markup.bold + settings + + fontStyle + bold + + + + name + M italic + scope + markup.italic + settings + + fontStyle + italic + + + + name + M strike + settings + + + + name + M add + settings + + + + name + M del + settings + + + + name + M underline + scope + markup.underline + settings + + fontStyle + underline + + + + name + M reference + scope + meta.reference, markup.underline.link + settings + + fontStyle + + foreground + #5780A6 + + + + name + M reference name + scope + entity.name.reference + settings + + background + #00438033 + foreground + #56A5A4 + + + + name + M underline link + scope + meta.reference.list markup.underline.link, text.html.textile markup.underline.link + settings + + fontStyle + underline + foreground + #56A5A4 + + + + name + M raw block + scope + markup.raw.block + settings + + background + #000000 + foreground + #999999 + + + + name + M quote block + scope + markup.quote + settings + + background + #FFFFFF1A + + + + name + ————————————————— + settings + + + + name + § CSS + scope + source.css + settings + + + + name + § Selector + scope + meta.selector + settings + + background + #00000080 + foreground + #666666 + + + + name + § Attribute-Match + scope + meta.attribute-match.css + settings + + background + #00048033 + foreground + #575AA6 + + + + name + § Pseudo-Class + scope + entity.other.attribute-name.pseudo-class, entity.other.attribute-name.tag.pseudo-class + settings + + foreground + #7C58A5 + + + + name + § Class + scope + meta.selector entity.other.attribute-name.class + settings + + foreground + #A459A5 + + + + name + § ID + scope + meta.selector entity.other.attribute-name.id + settings + + foreground + #A75980 + + + + name + § Tag + scope + meta.selector entity.name.tag + settings + + fontStyle + + foreground + #A7595A + + + + name + § Tag Wildcard + scope + entity.name.tag.wildcard, entity.other.attribute-name.universal + settings + + fontStyle + bold + foreground + #A77D58 + + + + name + § meta.scope.property-list + scope + meta.scope.property-list + settings + + fontStyle + bold + foreground + #333333 + + + + name + § meta.property-name + scope + meta.property-name + settings + + fontStyle + + foreground + #999999 + + + + name + § support.type.property-name + scope + support.type.property-name + settings + + background + #000000 + fontStyle + + foreground + #FFFFFF + + + + name + § meta.property-value + scope + meta.property-value + settings + + background + #0D0D0D + fontStyle + + foreground + #999999 + + + + name + ————————————————— + settings + + + + name + LaTeX + scope + text.latex + settings + + + + name + L Markup Raw + scope + text.latex markup.raw + settings + + background + #000000 + + + + name + L support.function + scope + text.latex support.function -support.function.textit -support.function.emph + settings + + foreground + #BDABD1 + + + + name + L support.function.section + scope + text.latex support.function.section + settings + + foreground + #FFFFFFBF + + + + name + L entity.name.section + scope + text.latex entity.name.section -meta.group -keyword.operator.braces + settings + + background + #FFFFFF + fontStyle + + foreground + #000000 + + + + name + L constant.language.general + scope + text.latex constant.language.general + settings + + + + name + L keyword.operator.delimiter + scope + text.latex keyword.operator.delimiter + settings + + background + #00000080 + + + + name + L keyword.operator.brackets + scope + text.latex keyword.operator.brackets + settings + + foreground + #999999 + + + + name + L keyword.operator.braces + scope + text.latex keyword.operator.braces + settings + + fontStyle + + foreground + #666666 + + + + name + L meta.footnote + scope + meta.footnote + settings + + background + #00048033 + foreground + #0008FF4D + + + + name + L meta.label.reference + scope + text.latex meta.label.reference + settings + + background + #FFFFFF0D + fontStyle + + + + + name + L keyword.control.ref + scope + text.latex keyword.control.ref + settings + + background + #180D0C + foreground + #A7595A + + + + name + L variable.parameter.label.reference + scope + text.latex variable.parameter.label.reference + settings + + background + #291616 + foreground + #D2BEAB + + + + name + L keyword.control.cite + scope + text.latex keyword.control.cite + settings + + background + #180D12 + foreground + #A75980 + + + + name + L variable.parameter.cite + scope + variable.parameter.cite + settings + + background + #29161F + foreground + #E8D5DE + + + + name + L variable.parameter.label + scope + text.latex variable.parameter.label + settings + + foreground + #FFFFFF80 + + + + name + L meta.group.braces + scope + text.latex meta.group.braces + settings + + foreground + #33333333 + + + + name + L meta.environment.list + scope + text.latex meta.environment.list + settings + + background + #00000080 + fontStyle + + foreground + #33333333 + + + + name + L meta.environment.list 2 + scope + text.latex meta.environment.list meta.environment.list + settings + + background + #00000080 + foreground + #33333333 + + + + name + L meta.environment.list 3 + scope + text.latex meta.environment.list meta.environment.list meta.environment.list + settings + + background + #000000 + foreground + #33333333 + + + + name + L meta.environment.list 4 + scope + text.latex meta.environment.list meta.environment.list meta.environment.list meta.environment.list + settings + + foreground + #33333333 + + + + name + L meta.environment.list 5 + scope + text.latex meta.environment.list meta.environment.list meta.environment.list meta.environment.list meta.environment.list + settings + + foreground + #33333333 + + + + name + L meta.environment.list 6 + scope + text.latex meta.environment.list meta.environment.list meta.environment.list meta.environment.list meta.environment.list meta.environment.list + settings + + foreground + #33333333 + + + + name + L meta.end-document + scope + text.latex meta.end-document, text.latex meta.begin-document, meta.end-document.latex support.function, meta.end-document.latex variable.parameter, meta.begin-document.latex support.function, meta.begin-document.latex variable.parameter + settings + + background + #CDCDCD + foreground + #000000 + + + + name + ————————————————— + settings + + + + name + meta.brace.erb.return-value + scope + meta.brace.erb.return-value + settings + + background + #45815D33 + foreground + #596B61 + + + + name + source.ruby.rails.embedded.return-value.one-line + scope + source.ruby.rails.embedded.return-value.one-line + settings + + background + #66666633 + + + + name + meta.brace.erb + scope + punctuation.section.embedded -(source string source punctuation.section.embedded), meta.brace.erb.html + settings + + background + #00FFF81A + foreground + #56A5A4 + + + + name + source.ruby.rails.embedded.one-line + scope + source.ruby.rails.embedded.one-line + settings + + background + #00FFF81A + + + + name + String Embedded Source + scope + source string source punctuation.section.embedded + settings + + foreground + #555F69 + + + + name + â—Š Source + scope + source + settings + + background + #000000 + fontStyle + + + + + name + â—Š meta.brace.erb + scope + meta.brace.erb + settings + + background + #000000 + + + + name + â—Š Source String Source + scope + source string source + settings + + background + #33333380 + foreground + #FFFFFF + + + + name + â—Š Source String Interpolated Source + scope + source string.interpolated source + settings + + background + #00000099 + foreground + #999999 + + + + name + â—Š Source Embeded Source + scope + source.java.embedded + settings + + background + #3333331A + + + + name + â—Š Text + scope + text -text.xml.strict + settings + + foreground + #FFFFFF + + + + name + â—Š Text Source + scope + text source, meta.scope.django.template + settings + + background + #000000 + foreground + #CCCCCC + + + + name + â—Š Text Source Text String + settings + + + + name + â—Š Text String Source + scope + text string source + settings + + foreground + #999999 + + + + name + â—Š Text Source String Source + settings + + + + name + â—Š Text String Source String Source + scope + text string source string source + settings + + + + name + ————————————————— + settings + + + + name + Syntax + scope + meta.syntax + settings + + foreground + #333333 + + + + name + Invalid + scope + invalid + settings + + background + #A7595A + fontStyle + bold + foreground + #211211 + + + + name + Comment + scope + 0comment + settings + + background + #0000FF1A + fontStyle + italic + foreground + #8F8FC3 + + + + name + Comment Punctuation + scope + comment punctuation + settings + + fontStyle + bold + foreground + #0000FF1A + + + + name + comment + scope + comment + settings + + foreground + #333333 + + + + name + Comment Punctuation + scope + comment punctuation + settings + + background + #8080800D + fontStyle + bold italic + foreground + #262626 + + + + name + ✘ HTML Comment + scope + text comment.block -source + settings + + fontStyle + italic + + + + name + ————————————————— + settings + + + + name + D Diff Add + scope + markup.inserted + settings + + background + #15281F + foreground + #81BB9E + + + + name + D Diff Delete + scope + markup.deleted + settings + + background + #400021 + foreground + #BC839F + + + + name + D Diff Changed + scope + markup.changed + settings + + background + #533F2C + foreground + #C3C38F + + + + name + text.subversion-commit meta.scope.changed-files + scope + text.subversion-commit meta.scope.changed-files, text.subversion-commit meta.scope.changed-files.svn meta.diff.separator + settings + + background + #000000 + foreground + #FFFFFF + + + + name + text.subversion-commit + scope + text.subversion-commit + settings + + background + #FFFFFF + foreground + #000000 + + + + name + ————————————————— + settings + + + + name + meta.delimiter + scope + punctuation.terminator, meta.delimiter, punctuation.separator.method + settings + + background + #FFFFFF03 + fontStyle + bold + foreground + #FFFFFF + + + + name + meta.delimiter.statement.js + scope + punctuation.terminator.statement, meta.delimiter.statement.js + settings + + background + #000000BF + + + + name + meta.delimiter.object.js + scope + meta.delimiter.object.js + settings + + background + #00000040 + + + + name + Bold String Quotes + scope + string.quoted.single.brace, string.quoted.double.brace + settings + + fontStyle + bold + foreground + #533F2C + + + + name + ————————————————— + settings + + + + name + meta.headers.blog + scope + text.blog -(text.blog text) + settings + + background + #FFFFFF + + + + name + meta.headers.blog + scope + meta.headers.blog + settings + + background + #FFFFFF + foreground + #666666 + + + + name + meta.headers.blog keyword.other.blog + scope + meta.headers.blog keyword.other.blog + settings + + background + #00FFF81A + fontStyle + + foreground + #192B2A + + + + name + meta.headers.blog string.unquoted.blog + scope + meta.headers.blog string.unquoted.blog + settings + + background + #FFFF551A + foreground + #533F2C + + + + name + ————————————————— + settings + + + + name + meta.brace.pipe + scope + meta.brace.pipe + settings + + background + #33333333 + fontStyle + + foreground + #4C4C4C + + + + name + Misc Punctuation + scope + meta.brace.erb, source.ruby.embedded.source.brace, punctuation.section.dictionary, punctuation.terminator.dictionary, punctuation.separator.object + settings + + fontStyle + bold + foreground + #4C4C4C + + + + name + Curly Punctuation + scope + meta.group.braces.curly punctuation.section.scope, meta.brace.curly + settings + + fontStyle + bold + foreground + #FFFFFF + + + + name + Object Punctuation + scope + punctuation.separator.objects, meta.group.braces.curly meta.delimiter.object.comma, punctuation.separator.key-value -meta.tag + settings + + fontStyle + bold + foreground + #345743 + + + + name + Array Punctuation + scope + meta.group.braces.square punctuation.section.scope, meta.group.braces.square meta.delimiter.object.comma, meta.brace.square, punctuation.separator.array, punctuation.section.array + settings + + background + #803D001A + fontStyle + bold + foreground + #695F55 + + + + name + meta.brace.curly meta.group + scope + meta.brace.curly meta.group + settings + + background + #00000080 + fontStyle + + foreground + #CDCDCD + + + + name + Function Punctuation + scope + meta.group.braces.round punctuation.section.scope, meta.group.braces.round meta.delimiter.object.comma, meta.brace.round + settings + + fontStyle + bold + foreground + #532D40 + + + + name + meta.brace.curly.function + scope + punctuation.section.function, meta.brace.curly.function, meta.function-call punctuation.section.scope.ruby + settings + + background + #3C008033 + fontStyle + + foreground + #ABACD2 + + + + name + º meta.source.embedded + scope + meta.source.embedded, entity.other.django.tagbraces + settings + + background + #00000080 + foreground + #666666 + + + + name + º meta.group.braces.round JS + scope + source.js meta.group.braces.round, meta.scope.heredoc + settings + + + + name + º meta.group.braces 1 + scope + meta.odd-tab.group1, meta.group.braces, meta.block.slate, text.xml.strict meta.tag, meta.tell-block meta.tell-block + settings + + background + #0A0A0A + + + + name + º meta.group.braces 2 + scope + meta.even-tab.group2, meta.group.braces meta.group.braces, meta.block.slate meta.block.slate, text.xml.strict meta.tag meta.tag, meta.group.braces meta.group.braces, meta.tell-block meta.tell-block + settings + + background + #0E0E0E + + + + name + º meta.group.braces 3 + scope + meta.odd-tab.group3, meta.group.braces meta.group.braces meta.group.braces , meta.block.slate meta.block.slate meta.block.slate , text.xml.strict meta.tag meta.tag meta.tag, meta.group.braces meta.group.braces meta.group.braces, meta.tell-block meta.tell-block meta.tell-block + settings + + background + #111111 + + + + name + º meta.group.braces 4 + scope + meta.even-tab.group4, meta.group.braces meta.group.braces meta.group.braces meta.group.braces , meta.block.slate meta.block.slate meta.block.slate meta.block.slate , text.xml.strict meta.tag meta.tag meta.tag meta.tag, meta.group.braces meta.group.braces meta.group.braces meta.group.braces, meta.tell-block meta.tell-block meta.tell-block meta.tell-block + settings + + background + #151515 + + + + name + º meta.group.braces 5 + scope + meta.odd-tab.group5, meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces , meta.block.slate meta.block.slate meta.block.slate meta.block.slate meta.block.slate , text.xml.strict meta.tag meta.tag meta.tag meta.tag meta.tag, meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces, meta.tell-block meta.tell-block meta.tell-block meta.tell-block meta.tell-block + settings + + background + #191919 + + + + name + º meta.group.braces 6 + scope + meta.even-tab.group6, meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces , meta.block.slate meta.block.slate meta.block.slate meta.block.slate meta.block.slate meta.block.slate , text.xml.strict meta.tag meta.tag meta.tag meta.tag meta.tag meta.tag, meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces, meta.tell-block meta.tell-block meta.tell-block meta.tell-block meta.tell-block meta.tell-block + settings + + background + #1C1C1C + + + + name + º meta.group.braces 7 + scope + meta.odd-tab.group7, meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces , meta.block.slate meta.block.slate meta.block.slate meta.block.slate meta.block.slate meta.block.slate meta.block.slate , text.xml.strict meta.tag meta.tag meta.tag meta.tag meta.tag meta.tag meta.tag, meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces, meta.tell-block meta.tell-block meta.tell-block meta.tell-block meta.tell-block meta.tell-block meta.tell-block + settings + + background + #1F1F1F + + + + name + º meta.group.braces 8 + scope + meta.even-tab.group8, meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces , meta.block.slate meta.block.slate meta.block.slate meta.block.slate meta.block.slate meta.block.slate meta.block.slate meta.block.slate , text.xml.strict meta.tag meta.tag meta.tag meta.tag meta.tag meta.tag meta.tag meta.tag, meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces, meta.tell-block meta.tell-block meta.tell-block meta.tell-block meta.tell-block meta.tell-block meta.tell-block meta.tell-block + settings + + background + #212121 + + + + name + º meta.group.braces 9 + scope + meta.odd-tab.group11, meta.odd-tab.group10, meta.odd-tab.group9, meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces , meta.block.slate meta.block.slate meta.block.slate meta.block.slate meta.block.slate meta.block.slate meta.block.slate meta.block.slate meta.block.slate , text.xml.strict meta.tag meta.tag meta.tag meta.tag meta.tag meta.tag meta.tag meta.tag meta.tag, meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces meta.group.braces, meta.tell-block meta.tell-block meta.tell-block meta.tell-block meta.tell-block meta.tell-block meta.tell-block meta.tell-block meta.tell-block + settings + + background + #242424 + + + + name + º meta.block.slate + scope + meta.block.slate + settings + + foreground + #666666 + + + + name + º meta.block.content.slate + scope + meta.block.content.slate + settings + + foreground + #CDCDCD + + + + name + ————————————————— + settings + + + + uuid + 4535004C-927A-401A-A6D5-1C9AC89E24C6 + + diff --git a/node_modules/ace/tool/tmthemes/Chrome DevTools.tmTheme b/node_modules/ace/tool/tmthemes/Chrome DevTools.tmTheme new file mode 100644 index 00000000..8f14e4fa --- /dev/null +++ b/node_modules/ace/tool/tmthemes/Chrome DevTools.tmTheme @@ -0,0 +1,294 @@ + + + + + author + Austin Cummings + name + Chrome DevTools + settings + + + settings + + background + #FFFFFF + caret + #000000 + foreground + #000000 + invisibles + #B3B3B3F4 + lineHighlight + #0000001A + selection + #BAD6FD + + + + name + String + scope + string + settings + + foreground + #C41A16 + + + + name + Number + scope + constant.numeric + settings + + foreground + #1C00CF + + + + name + Keyword + scope + keyword + settings + + foreground + #AA0D91 + + + + name + Operator + scope + keyword.operator + settings + + foreground + #000000 + + + + name + Identifier + scope + constant.language + settings + + foreground + #AA0D91 + + + + name + Exception + scope + support.class.exception + settings + + foreground + #990000 + + + + name + Function name + scope + entity.name.function + settings + + foreground + #000000 + + + + + name + Type name + scope + entity.name.type + settings + + fontStyle + bold underline + + + + name + Arguments + scope + variable.parameter + settings + + fontStyle + italic + + + + name + Comment + scope + comment + settings + + + foreground + #007400 + + + + name + Invalid + scope + invalid + settings + + + foreground + #FF0000 + + + + name + Trailing whitespace + scope + invalid.deprecated.trailing-whitespace + settings + + background + #E71A1100 + + + + name + Embedded source + scope + text source + settings + + background + #FAFAFAFC + foreground + #000000 + + + + name + Tag + scope + meta.tag, declaration.tag + settings + + foreground + #AA0D91 + + + + + name + Support + scope + support + settings + + fontStyle + bold + foreground + #000000 + + + + name + Storage + scope + storage + settings + + + foreground + #AA0D91 + + + + name + Section name + scope + entity.name.section + settings + + fontStyle + bold underline + + + + name + Frame title + scope + entity.name.function.frame + settings + + fontStyle + bold + foreground + #000000 + + + + + name + XML Declaration + scope + meta.tag.preprocessor.xml + settings + + foreground + #333333 + + + + name + Tag Attribute + scope + entity.other.attribute-name + settings + + fontStyle + italic + foreground + + #994500 + + + + name + Tag Name + scope + entity.name.tag + settings + + foreground + #881280 + + + + + uuid + 4FCFA210-B247-11D9-9D00-000D93347A42 + + diff --git a/node_modules/ace/tool/tmthemes/Clouds Midnight.tmTheme b/node_modules/ace/tool/tmthemes/Clouds Midnight.tmTheme new file mode 100644 index 00000000..1859deba --- /dev/null +++ b/node_modules/ace/tool/tmthemes/Clouds Midnight.tmTheme @@ -0,0 +1,361 @@ + + + + + name + Clouds Midnight + settings + + + settings + + background + #191919 + caret + #7DA5DC + foreground + #929292 + invisibles + #BFBFBF + lineHighlight + #D7D7D708 + selection + #000000 + + + + name + Comment + scope + comment + settings + + fontStyle + + foreground + #3C403B + + + + name + String + scope + string + settings + + fontStyle + + foreground + #5D90CD + + + + name + Number + scope + constant.numeric + settings + + foreground + #46A609 + + + + name + Built-in constant + scope + constant.language + settings + + fontStyle + + foreground + #39946A + + + + name + User-defined constant + scope + constant.character, constant.other + settings + + + + name + Variable + scope + variable.language, variable.other + settings + + fontStyle + + + + + name + Keyword + scope + keyword, support.constant.property-value, constant.other.color + settings + + fontStyle + + foreground + #927C5D + + + + name + Keyword -> Unit + scope + keyword.other.unit + settings + + foreground + #366F1A + + + + name + HTML Attribute + scope + entity.other.attribute-name.html + settings + + foreground + #A46763 + + + + name + Keyword -> Operator + scope + keyword.operator + settings + + foreground + #4B4B4B + + + + name + Storage + scope + storage + settings + + fontStyle + + foreground + #E92E2E + + + + name + Class name + scope + entity.name.class + settings + + fontStyle + + + + + name + Inherited class + scope + entity.other.inherited-class + settings + + fontStyle + + foreground + #858585 + + + + name + Function name + scope + entity.name.function + settings + + fontStyle + + + + + name + Function argument + scope + variable.parameter + settings + + + + name + Tag name + scope + entity.name.tag + settings + + fontStyle + + foreground + #606060 + + + + name + HTML Entity + scope + constant.character.entity + settings + + foreground + #A165AC + + + + name + JS Support Class + scope + support.class.js + settings + + foreground + #A165AC + + + + name + Tag attribute + scope + entity.other.attribute-name + settings + + fontStyle + + foreground + #606060 + + + + name + CSS Selector + scope + meta.selector.css, entity.name.tag.css, entity.other.attribute-name.id.css, entity.other.attribute-name.class.css + settings + + fontStyle + + foreground + #E92E2E + + + + name + CSS Property + scope + meta.property-name.css + settings + + foreground + #616161 + + + + name + Library function + scope + support.function + settings + + foreground + #E92E2E + + + + name + Library constant + scope + support.constant + settings + + + + name + Library class/type + scope + support.type, support.class + settings + + + + name + Library variable + scope + support.other.variable + settings + + fontStyle + + + + + name + Invalid + scope + invalid + settings + + background + #E92E2E + foreground + #FFFFFF + + + + name + Punctuation/Widgets + scope + punctuation.section.embedded + settings + + fontStyle + + foreground + #E92E2E + + + + name + Punctuation (Tags) + scope + punctuation.definition.tag + settings + + fontStyle + + foreground + #606060 + + + + name + Keyword -> CSS + scope + constant.other.color.rgb-value.css, support.constant.property-value.css + settings + + foreground + #A165AC + + + + uuid + E5304455-0AC7-4082-8E62-5FD1B3313EEC + + diff --git a/node_modules/ace/tool/tmthemes/Clouds.tmTheme b/node_modules/ace/tool/tmthemes/Clouds.tmTheme new file mode 100644 index 00000000..821476be --- /dev/null +++ b/node_modules/ace/tool/tmthemes/Clouds.tmTheme @@ -0,0 +1,348 @@ + + + + + name + Clouds + settings + + + settings + + background + #FFFFFF + caret + #000000 + foreground + #000000 + invisibles + #BFBFBF + lineHighlight + #FFFBD1 + selection + #BDD5FC + + + + name + Comment + scope + comment + settings + + fontStyle + + foreground + #BCC8BA + + + + name + String + scope + string + settings + + fontStyle + + foreground + #5D90CD + + + + name + Number + scope + constant.numeric + settings + + foreground + #46A609 + + + + name + Built-in constant + scope + constant.language + settings + + fontStyle + + foreground + #39946A + + + + name + User-defined constant + scope + constant.character, constant.other + settings + + + + name + Variable + scope + variable.language, variable.other + settings + + fontStyle + + + + + name + Keyword + scope + keyword, support.constant.property-value, constant.other.color + settings + + fontStyle + + foreground + #AF956F + + + + name + Keyword -> Unit + scope + keyword.other.unit + settings + + foreground + #96DC5F + + + + name + Keyword -> Operator + scope + keyword.operator + settings + + foreground + #484848 + + + + name + Storage + scope + storage + settings + + fontStyle + + foreground + #C52727 + + + + name + Class name + scope + entity.name.class + settings + + fontStyle + + + + + name + Inherited class + scope + entity.other.inherited-class + settings + + fontStyle + + foreground + #858585 + + + + name + Function name + scope + entity.name.function + settings + + fontStyle + + + + + name + Function argument + scope + variable.parameter + settings + + + + name + Tag name + scope + entity.name.tag + settings + + fontStyle + + foreground + #606060 + + + + name + HTML Entity + scope + constant.character.entity + settings + + foreground + #BF78CC + + + + name + JS Support Class + scope + support.class.js + settings + + foreground + #BF78CC + + + + name + Tag attribute + scope + entity.other.attribute-name + settings + + fontStyle + + foreground + #606060 + + + + name + CSS Selector + scope + meta.selector.css, entity.name.tag.css, entity.other.attribute-name.id.css, entity.other.attribute-name.class.css + settings + + fontStyle + + foreground + #C52727 + + + + name + CSS Property + scope + meta.property-name.css + settings + + foreground + #484848 + + + + name + Library function + scope + support.function + settings + + foreground + #C52727 + + + + name + Library constant + scope + support.constant + settings + + + + name + Library class/type + scope + support.type, support.class + settings + + + + name + Library variable + scope + support.other.variable + settings + + fontStyle + + + + + name + Invalid + scope + invalid + settings + + background + #FF002A + + + + name + Punctuation/Widgets + scope + punctuation.section.embedded + settings + + fontStyle + + foreground + #C52727 + + + + name + Punctuation (Tags) + scope + punctuation.definition.tag + settings + + fontStyle + + foreground + #606060 + + + + name + Keyword -> CSS + scope + constant.other.color.rgb-value.css, support.constant.property-value.css + settings + + foreground + #BF78CC + + + + uuid + 47536290-6FC1-4B09-A08F-B219909E1A69 + + diff --git a/node_modules/ace/tool/tmthemes/Cobalt.tmTheme b/node_modules/ace/tool/tmthemes/Cobalt.tmTheme new file mode 100644 index 00000000..3c685f25 --- /dev/null +++ b/node_modules/ace/tool/tmthemes/Cobalt.tmTheme @@ -0,0 +1,559 @@ + + + + + author + Jacob Rus + comment + Created by Jacob Rus. Based on ‘Slate’ by Wilson Miner + name + Cobalt + settings + + + settings + + background + #002240 + caret + #FFFFFF + foreground + #FFFFFF + invisibles + #FFFFFF26 + lineHighlight + #00000059 + selection + #B36539BF + + + + name + Punctuation + scope + punctuation - (punctuation.definition.string | punctuation.definition.comment) + settings + + fontStyle + + foreground + #E1EFFF + + + + name + Constant + scope + constant + settings + + fontStyle + + foreground + #FF628C + + + + name + Entity + scope + entity + settings + + fontStyle + + foreground + #FFDD00 + + + + name + Keyword + scope + keyword + settings + + fontStyle + + foreground + #FF9D00 + + + + name + Storage + scope + storage + settings + + fontStyle + + foreground + #FFEE80 + + + + name + String + scope + string -string.unquoted.old-plist -string.unquoted.heredoc, string.unquoted.heredoc string + settings + + fontStyle + + foreground + #3AD900 + + + + name + Comment + scope + comment + settings + + fontStyle + italic + foreground + #0088FF + + + + name + Support + scope + support + settings + + fontStyle + + foreground + #80FFBB + + + + name + Variable + scope + variable + settings + + fontStyle + + foreground + #CCCCCC + + + + name + Lang Variable + scope + variable.language + settings + + fontStyle + + foreground + #FF80E1 + + + + name + Function Call + scope + meta.function-call + settings + + foreground + #FFEE80 + + + + name + Invalid + scope + invalid + settings + + background + #800F00 + foreground + #F8F8F8 + + + + name + Embedded Source + scope + text source, string.unquoted.heredoc, source source + settings + + background + #223545 + fontStyle + + foreground + #FFFFFF + + + + name + Entity inherited-class + scope + entity.other.inherited-class + settings + + fontStyle + italic + foreground + #80FCFF + + + + name + String embedded-source + scope + string.quoted source + settings + + fontStyle + + foreground + #9EFF80 + + + + name + String constant + scope + string constant + settings + + foreground + #80FF82 + + + + name + String.regexp + scope + string.regexp + settings + + foreground + #80FFC2 + + + + name + String variable + scope + string variable + settings + + foreground + #EDEF7D + + + + name + Support.function + scope + support.function + settings + + fontStyle + + foreground + #FFB054 + + + + name + Support.constant + scope + support.constant + settings + + fontStyle + + foreground + #EB939A + + + + name + Exception + scope + support.type.exception + settings + + foreground + #FF1E00 + + + + name + C/C++ Preprocessor Line + scope + meta.preprocessor.c + settings + + foreground + #8996A8 + + + + name + C/C++ Preprocessor Directive + scope + meta.preprocessor.c keyword + settings + + foreground + #AFC4DB + + + + name + Doctype/XML Processing + scope + meta.sgml.html meta.doctype, meta.sgml.html meta.doctype entity, meta.sgml.html meta.doctype string, meta.xml-processing, meta.xml-processing entity, meta.xml-processing string + settings + + foreground + #73817D + + + + name + Meta.tag.A + scope + meta.tag, meta.tag entity + settings + + foreground + #9EFFFF + + + + name + css tag-name + scope + meta.selector.css entity.name.tag + settings + + foreground + #9EFFFF + + + + name + css#id + scope + meta.selector.css entity.other.attribute-name.id + settings + + foreground + #FFB454 + + + + name + css.class + scope + meta.selector.css entity.other.attribute-name.class + settings + + foreground + #5FE461 + + + + name + css property-name: + scope + support.type.property-name.css + settings + + foreground + #9DF39F + + + + name + css property-value; + scope + meta.property-group support.constant.property-value.css, meta.property-value support.constant.property-value.css + settings + + foreground + #F6F080 + + + + name + css @at-rule + scope + meta.preprocessor.at-rule keyword.control.at-rule + settings + + foreground + #F6AA11 + + + + name + css additional-constants + scope + meta.property-value support.constant.named-color.css, meta.property-value constant + settings + + foreground + #EDF080 + + + + name + css constructor.argument + scope + meta.constructor.argument.css + settings + + foreground + #EB939A + + + + name + diff.header + scope + meta.diff, meta.diff.header + settings + + background + #000E1A + fontStyle + + foreground + #F8F8F8 + + + + name + diff.deleted + scope + markup.deleted + settings + + background + #4C0900 + foreground + #F8F8F8 + + + + name + diff.changed + scope + markup.changed + settings + + background + #806F00 + foreground + #F8F8F8 + + + + name + diff.inserted + scope + markup.inserted + settings + + background + #154F00 + foreground + #F8F8F8 + + + + name + Raw Markup + scope + markup.raw + settings + + background + #8FDDF630 + + + + name + Block Quote + scope + markup.quote + settings + + background + #004480 + + + + name + List + scope + markup.list + settings + + background + #130D26 + + + + name + Bold Markup + scope + markup.bold + settings + + fontStyle + bold + foreground + #C1AFFF + + + + name + Italic Markup + scope + markup.italic + settings + + fontStyle + italic + foreground + #B8FFD9 + + + + name + Heading Markup + scope + markup.heading + settings + + background + #001221 + fontStyle + bold + foreground + #C8E4FD + + + + uuid + 06CD1FB2-A00A-4F8C-97B2-60E131980454 + + diff --git a/node_modules/ace/tool/tmthemes/Dawn.tmTheme b/node_modules/ace/tool/tmthemes/Dawn.tmTheme new file mode 100644 index 00000000..12cff9b6 --- /dev/null +++ b/node_modules/ace/tool/tmthemes/Dawn.tmTheme @@ -0,0 +1,437 @@ + + + + + author + David Powers + comment + Dawn + name + Dawn + settings + + + settings + + background + #F9F9F9 + caret + #000000 + foreground + #080808 + invisibles + #4B4B7E80 + lineHighlight + #2463B41F + selection + #275FFF4D + + + + name + Comment + scope + comment + settings + + fontStyle + italic + foreground + #5A525F + + + + name + Constant + scope + constant + settings + + fontStyle + bold + foreground + #811F24 + + + + name + Entity + scope + entity + settings + + fontStyle + + foreground + #BF4F24 + + + + name + Keyword + scope + keyword + settings + + fontStyle + + foreground + #794938 + + + + name + Storage + scope + storage + settings + + fontStyle + italic + foreground + #A71D5D + + + + name + String + scope + string | punctuation.definition.string + settings + + fontStyle + + foreground + #0B6125 + + + + name + Support + scope + support + settings + + fontStyle + + foreground + #691C97 + + + + name + Variable + scope + variable + settings + + fontStyle + + foreground + #234A97 + + + + name + Punctuation.separator + scope + punctuation.separator + settings + + foreground + #794938 + + + + name + Invalid – Deprecated + scope + invalid.deprecated + settings + + fontStyle + bold italic underline + foreground + #B52A1D + + + + name + Invalid – Illegal + scope + invalid.illegal + settings + + background + #B52A1D + fontStyle + italic underline + foreground + #F8F8F8 + + + + name + String embedded-source + scope + string source + settings + + background + #6F8BBA26 + fontStyle + + foreground + #080808 + + + + name + String constant + scope + string constant + settings + + fontStyle + bold + foreground + #696969 + + + + name + String variable + scope + string variable + settings + + fontStyle + + foreground + #234A97 + + + + name + String.regexp + scope + string.regexp + settings + + fontStyle + + foreground + #CF5628 + + + + name + String.regexp.«special» + scope + string.regexp.character-class, string.regexp constant.character.escaped, string.regexp source.ruby.embedded, string.regexp string.regexp.arbitrary-repitition + settings + + fontStyle + bold italic + foreground + #CF5628 + + + + name + String.regexp constant.character.escape + scope + string.regexp constant.character.escape + settings + + fontStyle + bold + foreground + #811F24 + + + + name + Embedded Source + scope + text source + settings + + background + #6F8BBA26 + + + + name + Support.function + scope + support.function + settings + + fontStyle + + foreground + #693A17 + + + + name + Support.constant + scope + support.constant + settings + + fontStyle + + foreground + #B4371F + + + + name + Support.variable + scope + support.variable + settings + + foreground + #234A97 + + + + name + Markup.list + scope + markup.list + settings + + foreground + #693A17 + + + + name + Markup.heading + scope + markup.heading | markup.heading entity.name + settings + + fontStyle + bold + foreground + #19356D + + + + name + Markup.quote + scope + markup.quote + settings + + background + #BBBBBB30 + fontStyle + italic + foreground + #0B6125 + + + + name + Markup.italic + scope + markup.italic + settings + + fontStyle + italic + foreground + #080808 + + + + name + Markup.bold + scope + markup.bold + settings + + fontStyle + bold + foreground + #080808 + + + + name + Markup.underline + scope + markup.underline + settings + + fontStyle + underline + foreground + #080808 + + + + name + Markup.link + scope + markup.link + settings + + fontStyle + italic underline + foreground + #234A97 + + + + name + Markup.raw + scope + markup.raw + settings + + background + #BBBBBB30 + fontStyle + + foreground + #234A97 + + + + name + Markup.deleted + scope + markup.deleted + settings + + foreground + #59140E + + + + name + Meta.separator + scope + meta.separator + settings + + background + #DCDCDC + fontStyle + bold + foreground + #19356D + + + + uuid + E7E82498-F9EA-49A6-A0D8-12327EA46B01 + + diff --git a/node_modules/ace/tool/tmthemes/Dreamweaver.tmTheme b/node_modules/ace/tool/tmthemes/Dreamweaver.tmTheme new file mode 100644 index 00000000..466863af --- /dev/null +++ b/node_modules/ace/tool/tmthemes/Dreamweaver.tmTheme @@ -0,0 +1,521 @@ + + + + + comment + By Jim Isaacs - jimisaacs.com + name + Dreamweaver + settings + + + settings + + background + #FFFFFF + caret + #000000 + foreground + #000000 + invisibles + #BFBFBF + lineHighlight + #00000012 + selection + #5EA0FF + + + + name + text + scope + text + settings + + foreground + #000000 + + + + name + constant numeric + scope + constant.numeric - source.css + settings + + fontStyle + + foreground + #EE000B + + + + name + comment general + scope + comment + settings + + fontStyle + + foreground + #9A9A9A + + + + name + html meta + scope + text.html meta.tag + settings + + fontStyle + + foreground + #00359E + + + + name + html string + scope + text.html.basic meta.tag string.quoted - source + settings + + foreground + #001EFF + + + + name + html contstant + scope + text.html.basic constant.character.entity.html + settings + + fontStyle + bold + foreground + #000000 + + + + name + html a tag + scope + text.html meta.tag.a - string + settings + + fontStyle + + foreground + #106800 + + + + name + html img tag + scope + text.html meta.tag.img - string + settings + + foreground + #6D232E + + + + name + html form tag + scope + text.html meta.tag.form - string + settings + + foreground + #FF9700 + + + + name + html table + scope + text.html meta.tag.table - string + settings + + foreground + #009079 + + + + name + js embedded + scope + source.js.embedded.html punctuation.definition.tag - source.php, source.js.embedded.html entity.name.tag.script, source.js.embedded entity.other.attribute-name - source.js string + settings + + fontStyle + + foreground + #842B44 + + + + name + js comment + scope + source.js comment - source.php + settings + + foreground + #9A9A9A + + + + name + js meta function + scope + source.js meta.function - source.php + settings + + fontStyle + + foreground + #000000 + + + + name + js instance / support.function + scope + source.js meta.class - source.php, source.js support.function - source.php + settings + + foreground + #24C696 + + + + name + js string + scope + source.js string - source.php, source.js keyword.operator + settings + + fontStyle + + foreground + #0035FF + + + + name + js support + scope + source.js support.class + settings + + foreground + #7E00B7 + + + + name + js storage + scope + source.js storage + settings + + fontStyle + bold + foreground + #000000 + + + + name + js storage (not function) / bool / new / braces + scope + source.js storage - storage.type.function - source.php, source.js constant - source.php, source.js keyword - source.php, source.js variable.language, source.js meta.brace, source.js punctuation.definition.parameters.begin, source.js punctuation.definition.parameters.end + settings + + fontStyle + bold + foreground + #05208C + + + + name + js regexp + scope + source.js string.regexp, source.js string.regexp constant + settings + + foreground + #106800 + + + + name + css embedded + scope + source.css.embedded.html punctuation.definition.tag, source.css.embedded.html entity.name.tag.style, source.css.embedded entity.other.attribute-name - meta.selector + settings + + foreground + #8D00B7 + + + + name + css @import + scope + source.css meta.at-rule.import.css + settings + + fontStyle + bold + foreground + #009C7F + + + + name + css @important + scope + source.css keyword.other.important + settings + + fontStyle + bold + foreground + #EE000B + + + + name + css @media + scope + source.css meta.at-rule.media + settings + + fontStyle + bold + foreground + #430303 + + + + name + css string + scope + source.css string + settings + + foreground + #106800 + + + + name + css selector/prop-list + scope + source.css meta.selector, source.css meta.property-list, source.css meta.at-rule + settings + + foreground + #DA29FF + + + + name + css punctuation + scope + source.css punctuation.separator - source.php, source.css punctuation.terminator - source.php + settings + + fontStyle + bold + foreground + #DA29FF + + + + name + css property name + scope + source.css meta.property-name + settings + + foreground + #05208C + + + + name + css property value + scope + source.css meta.property-value + settings + + foreground + #0035FF + + + + name + php begin/end block + scope + source.php punctuation.section.embedded.begin, source.php punctuation.section.embedded.end + settings + + fontStyle + bold + foreground + #EE000B + + + + name + php + scope + source.php - punctuation.section + settings + + fontStyle + + foreground + #000000 + + + + name + php varaible + scope + source.php variable, source.php meta.function.arguments + settings + + foreground + #000000 + + + + name + php punctuation + scope + source.php punctuation - string - variable - meta.function + settings + + foreground + #05208C + + + + name + php storage.type + scope + source.php storage.type + settings + + foreground + #24BF96 + + + + name + php keyword general / storage misc + scope + source.php keyword - comment, source.php storage.type.class, source.php storage.type.interface, source.php storage.modifier, source.php constant.language + settings + + foreground + #009714 + + + + name + php support / storage / operator + scope + source.php support , source.php storage, source.php keyword.operator, source.php storage.type.function + settings + + foreground + #0035FF + + + + name + php varaible global + scope + source.php variable.other.global + settings + + foreground + #0092F2 + + + + name + php support constant + scope + source.php support.constant, source.php constant.language.php + settings + + foreground + #551D02 + + + + name + php string + scope + source.php string, source.php string keyword.operator + settings + + fontStyle + + foreground + #E20000 + + + + name + php string variable + scope + source.php string.quoted.double variable + settings + + foreground + #FF6200 + + + + name + php comment general + scope + source.php comment + settings + + foreground + #FF9404 + + + + name + Invalid + scope + invalid + settings + + background + #EFFF8A + fontStyle + bold + foreground + #EE000B + + + + uuid + 4C43099A-C325-4F56-BACB-F332209207B0 + + diff --git a/node_modules/ace/tool/tmthemes/Eiffel.tmTheme b/node_modules/ace/tool/tmthemes/Eiffel.tmTheme new file mode 100644 index 00000000..1e8160c6 --- /dev/null +++ b/node_modules/ace/tool/tmthemes/Eiffel.tmTheme @@ -0,0 +1,439 @@ + + + + + name + Eiffel + author + Ian Joyner + settings + + + settings + + background + #FFFFFF + caret + #000000 + foreground + #000000 + invisibles + #BFBFBF + lineHighlight + #00000012 + selection + #C3DCFF + + + + name + Comment + scope + comment + settings + + fontStyle + + foreground + #00B418 + + + + name + Variable + scope + variable + settings + + fontStyle + italic + foreground + #0206FF + + + + name + Keyword + scope + keyword + settings + + fontStyle + bold + foreground + #0100B6 + + + + name + Number + scope + constant.numeric + settings + + fontStyle + italic + foreground + #CD0000 + + + + name + User-defined constant + scope + constant + settings + + fontStyle + italic + foreground + #C5060B + + + + name + Built-in constant + scope + constant.language + settings + + fontStyle + italic + foreground + #585CF6 + + + + name + String + scope + string + settings + + fontStyle + + foreground + #D80800 + + + + name + String interpolation + scope + constant.character.escape, string source + settings + + fontStyle + + foreground + #26B31A + + + + name + Preprocessor line + scope + meta.preprocessor + settings + + fontStyle + + foreground + #1A921C + + + + name + Preprocessor directive + scope + keyword.control.import + settings + + fontStyle + bold + foreground + #0C450D + + + + name + Function name + scope + entity.name.function, keyword.other.name-of-parameter.objc + settings + + fontStyle + bold + foreground + #0000A2 + + + + name + Type name + scope + entity.name.type + settings + + fontStyle + italic + + + + name + Inherited class name + scope + entity.other.inherited-class + settings + + fontStyle + italic + + + + name + Function parameter + scope + variable.parameter + settings + + fontStyle + italic + + + + name + Function argument and result types + scope + storage.type.method + settings + + fontStyle + + foreground + #70727E + + + + name + Section + scope + meta.section entity.name.section, declaration.section entity.name.section + settings + + fontStyle + italic + + + + name + Library function + scope + support.function + settings + + fontStyle + bold + foreground + #3C4C72 + + + + name + Library object + scope + support.class, support.type + settings + + fontStyle + bold + foreground + #6D79DE + + + + name + Library constant + scope + support.constant + settings + + fontStyle + bold + foreground + #06960E + + + + name + Library variable + scope + support.variable + settings + + fontStyle + bold + foreground + #21439C + + + + name + JS: Operator + scope + keyword.operator.js + settings + + foreground + #687687 + + + + name + Invalid + scope + invalid + settings + + background + #990000 + foreground + #FFFFFF + + + + name + Invalid trailing whitespace + scope + invalid.deprecated.trailing-whitespace + settings + + background + #FFD0D0 + + + + name + Embedded source + scope + text source, string.unquoted + settings + + background + #427FF530 + + + + name + Markup XML declaration + scope + meta.xml-processing, declaration.xml-processing + settings + + fontStyle + + foreground + #68685B + + + + name + Markup DOCTYPE + scope + meta.doctype, declaration.doctype + settings + + fontStyle + + foreground + #888888 + + + + name + Markup DTD + scope + meta.doctype.DTD, declaration.doctype.DTD + settings + + fontStyle + italic + + + + name + Markup tag + scope + meta.tag, declaration.tag + settings + + fontStyle + + foreground + #1C02FF + + + + name + Markup name of tag + scope + entity.name.tag + settings + + fontStyle + bold + + + + name + Markup tag attribute + scope + entity.other.attribute-name + settings + + fontStyle + italic + + + + name + Markup: Heading + scope + markup.heading + settings + + fontStyle + bold + foreground + #0C07FF + + + + name + Markup: Quote + scope + markup.quote + settings + + fontStyle + italic + foreground + #000000 + + + + name + Markup: List + scope + markup.list + settings + + foreground + #B90690 + + + + uuid + ADD7FDE7-C6BE-454B-A71A-7951ED54FB04 + + diff --git a/node_modules/ace/tool/tmthemes/Espresso Libre.tmTheme b/node_modules/ace/tool/tmthemes/Espresso Libre.tmTheme new file mode 100644 index 00000000..2ccae644 --- /dev/null +++ b/node_modules/ace/tool/tmthemes/Espresso Libre.tmTheme @@ -0,0 +1,402 @@ + + + + + author + Chris Thomas + name + Espresso Libre + settings + + + settings + + background + #2A211C + caret + #889AFF + foreground + #BDAE9D + invisibles + #BFBFBF + lineHighlight + #3A312C + selection + #C3DCFF + + + + name + Comment + scope + comment + settings + + fontStyle + italic + foreground + #0066FF + + + + name + Keyword + scope + keyword, storage + settings + + fontStyle + bold + foreground + #43A8ED + + + + name + Number + scope + constant.numeric + settings + + fontStyle + + foreground + #44AA43 + + + + name + User-defined constant + scope + constant + settings + + fontStyle + bold + foreground + #C5656B + + + + name + Built-in constant + scope + constant.language + settings + + fontStyle + bold + foreground + #585CF6 + + + + name + Variable + scope + variable.language, variable.other + settings + + fontStyle + + foreground + #318495 + + + + name + String + scope + string + settings + + fontStyle + + foreground + #049B0A + + + + name + String interpolation + scope + constant.character.escape, string source + settings + + fontStyle + + foreground + #2FE420 + + + + name + Preprocessor line + scope + meta.preprocessor + settings + + fontStyle + + foreground + #1A921C + + + + name + Preprocessor directive + scope + keyword.control.import + settings + + fontStyle + bold + foreground + #9AFF87 + + + + name + Function name + scope + entity.name.function, keyword.other.name-of-parameter.objc + settings + + fontStyle + bold + foreground + #FF9358 + + + + name + Type name + scope + entity.name.type + settings + + fontStyle + underline + + + + name + Inherited class name + scope + entity.other.inherited-class + settings + + fontStyle + italic + + + + name + Function parameter + scope + variable.parameter + settings + + fontStyle + italic + + + + name + Function argument and result types + scope + storage.type.method + settings + + fontStyle + + foreground + #8B8E9C + + + + name + Section + scope + meta.section entity.name.section, declaration.section entity.name.section + settings + + fontStyle + italic + + + + name + Library function + scope + support.function + settings + + fontStyle + bold + foreground + #7290D9 + + + + name + Library object + scope + support.class, support.type + settings + + fontStyle + bold + foreground + #6D79DE + + + + name + Library constant + scope + support.constant + settings + + fontStyle + bold + foreground + #00AF0E + + + + name + Library variable + scope + support.variable + settings + + fontStyle + bold + foreground + #2F5FE0 + + + + name + JS: Operator + scope + keyword.operator.js + settings + + foreground + #687687 + + + + name + Invalid + scope + invalid + settings + + background + #990000 + foreground + #FFFFFF + + + + name + Invalid trailing whitespace + scope + invalid.deprecated.trailing-whitespace + settings + + background + #FFD0D0 + + + + name + Embedded source + scope + text source, string.unquoted + settings + + background + #F5AA7730 + + + + name + Markup XML declaration + scope + meta.tag.preprocessor.xml + settings + + fontStyle + + foreground + #8F7E65 + + + + name + Markup DOCTYPE + scope + meta.tag.sgml.doctype + settings + + fontStyle + + foreground + #888888 + + + + name + Markup DTD + scope + string.quoted.docinfo.doctype.DTD + settings + + fontStyle + italic + + + + name + Markup tag + scope + meta.tag, declaration.tag + settings + + fontStyle + + foreground + #43A8ED + + + + name + Markup name of tag + scope + entity.name.tag + settings + + fontStyle + bold + + + + name + Markup tag attribute + scope + entity.other.attribute-name + settings + + fontStyle + italic + + + + uuid + 6B90703E-4E4B-43C8-9D32-921BEDF6D725 + + diff --git a/node_modules/ace/tool/tmthemes/GitHub.tmTheme b/node_modules/ace/tool/tmthemes/GitHub.tmTheme new file mode 100644 index 00000000..aa21abce --- /dev/null +++ b/node_modules/ace/tool/tmthemes/GitHub.tmTheme @@ -0,0 +1,573 @@ + + + + + author + Martin Kühl + comment + A theme based on the GitHub code stylesheet. + name + GitHub + settings + + + comment + +background #files .file .data background-color +caret #files .file .meta color +invisibles .syntax .w +lineHighlight #FFFEEB #files .file .private background-color + alt: #FFFFCC colour that gets added via javascript +selection #B4D5FE handmade :-) + alt: #FFFFCC colour that gets added via javascript + #EAF2F5 #header .userbox background-color + #EAEAEA #files .file background-color + #DEDEDE #files .file border-color + #F9EA86 Mac OS X system selection colour “Gold†+ + settings + + background + #F8F8FF + caret + #666666 + foreground + #000000 + invisibles + #BBBBBB + lineHighlight + #FFFEEB + selection + #B4D5FE + + + + comment + .syntax .c, .syntax .c[ml] + name + Comment + scope + comment + settings + + fontStyle + italic + foreground + #999988 + + + + name + Comment.Preproc + scope + comment.block.preprocessor + settings + + comment + .syntax .cp + fontStyle + bold + foreground + #999999 + + + + name + Comment.Special + scope + comment.documentation, comment.block.documentation + settings + + comment + .syntax .cs + fontStyle + bold italic + foreground + #999999 + + + + name + Error + scope + invalid.illegal + settings + + background + #E3D2D2 + comment + .syntax .err + foreground + #A61717 + + + + comment + .syntax .k, .syntax .k[dpr] + name + Keyword + scope + keyword, storage + settings + + fontStyle + bold + + + + comment + .syntax .o, .syntax .ow + name + Operator + scope + keyword.operator + settings + + fontStyle + bold + + + + name + Keyword.Constant + scope + constant.language, support.constant + settings + + comment + .style .kc + fontStyle + bold + + + + name + Keyword.Type + scope + storage.type, support.type + settings + + comment + .style .kt + fontStyle + bold + foreground + #445588 + + + + name + Name.Attribute + scope + entity.other.attribute-name + settings + + comment + .style .na + foreground + #008080 + + + + name + Name.Builtin + scope + variable.other + settings + + comment + .style .nb + foreground + #0086B3 + + + + name + Name.Builtin.Pseudo + scope + variable.language + settings + + comment + .style .bp + foreground + #999999 + + + + comment + TODO: support.class is styled as Name.Constant on GitHub. + name + Name.Class + scope + entity.name.type, entity.other.inherited-class, support.class + settings + + comment + .style .nc + fontStyle + bold + foreground + #445588 + + + + name + Name.Constant + scope + variable.other.constant + settings + + comment + .style .no + foreground + #008080 + + + + name + Name.Entity + scope + constant.character.entity + settings + + comment + .style .ni + foreground + #800080 + + + + name + Name.Exception + scope + entity.name.exception + settings + + comment + .style .ne + foreground + #990000 + + + + name + Name.Function + scope + entity.name.function, support.function, keyword.other.name-of-parameter + settings + + comment + .style .nf + foreground + #990000 + + + + name + Name.Namespace + scope + entity.name.section + settings + + comment + .style .nn + foreground + #555555 + + + + name + Name.Tag + scope + entity.name.tag + settings + + comment + .style .nt + foreground + #000080 + + + + name + Name.Variable + scope + variable.parameter, support.variable + settings + + comment + .style .nv, .style .v[cgi] + foreground + #008080 + + + + name + Literal.Number + scope + constant.numeric, constant.other + settings + + comment + .style .m, .style .m[fhio], .style .il + foreground + #009999 + + + + name + Literal.String + scope + string - string source, constant.character + settings + + comment + .style .s[bcd2ehixl] + fontStyle + + foreground + #DD1144 + + + + name + Literal.String.Regex + scope + string.regexp + settings + + comment + .style .sr + foreground + #009926 + + + + name + Literal.String.Symbol + scope + constant.other.symbol + settings + + comment + .style .ss + foreground + #990073 + + + + name + Punctuation + scope + punctuation + settings + + fontStyle + bold + + + + name + Generic.Deleted + scope + markup.deleted + settings + + background + #FFDDDD + comment + .syntax .gd + foreground + #000000 + + + + name + Generic.Emph + scope + markup.italic + settings + + comment + .syntax .ge + fontStyle + italic + + + + name + Generic.Error + scope + markup.error + settings + + comment + .syntax .gr + foreground + #AA0000 + + + + name + Generic.Heading + scope + markup.heading.1 + settings + + comment + .syntax .gh + foreground + #999999 + + + + name + Generic.Inserted + scope + markup.inserted + settings + + background + #DDFFDD + comment + .syntax .gi + foreground + #000000 + + + + name + Generic.Output + scope + markup.output, markup.raw + settings + + comment + .syntax .go + foreground + #888888 + + + + name + Generic.Prompt + scope + markup.prompt + settings + + comment + .syntax .gp + foreground + #555555 + + + + name + Generic.Strong + scope + markup.bold + settings + + comment + .syntax .gs + fontStyle + bold + + + + name + Generic.Subheading + scope + markup.heading + settings + + comment + .syntax .gu + foreground + #AAAAAA + + + + name + Generic.Traceback + scope + markup.traceback + settings + + comment + .syntax .gt + foreground + #AA0000 + + + + name + Generic.Underline + scope + markup.underline + settings + + fontStyle + underline + + + + name + Extra: Diff Range + scope + meta.diff.range, meta.diff.index, meta.separator + settings + + background + #EAF2F5 + comment + .syntax .gc + foreground + #999999 + + + + name + Extra: Diff From + scope + meta.diff.header.from-file + settings + + background + #FFDDDD + foreground + #999999 + + + + name + Extra: Diff To + scope + meta.diff.header.to-file + settings + + background + #DDFFDD + foreground + #999999 + + + + name + Extra: Link + scope + meta.link + settings + + fontStyle + + foreground + #4183C4 + + + + uuid + FDD6F02A-74F7-4B6C-97F1-857D792EC90E + + diff --git a/node_modules/ace/tool/tmthemes/IDLE.tmTheme b/node_modules/ace/tool/tmthemes/IDLE.tmTheme new file mode 100644 index 00000000..704296f5 --- /dev/null +++ b/node_modules/ace/tool/tmthemes/IDLE.tmTheme @@ -0,0 +1,235 @@ + + + + + author + Domenico Carbotta + name + IDLE + settings + + + settings + + background + #FFFFFF + caret + #000000 + foreground + #000000 + invisibles + #BFBFBF + lineHighlight + #00000012 + selection + #BAD6FD + + + + name + Comment + scope + comment + settings + + foreground + #919191 + + + + name + String + scope + string + settings + + foreground + #00A33F + + + + name + Number + scope + constant.numeric + settings + + + + name + Built-in constant + scope + constant.language + settings + + foreground + #A535AE + + + + name + User-defined constant + scope + constant.character, constant.other + settings + + + + name + Variable + scope + variable.language, variable.other + settings + + + + name + Keyword + scope + keyword + settings + + foreground + #FF5600 + + + + name + Storage + scope + storage + settings + + foreground + #FF5600 + + + + name + Type name + scope + entity.name.type + settings + + foreground + #21439C + + + + name + Inherited class + scope + entity.other.inherited-class + settings + + + + name + Function name + scope + entity.name.function + settings + + foreground + #21439C + + + + name + Function argument + scope + variable.parameter + settings + + + + name + Tag name + scope + entity.name.tag + settings + + + + name + Tag attribute + scope + entity.other.attribute-name + settings + + + + name + Library function + scope + support.function + settings + + foreground + #A535AE + + + + name + Library constant + scope + support.constant + settings + + foreground + #A535AE + + + + name + Library class/type + scope + support.type, support.class + settings + + foreground + #A535AE + + + + name + Library variable + scope + support.variable + settings + + foreground + #A535AE + + + + name + Invalid + scope + invalid + settings + + background + #990000 + foreground + #FFFFFF + + + + name + String interpolation + scope + constant.other.placeholder.py + settings + + fontStyle + + foreground + #990000 + + + + uuid + DDC0CBE1-442B-4CB5-80E4-26E4CFB3A277 + + diff --git a/node_modules/ace/tool/tmthemes/Katzenmilch.tmTheme b/node_modules/ace/tool/tmthemes/Katzenmilch.tmTheme new file mode 100644 index 00000000..3878ffe9 --- /dev/null +++ b/node_modules/ace/tool/tmthemes/Katzenmilch.tmTheme @@ -0,0 +1,399 @@ + + + + + name + Katzen-Milch + comment + Those silly germans and their cat milk! Ghee wizz! + settings + + + settings + + background + #f3f2f3 + caret + #100011 + foreground + #0f0009ff + invisibles + #000000 + lineHighlight + #ffffff + selection + #6405D044 + selectionBorder + #8425f0 + bracketContentsOptions + underline + tagsForeground + #0f0009ff + tagsOptions + underline + + + + name + Parenthesis + scope + punctuation.definition.list + settings + + fontStyle + + foreground + #940494 + background + #4444940a + + + + name + Comment + scope + comment + settings + + fontStyle + italic + foreground + #404f50aa + background + #5f0fff02 + + + + name + String + scope + string + settings + + foreground + #5a5f9b + background + #aaafdb09 + + + + name + Number + scope + constant.numeric + settings + + foreground + #4f827bee + background + #77c2bb0f + + + + name + User-defined Constant + scope + constant.character, constant.other + settings + + foreground + #025f69ff + background + #7f229910 + + + + name + Built-in Constant + scope + constant.language + settings + + fontStyle + + foreground + #7D7e52 + background + #bDbe820f + + + + name + Storage Modifier + scope + storage.modifier + settings + + fontStyle + bold + foreground + #7B5D8f + background + #9B9FfD0a + + + + name + Storage + scope + storage + settings + + fontStyle + bold + foreground + #7B5cbfff + background + #8B5Ddf0d + + + + name + Function Name + scope + entity.name.function + settings + + fontStyle + + foreground + #025f49f7 + background + #22ff491f + + + + name + Support Function + scope + support.function + settings + + foreground + #9D7e62 + background + #bDbe820a + + + + name + Misc Function + scope + entity.name.function.misc + settings + + foreground + #939469 + background + #E3E4A90a + + + + name + Predicate Function + scope + entity.name.function.predicate + settings + + foreground + #856F63 + background + #A5DF930a + + + + name + Input/Output Function + scope + entity.name.function.io + settings + + foreground + #aF938C + background + #DFB3AC0a + + + + name + External Symbol + scope + variable.other.external-symbol + settings + + foreground + #7BaFaD + background + #BBDFDD0a + + + + name + Variable + scope + variable.language, variable.other + settings + + foreground + #316fcf + background + #3aafff0a + + + + name + Parameter Variable + scope + variable.parameter + settings + + fontStyle + italic + foreground + #33969fdd + background + #05d6f90b + + + + name + Keyword + scope + keyword + settings + + foreground + #674Aa8 + background + #A3AAD80e + + + + name + Class Name + scope + entity.name.class + settings + + fontStyle + bold + foreground + #B9986F + background + #B998DF22 + + + + name + Structure Name + scope + entity.name.structure + settings + + foreground + #22af9d + background + #B998DF0a + + + + name + Type Name + scope + entity.name.type + settings + + foreground + #af47a9 + background + #af77a90d + + + + name + Class name + scope + entity.name.class, entity.name.type.class + settings + + foreground + #cc4357 + background + #ffddff92 + + + + name + Support Class + scope + support.class + settings + + foreground + #ef6aa7ff + background + #ef6aa710 + + + + name + Invalid + scope + invalid + settings + + background + #CC1B27 + foreground + #DFDFD5 + + + + + name + ♦ String embedded-source + scope + string source + settings + + fontStyle + italic + foreground + #13499fdd + background + #0099ff0a + + + + name + Tag name + scope + entity.name.tag + settings + + foreground + #3976a2 + background + #49a6d20a + + + + name + Tag attribute + scope + entity.other.attribute-name + settings + + fontStyle + + foreground + #4946c2ee + background + #4986c209 + + + + + diff --git a/node_modules/ace/tool/tmthemes/Kuroir Theme.tmTheme b/node_modules/ace/tool/tmthemes/Kuroir Theme.tmTheme new file mode 100644 index 00000000..36acd588 --- /dev/null +++ b/node_modules/ace/tool/tmthemes/Kuroir Theme.tmTheme @@ -0,0 +1,916 @@ + + + + + author + Stanley Rost + comment + Kuroir + name + Kuroir Theme + settings + + + settings + + background + #E8E9E8 + caret + #202020 + foreground + #363636 + invisibles + #0000004A + lineHighlight + #CBDC2F38 + selection + #F5AA0091 + + bracketsForeground + #C41717 + bracketsOptions + foreground underline + + bracketContentsForeground + #C41717 + bracketContentsOptions + foreground underline background + + guide + #8F8F8F + activeGuide + #FA2828 + + tagsOptions + stippled_underline + + + + name + Comment + scope + comment + settings + + background + #DCDCDC8F + fontStyle + + foreground + #949494E8 + + + + name + Regions + scope + comment.line.region + settings + + background + #E9D6DC85 + fontStyle + + foreground + #A54776 + + + + name + Line Marker + scope + comment.line.marker.php + settings + + background + #E9E4BE + foreground + #668D68 + + + + name + Todo + scope + comment.line.todo.php + settings + + background + #D9EAB8 + fontStyle + + foreground + #456E48 + + + + name + FIXME + scope + comment.line.fixme.php + settings + + background + #E1D0CA + fontStyle + + foreground + #880006 + + + + name + Constant + scope + constant + settings + + foreground + #CD6839 + + + + name + Entity + scope + entity + settings + + background + #E8E9E8 + fontStyle + + foreground + #8B4726 + + + + name + Storage + scope + storage + settings + + fontStyle + + foreground + #A52A2A + + + + name + Keyword Control + scope + keyword.control + settings + + foreground + #CD3700 + + + + name + Library Function + scope + support.function - variable, keyword.other.special-method.ruby + settings + + foreground + #B03060 + + + + name + Comparison + scope + keyword.operator.comparison,keyword.operator.logical + settings + + foreground + #B83126 + + + + name + String + scope + string + settings + + fontStyle + + foreground + #639300 + + + + name + R Interpolation + scope + string.quoted.double.ruby source.ruby.embedded.source + settings + + foreground + #007E69 + + + + name + Support + scope + support + settings + + fontStyle + + foreground + #104E8B + + + + name + Variable + scope + variable + settings + + foreground + #009ACD + + + + name + Invalid Deprecated + scope + invalid.deprecated + settings + + background + #E8E9E8 + fontStyle + italic underline + foreground + #FD1732 + + + + name + Invalid Illegal + scope + invalid.illegal + settings + + background + #FF060026 + foreground + #FD1224 + + + + name + Embedded Source (Bright) + scope + text source + settings + + background + #77ADE900 + foreground + #7B211A + + + + name + Entity inherited-class + scope + entity.other.inherited-class + settings + + fontStyle + italic + foreground + #005273 + + + + name + String.regexp + scope + string.regexp + settings + + background + #C9D4BE + foreground + #417E00 + + + + name + Support.function + scope + support.function + settings + + fontStyle + + foreground + #005273 + + + + name + Support.constant + scope + support.constant + settings + + fontStyle + + foreground + #CF6A4C + + + + name + j Entity Name Type + scope + entity.name.type + settings + + fontStyle + underline + + + + name + j Cast + scope + meta.cast + settings + + fontStyle + italic + foreground + #676767 + + + + name + Doctype/XML Processing + scope + meta.sgml.html meta.doctype, meta.sgml.html meta.doctype entity, meta.sgml.html meta.doctype string, meta.xml-processing, meta.xml-processing entity, meta.xml-processing string + settings + + foreground + #494949 + + + + name + Meta.tag.all + scope + meta.tag, meta.tag entity + settings + + foreground + #005273 + + + + name + Meta.tag.inline + scope + source entity.name.tag, source entity.other.attribute-name, meta.tag.inline, meta.tag.inline entity + settings + + foreground + #005273 + + + + name + Namespaces + scope + entity.name.tag.namespace, entity.other.attribute-name.namespace + settings + + foreground + #B85423 + + + + name + css tag-name + scope + entity.name.tag.css + settings + + foreground + #B83126 + + + + name + css:pseudo-class + scope + meta.selector.css entity.other.attribute-name.tag.pseudo-class + settings + + foreground + #B12E25 + + + + name + css#id + scope + meta.selector.css entity.other.attribute-name.id,entity.other.attribute-name.id.css + settings + + foreground + #B8002D + + + + name + css.class + scope + meta.selector.css entity.other.attribute-name.class, entity.other.attribute-name.class.css + settings + + foreground + #B8012D + + + + name + css property-name: + scope + support.type.property-name.css, meta.property-name + settings + + foreground + #005273 + + + + name + css @at-rule + scope + meta.preprocessor.at-rule keyword.control.at-rule + settings + + foreground + #8693A5 + + + + name + css property-value; + scope + meta.property-value + settings + + foreground + #417E00 + + + + name + css property-value color + scope + constant.other.color + settings + + foreground + #B8860B + + + + name + css !important / !default + scope + keyword.other.important,keyword.other.default + settings + + foreground + #EE3A8C + + + + name + css additional-constants + scope + meta.property-value support.constant.named-color.css, meta.property-value constant + settings + + foreground + #417E00 + + + + + + name + css constructor.argument + scope + meta.constructor.argument.css + settings + + foreground + #417E00 + + + + name + css constant.numeric + scope + constant.numeric + settings + + foreground + #9A5925 + + + + name + css keyword.unit + scope + keyword.other + settings + + foreground + #9F5E3D + + + + name + css keyword.unit + scope + source.scss support.function.misc + settings + + foreground + #1B76B0 + + + + name + diff.header + scope + meta.diff, meta.diff.header + settings + + background + #82000E + fontStyle + italic + foreground + #F8BEBE + + + + name + diff.deleted + scope + markup.deleted + settings + + background + #420E09 + foreground + #F8F8F8 + + + + name + diff.changed + scope + markup.changed + settings + + background + #4A410D + foreground + #F8F8F8 + + + + name + diff.inserted + scope + markup.inserted + settings + + background + #253B22 + foreground + #F8F8F8 + + + + name + Markup: Italic + scope + markup.italic + settings + + fontStyle + italic + foreground + #CD2626 + + + + name + Markup: Bold + scope + markup.bold + settings + + fontStyle + bold + foreground + #8B1A1A + + + + name + Markup: Underline + scope + markup.underline + settings + + fontStyle + underline + foreground + #E18964 + + + + name + Markup: Quote + scope + markup.quote + settings + + background + #FEE09C12 + fontStyle + italic + foreground + #8B7765 + + + + name + Markup: Heading + scope + markup.heading, markup.heading entity + settings + + background + #BF61330D + fontStyle + + foreground + #B8012D + + + + name + Markup: List + scope + markup.list + settings + + foreground + #8F5B26 + + + + name + Markup: Raw + scope + markup.raw + settings + + background + #B1B3BA08 + fontStyle + + foreground + #578BB3 + + + + name + Markup: Comment + scope + markup comment + settings + + fontStyle + italic + foreground + #F67B37 + + + + name + Markup: Separator + scope + meta.separator + settings + + background + #242424 + foreground + #60A633 + + + + name + Markup: Other + scope + markup.other + settings + + background + #B1B3BA08 + fontStyle + + foreground + #578BB3 + + + + name + Log Entry + scope + meta.line.entry.logfile, meta.line.exit.logfile + settings + + background + #EEEEEE29 + + + + name + Log Entry Error + scope + meta.line.error.logfile + settings + + background + #751012 + + + + name + SCSS Punctuation End Comments + scope + punctuation.definition.end + settings + + background + #DCDCDC8F + fontStyle + + + + + name + -------------------------------- + settings + + + + name + HTML Attribute name + scope + entity.other.attribute-name.html + settings + + foreground + #629F9E + + + + name + JS String + scope + string.quoted.double.js, string.quoted.single.js + settings + + foreground + #79A316 + + + + name + JS Function + scope + entity.name.function.js + settings + + foreground + #488C45 + fontStyle + italic + + + + name + JS Embedded code general + scope + source.js.embedded.html + settings + + foreground + #666 + + + + name + JS Storage Type + scope + storage.type.js + settings + + foreground + #BB3182 + + + + name + JS Support Class + scope + support.class.js + settings + + foreground + #338FD5 + + + + name + JS Control Keyword + scope + keyword.control.js, keyword.operator.js + settings + + foreground + #A99904 + fontStyle + italic + + + + + name + Matching Pairs + scope + entity.name.class + settings + + background + #D7D7A7 + foreground + #616838 + fontStyle + + + + + name + Active Guide + scope + active_guide + settings + + background + #968F96 + fontStyle + + + + + name + Highlight Matching Word + scope + highlight_matching_word + settings + + background + #CBDC2F38 + fontStyle + + + + + uuid + 467560D0-6ACE-4409-82FD-4791420837AC + + diff --git a/node_modules/ace/tool/tmthemes/LAZY.tmTheme b/node_modules/ace/tool/tmthemes/LAZY.tmTheme new file mode 100644 index 00000000..09ff5111 --- /dev/null +++ b/node_modules/ace/tool/tmthemes/LAZY.tmTheme @@ -0,0 +1,291 @@ + + + + + author + Domenico Carbotta + name + LAZY + settings + + + settings + + background + #FFFFFF + caret + #7C7C7C + foreground + #000000 + invisibles + #B6B6B6 + lineHighlight + #EFFCA68F + selection + #E3FC8D + + + + name + Comment + scope + comment + settings + + fontStyle + + foreground + #8C868F + + + + name + Constant + scope + constant + settings + + fontStyle + + foreground + #3B5BB5 + + + + name + Entity + scope + entity + settings + + fontStyle + + foreground + #3B5BB5 + + + + name + Latex Entity + scope + text.tex.latex entity + settings + + fontStyle + + foreground + #D62A28 + + + + name + Keyword + scope + keyword, storage + settings + + fontStyle + + foreground + #FF7800 + + + + name + String + scope + string, meta.verbatim + settings + + fontStyle + + foreground + #409B1C + + + + name + Support + scope + support + settings + + fontStyle + + foreground + #3B5BB5 + + + + name + Variable + scope + variable + settings + + fontStyle + + + + + name + Invalid – Deprecated + scope + invalid.deprecated + settings + + fontStyle + italic + foreground + #990000 + + + + name + Invalid – Illegal + scope + invalid.illegal + settings + + background + #9D1E15 + foreground + #F8F8F8 + + + + name + Superclass + scope + entity.other.inherited-class + settings + + fontStyle + italic + foreground + #3B5BB5 + + + + name + String interpolation + scope + string constant.other.placeholder + settings + + fontStyle + + foreground + #671EBB + + + + name + meta.function-call.py + scope + meta.function-call.py + settings + + fontStyle + + foreground + #3E4558 + + + + name + meta.tag + scope + meta.tag, meta.tag entity + settings + + foreground + #3A4A64 + + + + name + OCaml variant + scope + keyword.type.variant + settings + + fontStyle + + foreground + #7F90AA + + + + name + OCaml operator + scope + source.ocaml keyword.operator + settings + + foreground + #000000 + + + + name + OCaml infix operator + scope + source.ocaml keyword.operator.symbol.infix + settings + + fontStyle + + foreground + #3B5BB5 + + + + name + OCaml prefix operator + scope + source.ocaml keyword.operator.symbol.prefix + settings + + foreground + #3B5BB5 + + + + name + OCaml infix f-p operator + scope + source.ocaml keyword.operator.symbol.infix.floating-point + settings + + fontStyle + underline + + + + name + OCaml prefix f-p operator + scope + source.ocaml keyword.operator.symbol.prefix.floating-point + settings + + fontStyle + underline + + + + name + OCaml f-p constant + scope + source.ocaml constant.numeric.floating-point + settings + + fontStyle + underline + + + + uuid + A1E55FCB-3CD2-4811-9E73-D9B87419443A + + diff --git a/node_modules/ace/tool/tmthemes/LICENSE b/node_modules/ace/tool/tmthemes/LICENSE new file mode 100644 index 00000000..08f1380f --- /dev/null +++ b/node_modules/ace/tool/tmthemes/LICENSE @@ -0,0 +1,8 @@ +If not otherwise specified (see below), files in this directory fall under the following license: + + Permission to copy, use, modify, sell and distribute this + software is granted. This software is provided "as is" without + express or implied warranty, and with no claim as to its + suitability for any purpose. + +An exception is made for files in readable text which contain their own license information, or files where an accompanying file exists (in the same directory) with a “-license†suffix added to the base-name name of the original file, and an extension of txt, html, or similar. For example “tidy†is accompanied by “tidy-license.txtâ€. \ No newline at end of file diff --git a/node_modules/ace/tool/tmthemes/MagicWB (Amiga).tmTheme b/node_modules/ace/tool/tmthemes/MagicWB (Amiga).tmTheme new file mode 100644 index 00000000..7897886b --- /dev/null +++ b/node_modules/ace/tool/tmthemes/MagicWB (Amiga).tmTheme @@ -0,0 +1,376 @@ + + + + + author + Allan Odgaard + comment + Inspired by the original 8 MagicWB colors from Martin Huttenloher + name + MagicWB (Amiga) + settings + + + settings + + background + #969696 + caret + #FFFFFF + foreground + #000000 + invisibles + #FF38FF + lineHighlight + #00000012 + selection + #B1B1B1 + + + + name + Comment + scope + comment + settings + + fontStyle + italic + foreground + #8D2E75 + + + + name + String + scope + string + settings + + background + #FF000033 + fontStyle + + foreground + #FFFFFF + + + + name + Number + scope + constant.numeric + settings + + foreground + #FFFFFF + + + + name + Constant: Built-in + scope + constant.language + settings + + fontStyle + bold + foreground + #FFA995 + + + + name + Constant: User-defined + scope + constant.character, constant.other + settings + + background + #0000FF33 + fontStyle + + foreground + #FFA995 + + + + name + Variable + scope + variable.language, variable.other + settings + + foreground + #FFA995 + + + + name + Keyword + scope + keyword + settings + + fontStyle + bold + + + + name + Storage + scope + storage + settings + + fontStyle + bold + foreground + #3A68A3 + + + + name + Type Name + scope + entity.name.type + settings + + fontStyle + underline + + + + name + Inherited Class + scope + entity.other.inherited-class + settings + + fontStyle + italic + + + + name + Function Name + scope + entity.name.function + settings + + fontStyle + + foreground + #FFA995 + + + + name + Function Argument + scope + variable.parameter + settings + + fontStyle + italic + + + + name + Entity Name + scope + entity.name + settings + + fontStyle + bold + foreground + #0000FF + + + + name + Tag Attribute + scope + entity.other.attribute-name + settings + + fontStyle + italic + foreground + #3A68A3 + + + + name + Library Function + scope + support.function + settings + + foreground + #E5B3FF + + + + name + Objective-C Method Call + scope + support.function.any-method + settings + + fontStyle + + foreground + #000000 + + + + name + Objective-C Method Call - : + scope + support.function.any-method - punctuation + settings + + fontStyle + italic + + + + name + Library Constant + scope + support.constant + settings + + foreground + #FFFFFF + + + + name + Library Class/Type + scope + support.type, support.class + settings + + foreground + #FFA995 + + + + name + Library Variable + scope + support.variable + settings + + foreground + #3A68A3 + + + + name + Invalid + scope + invalid + settings + + background + #797979 + foreground + #FFFFFF + + + + name + Include <system> + scope + string.quoted.other.lt-gt.include + settings + + background + #969696 + fontStyle + italic + foreground + #FFA995 + + + + name + Include "user" + scope + string.quoted.double.include + settings + + background + #969696 + foreground + #FFA995 + + + + name + Markup: List Item + scope + markup.list + settings + + foreground + #4D4E60 + + + + name + Markup: Raw + scope + markup.raw + settings + + background + #0000FF + foreground + #FFFFFF + + + + name + Markup: Quote (Email) + scope + markup.quote + settings + + foreground + #00F0C9 + + + + name + Markup: Quote Double (Email) + scope + markup.quote markup.quote + settings + + fontStyle + + foreground + #4C457E + + + + name + Embedded Source + scope + text.html source + settings + + background + #8A9ECB + + + + uuid + B0A18BAA-6220-481C-9914-F6D3E51B5410 + + diff --git a/node_modules/ace/tool/tmthemes/Merbivore Soft.tmTheme b/node_modules/ace/tool/tmthemes/Merbivore Soft.tmTheme new file mode 100644 index 00000000..60c4cc94 --- /dev/null +++ b/node_modules/ace/tool/tmthemes/Merbivore Soft.tmTheme @@ -0,0 +1,322 @@ + + + + + name + Merbivore Soft + settings + + + settings + + background + #1C1C1C + caret + #FFFFFF + foreground + #E6E1DC + invisibles + #404040 + lineHighlight + #333435 + selection + #494949 + + + + name + Source + scope + source + settings + + + + name + Comment + scope + comment + settings + + fontStyle + italic + foreground + #AC4BB8 + + + + name + Deprecated + scope + invalid.deprecated + settings + + foreground + #FFFFFF + background + #FE3838 + + + + name + Keyword + scope + keyword, storage + settings + + fontStyle + + foreground + #FC803A + + + + name + Function (definition) + scope + entity.name.function, keyword.other.name-of-parameter.objc + settings + + fontStyle + + + + + name + Class (definition) + scope + entity.name + settings + + + + name + Class inheritence + scope + entity.other.inherited-class + settings + + foreground + #C984CD + + + + name + Number + scope + constant.numeric + settings + + fontStyle + + foreground + #7FC578 + + + + name + Variable + scope + variable.language, variable.other + settings + + fontStyle + + + + + name + Constant + scope + constant + settings + + fontStyle + + foreground + #68C1D8 + + + + name + Constant (other variable) + scope + variable.other.constant + settings + + + + name + Constant (built-in) + scope + constant.language + settings + + fontStyle + + foreground + #E1C582 + + + + name + String + scope + string + settings + + fontStyle + + foreground + #8EC65F + + + + name + Library function + scope + support.function + settings + + fontStyle + + + + + name + Library constant + scope + constant.library + settings + + foreground + #8EC65F + + + + name + Library type + scope + support.type + settings + + foreground + #68C1D8 + + + + name + Library constant + scope + support.constant + settings + + foreground + #8EC65F + + + + name + Markup tag + scope + meta.tag, declaration.tag, entity.name.tag + settings + + fontStyle + + foreground + #FC803A + + + + name + Markup tag + scope + meta + settings + + fontStyle + italic + foreground + #AC4BB8 + + + + name + Markup tag attribute + scope + entity.other.attribute-name + settings + + foreground + #EAF1A3 + + + + name + Invalid + scope + invalid + settings + + background + #FE3838 + foreground + #FFFFFF + + + + name + String interpolation + scope + constant.character.escaped, constant.character.escape, string source, string source.ruby + settings + + fontStyle + + foreground + #B3E5B4 + + + + name + Diff Add + scope + markup.inserted + settings + + background + #6FC58B + foreground + #E6E1DC + + + + name + Diff Remove + scope + markup.deleted + settings + + background + #AC3735 + foreground + #E6E1DC + + + + name + Diff Header + scope + meta.diff.header, meta.separator.diff, meta.diff.index, meta.diff.range + settings + + background + #5A9EE1 + + + + uuid + B3517E4B-5243-46CF-AB04-9AE7B41DE3F2 + + diff --git a/node_modules/ace/tool/tmthemes/Merbivore.tmTheme b/node_modules/ace/tool/tmthemes/Merbivore.tmTheme new file mode 100644 index 00000000..41afeb81 --- /dev/null +++ b/node_modules/ace/tool/tmthemes/Merbivore.tmTheme @@ -0,0 +1,296 @@ + + + + + name + Merbivore + settings + + + settings + + background + #161616 + caret + #FFFFFF + foreground + #E6E1DC + invisibles + #404040 + lineHighlight + #333435 + selection + #454545 + + + + name + Source + scope + source + settings + + + + name + Comment + scope + comment + settings + + fontStyle + italic + foreground + #AD2EA4 + + + + name + Keyword + scope + keyword, storage + settings + + fontStyle + + foreground + #FC6F09 + + + + name + Function (definition) + scope + entity.name.function, keyword.other.name-of-parameter.objc + settings + + fontStyle + + + + + name + Class (definition) + scope + entity.name + settings + + + + name + Class inheritence + scope + entity.other.inherited-class + settings + + foreground + #FC83FF + + + + name + Number + scope + constant.numeric + settings + + fontStyle + + foreground + #58C554 + + + + name + Variable + scope + variable.language, variable.other + settings + + fontStyle + + + + + name + Constant + scope + constant + settings + + fontStyle + + foreground + #1EDAFB + + + + name + Constant (other variable) + scope + variable.other.constant + settings + + + + name + Constant lib + scope + constant.library + settings + + foreground + #8DFF0A + + + + name + support function + scope + support.function + settings + + foreground + #FC6F09 + + + + name + Constant (built-in) + scope + constant.language + settings + + fontStyle + + foreground + #FDC251 + + + + name + String + scope + string + settings + + fontStyle + + foreground + #8DFF0A + + + + name + Library type + scope + support.type + settings + + foreground + #1EDAFB + + + + name + Library constant + scope + support.constant + settings + + foreground + #8DFF0A + + + + name + Markup tag + scope + meta.tag, declaration.tag, entity.name.tag + settings + + fontStyle + + foreground + #FC6F09 + + + + name + Markup tag attribute + scope + entity.other.attribute-name + settings + + foreground + #FFFF89 + + + + name + Invalid + scope + invalid + settings + + background + #990000 + foreground + #FFFFFF + + + + name + String interpolation + scope + constant.character.escaped, constant.character.escape, string source, string source.ruby + settings + + fontStyle + + foreground + #519F50 + + + + name + Diff Add + scope + markup.inserted + settings + + background + #144212 + foreground + #E6E1DC + + + + name + Diff Remove + scope + markup.deleted + settings + + background + #660000 + foreground + #E6E1DC + + + + name + Diff Header + scope + meta.diff.header, meta.separator.diff, meta.diff.index, meta.diff.range + settings + + background + #2F33AB + + + + uuid + 2ABC646D-06F3-48A5-94E9-18EF34474C97 + + diff --git a/node_modules/ace/tool/tmthemes/Monokai.tmTheme b/node_modules/ace/tool/tmthemes/Monokai.tmTheme new file mode 100644 index 00000000..c179cbe2 --- /dev/null +++ b/node_modules/ace/tool/tmthemes/Monokai.tmTheme @@ -0,0 +1,387 @@ + + + + + name + Monokai + settings + + + settings + + background + #272822 + caret + #F8F8F0 + foreground + #F8F8F2 + invisibles + #3B3A32 + lineHighlight + #3E3D32 + selection + #49483E + findHighlight + #FFE792 + findHighlightForeground + #000000 + selectionBorder + #222218 + activeGuide + #9D550FB0 + + bracketsForeground + #F8F8F2A5 + bracketsOptions + underline + + bracketContentsForeground + #F8F8F2A5 + bracketContentsOptions + underline + + tagsOptions + stippled_underline + + + + name + Comment + scope + comment + settings + + foreground + #75715E + + + + name + String + scope + string + settings + + foreground + #E6DB74 + + + + name + Number + scope + constant.numeric + settings + + foreground + #AE81FF + + + + + name + Built-in constant + scope + constant.language + settings + + foreground + #AE81FF + + + + name + User-defined constant + scope + constant.character, constant.other + settings + + foreground + #AE81FF + + + + name + Variable + scope + variable + settings + + fontStyle + + + + + name + Keyword + scope + keyword + settings + + foreground + #F92672 + + + + name + Storage + scope + storage + settings + + fontStyle + + foreground + #F92672 + + + + name + Storage type + scope + storage.type + settings + + fontStyle + italic + foreground + #66D9EF + + + + name + Class name + scope + entity.name.class + settings + + fontStyle + underline + foreground + #A6E22E + + + + name + Inherited class + scope + entity.other.inherited-class + settings + + fontStyle + italic underline + foreground + #A6E22E + + + + name + Function name + scope + entity.name.function + settings + + fontStyle + + foreground + #A6E22E + + + + name + Function argument + scope + variable.parameter + settings + + fontStyle + italic + foreground + #FD971F + + + + name + Tag name + scope + entity.name.tag + settings + + fontStyle + + foreground + #F92672 + + + + name + Tag attribute + scope + entity.other.attribute-name + settings + + fontStyle + + foreground + #A6E22E + + + + name + Library function + scope + support.function + settings + + fontStyle + + foreground + #66D9EF + + + + name + Library constant + scope + support.constant + settings + + fontStyle + + foreground + #66D9EF + + + + name + Library class/type + scope + support.type, support.class + settings + + fontStyle + italic + foreground + #66D9EF + + + + name + Library variable + scope + support.other.variable + settings + + fontStyle + + + + + name + Invalid + scope + invalid + settings + + background + #F92672 + fontStyle + + foreground + #F8F8F0 + + + + name + Invalid deprecated + scope + invalid.deprecated + settings + + background + #AE81FF + foreground + #F8F8F0 + + + + name + JSON String + scope + meta.structure.dictionary.json string.quoted.double.json + settings + + foreground + #CFCFC2 + + + + + name + diff.header + scope + meta.diff, meta.diff.header + settings + + foreground + #75715E + + + + name + diff.deleted + scope + markup.deleted + settings + + foreground + #F92672 + + + + name + diff.inserted + scope + markup.inserted + settings + + foreground + #A6E22E + + + + name + diff.changed + scope + markup.changed + settings + + foreground + #E6DB74 + + + + + scope + constant.numeric.line-number.find-in-files - match + settings + + foreground + #AE81FFA0 + + + + scope + entity.name.filename.find-in-files + settings + + foreground + #E6DB74 + + + + + uuid + D8D5E82E-3D5B-46B5-B38E-8C841C21347D + + diff --git a/node_modules/ace/tool/tmthemes/Pastels on Dark.tmTheme b/node_modules/ace/tool/tmthemes/Pastels on Dark.tmTheme new file mode 100644 index 00000000..47b83631 --- /dev/null +++ b/node_modules/ace/tool/tmthemes/Pastels on Dark.tmTheme @@ -0,0 +1,727 @@ + + + + + author + Mats Persson + name + Pastels on Dark + settings + + + settings + + background + #2C2828 + caret + #A7A7A7 + foreground + #8F938F + invisibles + #FFFFFF40 + lineHighlight + #FFFFFF08 + selection + #DDF0FF33 + + + + name + Comments + scope + comment + settings + + fontStyle + + foreground + #A6C6FF + + + + name + Comments Block + scope + comment.block + settings + + fontStyle + + foreground + #A6C6FF + + + + name + Strings + scope + string + settings + + foreground + #66A968 + + + + name + Numbers + scope + constant.numeric + settings + + fontStyle + + foreground + #CCCCCC + + + + name + Keywords + scope + keyword + settings + + fontStyle + + foreground + #757aD8 + + + + name + Preprocessor Line + scope + meta.preprocessor + settings + + fontStyle + + foreground + #2F006E + + + + name + Preprocessor Directive + scope + keyword.control.import + settings + + fontStyle + bold + + + + name + Functions + scope + support.function + settings + + fontStyle + + foreground + #AEB2F8 + + + + name + Function result + scope + declaration.function function-result + settings + + foreground + #0000FF + + + + name + Function name + scope + declaration.function function-name + settings + + fontStyle + bold + + + + name + Function argument name + scope + declaration.function argument-name + settings + + fontStyle + bold + + + + name + Function argument type + scope + declaration.function function-arg-type + settings + + foreground + #0000FF + + + + name + Function argument variable + scope + declaration.function function-argument + settings + + fontStyle + italic + + + + name + Class name + scope + declaration.class class-name + settings + + fontStyle + underline + + + + name + Class inheritance + scope + declaration.class class-inheritance + settings + + fontStyle + italic underline + + + + name + Invalid + scope + invalid, invalid.illegal + settings + + background + #562D56BF + fontStyle + bold + foreground + #F8F8F8 + + + + name + Invalid + scope + invalid.deprecated + settings + + fontStyle + italic, underline + foreground + #D2A8A1 + + + + name + Invalid Trailing Whitespace + scope + invalid.deprecated.trailing-whitespace + settings + + fontStyle + bold + background + #FFD0D0 + + + + name + Section + scope + declaration.section section-name + settings + + fontStyle + italic + + + + name + Interpolation + scope + string.interpolation + settings + + foreground + #C10006 + + + + name + Regular Expressions + scope + string.regexp + settings + + fontStyle + + foreground + #E9C062 + + + + name + Variables + scope + variable + settings + + foreground + #BEBF55 + + + + name + Variables + scope + variable.language + settings + + foreground + #C1C144 + + + + name + Constants + scope + constant + settings + + foreground + #4FB7C5 + + + + name + Character Constants + scope + constant.character + settings + + fontStyle + + foreground + #AFA472 + + + + name + Language Constants + scope + constant.language + settings + + fontStyle + bold + foreground + #DE8E30 + + + + name + Embedded Code + scope + embedded + settings + + fontStyle + underline + + + + name + Tag name + scope + keyword.markup.element-name + settings + + fontStyle + + foreground + #858EF4 + + + + name + Attribute name + scope + keyword.markup.attribute-name + settings + + fontStyle + + foreground + #9B456F + + + + name + Attribute with Value + scope + meta.attribute-with-value + settings + + fontStyle + + foreground + #9B456F + + + + name + Exceptions + scope + keyword.exception + settings + + fontStyle + bold + foreground + #C82255 + + + + name + Operators + scope + keyword.operator + settings + + fontStyle + + foreground + #797878 + + + + name + Control Structures + scope + keyword.control + settings + + fontStyle + bold + foreground + #6969FA + + + + name + HTML: DocInfo XML + scope + meta.tag.preprocessor.xml + settings + + foreground + #68685B + + + + name + HTML: DocType + scope + meta.tag.sgml.doctype + settings + + foreground + #494949 + + + + name + HTML: DocInfo DTD + scope + string.quoted.docinfo.doctype.DTD + settings + + fontStyle + italic + + + + name + HTML: ServerSide Includes + scope + comment.other.server-side-include.xhtml, comment.other.server-side-include.html + settings + + foreground + #909090 + + + + name + HTML: Tag + scope + text.html declaration.tag, text.html meta.tag, text.html entity.name.tag.xhtml + settings + + foreground + #858EF4 + + + + name + HTML: attribute="" + scope + keyword.markup.attribute-name + settings + + foreground + #9B456F + + + + name + PHP: PHPdocs + scope + keyword.other.phpdoc.php + settings + + foreground + #777777 + + + + name + PHP: Include() & Require() + scope + keyword.other.include.php + settings + + foreground + #C82255 + + + + name + PHP: Constants Core Predefined + scope + support.constant.core.php + settings + + fontStyle + bold + foreground + #DE8E20 + + + + name + PHP: Constants Standard Predefined + scope + support.constant.std.php + settings + + fontStyle + bold + foreground + #DE8E10 + + + + name + PHP: Variables Globals + scope + variable.other.global.php + settings + + foreground + #B72E1D + + + + name + PHP: Variables Safer Globals + scope + variable.other.global.safer.php + settings + + foreground + #00FF00 + + + + name + PHP: Strings Single-Quoted + scope + string.quoted.single.php + settings + + foreground + #BFA36D + + + + name + PHP: Keywords Storage + scope + keyword.storage.php + settings + + foreground + #6969FA + + + + name + PHP: Strings Double-Quoted + scope + string.quoted.double.php + settings + + foreground + #AD9361 + + + + name + CSS: Selectors #ID + scope + entity.other.attribute-name.id.css + settings + + foreground + #EC9E00 + + + + name + CSS: Selectors <Elements> + scope + entity.name.tag.css + settings + + fontStyle + bold + foreground + #B8CD06 + + + + name + CSS: Selectors .ClassName + scope + entity.other.attribute-name.class.css + settings + + foreground + #EDCA06 + + + + name + CSS: Selectors :PseudoClass + scope + entity.other.attribute-name.pseudo-class.css + settings + + foreground + #2E759C + + + + name + CSS: Invalid Comma + scope + invalid.bad-comma.css + settings + + background + #FF0000 + foreground + #FFFFFF + + + + name + CSS: Property Value + scope + support.constant.property-value.css + settings + + foreground + #9B2E4D + + + + name + CSS: Property Keyword + scope + support.type.property-name.css + settings + + foreground + #E1C96B + + + + name + CSS: Property Colours + scope + constant.other.rgb-value.css + settings + + foreground + #666633 + + + + name + CSS: Font Names + scope + support.constant.font-name.css + settings + + foreground + #666633 + + + + name + TMLangDef: Keys + scope + support.constant.tm-language-def, support.constant.name.tm-language-def + settings + + foreground + #7171F3 + + + + name + CSS: Units + scope + keyword.other.unit.css + settings + + foreground + #6969FA + + + + uuid + 343011CC-B7DF-11D9-B5C6-000D93C8BE28 + + diff --git a/node_modules/ace/tool/tmthemes/Slush and Poppies.tmTheme b/node_modules/ace/tool/tmthemes/Slush and Poppies.tmTheme new file mode 100644 index 00000000..02ecbcbe --- /dev/null +++ b/node_modules/ace/tool/tmthemes/Slush and Poppies.tmTheme @@ -0,0 +1,336 @@ + + + + + author + William D. Neumann + name + Slush & Poppies + settings + + + settings + + background + #F1F1F1 + caret + #000000 + foreground + #000000 + invisibles + #BFBFBF + lineHighlight + #00000026 + selection + #B0B0FF + + + + name + Comment + scope + comment + settings + + fontStyle + + foreground + #406040 + + + + name + String + scope + string + settings + + foreground + #C03030 + + + + name + Number + scope + constant.numeric + settings + + foreground + #0080A0 + + + + name + OCaml floating-point constants + scope + source.ocaml constant.numeric.floating-point + settings + + fontStyle + underline + + + + name + Character constants + scope + constant.character + settings + + foreground + #800000 + + + + name + Built-in constant + scope + constant.language + settings + + + + name + User-defined constant + scope + constant.character, constant.other + settings + + + + name + Variable + scope + variable.parameter, variable.other + settings + + + + name + Keyword + scope + keyword + settings + + fontStyle + + foreground + #2060A0 + + + + name + Operators + scope + keyword.operator + settings + + fontStyle + + foreground + #2060A0 + + + + name + OCaml prefix f-p operators + scope + source.ocaml keyword.operator.symbol.prefix.floating-point + settings + + fontStyle + underline + + + + name + OCaml infix f-p operators + scope + source.ocaml keyword.operator.symbol.infix.floating-point + settings + + fontStyle + underline + + + + name + Module Keyword + scope + entity.name.module, support.other.module + settings + + fontStyle + + foreground + #0080FF + + + + name + Storage types + scope + storage.type + settings + + foreground + #A08000 + + + + name + Storage + scope + storage + settings + + foreground + #008080 + + + + name + Variant types + scope + entity.name.class.variant + settings + + foreground + #C08060 + + + + name + Directives + scope + keyword.other.directive + settings + + fontStyle + bold + + + + name + Line-number directives + scope + source.ocaml keyword.other.directive.line-number + settings + + fontStyle + + + + + name + Inherited class + scope + entity.other.inherited-class + settings + + + + name + Function name + scope + entity.name.function + settings + + fontStyle + + foreground + #800000 + + + + name + Type name + scope + storage.type.user-defined + settings + + foreground + #800080 + + + + name + Class type name + scope + entity.name.type.class.type + settings + + foreground + #8000C0 + + + + name + Function argument + scope + variable.parameter + settings + + + + name + Tag name + scope + entity.name.tag + settings + + + + name + Tag attribute + scope + entity.other.attribute-name + settings + + + + name + Library function + scope + support.function + settings + + + + name + Library constant + scope + support.constant + settings + + + + name + Library class/type + scope + support.type, support.class + settings + + + + name + Library variable + scope + support.variable + settings + + + + name + Invalid + scope + invalid + settings + + + + uuid + D68685B8-1CFE-4C10-99C4-E21CBC892376 + + diff --git a/node_modules/ace/tool/tmthemes/Solarized-dark.tmTheme b/node_modules/ace/tool/tmthemes/Solarized-dark.tmTheme new file mode 100644 index 00000000..4efdabdb --- /dev/null +++ b/node_modules/ace/tool/tmthemes/Solarized-dark.tmTheme @@ -0,0 +1,312 @@ + + + + + name + Solarized (dark) + settings + + + settings + + background + #002B36 + caret + #D30102 + foreground + #93A1A1 + invisibles + #93A1A180 + lineHighlight + #073642 + selection + #073642 + + + + name + Comment + scope + comment + settings + + fontStyle + italic + foreground + #657B83 + + + + name + String + scope + string + settings + + foreground + #2AA198 + + + + name + Regexp + scope + string.regexp + settings + + foreground + #D30102 + + + + name + Number + scope + constant.numeric + settings + + foreground + #D33682 + + + + name + Variable + scope + variable.language, variable.other + settings + + foreground + #268BD2 + + + + name + Keyword + scope + keyword + settings + + foreground + #859900 + + + + name + Storage + scope + storage + settings + + fontStyle + bold + foreground + #93A1A1 + + + + name + Class name + scope + entity.name.class, entity.name.type.class + settings + + fontStyle + + foreground + #CB4B16 + + + + name + Function name + scope + entity.name.function + settings + + foreground + #268BD2 + + + + name + Variable start + scope + punctuation.definition.variable + settings + + foreground + #859900 + + + + name + Embedded code markers + scope + punctuation.section.embedded.begin, punctuation.section.embedded.end + settings + + foreground + #D30102 + + + + name + Built-in constant + scope + constant.language, meta.preprocessor + settings + + foreground + #B58900 + + + + name + Support.construct + scope + support.function.construct, keyword.other.new + settings + + foreground + #CB4B16 + + + + name + User-defined constant + scope + constant.character, constant.other + settings + + foreground + #CB4B16 + + + + name + Inherited class + scope + entity.other.inherited-class + settings + + foreground + #6C71C4 + + + + name + Function argument + scope + variable.parameter + settings + + + + name + Tag name + scope + entity.name.tag + settings + + fontStyle + bold + foreground + #268BD2 + + + + name + Tag start/end + scope + punctuation.definition.tag + settings + + foreground + #657B83 + + + + name + Tag attribute + scope + entity.other.attribute-name + settings + + foreground + #93A1A1 + + + + name + Library function + scope + support.function + settings + + foreground + #268BD2 + + + + name + Continuation + scope + punctuation.separator.continuation + settings + + foreground + #D30102 + + + + name + Library constant + scope + support.constant + settings + + + + name + Library class/type + scope + support.type, support.class + settings + + foreground + #859900 + + + + name + Library Exception + scope + support.type.exception + settings + + foreground + #CB4B16 + + + + name + Library variable + scope + support.other.variable + settings + + + + name + Invalid + scope + invalid + settings + + + + uuid + F930B0BF-AA03-4232-A30F-CEF749FF8E72 + + diff --git a/node_modules/ace/tool/tmthemes/Solarized-light.tmTheme b/node_modules/ace/tool/tmthemes/Solarized-light.tmTheme new file mode 100644 index 00000000..9db72b86 --- /dev/null +++ b/node_modules/ace/tool/tmthemes/Solarized-light.tmTheme @@ -0,0 +1,305 @@ + + + + + name + Solarized (light) + settings + + + settings + + background + #FDF6E3 + caret + #000000 + foreground + #586E75 + invisibles + #93A1A180 + lineHighlight + #EEE8D5 + selection + #073642 + + + + name + Comment + scope + comment + settings + + foreground + #93A1A1 + + + + name + String + scope + string + settings + + foreground + #2AA198 + + + + name + Regexp + scope + string.regexp + settings + + foreground + #D30102 + + + + name + Number + scope + constant.numeric + settings + + foreground + #D33682 + + + + name + Variable + scope + variable.language, variable.other + settings + + foreground + #268BD2 + + + + name + Keyword + scope + keyword + settings + + foreground + #859900 + + + + name + Storage + scope + storage + settings + + fontStyle + bold + foreground + #073642 + + + + name + Class name + scope + entity.name.class, entity.name.type.class + settings + + foreground + #268BD2 + + + + name + Function name + scope + entity.name.function + settings + + foreground + #268BD2 + + + + name + Variable start + scope + punctuation.definition.variable + settings + + foreground + #859900 + + + + name + Embedded code markers + scope + punctuation.section.embedded.begin, punctuation.section.embedded.end + settings + + foreground + #D30102 + + + + name + Built-in constant + scope + constant.language, meta.preprocessor + settings + + foreground + #B58900 + + + + name + Support.construct + scope + support.function.construct, keyword.other.new + settings + + foreground + #D30102 + + + + name + User-defined constant + scope + constant.character, constant.other + settings + + foreground + #CB4B16 + + + + name + Inherited class + scope + entity.other.inherited-class + settings + + + + name + Function argument + scope + variable.parameter + settings + + + + name + Tag name + scope + entity.name.tag + settings + + fontStyle + bold + foreground + #268BD2 + + + + name + Tag start/end + scope + punctuation.definition.tag.begin, punctuation.definition.tag.end + settings + + foreground + #93A1A1 + + + + name + Tag attribute + scope + entity.other.attribute-name + settings + + foreground + #93A1A1 + + + + name + Library function + scope + support.function + settings + + foreground + #268BD2 + + + + name + Continuation + scope + punctuation.separator.continuation + settings + + foreground + #D30102 + + + + name + Library constant + scope + support.constant + settings + + + + name + Library class/type + scope + support.type, support.class + settings + + foreground + #859900 + + + + name + Library Exception + scope + support.type.exception + settings + + foreground + #CB4B16 + + + + name + Library variable + scope + support.other.variable + settings + + + + name + Invalid + scope + invalid + settings + + + + uuid + 38E819D9-AE02-452F-9231-ECC3B204AFD7 + + diff --git a/node_modules/ace/tool/tmthemes/SpaceCadet.tmTheme b/node_modules/ace/tool/tmthemes/SpaceCadet.tmTheme new file mode 100644 index 00000000..156f43de --- /dev/null +++ b/node_modules/ace/tool/tmthemes/SpaceCadet.tmTheme @@ -0,0 +1,212 @@ + + + + + author + Alex Ross + comment + Created by Alex Ross + name + SpaceCadet + settings + + + settings + + background + #0D0D0D + caret + #7F005D + foreground + #DDE6CF + invisibles + #BFBFBF + lineHighlight + #00000012 + selection + #40002F + + + + name + Comment + scope + comment + settings + + foreground + #473C45 + + + + name + String + scope + string + settings + + foreground + #805978 + + + + name + Constant + scope + constant + settings + + foreground + #A8885A + + + + name + Variable + scope + variable.parameter, variable.other + settings + + foreground + #596380 + + + + name + Keyword + scope + keyword - keyword.operator, keyword.operator.logical + settings + + foreground + #728059 + + + + name + Storage + scope + storage + settings + + foreground + #9EBF60 + + + + name + Entity + scope + entity + settings + + foreground + #6078BF + + + + name + Inherited class + scope + entity.other.inherited-class + settings + + fontStyle + italic + + + + name + Support + scope + support + settings + + foreground + #8A4B66 + + + + name + Exception + scope + support.type.exception + settings + + foreground + #893062 + + + + name + Tag name + scope + entity.name.tag + settings + + + + name + Tag attribute + scope + entity.other.attribute-name + settings + + + + name + Library constant + scope + support.constant + settings + + + + name + Library class/type + scope + support.type, support.class + settings + + + + name + Library variable + scope + support.other.variable + settings + + + + name + Invalid + scope + invalid + settings + + background + #5F0047 + + + + name + - Meta + settings + + + + name + function.section + scope + meta.function.section + settings + + background + #371D28 + + + + uuid + 2C24E84F-F9FE-4C2E-92D2-F52198BA7E41 + + diff --git a/node_modules/ace/tool/tmthemes/Sunburst.tmTheme b/node_modules/ace/tool/tmthemes/Sunburst.tmTheme new file mode 100644 index 00000000..694c2c8c --- /dev/null +++ b/node_modules/ace/tool/tmthemes/Sunburst.tmTheme @@ -0,0 +1,665 @@ + + + + + author + Stanley Rost + comment + (Ï€) Soryu, 2005 + name + Sunburst + settings + + + settings + + background + #000000 + caret + #A7A7A7 + foreground + #F8F8F8 + invisibles + #CAE2FB3D + lineHighlight + #FFFFFF1A + selection + #DDF0FF33 + + + + name + Comment + scope + comment + settings + + fontStyle + italic + foreground + #AEAEAE + + + + name + Constant + scope + constant + settings + + foreground + #3387CC + + + + name + Entity + scope + entity + settings + + fontStyle + + foreground + #89BDFF + + + + name + Keyword + scope + keyword + settings + + fontStyle + + foreground + #E28964 + + + + name + Storage + scope + storage + settings + + fontStyle + + foreground + #99CF50 + + + + name + String + scope + string + settings + + fontStyle + + foreground + #65B042 + + + + name + Support + scope + support + settings + + fontStyle + + foreground + #9B859D + + + + name + Variable + scope + variable + settings + + foreground + #3E87E3 + + + + name + Invalid – Deprecated + scope + invalid.deprecated + settings + + fontStyle + italic underline + foreground + #FD5FF1 + + + + name + Invalid – Illegal + scope + invalid.illegal + settings + + background + #562D56BF + foreground + #FD5FF1 + + + + name + ----------------------------------- + settings + + + + name + ♦ Embedded Source (Bright) + scope + text source + settings + + background + #B1B3BA08 + + + + name + ♦ Entity inherited-class + scope + entity.other.inherited-class + settings + + fontStyle + italic + foreground + #9B5C2E + + + + name + ♦ String embedded-source + scope + string.quoted source + settings + + fontStyle + + foreground + #DAEFA3 + + + + name + ♦ String constant + scope + string constant + settings + + foreground + #DDF2A4 + + + + name + ♦ String.regexp + scope + string.regexp + settings + + foreground + #E9C062 + + + + name + ♦ String.regexp.«special» + scope + string.regexp constant.character.escape, string.regexp source.ruby.embedded, string.regexp string.regexp.arbitrary-repitition + settings + + foreground + #CF7D34 + + + + name + ♦ String variable + scope + string variable + settings + + foreground + #8A9A95 + + + + name + ♦ Support.function + scope + support.function + settings + + fontStyle + + foreground + #DAD085 + + + + name + ♦ Support.constant + scope + support.constant + settings + + fontStyle + + foreground + #CF6A4C + + + + name + c C/C++ Preprocessor Line + scope + meta.preprocessor.c + settings + + foreground + #8996A8 + + + + name + c C/C++ Preprocessor Directive + scope + meta.preprocessor.c keyword + settings + + foreground + #AFC4DB + + + + name + j Entity Name Type + scope + entity.name.type + settings + + fontStyle + underline + + + + name + j Cast + scope + meta.cast + settings + + fontStyle + italic + foreground + #676767 + + + + name + ✘ Doctype/XML Processing + scope + meta.sgml.html meta.doctype, meta.sgml.html meta.doctype entity, meta.sgml.html meta.doctype string, meta.xml-processing, meta.xml-processing entity, meta.xml-processing string + settings + + foreground + #494949 + + + + name + ✘ Meta.tag.«all» + scope + meta.tag, meta.tag entity + settings + + foreground + #89BDFF + + + + name + ✘ Meta.tag.inline + scope + source entity.name.tag, source entity.other.attribute-name, meta.tag.inline, meta.tag.inline entity + settings + + foreground + #E0C589 + + + + name + ✘ Namespaces + scope + entity.name.tag.namespace, entity.other.attribute-name.namespace + settings + + foreground + #E18964 + + + + name + § css tag-name + scope + meta.selector.css entity.name.tag + settings + + foreground + #CDA869 + + + + name + § css:pseudo-class + scope + meta.selector.css entity.other.attribute-name.tag.pseudo-class + settings + + foreground + #8F9D6A + + + + name + § css#id + scope + meta.selector.css entity.other.attribute-name.id + settings + + foreground + #8B98AB + + + + name + § css.class + scope + meta.selector.css entity.other.attribute-name.class + settings + + foreground + #9B703F + + + + name + § css property-name: + scope + support.type.property-name.css + settings + + foreground + #C5AF75 + + + + name + § css property-value; + scope + meta.property-group support.constant.property-value.css, meta.property-value support.constant.property-value.css + settings + + foreground + #F9EE98 + + + + name + § css @at-rule + scope + meta.preprocessor.at-rule keyword.control.at-rule + settings + + foreground + #8693A5 + + + + name + § css additional-constants + scope + meta.property-value support.constant.named-color.css, meta.property-value constant + settings + + foreground + #DD7B3B + + + + name + § css constructor.argument + scope + meta.constructor.argument.css + settings + + foreground + #8F9D6A + + + + name + ⎇ diff.header + scope + meta.diff, meta.diff.header + settings + + background + #0E2231 + fontStyle + italic + foreground + #F8F8F8 + + + + name + ⎇ diff.deleted + scope + markup.deleted + settings + + background + #420E09 + foreground + #F8F8F8 + + + + name + ⎇ diff.changed + scope + markup.changed + settings + + background + #4A410D + foreground + #F8F8F8 + + + + name + ⎇ diff.inserted + scope + markup.inserted + settings + + background + #253B22 + foreground + #F8F8F8 + + + + name + -------------------------------- + settings + + + + name + Markup: Italic + scope + markup.italic + settings + + fontStyle + italic + foreground + #E9C062 + + + + name + Markup: Bold + scope + markup.bold + settings + + fontStyle + bold + foreground + #E9C062 + + + + name + Markup: Underline + scope + markup.underline + settings + + fontStyle + underline + foreground + #E18964 + + + + name + Markup: Quote + scope + markup.quote + settings + + background + #FEE09C12 + fontStyle + italic + foreground + #E1D4B9 + + + + name + Markup: Heading + scope + markup.heading, markup.heading entity + settings + + background + #632D04 + fontStyle + + foreground + #FEDCC5 + + + + name + Markup: List + scope + markup.list + settings + + foreground + #E1D4B9 + + + + name + Markup: Raw + scope + markup.raw + settings + + background + #B1B3BA08 + fontStyle + + foreground + #578BB3 + + + + name + Markup: Comment + scope + markup comment + settings + + fontStyle + italic + foreground + #F67B37 + + + + name + Markup: Separator + scope + meta.separator + settings + + background + #242424 + foreground + #60A633 + + + + name + Log Entry + scope + meta.line.entry.logfile, meta.line.exit.logfile + settings + + background + #EEEEEE29 + + + + name + Log Entry Error + scope + meta.line.error.logfile + settings + + background + #751012 + + + + uuid + C8C58F9A-35FE-44A4-9BC2-2F3C343DC81D + + diff --git a/node_modules/ace/tool/tmthemes/Textmate (Mac Classic).tmTheme b/node_modules/ace/tool/tmthemes/Textmate (Mac Classic).tmTheme new file mode 100644 index 00000000..4b789dfe --- /dev/null +++ b/node_modules/ace/tool/tmthemes/Textmate (Mac Classic).tmTheme @@ -0,0 +1,450 @@ + + + + + author + Chris Thomas + name + Mac Classic + settings + + + settings + + background + #FFFFFF + caret + #000000 + foreground + #000000 + invisibles + #BFBFBF + lineHighlight + #00000012 + selection + #4D97FF54 + + + + name + Comment + scope + comment + settings + + fontStyle + italic + foreground + #0066FF + + + + name + Keyword + scope + keyword, storage + settings + + fontStyle + bold + foreground + #0000FF + + + + name + Number + scope + constant.numeric + settings + + fontStyle + + foreground + #0000CD + + + + name + User-defined constant + scope + constant + settings + + fontStyle + bold + foreground + #C5060B + + + + name + Built-in constant + scope + constant.language + settings + + fontStyle + bold + foreground + #585CF6 + + + + name + Variable + scope + variable.language, variable.other + settings + + fontStyle + + foreground + #318495 + + + + name + String + scope + string + settings + + fontStyle + + foreground + #036A07 + + + + name + String interpolation + scope + constant.character.escape, string source + settings + + fontStyle + + foreground + #26B31A + + + + name + Preprocessor line + scope + meta.preprocessor + settings + + fontStyle + + foreground + #1A921C + + + + name + Preprocessor directive + scope + keyword.control.import + settings + + fontStyle + bold + foreground + #0C450D + + + + name + Function name + scope + entity.name.function, support.function.any-method + settings + + fontStyle + bold + foreground + #0000A2 + + + + name + Type name + scope + entity.name.type + settings + + fontStyle + underline + + + + name + Inherited class name + scope + entity.other.inherited-class + settings + + fontStyle + italic + + + + name + Function parameter + scope + variable.parameter + settings + + fontStyle + italic + + + + name + Function argument and result types + scope + storage.type.method + settings + + fontStyle + + foreground + #70727E + + + + name + Section + scope + meta.section entity.name.section, declaration.section entity.name.section + settings + + fontStyle + italic + + + + name + Library function + scope + support.function + settings + + fontStyle + bold + foreground + #3C4C72 + + + + name + Library object + scope + support.class, support.type + settings + + fontStyle + bold + foreground + #6D79DE + + + + name + Library constant + scope + support.constant + settings + + fontStyle + bold + foreground + #06960E + + + + name + Library variable + scope + support.variable + settings + + fontStyle + bold + foreground + #21439C + + + + name + JS: Operator + scope + keyword.operator.js + settings + + foreground + #687687 + + + + name + Invalid + scope + invalid + settings + + background + #990000 + foreground + #FFFFFF + + + + name + Invalid trailing whitespace + scope + invalid.deprecated.trailing-whitespace + settings + + background + #FFD0D0 + + + + name + Embedded source + scope + text source, string.unquoted + settings + + background + #0000000D + + + + name + Embedded embedded source + scope + text source string.unquoted, text source text source + settings + + background + #0000000F + + + + name + Markup XML declaration + scope + meta.tag.preprocessor.xml + settings + + fontStyle + + foreground + #68685B + + + + name + Markup DOCTYPE + scope + meta.tag.sgml.doctype, meta.tag.sgml.doctype entity, meta.tag.sgml.doctype string, meta.tag.preprocessor.xml, meta.tag.preprocessor.xml entity, meta.tag.preprocessor.xml string + settings + + fontStyle + + foreground + #888888 + + + + name + Markup DTD + scope + string.quoted.docinfo.doctype.DTD + settings + + fontStyle + italic + + + + name + Markup tag + scope + meta.tag, declaration.tag + settings + + fontStyle + + foreground + #1C02FF + + + + name + Markup name of tag + scope + entity.name.tag + settings + + fontStyle + bold + + + + name + Markup tag attribute + scope + entity.other.attribute-name + settings + + fontStyle + italic + + + + name + Markup: Heading + scope + markup.heading + settings + + fontStyle + bold + foreground + #0C07FF + + + + name + Markup: Quote + scope + markup.quote + settings + + fontStyle + italic + foreground + #000000 + + + + name + Markup: List + scope + markup.list + settings + + foreground + #B90690 + + + + uuid + 71D40D9D-AE48-11D9-920A-000D93589AF6 + + diff --git a/node_modules/ace/tool/tmthemes/Tomorrow-Night-Blue.tmTheme b/node_modules/ace/tool/tmthemes/Tomorrow-Night-Blue.tmTheme new file mode 100644 index 00000000..b1669a27 --- /dev/null +++ b/node_modules/ace/tool/tmthemes/Tomorrow-Night-Blue.tmTheme @@ -0,0 +1,186 @@ + + + + + comment + http://chriskempson.com + name + Tomorrow Night - Blue + settings + + + settings + + background + #002451 + caret + #FFFFFF + foreground + #FFFFFF + invisibles + #404F7D + lineHighlight + #00346E + selection + #003F8E + + + + name + Comment + scope + comment + settings + + foreground + #7285B7 + + + + name + Foreground, Operator + scope + keyword.operator.class, keyword.operator, constant.other, source.php.embedded.line + settings + + fontStyle + + foreground + #FFFFFF + + + + name + Variable, String Link, Regular Expression, Tag Name + scope + variable, support.other.variable, string.other.link, string.regexp, entity.name.tag, entity.other.attribute-name, meta.tag, declaration.tag + settings + + foreground + #FF9DA4 + + + + name + Number, Constant, Function Argument, Tag Attribute, Embedded + scope + constant.numeric, constant.language, support.constant, constant.character, variable.parameter, punctuation.section.embedded, keyword.other.unit + settings + + fontStyle + + foreground + #FFC58F + + + + name + Class, Support + scope + entity.name.class, entity.name.type.class, support.type, support.class + settings + + fontStyle + + foreground + #FFEEAD + + + + name + String, Symbols, Inherited Class, Markup Heading + scope + string, constant.other.symbol, entity.other.inherited-class, markup.heading + settings + + fontStyle + + foreground + #D1F1A9 + + + + name + Operator, Misc + scope + keyword.operator, constant.other.color + settings + + foreground + #99FFFF + + + + name + Function, Special Method, Block Level + scope + entity.name.function, meta.function-call, support.function, keyword.other.special-method, meta.block-level + settings + + fontStyle + + foreground + #BBDAFF + + + + name + Keyword, Storage + scope + keyword, storage, storage.type, entity.name.tag.css + settings + + fontStyle + + foreground + #EBBBFF + + + + name + Invalid + scope + invalid + settings + + background + #F99DA5 + fontStyle + + foreground + #FFFFFF + + + + name + Separator + scope + meta.separator + settings + + background + #BBDAFE + foreground + #FFFFFF + + + + name + Deprecated + scope + invalid.deprecated + settings + + background + #EBBBFF + fontStyle + + foreground + #FFFFFF + + + + uuid + 3F4BB232-3C3A-4396-99C0-06A9573715E9 + + diff --git a/node_modules/ace/tool/tmthemes/Tomorrow-Night-Bright.tmTheme b/node_modules/ace/tool/tmthemes/Tomorrow-Night-Bright.tmTheme new file mode 100644 index 00000000..15d40106 --- /dev/null +++ b/node_modules/ace/tool/tmthemes/Tomorrow-Night-Bright.tmTheme @@ -0,0 +1,186 @@ + + + + + comment + http://chriskempson.com + name + Tomorrow Night - Bright + settings + + + settings + + background + #000000 + caret + #9F9F9F + foreground + #DEDEDE + invisibles + #343434 + lineHighlight + #2A2A2A + selection + #424242 + + + + name + Comment + scope + comment + settings + + foreground + #969896 + + + + name + Foreground + scope + keyword.operator.class, constant.other, source.php.embedded.line + settings + + fontStyle + + foreground + #EEEEEE + + + + name + Variable, String Link, Regular Expression, Tag Name + scope + variable, support.other.variable, string.other.link, string.regexp, entity.name.tag, entity.other.attribute-name, meta.tag, declaration.tag + settings + + foreground + #D54E53 + + + + name + Number, Constant, Function Argument, Tag Attribute, Embedded + scope + constant.numeric, constant.language, support.constant, constant.character, variable.parameter, punctuation.section.embedded, keyword.other.unit + settings + + fontStyle + + foreground + #E78C45 + + + + name + Class, Support + scope + entity.name.class, entity.name.type.class, support.type, support.class + settings + + fontStyle + + foreground + #E7C547 + + + + name + String, Symbols, Inherited Class, Markup Heading + scope + string, constant.other.symbol, entity.other.inherited-class, markup.heading + settings + + fontStyle + + foreground + #B9CA4A + + + + name + Operator, Misc + scope + keyword.operator, constant.other.color + settings + + foreground + #70C0B1 + + + + name + Function, Special Method, Block Level + scope + entity.name.function, meta.function-call, support.function, keyword.other.special-method, meta.block-level + settings + + fontStyle + + foreground + #7AA6DA + + + + name + Keyword, Storage + scope + keyword, storage, storage.type, entity.name.tag.css + settings + + fontStyle + + foreground + #C397D8 + + + + name + Invalid + scope + invalid + settings + + background + #DF5F5F + fontStyle + + foreground + #CED2CF + + + + name + Separator + scope + meta.separator + settings + + background + #82A3BF + foreground + #CED2CF + + + + name + Deprecated + scope + invalid.deprecated + settings + + background + #B798BF + fontStyle + + foreground + #CED2CF + + + + uuid + 33D8C715-AD3A-455B-8DF2-56F708909FFE + + diff --git a/node_modules/ace/tool/tmthemes/Tomorrow-Night-Eighties.tmTheme b/node_modules/ace/tool/tmthemes/Tomorrow-Night-Eighties.tmTheme new file mode 100644 index 00000000..33dabddf --- /dev/null +++ b/node_modules/ace/tool/tmthemes/Tomorrow-Night-Eighties.tmTheme @@ -0,0 +1,186 @@ + + + + + comment + http://chriskempson.com + name + Tomorrow Night - Eighties + settings + + + settings + + background + #2D2D2D + caret + #CCCCCC + foreground + #CCCCCC + invisibles + #6A6A6A + lineHighlight + #393939 + selection + #515151 + + + + name + Comment + scope + comment + settings + + foreground + #999999 + + + + name + Foreground + scope + keyword.operator.class, constant.other, source.php.embedded.line + settings + + fontStyle + + foreground + #CCCCCC + + + + name + Variable, String Link, Tag Name + scope + variable, support.other.variable, string.other.link, entity.name.tag, entity.other.attribute-name, meta.tag, declaration.tag + settings + + foreground + #F2777A + + + + name + Number, Constant, Function Argument, Tag Attribute, Embedded + scope + constant.numeric, constant.language, support.constant, constant.character, variable.parameter, punctuation.section.embedded, keyword.other.unit + settings + + fontStyle + + foreground + #F99157 + + + + name + Class, Support + scope + entity.name.class, entity.name.type.class, support.type, support.class + settings + + fontStyle + + foreground + #FFCC66 + + + + name + String, Symbols, Inherited Class, Markup Heading + scope + string, constant.other.symbol, entity.other.inherited-class, markup.heading + settings + + fontStyle + + foreground + #99CC99 + + + + name + Operator, Misc + scope + keyword.operator, constant.other.color + settings + + foreground + #66CCCC + + + + name + Function, Special Method, Block Level + scope + entity.name.function, meta.function-call, support.function, keyword.other.special-method, meta.block-level + settings + + fontStyle + + foreground + #6699CC + + + + name + Keyword, Storage + scope + keyword, storage, storage.type, entity.name.tag.css + settings + + fontStyle + + foreground + #CC99CC + + + + name + Invalid + scope + invalid + settings + + background + #F2777A + fontStyle + + foreground + #CDCDCD + + + + name + Separator + scope + meta.separator + settings + + background + #99CCCC + foreground + #CDCDCD + + + + name + Deprecated + scope + invalid.deprecated + settings + + background + #CC99CC + fontStyle + + foreground + #CDCDCD + + + + uuid + DE477E5B-BD4D-46B0-BF80-2EA32A2814D5 + + diff --git a/node_modules/ace/tool/tmthemes/Tomorrow-Night.tmTheme b/node_modules/ace/tool/tmthemes/Tomorrow-Night.tmTheme new file mode 100644 index 00000000..bb1efaf0 --- /dev/null +++ b/node_modules/ace/tool/tmthemes/Tomorrow-Night.tmTheme @@ -0,0 +1,186 @@ + + + + + comment + http://chriskempson.com + name + Tomorrow Night + settings + + + settings + + background + #1D1F21 + caret + #AEAFAD + foreground + #C5C8C6 + invisibles + #4B4E55 + lineHighlight + #282A2E + selection + #373B41 + + + + name + Comment + scope + comment + settings + + foreground + #969896 + + + + name + Foreground + scope + keyword.operator.class, constant.other, source.php.embedded.line + settings + + fontStyle + + foreground + #CED1CF + + + + name + Variable, String Link, Regular Expression, Tag Name + scope + variable, support.other.variable, string.other.link, string.regexp, entity.name.tag, entity.other.attribute-name, meta.tag, declaration.tag + settings + + foreground + #CC6666 + + + + name + Number, Constant, Function Argument, Tag Attribute, Embedded + scope + constant.numeric, constant.language, support.constant, constant.character, variable.parameter, punctuation.section.embedded, keyword.other.unit + settings + + fontStyle + + foreground + #DE935F + + + + name + Class, Support + scope + entity.name.class, entity.name.type.class, support.type, support.class + settings + + fontStyle + + foreground + #F0C674 + + + + name + String, Symbols, Inherited Class, Markup Heading + scope + string, constant.other.symbol, entity.other.inherited-class, markup.heading + settings + + fontStyle + + foreground + #B5BD68 + + + + name + Operator, Misc + scope + keyword.operator, constant.other.color + settings + + foreground + #8ABEB7 + + + + name + Function, Special Method, Block Level + scope + entity.name.function, meta.function-call, support.function, keyword.other.special-method, meta.block-level + settings + + fontStyle + + foreground + #81A2BE + + + + name + Keyword, Storage + scope + keyword, storage, storage.type, entity.name.tag.css + settings + + fontStyle + + foreground + #B294BB + + + + name + Invalid + scope + invalid + settings + + background + #DF5F5F + fontStyle + + foreground + #CED2CF + + + + name + Separator + scope + meta.separator + settings + + background + #82A3BF + foreground + #CED2CF + + + + name + Deprecated + scope + invalid.deprecated + settings + + background + #B798BF + fontStyle + + foreground + #CED2CF + + + + uuid + F96223EB-1A60-4617-92F3-D24D4F13DB09 + + diff --git a/node_modules/ace/tool/tmthemes/Tomorrow.tmTheme b/node_modules/ace/tool/tmthemes/Tomorrow.tmTheme new file mode 100644 index 00000000..8c98c226 --- /dev/null +++ b/node_modules/ace/tool/tmthemes/Tomorrow.tmTheme @@ -0,0 +1,186 @@ + + + + + comment + http://chriskempson.com + name + Tomorrow + settings + + + settings + + background + #FFFFFF + caret + #AEAFAD + foreground + #4D4D4C + invisibles + #D1D1D1 + lineHighlight + #EFEFEF + selection + #D6D6D6 + + + + name + Comment + scope + comment + settings + + foreground + #8E908C + + + + name + Foreground + scope + keyword.operator.class, constant.other, source.php.embedded.line + settings + + fontStyle + + foreground + #666969 + + + + name + Variable, String Link, Regular Expression, Tag Name + scope + variable, support.other.variable, string.other.link, string.regexp, entity.name.tag, entity.other.attribute-name, meta.tag, declaration.tag + settings + + foreground + #C82829 + + + + name + Number, Constant, Function Argument, Tag Attribute, Embedded + scope + constant.numeric, constant.language, support.constant, constant.character, variable.parameter, punctuation.section.embedded, keyword.other.unit + settings + + fontStyle + + foreground + #F5871F + + + + name + Class, Support + scope + entity.name.class, entity.name.type.class, support.type, support.class + settings + + fontStyle + + foreground + #C99E00 + + + + name + String, Symbols, Inherited Class, Markup Heading + scope + string, constant.other.symbol, entity.other.inherited-class, markup.heading + settings + + fontStyle + + foreground + #718C00 + + + + name + Operator, Misc + scope + keyword.operator, constant.other.color + settings + + foreground + #3E999F + + + + name + Function, Special Method, Block Level + scope + entity.name.function, meta.function-call, support.function, keyword.other.special-method, meta.block-level + settings + + fontStyle + + foreground + #4271AE + + + + name + Keyword, Storage + scope + keyword, storage, storage.type + settings + + fontStyle + + foreground + #8959A8 + + + + name + Invalid + scope + invalid + settings + + background + #C82829 + fontStyle + + foreground + #FFFFFF + + + + name + Separator + scope + meta.separator + settings + + background + #4271AE + foreground + #FFFFFF + + + + name + Deprecated + scope + invalid.deprecated + settings + + background + #8959A8 + fontStyle + + foreground + #FFFFFF + + + + uuid + 82CCD69C-F1B1-4529-B39E-780F91F07604 + + diff --git a/node_modules/ace/tool/tmthemes/Twilight.tmTheme b/node_modules/ace/tool/tmthemes/Twilight.tmTheme new file mode 100644 index 00000000..a5984e82 --- /dev/null +++ b/node_modules/ace/tool/tmthemes/Twilight.tmTheme @@ -0,0 +1,527 @@ + + + + + author + Michael Sheets + name + Twilight + settings + + + settings + + background + #141414 + caret + #A7A7A7 + foreground + #F8F8F8 + invisibles + #FFFFFF40 + lineHighlight + #FFFFFF08 + selection + #DDF0FF33 + + + + name + Comment + scope + comment + settings + + fontStyle + italic + foreground + #5F5A60 + + + + name + Constant + scope + constant + settings + + foreground + #CF6A4C + + + + name + Entity + scope + entity + settings + + fontStyle + + foreground + #9B703F + + + + name + Keyword + scope + keyword + settings + + fontStyle + + foreground + #CDA869 + + + + name + Storage + scope + storage + settings + + fontStyle + + foreground + #F9EE98 + + + + name + String + scope + string + settings + + fontStyle + + foreground + #8F9D6A + + + + name + Support + scope + support + settings + + fontStyle + + foreground + #9B859D + + + + name + Variable + scope + variable + settings + + foreground + #7587A6 + + + + name + Invalid – Deprecated + scope + invalid.deprecated + settings + + fontStyle + italic underline + foreground + #D2A8A1 + + + + name + Invalid – Illegal + scope + invalid.illegal + settings + + background + #562D56BF + foreground + #F8F8F8 + + + + name + ----------------------------------- + settings + + + + name + ♦ Embedded Source + scope + text source + settings + + background + #B0B3BA14 + + + + name + ♦ Embedded Source (Bright) + scope + text.html.ruby source + settings + + background + #B1B3BA21 + + + + name + ♦ Entity inherited-class + scope + entity.other.inherited-class + settings + + fontStyle + italic + foreground + #9B5C2E + + + + name + ♦ String embedded-source + scope + string source + settings + + fontStyle + + foreground + #DAEFA3 + + + + name + ♦ String constant + scope + string constant + settings + + foreground + #DDF2A4 + + + + name + ♦ String.regexp + scope + string.regexp + settings + + fontStyle + + foreground + #E9C062 + + + + name + ♦ String.regexp.«special» + scope + string.regexp constant.character.escape, string.regexp source.ruby.embedded, string.regexp string.regexp.arbitrary-repitition + settings + + foreground + #CF7D34 + + + + name + ♦ String variable + scope + string variable + settings + + foreground + #8A9A95 + + + + name + ♦ Support.function + scope + support.function + settings + + fontStyle + + foreground + #DAD085 + + + + name + ♦ Support.constant + scope + support.constant + settings + + fontStyle + + foreground + #CF6A4C + + + + name + c C/C++ Preprocessor Line + scope + meta.preprocessor.c + settings + + foreground + #8996A8 + + + + name + c C/C++ Preprocessor Directive + scope + meta.preprocessor.c keyword + settings + + foreground + #AFC4DB + + + + name + ✘ Doctype/XML Processing + scope + meta.tag.sgml.doctype, meta.tag.sgml.doctype entity, meta.tag.sgml.doctype string, meta.tag.preprocessor.xml, meta.tag.preprocessor.xml entity, meta.tag.preprocessor.xml string + settings + + foreground + #494949 + + + + name + ✘ Meta.tag.«all» + scope + declaration.tag, declaration.tag entity, meta.tag, meta.tag entity + settings + + foreground + #AC885B + + + + name + ✘ Meta.tag.inline + scope + declaration.tag.inline, declaration.tag.inline entity, source entity.name.tag, source entity.other.attribute-name, meta.tag.inline, meta.tag.inline entity + settings + + foreground + #E0C589 + + + + name + § css tag-name + scope + meta.selector.css entity.name.tag + settings + + foreground + #CDA869 + + + + name + Function name + scope + entity.name.function, support.function.any-method + settings + + fontStyle + bold + foreground + #AC885B + + + + name + § css:pseudo-class + scope + meta.selector.css entity.other.attribute-name.tag.pseudo-class + settings + + foreground + #8F9D6A + + + + name + § css#id + scope + meta.selector.css entity.other.attribute-name.id + settings + + foreground + #8B98AB + + + + name + § css.class + scope + meta.selector.css entity.other.attribute-name.class + settings + + foreground + #9B703F + + + + name + § css property-name: + scope + support.type.property-name.css + settings + + foreground + #C5AF75 + + + + name + § css property-value; + scope + meta.property-group support.constant.property-value.css, meta.property-value support.constant.property-value.css + settings + + foreground + #F9EE98 + + + + name + § css @at-rule + scope + meta.preprocessor.at-rule keyword.control.at-rule + settings + + foreground + #8693A5 + + + + name + § css additional-constants + scope + meta.property-value support.constant.named-color.css, meta.property-value constant + settings + + foreground + #CA7840 + + + + name + § css constructor.argument + scope + meta.constructor.argument.css + settings + + foreground + #8F9D6A + + + + name + ⎇ diff.header + scope + meta.diff, meta.diff.header, meta.separator + settings + + background + #0E2231 + fontStyle + italic + foreground + #F8F8F8 + + + + name + ⎇ diff.deleted + scope + markup.deleted + settings + + background + #420E09 + foreground + #F8F8F8 + + + + name + ⎇ diff.changed + scope + markup.changed + settings + + background + #4A410D + foreground + #F8F8F8 + + + + name + ⎇ diff.inserted + scope + markup.inserted + settings + + background + #253B22 + foreground + #F8F8F8 + + + + name + Markup: List + scope + markup.list + settings + + foreground + #F9EE98 + + + + name + Markup: Heading + scope + markup.heading + settings + + foreground + #CF6A4C + + + + uuid + 766026CB-703D-4610-B070-8DE07D967C5F + + diff --git a/node_modules/ace/tool/tmthemes/Vibrant Ink.tmTheme b/node_modules/ace/tool/tmthemes/Vibrant Ink.tmTheme new file mode 100644 index 00000000..a1e5cf28 --- /dev/null +++ b/node_modules/ace/tool/tmthemes/Vibrant Ink.tmTheme @@ -0,0 +1,460 @@ + + + + + name + Vibrant Ink + settings + + + settings + + background + #0F0F0F + caret + #FFFFFF + foreground + #FFFFFF + invisibles + #404040 + lineHighlight + #333333 + selection + #6699CC + + + + name + Text base + scope + text + settings + + background + #0F0F0F + foreground + #FFFFFF + + + + name + Inline Ruby Html + scope + source.ruby.rails.embedded.html + settings + + background + #000000 + + + + name + Ruby Html + scope + text.html.ruby + settings + + background + #101010 + foreground + #FFFFFF + + + + name + Invalid + scope + invalid, invalid.deprecated + settings + + background + #000000 + foreground + #CCFF33 + + + + name + Number + scope + constant.numeric + settings + + foreground + #99CC99 + + + + name + Ruby source + scope + source.ruby + settings + + + + name + Source base + scope + source + settings + + background + #000000 + foreground + #FFFFFF + + + + name + Comment + scope + comment + settings + + foreground + #9933CC + + + + name + Constant + scope + constant + settings + + foreground + #339999 + + + + name + Keyword + scope + keyword + settings + + fontStyle + + foreground + #FF6600 + + + + name + Pre-processor Line + scope + keyword.preprocessor + settings + + fontStyle + + foreground + #EDF8F9 + + + + name + Pre-processor Directive + scope + keyword.preprocessor directive + settings + + fontStyle + + foreground + #FFFFFF + + + + name + Function name + scope + entity.name.function, storage.type.function.js + settings + + fontStyle + + foreground + #FFCC00 + + + + name + Function argument + scope + variable.parameter + settings + + fontStyle + italic + + + + name + Block comment + scope + source comment.block + settings + + background + #070707 + foreground + #772CB7 + + + + name + Variable + scope + variable.other + settings + + fontStyle + + foreground + #FFFFFF + + + + name + Support Function + scope + support.function + settings + + foreground + #FFCC00 + + + + name + String + scope + string + settings + + foreground + #66FF00 + + + + name + String escapes + scope + string constant.character.escape + settings + + foreground + #AAAAAA + + + + name + String (executed) + scope + string.interpolated + settings + + background + #CCCC33 + foreground + #000000 + + + + name + Regular expression + scope + string.regexp + settings + + foreground + #44B4CC + + + + name + String (literal) + scope + string.literal + settings + + foreground + #CCCC33 + + + + name + String escapes (executed) + scope + string.interpolated constant.character.escape + settings + + foreground + #555555 + + + + name + Class name + scope + entity.name.class, support.class.js + settings + + fontStyle + underline + + + + name + Class inheritance + scope + entity.other.inherited-class + settings + + fontStyle + italic underline + + + + name + Tag name + scope + entity.name.tag + settings + + fontStyle + + + + + name + Html Meta + scope + meta.tag.inline.any.html, meta.tag.block.any.html + settings + + fontStyle + + foreground + #FF6600 + + + + name + Tag attribute + scope + entity.other.attribute-name + settings + + fontStyle + italic + foreground + #99CC99 + + + + name + Other Keywords + scope + keyword.other + settings + + foreground + #DDE93D + + + + name + CSS Selector + scope + meta.selector.css, entity.other.attribute-name.pseudo-class.css, entity.name.tag.wildcard.css, entity.other.attribute-name.id.css, entity.other.attribute-name.class.css + settings + + foreground + #FF6600 + + + + name + CSS Property + scope + support.type.property-name.css + settings + + foreground + #999966 + + + + name + CSS Other + scope + keyword.other.unit.css, constant.other.rgb-value.css, constant.numeric.css + settings + + foreground + #FFFFFF + + + + name + Javascript Events + scope + support.function.event-handler.js + settings + + foreground + #FFFFFF + + + + name + Javascript Operators + scope + keyword.operator.js + settings + + foreground + #FFFFFF + + + + name + Javascript Keywords + scope + keyword.control.js + settings + + foreground + #CCCC66 + + + + name + Prototype Objects + scope + support.class.prototype.js + settings + + foreground + #FFFFFF + + + + name + Prototype Methods + scope + object.property.function.prototype.js + settings + + foreground + #FF6600 + + + + uuid + 4B7A9AA6-C472-4460-BA48-199E2624956B + + diff --git a/node_modules/ace/tool/tmthemes/Xcode_default.tmTheme b/node_modules/ace/tool/tmthemes/Xcode_default.tmTheme new file mode 100644 index 00000000..c7b5072c --- /dev/null +++ b/node_modules/ace/tool/tmthemes/Xcode_default.tmTheme @@ -0,0 +1,240 @@ + + + + + comment + Carmine Paolino + name + Xcode default + settings + + + settings + + background + #FFFFFF + caret + #000000 + foreground + #000000 + invisibles + #BFBFBF + lineHighlight + #00000012 + selection + #B5D5FF + + + + name + Comment + scope + comment + settings + + foreground + #008E00 + + + + name + Preprocessor Statements + scope + meta.preprocessor, keyword.control.import + settings + + foreground + #7D4726 + + + + name + String + scope + string + settings + + foreground + #DF0002 + + + + name + Number + scope + constant.numeric + settings + + foreground + #3A00DC + + + + name + Built-in constant + scope + constant.language + settings + + foreground + #C800A4 + + + + name + User-defined constant + scope + constant.character, constant.other + settings + + foreground + #275A5E + + + + name + Variable + scope + variable.language, variable.other + settings + + foreground + #C800A4 + + + + name + Keyword + scope + keyword + settings + + foreground + #C800A4 + + + + name + Storage + scope + storage + settings + + foreground + #C900A4 + + + + name + Class name + scope + entity.name.class + settings + + foreground + #438288 + + + + name + Inherited class + scope + entity.other.inherited-class + settings + + + + name + Function name + scope + entity.name.function + settings + + + + name + Function argument + scope + variable.parameter + settings + + + + name + Tag name + scope + entity.name.tag + settings + + foreground + #790EAD + + + + name + Tag attribute + scope + entity.other.attribute-name + settings + + foreground + #450084 + + + + name + Library function + scope + support.function + settings + + foreground + #450084 + + + + name + Library constant + scope + support.constant + settings + + foreground + #450084 + + + + name + Library class/type + scope + support.type, support.class + settings + + foreground + #790EAD + + + + name + Library variable + scope + support.other.variable + settings + + foreground + #790EAD + + + + name + Invalid + scope + invalid + settings + + + + uuid + EE3AD170-2B7F-4DE1-B724-C75F13FE0085 + + diff --git a/node_modules/ace/tool/tmthemes/Zenburnesque.tmTheme b/node_modules/ace/tool/tmthemes/Zenburnesque.tmTheme new file mode 100644 index 00000000..8631f986 --- /dev/null +++ b/node_modules/ace/tool/tmthemes/Zenburnesque.tmTheme @@ -0,0 +1,343 @@ + + + + + author + William D. Neumann + name + Zenburnesque + settings + + + settings + + background + #404040 + caret + #FFFF66 + foreground + #DEDEDE + invisibles + #A8A8A8 + lineHighlight + #A0804026 + selection + #A0A0C0 + + + + name + Comment + scope + comment + settings + + fontStyle + italic + foreground + #709070 + + + + name + Directive + scope + keyword.other.directive + settings + + fontStyle + bold + + + + name + Line-number directives + scope + keyword.other.directive.line-number + settings + + fontStyle + underline + + + + name + Characters + scope + constant.character + settings + + foreground + #FF8080 + + + + name + String + scope + string + settings + + foreground + #FF2020 + + + + name + Number + scope + constant.numeric + settings + + foreground + #22C0FF + + + + name + Floating-point numbers + scope + constant.numeric.floating-point + settings + + fontStyle + underline + + + + name + Built-in constant + scope + constant.language + settings + + + + name + User-defined constant + scope + constant.character, constant.other + settings + + + + name + Variable + scope + variable.parameter, variable.other + settings + + + + name + Language Keyword + scope + keyword + settings + + foreground + #FFFFA0 + + + + name + Module Keyword + scope + entity.name.module, support.other.module + settings + + fontStyle + bold + foreground + #FF8000 + + + + name + Operators + scope + keyword.operator + settings + + foreground + #FFFFA0 + + + + name + Floating-point infix operators + scope + source.ocaml keyword.operator.symbol.infix.floating-point + settings + + fontStyle + underline + + + + name + Floating-point prefix operators + scope + source.ocaml keyword.operator.symbol.prefix.floating-point + settings + + fontStyle + underline + + + + name + Storage Types + scope + storage.type + settings + + foreground + #6080FF + + + + name + Variant Types + scope + entity.name.class.variant + settings + + foreground + #4080A0 + + + + name + Storage + scope + storage + settings + + + + name + Type name + scope + entity.name.type + settings + + foreground + #F09040 + + + + name + Inherited class + scope + entity.other.inherited-class + settings + + + + name + Function name + scope + entity.name.function + settings + + fontStyle + bold + foreground + #FFCC66 + + + + name + Type name + scope + storage.type.user-defined + settings + + foreground + #FFE000 + + + + name + Class type name + scope + entity.name.type.class.type + settings + + foreground + #F4A020 + + + + name + Function argument + scope + variable.parameter + settings + + fontStyle + + + + + name + Tag name + scope + entity.name.tag + settings + + + + name + Tag attribute + scope + entity.other.attribute-name + settings + + + + name + Library function + scope + support.function + settings + + + + name + Library constant + scope + support.constant + settings + + + + name + Library class/type + scope + support.type, support.class + settings + + + + name + Library variable + scope + support.variable + settings + + + + name + Invalid + scope + invalid + settings + + + + uuid + 8D4988B9-ADD8-436F-B388-BC1360F8504B + + diff --git a/node_modules/ace/tool/tmthemes/iPlastic.tmTheme b/node_modules/ace/tool/tmthemes/iPlastic.tmTheme new file mode 100644 index 00000000..7253df6a --- /dev/null +++ b/node_modules/ace/tool/tmthemes/iPlastic.tmTheme @@ -0,0 +1,286 @@ + + + + + author + Jeroen van der Ham + name + iPlastic + settings + + + settings + + background + #EEEEEEEB + caret + #000000 + foreground + #000000 + invisibles + #B3B3B3F4 + lineHighlight + #0000001A + selection + #BAD6FD + + + + name + String + scope + string + settings + + foreground + #009933 + + + + name + Number + scope + constant.numeric + settings + + foreground + #0066FF + + + + name + Regular expression + scope + string.regexp + settings + + foreground + #FF0080 + + + + name + Keyword + scope + keyword + settings + + foreground + #0000FF + + + + name + Identifier + scope + constant.language + settings + + foreground + #9700CC + + + + name + Exception + scope + support.class.exception + settings + + foreground + #990000 + + + + name + Function name + scope + entity.name.function + settings + + foreground + #FF8000 + + + + name + Type name + scope + entity.name.type + settings + + fontStyle + bold underline + + + + name + Arguments + scope + variable.parameter + settings + + fontStyle + italic + + + + name + Comment + scope + comment + settings + + fontStyle + italic + foreground + #0066FF + + + + name + Invalid + scope + invalid + settings + + background + #E71A114D + foreground + #FF0000 + + + + name + Trailing whitespace + scope + invalid.deprecated.trailing-whitespace + settings + + background + #E71A1100 + + + + name + Embedded source + scope + text source + settings + + background + #FAFAFAFC + foreground + #000000 + + + + name + Tag + scope + meta.tag, declaration.tag + settings + + foreground + #0033CC + + + + name + Constant + scope + constant, support.constant + settings + + foreground + #6782D3 + + + + name + Support + scope + support + settings + + fontStyle + bold + foreground + #3333FF + + + + name + Storage + scope + storage + settings + + fontStyle + bold + + + + name + Section name + scope + entity.name.section + settings + + fontStyle + bold underline + + + + name + Frame title + scope + entity.name.function.frame + settings + + fontStyle + bold + foreground + #000000 + + + + name + XML Declaration + scope + meta.tag.preprocessor.xml + settings + + foreground + #333333 + + + + name + Tag Attribute + scope + entity.other.attribute-name + settings + + fontStyle + italic + foreground + #3366CC + + + + name + Tag Name + scope + entity.name.tag + settings + + fontStyle + bold + + + + uuid + 4FCFA210-B247-11D9-9D00-000D93347A42 + + diff --git a/node_modules/ace/tool/tmthemes/idleFingers.tmTheme b/node_modules/ace/tool/tmthemes/idleFingers.tmTheme new file mode 100644 index 00000000..d86a0edd --- /dev/null +++ b/node_modules/ace/tool/tmthemes/idleFingers.tmTheme @@ -0,0 +1,393 @@ + + + + + name + idleFingers + settings + + + settings + + background + #323232 + caret + #91FF00 + foreground + #FFFFFF + invisibles + #404040 + lineHighlight + #353637 + selection + #5A647EE0 + + + + name + text + scope + text + settings + + foreground + #FFFFFF + + + + name + Source base + scope + source + settings + + background + #282828 + foreground + #CDCDCD + + + + name + Comment + scope + comment + settings + + fontStyle + italic + foreground + #BC9458 + + + + name + Html Tags + scope + meta.tag, declaration.tag, meta.doctype + settings + + foreground + #FFE5BB + + + + name + Function Name + scope + entity.name + settings + + foreground + #FFC66D + + + + name + Ruby Function Name + scope + source.ruby entity.name + settings + + foreground + #FFF980 + + + + name + Other Variable + scope + variable.other + settings + + foreground + #B7DFF8 + + + + name + Ruby Class Name + scope + support.class.ruby + settings + + foreground + #CCCC33 + + + + name + Constant + scope + constant, support.constant + settings + + foreground + #6C99BB + + + + name + Keyword + scope + keyword + settings + + fontStyle + + foreground + #CC7833 + + + + name + Pre-processor Line + scope + other.preprocessor.c + settings + + fontStyle + + foreground + #D0D0FF + + + + name + Pre-processor Directive + scope + entity.name.preprocessor + settings + + fontStyle + + + + + name + Function name + scope + entity.name.function + settings + + fontStyle + + + + + name + Function argument + scope + variable.parameter + settings + + fontStyle + italic + + + + name + Block comment + scope + source comment.block + settings + + background + #575757 + foreground + #FFFFFF + + + + name + String + scope + string + settings + + foreground + #A5C261 + + + + name + String escapes + scope + string constant.character.escape + settings + + foreground + #AAAAAA + + + + name + String (executed) + scope + string.interpolated + settings + + background + #CCCC33 + foreground + #000000 + + + + name + Regular expression + scope + string.regexp + settings + + foreground + #CCCC33 + + + + name + String (literal) + scope + string.literal + settings + + foreground + #CCCC33 + + + + name + String escapes (executed) + scope + string.interpolated constant.character.escape + settings + + foreground + #787878 + + + + name + Class name + scope + entity.name.class + settings + + fontStyle + underline + + + + name + Class inheritance + scope + entity.other.inherited-class + settings + + fontStyle + italic underline + + + + name + Tag name + scope + entity.name.tag + settings + + fontStyle + + + + + name + Tag attribute + scope + entity.other.attribute-name + settings + + fontStyle + + + + + name + Support function + scope + support.function + settings + + fontStyle + + foreground + #B83426 + + + + name + Textile List + scope + markup.list.unnumbered.textile + settings + + foreground + #6EA533 + + + + name + Textile Numbered list + scope + markup.list.numbered.textile + settings + + foreground + #6EA533 + + + + name + Textile Bold + scope + markup.bold.textile + settings + + fontStyle + bold + foreground + #C2C2C2 + + + + name + Invalid + scope + invalid + settings + + background + #FF0000 + fontStyle + + foreground + #FFFFFF + + + + name + User1 + scope + collab.user1 + settings + + background + #FFF980 + foreground + #323232 + + + + uuid + 95BEF169-A2E5-4041-A84A-AAFC1DD61558 + + diff --git a/node_modules/ace/tool/tmthemes/krTheme.tmTheme b/node_modules/ace/tool/tmthemes/krTheme.tmTheme new file mode 100644 index 00000000..65c5c9b6 --- /dev/null +++ b/node_modules/ace/tool/tmthemes/krTheme.tmTheme @@ -0,0 +1,551 @@ + + + + + comment + Created by Kenneth Reitz, inspired by minimal design + name + krTheme + settings + + + settings + + background + #0B0A09 + caret + #FF9900 + foreground + #FCFFE0 + invisibles + #FFB16F52 + lineHighlight + #38403D + selection + #AA00FF73 + + + + name + Constant + scope + constant + settings + + fontStyle + + foreground + #D27518C2 + + + + name + Entity + scope + entity + settings + + fontStyle + + foreground + #A89100B5 + + + + name + Entity Other + scope + entity.other + settings + + foreground + #BA6912 + + + + name + Keyword + scope + keyword + settings + + fontStyle + + foreground + #949C8B + + + + name + Storage + scope + storage + settings + + fontStyle + + foreground + #FFEE80 + + + + name + String + scope + string -string.unquoted.old-plist -string.unquoted.heredoc, string.unquoted.heredoc string + settings + + foreground + #C7A4A1B5 + + + + name + Comment + scope + comment + settings + + fontStyle + italic + foreground + #706D5B + + + + name + Support + scope + support + settings + + fontStyle + + foreground + #9FC28A + + + + name + Variable + scope + variable + settings + + fontStyle + + foreground + #D1A796 + + + + name + Lang Variable + scope + variable.language + settings + + fontStyle + + foreground + #FF80E1 + + + + name + Function Call + scope + meta.function-call + settings + + foreground + #FFEE80 + + + + name + Invalid + scope + invalid + settings + + background + #A41300 + foreground + #F8F8F8 + + + + name + Embedded Source + scope + text source, string.unquoted.heredoc, source source + settings + + background + #24231D4D + fontStyle + + foreground + #D9D59F + + + + name + Entity inherited-class + scope + entity.other.inherited-class + settings + + fontStyle + + foreground + #7EFCFF + + + + name + String embedded-source + scope + string.quoted source + settings + + fontStyle + + foreground + #439740BA + + + + name + String constant + scope + string constant + settings + + foreground + #60DB5DBA + + + + name + String.regexp + scope + string.regexp + settings + + foreground + #7DFFC0A6 + + + + name + String variable + scope + string variable + settings + + fontStyle + + foreground + #B8B960 + + + + name + Support.function + scope + support.function + settings + + fontStyle + + foreground + #85873A + + + + name + Support.constant + scope + support.constant + settings + + fontStyle + + foreground + #C27E66 + + + + name + Exception + scope + support.class.exception + settings + + foreground + #FF1E00 + + + + name + C/C++ Preprocessor Line + scope + meta.preprocessor.c + settings + + foreground + #8996A8 + + + + name + C/C++ Preprocessor Directive + scope + meta.preprocessor.c keyword + settings + + foreground + #AFC4DB + + + + name + Doctype/XML Processing + scope + meta.sgml.html meta.doctype, meta.sgml.html meta.doctype entity, meta.sgml.html meta.doctype string, meta.xml-processing, meta.xml-processing entity, meta.xml-processing string + settings + + foreground + #73817D + + + + name + Meta.tag.A + scope + meta.tag, meta.tag entity + settings + + foreground + #BABD9C + + + + name + css tag-name + scope + meta.selector.css entity.name.tag + settings + + foreground + #99A190 + + + + name + css#id + scope + meta.selector.css entity.other.attribute-name.id + settings + + foreground + #CC8844 + + + + name + css.class + scope + meta.selector.css entity.other.attribute-name.class + settings + + foreground + #CFB958 + + + + name + css property-name: + scope + support.type.property-name.css + settings + + foreground + #E0DDAD + + + + name + css property-value; + scope + meta.property-group support.constant.property-value.css, meta.property-value support.constant.property-value.css + settings + + foreground + #AEB14B + + + + name + css @at-rule + scope + meta.preprocessor.at-rule keyword.control.at-rule + settings + + foreground + #FFB010 + + + + name + css additional-constants + scope + meta.property-value support.constant.named-color.css, meta.property-value constant + settings + + foreground + #999179 + + + + name + css constructor.argument + scope + meta.constructor.argument.css + settings + + foreground + #EB939A + + + + name + diff.header + scope + meta.diff, meta.diff.header + settings + + background + #000E1A + fontStyle + + foreground + #F8F8F8 + + + + name + diff.deleted + scope + markup.deleted + settings + + background + #800F00 + foreground + #F8F8F8 + + + + name + diff.changed + scope + markup.changed + settings + + background + #806F00 + foreground + #F8F8F8 + + + + name + diff.inserted + scope + markup.inserted + settings + + background + #228000 + foreground + #F8F8F8 + + + + name + Raw Markup + scope + markup.raw + settings + + background + #8FDDF630 + + + + name + Block Quote + scope + markup.quote + settings + + background + #005BAA + + + + name + List + scope + markup.list + settings + + background + #0F0040 + + + + name + Bold Markup + scope + markup.bold + settings + + fontStyle + bold + foreground + #9D80FF + + + + name + Italic Markup + scope + markup.italic + settings + + fontStyle + italic + foreground + #80FFBB + + + + name + Heading Markup + scope + markup.heading + settings + + fontStyle + bold + + + + uuid + 87F051F7-B6FB-408C-96F9-467B66C14E9F + + diff --git a/node_modules/ace/tool/tmthemes/monoindustrial.tmTheme b/node_modules/ace/tool/tmthemes/monoindustrial.tmTheme new file mode 100644 index 00000000..81f8eb70 --- /dev/null +++ b/node_modules/ace/tool/tmthemes/monoindustrial.tmTheme @@ -0,0 +1,451 @@ + + + + + name + monoindustrial + settings + + + settings + + background + #222C28 + caret + #FFFFFF + foreground + #FFFFFF + invisibles + #666C6880 + lineHighlight + #0C0D0C40 + selection + #91999466 + + + + name + Comment + scope + comment + settings + + background + #151C19 + fontStyle + + foreground + #666C68 + + + + name + Type + scope + storage, support.type + settings + + foreground + #C23B00 + + + + name + Embedded code + scope + string.unquoted.embedded, text source, string.unquoted + settings + + background + #151C19 + foreground + #FFFFFF + + + + name + String interpolation + scope + constant.character.escaped, string source - string.unquoted.embedded, string string source + settings + + background + #1A0700 + foreground + #E9470000 + + + + name + String + scope + string - string source, string source string, meta.scope.heredoc + settings + + background + #1A0700 + fontStyle + + foreground + #C23800 + + + + name + Number + scope + constant.numeric + settings + + foreground + #E98800 + + + + name + Variable + scope + variable.language, variable.other + settings + + fontStyle + + foreground + #648BD2 + + + + name + Constant + scope + constant + settings + + foreground + #E98800 + + + + name + Preprocessor line + scope + other.preprocessor + settings + + background + #161D1A + fontStyle + + foreground + #A8B3AB + + + + name + Preprocessor directive + scope + entity.name.preprocessor + settings + + background + #161D1A + fontStyle + + foreground + #A8B3AB + + + + name + Function name + scope + entity.name.function, keyword.operator, keyword.other.name-of-parameter + settings + + fontStyle + + foreground + #A8B3AB + + + + name + Class name + scope + entity.name.class + settings + + fontStyle + + foreground + #9A2F00 + + + + name + Function parameter + scope + variable.parameter + settings + + fontStyle + + foreground + #648BD2 + + + + name + Function argument and result types + scope + storage.type.method + settings + + fontStyle + + foreground + #666C68 + + + + name + Keyword + scope + keyword, storage.type.function.php + settings + + fontStyle + + foreground + #A39E64 + + + + name + Invalid + scope + invalid + settings + + background + #990000AD + foreground + #FFFFFF + + + + name + Invalid trailing whitespace + scope + invalid.trailing-whitespace + settings + + background + #FFD0D0 + foreground + #000000 + + + + name + Library function + scope + support.function + settings + + fontStyle + + foreground + #588E60 + + + + name + Library object + scope + support.class, support.type, entity.name + settings + + fontStyle + + foreground + #5778B6 + + + + name + Library constant + scope + support.constant + settings + + foreground + #C87500 + + + + name + Library variable + scope + support.other.variable + settings + + fontStyle + + foreground + #5879B7 + + + + name + Markup XML declaration + scope + declaration.xml-processing + settings + + fontStyle + + foreground + #68685B + + + + name + Markup DOCTYPE + scope + declaration.doctype + settings + + fontStyle + + foreground + #888888 + + + + name + Markup DTD + scope + declaration.doctype.DTD + settings + + fontStyle + + foreground + #888888 + + + + name + Markup tag + scope + declaration.tag + settings + + fontStyle + + foreground + #A65EFF + + + + name + Markup name of tag + scope + entity.name.tag + settings + + foreground + #A65EFF + + + + name + Markup tag attribute + scope + entity.other.attribute-name + settings + + fontStyle + + foreground + #909993 + + + + name + Punctuation + scope + punctuation + settings + + foreground + #90999380 + + + + name + Inherited class name + scope + entity.other.inherited-class + settings + + fontStyle + + foreground + #7642B7 + + + + name + Changed files (Subversion) + scope + meta.scope.changed-files.svn, markup.inserted.svn, markup.changed.svn, markup.deleted.svn + settings + + background + #00000059 + fontStyle + + foreground + #FFFFFF + + + + name + Blocks, Expressions 1 + scope + meta.section + settings + + background + #78807B0A + + + + name + Blocks, Expressions 2 + scope + meta.section meta.section + settings + + background + #78807B0A + + + + name + Blocks, Expressions 3 + scope + meta.section meta.section meta.section + settings + + background + #78807B0A + + + + uuid + EEA328BA-54E5-49DC-81F3-1F25BF8AF163 + + diff --git a/node_modules/ace/tool/update_deps.js b/node_modules/ace/tool/update_deps.js new file mode 100644 index 00000000..c3648d9c --- /dev/null +++ b/node_modules/ace/tool/update_deps.js @@ -0,0 +1,324 @@ +var https = require("https"); +var http = require("http"); +var url = require("url"); +var fs = require("fs"); + +var Path = require("path"); +var spawn = require("child_process").spawn; +var async = require("asyncjs"); +var rootDir = __dirname + "/../lib/ace/"; + +var deps = { + csslint: { + path: "mode/css/csslint.js", + url: "https://raw.github.com/stubbornella/csslint/master/release/csslint.js", + needsFixup: true + }, + requirejs: { + path: "../../demo/kitchen-sink/require.js", + url: "https://raw.github.com/jrburke/requirejs/master/require.js", + needsFixup: false + }, + luaparse: { + path: "mode/lua/luaparse.js", + url: "https://raw.github.com/oxyc/luaparse/master/luaparse.js", + needsFixup: true, + postProcess: function(src) { + return src.replace( + /\(function\s*\(root,\s*name,\s*factory\)\s*{[\s\S]*?}\(this,\s*'luaparse',/, + "(function (root, name, factory) {\n factory(exports)\n}(this, 'luaparse'," + ) + } + }, + html5: { + path: "mode/html/saxparser.js", + browserify: { + npmModule: "git+https://github.com/aredridel/html5.git#master", + path: "html5/lib/sax/SAXParser.js", + exports: "SAXParser" + }, + fetch: browserify, + needsFixup: true, + postProcess: function(src) { + return src; + } + }, + xquery: { + path: "mode/xquery/xquery_lexer.js", + browserify: { + npmModule: "git+https://github.com/wcandillon/xqlint.git#master", + path: "xqlint/lib/lexers/xquery_lexer.js", + exports: "XQueryLexer" + }, + fetch: browserify, + needsFixup: true, + postProcess: function(src){ + return src; + } + }, + jsoniq: { + path: "mode/xquery/jsoniq_lexer.js", + browserify: { + npmModule: "git+https://github.com/wcandillon/xqlint.git#master", + path: "xqlint/lib/lexers/jsoniq_lexer.js", + exports: "JSONiqLexer" + }, + fetch: browserify, + needsFixup: true, + postProcess: function(src){ + return src; + } + }, + xqlint: { + path: "mode/xquery/xqlint.js", + browserify: { + npmModule: "git+https://github.com/wcandillon/xqlint.git#master", + path: "xqlint/lib/xqlint.js", + exports: "XQLint" + }, + fetch: browserify, + needsFixup: true, + postProcess: function(src){ + return src; + } + }, + jshint: { + path: "mode/javascript/jshint.js", + browserify: { + npmModule: "git+https://github.com/ajaxorg/jshint.git#master", + path: "jshint/src/jshint.js", + exports: "jshint" + }, + fetch: browserify, + needsFixup: true, + postProcess: function(src) { + src = src.replace( + /"Expected a conditional expression and instead saw an assignment."/g, + '"Assignment in conditional expression"' + ); + src = src.replace(/var defaultMaxListeners = 10;/, function(a) {return a.replace("10", "200")}); + return src; + } + }, + emmet: { + path: "ext/emmet core.js", + url: [ + "https://raw.github.com/sergeche/emmet-sublime/master/emmet/emmet-app.js", + "https://raw.github.com/sergeche/emmet-sublime/master/emmet/snippets.json" + ], + postProcess: function(data) { + return data[0] + .replace("define(emmet)", "define('emmet', [], emmet)") + .replace(/(emmet.define\('bootstrap'.*)[\s\S]*$/, function(_, x) { + return x + "\n" + + "var snippets = " + data[1] + ";\n" + + "var res = require('resources');\n" + + "var userData = res.getVocabulary('user') || {};\n" + + "res.setVocabulary(require('utils').deepMerge(userData, snippets), 'user');\n" + + "});"; + }); + } + }, + vim: { + fetch: function(){ + var rootHref = "https://raw.githubusercontent.com/codemirror/CodeMirror/master/" + var fileMap = {"keymap/vim.js": "keyboard/vim.js", "test/vim_test.js": "keyboard/vim_test.js"}; + async.forEach(Object.keys(fileMap), function(x, next) { + download(rootHref + x, function(e, d) { + d = d.replace(/^\(function.*{[^{}]+^}[^{}]+{/m, "define(function(require, exports, module) {"); + d = d.replace(/^\s*return vimApi;\s*};/gm, " //};") + .replace("var Vim = function() {", "$& return vimApi; } //{") + fs.writeFile(rootDir + fileMap[x], d, next) + }) + }, function() { + console.log("done") + }); + } + }, + liveScript: { + path: "mode/livescript.js", + url: "https://raw.githubusercontent.com/gkz/LiveScript/master/lib/mode-ls.js" + }, + coffee: { + fetch: function(){ + var rootHref = "https://raw.github.com/jashkenas/coffee-script/master/"; + var path = "mode/coffee/"; + + var subDir = "lib/coffee-script/"; + var deps = [ + "helpers.js", + "lexer.js", + "nodes.js", + "parser.js", + "rewriter.js", + "scope.js" + ].map(function(x) { + return { + name: x, + href: rootHref + subDir + x, + path: rootDir + path + x + }; + }); + deps.push({name:"LICENSE", href: rootHref + "LICENSE"}); + + var downloads = {}, counter = 0; + + deps.forEach(function(x) { + download(x.href, function(err, data) { + counter++; + downloads[x.name] = data; + if (counter == deps.length) + allDone(); + }); + }); + function allDone() { + deps.pop(); + var license = downloads.LICENSE.split('\n'); + license = "/**\n * " + license.join("\n * ") + "\n */"; + + deps.forEach(function(x) { + var data = downloads[x.name]; + console.log(x.name); + console.log(!data); + if (!data) + return; + if (x.name == "parser.js") { + data = data.replace("var parser = (function(){", "") + .replace(/\nreturn (new Parser)[\s\S]*$/, "\n\nmodule.exports = $1;\n\n"); + } else { + data = data.replace("(function() {", "") + .replace(/\}\).call\(this\);\s*$/, ""); + } + data = license + + "\n\n" + + "define(function(require, exports, module) {\n" + + data + + "\n});"; + + fs.writeFile(x.path, data, "utf-8", function(err){ + if (err) throw err; + console.log("File " + x.name + " saved."); + console.warn("mode/coffee/coffee-script file needs to updated manually"); + console.warn("mode/coffee/parser.js: parseError function needs to be modified"); + }); + }); + } + } + }, + xmldom: { + fetch: function() { + var rootHref = "https://raw.githubusercontent.com/iDeBugger/xmldom/master/" + var fileMap = { + "sax.js": "mode/xml/sax.js", + "dom-parser.js": "mode/xml/dom-parser.js", + "dom.js": "mode/xml/dom.js" + }; + async.forEach(Object.keys(fileMap), function(x, next) { + download(rootHref + x, function(e, d) { + fs.writeFile(rootDir + fileMap[x], d, next) + }) + }, function() { + console.log("XmlDOM updating done") + }); + } + }, +}; + +var download = function(href, callback) { + if (Array.isArray(href)) + return async.map(href, download, callback); + + var options = url.parse(href); + var protocol = options.protocol === "https:" ? https : http; + console.log("connecting to " + options.host + " " + options.path); + protocol.get(options, function(res) { + var data = ""; + res.setEncoding("utf-8"); + + res.on("data", function(chunk){ + data += chunk; + }); + + res.on("end", function(){ + callback(null, data); + }); + }); +}; + +var getDep = function(dep) { + if (!dep.fetch) + dep.fetch = download + dep.fetch(dep.url, function(err, data) { + if (dep.postProcess) + data = dep.postProcess(data); + if (dep.needsFixup) + data = "define(function(require, exports, module) {\n" + + data + + "\n});"; + + fs.writeFile(rootDir + dep.path, data, "utf-8", function(err){ + if (err) throw err; + console.log("File " + dep.path + " saved."); + }); + }); +}; + +function run(cmd, cb) { + var proc = process.platform == "win32" + ? spawn("cmd", ["/c", cmd], {cwd: __dirname}) + : spawn("bash", ["-c", cmd], {cwd: __dirname}); + + var result = "", err = ""; + proc.stderr.setEncoding("utf8"); + proc.stderr.on('data', function (data) { + err += data; + }); + + proc.stdout.setEncoding("utf8"); + proc.stdout.on('data', function (data) { + result += data; + }); + + proc.on('exit', done); + proc.on('close', done); + function done(code) { + if (code !== 0) { + console.error(cmd + '::: process exited with code :::' + code); + console.error(err) + } + cb(err, result) + } +} + +function unquote(str) { + return str.replace(/\\(.)/g, function(x, a) { + return a == "n" ? "\n" + : a == "t" ? "\t" + : a == "r" ? "\r" + : a + }); +} + +function browserify(_, cb) { + var br = this.browserify; + var path = Path.join("node_modules", br.path) + run("npm install " + this.browserify.npmModule, function() { + run("browserify " + path + " -s " + br.exports, function(err, src) { + src = src.replace(/^.*return\s*\(function/, "module.exports = (function") + .replace(/\}\);\s*$/, ""); + src = src.replace(/(\],|\{)((?:\d+|"\w+"):\[)/g, "$1\n$2") + .replace(/^(\},)(\{[^{}\[\]]*?\}\])/gm, "$1\n$2") + cb(err, src); + }) + }) +} + +var args = process.argv.slice(2); +args = args.filter(function(x) {return x[0] != "-" }); +if (!args.length) + args = Object.keys(deps); + +args.forEach(function(key) { + getDep(deps[key]) +}); + diff --git a/node_modules/ace/tool/wrap_keyword_regexp.js b/node_modules/ace/tool/wrap_keyword_regexp.js new file mode 100644 index 00000000..d1e1508a --- /dev/null +++ b/node_modules/ace/tool/wrap_keyword_regexp.js @@ -0,0 +1,21 @@ +// a little script to turn giant keyword regexps into +// something that ace can use; for example: +// +// \b(NS(Rect(ToCGRect|FromCGRect)|MakeCollectable|S(tringFromProtocol))\b +// +// into +// +// (?:\\b)(NS(?:Rect(?:ToCGRect|FromCGRect)|MakeCollectable|S(?:tringFromProtocol))(?:\b) + +var inputString = process.argv.splice(2)[0]; + +// solve word boundaries +var outputString = inputString.replace(/\\b/g, "(?:\\\\b)"); + +// I apparently need to do this, instead of something clever, because the regexp +// lastIndex is screwing up my positional +outputString = outputString.split("b)("); + +outputString = outputString[0] + "b)(" + outputString[1].replace(/\(([^\?])/g, "(?:$1"); + +console.log("\n\n" + outputString + "\n\n"); \ No newline at end of file diff --git a/node_modules/ace/version.js b/node_modules/ace/version.js new file mode 100755 index 00000000..eaf1e5fe --- /dev/null +++ b/node_modules/ace/version.js @@ -0,0 +1,4 @@ +#!/usr/bin/env node +var x; +x = require('./package'); +console.log(x.version) diff --git a/node_modules/ace_tree/.gitignore b/node_modules/ace_tree/.gitignore new file mode 100644 index 00000000..813d6c10 --- /dev/null +++ b/node_modules/ace_tree/.gitignore @@ -0,0 +1,20 @@ +# Junk that could exist anywhere: +.DS_Store +*.swp +*.tmp + +# Project files that should not be in the repo +.* +!/.gitignore +.*.gz +*.tmTheme.js + +# A handy place to put stuff that git should ignore: +/ignore/ +node_modules/ +jam/ +* * + +.git-ref +npm-debug.log +deps/ diff --git a/node_modules/ace_tree/LICENSE b/node_modules/ace_tree/LICENSE new file mode 100644 index 00000000..d188c3e4 --- /dev/null +++ b/node_modules/ace_tree/LICENSE @@ -0,0 +1,15 @@ + +Copyright (C) 2015, Ajax.org B.V. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +See . + diff --git a/node_modules/ace_tree/demo.html b/node_modules/ace_tree/demo.html new file mode 100644 index 00000000..d415983f --- /dev/null +++ b/node_modules/ace_tree/demo.html @@ -0,0 +1,25 @@ + + + + + + Ace Tree + + + + +
      +
      + + + + + + + diff --git a/node_modules/ace_tree/demo/demo.js b/node_modules/ace_tree/demo/demo.js new file mode 100644 index 00000000..70f609f2 --- /dev/null +++ b/node_modules/ace_tree/demo/demo.js @@ -0,0 +1,117 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +/*global editor:true, txt:true, tree:true, datagrid:true*/ +define(function(require, exports, module) { + +// var ace = require("ace/ace"); +// editor = ace.edit("editor-container"); + +var Tooltip = require("ace_tree/tooltip"); + +txt = require("ace/requirejs/text!root/list.txt").trim().replace(/\r/g, ""); + +var root = {}; +txt.split(/[\r\n]+/).forEach(function(x) { + var parts = x.split(":"); + var node = root; + parts.forEach(function(p, i) { + var map = node.map || (node.map = {}); + node = map[p] || (map[p] = {label: p, $depth: i}); + }); +}); + + + +var Tree = require("ace_tree/tree"); +var DataProvider = require("ace_tree/data_provider"); + +var treeEl = document.getElementById("tree"); +tree = new Tree(treeEl); +tree.setDataProvider(new DataProvider(root)); + + +DataProvider.variableHeightRowMixin.call(tree.provider); +tree.provider.getItemHeight = function(node, i) { + return this.rowHeight; // * (i%2 + 1); +}; + +new Tooltip(tree); + +var datagridEl = document.getElementById("datagrid"); +datagrid = new Tree(datagridEl); +var gridData = new DataProvider(); +gridData.getChildrenFromMap = gridData.getChildren; +gridData.getChildren = function(node) { + node.children = node.map && Object.keys(node.map).map(function(key) { + var child = node.map[key]; + return { + label: key.toUpperCase(), + key: key, + length: key.length, + childCount: Object.keys(child.map || child), + map: child.map + }; + }); + return this.getChildrenFromMap(node); +}; + +gridData.setRoot({map: root.map}); + + + +gridData.columns = [{ + caption: "Key", + getText: function(node) { return node.key }, + width: "60%", + className: "main", + type: "tree" +}, { + caption: "Len", + getText: function(node) { return node.length }, + width: "50px", + className: "red" +}, { + caption: "Child Count", + getText: function(node) { return node.childCount }, + width: "40%" +}]; + + +datagrid.setDataProvider(gridData); + + +window.addEventListener("resize", function() { + tree.resize(); + datagrid.resize(); +}); + + +}); diff --git a/node_modules/ace_tree/demo/layout.js b/node_modules/ace_tree/demo/layout.js new file mode 100644 index 00000000..4729af44 --- /dev/null +++ b/node_modules/ace_tree/demo/layout.js @@ -0,0 +1,134 @@ + +define(function(require, exports, module) { +"use strict"; + +var dom = require("ace/lib/dom"); +var event = require("ace/lib/event"); + +var EditSession = require("ace/edit_session").EditSession; +var UndoManager = require("ace/undomanager").UndoManager; +var Renderer = require("ace/virtual_renderer").VirtualRenderer; +var Editor = require("ace/editor").Editor; +var MultiSelect = require("ace/multi_select").MultiSelect; + +dom.importCssString("\ +splitter {\ + border: 1px solid #C6C6D2;\ + width: 0px;\ + cursor: ew-resize;\ + z-index:10}\ +splitter:hover {\ + margin-left: -2px;\ + width:3px;\ + border-color: #B5B4E0;\ +}\ +", "splitEditor"); + +exports.edit = function(el) { + if (typeof(el) == "string") + el = document.getElementById(el); + + var editor = new Editor(new Renderer(el, require("ace/theme/textmate"))); + + editor.resize(); + event.addListener(window, "resize", function() { + editor.resize(); + }); + return editor; +}; + + +var SplitRoot = function(el, theme, position, getSize) { + el.style.position = position || "relative"; + this.container = el; + this.getSize = getSize || this.getSize; + this.resize = this.$resize.bind(this); + + event.addListener(el.ownerDocument.defaultView, "resize", this.resize); + this.editor = this.createEditor(); +}; + +(function(){ + this.createEditor = function() { + var el = document.createElement("div"); + el.className = this.$editorCSS; + el.style.cssText = "position: absolute; top:0px; bottom:0px"; + this.$container.appendChild(el); + var session = new EditSession(""); + var editor = new Editor(new Renderer(el, this.$theme)); + + /*editor.on("focus", function() { + this._emit("focus", editor); + }.bind(this));*/ + + this.$editors.push(editor); + editor.setFontSize(this.$fontSize); + return editor; + }; + this.$resize = function() { + var size = this.getSize(this.container); + this.rect = { + x: size.left, + y: size.top, + w: size.width, + h: size.height + }; + this.item.resize(this.rect); + }; + this.getSize = function(el) { + return el.getBoundingClientRect(); + }; + this.destroy = function() { + var win = this.container.ownerDocument.defaultView; + event.removeListener(win, "resize", this.resize); + }; + + +}).call(SplitRoot.prototype); + + + +var Split = function(){ + +}; +(function(){ + this.execute = function(options) { + this.$u.execute(options); + }; + +}).call(Split.prototype); + + + +exports.singleLineEditor = function(el) { + var renderer = new Renderer(el); + el.style.overflow = "hidden"; + + renderer.screenToTextCoordinates = function(x, y) { + var pos = this.pixelToScreenCoordinates(x, y); + return this.session.screenToDocumentPosition( + Math.min(this.session.getScreenLength() - 1, Math.max(pos.row, 0)), + Math.max(pos.column, 0) + ); + }; + + renderer.$maxLines = 4; + + renderer.setStyle("ace_one-line"); + var editor = new Editor(renderer); + new MultiSelect(editor); + editor.session.setUndoManager(new UndoManager()); + + editor.setHighlightActiveLine(false); + editor.setShowPrintMargin(false); + editor.renderer.setShowGutter(false); + editor.renderer.setHighlightGutterLine(false); + editor.$mouseHandler.$focusWaitTimout = 0; + + return editor; +}; + + + +}); + diff --git a/node_modules/ace_tree/demo/styles.css b/node_modules/ace_tree/demo/styles.css new file mode 100644 index 00000000..afcc070e --- /dev/null +++ b/node_modules/ace_tree/demo/styles.css @@ -0,0 +1,52 @@ +html { + height: 100%; + width: 100%; + overflow: hidden; +} + +body { + overflow: hidden; + margin: 0; + padding: 0; + height: 100%; + width: 100%; + font-family: Arial, Helvetica, sans-serif, Tahoma, Verdana, sans-serif; + font-size: 12px; + background: rgb(14, 98, 165); +} + +#tree { + position: absolute; + top: 0px; + left: 0px; + bottom: 0px; + right: 80%; +} + +#datagrid { + position: absolute; + top: 0px; + left: 20%; + bottom: 0px; + right: 0px; +} + +#controls { + padding: 5px; +} + +#controls td { + text-align: right; +} + +#controls td + td { + text-align: left; +} +.loading { + color: gray; + position: absolute; + right: 0; + border-left: 1px solid; +} + + diff --git a/node_modules/ace_tree/demo/util.js b/node_modules/ace_tree/demo/util.js new file mode 100644 index 00000000..d2e32524 --- /dev/null +++ b/node_modules/ace_tree/demo/util.js @@ -0,0 +1,238 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var dom = require("ace/lib/dom"); +var event = require("ace/lib/event"); + +var EditSession = require("ace/edit_session").EditSession; +var UndoManager = require("ace/undomanager").UndoManager; +var Renderer = require("ace/virtual_renderer").VirtualRenderer; +var Editor = require("ace/editor").Editor; +var MultiSelect = require("ace/multi_select").MultiSelect; + +exports.createEditor = function(el) { + return new Editor(new Renderer(el)); +} + +exports.createSplitEditor = function(el) { + if (typeof(el) == "string") + el = document.getElementById(el); + + var e0 = document.createElement("div"); + var s = document.createElement("splitter"); + var e1 = document.createElement("div"); + el.appendChild(e0); + el.appendChild(e1); + el.appendChild(s); + e0.style.position = e1.style.position = s.style.position = "absolute"; + el.style.position = "relative"; + var split = {$container: el}; + + split.editor0 = split[0] = new Editor(new Renderer(e0)); + split.editor1 = split[1] = new Editor(new Renderer(e1)); + split.splitter = s; + + MultiSelect(split.editor0); + MultiSelect(split.editor1); + + s.ratio = 0.5; + + split.resize = function resize(){ + var height = el.parentNode.clientHeight - el.offsetTop; + var total = el.clientWidth; + var w1 = total * s.ratio; + var w2 = total * (1- s.ratio); + s.style.left = w1 - 1 + "px"; + s.style.height = el.style.height = height + "px"; + + var st0 = split[0].container.style; + var st1 = split[1].container.style; + st0.width = w1 + "px"; + st1.width = w2 + "px"; + st0.left = 0 + "px"; + st1.left = w1 + "px"; + + st0.top = st1.top = "0px"; + st0.height = st1.height = height + "px"; + + split[0].resize(); + split[1].resize(); + }; + + split.onMouseDown = function(e) { + var rect = el.getBoundingClientRect(); + var x = e.clientX; + var y = e.clientY; + + var button = e.button; + if (button !== 0) { + return; + } + + var onMouseMove = function(e) { + x = e.clientX; + y = e.clientY; + }; + var onResizeEnd = function(e) { + clearInterval(timerId); + }; + + var onResizeInterval = function() { + s.ratio = (x - rect.left) / rect.width + split.resize() + }; + + event.capture(s, onMouseMove, onResizeEnd); + var timerId = setInterval(onResizeInterval, 40); + + return e.preventDefault(); + }; + + + + event.addListener(s, "mousedown", split.onMouseDown); + event.addListener(window, "resize", split.resize); + split.resize(); + return split; +}; + +/***************************/ +exports.stripLeadingComments = function(str) { + if(str.slice(0,2)=='/*') { + var j = str.indexOf('*/')+2; + str = str.substr(j); + } + return str.trim() + "\n"; +}; + +/***************************/ +exports.saveOption = function(el, val) { + if (!el.onchange && !el.onclick) + return; + + if ("checked" in el) { + if (val !== undefined) + el.checked = val; + + localStorage && localStorage.setItem(el.id, el.checked ? 1 : 0); + } + else { + if (val !== undefined) + el.value = val; + + localStorage && localStorage.setItem(el.id, el.value); + } +}; + +exports.bindCheckbox = function(id, callback, noInit) { + if (typeof id == "string") + var el = document.getElementById(id); + else { + var el = id; + id = el.id; + } + var el = document.getElementById(id); + if (localStorage && localStorage.getItem(id)) + el.checked = localStorage.getItem(id) == "1"; + + var onCheck = function() { + callback(!!el.checked); + exports.saveOption(el); + }; + el.onclick = onCheck; + noInit || onCheck(); + return el; +}; + +exports.bindDropdown = function(id, callback, noInit) { + if (typeof id == "string") + var el = document.getElementById(id); + else { + var el = id; + id = el.id; + } + if (localStorage && localStorage.getItem(id)) + el.value = localStorage.getItem(id); + + var onChange = function() { + callback(el.value); + exports.saveOption(el); + }; + + el.onchange = onChange; + noInit || onChange(); +}; + +exports.fillDropdown = function(el, values) { + if (typeof el == "string") + el = document.getElementById(el); + + dropdown(values).forEach(function(e) { + el.appendChild(e); + }); +}; + +function elt(tag, attributes, content) { + var el = dom.createElement(tag); + if (typeof content == "string") { + el.appendChild(document.createTextNode(content)); + } else if (content) { + content.forEach(function(ch) { + el.appendChild(ch); + }); + } + + for (var i in attributes) + el.setAttribute(i, attributes[i]); + return el; +} + +function optgroup(values) { + return values.map(function(item) { + if (typeof item == "string") + item = {name: item, caption: item}; + return elt("option", {value: item.name}, item.caption || item.desc); + }); +} + +function dropdown(values) { + if (Array.isArray(values)) + return optgroup(values); + + return Object.keys(values).map(function(i) { + return elt("optgroup", {"label": i}, optgroup(values[i])); + }); +} + + +}); diff --git a/node_modules/ace_tree/lib/ace_tree/anchor.js b/node_modules/ace_tree/lib/ace_tree/anchor.js new file mode 100644 index 00000000..827d83a2 --- /dev/null +++ b/node_modules/ace_tree/lib/ace_tree/anchor.js @@ -0,0 +1,242 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("ace/lib/oop"); +var EventEmitter = require("ace/lib/event_emitter").EventEmitter; + +/** + * + * Defines the floating pointer in the document. Whenever text is inserted or deleted before the cursor, the position of the cursor is updated. + * + * @class Anchor + **/ + +/** + * Creates a new `Anchor` and associates it with a document. + * + * @param {Document} doc The document to associate with the anchor + * @param {Number} row The starting row position + * @param {Number} column The starting column position + * + * @constructor + **/ + +var Anchor = exports.Anchor = function(doc, row, column) { + this.document = doc; + + if (typeof column == "undefined") + this.setPosition(row.row, row.column); + else + this.setPosition(row, column); + + this.$onChange = this.onChange.bind(this); + doc.on("change", this.$onChange); +}; + +(function() { + + oop.implement(this, EventEmitter); + + /** + * Returns an object identifying the `row` and `column` position of the current anchor. + * @returns {Object} + **/ + + this.getPosition = function() { + return this.$clipPositionToDocument(this.row, this.column); + }; + + /** + * + * Returns the current document. + * @returns {Document} + **/ + + this.getDocument = function() { + return this.document; + }; + + /** + * Fires whenever the anchor position changes. + * + * Both of these objects have a `row` and `column` property corresponding to the position. + * + * Events that can trigger this function include [[Anchor.setPosition `setPosition()`]]. + * + * @event change + * @param {Object} e An object containing information about the anchor position. It has two properties: + * - `old`: An object describing the old Anchor position + * - `value`: An object describing the new Anchor position + * + * + **/ + + this.onChange = function(e) { + var delta = e.data; + var range = delta.range; + + if (range.start.row == range.end.row && range.start.row != this.row) + return; + + if (range.start.row > this.row) + return; + + if (range.start.row == this.row && range.start.column > this.column) + return; + + var row = this.row; + var column = this.column; + var start = range.start; + var end = range.end; + + if (delta.action === "insertText") { + if (start.row === row && start.column <= column) { + if (start.row === end.row) { + column += end.column - start.column; + } else { + column -= start.column; + row += end.row - start.row; + } + } else if (start.row !== end.row && start.row < row) { + row += end.row - start.row; + } + } else if (delta.action === "insertLines") { + if (start.row <= row) { + row += end.row - start.row; + } + } else if (delta.action === "removeText") { + if (start.row === row && start.column < column) { + if (end.column >= column) + column = start.column; + else + column = Math.max(0, column - (end.column - start.column)); + + } else if (start.row !== end.row && start.row < row) { + if (end.row === row) + column = Math.max(0, column - end.column) + start.column; + row -= (end.row - start.row); + } else if (end.row === row) { + row -= end.row - start.row; + column = Math.max(0, column - end.column) + start.column; + } + } else if (delta.action == "removeLines") { + if (start.row <= row) { + if (end.row <= row) + row -= end.row - start.row; + else { + row = start.row; + column = 0; + } + } + } + + this.setPosition(row, column, true); + }; + + /** + * Sets the anchor position to the specified row and column. If `noClip` is `true`, the position is not clipped. + * @param {Number} row The row index to move the anchor to + * @param {Number} column The column index to move the anchor to + * @param {Boolean} noClip Identifies if you want the position to be clipped + * + * + * + **/ + + this.setPosition = function(row, column, noClip) { + var pos; + if (noClip) { + pos = { + row: row, + column: column + }; + } else { + pos = this.$clipPositionToDocument(row, column); + } + + if (this.row == pos.row && this.column == pos.column) + return; + + var old = { + row: this.row, + column: this.column + }; + + this.row = pos.row; + this.column = pos.column; + this._emit("change", { + old: old, + value: pos + }); + }; + + /** + * When called, the `'change'` event listener is removed. + * + **/ + + this.detach = function() { + this.document.removeEventListener("change", this.$onChange); + }; + + /** + * Clips the anchor position to the specified row and column. + * @param {Number} row The row index to clip the anchor to + * @param {Number} column The column index to clip the anchor to + * + **/ + this.$clipPositionToDocument = function(row, column) { + var pos = {}; + + if (row >= this.document.getLength()) { + pos.row = Math.max(0, this.document.getLength() - 1); + pos.column = this.document.getLine(pos.row).length; + } + else if (row < 0) { + pos.row = 0; + pos.column = 0; + } + else { + pos.row = row; + pos.column = Math.min(this.document.getLine(pos.row).length, Math.max(0, column)); + } + + if (column < 0) + pos.column = 0; + + return pos; + }; + +}).call(Anchor.prototype); + +}); diff --git a/node_modules/ace_tree/lib/ace_tree/commands/default_commands.js b/node_modules/ace_tree/lib/ace_tree/commands/default_commands.js new file mode 100644 index 00000000..e7918244 --- /dev/null +++ b/node_modules/ace_tree/lib/ace_tree/commands/default_commands.js @@ -0,0 +1,159 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +function bindKey(win, mac) { + return {win: win, mac: mac}; +} + +exports.commands = [{ + name: "selectAll", + bindKey: bindKey("Ctrl-A", "Command-A"), + exec: function(editor) { editor.selectAll(); } +}, { + name: "centerselection", + bindKey: bindKey(null, "Ctrl-L"), + exec: function(editor) { editor.centerSelection(); } +}, { + name: "closeOrlevelUp", + bindKey: bindKey("Left", "Left|Ctrl-B"), + exec: function(editor) { editor.navigateLevelUp(true); } +}, , { + name: "levelUp", + bindKey: bindKey("Shift-Left", "Shift-Left|Ctrl-B"), + exec: function(editor) { editor.navigateLevelUp(); } +}, { + name: "levelDown", + bindKey: bindKey("Right", "Right|Ctrl-F"), + exec: function(editor) { editor.navigateLevelDown(); } +}, { + name: "goToStart", + editorKey: bindKey("Ctrl-Home", "Ctrl-Home"), + bindKey: bindKey("Home|Ctrl-Home", "Home|Ctrl-Home"), + exec: function(editor) { editor.navigateStart(); } +}, { + name: "goToEnd", + editorKey: bindKey("Ctrl-End", "Ctrl-End"), + bindKey: bindKey("End|Ctrl-End", "End|Ctrl-End"), + exec: function(editor) { editor.navigateEnd(); } +}, { + name: "closeAllFromSelected", + bindKey: bindKey("Ctrl-Left", "Ctrl-Left"), + exec: function(ed) { ed.provider.close(ed.selection.getCursor(), true); } +}, { + name: "openAllFromSelected", + bindKey: bindKey("Ctrl-Right", "Ctrl-Right"), + exec: function(ed) { ed.provider.open(ed.selection.getCursor(), true); } +}, { + name: "pageup", + bindKey: "Option-PageUp", + exec: function(editor) { editor.scrollPageUp(); } +}, { + name: "gotopageup", + bindKey: "PageUp", + exec: function(editor) { editor.gotoPageUp(); } +}, { + name: "pagedown", + bindKey: "Option-PageDown", + exec: function(editor) { editor.scrollPageDown(); } +}, { + name: "gotopageDown", + bindKey: "PageDown", + exec: function(editor) { editor.gotoPageDown(); } +}, { + name: "scrollup", + bindKey: bindKey("Ctrl-Up", null), + exec: function(e) { e.renderer.scrollBy(0, -2 * e.renderer.layerConfig.lineHeight); } +}, { + name: "scrolldown", + bindKey: bindKey("Ctrl-Down", null), + exec: function(e) { e.renderer.scrollBy(0, 2 * e.renderer.layerConfig.lineHeight); } +}, { + name: "insertstring", + exec: function(e, args) { e.insertSting(args) } +}, { + name: "goUp", + bindKey: bindKey("Up", "Up|Ctrl-P"), + exec: function(editor) { editor.selection.moveSelection(-1); } +}, { + name: "goDown", + bindKey: bindKey("Down", "Down|Ctrl-N"), + exec: function(editor) { editor.selection.moveSelection(1); } +}, { + name: "selectUp", + bindKey: bindKey("Shift-Up", "Shift-Up"), + exec: function(editor) { editor.selection.moveSelection(-1, true); } +}, { + name: "selectDown", + bindKey: bindKey("Shift-Down", "Shift-Down"), + exec: function(editor) { editor.selection.moveSelection(1, true); } +}, { + name: "selectToUp", + bindKey: bindKey("Ctrl-Up", "Ctrl-Up"), + exec: function(editor) { editor.selection.moveSelection(-1, false, true); } +}, { + name: "selectToDown", + bindKey: bindKey("Ctrl-Down", "Ctrl-Down"), + exec: function(editor) { editor.selection.moveSelection(1, false, true); } +}, { + name: "selectMoreUp", + bindKey: bindKey("Ctrl-Shift-Up", "Ctrl-Shift-Up"), + exec: function(editor) { editor.selection.moveSelection(-1, true, true); } +}, { + name: "selectMoreDown", + bindKey: bindKey("Ctrl-Shift-Down", "Ctrl-Shift-Down"), + exec: function(editor) { editor.selection.moveSelection(1, true, true); } +}, { + name: "rename", + bindKey: "F2", + exec: function(tree) { tree.edit && tree.edit.startRename(); } +}, { + name: "chose", + bindKey: "Enter", + exec: function(tree) { tree._emit("afterChoose"); } +}, { + name: "delete", + bindKey: "Delete", + exec: function(tree) { tree._emit("delete"); } +}, { + name: "foldOther", + bindKey: bindKey("Alt-0", "Command-Option-0"), + exec: function(tree) { + tree.provider.close(tree.provider.root, true); + tree.reveal(tree.selection.getCursor()); + } +} + + +]; + +}); diff --git a/node_modules/ace_tree/lib/ace_tree/config.js b/node_modules/ace_tree/lib/ace_tree/config.js new file mode 100644 index 00000000..ef800e49 --- /dev/null +++ b/node_modules/ace_tree/lib/ace_tree/config.js @@ -0,0 +1,273 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"no use strict"; + +var lang = require("ace/lib/lang"); +var oop = require("ace/lib/oop"); +var net = require("ace/lib/net"); +var EventEmitter = require("ace/lib/event_emitter").EventEmitter; + +var global = (function() { + return this; +})(); + +var options = { + packaged: false, + workerPath: null, + modePath: null, + themePath: null, + basePath: "", + suffix: ".js", + $moduleUrls: {} +}; + +exports.get = function(key) { + if (!options.hasOwnProperty(key)) + throw new Error("Unknown config key: " + key); + + return options[key]; +}; + +exports.set = function(key, value) { + if (!options.hasOwnProperty(key)) + throw new Error("Unknown config key: " + key); + + options[key] = value; +}; + +exports.all = function() { + return lang.copyObject(options); +}; + +// module loading +oop.implement(exports, EventEmitter); + +exports.moduleUrl = function(name, component) { + if (options.$moduleUrls[name]) + return options.$moduleUrls[name]; + + var parts = name.split("/"); + component = component || parts[parts.length - 2] || ""; + var base = parts[parts.length - 1].replace(component, "").replace(/(^[\-_])|([\-_]$)/, ""); + + if (!base && parts.length > 1) + base = parts[parts.length - 2]; + var path = options[component + "Path"]; + if (path == null) + path = options.basePath; + if (path && path.slice(-1) != "/") + path += "/"; + return path + component + "-" + base + this.get("suffix"); +}; + +exports.setModuleUrl = function(name, subst) { + return options.$moduleUrls[name] = subst; +}; + +exports.$loading = {}; +exports.loadModule = function(moduleName, onLoad) { + var module, moduleType; + if (Array.isArray(moduleName)) { + moduleType = moduleName[0]; + moduleName = moduleName[1]; + } + + try { + module = require(moduleName); + } catch (e) {}; + // require(moduleName) can return empty object if called after require([moduleName], callback) + if (module && !exports.$loading[moduleName]) + return onLoad && onLoad(module); + + if (!exports.$loading[moduleName]) + exports.$loading[moduleName] = []; + + exports.$loading[moduleName].push(onLoad); + + if (exports.$loading[moduleName].length > 1) + return; + + var afterLoad = function() { + require([moduleName], function(module) { + exports._emit("load.module", {name: moduleName, module: module}); + var listeners = exports.$loading[moduleName]; + exports.$loading[moduleName] = null; + listeners.forEach(function(onLoad) { + onLoad && onLoad(module); + }); + }); + }; + + if (!exports.get("packaged")) + return afterLoad(); + net.loadScript(exports.moduleUrl(moduleName, moduleType), afterLoad); +}; + + +// initialization +exports.init = function() { + options.packaged = require.packaged || module.packaged || (global.define && define.packaged); + + if (!global.document) + return ""; + + var scriptOptions = {}; + var scriptUrl = ""; + + var scripts = document.getElementsByTagName("script"); + for (var i=0; i .caption { + overflow: visible; + display: inline-block; +} +.ace_tree-light .tree-row { + border: 1px solid transparent; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +.ace_tree-light .tree-row:hover, +.ace_tree-light .tree-row.hover{ + background: rgba(0, 0, 0, 0.03); +} +.ace_tree-light .tree-row.selected { + background: rgba(0, 0, 0, 0.04); +} + +.ace_tree_focus.ace_tree-light .tree-row.selected { + border-top: 1px solid #3A9BEC; + border-bottom: 1px solid #185F97; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#1f82d2', endColorstr='#2890e5'); + background: -webkit-gradient(linear, left top, left bottom, from(#2890E5), color-stop(1, #1F82D2)); + background: -moz-linear-gradient(center bottom, #1f82d2 0%, #2890e5 100%) repeat scroll 0 0 transparent; + background: linear-gradient(center bottom, #1f82d2 0%, #2890e5 100%) repeat scroll 0 0 transparent; + color: #f8f8f8; +} + + +/* datagrid */ + +.ace_tree-light .tree-row>.tree-column { + border: 1px solid rgb(204, 204, 204); + border-width: 0 1px 1px 0; + padding: 4px 5px; +} + +.ace_tree-light .tree-row.selected>.tree-column { + background: transparent; +} +.ace_tree-light .tree-headings { + background: rgb(253, 253, 253); +} +.ace_tree-light .tree-headings>.tree-column { + background: transparent; + padding: 5px 3px; +} + +.ace_tree-light .tree-headings>.tree-column-resizer { + height: 100%; + background: rgb(182, 182, 182); + display: inline-block; + width: 1px; + z-index: 1000; + position: absolute; + margin-left: -1px; + border-left: 1px solid rgba(0, 0, 0, 0); +} + + + diff --git a/node_modules/ace_tree/lib/ace_tree/css/light_theme.js b/node_modules/ace_tree/lib/ace_tree/css/light_theme.js new file mode 100644 index 00000000..1a3838f7 --- /dev/null +++ b/node_modules/ace_tree/lib/ace_tree/css/light_theme.js @@ -0,0 +1,33 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright 2011 Irakli Gozalishvili. All rights reserved. + * 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. + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { + +exports.isDark = false; +exports.cssClass = "ace_tree-light"; +exports.cssText = require("ace/requirejs/text!./light_theme.css"); + +var dom = require("ace/lib/dom"); +dom.importCssString(exports.cssText, exports.cssClass); + +}); \ No newline at end of file diff --git a/node_modules/ace_tree/lib/ace_tree/css/tree.css b/node_modules/ace_tree/lib/ace_tree/css/tree.css new file mode 100644 index 00000000..5fafd0d5 --- /dev/null +++ b/node_modules/ace_tree/lib/ace_tree/css/tree.css @@ -0,0 +1,191 @@ +.ace_tree{ + overflow : hidden; + font : 12px Tahoma, Arial; + cursor: default; + position: relative; + white-space: pre; +} + +.ace_tree textarea{ + position : absolute; + z-index : 0; +} + +.ace_tree_scroller { + position: absolute; + overflow: hidden; + top: 0; + bottom: 0; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + -o-user-select: none; + user-select: none; +} + +.ace_tree_content { + position: absolute; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + +.ace_scrollbar { + position: absolute; + overflow-x: hidden; + overflow-y: auto; + right: 0; + top: 0; + bottom: 0; +} + +.ace_scrollbar-inner { + position: absolute; + cursor: text; + left: 0; + top: 0; +} + +.ace_scrollbar-h { + position: absolute; + overflow-x: auto; + overflow-y: hidden; + right: 0; + left: 0; + bottom: 0; +} + +.ace_tree_horheading { + position : absolute; +} + +.ace_tree_verheading{ + bottom : 0; + position : absolute; +} + +.ace_tree_heading { + z-index: 10; + position: relative; + white-space: nowrap; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + pointer-events: none; +} + +.ace_tree_layer { + z-index: 1; + position: absolute; + overflow: hidden; + white-space: nowrap; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + pointer-events: none; +} + +.ace_tree .tree-indent { + display : inline-block; +} + +.ace_tree_selection_range{ + position : absolute; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +.ace_tree_focus .ace_tree_selection_range{ + +} + +.ace_tree-editor { + position : absolute; + z-index : 10000; + background : white; + padding : 3px 4px 3px 4px; + -moz-box-sizing : border-box; + box-sizing : border-box; + border : 1px dotted green; + left: 0; + right: 0 +} + + + +.ace_tree .toggler { + width: 10px; + height: 10px; + background-repeat: no-repeat; + background-position: 0px 0px; + background-repeat: no-repeat; + cursor: pointer; + display: inline-block; + pointer-events: auto; +} + +.ace_tree .toggler.empty { + pointer-events: none; +} + +.ace_tree .toggler.open { + background-position: -10px 0px; +} + +.ace_tree .toggler.empty { + background-position: 50px 0px; + cursor: default; +} + +.ace_tree_cells, .ace_tree_cell-layer { + width: 100%; +} +.ace_tree_selection-layer { + width: 100%; + height: 110%; +} +.ace_tree_cells .message.empty { + text-align: center; + opacity: 0.9; + cursor : default; +} + +/* datagrid */ + +.ace_tree .tree-row>.tree-column { + display: inline-block; + overflow: hidden; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + + +.tree-headings { + white-space: nowrap; + position: absolute; + overflow: hidden; + top: 0; + left: 0; + right: 0; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +.tree-headings>.tree-column { + display: inline-block; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.tree-headings>.tree-column-resizer { + height: 100%; + background: rgb(182, 182, 182); + display: inline-block; + width: 2px; + z-index: 1000; + position: absolute; + margin-left: -2px; + border-left: 1px solid rgba(0, 0, 0, 0); +} diff --git a/node_modules/ace_tree/lib/ace_tree/css/tree_background.png b/node_modules/ace_tree/lib/ace_tree/css/tree_background.png new file mode 100644 index 0000000000000000000000000000000000000000..a97a2340d764dd5e9d9d1e1d073ba88eced60afd GIT binary patch literal 3676 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 0) { + this.open(childNode, deep - 1); + } + } + + if (justLoaded) + node.justLoaded = true; + + this.rows = items.length; + silent || this._signal("expand", node); + }; + + this.close = + this.collapse = function(node, deep, silent) { + if (typeof deep != "number") + deep = deep ? 1000 : 0; + var items = this.visibleItems; + var isRoot = node === this.root; + if (isRoot) { + this.setOpen(node, false); + if (deep) { + for (var i = 0; i < items.length; i++) { + var ch = items[i]; + if (!ch.isRoot) + if (this.isOpen(ch) && ch.$depth - node.$depth < deep) { + this.setOpen(ch, false); + silent || this._signal("collapse", ch); + } + } + } + items.length = 0; + if (isRoot) + this.open(this.root, 0, silent); + return; + } + + if (!node || !this.isOpen(node)) + return; + var i = items.indexOf(node); + if (i === -1) + return; + var thisDepth = node.$depth; + var deletecount = 0; + for (var t = i + 1; t < items.length; t++) { + if (items[t].$depth > thisDepth) + deletecount++; + else + break; + } + + if (deep) { + for (var j = 0; j < deletecount; j++) { + var ch = items[j + i]; + if (this.isOpen(ch) && ch.$depth - node.$depth < deep) { + this.setOpen(ch, false); + silent || this._signal("collapse", ch); + } + } + } + items.splice(i + 1, deletecount); + this.setOpen(node, false); + silent || this._signal("collapse", node); + + if (isRoot) + this.open(this.root, 0, silent); + }; + + this.toggleNode = function(node, deep, silent) { + if (node && this.isOpen(node)) + this.close(node, deep, silent); + else + this.open(node, deep, silent); + }; + + this.sort = function(children, compare) { + if (!compare) { + compare = alphanumCompare; + } + return children.sort(function(a, b) { + var aChildren = a.children || a.map; + var bChildren = b.children || b.map; + if (aChildren && !bChildren) return -1; + if (!aChildren && bChildren) return 1; + + return compare(a.label || "", b.label || ""); + }); + }; + + this.setFilter = function(fn) { + this.$filterFn = fn; + this.setRoot(this.root); + }; + this.getChildren = function(node) { + var children = node.children; + if (!children) { + if (node.status === "pending") + return; + if (node.map) { + children = Object.keys(node.map).map(function(key) { + var ch = node.map[key]; + ch.parent = node; + return ch; + }); + } else if (node.items) { + children = node.items; + } + if (children) { + node.children = children; + } + } + var ch = children && children[0] && children[0]; + if (ch) { + var d = (node.$depth + 1) || 0; + children.forEach(function(n) { + n.$depth = d; + n.parent = node; + }); + } + + if (this.$filterFn) { + children = children && children.filter(this.$filterFn); + } + + if (this.$sortNodes && !node.$sorted) { + children && this.sort(children); + } + return children; + }; + this.loadChildren = null; + this.shouldLoadChildren = function(node, ch) { + return node.status === "pending"; + }; + + this.hasChildren = function(node) { + if (node.children) + return node.children.length !== 0; + return node.map + || node.items && node.items.length; + }; + + this.findNodeByPath = function() { + + }; + + this.getSibling = function(node, dir) { + if (!dir) dir = 1; + var parent = node.parent; + var ch = this.getChildren(parent); + var pos = ch.indexOf(node); + return ch[pos + dir]; + }; + + this.getNodeAtIndex = function(i) { + return this.visibleItems[i]; + }; + + this.getIndexForNode = function(node) { + return this.visibleItems.indexOf(node); + }; + + this.getMinIndex = function() {return 0}; + this.getMaxIndex = function() {return this.visibleItems.length - 1}; + + this.setOpen = function(node, val) { + return node.isOpen = val; + }; + this.isOpen = function(node) { + return node.isOpen; + }; + this.isVisible = function(node) { + return this.visibleItems.indexOf(node) !== -1; + }; + this.isSelected = function(node) { + return node.isSelected; + }; + this.setSelected = function(node, val) { + return node.isSelected = !!val; + }; + this.isSelectable = function(node) { + return !node || !node.noSelect; + }; + + this.isAncestor = function(node, child) { + do { + if (child == node) + return true; + } while (child = child.parent); + return false; + }; + + this.setAttribute = function(node, name, value) { + node[name] = value; + this._signal("change", node); + }; + + this.getDataRange = function(rows, columns, callback) { + var view = this.visibleItems.slice(rows.start, rows.start + rows.length); + callback(null, view, false); + return view; + }; + + this.getRange = function(top, bottom) { + var start = Math.floor(top / this.rowHeight); + var end = Math.ceil(bottom / this.rowHeight) + 1; + var range = this.visibleItems.slice(start, end); + range.count = start; + range.size = this.rowHeight * range.count; + return range; + }; + this.getTotalHeight = function(top, bottom) { + return this.rowHeight * this.visibleItems.length; + }; + + this.getNodePosition = function(node) { + var i = this.visibleItems.indexOf(node); + if (i == -1 && node && node.parent) { + i = this.visibleItems.indexOf(node.parent); + } + var top = i * this.rowHeight; + var height = this.rowHeight; + return {top: top, height: height}; + }; + + this.findItemAtOffset = function(offset, clip) { + var index = Math.floor(offset / this.rowHeight); + if (clip) + index = Math.min(Math.max(0, index), this.visibleItems.length - 1); + return this.visibleItems[index]; + }; + + this.getIconHTML = function(node) { + return ""; + }; + this.getClassName = function(node) { + return (node.className || "") + (node.status == "loading" ? " loading" : ""); + }; + this.setClass = function(node, name, include) { + node.className = node.className || ""; + dom.setCssClass(node, name, include); + this._signal("changeClass"); + }; + this.redrawNode = null; + this.getCaptionHTML = function(node) { + return escapeHTML(node.label || node.name || ""); + }; + this.getContentHTML = null; + this.getEmptyMessage = function() { return this.emptyMessage || "" }; + this.getText = function(node) { + return node.label || node.name || ""; + }; + this.getRowIndent = function(node){ + return node.$depth; + }; + this.hideAllNodes = function(){ + this.visibleItems = []; + this.forceEmpty = true; + this.setRoot(this.root); + }; + this.showAllNodes = function(){ + this.forceEmpty = false; + this.setRoot(this.root); + }; + +}).call(DataProvider.prototype); + +function alphanumCompare(a, b) { + var caseOrder = 0; + for (var x = 0, l = Math.min(a.length, b.length); x < l; x++) { + var ch1 = a.charCodeAt(x); + var ch2 = b.charCodeAt(x); + + if (ch1 < 58 && ch2 < 58 && ch1 > 47 && ch2 > 47) { + var num1 = 0, num2 = 0; + var n = x; + do { + num1 = 10 * num1 + (ch1 - 48); + ch1 = a.charCodeAt(++n); + } while(ch1 > 47 && ch1 < 58); + n = x; + do { + num2 = 10 * num2 + (ch2 - 48); + ch2 = b.charCodeAt(++n); + } while(ch2 > 47 && ch2 < 58); + + if (num1 === num2) + x = n - 1; + else + return num1 - num2; + } else if (ch1 !== ch2) { + var ch1L = a[x].toLowerCase(); + var ch2L = b[x].toLowerCase(); + if (ch1L < ch2L) return -1; + if (ch1L > ch2L) return 1; + if (!caseOrder) caseOrder = ch2 - ch1; + } + } + return caseOrder || a.length - b.length; +} + +DataProvider.alphanumCompare = alphanumCompare; +DataProvider.variableHeightRowMixin = function() { + var reset = function () { + this.$cachedTotalHeight = 0; + }.bind(this); + this.on("collapse", reset); + this.on("expand", reset); + // this.rowCache + this.getNodePosition = function(node) { + var i = this.visibleItems.indexOf(node); + if (i == -1 && node && node.parent) { + i = this.visibleItems.indexOf(node.parent); + } + + var items = this.visibleItems; + var top = 0, height = 0; + for (var index = 0; index < i; index++) { + height = this.getItemHeight(items[index], index); + top += height; + } + height = this.getItemHeight(items[i], i); + return {top: top, height: height}; + }; + + this.findIndexAtOffset = function(offset, clip) { + var items = this.visibleItems; + var top = 0, index = 0, l = items.length; + while (index < l) { + var height = this.getItemHeight(items[index].height, index); + top += height; + index++; + if (top >= offset) { + index--; + top -= height; + break; + } + } + + if (clip) + index = Math.min(Math.max(0, index), items.length - 1); + return index; + }; + + this.findItemAtOffset = function(offset, clip) { + var index = this.findIndexAtOffset(offset, clip); + return this.visibleItems[index]; + }; + + this.getItemHeight = function(node, index) { + return node.height || this.rowHeight; + }; + + this.getRange = function(top, bottom) { + var items = this.visibleItems; + var startH = 0, index = 0, l = items.length; + while (index < l) { + var height = this.getItemHeight(items[index].height, index); + startH += height; + index++; + if (startH >= top) { + index--; + startH -= height; + break; + } + } + index = Math.min(Math.max(0, index), items.length - 1); + + var start = index; + var end = this.findIndexAtOffset(bottom, true) + 1; + var range = this.visibleItems.slice(start, end); + range.count = start; + range.size = startH; + return range; + }; + + this.getTotalHeight = function () { + if (!this.$cachedTotalHeight) { + var items = this.visibleItems; + var height = 0; + for (var index = 0; index < items.length; index++) { + height += this.getItemHeight(items[index], index); + } + this.$cachedTotalHeight = height; + } + return this.$cachedTotalHeight; + }; +}; +module.exports = DataProvider; +}); diff --git a/node_modules/ace_tree/lib/ace_tree/data_provider_mirror.js b/node_modules/ace_tree/lib/ace_tree/data_provider_mirror.js new file mode 100644 index 00000000..c294c750 --- /dev/null +++ b/node_modules/ace_tree/lib/ace_tree/data_provider_mirror.js @@ -0,0 +1,71 @@ +/** + * The main class required to set up a Tree instance in the browser. + * + * @class Tree + **/ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("ace/lib/oop"); +var DataProvider = require("./data_provider"); + +var Mirror = function(source) { + this.source = source; + this.rowHeight = 25; + this.expandedList = Object.create(null); + this.selectedList = Object.create(null); + + source && this.setRoot(source.root); +}; + +oop.inherits(Mirror, DataProvider); + +(function() { + + this.setRoot = function(root){ + if (Array.isArray(root)) + root = {items: root}; + + this.root = root || {}; + + if (this.root.$depth == undefined) { + this.root.$depth = -1; + } + if (this.root.$depth < 0) { + this.visibleItems = []; + this.root.isOpen = false; + this.open(this.root); + this.visibleItems.unshift(); + } else { + this.visibleItems = [this.root]; + } + this.$selectedNode = this.root; + + this._signal("setRoot"); + this._signal("change"); + }; + + this.setOpen = function(node, val) { + if (val) + this.expandedList[node.path] = val; + else + delete this.expandedList[node.path]; + }; + this.isOpen = function(node) { + return this.expandedList[node.path]; + }; + this.isSelected = function(node) { + return this.selectedList[node.path]; + }; + this.setSelected = function(node, val) { + if (val) + this.selectedList[node.path] = !!val; + else + delete this.selectedList[node.path]; + }; + +}).call(Mirror.prototype); + +module.exports = Mirror; +}); diff --git a/node_modules/ace_tree/lib/ace_tree/data_provider_test.js b/node_modules/ace_tree/lib/ace_tree/data_provider_test.js new file mode 100644 index 00000000..701d0d06 --- /dev/null +++ b/node_modules/ace_tree/lib/ace_tree/data_provider_test.js @@ -0,0 +1,96 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +if (typeof process !== "undefined") { + require("amd-loader"); + require("./test/setup_paths"); +} + +define(function(require, exports, module) { +"use strict"; + +var TreeData = require("./data_provider"); +var assert = require("ace/test/assertions"); + +module.exports = { + "test: simple expand/collapse" : function() { + var model = new TreeData([{label: "a"}]); + assert.equal(model.visibleItems.length, 1); + var first = model.visibleItems[0]; + assert.equal(first.$depth, 0); + + first.items = [{label: "x"}]; + + model.expand(first); + assert.equal(model.visibleItems.length, 2); + var second = model.visibleItems[1]; + assert.equal(second.$depth, 1); + model.collapse(first); + + assert.equal(model.visibleItems.length, 1); + assert.equal(model.visibleItems[0], first); + + // console.log(model.visibleItems); + }, + + "test: async expand/collapse" : function() { + var model = new TreeData([{label: "a"}]); + assert.equal(model.visibleItems.length, 1); + var first = model.visibleItems[0]; + assert.equal(first.$depth, 0); + + first.status = "pending"; + model.loadChildren = function(node, cb) { + node.map = {x : {label: "x"}}; + cb(null); + }; + + model.expand(first); + assert.equal(model.visibleItems.length, 2); + var second = model.visibleItems[1]; + assert.equal(second.$depth, 1); + + // console.log(model.visibleItems); + }, + + "test alphanum sort" : function() { + var alphanumCompare = TreeData.alphanumCompare + assert.equal( + ["w4y", "w4x", "a14", "a2", "A2"].sort(alphanumCompare) + "", + ["a2","A2","a14","w4x","w4y"] + "" + ); + } +}; + +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec(); +} diff --git a/node_modules/ace_tree/lib/ace_tree/edit.js b/node_modules/ace_tree/lib/ace_tree/edit.js new file mode 100644 index 00000000..4dcc71e4 --- /dev/null +++ b/node_modules/ace_tree/lib/ace_tree/edit.js @@ -0,0 +1,396 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var Range = require("ace/range").Range; + +var UndoManager = require("ace/undomanager").UndoManager; +var Renderer = require("ace/virtual_renderer").VirtualRenderer; +var Editor = require("ace/editor").Editor; +var FontMetrics = require("ace/layer/font_metrics").FontMetrics; +require("ace/multi_select"); + +var EditableTree = function(tree) { + this.tree = tree; + this.tree.on("click", this.onClick = this.onClick.bind(this)); + this.tree.on("blur", this.onTreeBlur = this.onTreeBlur.bind(this)); + this.tree.on("focus", this.onTreeFocus = this.waitForRename.bind(this)); + this.tree.on("mousedown", this.onMouseDown = this.onMouseDown.bind(this)); + this.tree.on("dblclick", this.onDoubleClick = this.onDoubleClick.bind(this)); + this.tree.on("startDrag", this.onTreeBlur); + this.timer = null; +}; + +(function() { + this.RENAME_DELAY = 400; + this.onTreeBlur = function(e) { this.cancel() }; + + this.onDoubleClick = function(e) { + var node = e.getNode(); + if (this.tree.provider.columns) { + if (e.domEvent.detail == 2 && node) { + var columnData = this.tree.renderer.$headingLayer.findColumn(e.getDocumentPosition().x); + var column = columnData && columnData.column; + if (column.editor) { + this.startRename(node, column); + e.stop(); + } + } + return; + } + }; + this.onMouseDown = function(e) { + this.cancel(); + if (e.domEvent.detail > 1 || e.getButton() !== 0) { + return; + } + var sel = this.tree.selection.getSelectedNodes(); + if (sel.length == 1 && e.editor.isFocused() && !this.afterRename) { + this.lastNode = sel[0]; + } + }; + this.cancel = function() { + if (this.timer) + clearTimeout(this.timer); + this.lastNode = null; + }; + this.waitForRename = function() { + this.afterRename = setTimeout(function() { + this.afterRename = null; + }.bind(this), 10); + }; + this.onClick = function(e) { + var node = e.getNode(); + if (this.tree.provider.columns) + return; + var lastNode = this.lastNode; + this.cancel(); + var sel = this.tree.selection.getSelectedNodes(); + if (sel.length != 1) + return; + + if (!node || !lastNode || node != sel[0] || node != lastNode) + return; + this.timer = setTimeout(function() { + this.cancel(); + var sel = this.tree.selection.getSelectedNodes(); + if (lastNode === sel[0] && sel.length == 1) { + this.startRename(lastNode); + } + }.bind(this), this.RENAME_DELAY); + }; + this.createEditor = function(el) { + var renderer = new Renderer(el); + var wrapper = document.createElement("div"); + wrapper.className = "ace_wrapper"; + wrapper.appendChild(renderer.container); + wrapper.style.position = "absolute"; + + renderer.screenToTextCoordinates = function(x, y) { + var pos = this.pixelToScreenCoordinates(x, y); + return this.session.screenToDocumentPosition( + Math.min(this.session.getScreenLength() - 1, Math.max(pos.row, 0)), + Math.max(pos.column, 0) + ); + }; + renderer.setStyle("ace_one-line"); + renderer.setStyle("ace_tree-editor"); + var editor = new Editor(renderer); + editor.session.setUndoManager(new UndoManager()); + editor.wrapper = wrapper; + + editor.setHighlightActiveLine(false); + editor.setShowPrintMargin(false); + editor.renderer.setShowGutter(false); + editor.renderer.setHighlightGutterLine(false); + editor.$mouseHandler.$focusWaitTimout = 0; + editor.renderer.setPadding(2); + editor.container.style.font = "inherit"; + editor.renderer.$markerBack.element.style.marginTop = + editor.renderer.$cursorLayer.element.style.marginTop = "1px"; + if (this.column) + editor.renderer.scroller.style.paddingTop = "1px"; + + var tree = this.tree; + if (!tree.renderer.fontMetrics) { + tree.renderer.fontMetrics = new FontMetrics(tree.renderer.container); + } + tree.renderer.fontMetrics.checkForSizeChanges(); + + editor.session.$setFontMetrics(tree.renderer.fontMetrics); + + return editor; + }; + + this._initEditor = function() { + this.ace = this.createEditor(); + this.ace.treeEditor = this; + this.ace.commands.bindKeys({ + "Esc": function(ace) { + ace.treeEditor.endRename(true); + ace.treeEditor.tree.focus(); + }, + "Enter": function(ace) { + ace.treeEditor.endRename(); + ace.treeEditor.tree.focus(); + }, + "Tab": function(ace) { + ace.treeEditor.editNext(1); + }, + "Shift-Tab": function(ace) { + ace.treeEditor.editNext(-1); + } + }); + this.tree.container.appendChild(this.ace.wrapper); + + // make sure no one can steal focus from us + setTimeout(function() { + if (this.ace) { + this.ace.focus(); + this.ace.on("blur", this._onBlur = this._onBlur.bind(this)); + } + }.bind(this), 20); + this.tree.renderer.on("afterRender", this._onAfterRender = this._onAfterRender.bind(this)); + this.ace.renderer.on("afterRender", this._onAfterRender); + this.ace.on("execCommand", function() { + this.tree.reveal(this.renaming, false); + }.bind(this)); + this.ace.focus(); + this._onAfterRender(); + + this.tree._emit("createEditor", {ace: this.ace}); + }; + + this._onBlur = function() { + if (!this.ace || !this.ace.textInput || !this.renaming) + return; + if (this.ace.$mouseHandler.isMousePressed) + return; + // for debugging + // console.log("comment me out when you are done!") + // if (document.activeElement === this.ace.textInput.getElement()) + // return; + this.endRename(); + }; + + this._onAfterRender = function() { + var i = this.tree.provider.getIndexForNode(this.renaming); + var domNode = this.tree.renderer.$cellLayer.getDomNodeAtIndex(i); + var style = this.ace.wrapper.style; + if (!domNode || !domNode.lastChild) + return style.top = "-100px"; + + var renameNode = this.column + ? domNode.children[this.column.index] + : domNode.lastChild; + // empty nodes will have wrong height + if (!renameNode.textContent) + renameNode.textContent = "\xa0"; + + if (this.column && this.renaming.fullWidth) + renameNode = renameNode.parentNode; + var rect = renameNode.getBoundingClientRect(); + var treeRect = this.tree.container.getBoundingClientRect(); + + if (this.column) { + var child = renameNode.lastChild; + var left = rect.left; + var offset = this.column.type === "tree" && !this.renaming.fullWidth + ? (child.nodeType == 1 ? child.getBoundingClientRect() : rect).left - left - 2 + : 0; + style.top = rect.top - treeRect.top + "px"; + style.left = rect.left - treeRect.left + offset + "px"; + style.width = rect.width - offset + "px"; + style.height = rect.height + "px"; + } else { + var nodeRect = domNode.getBoundingClientRect(); + var maxWidth = Math.max(nodeRect.right - rect.left, 10); + var chars = this.ace.session.$getStringScreenWidth(this.ace.session.getLine(0))[0]; + var minWidth = Math.max(chars*this.tree.renderer.fontMetrics.$characterSize.width + 6, 15); + style.top = rect.top - treeRect.top + 2 + "px"; + style.left = rect.left - treeRect.left - 2 + "px"; + style.width = Math.min(minWidth, maxWidth) + "px"; + style.height = rect.height - 4 + "px"; + domNode.style.color = "transparent"; + this.ace.renderer.onResize(!this.lastDomNode, 0, Math.min(minWidth, maxWidth), this.ace.renderer.$size.height); + this.lastDomNode = domNode; + } + }; + + this._destroyEditor = function() { + if (this.lastDomNode) { + this.lastDomNode.style.color = ""; + this.lastDomNode + } + this.ace.off("blur", this._onBlur); + + this.tree.renderer.off("afterRender", this._onAfterRender); + this.ace.blur(); + + this.ace.destroy(); + if (this.ace.wrapper.parentNode) + this.ace.wrapper.parentNode.removeChild(this.ace.wrapper); + this.ace = null; + }; + + this.findNextEditPoint = function(dir, node, col, keepColumn) { + if (col == null) + col = this.column ? this.column.index : 0; + if (node == null) + node = this.renaming; + var provider = this.tree.provider; + var columns = provider.columns; + + if (columns && !keepColumn) { + var i = col + dir; + if (columns[i]) + return {node: node, column: i}; + else + col = dir < 0 ? columns.length - 1 : 0; + } + + var nodeIndex = provider.getIndexForNode(node); + var newNode = provider.getNodeAtIndex(nodeIndex + dir); + + return newNode && {node: newNode, column: col}; + }; + + this.editNext = function(dir, keepColumn) { + var p = this.findNextEditPoint(dir, this.renaming, null, keepColumn); + if (p) { + if (this.renaming) { + var node = this.renaming; + if (p.node == node && p.column == (this.column && this.column.index) + dir) + p = null; + this.stopRename(); // save current change + var model = this.tree.provider; + if (model.updateNodeAfterChange) { + node = model.updateNodeAfterChange(node); + if (p) + p.node = model.updateNodeAfterChange(p.node); + } + p = p || this.findNextEditPoint(dir, node); + } + if (p && p.node) + this.startRename(p.node, p.column); + } + }; + + + this.startRename = function(node, column) { + var model = this.tree.provider; + node = node || this.tree.selection.getCursor(); + if (!node) + return false; + if (typeof column == "number" && model.columns) + column = model.columns[column]; + if (model.columns && node.fullWidth) + column = model.columns[0]; + if (this.renaming === node && this.column == column || node.noSelect) + return false; + + if (this.renaming) + this.endRename(true); + + if (model.isEditable && !model.isEditable(node) || node.isEditable === false) + return false; + + this.column = column; + var val = (column || model).getText(node); + var e = { + node: node, + column: column, + value: val + }; + this.tree._emit("beforeRename", e); + + if (e.defaultPrevented || !e.node) + return; + this.renaming = e.node; + this._initEditor(); + + this.tree._emit("renameStart", e); + + if (e.node != node && e.value == val) + e.value = (column || model).getText(node); + + this.tree.renderer.scrollCaretIntoView(this.renaming); + this.tree.renderer.visualizeFocus(); + var endCol = -1; + if (this.renaming.isNew) { + val = ""; + } else { + val = e.value; + // todo move this to c9.ide.tree? + if (!column && !node.isFolder) + endCol = val.lastIndexOf("."); + } + if (endCol < 0) + endCol = val.length; + this.origVal = val; + this.ace.setValue(val); + this.ace.selection.setRange(endCol + ? new Range(0, 0, 0, endCol) + : new Range(0, 1, 0, val.length) + ); + }; + + this.stopRename = + this.endRename = function(cancel) { + var node = this.renaming; + this.renaming = null; + this.cancel(); + this.waitForRename(); + if (!this.tree.isFocused()) + this.tree.renderer.visualizeBlur(); + + if (!node) + return; + + var val = this.ace.getValue(); + + this._destroyEditor(); + + if (!cancel && this.origVal !== val) { + this.tree._emit("rename", { + node: node, + value: val, + column: this.column + }); + this.tree.provider._signal("change"); + } + }; + +}).call(EditableTree.prototype); + +module.exports = EditableTree; +}); diff --git a/node_modules/ace_tree/lib/ace_tree/filter.js b/node_modules/ace_tree/lib/ace_tree/filter.js new file mode 100644 index 00000000..d34e978c --- /dev/null +++ b/node_modules/ace_tree/lib/ace_tree/filter.js @@ -0,0 +1,140 @@ +define(function(require, exports, module) { +"use strict"; + +var Editor = require("ace/editor").Editor; +var UndoManager = require("ace/undomanager").UndoManager; +var Renderer = require("ace/virtual_renderer").VirtualRenderer; +var lang = require("ace/lib/lang"); + +exports.treeSearch = function treeSearch(tree, keyword, caseInsensitive, results, head) { + if (caseInsensitive) + keyword = keyword.toLowerCase(); + results = results || []; + head = head || 0; + for (var i = 0; i < tree.length; i++) { + var node = tree[i]; + var name = node.name || node.label || ""; + if (caseInsensitive) + name = name.toLowerCase(); + var index = name.indexOf(keyword); + var items = node.items || node.children; + if (index === -1) { + if (items) + results = treeSearch(items, keyword, caseInsensitive, results, head); + continue; + } + var result = { + items: items ? treeSearch(items, keyword, caseInsensitive) : [] + }; + for (var p in node) { + if (node.hasOwnProperty(p) && p !== "items" && p !== "children") + result[p] = node[p]; + } + if (index === 0) { + results.splice(head, 0, result); + head++; + } + else { + results.push(result); + } + } + return results; +}; + +exports.getCaptionHTML = function(node){ + var value = node.name || node.label || ""; + + if (this.reFilter) { + var re = new RegExp("(" + this.reFilter + ")", 'i'); + value = value.replace(re, "$1"); + } + + return value; +}; + +exports.setFilter = function(str){ + if (!str && this.filterString) { + if (this.unfilteredRoot && this.unfilteredRoot != this.root) { + this.setRoot(this.unfilteredRoot); + } + } else { + if (!this.unfilteredRoot) + this.unfilteredRoot = this.root; + + var root = this.unfilteredRoot; + if (str.lastIndexOf(this.filterString, 0) == 0) + this.root = root; + + this.setRoot(exports.treeSearch(root.children, str, true)); + this.filterString = str; + this.getCaptionHTML = exports.getCaptionHTML; + } + + this.filterString = str; + this.reFilter = lang.escapeRegExp(this.filterString); +}; + + +exports.$createFilterInputBox = function(tree) { + if (!tree.filterEditor) { + tree.filterEditor = new Editor(new Renderer()); + tree.filterEditor.setOptions({ + maxLines: 1, + showGutter: false, + highlightActiveLine: false + }); + tree.filterEditor.session.setUndoManager(new UndoManager()); + + tree.filterEditor.on("input", function(e, editor) { + var val = editor.getValue(); + if (tree.provider) { + if (!tree.provider.setFilter) + tree.provider.setFilter = exports.setFilter; + tree.provider.setFilter(val); + } + if (!val) + tree.focus(); + }); + + tree.filterEditor.commands.bindKeys({ + "Return": function(editor) {tree.focus()}, + "Esc": function(editor) {editor.setValue(""); tree.focus(); } + }); + tree.on("focus", function() { + if (!tree.filterEditor.getValue()) + tree.filterEditor.hide(); + }); + tree.filterEditor.hide = function() { + if (this.container.parentNode && tree.$autoShowFilter) + this.container.parentNode.removeChild(this.container); + }; + + var forwardToTree = function() { + tree.execCommand(this.name); + }; + tree.filterEditor.commands.addCommands([ + "centerselection", + "goToStart", + "goToEnd", + "pageup", + "gotopageup", + "scrollup", + "scrolldown", + "goUp", + "goDown", + "selectUp", + "selectDown", + "selectMoreUp", + "selectMoreDown" + ].map(function(name) { + var command = tree.commands.byName[name]; + return { + name: command.name, + bindKey: command.editorKey || command.bindKey, + exec: forwardToTree + }; + })); + } +}; + +}); diff --git a/node_modules/ace_tree/lib/ace_tree/layer/cells.js b/node_modules/ace_tree/lib/ace_tree/layer/cells.js new file mode 100644 index 00000000..58721e89 --- /dev/null +++ b/node_modules/ace_tree/lib/ace_tree/layer/cells.js @@ -0,0 +1,199 @@ +define(function(require, exports, module) { +"use strict"; + +var oop = require("ace/lib/oop"); +var dom = require("ace/lib/dom"); +var lang = require("ace/lib/lang"); +var escapeHTML = lang.escapeHTML; +var EventEmitter = require("ace/lib/event_emitter").EventEmitter; + +var Cells = function(parentEl) { + this.element = dom.createElement("div"); + this.element.className = "ace_tree_layer ace_tree_cell-layer"; + parentEl.appendChild(this.element); +}; + +(function() { + + oop.implement(this, EventEmitter); + + this.config = {}, + + this.setDataProvider = function(provider) { + this.provider = provider; + if (provider) + this.update = provider.renderRow ? this.$customUpdate : this.$treeModeUpdate; + }; + + this.update = function (config) { + }; + + this.measureSizes = function() { + var domNode = this.element.firstChild; + if (domNode) { + this.provider.rowHeight = domNode.offsetHeight; + this.provider.rowHeightInner = domNode.clientHeight; + } + }; + + this.$treeModeUpdate = function (config) { + this.config = config; + + var provider = this.provider; + var row, html = [], view = config.view, datarow; + var firstRow = config.firstRow, lastRow = config.lastRow + 1; + var hsize = "auto;", vsize = provider.rowHeightInner || provider.rowHeight; + + for (row = firstRow; row < lastRow; row++) { + datarow = view[row - firstRow]; + if (provider.getItemHeight) + vsize = provider.getItemHeight(datarow, row); + this.$renderRow(html, datarow, vsize, hsize, row); + } + + if (firstRow === 0 && lastRow === 0) { + this.renderPlaceHolder(provider, html, config); + } + + this.element = dom.setInnerHtml(this.element, html.join("")); + + if (!vsize) { + this.measureSizes(); + } + }; + + this.columnNode = function(datarow, column) { + return ""; + }; + + this.getRowClass = function(datarow, row) { + var provider = this.provider; + return "tree-row " + + (provider.isSelected(datarow) ? "selected ": '') + + (provider.getClassName(datarow) || "") + (row & 1 ? " odd" : " even"); + }; + + this.$renderRow = function(html, datarow, vsize, hsize, row) { + var provider = this.provider; + var columns = provider.columns; + var indent = provider.$indentSize;// provider.getIndent(datarow); + html.push("
      "); + + if (!columns || columns[0].type == "tree") { + if (columns) { + html.push(this.columnNode(datarow, columns[0], row)); + } + var depth = provider.getRowIndent(datarow); + html.push( + (depth ? "" : "" ) + + "" + + provider.getIconHTML(datarow) + + ( provider.getContentHTML ? provider.getContentHTML(datarow) + : "" + + provider.getCaptionHTML(datarow) + + "" + ) + ); + } + if (columns) { + for (var col = columns[0].type == "tree" ? 1 : 0; col < columns.length; col++) { + html.push("" + + this.columnNode(datarow, columns[col], row) + + escapeHTML(columns[col].getText(datarow) + "")); + } + html.push(""); + } + + html.push("
      "); + }; + + this.$customUpdate = function(config) { + this.config = config; + + var provider = this.provider; + var html = []; + var firstRow = config.firstRow, lastRow = config.lastRow + 1; + + for (var row = firstRow; row < lastRow; row++) { + provider.renderRow(row, html, config); + } + + if (firstRow === 0 && lastRow === 0) { + this.renderPlaceHolder(provider, html, config); + } + + this.element = dom.setInnerHtml(this.element, html.join("")); + }; + + this.updateClasses = function(config) { + // fallback to full redraw for customUpdate + if (this.update == this.$customUpdate && !this.provider.updateNode) + return this.update(config); + + this.config = config; + + var provider = this.provider; + var row, view = config.view, datarow; + var firstRow = config.firstRow, lastRow = config.lastRow + 1; + var children = this.element.children; + + if (children.length != lastRow - firstRow) + return this.update(config); + + for (row = firstRow; row < lastRow; row++) { + datarow = view[row - firstRow]; + var el = children[row - firstRow]; + el.className = this.getRowClass(datarow, row); + if (provider.redrawNode) + provider.redrawNode(el, datarow); + } + }; + + this.scroll = function(config) { + // not implemented + return this.update(config); + + this.element.insertAdjacentHTML("afterBegin", "ar"); + this.element.insertAdjacentHTML("beforeEnd", "ar"); + }; + + this.updateRows = function(config, firstRow, lastRow) { + // not implemented + }; + + this.destroy = function() { + + }; + + this.getDomNodeAtIndex = function(i) { + return this.element.children[i - this.config.firstRow]; + }; + + this.renderPlaceHolder = function(provider, html, config) { + if (provider.renderEmptyMessage) { + provider.renderEmptyMessage(html, config); + } else if (provider.getEmptyMessage) { + html.push( + "
      ", + provider.getEmptyMessage(), + "
      " + ); + } + }; + +}).call(Cells.prototype); + +exports.Cells = Cells; + +}); diff --git a/node_modules/ace_tree/lib/ace_tree/layer/heading.js b/node_modules/ace_tree/lib/ace_tree/layer/heading.js new file mode 100644 index 00000000..d0a0f66c --- /dev/null +++ b/node_modules/ace_tree/lib/ace_tree/layer/heading.js @@ -0,0 +1,193 @@ +define(function(require, exports, module) { +"use strict"; +var oop = require("ace/lib/oop"); +var dom = require("ace/lib/dom"); +var lang = require("ace/lib/lang"); +var EventEmitter = require("ace/lib/event_emitter").EventEmitter; + +var RESIZER_WIDTH = 3; + +function getColumnText(node) { + return node[this.value] || this.defaultValue || ""; +} + +function ColumnHeader(parentEl, renderer) { + this.element = dom.createElement("div"); + parentEl.appendChild(this.element); + this.element.className = "tree-headings"; + this.visible = false; +} +(function() { + + this.minWidth = 25; + + this.update = function() { + if (!this.provider || !this.visible) + return; + var columns = this.provider.columns; + var html = []; + for (var i = 0; i < columns.length; i++) { + var col = columns[i]; + html.push("" + + col.caption + + "" + + "" + + "" + ); + } + this.element.style.paddingRight = columns.$fixedWidth; + this.element.innerHTML = html.join(""); + }; + + this.setDataProvider = function(provider) { + this.provider = provider; + if (!provider) + return; + var columns = this.provider.columns; + if (!columns) { + this.visible = false; + return; + } + this.visible = true; + var fixedWidth = 0; + + columns.forEach(function(col, i) { + col.index = i; + if (col.value && !col.getText) + col.getText = getColumnText; + var w = col.width; + if (w.slice(-1) == "%") { + col.flex = parseInt(w, 10) / 100; + col.$width = col.width; + } else { + col.width = parseInt(w, 10) || this.minWidth; + fixedWidth += col.width; + col.$width = col.width + "px"; + } + col.pixelWidth = 0; + }, this); + columns.$fixedWidth = fixedWidth + "px"; + provider.columns = columns; + }; + + this.updateWidth = function(width) { + if (!this.provider || !this.visible) + return; + + var columns = this.provider.columns; + var fixedWidth = 0; + + columns.width = width; + + + columns.forEach(function(col) { + if (!col.flex) { + fixedWidth += col.width; + } + }); + + var flexWidth = width - fixedWidth; + + columns.forEach(function(col) { + if (col.flex) { + col.pixelWidth = flexWidth * col.flex; + col.$width = col.flex * 100 + "%"; + } else { + col.pixelWidth = col.width; + col.$width = col.width + "px"; + } + }); + columns.fixedWidth = fixedWidth; + columns.$fixedWidth = fixedWidth + "px"; + }; + + this.changeColumnWidth = function(changedColumn, dw, total) { + this.updateWidth(total); + + var columns = this.provider.columns; + var minWidth = this.minWidth; + + if (!dw) + return; + + var index = columns.indexOf(changedColumn); + var col, nextCol, prevCol; + for (var i = index + 1; i < columns.length; i++) { + col = columns[i]; + if (Math.floor(col.pixelWidth) > minWidth || dw < 0) { + if (col.flex) { + nextCol = col; + break; + } else if (!nextCol) { + nextCol = col; + } + } + } + for (var i = index; i >= 0; i--) { + col = columns[i]; + if (Math.floor(col.pixelWidth) > minWidth || dw > 0) { + if (col.flex) { + prevCol = col; + break; + } else if (!prevCol) { + prevCol = col; + if (col == changedColumn) + break; + } + } + } + if (!prevCol || !nextCol) + return; + + if (nextCol.pixelWidth - dw < minWidth) + dw = nextCol.pixelWidth - minWidth; + + if (prevCol.pixelWidth + dw < minWidth) + dw = minWidth - prevCol.pixelWidth; + + nextCol.pixelWidth -= dw; + prevCol.pixelWidth += dw; + + if (!nextCol.flex) + columns.fixedWidth -= dw; + if (!prevCol.flex) + columns.fixedWidth += dw; + var flexWidth = total - columns.fixedWidth; + + columns.forEach(function(col) { + if (col.flex) { + col.flex = col.pixelWidth / flexWidth; + } else { + col.width = col.pixelWidth; + } + }); + + this.updateWidth(total); + }; + + this.findColumn = function(x) { + var columns = this.provider.columns; + if (this.element.offsetWidth != columns.width) + this.updateWidth(this.element.offsetWidth); + var w = 0; + for (var i = 0; i < columns.length; i++) { + var column = columns[i]; + w += column.pixelWidth; + if (x < w + RESIZER_WIDTH) { + return { + index: i, + column: column, + overResizer: x > w - RESIZER_WIDTH + }; + } + } + }; + +}).call(ColumnHeader.prototype); + + +exports.ColumnHeader = ColumnHeader; + +}); diff --git a/node_modules/ace_tree/lib/ace_tree/layer/markers.js b/node_modules/ace_tree/lib/ace_tree/layer/markers.js new file mode 100644 index 00000000..e6c22f18 --- /dev/null +++ b/node_modules/ace_tree/lib/ace_tree/layer/markers.js @@ -0,0 +1,153 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var dom = require("ace/lib/dom"); + +var Selection = function(parentEl, renderer) { + this.element = dom.createElement("div"); + this.element.className = "ace_tree_layer ace_tree_selection-layer"; + parentEl.appendChild(this.element); + + this.renderer = renderer; + this.markerEl = null; + this.arrowEl = null; +}; + +(function() { + + this.setDataProvider = function(provider) { + this.provider = provider; + }; + + this.update = function(config) { + // markedFolderType: 0: folder, -1: before, 1: after + if (!this.provider.markedFolder || this.provider.markedFolderType) { + this.markerEl && this.clearFolderMarker(); + } else { + this.showFolderMarker(config); + } + + if (!this.provider.markedFolder || !this.provider.markedFolderType) { + this.arrowEl && this.clearInsertionMarker(); + } else { + this.showInsertionMarker(config); + } + }; + + this.showFolderMarker = function(config) { + this.config = config; + var provider = this.provider; + var node = provider.markedFolder; + + var start = provider.getIndexForNode(node); + var items = provider.visibleItems; + var end = start + 1; + var depth = node.$depth; + while (items[end] && items[end].$depth > depth) { + end++; + } + end --; + + if (start > config.lastRow || end < config.firstRow || start === end) { + return this.clearFolderMarker(); + } + start++; + end++; + var top = Math.max(start - config.firstRow, - 1) * provider.rowHeight; + var left = (depth + 1) * provider.$indentSize; + var bottom = Math.min(end - config.firstRow, config.lastRow - config.firstRow + 2) * provider.rowHeight; + + if (!this.markerEl) { + this.markerEl = dom.createElement("div"); + this.markerEl.className = "dragHighlight"; + this.element.appendChild(this.markerEl); + } + this.markerEl.style.top = top + "px"; + this.markerEl.style.left = left + "px"; + this.markerEl.style.right = "7px"; + this.markerEl.style.height = bottom - top + "px"; + }; + this.showInsertionMarker = function(config) { + this.config = config; + var provider = this.provider; + var node = provider.markedFolder; + + var type = this.provider.markedFolderType; + + var start = provider.getIndexForNode(node); + var depth = node.$depth; + + if (start > config.lastRow || start < config.firstRow) { + return this.clearInsertionMarker(); + } + + if (type == 1) + start++; + + var top = Math.max(start - config.firstRow, - 1) * provider.rowHeight; + var left = (depth + 1) * provider.$indentSize; + + if (!this.arrowEl) { + this.arrowEl = dom.createElement("div"); + this.arrowEl.className = "dragArrow"; + this.element.appendChild(this.arrowEl); + } + this.arrowEl.style.top = top + "px"; + this.arrowEl.style.left = left + "px"; + this.arrowEl.style.right = "7px"; + }; + this.clearFolderMarker = function() { + if (this.markerEl) { + this.markerEl.parentNode.removeChild(this.markerEl); + this.markerEl = null; + } + }; + this.clearInsertionMarker = function() { + if (this.arrowEl) { + this.arrowEl.parentNode.removeChild(this.arrowEl); + this.arrowEl = null; + } + }; + this.clear = function() { + this.clearFolderMarker(); + this.clearInsertMarker(); + }; + this.destroy = function() { + + }; + +}).call(Selection.prototype); + +exports.Selection = Selection; + +}); diff --git a/node_modules/ace_tree/lib/ace_tree/lib/btree.js b/node_modules/ace_tree/lib/ace_tree/lib/btree.js new file mode 100644 index 00000000..763e29b3 --- /dev/null +++ b/node_modules/ace_tree/lib/ace_tree/lib/btree.js @@ -0,0 +1,501 @@ +define(function(require, exports, module) { + +function BTree(maxChilds){ + this.maxChilds = maxChilds; + this.minChilds = Math.floor(maxChilds / 2); + + this.root = []; +} +BTree.prototype = { + get length() { + return this.root.count; + }, + + get size() { + return this.root.size; + }, + + /** + * Loads a data set efficiently into the tree + */ + load : function(data){ + var btree = this; + btree.root = null; + + function checkParents(nodes){ + var p, c; + if (nodes.length == max + 1) { //instead of .length it could calc based on i + if (!nodes.parent) { + c = nodes.pop(); + nodes.count -= c.count; //this could be optimized to not set and unset this + nodes.size -= c.size; //this could be optimized to not set and unset this + p = nodes.parent = btree.root = [nodes, c]; + c.parent = p; + p.size = nodes.size + c.size; + p.count = nodes.count + c.count; + p.push(nodes = []); + nodes.count = nodes.size = 0; + } + else { + c = nodes.pop(); + nodes.count -= c.count; //this could be optimized to not set and unset this + nodes.size -= c.size; //this could be optimized to not set and unset this + p = nodes.parent; + p.size += nodes.size + c.size; + p.count += nodes.count + c.count; + p.push(c, nodes = []); + c.parent = p; + nodes.count = nodes.size = 0; + checkParents(p); + } + nodes.parent = p; + } + return nodes; + } + + var leaf = [], leafs = [leaf], max = this.maxChilds; + leafs.size = leafs.count = leaf.size = leaf.count = 0; + leaf.parent = leafs; + for (var d, i = 0, l = data.length; i < l; i++) { + d = data[i]; + d.count = 1; + + if ((i + 1) % (max + 1) === 0) { + leafs.push(d); + d.parent = leafs; + leafs.size += leaf.size + d.size; + leafs.count += leaf.count + d.count; //always 1 + + if ((i / (max + 1)) % (max + 1)) + leafs = checkParents(leafs); + + leafs.push(leaf = []); + leaf.parent = leafs; + leaf.size = leaf.count = 0; + } + else { + leaf.push(d); + d.parent = leaf; + leaf.size += d.size; + leaf.count += d.count; + } + } + + if (leaf.length) { + var p = leaf; + do { + p.parent.count += p.count; + p.parent.size += p.size; + } while((p = p.parent).parent); + } + + if (!btree.root) + btree.root = leafs; + }, + + /** + * + */ + loadHumongousSet : function(count, size){ + var billion = 1000000000; + var parts = Math.ceil(count / billion); + if (parts > this.maxChilds) + throw new Error("Exceeded maximum size of 25 billion"); + + if (parts > 1) { + this.root = []; + for (var n, i = 0; i < parts - 1; i++) { + this.root.push(n = Array(billion)); + n.size = billion * size; + n.count = billion; + n.parent = this.root; + } + var last = count % billion || billion; + this.root.push(n = Array(last)); + n.size = last * size; + n.count = last; + n.parent = this.root; + } + else { + this.root = [Array(count)]; + this.root[0].size = size * count; + this.root[0].count = count; + this.root[0].parent = this.root; + } + + this.defaultSize = size; + + this.root.size = size * count; + this.root.count = count; + }, + + /** + * Add an object to the tree + * @param afterIndex {Number} the index of the node to insert after. Null to append as last child. + * @param size {Number} the size of the node (usually stands for pixels) + * @param value {Mixed} the value of the node + */ + add : function(afterIndex, size, value){ + if (typeof size != "number" || isNaN(size)) + throw new Error("Incorrect size specified: " + size); + + // Find parent + var after = (afterIndex + ? this.findNodeByIndex(afterIndex) + : this.findLastNode()); + var parent = after.parent || this.root; + + // Add new leaf node + var node = {}; + node.size = size; + node.value = value; + node.count = 1; + node.parent = parent; + + if (!afterIndex) + parent.push(node); + else { + var idx = parent.indexOf(idx) + 1; + idx && parent.splice(idx, 0, node) || parent.push(node); + } + + this.checkParents(parent); + }, + + checkParents : function(parent){ + // Update a set + function update(parent){ + var total = 0, count = 0; + for (var i = 0; i < parent.length; i++) { + total += parent[i].size; + count += parent[i].count; + parent[i].parent = parent; + } + parent.size = total; + parent.count = count; + } + + var max = this.maxChilds, min = this.minChilds, btree = this; + (function recur(parent) { + // End of recursion + if (!parent){ + return; + } + + // There is still room + else if (parent.length <= max) { + update(parent); + recur(parent.parent); + } + + // Split the parent into two nodes + else { + var right = parent.splice(min + 1); + var median = parent.pop(); + + // Update left set + update(parent); + + // Update right set + update(right); + + // Find grandpa or create a new root + var grandpa = parent.parent || (btree.root = [parent]); + + // Insert new children in grandpa + var idx = grandpa.indexOf(parent); + grandpa.splice(idx + 1, 0, median, right); + + // Check if grandpa needs to be split + recur(grandpa); + } + })(parent); + }, + + /** + * Updates the size of nodes + */ + updateNodes : function(nodes){ + var n, p, i, l, parents = [], right, grandpa, idx, empty = []; + + for (n, p, i = nodes.length - 1; i >= 0; i--) { + n = nodes[i]; + if (n.empty) { + right = n.parent.splice(n.index); + right.shift(); + + n.parent.count = n.parent.length; + n.parent.size = n.parent.length * this.defaultSize; + + grandpa = n.parent.parent; + idx = grandpa.indexOf(n.parent); + + var args = [idx + (n.parent.length ? 1 : 0), n.parent.length ? 0 : 1, n]; + if (right.length) { + args.push(right); + + right.count = right.length; + right.size = right.length * this.defaultSize; + } + grandpa.splice.apply(grandpa, args); + + delete n.index; + delete n.empty; + + if (empty.indexOf(grandpa) == -1) + empty.push(grandpa); + + continue; + } + + p = n.parent; + if (parents.indexOf(p) == -1) + parents.push(p); + } + + for (i = 0, l = empty.length; i < l; i++) { + this.checkParents(empty[i]); //@todo this could be done more efficiently + } + + var size, count; + for (i = 0, l = parents.length; i < l; i++) { + p = parents[i]; + + do { + size = 0, count = 0; + for (var j = 0, lj = p.length; j < lj; j++) { + size += p[j].size; + count += p[j].count; + } + p.size = size; + p.count = count; + } while((p = p.parent)); + } + }, + + remove : function(index){ + + }, + + findSizeAtIndex : function(index){ + var count = 0, size = 0; + + var defSize = this.defaultSize; + return (function recur(node){ + for (var n, i = 0, l = node.length; i < l; i++) { + if ((n = node[i]).count + count > index) { + if (n.length) { + // Empty set + if (!n[0]) { + size += (index - count) * defSize; + return size; + } + // Find in filled set + return recur(n); + } + else return size; + } + else { + count += n.count; + size += n.size; + } + } + })(this.root); + }, + + /** + * Returns an array of nodes that are within the viewport specified + * @todo should return the start index of the first node as well + */ + getRange : function(start, end, compIndex){ + if (!this.root.length) return false; + + var count = 0, size = 0, nodes = [], found, fsize, fcount; + + var defSize = this.defaultSize; + (function recur(node){ + var n, i, l; + + if (!node[0]) { + i = found ? 0 : (compIndex + ? start - count + : Math.floor((start - size) / defSize)); + + var offset = compIndex ? end - count : end - size; + + if (i !== 0) { + size += i * defSize; + count += i; + } + + l = compIndex + ? Math.min(node.length, offset + (found ? 0 : start - count)) + : Math.min(node.length, Math.ceil((offset + (found ? 0 : start - size)) / defSize)); + + // It's in this set + if (node.length >= i + 1) { + for (;i < l; i++) { + nodes.push({ + size : defSize, + empty : true, + parent : node, + count : 1, + index : i + }); + + if (!found) { + fcount = count; + fsize = size;// + (i * defSize); + found = true; + } + + size += defSize; + count += 1; + } + return; + } + else { + return; + } + } + + for (i = 0, l = node.length; i < l; i++) { + if (compIndex ? count >= end : size >= end) + return; + + n = node[i]; + // Empty set + if (found || (compIndex ? n.count + count : n.size + size) >= start) { + if (n.length) { + recur(n); + continue; + } + + nodes.push(n); + + if (!found) { + fcount = count; + fsize = size; + found = true; + } + } + + size += n.size; + count += n.count; + } + })(this.root); + + nodes.size = fsize || 0; + nodes.count = fcount || 0; + + return nodes; + }, + + /** + * Returns the node at some arbitrary total position + * @param start {Number} the start position from where to find the node + */ + findNodeAtStart : function(start){ + var size = 0; + + var defSize = this.defaultSize; + return (function recur(node){ + for (var n, i = 0, l = node.length; i < l; i++) { + if ((n = node[i]).size + size > start) { + if (n.length) { + // Empty set + if (!n[0]) { + return { + size : defSize, + empty : true, + count : 1, + parent : n, + index : Math.ceil((start - size) / defSize) - 1 + }; + } + return recur(n); + } + else return n; + } + else + size += n.size; + } + })(this.root); + }, + + /** + * Returns the node at some index + * @param index {Number} the zero based index of the node, calculated sequentially. + */ + findNodeByIndex : function(index){ + var count = 0; + + var defSize = this.defaultSize; + return (function recur(node){ + for (var n, i = 0, l = node.length; i < l; i++) { + if ((n = node[i]).count + count > index) { + if (n.length) { + // Empty set + if (!n[0]) { + return { + size : defSize, + empty : true, + count : 1, + parent : n, + index : index - count - 1 + }; + } + // Find in filled set + return recur(n); + } + else return n; + } + else + count += n.count; + } + })(this.root); + }, + + /** + * Returns the last node in the tree, sequentially + */ + findLastNode : function(){ + return (function recur(node){ + if (node.length) return recur(node[node.length - 1]); + else return node; + })(this.root); + }, + + /** + * Returns the first node in the tree, sequentially + */ + findFirstNode : function(){ + return (function recur(node){ + if (node.length) return recur(node[0]); + else return node; + })(this.root); + }, + + /** + * Return an array of all objects in tree, sequentially. + * Each object has a size and value property + */ + toArray : function(){ + var list = []; + + (function recur(node){ + for (var n, i = 0, l = node.length; i < l; i++) { + if ((n = node[i]).length) + recur(n); + else + list.push({size: n.size, value: n.value}); + } + })(this.root); + + return list; + } +}; + +module.exports = BTree; + +}); \ No newline at end of file diff --git a/node_modules/ace_tree/lib/ace_tree/lib/btree_test.js b/node_modules/ace_tree/lib/ace_tree/lib/btree_test.js new file mode 100644 index 00000000..2ca1b55e --- /dev/null +++ b/node_modules/ace_tree/lib/ace_tree/lib/btree_test.js @@ -0,0 +1,266 @@ +/*global describe it before */ + +var isBrowser = true; +if (typeof module !== "undefined") { + var isBrowser = false; + require("amd-loader"); +} + +define(function(require, exports, module) { + "use strict"; + + var expect = (isBrowser ? require("../../node_modules/chai/chai") : global["require"]("chai")).expect; + var BTree = isBrowser ? require("./btree") : global["require"]("experiments/btree"); + + describe("BTree", function(){ + var btree, expected = [], data; + before(function(done){ + btree = new BTree(25); + done(); + }); + + describe("add()", function(){ + it('should add a single node to the tree', function(done) { + btree.add(null, 90, {"root": 1}); + + expected.push({size: 90, value: {"root": 1}}); + expect(btree.toArray()).deep.equal(expected); + done(); + }); + it('should add a multiple nodes to the tree and create a new level', function(done) { + var size; + for (var i = 0; i < 25; i++) { + size = Math.round(90 * Math.random()); + btree.add(null, size, {"first": i}); + expected.push({size: size, value: {"first": i}}); + } + + expect(btree.toArray()).deep.equal(expected); + done(); + }); + it('should add create more levels as each time the max nodes is reached', function(done) { + var size; + for (var i = 0; i < 150; i++) { + size = Math.round(90 * Math.random()); + btree.add(null, size, {"second": i}); + expected.push({size: size, value: {"second": i}}); + } + + expect(btree.toArray()).deep.equal(expected); + done(); + }); + }); + describe("findNodeAtStart(), findNodeByIndex()", function() { + it('should find a node based on a start position', function(done) { + var node = btree.findNodeAtStart(0); + expect(node.value, "node at 0px").to.deep.equal(expected[0].value); + + node = btree.findNodeAtStart(80); + expect(node.value, "node at 80px").to.deep.equal(expected[0].value); + + node = btree.findNodeAtStart(500); + var total = 0, found, i = 0; do { + found = expected[i]; + total += expected[i++].size; + } while(total < 500); + expect(node.value, "node at 500px").to.deep.equal(found.value); + + total = 0, found, i = 0; do { + total += expected[i++].size; + found = expected[i]; + } while(i == 100); + node = btree.findNodeAtStart(total); + expect(node.value, "node at 500px").to.deep.equal(found.value); + + done(); + }); + it('should find a node based on an index', function(done) { + var node = btree.findNodeByIndex(0); + expect(node.value, "node at index 0").to.deep.equal(expected[0].value); + + node = btree.findNodeByIndex(80); + expect(node.value, "node at index 80").to.deep.equal(expected[80].value); + done(); + }); + }); + describe("load()", function() { + it('should load 10 records', function(done) { + expected = [], data = []; + for (var size, i = 0; i < 10; i++) { + size = Math.round(90 * Math.random()); + expected.push({size: size, value: {"first": i}}); + data.push({size: size, value: {"first": i}}); + } + + btree.load(data); + expect(btree.toArray()).to.deep.equal(expected); + expect(btree.root.count).equal(10); + done(); + }); + it('should load 100 records', function(done) { + expected = [], data = []; + for (var size, i = 0; i < 100; i++) { + size = Math.round(90 * Math.random()); + expected.push({size: size, value: {"first": i}}); + data.push({size: size, value: {"first": i}}); + } + + btree.load(data); + expect(btree.toArray()).to.deep.equal(expected); + expect(btree.root.count).equal(100); + done(); + }); + it('should load 1000 records', function(done) { + expected = [], data = []; + for (var size, i = 0; i < 1000; i++) { + size = Math.round(90 * Math.random()); + expected.push({size: size, value: {"first": i}}); + data.push({size: size, value: {"first": i}}); + } + + btree.load(data); + expect(btree.toArray()).to.deep.equal(expected); + expect(btree.root.count).equal(1000); + done(); + }); + it('should find a node based on a start position', function(done) { + var node = btree.findNodeAtStart(0); + expect(node.value, "node at 0px").to.deep.equal(expected[0].value); + + node = btree.findNodeAtStart(500); + var total = 0, found, i = 0; do { + found = expected[i]; + total += expected[i++].size; + } while(total < 500); + expect(node.value, "node at 500px").to.deep.equal(found.value); + + total = 0, found, i = 0; do { + total += expected[i++].size; + found = expected[i]; + } while(i == 100); + node = btree.findNodeAtStart(total); + expect(node.value, "node at 500px").to.deep.equal(found.value); + + done(); + }); + it('should find a node based on an index', function(done) { + var node = btree.findNodeByIndex(0); + expect(node.value, "node at index 0").to.deep.equal(expected[0].value); + + node = btree.findNodeByIndex(800); + expect(node.value, "node at index 800").to.deep.equal(expected[800].value); + done(); + }); + }); + + function getRange(start, end){ + var total = 0, nodes = [], i = 0; do { + total += expected[i].size; + if (total > start) + nodes.push(expected[i]); + i++; + } while(total < end); + + return nodes; + } + + describe("getRange()", function() { + it('should return nodes within a viewport starting at 0', function(done) { + var nodes = btree.getRange(0, 500); + var range = getRange(0, 500); + + expect(nodes, "length").length(range.length); + expect(nodes[0].value, "first").deep.equal(range[0].value); + expect(nodes[nodes.length - 1].value, "last").deep.equal(range[range.length - 1].value); + done(); + }); + it('should return nodes within a viewport starting at 4000', function(done) { + var nodes = btree.getRange(4000, 5600); + var range = getRange(4000, 5600); + + expect(nodes, "length").length(range.length); + expect(nodes[0].value, "first").deep.equal(range[0].value); + expect(nodes[nodes.length - 1].value, "last").deep.equal(range[range.length - 1].value); + done(); + }); + }); + describe("updateNodes()", function() { + /* + @todo + - remove left node + - remove right node + - remove node in the middle + + same, but with 2 nodes in the middle + + for humongous set and normal set and mixed + */ + it('should update a set of nodes', function(done) { + var viewport = btree.getRange(3000, 5000); + + var start = Math.round(viewport.length / 4); + var end = Math.round(viewport.length * 3 / 4); + + var changed = []; + for (var node, i = start; i < end; i++) { + node = viewport[i]; + node.oldsize = node.size; + node.size = 0; + changed.push(node); + }; + + btree.updateNodes(changed); + + var viewport2 = btree.getRange(3000, 5000); + expect(viewport2.length).gt(viewport.length); + done(); + }); + }); + describe("Scalability Tests", function() { + it('should load 25 billion records', function(done) { + btree.loadHumongousSet(25000000000, 90); + + expect(btree.root.count).equal(25000000000); + expect(btree.root.size).equal(25000000000 * 90); + done(); + }); + it('should update a set of nodes', function(done) { + var viewport = btree.getRange(3000, 5000); + + viewport.forEach(function(n){ + expect(n).not.instanceOf(Array); + }); + + var start = Math.round(viewport.length / 4); + var end = Math.round(viewport.length * 3 / 4); + + var changed = []; + for (var node, i = start; i < end; i++) { + node = viewport[i]; + node.oldsize = node.size; + node.size = 0; + changed.push(node); + }; + btree.updateNodes(changed); + + var viewport2 = btree.getRange(3000, 5000); + + viewport2.forEach(function(n){ + expect(n).not.instanceOf(Array); + }); + + expect(viewport2.length).gt(viewport.length); + expect(btree.root.count).equal(25000000000); + expect(btree.root.size).equal((25000000000 - changed.length) * 90); + + done(); + }); + }); + }); + + (typeof onload == "function") && onload(); +}); + +// if (typeof module !== "undefined" && module === require.main) { +// mocha.run(); +// } \ No newline at end of file diff --git a/node_modules/ace_tree/lib/ace_tree/list_data.js b/node_modules/ace_tree/lib/ace_tree/list_data.js new file mode 100644 index 00000000..8ad69208 --- /dev/null +++ b/node_modules/ace_tree/lib/ace_tree/list_data.js @@ -0,0 +1,85 @@ +define(function(require, exports, module) { +"use strict"; + +var oop = require("ace/lib/oop"); +var DataProvider = require("./data_provider"); + +var ListData = function(array) { + this.visibleItems = array || []; + this._selectStore = Object.create(null); +}; + +oop.inherits(ListData, DataProvider); + +(function() { + + this.getDataRange = function(rows, columns, callback) { + var view = this.visibleItems.slice(rows.start, rows.start + rows.length); + callback(null, view, false); + return view; + }; + + this.getRange = function(top, bottom) { + var start = Math.floor(top / this.rowHeight); + var end = Math.ceil(bottom / this.rowHeight) + 1; + var range = this.visibleItems.slice(start, end); + range.count = start; + range.size = this.rowHeight * range.count; + return range; + }; + + this.getTotalHeight = function(top, bottom) { + return this.rowHeight * this.visibleItems.length; + }; + + this.getNodePosition = function(node) { + var i = node ? node.index : 0; + var top = i * this.rowHeight; + var height = this.rowHeight; + return {top: top, height: height}; + }; + + this.findItemAtOffset = function(offset) { + var index = Math.floor(offset / this.rowHeight); + return this.getNodeAtIndex(index); + }; + this.getNodeAtIndex = function(index) { + var id = this.visibleItems[index]; + return this._selectStore[id] || { + id: id, + index: index, + isSelected: this.isSelected(id) + }; + }; + + this.getIndexForNode = function(node) { + if (typeof node == "string") + return this.visibleItems.indexOf(node); + if (!node) + return -1; + if (this.visibleItems[node.index] === node.id) + return node.index; + return this.visibleItems.indexOf(node.id); + }; + + this.isSelected = function(node) { + if (typeof node == "object") + var id = node.id; + else if (typeof node == "number") + var id = this.visibleItems[node]; + else + var id = node; + return !!this._selectStore[id]; + }; + this.setSelected = function(node, val) { + if (val) + this._selectStore[node.id] = node; + else + delete this._selectStore[node.id]; + node.isSelected = val; + }; + +}).call(ListData.prototype); + +return ListData; +}); \ No newline at end of file diff --git a/node_modules/ace_tree/lib/ace_tree/mouse/default_handlers.js b/node_modules/ace_tree/lib/ace_tree/mouse/default_handlers.js new file mode 100644 index 00000000..9f0043d1 --- /dev/null +++ b/node_modules/ace_tree/lib/ace_tree/mouse/default_handlers.js @@ -0,0 +1,253 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var dom = require("ace/lib/dom"); + +var DRAG_OFFSET = 5; // pixels +function DefaultHandlers(mouseHandler) { + mouseHandler.$clickSelection = null; + + var editor = mouseHandler.editor; + editor.setDefaultHandler("mousedown", this.onMouseDown.bind(mouseHandler)); + editor.setDefaultHandler("dblclick", this.onDoubleClick.bind(mouseHandler)); + // editor.setDefaultHandler("tripleclick", this.onTripleClick.bind(mouseHandler)); + // editor.setDefaultHandler("quadclick", this.onQuadClick.bind(mouseHandler)); + editor.setDefaultHandler("mouseleave", this.onMouseLeave.bind(mouseHandler)); + editor.setDefaultHandler("mousemove", this.onMouseMove.bind(mouseHandler)); + editor.setDefaultHandler("mousewheel", this.onMouseWheel.bind(mouseHandler)); + editor.setDefaultHandler("mouseup", this.onMouseUp.bind(mouseHandler)); + editor.setDefaultHandler("click", this.onClick.bind(mouseHandler)); + + var exports = ["dragMoveSelection", "dragWait", "dragWaitEnd", "getRegion", "updateHoverState"]; + + exports.forEach(function(x) { + mouseHandler[x] = this[x]; + }, this); +} + +(function() { + + function isTogglerClick(target) { + return dom.hasCssClass(target, "toggler") && !dom.hasCssClass(target, "empty"); + } + + this.onMouseMove = function(e) { + var editor = this.editor; + var node = e.getNode(); + + var title; + if (!node) { + title = ""; + } else if (editor.provider.columns) { + var pos = e.getDocumentPosition(); + var columnData = editor.renderer.$headingLayer.findColumn(pos.x); + title = columnData ? columnData.column.getText(node) : ""; + } else { + title = editor.provider.getText(node); + } + + if (editor.container.title != title) + editor.container.title = title; + this.updateHoverState(node); + }; + + this.onMouseLeave = function() { + this.updateHoverState(null); + }; + + this.updateHoverState = function(node) { + var provider = this.editor.provider; + if (node !== this.node && provider) { + if (this.node) + provider.setClass(this.node, "hover", false); + this.node = node; + if (this.node) + provider.setClass(this.node, "hover", true); + } + }; + + this.onMouseDown = function(ev) { + var editor = this.editor; + var provider = editor.provider; + + ev.detail = 1; + this.mousedownEvent = ev; + this.delayedSelect = false; + this.isMousePressed = true; + + var button = ev.getButton(); + var selectedNodes = editor.selection.getSelectedNodes(); + var isMultiSelect = selectedNodes.length > 1; + if (button !== 0 && isMultiSelect) { + return; // stopping event here breaks contextmenu on ff mac + } + + var node = ev.getNode(); + this.$clickNode = node; + if (!node) return; // Click outside cells + + var inSelection = provider.isSelected(node); + + var target = ev.domEvent.target; + this.region = null; + if (isTogglerClick(target) || node.clickAction == "toggle") { + this.region = "toggler"; + var toggleChildren = ev.getShiftKey(); + var deep = ev.getAccelKey(); + if (button === 0) { + if (toggleChildren) { + if (deep) { + node = node.parent; + } + provider.close(node, true); + provider.open(node); + } else { + provider.toggleNode(node, deep); + } + } + this.$clickNode = null; + } else if (dom.hasCssClass(target, "icon-ok")) { + if (ev.getShiftKey()) { + editor.selection.expandSelection(node, null, true); + } else { + editor.selection.toggleSelect(node); + } + } else if (ev.getAccelKey()) { + if (isMultiSelect && inSelection) + this.delayedSelect = "toggle"; + else + editor.selection.toggleSelect(node); + } else if (ev.getShiftKey()) { + editor.selection.expandSelection(node); + } else if (inSelection && isMultiSelect) { + if (!editor.isFocused()) + this.$clickNode = null; + else + this.delayedSelect = true; + } else { + editor.selection.setSelection(node); + } + if (this.$clickNode) + editor.$mouseHandler.captureMouse(ev, "dragWait"); + + return ev.preventDefault(); + }; + + this.onMouseUp = function(ev) { + var pos = ev.getDocumentPosition(); + var node = this.editor.provider.findItemAtOffset(pos.y); + if (node && this.$clickNode && this.$clickNode == node) { + ev.button = ev.getButton(); + ev.target = ev.domEvent.target; + ev.detail = this.mousedownEvent.detail; + this.onMouseEvent("click", ev); + } + this.$clickNode = this.mouseEvent = null; + }; + + this.onClick = function(ev) { + if (this.mousedownEvent.detail === 2) { + this.editor._emit("afterChoose"); + } + }; + + this.onDoubleClick = function(ev) { + var provider = this.editor.provider; + if (provider.toggleNode && !isTogglerClick(ev.domEvent.target)) { + var node = ev.getNode(); + if (node) + provider.toggleNode(node); + } + if (this.mousedownEvent) + this.mousedownEvent.detail = 2; + }; + + this.dragMoveSelection = function() { + var editor = this.editor; + var ev = this.mouseEvent; + ev.$pos = ev.node = null; + var node = ev.getNode(true); + if (node != editor.selection.getCursor() && node) { + if (ev.getShiftKey()) { + editor.selection.expandSelection(node, null, true); + } else { + editor.selection.selectNode(node); + } + editor.renderer.scrollCaretIntoView(); + } + }; + + this.dragWait = function() { + var ev = this.mousedownEvent; + if (Math.abs(this.x - ev.x) + Math.abs(this.y - ev.y) > DRAG_OFFSET) { + this.delayedSelect = false; + this.editor._emit("startDrag", ev); + if (this.state == "dragWait" && ev.getButton() === 0) + this.setState("dragMoveSelection"); + } + }; + + this.dragWaitEnd = function() { + if (this.delayedSelect) { + var selection = this.editor.selection; + if (this.$clickNode) { + if (this.delayedSelect == "toggle") + selection.toggleSelect(this.$clickNode); + else + selection.setSelection(this.$clickNode); + } + this.delayedSelect = false; + } + }; + + + this.onMouseWheel = function(ev) { + if (ev.getShiftKey() || ev.getAccelKey()) + return; + var t = ev.domEvent.timeStamp; + var dt = t - (this.$lastScrollTime || 0); + + var editor = this.editor; + var isScrolable = editor.renderer.isScrollableBy(ev.wheelX * ev.speed, ev.wheelY * ev.speed); + if (isScrolable || dt < 200) { + this.$lastScrollTime = t; + editor.renderer.scrollBy(ev.wheelX * ev.speed, ev.wheelY * ev.speed); + return ev.stop(); + } + }; + +}).call(DefaultHandlers.prototype); + +exports.DefaultHandlers = DefaultHandlers; + +}); diff --git a/node_modules/ace_tree/lib/ace_tree/mouse/drag_handler.js b/node_modules/ace_tree/lib/ace_tree/mouse/drag_handler.js new file mode 100644 index 00000000..c4d15cec --- /dev/null +++ b/node_modules/ace_tree/lib/ace_tree/mouse/drag_handler.js @@ -0,0 +1,293 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var event = require("ace/lib/event"); +var useragent = require("ace/lib/useragent"); +var DefaultHandlers = require("./default_handlers").DefaultHandlers; +var MouseEvent = require("./mouse_event").MouseEvent; +var config = require("../config"); +var dom = require("ace/lib/dom"); + +function initDragHandlers(mouseHandler) { + var tree = mouseHandler.editor; + var UNFOLD_TIMEOUT = 500; + var WIDGET_UNFOLD_TIMEOUT = 500; + var AUTOSCROLL_DELAY = 300; + var MIN_DRAG_T = 500; + var dragInfo, x, y, dx, dy; + var scrollerRect; + + mouseHandler.drag = function() { + var ev = this.mouseEvent; + if (!dragInfo || !ev) return; + var node = ev.getNode(); + dx = ev.x - x; + dy = ev.y - y; + x = ev.x; + y = ev.y; + var isInTree = isInRect(x, y, scrollerRect); + if (!isInTree) { + node = null; + } + + if (dragInfo.isInTree != isInTree && dragInfo.selectedNodes) { + dragInfo.isInTree = isInTree; + ev.dragInfo = dragInfo; + tree._signal(isInTree ? "dragIn" : "dragOut" , ev); + } + if (!isInTree) { + ev.dragInfo = dragInfo; + tree._signal("dragMoveOutside", ev); + } + + if (dragInfo.el) { + dragInfo.el.style.top = ev.y - dragInfo.offsetY + "px"; + dragInfo.el.style.left = ev.x - dragInfo.offsetX + "px"; + } + + var hoverNode = node; + if (hoverNode) { + var xOffset = x - scrollerRect.left; + + var depth = Math.max(0, Math.floor(xOffset / tree.provider.$indentSize)); + var depthDiff = hoverNode.$depth - depth; + while (depthDiff > 0 && hoverNode.parent) { + depthDiff--; + hoverNode = hoverNode.parent; + } + + if (!hoverNode.isFolder && dragInfo.mode != "sort") { + hoverNode = hoverNode.parent; + } + } + + if (dragInfo.hoverNode !== hoverNode) { + if (dragInfo.hoverNode) { + tree.provider.setClass(dragInfo.hoverNode, "dropTarget", false); + tree._signal("folderDragLeave", dragInfo); + } + if (hoverNode && dragInfo.selectedNodes && dragInfo.selectedNodes.indexOf(hoverNode) != -1) { + hoverNode = null; + } + dragInfo.hoverNode = hoverNode; + if (dragInfo.hoverNode) { + tree._signal("folderDragEnter", dragInfo); + if (dragInfo.mode !== "sort") + tree.provider.setClass(dragInfo.hoverNode, "dropTarget", true); + } + highlightFolder(tree, dragInfo.hoverNode, dragInfo.insertPos); + } + + var now = Date.now(); + + var target = ev.domEvent.target; + var isFoldWidget = target && (dom.hasCssClass(target, "toggler") + && !dom.hasCssClass(target, "empty")); + + var distance = Math.abs(dx) + Math.abs(dy); + + var pos = ev.y - scrollerRect.top; + var rowHeight = tree.provider.rowHeight; + var renderer = tree.renderer; + var autoScrollMargin = 1.5 * rowHeight; + var scroll = pos - autoScrollMargin; + if (scroll > 0) { + scroll += -renderer.$size.scrollerHeight + 2 * autoScrollMargin; + if (scroll < 0) + scroll = 0; + } + if (!scroll || !isInTree) + dragInfo.autoScroll = false; + + if (distance <= 2) { + if (!dragInfo.stopTime) + dragInfo.stopTime = now; + } else { + if (!isFoldWidget) + dragInfo.stopTime = undefined; + } + var dt = now - dragInfo.stopTime; + + if (scroll && isInTree) { + if (dt > AUTOSCROLL_DELAY || dragInfo.autoScroll) { + tree.renderer.scrollBy(0, scroll / 2); + dragInfo.autoScroll = true; + } + } + else if (node && dragInfo.mode === "move") { + if (node.parent === tree.provider.root || node.isRoot || node.parent && node.parent.isRoot) + isFoldWidget = false; + + if (isFoldWidget && dt > WIDGET_UNFOLD_TIMEOUT && dt < 2 * WIDGET_UNFOLD_TIMEOUT) { + tree.provider.toggleNode(node); + dragInfo.stopTime = Infinity; + } + else if (!isFoldWidget && dt > UNFOLD_TIMEOUT && dt < 2 * UNFOLD_TIMEOUT) { + tree.provider.open(node); + dragInfo.stopTime = Infinity; + } + } + }; + + mouseHandler.dragEnd = function(e, cancel) { + if (dragInfo) { + window.removeEventListener("keydown", keyHandler, true); + window.removeEventListener("keyup", keyHandler, true); + if (dragInfo.el && dragInfo.el.parentNode) + dragInfo.el.parentNode.removeChild(dragInfo.el); + if (dragInfo.hoverNode) { + tree.provider.setClass(dragInfo.hoverNode, "dropTarget", false); + tree._signal("folderDragLeave", dragInfo); + } + highlightFolder(tree, null); + + if (tree.isFocused()) + tree.renderer.visualizeFocus(); + tree.renderer.setStyle("ace_tree_DragOver", false); + + dragInfo.target = dragInfo.hoverNode; + + if (!cancel && dragInfo.selectedNodes && Date.now() - dragInfo.startT > MIN_DRAG_T) + tree._emit("drop", dragInfo); + + if (!dragInfo.isInTree) { + if (cancel) + dragInfo.selectedNodes = null; + tree._signal("dropOutside" , {dragInfo: dragInfo}); + } + dragInfo = null; + } + }; + + mouseHandler.dragStart = function() { + mouseHandler.setState("drag"); + tree.renderer.visualizeBlur(); + tree.renderer.setStyle("ace_tree_DragOver", true); + scrollerRect = tree.renderer.scroller.getBoundingClientRect(); + dragInfo = {}; + }; + + tree.on("startDrag", function(ev) { + if (!tree.getOption("enableDragDrop")) + return; + var node = ev.getNode(); + if (!node || ev.getButton()) + return; + mouseHandler.dragStart(); + + window.addEventListener("keydown", keyHandler, true); + window.addEventListener("keyup", keyHandler, true); + + var selectedNodes = tree.selection.getSelectedNodes(); + var el = constructDragNode(node); + + dragInfo = { + el: el, + node: node, + selectedNodes: selectedNodes, + offsetX: 10, + offsetY: 10, + target: node, + startT: Date.now(), + isInTree: true, + mode: "move" + }; + + ev.dragInfo = dragInfo; + tree._signal("dragStarted", ev); + + if (mouseHandler.state == "drag") + mouseHandler.drag(); + }); + + function constructDragNode(node) { + var i = tree.provider.getIndexForNode(node); + var domNode = tree.renderer.$cellLayer.getDomNodeAtIndex(i); + if (!domNode) return; + + var offset = domNode.offsetHeight; + + var selectedNodes = tree.selection.getSelectedNodes(); + var el = document.createElement("div"); + el.className = tree.container.className + " filetreeDragImage"; + var ch = el.appendChild(domNode.cloneNode(true)); + ch.removeChild(ch.firstChild); + ch.style.paddingRight = "5px"; + ch.style.opacity = "0.8"; + + el.style.position = "absolute"; + el.style.zIndex = "100000"; + el.style.pointerEvents = "none"; + el.style.overflow = "visible"; + + if (selectedNodes.length > 1) { + ch.style.color = "transparent"; + ch = el.appendChild(domNode.cloneNode(true)); + ch.removeChild(ch.firstChild); + ch.style.paddingRight = "5px"; + ch.style.top = - offset + 2 + "px"; + ch.style.left = "2px"; + ch.style.position = "relative"; + ch.style.opacity = "0.8"; + } + + document.body.appendChild(el); + return el; + } + + function keyHandler(e){ + if (dragInfo) { + if (e.keyCode === 27) { + mouseHandler.dragEnd(null, true); + } else if (dragInfo && e.keyCode == 17 || e.keyCode == 18) { + dragInfo.isCopy = e.type == "keydown"; + dom.setCssClass(dragInfo.el, "copy", dragInfo.isCopy); + } + } + + } +} + +function highlightFolder(tree, node, type) { + tree.provider.markedFolder = node; + tree.provider.markedFolderType = type; + tree.renderer.$loop.schedule(tree.renderer.CHANGE_MARKER); +} + +function isInRect(x, y, rect) { + if (x < rect.right && x > rect.left && y > rect.top && y < rect.bottom) + return true; +} + +module.exports = initDragHandlers; +}); diff --git a/node_modules/ace_tree/lib/ace_tree/mouse/heading_handler.js b/node_modules/ace_tree/lib/ace_tree/mouse/heading_handler.js new file mode 100644 index 00000000..b8012b76 --- /dev/null +++ b/node_modules/ace_tree/lib/ace_tree/mouse/heading_handler.js @@ -0,0 +1,74 @@ +define(function(require, exports, module) { +"use strict"; +var event = require("ace/lib/event"); + +function HeadingHandler(mouseHandler) { + var editor = mouseHandler.editor; + var headingLayer = editor.renderer.$headingLayer; + + + event.addListener(headingLayer.element, + "mousedown", + mouseHandler.onMouseEvent.bind(mouseHandler, "headerMouseDown")); + + event.addListener(headingLayer.element, + "mousemove", + mouseHandler.onMouseEvent.bind(mouseHandler, "headerMouseMove")); + + var overResizer, dragStartPos, columnData; + editor.setDefaultHandler("headerMouseMove", function(e) { + if (dragStartPos || !editor.provider || !editor.provider.columns) + return; + var pos = e.getDocumentPosition(); + var width = editor.renderer.$size.scrollerWidth; + if (width != editor.provider.columns.width) + headingLayer.updateWidth(width); + columnData = headingLayer.findColumn(pos.x); + + overResizer = columnData && columnData.overResizer; + headingLayer.element.style.cursor = overResizer + ? "ew-resize" + : "default"; + }); + + + editor.setDefaultHandler("headerMouseDown", function(e) { + if (overResizer) { + var pos = e.getDocumentPosition(); + dragStartPos = {x: pos.x}; + mouseHandler.setState("headerResize"); + mouseHandler.captureMouse(e); + mouseHandler.mouseEvent = e; + } + e.stop(); + }); + + mouseHandler.headerResize = function() { + if (this.mouseEvent && dragStartPos) { + var pos = this.mouseEvent.getDocumentPosition(); + var dx = pos.x // - dragStartPos.x; + var columns = editor.renderer.provider.columns; + for (var i = 0; i < columns.length; i++) { + var col = columns[i]; + dx -= col.pixelWidth; + if (col === columnData.column) + break; + } + var total = editor.renderer.$size.scrollerWidth; + headingLayer.changeColumnWidth(columnData.column, dx, total); + + var renderer = editor.renderer; + renderer.updateFull(); + } + }; + mouseHandler.headerResizeEnd = function() { + dragStartPos = null; + headingLayer.element.style.cursor = ""; + overResizer = false; + }; + +} + +exports.HeadingHandler = HeadingHandler; + +}); diff --git a/node_modules/ace_tree/lib/ace_tree/mouse/mouse_event.js b/node_modules/ace_tree/lib/ace_tree/mouse/mouse_event.js new file mode 100644 index 00000000..c68c528a --- /dev/null +++ b/node_modules/ace_tree/lib/ace_tree/mouse/mouse_event.js @@ -0,0 +1,129 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var event = require("ace/lib/event"); +var useragent = require("ace/lib/useragent"); + +/* + * Custom Ace mouse event + */ +var MouseEvent = exports.MouseEvent = function(domEvent, editor) { + this.domEvent = domEvent; + this.editor = editor; + + this.x = this.clientX = domEvent.clientX; + this.y = this.clientY = domEvent.clientY; + + this.$pos = null; + this.$inSelection = null; + + this.propagationStopped = false; + this.defaultPrevented = false; +}; + +(function() { + + this.stopPropagation = function() { + event.stopPropagation(this.domEvent); + this.propagationStopped = true; + }; + + this.preventDefault = function() { + event.preventDefault(this.domEvent); + this.defaultPrevented = true; + }; + + this.stop = function() { + this.stopPropagation(); + this.preventDefault(); + }; + + /* + * Get the document position below the mouse cursor + * + * @return {Object} 'row' and 'column' of the document position + */ + this.getDocumentPosition = function() { + if (this.$pos) + return this.$pos; + + this.$pos = this.editor.renderer.screenToTextCoordinates(this.clientX, this.clientY); + return this.$pos; + }; + + /* + * Check if the mouse cursor is inside of the text selection + * + * @return {Boolean} whether the mouse cursor is inside of the selection + */ + this.inSelection = function() { + if (this.$inSelection !== null) + return this.$inSelection; + + var node = this.getNode(); + this.$inSelection = !!(node && node.isSelected); + return this.$inSelection; + }; + + this.node = null; + this.getNode = function(clip) { + if (this.node) + return this.node; + var pos = this.getDocumentPosition(clip); + if (!pos || !this.editor.provider) return; // Click outside cells + return this.node = this.editor.provider.findItemAtOffset(pos.y, clip); + }; + + /* + * Get the clicked mouse button + * + * @return {Number} 0 for left button, 1 for middle button, 2 for right button + */ + this.getButton = function() { + return event.getButton(this.domEvent); + }; + + /* + * @return {Boolean} whether the shift key was pressed when the event was emitted + */ + this.getShiftKey = function() { + return this.domEvent.shiftKey; + }; + + this.getAccelKey = useragent.isMac + ? function() { return this.domEvent.metaKey; } + : function() { return this.domEvent.ctrlKey; }; + +}).call(MouseEvent.prototype); + +}); diff --git a/node_modules/ace_tree/lib/ace_tree/mouse/mouse_handler.js b/node_modules/ace_tree/lib/ace_tree/mouse/mouse_handler.js new file mode 100644 index 00000000..4693d776 --- /dev/null +++ b/node_modules/ace_tree/lib/ace_tree/mouse/mouse_handler.js @@ -0,0 +1,144 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var event = require("ace/lib/event"); +var useragent = require("ace/lib/useragent"); +var DefaultHandlers = require("./default_handlers").DefaultHandlers; +var initDragHandlers = require("./drag_handler"); +var HeadingHandler = require("./heading_handler").HeadingHandler; +var MouseEvent = require("./mouse_event").MouseEvent; +var config = require("../config"); + +var MouseHandler = function(editor) { + this.editor = editor; + + new DefaultHandlers(this); + new HeadingHandler(this); + initDragHandlers(this); + + + var mouseTarget = editor.renderer.getMouseEventTarget(); + event.addListener(mouseTarget, "mousedown", function(e) { + editor.focus(true); + return event.preventDefault(e); + }); + + event.addListener(mouseTarget, "mousemove", this.onMouseEvent.bind(this, "mousemove")); + // event.addListener(mouseTarget, "mouseup", this.onMouseEvent.bind(this, "mouseup")); + event.addMultiMouseDownListener(mouseTarget, [300, 300, 250], this, "onMouseEvent"); + event.addMultiMouseDownListener(editor.renderer.scrollBarV.inner, [300, 300, 250], this, "onMouseEvent"); + event.addMultiMouseDownListener(editor.renderer.scrollBarH.inner, [300, 300, 250], this, "onMouseEvent"); + event.addMouseWheelListener(editor.container, this.onMouseWheel.bind(this, "mousewheel")); + event.addListener(mouseTarget, "mouseout", this.onMouseEvent.bind(this, "mouseleave")); +}; + +(function() { + this.onMouseEvent = function(name, e) { + this.editor._emit(name, new MouseEvent(e, this.editor)); + }; + + this.onMouseWheel = function(name, e) { + var mouseEvent = new MouseEvent(e, this.editor); + mouseEvent.speed = this.$scrollSpeed * 2; + mouseEvent.wheelX = e.wheelX; + mouseEvent.wheelY = e.wheelY; + + this.editor._emit(name, mouseEvent); + }; + + this.setState = function(state) { + this.state = state; + }; + + this.captureMouse = function(ev, state) { + if (state) + this.setState(state); + + this.x = ev.x; + this.y = ev.y; + + this.isMousePressed = true; + + // do not move textarea during selection + var renderer = this.editor.renderer; + if (renderer.$keepTextAreaAtCursor) + renderer.$keepTextAreaAtCursor = null; + + var self = this; + var onMouseMove = function(e) { + self.x = e.clientX; + self.y = e.clientY; + self.mouseEvent = new MouseEvent(e, self.editor); + self.$mouseMoved = true; + }; + + var onCaptureEnd = function(e) { + clearInterval(timerId); + onCaptureInterval(); + self[self.state + "End"] && self[self.state + "End"](e); + self.$clickSelection = null; + if (renderer.$keepTextAreaAtCursor == null) { + renderer.$keepTextAreaAtCursor = true; + renderer.$moveTextAreaToCursor(); + } + self.isMousePressed = false; + e && self.onMouseEvent("mouseup", e); + self.$onCaptureMouseMove = self.releaseMouse = null; + }; + + var onCaptureInterval = function() { + self[self.state] && self[self.state](); + self.$mouseMoved = false; + }; + + if (useragent.isOldIE && ev.domEvent.type == "dblclick") { + return setTimeout(function() {onCaptureEnd(ev.domEvent);}); + } + + self.$onCaptureMouseMove = onMouseMove; + self.releaseMouse = event.capture(this.editor.container, onMouseMove, onCaptureEnd); + var timerId = setInterval(onCaptureInterval, 20); + }; + this.releaseMouse = null; +}).call(MouseHandler.prototype); + +config.defineOptions(MouseHandler.prototype, "mouseHandler", { + scrollSpeed: {initialValue: 2}, + dragDelay: {initialValue: 150}, + focusTimout: {initialValue: 0}, + enableDragDrop: {initialValue: false} +}); + + +exports.MouseHandler = MouseHandler; +}); diff --git a/node_modules/ace_tree/lib/ace_tree/quicksearch.js b/node_modules/ace_tree/lib/ace_tree/quicksearch.js new file mode 100644 index 00000000..8d9ca33b --- /dev/null +++ b/node_modules/ace_tree/lib/ace_tree/quicksearch.js @@ -0,0 +1,40 @@ +define(function(require, exports, module) { +"use strict"; + +var quickSearch = function(tree, str) { + var node = tree.selection.getCursor() + var siblings = tree.provider.getChildren(node.parent); + + if (!siblings || siblings.length == 1) { + return; + } + + var index = siblings.indexOf(node); + var newNode + for (var i = index + 1; i < siblings.length; i++) { + node = siblings[i]; + var label = node.label || node.name || ""; + if (label[0] == str) { + newNode = node; + break; + } + } + if (!newNode) { + for (var i = 0; i < index; i++) { + node = siblings[i]; + var label = node.label || node.name || ""; + if (label[0] == str) { + newNode = node; + break; + } + } + } + + if (newNode) { + tree.selection.selectNode(newNode); + tree.renderer.scrollCaretIntoView(newNode, 0.5); + } +}; + +module.exports = quickSearch; +}); diff --git a/node_modules/ace_tree/lib/ace_tree/scrollable.js b/node_modules/ace_tree/lib/ace_tree/scrollable.js new file mode 100644 index 00000000..a17f5dbe --- /dev/null +++ b/node_modules/ace_tree/lib/ace_tree/scrollable.js @@ -0,0 +1,45 @@ +/** + * The main class required to set up a Tree instance in the browser. + * + * @class Tree + **/ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("ace/lib/oop"); +var EventEmitter = require("ace/lib/event_emitter").EventEmitter; + + +var scrollable = {}; + +(function() { + oop.implement(this, EventEmitter); + + this.$scrollTop = 0; + this.getScrollTop = function() { return this.$scrollTop; }; + this.setScrollTop = function(scrollTop) { + scrollTop = Math.round(scrollTop); + if (this.$scrollTop === scrollTop || isNaN(scrollTop)) + return; + + this.$scrollTop = scrollTop; + this._signal("changeScrollTop", scrollTop); + }; + + this.$scrollLeft = 0; + this.getScrollLeft = function() { return this.$scrollLeft; }; + this.setScrollLeft = function(scrollLeft) { + scrollLeft = Math.round(scrollLeft); + if (this.$scrollLeft === scrollLeft || isNaN(scrollLeft)) + return; + + this.$scrollLeft = scrollLeft; + this._signal("changeScrollLeft", scrollLeft); + }; + + +}).call(scrollable); + +module.exports = scrollable; +}); diff --git a/node_modules/ace_tree/lib/ace_tree/selection.js b/node_modules/ace_tree/lib/ace_tree/selection.js new file mode 100644 index 00000000..325864bf --- /dev/null +++ b/node_modules/ace_tree/lib/ace_tree/selection.js @@ -0,0 +1,269 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +var oop = require("ace/lib/oop"); +var EventEmitter = require("ace/lib/event_emitter").EventEmitter; + +var Selection = function(provider) { + this.provider = provider; + if (this.provider && !this.provider.selectedItems) + this.provider.selectedItems = []; + this.provider.on("remove", this.unselectRemoved = this.unselectRemoved.bind(this)); +}; + +(function() { + + oop.implement(this, EventEmitter); + + this.$wrapAround = false; + this.getRange = function() {}; + + this.selectAll = function() { + var sel = this.provider.selectedItems; + this.expandSelection(sel[0], sel[sel.length -1]); + + this._signal("change"); + }; + + this.moveSelection = function(dir, select, add) { + var provider = this.provider; + var cursor = this.getCursor(); + var anchor = this.getAnchor(); + var i = provider.getIndexForNode(cursor); + if (!add) { + this.clear(true); + } else if (add && !select) { + this.unselectNode(cursor); + } + + var min = provider.getMinIndex(); + var max = provider.getMaxIndex(); + var wrapped = false; + var newI = i; + do { + newI += dir; + if (newI < min) { + newI = this.$wrapAround ? max : min; + wrapped = true; + } else if (newI > max) { + newI = this.$wrapAround ? min : max; + wrapped = true; + } + var newNode = provider.getNodeAtIndex(newI); + + } while (!wrapped && newNode && !provider.isSelectable(newNode)); + + if (!newNode || !provider.isSelectable(newNode)) + newNode = cursor; + + if (select) { + this.expandSelection(newNode, anchor, add); + } else { + this.selectNode(newNode, add); + } + }; + + this.getCursor = function() { + var sel = this.provider.selectedItems; + return sel.cursor || sel[sel.length - 1]; + }; + this.getAnchor = function() { + var sel = this.provider.selectedItems; + return sel.anchor || sel.cursor || sel[0]; + }; + this.getSelectedNodes = function() { + var sel = this.provider.selectedItems; + return sel.slice(); + }; + this.getVisibleSelectedNodes = function() { + var provider = this.provider; + var sel = provider.selectedItems; + return sel.filter(function(node) { + return provider.isVisible(node); + }); + }; + + this.isEmpty = function() { + var sel = this.provider.selectedItems; + return sel.length === 0; + }; + this.isMultiRow = function() { + var sel = this.provider.selectedItems; + return sel.length > 1; + }; + this.toggleSelect = function(node) { + var provider = this.provider; + var sel = provider.selectedItems; + var i = sel.indexOf(node); + if (i != -1) + sel.splice(i, 1); + provider.setSelected(node, !provider.isSelected(node)); + if (provider.isSelected(node)) { + sel.push(node); + sel.anchor = sel.cursor = node; + } else + sel.anchor = sel.cursor = sel[sel.length - 1]; + + this._signal("change"); + }; + this.selectNode = function(node, add, silent) { + var provider = this.provider; + var sel = provider.selectedItems; + if (!provider.isSelectable(node)) + return; + if (!add) + this.clear(true); + if (node) { + var i = sel.indexOf(node); + if (i != -1) + sel.splice(i, 1); + provider.setSelected(node, true); + if (provider.isSelected(node)) + sel.push(node); + } + sel.anchor = sel.cursor = node; + this._signal("change"); + }; + this.add = function(node) { + this.selectNode(node, true); + }; + this.remove = function(node) { + if (this.provider.isSelected(node)) + this.toggleSelect(node); + }; + this.clear = + this.clearSelection = function(silent) { + var provider = this.provider; + var sel = provider.selectedItems; + sel.forEach(function(node) { provider.setSelected(node, false); }); + sel.splice(0, sel.length); + sel.anchor = sel.cursor; + + silent || this._signal("change"); + }; + this.unselectNode = function(node, silent) { + var provider = this.provider; + var sel = provider.selectedItems; + var i = sel.indexOf(node); + if (i != -1) { + sel.splice(i, 1); + provider.setSelected(node, false); + if (sel.anchor == node) + sel.anchor = sel[i-1] || sel[i]; + if (sel.cursor == node) + sel.cursor = sel[i] || sel[i-1]; + silent || this._signal("change"); + } + }; + this.setSelection = function(nodes) { + if (Array.isArray(nodes)) { + this.clear(true); + nodes.forEach(function(node) { + this.selectNode(node, true, true); + }, this); + } else + this.selectNode(nodes, false, true); + }; + this.expandSelection = function(cursor, anchor, additive) { + anchor = anchor || this.getAnchor(); + + if (!additive) + this.clear(true); + var provider = this.provider; + var sel = provider.selectedItems; + + var end = provider.getIndexForNode(cursor); + var start = provider.getIndexForNode(anchor || cursor); + + if (end > start) { + for (var i = start; i <= end; i++) { + var node = provider.getNodeAtIndex(i); + var index = sel.indexOf(node); + if (index != -1) + sel.splice(index, 1); + if (provider.isSelectable(node)) + provider.setSelected(node, true); + sel.push(node); + } + } else { + for (var i = start; i >= end; i--) { + var node = provider.getNodeAtIndex(i); + var index = sel.indexOf(node); + if (index != -1) + sel.splice(index, 1); + if (provider.isSelectable(node)) + provider.setSelected(node, true); + sel.push(node); + } + } + + sel.cursor = cursor; + sel.anchor = anchor; + + this._signal("change"); + }; + + this.unselectRemoved = function(toRemove) { + var sel = this.getSelectedNodes(); + var provider = this.provider; + var changed, cursor = this.getCursor(); + sel.forEach(function(n) { + if (provider.isAncestor(toRemove, n)) { + changed = true; + this.unselectNode(n, true); + } + }, this); + if (changed && !provider.isSelected(cursor)) { + var parent = toRemove.parent; + var ch = []; + if (parent && provider.isOpen(parent)) { + ch = provider.getChildren(parent); + var i = ch.indexOf(toRemove); + } + if (i == -1) { + i = toRemove.index; + var node = ch[i] || ch[i - 1] || parent; + } else { + node = ch[i + 1] || ch[i - 1] || parent; + } + if (node == provider.root) + node = ch[0] || node; + if (node) + this.selectNode(node, true); + this._signal("change"); + } + }; +}).call(Selection.prototype); + +exports.Selection = Selection; +}); diff --git a/node_modules/ace_tree/lib/ace_tree/selection_test.js b/node_modules/ace_tree/lib/ace_tree/selection_test.js new file mode 100644 index 00000000..b69fd6dd --- /dev/null +++ b/node_modules/ace_tree/lib/ace_tree/selection_test.js @@ -0,0 +1,465 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +if (typeof process !== "undefined") { + require("amd-loader"); +} + +define(function(require, exports, module) { +"use strict"; + +var EditSession = require("./edit_session").EditSession; +var assert = require("./test/assertions"); + +module.exports = { + createSession : function(rows, cols) { + var line = new Array(cols + 1).join("a"); + var text = new Array(rows).join(line + "\n") + line; + return new EditSession(text); + }, + + "test: move cursor to end of file should place the cursor on last row and column" : function() { + var session = this.createSession(200, 10); + var selection = session.getSelection(); + + selection.moveCursorFileEnd(); + assert.position(selection.getCursor(), 199, 10); + }, + + "test: moveCursor to start of file should place the cursor on the first row and column" : function() { + var session = this.createSession(200, 10); + var selection = session.getSelection(); + + selection.moveCursorFileStart(); + assert.position(selection.getCursor(), 0, 0); + }, + + "test: move selection lead to end of file" : function() { + var session = this.createSession(200, 10); + var selection = session.getSelection(); + + selection.moveCursorTo(100, 5); + selection.selectFileEnd(); + + var range = selection.getRange(); + + assert.position(range.start, 100, 5); + assert.position(range.end, 199, 10); + }, + + "test: move selection lead to start of file" : function() { + var session = this.createSession(200, 10); + var selection = session.getSelection(); + + selection.moveCursorTo(100, 5); + selection.selectFileStart(); + + var range = selection.getRange(); + + assert.position(range.start, 0, 0); + assert.position(range.end, 100, 5); + }, + + "test: move cursor word right" : function() { + var session = new EditSession([ + "ab", + " Juhu Kinners (abc, 12)", + " cde" + ].join("\n")); + + var selection = session.getSelection(); + session.$selectLongWords = true; + + selection.moveCursorDown(); + assert.position(selection.getCursor(), 1, 0); + + selection.moveCursorWordRight(); + assert.position(selection.getCursor(), 1, 5); + + selection.moveCursorWordRight(); + assert.position(selection.getCursor(), 1, 13); + + selection.moveCursorWordRight(); + assert.position(selection.getCursor(), 1, 18); + + selection.moveCursorWordRight(); + assert.position(selection.getCursor(), 1, 22); + + // wrap line + selection.moveCursorWordRight(); + assert.position(selection.getCursor(), 2, 4); + + selection.moveCursorWordRight(); + assert.position(selection.getCursor(), 2, 4); + }, + + "test: select word right if cursor in word" : function() { + var session = new EditSession("Juhu Kinners"); + var selection = session.getSelection(); + + selection.moveCursorTo(0, 2); + selection.moveCursorWordRight(); + + assert.position(selection.getCursor(), 0, 4); + }, + + "test: moveCursor word left" : function() { + var session = new EditSession([ + "ab", + " Juhu Kinners (abc, 12)", + " cde" + ].join("\n")); + + var selection = session.getSelection(); + session.$selectLongWords = true; + + selection.moveCursorDown(); + selection.moveCursorLineEnd(); + assert.position(selection.getCursor(), 1, 23); + + selection.moveCursorWordLeft(); + assert.position(selection.getCursor(), 1, 20); + + selection.moveCursorWordLeft(); + assert.position(selection.getCursor(), 1, 15); + + selection.moveCursorWordLeft(); + assert.position(selection.getCursor(), 1, 6); + + selection.moveCursorWordLeft(); + assert.position(selection.getCursor(), 1, 1); + + // wrap line + selection.moveCursorWordLeft(); + assert.position(selection.getCursor(), 0, 0); + + selection.moveCursorWordLeft(); + assert.position(selection.getCursor(), 0, 0); + }, + + "test: moveCursor word left with umlauts" : function() { + var session = new EditSession(" Fuß Füße"); + session.$selectLongWords = true; + + var selection = session.getSelection(); + selection.moveCursorTo(0, 9) + selection.moveCursorWordLeft(); + assert.position(selection.getCursor(), 0, 5); + + selection.moveCursorWordLeft(); + assert.position(selection.getCursor(), 0, 1); + }, + + "test: select word left if cursor in word" : function() { + var session = new EditSession("Juhu Kinners"); + var selection = session.getSelection(); + session.$selectLongWords = true; + + selection.moveCursorTo(0, 8); + + selection.moveCursorWordLeft(); + assert.position(selection.getCursor(), 0, 5); + }, + + "test: select word right and select" : function() { + var session = new EditSession("Juhu Kinners"); + var selection = session.getSelection(); + + selection.moveCursorTo(0, 0); + selection.selectWordRight(); + + var range = selection.getRange(); + + assert.position(range.start, 0, 0); + assert.position(range.end, 0, 4); + }, + + "test: select word left and select" : function() { + var session = new EditSession("Juhu Kinners"); + var selection = session.getSelection(); + + selection.moveCursorTo(0, 3); + selection.selectWordLeft(); + + var range = selection.getRange(); + + assert.position(range.start, 0, 0); + assert.position(range.end, 0, 3); + }, + + "test: select word with cursor in word should select the word" : function() { + var session = new EditSession("Juhu Kinners 123"); + var selection = session.getSelection(); + + selection.moveCursorTo(0, 8); + selection.selectWord(); + + var range = selection.getRange(); + assert.position(range.start, 0, 5); + assert.position(range.end, 0, 12); + }, + + "test: select word with cursor in word including right whitespace should select the word" : function() { + var session = new EditSession("Juhu Kinners 123"); + var selection = session.getSelection(); + + selection.moveCursorTo(0, 8); + selection.selectAWord(); + + var range = selection.getRange(); + assert.position(range.start, 0, 5); + assert.position(range.end, 0, 18); + }, + + "test: select word with cursor betwen white space and word should select the word" : function() { + var session = new EditSession("Juhu Kinners"); + var selection = session.getSelection(); + session.$selectLongWords = true; + + selection.moveCursorTo(0, 4); + selection.selectWord(); + + var range = selection.getRange(); + assert.position(range.start, 0, 0); + assert.position(range.end, 0, 4); + + selection.moveCursorTo(0, 5); + selection.selectWord(); + + var range = selection.getRange(); + assert.position(range.start, 0, 5); + assert.position(range.end, 0, 12); + }, + + "test: select word with cursor in white space should select white space" : function() { + var session = new EditSession("Juhu Kinners"); + var selection = session.getSelection(); + session.$selectLongWords = true; + + selection.moveCursorTo(0, 5); + selection.selectWord(); + + var range = selection.getRange(); + assert.position(range.start, 0, 4); + assert.position(range.end, 0, 6); + }, + + "test: moving cursor should fire a 'changeCursor' event" : function() { + var session = new EditSession("Juhu Kinners"); + var selection = session.getSelection(); + session.$selectLongWords = true; + + selection.moveCursorTo(0, 5); + + var called = false; + selection.addEventListener("changeCursor", function() { + called = true; + }); + + selection.moveCursorTo(0, 6); + assert.ok(called); + }, + + "test: calling setCursor with the same position should not fire an event": function() { + var session = new EditSession("Juhu Kinners"); + var selection = session.getSelection(); + session.$selectLongWords = true; + + selection.moveCursorTo(0, 5); + + var called = false; + selection.addEventListener("changeCursor", function() { + called = true; + }); + + selection.moveCursorTo(0, 5); + assert.notOk(called); + }, + + "test: moveWordright should move past || and [": function() { + var session = new EditSession("||foo["); + var selection = session.getSelection(); + session.$selectLongWords = true; + + // Move behind ||foo + selection.moveCursorWordRight(); + assert.position(selection.getCursor(), 0, 5); + + // Move behind [ + selection.moveCursorWordRight(); + assert.position(selection.getCursor(), 0, 6); + }, + + "test: moveWordLeft should move past || and [": function() { + var session = new EditSession("||foo["); + var selection = session.getSelection(); + session.$selectLongWords = true; + + selection.moveCursorTo(0, 6); + + // Move behind [foo + selection.moveCursorWordLeft(); + assert.position(selection.getCursor(), 0, 2); + + // Move behind || + selection.moveCursorWordLeft(); + assert.position(selection.getCursor(), 0, 0); + }, + + "test: move cursor to line start should move cursor to end of the indentation first": function() { + var session = new EditSession("12\n Juhu\n12"); + var selection = session.getSelection(); + + selection.moveCursorTo(1, 6); + selection.moveCursorLineStart(); + + assert.position(selection.getCursor(), 1, 4); + }, + + "test: move cursor to line start when the cursor is at the end of the indentation should move cursor to column 0": function() { + var session = new EditSession("12\n Juhu\n12"); + var selection = session.getSelection(); + + selection.moveCursorTo(1, 4); + selection.moveCursorLineStart(); + + assert.position(selection.getCursor(), 1, 0); + }, + + "test: move cursor to line start when the cursor is at column 0 should move cursor to the end of the indentation": function() { + var session = new EditSession("12\n Juhu\n12"); + var selection = session.getSelection(); + + selection.moveCursorTo(1, 0); + selection.moveCursorLineStart(); + + assert.position(selection.getCursor(), 1, 4); + }, + + // Eclipse style + "test: move cursor to line start when the cursor is before the initial indentation should move cursor to the end of the indentation": function() { + var session = new EditSession("12\n Juhu\n12"); + var selection = session.getSelection(); + + selection.moveCursorTo(1, 2); + selection.moveCursorLineStart(); + + assert.position(selection.getCursor(), 1, 4); + }, + + "test go line up when in the middle of the first line should go to document start": function() { + var session = new EditSession("juhu kinners"); + var selection = session.getSelection(); + + selection.moveCursorTo(0, 4); + selection.moveCursorUp(); + + assert.position(selection.getCursor(), 0, 0); + }, + + "test: (wrap) go line up when in the middle of the first line should go to document start": function() { + var session = new EditSession("juhu kinners"); + session.setWrapLimitRange(5, 5); + session.adjustWrapLimit(80); + + var selection = session.getSelection(); + + selection.moveCursorTo(0, 4); + selection.moveCursorUp(); + + assert.position(selection.getCursor(), 0, 0); + }, + + + "test go line down when in the middle of the last line should go to document end": function() { + var session = new EditSession("juhu kinners"); + var selection = session.getSelection(); + + selection.moveCursorTo(0, 4); + selection.moveCursorDown(); + + assert.position(selection.getCursor(), 0, 12); + }, + + "test (wrap) go line down when in the middle of the last line should go to document end": function() { + var session = new EditSession("juhu kinners"); + session.setWrapLimitRange(8, 8); + session.adjustWrapLimit(80); + + var selection = session.getSelection(); + + selection.moveCursorTo(0, 10); + selection.moveCursorDown(); + + assert.position(selection.getCursor(), 0, 12); + }, + + "test go line up twice and then once down when in the second should go back to the previous column": function() { + var session = new EditSession("juhu\nkinners"); + var selection = session.getSelection(); + + selection.moveCursorTo(1, 4); + selection.moveCursorUp(); + selection.moveCursorUp(); + selection.moveCursorDown(); + + assert.position(selection.getCursor(), 1, 4); + }, + + "test (keyboard navigation) when curLine is not EOL and targetLine is all whitespace new column should be current column": function() { + var session = new EditSession("function (a) {\n\ + \n\ +}"); + var selection = session.getSelection(); + + selection.moveCursorTo(2, 0); + selection.moveCursorUp(); + + assert.position(selection.getCursor(), 1, 0); + }, + + "test (keyboard navigation) when curLine is EOL and targetLine is shorter dan current column, new column should be targetLine's EOL": function() { + var session = new EditSession("function (a) {\n\ + \n\ +}"); + var selection = session.getSelection(); + + selection.moveCursorTo(0, 14); + selection.moveCursorDown(); + + assert.position(selection.getCursor(), 1, 4); + } +}; + +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec() +} diff --git a/node_modules/ace_tree/lib/ace_tree/test/setup_paths.js b/node_modules/ace_tree/lib/ace_tree/test/setup_paths.js new file mode 100644 index 00000000..6846cd7a --- /dev/null +++ b/node_modules/ace_tree/lib/ace_tree/test/setup_paths.js @@ -0,0 +1,19 @@ +var modules = require("module"); +var oldResolve = modules._resolveFilename; +var extraPaths = [ + __dirname + "/../../../../ace/lib", + __dirname + "/../../node_modules/ace/lib", + __dirname + "/../" +]; +modules._resolveFilename = function(request, paths) { + // Ensure client extensions can be loaded + request = request.replace(/^ext\//, "ext.") + .replace(/^core\//, "cloud9.core/www/core/") + .replace(/^lib\/chai\//, "chai/"); + // Add the extra paths + extraPaths.forEach(function(p) { + if (paths.paths.indexOf(p) === -1) + paths.paths.push(p); + }); + return oldResolve(request, paths); +}; diff --git a/node_modules/ace_tree/lib/ace_tree/tooltip.js b/node_modules/ace_tree/lib/ace_tree/tooltip.js new file mode 100644 index 00000000..81de9138 --- /dev/null +++ b/node_modules/ace_tree/lib/ace_tree/tooltip.js @@ -0,0 +1,93 @@ +define(function(require, exports, module) { +"use strict"; +var dom = require("ace/lib/dom"); +var lang = require("ace/lib/lang"); +dom.importCssString(".no-events * {pointer-events:none!important}"); +function Tooltip(tree) { + this.tree = tree; + this.tree.on("mousemove", this.onMouseMove.bind(this)); + this.tree.on("mousewheel", this.onMouseMove.bind(this, null)); + this.tree.renderer.scroller.addEventListener("mouseout", this.onMouseOut.bind(this)); + this.setUp(); + // this.tree.renderer.on("afterRender", this.updateNodeClass.bind(this)); + this.clearDelayed = lang.delayedCall(this.onMouseMove.bind(this), 50); +} + +(function() { + this.setUp = function() { + var container = this.tree.container; + this.root = document.createElement("div"); + this.root.className = container.className + " no-events"; + this.root.style.cssText = "border: 0px;margin: 0px;" + + "position: absolute; bottom: initial; right: initial; width: auto; height: auto;" + + "overflow: visible;z-index: 1000000; white-space: pre;" + + "pointer-events: none"; + // var color = dom.computedStyle(container).backgroundColor; + // if (!color) + this.root.style.backgroundColor = "rgb(48, 49, 48)"; + document.body.appendChild(this.root); + + }; + this.updateNode = function(treeNode) { + if (this.node) { + this.node.parentNode.removeChild(this.node); + this.node = null; + } + this.treeNode = treeNode; + if (!treeNode) { + this.root.style.display = "none"; + return; + } + this.root.className = this.tree.container.className + " no-events"; + this.root.style.display = ""; + var rect = treeNode.getBoundingClientRect(); + this.node = treeNode.cloneNode(true); + this.node.style.margin = "0px"; + + this.root.appendChild(this.node); + this.root.style.top = rect.top + "px"; + this.root.style.left = rect.left + "px"; + }; + + this.updateNodeClass = function() { + if (this.node && this.treeNode) { + if (this.treeNode.parentNode == this.tree.renderer.$cellLayer.element) + this.node.className = this.treeNode.className; + else + this.updateNode(null); + } + }; + + this.dettach = function() { + + }; + + this.attach = function() { + + }; + + this.onMouseMove = function(ev) { + var target = ev && ev.domEvent.target; + while (target && !dom.hasCssClass(target, "tree-row")) { + target = target.parentElement; + } + if (target == this.treeNode) + return; + this.updateNode(target); + if (target) + this.clearDelayed.cancel(); + }; + + + this.onMouseOut = function(e) { + this.onMouseMove({domEvent: e}) + }; + this.onMouseOver = function(ev) { + this.clearDelayed.schedule(); + }; + +}).call(Tooltip.prototype); + +module.exports = Tooltip; + +}); \ No newline at end of file diff --git a/node_modules/ace_tree/lib/ace_tree/tree.js b/node_modules/ace_tree/lib/ace_tree/tree.js new file mode 100644 index 00000000..78513294 --- /dev/null +++ b/node_modules/ace_tree/lib/ace_tree/tree.js @@ -0,0 +1,726 @@ +/** + * The main class required to set up a Tree instance in the browser. + * + * @class Tree + **/ + +define(function(require, exports, module) { +"use strict"; + +// var UndoManager = require("./undomanager").UndoManager; +var Renderer = require("./virtual_renderer").VirtualRenderer; +// var MultiSelect = require("./multi_select").MultiSelect; + +exports.config = require("./config"); + +var oop = require("ace/lib/oop"); +var lang = require("ace/lib/lang"); +var useragent = require("ace/lib/useragent"); +var TextInput = require("ace/keyboard/textinput").TextInput; +var MouseHandler = require("./mouse/mouse_handler").MouseHandler; +var KeyBinding = require("ace/keyboard/keybinding").KeyBinding; +var Selection = require("./selection").Selection; +var EventEmitter = require("ace/lib/event_emitter").EventEmitter; +var CommandManager = require("ace/commands/command_manager").CommandManager; +var defaultCommands = require("./commands/default_commands").commands; +var config = require("./config"); + +var quickSearch = require("./quicksearch"); +/** + * @class Tree + **/ + +/** + * Creates a new `Tree` object. + * @param {Object} element The html element the Tree table renders in. + * + * + * @constructor + **/ +var Tree = function(element, cellWidth, cellHeight) { + this.cellWidth = cellWidth || 80; + this.cellHeight = cellHeight || 24; + + this.renderer = new Renderer(element, this.cellWidth, this.cellHeight); + this.container = this.renderer.container; + + this.commands = new CommandManager(useragent.isMac ? "mac" : "win", defaultCommands); + this.textInput = new TextInput(this.container, this); + this.keyBinding = new KeyBinding(this); + + // TODO detect touch event support + this.$mouseHandler = new MouseHandler(this); + + this.$blockScrolling = 0; + + var _self = this; + this.renderer.on("edit", function(e){ + _self._emit("edit", e); + }); + + this.commands.on("exec", function() { + this.selectionChanged = false; + }.bind(this)); + this.commands.on("afterExec", function() { + if (this.selectionChanged) { + this.selectionChanged = false; + this.renderer.scrollCaretIntoView(); + this._signal("userSelect"); + } + }.bind(this)); + this.on("changeSelection", function() { + if (this.$mouseHandler.isMousePressed) + this._signal("userSelect"); + }.bind(this)); + + + // var Tooltip = require("./tooltip") + // new Tooltip(this) + + config.resetOptions(this); + config._emit("Tree", this); +}; + +(function(){ + + oop.implement(this, EventEmitter); + + /** + * + **/ + this.setDataProvider = function(provider) { + if (this.provider) { + var oldProvider = this.provider; + // this.session.off("changeScrollLeft", this.$onScrollLeftChange); + + this.selection.off("changeCaret", this.$onCaretChange); + this.selection.off("change", this.$onSelectionChange); + + oldProvider.off("changeClass", this.$onChangeClass); + oldProvider.off("expand", this.$redraw); + oldProvider.off("collapse", this.$redraw); + oldProvider.off("change", this.$redraw); + oldProvider.off("changeScrollTop", this.$onScrollTopChange); + oldProvider.off("changeScrollLeft", this.$onScrollLeftChange); + } + + this.provider = provider; + if (provider) { + this.renderer.setDataProvider(provider); + + // this.$onScrollLeftChange = this.onScrollLeftChange.bind(this); + // this.session.on("changeScrollLeft", this.$onScrollLeftChange); + + if (!this.$redraw) this.$redraw = this.redraw.bind(this); + + this.provider.on("expand", this.$redraw); + this.provider.on("collapse", this.$redraw); + this.provider.on("change", this.$redraw); + + // FIXME + if (!this.provider.selection) { + this.provider.selection = new Selection(this.provider); + } + + this.selection = this.provider.selection; + + this.$onCaretChange = this.onCaretChange.bind(this); + this.selection.on("changeCaret", this.$onCaretChange); + this.$onChangeClass = this.$onChangeClass.bind(this); + this.provider.on("changeClass", this.$onChangeClass); + + this.$onSelectionChange = this.onSelectionChange.bind(this); + this.selection.on("change", this.$onSelectionChange); + + + this.$onScrollTopChange = this.onScrollTopChange.bind(this); + this.provider.on("changeScrollTop", this.$onScrollTopChange); + + this.$onScrollLeftChange = this.onScrollLeftChange.bind(this); + this.provider.on("changeScrollLeft", this.$onScrollLeftChange); + + this.$blockScrolling += 1; + this.onCaretChange(); + this.$blockScrolling -= 1; + + this.onScrollTopChange(); + this.onScrollLeftChange(); + this.onSelectionChange(); + this.renderer.updateFull(); + } + + this._emit("changeDataProvider", { + provider: provider, + oldProvider: oldProvider + }); + }; + + this.redraw = function() { + this.renderer.updateFull(); + }; + + this.getLength = function(){ + return 0; // this.renderer.$treeLayer.length; + }; + + this.getLine = function(row){ + return { + length : 0 // this.renderer.$horHeadingLayer.length - 1 + }; + }; + + /** + * Returns the current session being used. + **/ + this.getDataProvider = function() { + return this.provider; + }; + + /** + * + * Returns the currently highlighted selection. + * @returns {String} The highlighted selection + **/ + this.getSelection = function() { + return this.selection; + }; + + /** + * {:VirtualRenderer.onResize} + * @param {Boolean} force If `true`, recomputes the size, even if the height and width haven't changed + * + * + * @related VirtualRenderer.onResize + **/ + this.resize = function(force) { + this.renderer.onResize(force); + }; + + /** + * + * Brings the current `textInput` into focus. + **/ + this.focus = function(once) { + // Safari needs the timeout + // iOS and Firefox need it called immediately + // to be on the save side we do both + var _self = this; + once || setTimeout(function() { + _self.textInput.focus(); + }); + this.textInput.focus(); + }; + + /** + * Returns `true` if the current `textInput` is in focus. + * @return {Boolean} + **/ + this.isFocused = function() { + return this.textInput.isFocused(); + }; + + /** + * + * Blurs the current `textInput`. + **/ + this.blur = function() { + this.textInput.blur(); + }; + + /** + * Emitted once the editor comes into focus. + * @event focus + * + * + **/ + this.onFocus = function() { + if (this.$isFocused) + return; + this.$isFocused = true; + this.renderer.visualizeFocus(); + this._emit("focus"); + }; + + /** + * Emitted once the editor has been blurred. + * @event blur + * + * + **/ + this.onBlur = function() { + if (!this.$isFocused) + return; + this.$isFocused = false; + this.renderer.visualizeBlur(); + this._emit("blur"); + }; + + this.onScrollTopChange = function() { + this.renderer.scrollToY(this.provider.getScrollTop()); + }; + + this.onScrollLeftChange = function() { + this.renderer.scrollToX(this.renderer.getScrollLeft()); + }; + + this.$onChangeClass = function() { + this.renderer.updateCaret(); + }; + + /** + * Emitted when the selection changes. + * + **/ + this.onCaretChange = function() { + this.$onChangeClass(); + + if (!this.$blockScrolling) + this.selectionChanged = true; + + this._emit("changeSelection"); + }; + + this.onSelectionChange = function(e) { + this.onCaretChange(); + }; + + this.execCommand = function(command, args) { + this.commands.exec(command, this, args); + }; + + this.onTextInput = function(text) { + this.keyBinding.onTextInput(text); + }; + + this.onCommandKey = function(e, hashId, keyCode) { + this.keyBinding.onCommandKey(e, hashId, keyCode); + }; + + this.insertSting = function(str) { + if (this.startFilter) + return this.startFilter(str); + + quickSearch(this, str); + }; + + this.setTheme = function(theme) { + this.renderer.setTheme(theme); + }; + + /** + * Returns an object indicating the currently selected rows. The object looks like this: + * + * ```json + * { first: range.start.row, last: range.end.row } + * ``` + * + * @returns {Object} + **/ + this.$getSelectedRows = function() { + var range = this.getSelectionRange().collapseRows(); + + return { + first: range.start.row, + last: range.end.row + }; + }; + + /** + * {:VirtualRenderer.getVisibleNodes} + * @param {Number} tolerance fraction of the node allowed to be hidden while node still considered visible (default 1/3) + * @returns {Array} + * @related VirtualRenderer.getVisibleNodes + **/ + this.getVisibleNodes = function(tolerance) { + return this.renderer.getVisibleNodes(tolerance); + }; + /** + * Indicates if the node is currently visible on the screen. + * @param {Object} node The node to check + * @param {Number} tolerance fraction of the node allowed to be hidden while node still considered visible (default 1/3) + * + * @returns {Boolean} + **/ + this.isNodeVisible = function(node, tolerance) { + return this.renderer.isNodeVisible(node, tolerance); + }; + + this.$moveByPage = function(dir, select) { + var renderer = this.renderer; + var config = this.renderer.layerConfig; + config.lineHeight = this.provider.rowHeight; + var rows = dir * Math.floor(config.height / config.lineHeight); + + this.$blockScrolling++; + this.selection.moveSelection(rows, select); + this.$blockScrolling--; + + var scrollTop = renderer.scrollTop; + + renderer.scrollBy(0, rows * config.lineHeight); + if (select != null) + renderer.scrollCaretIntoView(null, 0.5); + + renderer.animateScrolling(scrollTop); + }; + + /** + * Selects the text from the current position of the document until where a "page down" finishes. + **/ + this.selectPageDown = function() { + this.$moveByPage(1, true); + }; + + /** + * Selects the text from the current position of the document until where a "page up" finishes. + **/ + this.selectPageUp = function() { + this.$moveByPage(-1, true); + }; + + /** + * Shifts the document to wherever "page down" is, as well as moving the cursor position. + **/ + this.gotoPageDown = function() { + this.$moveByPage(1, false); + }; + + /** + * Shifts the document to wherever "page up" is, as well as moving the cursor position. + **/ + this.gotoPageUp = function() { + this.$moveByPage(-1, false); + }; + + /** + * Scrolls the document to wherever "page down" is, without changing the cursor position. + **/ + this.scrollPageDown = function() { + this.$moveByPage(1); + }; + + /** + * Scrolls the document to wherever "page up" is, without changing the cursor position. + **/ + this.scrollPageUp = function() { + this.$moveByPage(-1); + }; + + /** + * Scrolls to a row. If `center` is `true`, it puts the row in middle of screen (or attempts to). + * @param {Number} row The row to scroll to + * @param {Boolean} center If `true` + * @param {Boolean} animate If `true` animates scrolling + * @param {Function} callback Function to be called when the animation has finished + * + * + * @related VirtualRenderer.scrollToRow + **/ + this.scrollToRow = function(row, center, animate, callback) { + this.renderer.scrollToRow(row, center, animate, callback); + }; + + /** + * Attempts to center the current selection on the screen. + **/ + this.centerSelection = function() { + var range = this.getSelectionRange(); + var pos = { + row: Math.floor(range.start.row + (range.end.row - range.start.row) / 2), + column: Math.floor(range.start.column + (range.end.column - range.start.column) / 2) + }; + this.renderer.alignCaret(pos, 0.5); + }; + + /** + * Gets the current position of the Caret. + * @returns {Object} An object that looks something like this: + * + * ```json + * { row: currRow, column: currCol } + * ``` + * + * @related Selection.getCursor + **/ + this.getCursorPosition = function() { + return this.selection.getCursor(); + }; + + /** + * Returns the screen position of the Caret. + * @returns {Number} + **/ + this.getCursorPositionScreen = function() { + return this.session.documentToScreenPosition(this.getCursorPosition()); + }; + + /** + * {:Selection.getRange} + * @returns {Range} + * @related Selection.getRange + **/ + this.getSelectionRange = function() { + return this.selection.getRange(); + }; + + + /** + * Selects all the text in editor. + * @related Selection.selectAll + **/ + this.selectAll = function() { + this.$blockScrolling += 1; + this.selection.selectAll(); + this.$blockScrolling -= 1; + }; + + /** + * {:Selection.clearSelection} + * @related Selection.clearSelection + **/ + this.clearSelection = function() { + this.selection.clearSelection(); + }; + + /** + * Moves the Caret to the specified row and column. Note that this does not de-select the current selection. + * @param {Number} row The new row number + * @param {Number} column The new column number + * + * + * @related Selection.moveCaretTo + **/ + this.moveCaretTo = function(row, column) { + this.selection.moveCaretTo(row, column); + }; + + /** + * Moves the Caret to the position indicated by `pos.row` and `pos.column`. + * @param {Object} pos An object with two properties, row and column + * + * + * @related Selection.moveCaretToPosition + **/ + this.moveCaretToPosition = function(pos) { + this.selection.moveCaretToPosition(pos); + }; + + /** + * Moves the Caret to the specified row number, and also into the indiciated column. + * @param {Number} rowNumber The row number to go to + * @param {Number} column A column number to go to + * @param {Boolean} animate If `true` animates scolling + * + **/ + this.gotoRow = function(rowNumber, column, animate) { + this.selection.clearSelection(); + + if (column === undefined) + column = this.selection.getCursor().column; + + this.$blockScrolling += 1; + this.moveCaretTo(rowNumber - 1, column || 0); + this.$blockScrolling -= 1; + + if (!this.isRowFullyVisible(rowNumber - 1)) + this.scrollToRow(rowNumber - 1, true, animate); + }; + + /** + * Moves the Caret to the specified row and column. Note that this does de-select the current selection. + * @param {Number} row The new row number + * @param {Number} column The new column number + * + * + * @related Editor.moveCaretTo + **/ + this.navigateTo = function(row, column) { + this.clearSelection(); + this.moveCaretTo(row, column); + }; + + /** + * Moves the Caret up in the document the specified number of times. Note that this does de-select the current selection. + * @param {Number} times The number of times to change navigation + * + * + **/ + this.navigateUp = function() { + var node = this.provider.navigate("up"); + node && this.selection.setSelection(node); + this.$scrollIntoView(); + }; + + /** + * Moves the Caret down in the document the specified number of times. Note that this does de-select the current selection. + * @param {Number} times The number of times to change navigation + * + * + **/ + this.navigateDown = function() { + var node = this.provider.navigate("down"); + node && this.selection.setSelection(node); + }; + + /** + * Moves the Caret left in the document the specified number of times. Note that this does de-select the current selection. + **/ + this.navigateLevelUp = function(toggleNode) { + var node = this.selection.getCursor(); + if (!node) { + // continue + } else if (toggleNode && this.provider.isOpen(node)) { + this.provider.close(node); + } else { + this.selection.setSelection(node.parent); + } + }; + + /** + * Moves the Caret right in the document the specified number of times. Note that this does de-select the current selection. + **/ + this.navigateLevelDown = function() { + var node = this.selection.getCursor(); + var hasChildren = this.provider.hasChildren(node); + if (!hasChildren || this.provider.isOpen(node)) + return this.selection.moveSelection(1); + + this.provider.open(node); + }; + + this.navigateStart = function() { + var node = this.getFirstNode(); + this.selection.setSelection(node); + }; + + this.navigateEnd = function() { + var node = this.getLastNode(); + this.selection.setSelection(node); + }; + this.getFirstNode = function() { + var index = this.provider.getMinIndex(); + return this.provider.getNodeAtIndex(index); + }; + this.getLastNode = function() { + var index = this.provider.getMaxIndex(); + return this.provider.getNodeAtIndex(index); + }; + + this.$scrollIntoView = function(node) { + this.renderer.scrollCaretIntoView(); + }; + + this.select = function(node) { + this.selection.setSelection(node); + }; + + this.getCopyText = function(node) { + return ""; + }; + this.onPaste = function(node) { + return ""; + }; + + this.reveal = function(node, animate) { + var provider = this.provider; + var parent = node.parent; + while (parent) { + if (!provider.isOpen(parent)) + provider.expand(parent); + parent = parent.parent; + } + + this.select(node); + var scrollTop = this.renderer.scrollTop; + this.renderer.scrollCaretIntoView(node, 0.5); + if (animate !== false) + this.renderer.animateScrolling(scrollTop); + }; + + /** + * {:UndoManager.undo} + * @related UndoManager.undo + **/ + this.undo = function() { + this.$blockScrolling++; + this.session.getUndoManager().undo(); + this.$blockScrolling--; + this.renderer.scrollCaretIntoView(null, 0.5); + }; + + /** + * {:UndoManager.redo} + * @related UndoManager.redo + **/ + this.redo = function() { + this.$blockScrolling++; + this.session.getUndoManager().redo(); + this.$blockScrolling--; + this.renderer.scrollCaretIntoView(null, 0.5); + }; + + /** + * Returns `true` if the editor is set to read-only mode. + * @returns {Boolean} + **/ + this.getReadOnly = function() { + return this.getOption("readOnly"); + }; + + /** + * + * Cleans up the entire editor. + **/ + this.destroy = function() { + this.renderer.destroy(); + this._emit("destroy", this); + }; + + this.setHorHeadingVisible = function(value){ + this.renderer.setHorHeadingVisible(value); + }; + + this.setVerHeadingVisible = function(value){ + this.renderer.setVerHeadingVisible(value); + }; + + this.enable = function() { + this.$disabled = false; + this.container.style.pointerEvents = ""; + this.container.style.opacity = ""; + }; + + this.disable = function() { + this.$disabled = true; + this.container.style.pointerEvents = "none"; + this.container.style.opacity = "0.9"; + if (this.isFocused()) + this.blur(); + }; + +}).call(Tree.prototype); + +config.defineOptions(Tree.prototype, "Tree", { + toggle: { + set: function(toggle) { + + }, + initialValue: false + }, + readOnly: { + set: function(readOnly) { + this.textInput.setReadOnly(readOnly); + }, + initialValue: false + }, + + animatedScroll: "renderer", + maxLines: "renderer", + minLines: "renderer", + + scrollSpeed: "$mouseHandler", + enableDragDrop: "$mouseHandler" +}); + +module.exports = Tree; +}); diff --git a/node_modules/ace_tree/lib/ace_tree/undomanager.js b/node_modules/ace_tree/lib/ace_tree/undomanager.js new file mode 100644 index 00000000..b20bd7d8 --- /dev/null +++ b/node_modules/ace_tree/lib/ace_tree/undomanager.js @@ -0,0 +1,135 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +define(function(require, exports, module) { +"use strict"; + +/** + * + * + * This object maintains the undo stack for a Pivot Table. + * @class UndoManager + **/ + +/** + * + * + * Resets the current undo state and creates a new `UndoManager`. + * + * @constructor + **/ +var UndoManager = function() { + this.reset(); +}; + +(function() { + + /** + * Provides a means for implementing your own undo manager. `options` has one property, `args`, an [[Array `Array`]], with two elements: + * + * - `args[0]` is an array of deltas + * - `args[1]` is the document to associate with + * + * @param {Object} options Contains additional properties + * + **/ + this.execute = function(options) { + var deltas = options.args[0]; + this.$doc = options.args[1]; + this.$undoStack.push(deltas); + this.$redoStack = []; + }; + + /** + * [Perform an undo operation on the document, reverting the last change.]{: #UndoManager.undo} + * @param {Boolean} dontSelect + * + * + * @returns {Range} The range of the undo. + **/ + this.undo = function(dontSelect) { + var deltas = this.$undoStack.pop(); + var undoSelectionRange = null; + if (deltas) { + undoSelectionRange = + this.$doc.undoChanges(deltas, dontSelect); + this.$redoStack.push(deltas); + } + return undoSelectionRange; + }; + + /** + * [Perform a redo operation on the document, reimplementing the last change.]{: #UndoManager.redo} + * @param {Boolean} dontSelect + * + * + **/ + this.redo = function(dontSelect) { + var deltas = this.$redoStack.pop(); + var redoSelectionRange = null; + if (deltas) { + redoSelectionRange = + this.$doc.redoChanges(deltas, dontSelect); + this.$undoStack.push(deltas); + } + return redoSelectionRange; + }; + + /** + * + * Destroys the stack of undo and redo redo operations. + **/ + this.reset = function() { + this.$undoStack = []; + this.$redoStack = []; + }; + + /** + * + * Returns `true` if there are undo operations left to perform. + * @returns {Boolean} + **/ + this.hasUndo = function() { + return this.$undoStack.length > 0; + }; + + /** + * + * Returns `true` if there are redo operations left to perform. + * @returns {Boolean} + **/ + this.hasRedo = function() { + return this.$redoStack.length > 0; + }; + +}).call(UndoManager.prototype); + +exports.UndoManager = UndoManager; +}); diff --git a/node_modules/ace_tree/lib/ace_tree/virtual_renderer.js b/node_modules/ace_tree/lib/ace_tree/virtual_renderer.js new file mode 100644 index 00000000..3400c429 --- /dev/null +++ b/node_modules/ace_tree/lib/ace_tree/virtual_renderer.js @@ -0,0 +1,1166 @@ +define(function(require, exports, module) { +"use strict"; + +var oop = require("ace/lib/oop"); +var dom = require("ace/lib/dom"); +var config = require("./config"); + +var CellLayer = require("./layer/cells").Cells; +var MarkerLayer = require("./layer/markers").Selection; +var HeaderLayer = require("./layer/heading").ColumnHeader; + +var ScrollBarH = require("ace/scrollbar").ScrollBarH; +var ScrollBarV = require("ace/scrollbar").ScrollBarV; +var RenderLoop = require("ace/renderloop").RenderLoop; +var EventEmitter = require("ace/lib/event_emitter").EventEmitter; +var pivotCss = require("ace/requirejs/text!./css/tree.css"); + +dom.importCssString(pivotCss, "ace_tree"); + +var defaultTheme = require("./css/light_theme"); +/** + * The class that is responsible for drawing everything you see on the screen! + * @class VirtualRenderer + **/ + +/** + * Constructs a new `VirtualRenderer` within the `container` specified, applying the given `theme`. + * @param {DOMElement} container The root element of the editor + * @param {Number} cellWidth The default width of a cell in pixels + * @param {Number} cellHeight The default height of a cell in pixels + * + * @constructor + **/ + +var VirtualRenderer = function(container, cellWidth, cellHeight) { + var _self = this; + + this.container = container || dom.createElement("div"); + + dom.addCssClass(this.container, "ace_tree"); + dom.addCssClass(this.container, "ace_tree"); + + this.setTheme(this.$theme); + this.scroller = dom.createElement("div"); + this.scroller.className = "ace_tree_scroller"; + this.container.appendChild(this.scroller); + + this.cells = dom.createElement("div"); + this.cells.className = "ace_tree_cells"; + this.scroller.appendChild(this.cells); + + this.$headingLayer = new HeaderLayer(this.container, this); + this.$markerLayer = new MarkerLayer(this.cells, this); + + this.$cellLayer = new CellLayer(this.cells); + this.canvas = this.$cellLayer.element; + + // Indicates whether the horizontal scrollbarscrollbar is visible + this.$horizScroll = false; + + this.scrollBarV = new ScrollBarV(this.container, this); + this.scrollBarV.setVisible(true); + this.scrollBarV.addEventListener("scroll", function(e) { + if (!_self.$inScrollAnimation) + _self.setScrollTop(e.data - _self.scrollMargin.top); + }); + + this.scrollBarH = new ScrollBarH(this.container, this); + this.scrollBarH.addEventListener("scroll", function(e) { + if (!_self.$inScrollAnimation) + _self.setScrollLeft(e.data); + }); + + this.scrollTop = 0; + this.scrollLeft = 0; + + this.caretPos = { + row : 0, + column : 0 + }; + + this.$size = { + width: 0, + height: 0, + scrollerHeight: 0, + scrollerWidth: 0, + headingHeight: 0 + }; + + this.layerConfig = { + width : 1, + padding : 0, + firstRow : 0, + firstRowScreen: 0, + lastRow : 0, + lineHeight : 1, + characterWidth : 1, + minHeight : 1, + maxHeight : 1, + offset : 0, + height : 1 + }; + + this.scrollMargin = { + left: 0, + right: 0, + top: 0, + bottom: 0, + v: 0, + h: 0 + }; + + + this.$loop = new RenderLoop( + this.$renderChanges.bind(this), + this.container.ownerDocument.defaultView + ); + this.$loop.schedule(this.CHANGE_FULL); + this.setTheme(defaultTheme); + + this.$windowFocus = this.$windowFocus.bind(this); + window.addEventListener("focus", this.$windowFocus); +}; + +(function() { + this.CHANGE_SCROLL = 1; + this.CHANGE_COLUMN = 2; + this.CHANGE_ROW = 4; + this.CHANGE_CELLS = 8; + this.CHANGE_SIZE = 16; + this.CHANGE_CLASS = 32; + this.CHANGE_MARKER = 64; + this.CHANGE_FULL = 128; + + this.CHANGE_H_SCROLL = 1024; + + oop.implement(this, EventEmitter); + + /** + * + * Associates the renderer with an DataProvider. + **/ + this.setDataProvider = function(provider) { + this.provider = provider; + + if (this.scrollMargin.top && provider && provider.getScrollTop() <= 0) + provider.setScrollTop(-this.scrollMargin.top); + + this.scroller.className = "ace_tree_scroller"; + + this.$cellLayer.setDataProvider(provider); + this.$markerLayer.setDataProvider(provider); + this.$headingLayer.setDataProvider(provider); + + this.$size.headingHeight = provider && provider.columns + ? provider.headerHeight || provider.rowHeight + : 0; + + this.$loop.schedule(this.CHANGE_FULL); + }; + + /** + * Triggers a partial update of the text, from the range given by the two parameters. + * @param {Number} firstRow The first row to update + * @param {Number} lastRow The last row to update + * + * + **/ + this.updateRows = function(firstRow, lastRow) { + if (lastRow === undefined) + lastRow = Infinity; + + if (!this.$changedLines) { + this.$changedLines = { + firstRow: firstRow, + lastRow: lastRow + }; + } + else { + if (this.$changedLines.firstRow > firstRow) + this.$changedLines.firstRow = firstRow; + + if (this.$changedLines.lastRow < lastRow) + this.$changedLines.lastRow = lastRow; + } + + if (this.$changedLines.firstRow > this.layerConfig.lastRow || + this.$changedLines.lastRow < this.layerConfig.firstRow) + return; + this.$loop.schedule(this.CHANGE_ROW); + }; + + this.updateCaret = function() { + this.$loop.schedule(this.CHANGE_CLASS); + }; + + /** + * Triggers a full update of the text, for all the rows. + **/ + this.updateCells = function() { + this.$loop.schedule(this.CHANGE_CELLS); + }; + + /** + * Triggers a full update of all the layers, for all the rows. + * @param {Boolean} force If `true`, forces the changes through + * + * + **/ + this.updateFull = function(force) { + if (force) + this.$renderChanges(this.CHANGE_FULL, true); + else + this.$loop.schedule(this.CHANGE_FULL); + }; + + this.updateHorizontalHeadings = function(){ + this.$loop.schedule(this.CHANGE_COLUMN); + }; + + this.updateVerticalHeadings = function(){ + this.$loop.schedule(this.CHANGE_ROW); + }; + + + this.$changes = 0; + /** + * [Triggers a resize of the editor.]{: #VirtualRenderer.onResize} + * @param {Boolean} force If `true`, recomputes the size, even if the height and width haven't changed + * @param {Number} width The width of the editor in pixels + * @param {Number} height The hiehgt of the editor, in pixels + * + * + **/ + this.onResize = function(force, width, height) { + if (this.resizing > 2) + return; + else if (this.resizing > 0) + this.resizing++; + else + this.resizing = force ? 1 : 0; + // `|| el.scrollHeight` is required for outosizing editors on ie + // where elements with clientHeight = 0 alsoe have clientWidth = 0 + var el = this.container; + if (!height) + height = el.clientHeight || el.scrollHeight; + if (!width) + width = el.clientWidth || el.scrollWidth; + var changes = this.$updateCachedSize(force, width, height); + + if (!this.$size.scrollerHeight || (!width && !height)) + return this.resizing = 0; + + if (force) + this.$renderChanges(changes, true); + else + this.$loop.schedule(changes | this.$changes); + + if (this.resizing) + this.resizing = 0; + }; + + this.$windowFocus = function(){ + this.onResize(); + }; + + this.$updateCachedSize = function(force, width, height) { + var changes = 0; + var size = this.$size; + var provider = this.provider; + if (provider) { + var headingHeight = provider.columns + ? provider.headerHeight || provider.rowHeight + : 0; + if (headingHeight != size.headingHeight) { + size.headingHeight = headingHeight; + changes |= this.CHANGE_SIZE; + } + } + + if (height && (force || size.height != height)) { + size.height = height; + changes |= this.CHANGE_SIZE; + + size.scrollerHeight = size.height; + if (this.$horizScroll) + size.scrollerHeight -= this.scrollBarH.getHeight(); + + //if (this.heading) { + size.scrollerHeight -= size.headingHeight; + // } + + this.$headingLayer.element.style.height = + this.scroller.style.top = + this.scrollBarV.element.style.top = size.headingHeight + "px"; + // this.scrollBarV.setHeight(size.scrollerHeight); + this.scrollBarV.element.style.bottom = this.scrollBarH.getHeight() + "px"; + + if (provider && provider.setScrollTop) { + // provider.setScrollTop(this.getScrollTop()); + changes |= this.CHANGE_SCROLL; + } + } + + if (width && (force || size.width != width)) { + changes |= this.CHANGE_SIZE; + size.width = width; + + this.scrollBarH.element.style.left = + this.scroller.style.left = 0 + "px"; + size.scrollerWidth = Math.max(0, width - this.scrollBarV.getWidth()); + + this.$headingLayer.element.style.right = + this.scrollBarH.element.style.right = + this.scroller.style.right = this.scrollBarV.getWidth() + "px"; + this.scroller.style.bottom = this.scrollBarH.getHeight() + "px"; + + // this.scrollBarH.element.style.setWidth(size.scrollerWidth); + + this.$headingLayer.updateWidth(size.scrollerWidth); + + if (provider && provider.columns) + changes |= this.CHANGE_FULL; + } + + if (changes) + this._signal("resize"); + + return changes; + }; + + this.setVerHeadingVisible = function(value){ + this.$treeLayer.visible = value; + if (this.layerConfig.vRange && this.layerConfig.hRange) { + this.$renderChanges(this.CHANGE_FULL, true); + this.onResize(true); + } + }; + + /** + * + * Returns the root element containing this renderer. + * @returns {DOMElement} + **/ + this.getContainerElement = function() { + return this.container; + }; + + /** + * + * Returns the element that the mouse events are attached to + * @returns {DOMElement} + **/ + this.getMouseEventTarget = function() { + return this.scroller; + }; + /** + * [Returns array of nodes currently visible on the screen]{: #VirtualRenderer.getVisibleNodes} + * @param {Object} node Tree node + * @param {Number} tolerance fraction of the node allowed to be hidden while node still considered visible (default 1/3) + * @returns {Array} + **/ + this.getVisibleNodes = function(tolerance) { + var nodes = this.layerConfig.vRange; + var first = 0; + var last = nodes.length - 1; + while (this.isNodeVisible(nodes[first], tolerance) && first < last) + first++; + while (!this.isNodeVisible(nodes[last], tolerance) && last > first) + last--; + return nodes.slice(first, last + 1); + }; + /** + * [Indicates if the node is currently visible on the screen]{: #VirtualRenderer.isNodeVisible} + * @param {Object} node Tree node + * @param {Number} tolerance fraction of the node allowed to be hidden while node still considered visible (default 1/3) + * @returns {Boolean} + **/ + this.isNodeVisible = function(node, tolerance) { + var layerConfig = this.layerConfig; + if (!layerConfig.vRange) return; + var provider = this.provider; + var i = layerConfig.vRange.indexOf(node); + + if (i == -1) return false; + var nodePos = provider.getNodePosition(node); + + var top = nodePos.top; + var height = nodePos.height; + if (tolerance === undefined) + tolerance = 1 / 3; + if (this.scrollTop > top + tolerance * height) + return false; + if (this.scrollTop + this.$size.scrollerHeight <= top + (1 - tolerance) * height) + return false; + return true; + }; + + this.$updateScrollBar = function() { + // todo separate event for h v scroll + this.$updateScrollBarH(); + this.$updateScrollBarV(); + }; + + this.setScrollMargin = function(top, bottom, left, right) { + var sm = this.scrollMargin; + sm.top = top|0; + sm.bottom = bottom|0; + sm.right = right|0; + sm.left = left|0; + sm.v = sm.top + sm.bottom; + sm.h = sm.left + sm.right; + if (sm.top && this.scrollTop <= 0 && this.provider) + this.provider.setScrollTop(sm.top); + this.updateFull(); + }; + this.$updateScrollBarV = function() { + this.scrollBarV.setInnerHeight(this.layerConfig.maxHeight + this.scrollMargin.v); + this.scrollBarV.setScrollTop(this.scrollTop + this.scrollMargin.top); + }; + this.$updateScrollBarH = function() { + this.scrollBarH.setInnerWidth(this.layerConfig.maxWidth + this.scrollMargin.h); + this.scrollBarH.setScrollLeft(this.scrollLeft + this.scrollMargin.left); + }; + + this.$frozen = false; + this.freeze = function() { + this.$frozen = true; + }; + + this.unfreeze = function() { + this.$frozen = false; + }; + + this.$renderChanges = function(changes, force) { + if (this.$changes) { + changes |= this.$changes; + this.$changes = 0; + } + if ((!this.provider || !this.container.offsetWidth || this.$frozen) || (!changes && !force)) { + this.$changes |= changes; + return; + } + if (!this.$size.width) { + this.$changes |= changes; + return this.onResize(true); + } + + // this.$logChanges(changes); + + this._signal("beforeRender"); + var config = this.layerConfig; + // text, scrolling and resize changes can cause the view port size to change + if (changes & this.CHANGE_FULL || + changes & this.CHANGE_SIZE || + changes & this.CHANGE_SCROLL || + changes & this.CHANGE_H_SCROLL || + changes & this.CHANGE_COLUMN || + changes & this.CHANGE_ROW || + changes & this.CHANGE_CELLS + ) { + changes |=this.$computeLayerConfig(); + + config = this.layerConfig; + // update scrollbar first to not lose scroll position when gutter calls resize + this.$updateScrollBar(); + this.cells.style.marginTop = -config.vOffset + "px"; + this.cells.style.marginLeft = -config.hOffset + "px"; + this.cells.style.width = config.width + "px"; + this.cells.style.height = config.height + config.rowHeight + "px"; + } + // full + if (changes & this.CHANGE_FULL) { + this.$headingLayer.update(this.layerConfig); + this.$cellLayer.update(this.layerConfig); + this.$markerLayer.update(this.layerConfig); + this._signal("afterRender"); + return; + } + + // scrolling + if (changes & this.CHANGE_SCROLL) { + if (changes & this.CHANGE_ROW || + changes & this.CHANGE_COLUMN || + changes & this.CHANGE_CELLS + ) { + this.$headingLayer.update(this.layerConfig); + this.$cellLayer.update(this.layerConfig); + } + else { + this.$headingLayer.update(this.layerConfig); + this.$cellLayer.scroll(this.layerConfig); + } + + this.$markerLayer.update(this.layerConfig); + this.$updateScrollBar(); + this._signal("afterRender"); + return; + } + + if (changes & this.CHANGE_CLASS) + this.$cellLayer.updateClasses(this.layerConfig); + + if (changes & this.CHANGE_MARKER || changes & this.CHANGE_CELLS) + this.$markerLayer.update(this.layerConfig); + + // if (changes & this.CHANGE_ROW) + // this.$treeLayer.update(this.layerConfig); + // this.$updateRows(); + //@todo analog to updateRows? + if (changes & this.CHANGE_COLUMN) + this.$horHeadingLayer.update(this.layerConfig); + if (changes & this.CHANGE_CELLS) + this.$cellLayer.update(this.layerConfig); + + if (changes & this.CHANGE_SIZE) + this.$updateScrollBar(); + + this._signal("afterRender"); + }; + + + this.$autosize = function() { + var headingHeight = this.$size.headingHeight; + var height = this.provider.getTotalHeight() + headingHeight; + var maxHeight = this.getMaxHeight + ? this.getMaxHeight() + : this.$maxLines * this.provider.rowHeight + headingHeight; + var desiredHeight = Math.max( + (this.$minLines || 1) * this.provider.rowHeight + headingHeight, + Math.min(maxHeight, height) + ); + var vScroll = height > maxHeight; + + if (desiredHeight != this.desiredHeight || + this.$size.height != this.desiredHeight || vScroll != this.$vScroll) { + if (vScroll != this.$vScroll) { + this.$vScroll = vScroll; + this.scrollBarV.setVisible(vScroll); + } + + var w = this.container.clientWidth; + this.container.style.height = desiredHeight + "px"; + this.$updateCachedSize(true, w, desiredHeight); + // this.$loop.changes = 0; + this.desiredHeight = desiredHeight; + this._signal("autoresize"); + } + }; + + this.$computeLayerConfig = function() { + if (this.$maxLines) + this.$autosize(); + + var provider = this.provider; + var vertical = this.$treeLayer; + var horizontal = this.$horHeadingLayer; + + var top = Math.max(this.scrollTop, 0); + var vRange = provider.getRange(top, top + this.$size.height); + var hRange = {size: 0}// horizontal.getRange(this.scrollLeft, this.scrollLeft + this.$size.width); + + var minHeight = this.$size.scrollerHeight; + var maxHeight = provider.getTotalHeight(); + + var minWidth = this.$size.scrollerWidth; + var maxWidth = 0 //horizontal.size; + + var hideScrollbars = this.$size.height <= 2 * 10; + var horizScroll = !hideScrollbars && (this.$hScrollBarAlwaysVisible || + this.$size.scrollerWidth - maxWidth < 0); + + var hScrollChanged = this.$horizScroll !== horizScroll; + if (hScrollChanged) { + this.$horizScroll = horizScroll; + this.scrollBarH.setVisible(horizScroll); + } + + var vScroll = !hideScrollbars && (this.$vScrollBarAlwaysVisible || + this.$size.scrollerHeight - maxHeight < 0); + var vScrollChanged = this.$vScroll !== vScroll; + if (vScrollChanged) { + this.$vScroll = vScroll; + this.scrollBarV.setVisible(vScroll); + } + + this.provider.setScrollTop(Math.max(-this.scrollMargin.top, + Math.min(this.scrollTop, maxHeight - this.$size.scrollerHeight + this.scrollMargin.bottom))); + + this.provider.setScrollLeft(Math.max(-this.scrollMargin.left, Math.min(this.scrollLeft, + maxWidth - this.$size.scrollerWidth + this.scrollMargin.right))); + + + if (this.provider.getScrollTop() != this.scrollTop) + this.scrollTop = this.provider.getScrollTop(); + + var vOffset = this.scrollTop - vRange.size; + var hOffset = this.scrollLeft - hRange.size; + + var rowCount = vRange.length; + var firstRow = vRange.count; + var lastRow = firstRow + rowCount - 1; + + var colCount = hRange.length; + var firstCol = hRange.count; + var lastCol = firstCol + colCount - 1; + + if (this.layerConfig) + this.layerConfig.discard = true; + + var changes = 0; + // Horizontal scrollbar visibility may have changed, which changes + // the client height of the scroller + if (hScrollChanged || vScrollChanged) { + changes = this.$updateCachedSize(true, this.$size.width, this.$size.height); + this._signal("scrollbarVisibilityChanged"); + //if (vScrollChanged) + // longestLine = this.$getLongestLine(); + } + + this.layerConfig = { + vRange : vRange, + hRange : hRange, + width : minWidth, + height : minHeight, + firstRow : firstRow, + lastRow : lastRow, + firstCol : firstCol, + lastCol : lastCol, + minHeight : minHeight, + maxHeight : maxHeight, + minWidth : minWidth, + maxWidth : maxWidth, + vOffset : vOffset, + hOffset : hOffset, + rowHeight: provider.rowHeight + }; + + var config = this.layerConfig, renderer = this; + if (vRange) { + config.view = provider.getDataRange( + {start: vRange.count, length: vRange.length}, + {start: hRange.count, length: hRange.length}, + function(err, view, update){ + if (err) return false; //@todo + config.view = view; + + if (update) + renderer.$loop.schedule(renderer.CHANGE_CELLS); + }); + } + + // For debugging. + // console.log(JSON.stringify(this.layerConfig)); + + return changes; + }; + + this.$updateRows = function() { + var firstRow = this.$changedLines.firstRow; + var lastRow = this.$changedLines.lastRow; + this.$changedLines = null; + + var layerConfig = this.layerConfig; + + if (firstRow > layerConfig.lastRow + 1) { return; } + if (lastRow < layerConfig.firstRow) { return; } + + // if the last row is unknown -> redraw everything + if (lastRow === Infinity) { + this.$cellLayer.update(layerConfig); + return; + } + + // else update only the changed rows + this.$cellLayer.updateRows(layerConfig, firstRow, lastRow); + return true; + }; + + this.scrollSelectionIntoView = function(anchor, lead, offset) { + // first scroll anchor into view then scroll lead into view + this.scrollCaretIntoView(anchor, offset); + this.scrollCaretIntoView(lead, offset); + }; + + /** + * + * Scrolls the Caret into the first visible area of the editor + **/ + this.scrollCaretIntoView = function(caret, offset) { + // the editor is not visible + if (this.$size.scrollerHeight === 0) + return; + + var provider = this.provider; + var node = caret || provider.selection.getCursor(); + if (!node) + return; + + var nodePos = provider.getNodePosition(node); + + var top = nodePos.top; + var height = nodePos.height; + var left = 0; + var width = 0; + + + if (this.scrollTop > top) { + if (offset) + top -= offset * this.$size.scrollerHeight; + this.provider.setScrollTop(top); + } else if (this.scrollTop + this.$size.scrollerHeight < top + height) { + if (offset) + top += offset * this.$size.scrollerHeight; + this.provider.setScrollTop(top + height - this.$size.scrollerHeight); + } + + var scrollLeft = this.scrollLeft; + + if (scrollLeft > left) { + if (left < 0) + left = 0; + this.provider.setScrollLeft(left); + } else if (scrollLeft + this.$size.scrollerWidth < left + width) { + this.provider.setScrollLeft(Math.round(left + width - this.$size.scrollerWidth)); + } + }; + + /** + * @returns {Number} + **/ + this.getScrollTop = function() { + return this.scrollTop; + }; + + /** + * @returns {Number} + **/ + this.getScrollLeft = function() { + return this.scrollLeft; + }; + + /** + * This function sets the scroll top value. It also emits the `'changeScrollTop'` event. + * @param {Number} scrollTop The new scroll top value + * + **/ + this.setScrollTop = function(scrollTop) { + scrollTop = Math.round(scrollTop); + if (this.scrollTop === scrollTop || isNaN(scrollTop)) + return; + + this.scrollToY(scrollTop); + }; + + /** + * This function sets the scroll top value. It also emits the `'changeScrollLeft'` event. + * @param {Number} scrollLeft The new scroll left value + * + **/ + this.setScrollLeft = function(scrollLeft) { + scrollLeft = Math.round(scrollLeft); + if (this.scrollLeft === scrollLeft || isNaN(scrollLeft)) + return; + + this.scrollToX(scrollLeft); + }; + + /** + * + * Returns the first visible row, regardless of whether it's fully visible or not. + * @returns {Number} + **/ + this.getScrollTopRow = function() { + return this.layerConfig.firstRow; + }; + + /** + * + * Returns the last visible row, regardless of whether it's fully visible or not. + * @returns {Number} + **/ + this.getScrollBottomRow = function() { + return this.layerConfig.lastRow; + //return Math.max(0, Math.floor((this.scrollTop + this.$size.scrollerHeight) / this.lineHeight) - 1); + }; + + this.alignCaret = function(cursor, alignment) { + if (typeof cursor == "number") + cursor = {row: cursor, column: 0}; + + var node = this.provider.findNodeByIndex(cursor.row); + var pos = this.provider.findSizeAtIndex(cursor.row); + var h = this.$size.scrollerHeight; + var offset = pos - ((h - node.size) * (alignment || 0)); + + this.setScrollTop(offset); + return offset; + }; + + this.STEPS = 8; + this.$calcSteps = function(fromValue, toValue){ + var i = 0; + var l = this.STEPS; + var steps = []; + + var func = function(t, x_min, dx) { + return dx * (Math.pow(t - 1, 3) + 1) + x_min; + }; + + for (i = 0; i < l; ++i) + steps.push(func(i / this.STEPS, fromValue, toValue - fromValue)); + + return steps; + }; + + /** + * Gracefully scrolls the editor to the row indicated. + * @param {Number} line A line number + * @param {Boolean} center If `true`, centers the editor the to indicated line + * @param {Boolean} animate If `true` animates scrolling + * @param {Function} callback Function to be called after the animation has finished + * + * + **/ + this.scrollToRow = function(row, center, animate, callback) { + var node = this.provider.findNodeByIndex(row); + var offset = this.provider.findSizeAtIndex(row); + if (center) + offset -= (this.$size.scrollerHeight - node.size) / 2; + + var initialScroll = this.scrollTop; + this.setScrollTop(offset); + if (animate !== false) + this.animateScrolling(initialScroll, callback); + }; + + this.animateScrolling = function(fromValue, callback) { + var toValue = this.scrollTop; + if (this.$animatedScroll && Math.abs(fromValue - toValue) < 100000) { + var _self = this; + var steps = _self.$calcSteps(fromValue, toValue); + this.$inScrollAnimation = true; + + clearInterval(this.$timer); + + _self.provider.setScrollTop(steps.shift()); + this.$timer = setInterval(function() { + if (steps.length) { + _self.setScrollTop(steps.shift()); + // trick provider to think it's already scrolled to not loose toValue + _self.scrollTop = toValue; + } else if (toValue != null) { + _self.scrollTop = -1; + _self.setScrollTop(toValue); + toValue = null; + } else { + // do this on separate step to not get spurious scroll event from scrollbar + _self.$timer = clearInterval(_self.$timer); + _self.$inScrollAnimation = false; + callback && callback(); + } + }, 10); + } + }; + + /** + * Scrolls the editor to the y pixel indicated. + * @param {Number} scrollTop The position to scroll to + * + * + * @returns {Number} + **/ + this.scrollToY = function(scrollTop) { + // after calling scrollBar.setScrollTop + // scrollbar sends us event with same scrollTop. ignore it + if (this.scrollTop !== scrollTop) { + this.$loop.schedule(this.CHANGE_SCROLL); + this.scrollTop = scrollTop; + } + }; + + /** + * Scrolls the editor across the x-axis to the pixel indicated. + * @param {Number} scrollLeft The position to scroll to + * + * + * @returns {Number} + **/ + this.scrollToX = function(scrollLeft) { + if (scrollLeft < 0) + scrollLeft = 0; + + if (this.scrollLeft !== scrollLeft) { + this.$loop.schedule(this.CHANGE_SCROLL); + this.scrollLeft = scrollLeft; + } + }; + + /** + * Scrolls the editor across both x- and y-axes. + * @param {Number} deltaX The x value to scroll by + * @param {Number} deltaY The y value to scroll by + * + * + **/ + this.scrollBy = function(deltaX, deltaY) { + deltaY && this.provider.setScrollTop(this.provider.getScrollTop() + deltaY); + deltaX && this.provider.setScrollLeft(this.provider.getScrollLeft() + deltaX); + }; + + /** + * Returns `true` if you can still scroll by either parameter; in other words, you haven't reached the end of the file or line. + * @param {Number} deltaX The x value to scroll by + * @param {Number} deltaY The y value to scroll by + * + * + * @returns {Boolean} + **/ + this.isScrollableBy = function(deltaX, deltaY) { + if (deltaY < 0 && this.getScrollTop() >= 1) + return true; + if (deltaY > 0 && this.getScrollTop() + this.$size.scrollerHeight - this.layerConfig.maxHeight < -1) + return true; + if (deltaX < 0 && this.getScrollLeft() >= 1) + return true; + if (deltaX > 0 && this.getScrollLeft() + this.$size.scrollerWidth - this.layerConfig.maxWidth < -1) + return true; + }; + + // @todo this code can be compressed + this.screenToTextCoordinates = function(x, y) { + var canvasPos = this.scroller.getBoundingClientRect(); + y -= canvasPos.top; + x -= canvasPos.left; + + return { + x : x + this.scrollLeft, + y : y + this.scrollTop + }; + }; + + /** + * Returns an object containing the `pageX` and `pageY` coordinates of the document position. + * @param {Number} row The document row position + * @param {Number} column The document column position + * + * + * + * @returns {Object} + **/ + this.textToScreenCoordinates = function(row, column) { + throw new Error(); + + }; + + this.findNodeAt = function(x, y, coords) { + + }; + + this.$moveTextAreaToCursor = function(){}; + + /** + * + * Focuses the current container. + **/ + this.visualizeFocus = function() { + dom.addCssClass(this.container, "ace_tree_focus"); + }; + + /** + * + * Blurs the current container. + **/ + this.visualizeBlur = function() { + dom.removeCssClass(this.container, "ace_tree_focus"); + }; + + /** + * [Sets a new theme for the editor. `theme` should exist, and be a directory path, like `ace/theme/textmate`.]{: #VirtualRenderer.setTheme} + * @param {String} theme The path to a theme + * @param {Function} cb optional callback + * + **/ + this.setTheme = function(theme, cb) { + var _self = this; + this.$themeValue = theme; + _self._dispatchEvent('themeChange',{theme:theme}); + + if (!theme || typeof theme == "string") { + var moduleName = theme || "ace/theme/textmate"; + config.loadModule(["theme", moduleName], afterLoad); + } else { + afterLoad(theme); + } + + function afterLoad(module) { + if (_self.$themeValue != theme) + return cb && cb(); + if (!module.cssClass) + return; + dom.importCssString( + module.cssText, + module.cssClass, + _self.container.ownerDocument + ); + + if (_self.theme) + dom.removeCssClass(_self.container, _self.theme.cssClass); + + // this is kept only for backwards compatibility + _self.$theme = module.cssClass; + + _self.theme = module; + dom.addCssClass(_self.container, module.cssClass); + dom.setCssClass(_self.container, "ace_dark", module.isDark); + + var padding = module.padding || 4; + if (_self.$padding && padding != _self.$padding) + _self.setPadding(padding); + + // force re-measure of the gutter width + if (_self.$size) { + _self.$size.width = 0; + _self.onResize(); + } + + _self._dispatchEvent('themeLoaded', {theme:module}); + cb && cb(); + } + }; + + /** + * [Returns the path of the current theme.]{: #VirtualRenderer.getTheme} + * @returns {String} + **/ + this.getTheme = function() { + return this.$themeValue; + }; + + // Methods allows to add / remove CSS classnames to the editor element. + // This feature can be used by plug-ins to provide a visual indication of + // a certain mode that editor is in. + + /** + * [Adds a new class, `style`, to the editor.]{: #VirtualRenderer.setStyle} + * @param {String} style A class name + * + * + **/ + this.setStyle = function setStyle(style, include) { + dom.setCssClass(this.container, style, include !== false); + }; + + /** + * [Removes the class `style` from the editor.]{: #VirtualRenderer.unsetStyle} + * @param {String} style A class name + * + * + **/ + this.unsetStyle = function unsetStyle(style) { + dom.removeCssClass(this.container, style); + }; + + /** + * + * Destroys the text and Caret layers for this renderer. + **/ + this.destroy = function() { + window.removeEventListener("focus", this.$windowFocus); + + this.$cellLayer.destroy(); + }; + +}).call(VirtualRenderer.prototype); + +config.defineOptions(VirtualRenderer.prototype, "renderer", { + animatedScroll: {initialValue: true}, + showInvisibles: { + set: function(value) { + if (this.$cellLayer.setShowInvisibles(value)) + this.$loop.schedule(this.CHANGE_TEXT); + }, + initialValue: false + }, + showPrintMargin: { + set: function() { this.$updatePrintMargin(); }, + initialValue: true + }, + printMarginColumn: { + set: function() { this.$updatePrintMargin(); }, + initialValue: 80 + }, + printMargin: { + set: function(val) { + if (typeof val == "number") + this.$printMarginColumn = val; + this.$showPrintMargin = !!val; + this.$updatePrintMargin(); + }, + get: function() { + return this.$showPrintMargin && this.$printMarginColumn; + } + }, + displayIndentGuides: { + set: function(show) { + if (this.$cellLayer.setDisplayIndentGuides(show)) + this.$loop.schedule(this.CHANGE_TEXT); + }, + initialValue: true + }, + hScrollBarAlwaysVisible: { + set: function(alwaysVisible) { + this.$hScrollBarAlwaysVisible = alwaysVisible; + if (!this.$hScrollBarAlwaysVisible || !this.$horizScroll) + this.$loop.schedule(this.CHANGE_SCROLL); + }, + initialValue: false + }, + vScrollBarAlwaysVisible: { + set: function(val) { + if (!this.$vScrollBarAlwaysVisible || !this.$vScroll) + this.$loop.schedule(this.CHANGE_SCROLL); + }, + initialValue: false + }, + fontSize: { + set: function(size) { + if (typeof size == "number") + size = size + "px"; + this.container.style.fontSize = size; + this.updateFontSize(); + }, + initialValue: 12 + }, + fontFamily: { + set: function(name) { + this.container.style.fontFamily = name; + this.updateFontSize(); + } + }, + maxLines: { + set: function(val) { + this.updateFull(); + } + }, + minLines: { + set: function(val) { + this.updateFull(); + } + }, + scrollPastEnd: { + set: function(val) { + val = +val || 0; + if (this.$scrollPastEnd == val) + return; + this.$scrollPastEnd = val; + this.$loop.schedule(this.CHANGE_SCROLL); + }, + initialValue: 0, + handlesSet: true + } +}); + +exports.VirtualRenderer = VirtualRenderer; +}); diff --git a/node_modules/ace_tree/lib/ace_tree/virtual_renderer_test.js b/node_modules/ace_tree/lib/ace_tree/virtual_renderer_test.js new file mode 100644 index 00000000..e8a8fcbd --- /dev/null +++ b/node_modules/ace_tree/lib/ace_tree/virtual_renderer_test.js @@ -0,0 +1,86 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Distributed under the BSD license: + * + * Copyright (c) 2010, Ajax.org B.V. + * All rights reserved. + * + * 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 Ajax.org B.V. 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 AJAX.ORG B.V. 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. + * + * ***** END LICENSE BLOCK ***** */ + +if (typeof process !== "undefined") { + require("amd-loader"); + require("./test/mockdom"); +} + +define(function(require, exports, module) { +"use strict"; + +var EditSession = require("./edit_session").EditSession; +var VirtualRenderer = require("./virtual_renderer").VirtualRenderer; +var assert = require("./test/assertions"); + +module.exports = { + "test: screen2text the column should be rounded to the next character edge" : function() { + var el = document.createElement("div"); + + if (!el.getBoundingClientRect) { + console.log("Skipping test: This test only runs in the browser"); + return; + } + + el.style.left = "20px"; + el.style.top = "30px"; + el.style.width = "300px"; + el.style.height = "100px"; + document.body.appendChild(el); + + var renderer = new VirtualRenderer(el); + renderer.setPadding(0); + renderer.setSession(new EditSession("1234")); + + var r = renderer.scroller.getBoundingClientRect(); + function testPixelToText(x, y, row, column) { + assert.position(renderer.screenToTextCoordinates(x+r.left, y+r.top), row, column); + } + + renderer.characterWidth = 10; + renderer.lineHeight = 15; + + testPixelToText(4, 0, 0, 0); + testPixelToText(5, 0, 0, 1); + testPixelToText(9, 0, 0, 1); + testPixelToText(10, 0, 0, 1); + testPixelToText(14, 0, 0, 1); + testPixelToText(15, 0, 0, 2); + document.body.removeChild(el); + } + + // change tab size after setDocument (for text layer) +}; + +}); + +if (typeof module !== "undefined" && module === require.main) { + require("asyncjs").test.testcase(module.exports).exec() +} diff --git a/node_modules/ace_tree/list.txt b/node_modules/ace_tree/list.txt new file mode 100644 index 00000000..8d0dcff1 --- /dev/null +++ b/node_modules/ace_tree/list.txt @@ -0,0 +1,1318 @@ +system:Predicate +system:Predicate:fullName +system:RefModePredicate +system:RefModePredicate:$_none +system:Entity +system:Entity:$_none +system:NameSpace +system:NameSpace:name +system:TypeSpace +system:TypeSpace:name +system:MappingPredicate +system:MappingPredicate:$_none +system:PulsePredicate +system:PulsePredicate:$_none +system:TypeHierarchy +system:TypeHierarchy:name +system:PredicateDerivationType +system:PredicateDerivationType:name +system:CompositionType +system:CompositionType:name +system:StorageStructure +system:StorageStructure:name +system:StorageSpace +system:StorageSpace:name +system:PartitioningState +system:PartitioningState:name +system:LockingPolicy +system:LockingPolicy:name +system:TypeOrder +system:TypeOrder:id +system:NativeType +system:NativeType:name +system:TypeMapNode +system:TypeMapNode:id +system:AggMethod +system:AggMethod:name +system:SpreadMethod +system:SpreadMethod:name +system:RecalcAggMode +system:RecalcAggMode:name +system:HorizontalAlignment +system:HorizontalAlignment:name +system:Alignment +system:Alignment:name +system:CompositeAggMethod +system:CompositeAggMethod:$_none +system:CompositeSpreadMethod +system:CompositeSpreadMethod:$_none +system:Replication +system:Replication:name +system:TaskTiming +system:TaskTiming:id +system:WorkSpaceProperties +system:WorkSpaceProperties:name +system:ExternalWorkSpace +system:ExternalWorkSpace:url +system:RegisteredLibraries +system:RegisteredLibraries:path +system:TypeMapSignature +system:TypeMapSignature:name +system:AggSignature +system:AggSignature:name +system:InstalledProjects +system:InstalledProjects:name +system:Predicate:name +system:Predicate:label +system:Predicate:storageSpace +system:Predicate:storage +system:Predicate:chunkSize +system:Predicate:partitioning +system:Predicate:numPartitions +system:Predicate:lockingPolicy +system:Predicate:key +system:Predicate:value +system:Predicate:isOrdered +system:Predicate:capacity +system:Predicate:maxIndex +system:Predicate:maxRefMode +system:Predicate:defaultValue +system:Predicate:defaultValueIndex +system:Predicate:format +system:Predicate:cellStyleName +system:Predicate:valueConstraint +system:Predicate:displayWidth +system:Predicate:readOnly +system:Predicate:allowsNulls +system:Predicate:horizontalAlignment +system:Predicate:nameSpace +system:Predicate:description +system:Predicate:displayName +system:Predicate:isOneToOneMapping +system:Predicate:isDisjoint +system:Predicate:allowMissingData +system:Predicate:procedure +system:Predicate:derivationType +system:Predicate:compositionType +system:Predicate:recalcAggMode +system:Predicate:allowedAggMethods +system:Predicate:defaultAggMethod +system:Predicate:allowedSpreadMethods +system:Predicate:defaultSpreadMethod +system:Predicate:lastUpdate +system:Predicate:lastGC +system:Predicate:isSkolem +system:Predicate:isAutoNumbered +system:Predicate:remoteRef +system:Predicate:percentAggDimension +system:Predicate:percentAggBase +system:Entity:refMode +system:Entity:baseType +system:Entity:subtypes +system:Entity:labelPredicate +system:Entity:securityPredicate +system:Entity:kind +system:Entity:lockingPriority +system:TypeSpace:types +system:TypeSpace:roles +system:TypeSpace:labels +system:NameSpace:label +system:NameSpace:parent +system:TypeHierarchy:label +system:TypeHierarchy:root +system:TypeHierarchy:mapNames +system:TypeHierarchy:typeNames +system:TypeMapNode:mappingPredicate +system:TypeMapNode:nextNodePredicate +system:MappingPredicate:fromType +system:MappingPredicate:toType +system:CompositeAggMethod:aggMethod +system:CompositeAggMethod:kind +system:CompositeAggMethod:role +system:CompositeSpreadMethod:spreadMethod +system:CompositeSpreadMethod:kind +system:CompositeSpreadMethod:role +system:deltaBackup +system:float32Precision +system:float64Precision +system:decimal64Precision +system:decimal128Precision +system:Replication:url +system:Replication:portRange +system:Replication:version +system:Replication:active +system:TaskTiming:wallTime +system:workSpaceInfo +system:ExternalWorkSpace:localPath +system:nameSpaceToWorkSpaceMap +system:TypeMapSignature:typeMappingPredicates +system:AggMethod:types +system:AggSignature:blockName +system:AggSignature:sig +system:AggSignature:resultPredName +system:AggSignature:description +system:AggSignature:basePredName +system:AggSignature:refMeasureName +system:AggSignature:instantiate +system:AggSignature:error +system:AggSignature:isRecalc +system:AggSignature:aggMethods +system:AggSignature:spreadMethods +system:AggSignature:hierarchies +system:AggSignature:sequence +system:AggSignature:levelTargetIndices +system:InstalledProjects:hash +system:logic:Block:ExecutionMode +system:logic:Block:ExecutionMode:name +system:logic:Block:FetchMode +system:logic:Block:FetchMode:name +system:logic:Block:Lifetime +system:logic:Block:Lifetime:name +system:logic:Block:SortType +system:logic:Block:SortType:name +system:logic:LogicBlock +system:logic:LogicBlockId +system:logic:ActiveBlock +system:logic:ActiveBlock:$_none +system:logic:DerivedPredicate +system:logic:DerivedPredicate:$_none +system:logic:MetaPredicate +system:logic:MetaPredicate:$_none +system:logic:NamedProgram +system:logic:namedProgramName +system:logic:WatchPred +system:logic:WatchPred:$_none +system:counter:counters +system:counter:counters_name +system:protoagg:predicateName +system:logic:Block:defaultFetchMode +system:logic:Block:defaultPageSize +system:logic:Block:executionMode +system:logic:Block:lifetime +system:logic:Block:localPredicateNames +system:logic:Block:sortOrder +system:logic:Block:sortType +system:logic:executableProgram +system:logic:firstMapFor +system:logic:historicalLocks +system:logic:lastMapFor +system:logic:logicBlockHasPredicates +system:logic:logicBlockLB0Text +system:logic:logicBlockName +system:logic:logicBlockProtoExecutableProgram +system:logic:logicBlockSourceText +system:logic:namedProgramLB0Source +system:logic:namedProgramSource +system:logic:programVersion +system:versionedType +system:counter:counter_values +system:Predicate:isBuiltIn +system:Predicate:isRemote +system:Predicate:isDerivedOnly +system:Predicate:isDisplayable +system:Predicate:isDisplayableAppPredicate +system:Predicate:useMultiLineEditor +system:Predicate:isRefMode +system:Predicate:keyArity +system:Predicate:_keyArity +system:Entity:appAttributes +system:Predicate:isMeasureBase +system:Predicate:_keyArity:_derivationCounts +system:logic:Block:displayName +system:InstalledProjects:timeStamp +system:InstalledProjects:blocks +system:Predicate:remoteRefMap +system:MessageProtocol +system:MessageProtocol:name +system:MessageProtocol:descriptor +$__protocol_GetDescriptor:_name +$__protocol_GetDescriptor:_descriptor +$__protocol_AddDescriptor:_name +$__protocol_AddDescriptor:_descriptor +bloxweb:MessageProtocol +bloxweb:MessageProtocolId +bloxweb:MessageProtocol:name +bloxweb:MessageProtocol:descriptor_bytes +bloxweb:MessageProtocolId:_$inverse +bloxweb:internal:Encoding +bloxweb:internal:Service +bloxweb:internal:ServiceId +bloxweb:internal:CORSRule +bloxweb:internal:CORSRuleId +bloxweb:internal:ServiceParameter +bloxweb:internal:ServiceParameterId +bloxweb:internal:ServiceInstance +bloxweb:internal:ServiceInstanceId +bloxweb:internal:HandlerConfig +bloxweb:internal:HandlerConfigId +bloxweb:internal:ProxyHandler +bloxweb:internal:ProxyHandlerId +bloxweb:internal:GlobalProtoBufHandler +bloxweb:internal:GlobalProtoBufHandlerId +bloxweb:internal:SQSS3ProxyHandler +bloxweb:internal:SQSS3ProxyHandlerId +bloxweb:internal:TransferProtocol +bloxweb:internal:TransferProtocolId +bloxweb:internal:SQS_S3 +bloxweb:internal:SQS_S3Id +bloxweb:internal:SQSHeader +bloxweb:internal:SQSHeaderId +bloxweb:internal:StatusService +bloxweb:internal:StatusServiceId +bloxweb:internal:Realm +bloxweb:internal:RealmId +bloxweb:internal:Mechanism +bloxweb:internal:MechanismId +bloxweb:internal:Option +bloxweb:internal:OptionId +bloxweb:internal:ServiceClient +bloxweb:internal:ServiceClientId +bloxweb:internal:Transport +bloxweb:internal:TransportId +bloxweb:internal:TCPTransport +bloxweb:internal:TCPTransportId +bloxweb:internal:SQSTransport +bloxweb:internal:SQSTransportId +bloxweb:internal:Encoding:value +bloxweb:internal:Service:prefix +bloxweb:internal:Service:handler +bloxweb:internal:Service:handler_config +bloxweb:internal:Service:block_name +bloxweb:internal:Service:request_protocol +bloxweb:internal:Service:request_message +bloxweb:internal:Service:response_protocol +bloxweb:internal:Service:response_message +bloxweb:internal:Service:file_binding +bloxweb:internal:Service:request_encoding +bloxweb:internal:Service:response_encoding +bloxweb:internal:Service:transfer_protocol +bloxweb:internal:Service:status_service +bloxweb:internal:Service:authenticator +bloxweb:internal:Service:readonly +bloxweb:internal:Service:exclusive +bloxweb:internal:Service:parameter +bloxweb:internal:Service:group +bloxweb:internal:Service:disabled_status +bloxweb:internal:Service:cors_rule +bloxweb:internal:Service:ignore_authentication_requirement +bloxweb:internal:CORSRule:allowed_origin +bloxweb:internal:CORSRule:allowed_method +bloxweb:internal:CORSRule:allowed_header +bloxweb:internal:ServiceParameter:key +bloxweb:internal:ServiceParameter:value +bloxweb:internal:ServiceInstance:workspace +bloxweb:internal:ServiceInstance:service +bloxweb:internal:HandlerConfig:proxy +bloxweb:internal:HandlerConfig:global_protobuf +bloxweb:internal:HandlerConfig:sqs_s3_proxy +bloxweb:internal:ProxyHandler:target +bloxweb:internal:ProxyHandler:host +bloxweb:internal:ProxyHandler:prefix +bloxweb:internal:GlobalProtoBufHandler:target +bloxweb:internal:GlobalProtoBufHandler:accept_failure +bloxweb:internal:SQSS3ProxyHandler:request_queue +bloxweb:internal:SQSS3ProxyHandler:response_queue +bloxweb:internal:SQSS3ProxyHandler:bucket +bloxweb:internal:SQSS3ProxyHandler:enc_key_name +bloxweb:internal:TransferProtocol:http +bloxweb:internal:TransferProtocol:sqs_s3 +bloxweb:internal:SQS_S3:queue_name +bloxweb:internal:SQS_S3:bucket_name +bloxweb:internal:SQS_S3:sqs_endpoint +bloxweb:internal:SQS_S3:s3_endpoint +bloxweb:internal:SQS_S3:s3_region +bloxweb:internal:SQS_S3:delete_from_sqs +bloxweb:internal:SQS_S3:delete_from_s3 +bloxweb:internal:SQS_S3:access_key +bloxweb:internal:SQS_S3:secret_key +bloxweb:internal:SQSHeader:message_key +bloxweb:internal:SQSHeader:tenant +bloxweb:internal:StatusService:primary_queue_name +bloxweb:internal:StatusService:backup_queue_name +bloxweb:internal:StatusService:access_key +bloxweb:internal:StatusService:secret_key +bloxweb:internal:Realm:name +bloxweb:internal:Realm:config +bloxweb:internal:Realm:stateful +bloxweb:internal:Realm:session_key +bloxweb:internal:Realm:mechanism +bloxweb:internal:Realm:options +bloxweb:internal:Mechanism:clazz +bloxweb:internal:Mechanism:options +bloxweb:internal:Option:key +bloxweb:internal:Option:value +bloxweb:internal:ServiceClient:uri +bloxweb:internal:ServiceClient:transport +bloxweb:internal:Transport:tcp +bloxweb:internal:Transport:sqs +bloxweb:internal:ServiceId:_$inverse +bloxweb:internal:CORSRuleId:_$inverse +bloxweb:internal:ServiceParameterId:_$inverse +bloxweb:internal:ServiceInstanceId:_$inverse +bloxweb:internal:HandlerConfigId:_$inverse +bloxweb:internal:ProxyHandlerId:_$inverse +bloxweb:internal:GlobalProtoBufHandlerId:_$inverse +bloxweb:internal:SQSS3ProxyHandlerId:_$inverse +bloxweb:internal:TransferProtocolId:_$inverse +bloxweb:internal:SQS_S3Id:_$inverse +bloxweb:internal:SQSHeaderId:_$inverse +bloxweb:internal:StatusServiceId:_$inverse +bloxweb:internal:RealmId:_$inverse +bloxweb:internal:MechanismId:_$inverse +bloxweb:internal:OptionId:_$inverse +bloxweb:internal:ServiceClientId:_$inverse +bloxweb:internal:TransportId:_$inverse +bloxweb:internal:TCPTransportId:_$inverse +bloxweb:internal:SQSTransportId:_$inverse +bloxweb:ProtoBufMetaRequest +bloxweb:ProtoBufMetaRequestId +bloxweb:ProtoBufProtocolRequest +bloxweb:ProtoBufProtocolRequestId +bloxweb:ProtoBufMetaResponse +bloxweb:ProtoBufMetaResponseId +bloxweb:ProtoBufProtocolResponse +bloxweb:ProtoBufProtocolResponseId +bloxweb:ProtoBufMetaRequest:protocol +bloxweb:ProtoBufMetaResponse:protocol +bloxweb:ProtoBufProtocolResponse:request_message_name +bloxweb:ProtoBufProtocolResponse:request_descriptor +bloxweb:ProtoBufProtocolResponse:response_message_name +bloxweb:ProtoBufProtocolResponse:response_descriptor +bloxweb:ProtoBufMetaRequestId:_$inverse +bloxweb:ProtoBufProtocolRequestId:_$inverse +bloxweb:ProtoBufMetaResponseId:_$inverse +bloxweb:ProtoBufProtocolResponseId:_$inverse +bloxweb:http:Request +bloxweb:http:RequestId +bloxweb:http:Response +bloxweb:http:ResponseId +bloxweb:http:Field +bloxweb:http:FieldId +bloxweb:http:RequestURI +bloxweb:http:RequestURIId +bloxweb:http:Request:method +bloxweb:http:Request:uri +bloxweb:http:Request:header +bloxweb:http:Response:status_code +bloxweb:http:Response:header +bloxweb:http:Field:name +bloxweb:http:Field:value +bloxweb:http:RequestURI:full +bloxweb:http:RequestURI:service_prefix +bloxweb:http:RequestURI:extra_path +bloxweb:http:RequestURI:parameter +bloxweb:http:RequestId:_$inverse +bloxweb:http:ResponseId:_$inverse +bloxweb:http:FieldId:_$inverse +bloxweb:http:RequestURIId:_$inverse +bloxweb:authenticationKey +bloxweb:auth:username +$bloxweb_service_query:_services +$bloxweb_service_query:_realms +$bloxweb_service_query:_protocols +bloxweb:delim:EntityCreation +bloxweb:delim:FileBinding +bloxweb:delim:FileBindingId +bloxweb:delim:FileDefinition +bloxweb:delim:FileDefinitionId +bloxweb:delim:FileColumn +bloxweb:delim:FileColumnId +bloxweb:delim:PredicateBinding +bloxweb:delim:PredicateBindingId +bloxweb:delim:ColumnBinding +bloxweb:delim:ColumnBindingId +bloxweb:delim:Transform +bloxweb:delim:TransformId +bloxweb:delim:Format +bloxweb:delim:FormatId +bloxweb:delim:EntityCreation:value +bloxweb:delim:FileBinding:name +bloxweb:delim:FileBinding:file +bloxweb:delim:FileBinding:predicate +bloxweb:delim:FileDefinition:name +bloxweb:delim:FileDefinition:delimiter +bloxweb:delim:FileDefinition:column +bloxweb:delim:FileColumn:header +bloxweb:delim:FileColumn:format +bloxweb:delim:FileColumn:required +bloxweb:delim:FileColumn:can_be_absent +bloxweb:delim:PredicateBinding:predicate_name +bloxweb:delim:PredicateBinding:column +bloxweb:delim:PredicateBinding:export +bloxweb:delim:PredicateBinding:filter +bloxweb:delim:PredicateBinding:incremental +bloxweb:delim:PredicateBinding:negated +bloxweb:delim:ColumnBinding:header +bloxweb:delim:ColumnBinding:entity_creation +bloxweb:delim:ColumnBinding:import_function +bloxweb:delim:ColumnBinding:import_function_inverse +bloxweb:delim:ColumnBinding:export_function +bloxweb:delim:ColumnBinding:export_function_inverse +bloxweb:delim:ColumnBinding:transform +bloxweb:delim:Transform:id +bloxweb:delim:Transform:param +bloxweb:delim:Format:id +bloxweb:delim:Format:param +bloxweb:delim:FileBindingId:_$inverse +bloxweb:delim:FileDefinitionId:_$inverse +bloxweb:delim:FileColumnId:_$inverse +bloxweb:delim:PredicateBindingId:_$inverse +bloxweb:delim:ColumnBindingId:_$inverse +bloxweb:delim:TransformId:_$inverse +bloxweb:delim:FormatId:_$inverse +bloxweb:delim:runtime:has_import_errors +bloxweb:delim:runtime:checked_read_string +bloxweb:delim:runtime:checked_read_alphanum +bloxweb:delim:runtime:checked_read_integer +bloxweb:delim:runtime:checked_read_float +bloxweb:delim:runtime:checked_read_nonnegative_integer +bloxweb:delim:runtime:checked_read_positive_integer +bloxweb:delim:schema:file_definition +bloxweb:delim:schema:column +bloxweb:delim:schema:format +bloxweb:delim:schema:format_datetime +bloxweb:delim:schema:format_date +bloxweb:delim:schema:format_boolean +bloxweb:delim:schema:file_definition_by_name +bloxweb:delim:schema:file_delimiter +bloxweb:delim:schema:file_column +bloxweb:delim:schema:column_header +bloxweb:delim:schema:column_format +bloxweb:delim:schema:column_optional +bloxweb:delim:schema:column_can_be_absent +bloxweb:delim:schema:datetime_format +bloxweb:delim:schema:date_format +bloxweb:delim:schema:boolean_format +bloxweb:delim:schema:format_alphanumeric +bloxweb:delim:schema:format_empty_string +bloxweb:delim:schema:format_string +bloxweb:delim:schema:format_integer +bloxweb:delim:schema:format_nonnegative_integer +bloxweb:delim:schema:format_positive_integer +bloxweb:delim:schema:format_float +bloxweb:delim:schema:file_definition_name +bloxweb:delim:schema:column_by_name +bloxweb:delim:schema:file_columns +bloxweb:delim:schema:column_file_definition +bloxweb:delim:binding:file_binding +bloxweb:delim:binding:predicate_binding +bloxweb:delim:binding:column_binding +bloxweb:delim:binding:transformation +bloxweb:delim:binding:file_binding_by_name +bloxweb:delim:binding:file_binding_definition_name +bloxweb:delim:binding:predicate_binding_name +bloxweb:delim:binding:predicate_binding_by_name +bloxweb:delim:binding:predicate_binding_by_name_index +bloxweb:delim:binding:predicate_binding_export +bloxweb:delim:binding:predicate_binding_filter +bloxweb:delim:binding:predicate_binding_negated +bloxweb:delim:binding:predicate_binding_incremental +bloxweb:delim:binding:column_binding_by_arg +bloxweb:delim:binding:column_binding_header +bloxweb:delim:binding:column_binding_entity_creation +bloxweb:delim:binding:column_binding_transformation +bloxweb:delim:binding:transformation_id +bloxweb:delim:binding:transformation_param +bloxweb:delim:binding:column_binding_function +bloxweb:delim:binding:column_binding_function_inverse +bloxweb:delim:binding:column_binding_import_function +bloxweb:delim:binding:column_binding_import_function_inverse +bloxweb:delim:binding:column_binding_export_function +bloxweb:delim:binding:column_binding_export_function_inverse +bloxweb:delim:binding:predicate_binding_file_binding +bloxweb:delim:binding:file_binding_name +bloxweb:delim:binding:file_binding_definition +bloxweb:delim:binding:predicate_bindings +bloxweb:delim:binding:column_binding_column +bloxweb:delim:binding:entity_creation +bloxweb:delim:binding:column_binding_file_definition +bloxweb:delim:binding:predicate_binding_file_definition +bloxweb:delim:query:bindings +bloxweb:delim:query:proto_file_binding +bloxweb:delim:query:proto_file_definition +bloxweb:delim:query:proto_file_column +bloxweb:delim:query:proto_predicate_binding +bloxweb:delim:query:proto_column_binding +bloxweb:delim:query:proto_format +bloxweb:delim:query:format_to_string +bloxweb:delim:query:proto_transformation +bloxweb:delim:binding_abbr:file_binding_predicate +bloxweb:delim:binding_abbr:file_binding_predicate_columns +bloxweb:delim:binding_abbr:predicate_binding_columns +bloxweb:delim:binding_abbr:column_binding_headers +bloxweb:delim:binding_abbr:column_binding_transform +bloxweb:delim:binding_abbr:file_binding_entity_creation +bloxweb:delim:binding_abbr:file_binding_column_entity_creation +bloxweb:delim:binding_abbr:predicate_binding_entity_creation +bloxweb:delim:binding_abbr:cons_transformation +bloxweb:delim:binding_abbr:transform_id +bloxweb:delim:binding_abbr:transform_arg +bloxweb:delim:binding_abbr:str_transform_args +bloxweb:delim:binding_abbr:str_transform +bloxweb:delim:binding_abbr:char_at +bloxweb:delim:filter:filter_by_columns +bloxweb:delim:schema_abbr:column_headers +bloxweb:delim:schema_abbr:column_formats +bloxweb:delim:schema_abbr:file_column_format +bloxweb:delim:schema_abbr:column_format_str +bloxweb:delim:schema_abbr:file_columns_required +bloxweb:delim:schema_abbr:file_column_required +bloxweb:delim:schema_abbr:file_columns_optional +bloxweb:delim:schema_abbr:file_column_optional +bloxweb:delim:schema_abbr:file_columns_can_be_absent +bloxweb:delim:schema_abbr:file_column_can_be_absent +bloxweb:delim:schema_abbr:column_required +bloxweb:delim:schema_abbr:cons_format_datetime +bloxweb:delim:schema_abbr:cons_format_date +bloxweb:delim:schema_abbr:cons_format_boolean +bloxweb:delim:schema_abbr:file_has_column_required +bloxweb:delim:schema_abbr:format_lookup +bloxweb:config:service:service +bloxweb:config:service:workspace_service +bloxweb:config:service:custom_handler +bloxweb:config:service:default_handler +bloxweb:config:service:service_prefix +bloxweb:config:service:auth_realm +bloxweb:config:service:readonly +bloxweb:config:service:exclusive +bloxweb:config:service:inactive_block_name +bloxweb:config:service:disabled_status +bloxweb:config:service:service_parameter +bloxweb:config:service:group +bloxweb:config:service:ignore_authentication_requirement +bloxweb:config:service:handler +bloxweb:config:protobuf:protobuf_service +bloxweb:config:protobuf:default_protobuf_service +bloxweb:config:protobuf:protobuf_request_encoding +bloxweb:config:protobuf:protobuf_request_protocol +bloxweb:config:protobuf:protobuf_request_message +bloxweb:config:protobuf:protobuf_response_encoding +bloxweb:config:protobuf:protobuf_response_protocol +bloxweb:config:protobuf:protobuf_response_message +bloxweb:config:protobuf:auto_encoding +bloxweb:config:protobuf:json_encoding +bloxweb:config:protobuf:binary_encoding +bloxweb:config:protobuf:supported_encoding +bloxweb:config:global_protobuf:global_protobuf_service +bloxweb:config:global_protobuf:service_client +bloxweb:config:global_protobuf:global_protobuf_target +bloxweb:config:global_protobuf:service_client_uri +bloxweb:config:global_protobuf:accept_failure +bloxweb:config:global_protobuf_abbr:global_protobuf_target_uri +bloxweb:config:global_protobuf_abbr:service_client_by_uri +bloxweb:config:query_protocols:_result +bloxweb:config:query_protocols:cons +bloxweb:config:proxy:proxy_service +bloxweb:config:proxy:exact_proxy +bloxweb:config:proxy:transparent_proxy +bloxweb:config:proxy:proxy_target +bloxweb:config:proxy:proxy_host +bloxweb:config:proxy:proxy_prefix +bloxweb:config:cors:rule +bloxweb:config:cors:rule_by_name +bloxweb:config:cors:allowed_origin +bloxweb:config:cors:allowed_method +bloxweb:config:cors:allowed_header +bloxweb:config:cors:with_rule +bloxweb:config:cors:with_rule_by_name +bloxweb:config:protobuf_abbr:protobuf_encoding +bloxweb:config:protobuf_abbr:protobuf_protocol +bloxweb:config:protobuf_abbr:protobuf_message +bloxweb:config:auth:realm +bloxweb:config:auth:realm_name +bloxweb:config:auth:realm_config +bloxweb:config:auth:realm_option +bloxweb:config:auth:realm_mechanism_class +bloxweb:config:auth:realm_mechanism_option +bloxweb:config:auth:realm_session_key +bloxweb:config:query_realms:_result +bloxweb:config:query_realms:cons_realm +bloxweb:config:query_realms:options +bloxweb:config:query_realms:cons_option +bloxweb:config:query_realms:mechanism_options +bloxweb:config:query_realms:cons_mechanism_option +bloxweb:config:query_realms:cons_mechanism +bloxweb:config:version:version +bloxweb:config:user:current_user_service +bloxweb:config:service_abbr:service_by_prefix +bloxweb:config:service_abbr:service_by_group +bloxweb:config:delim:delim_service +bloxweb:config:delim:delim_txn_service +bloxweb:config:delim:delim_file_binding +bloxweb:config:delim:abort_on_error +bloxweb:config:query_services:_result +bloxweb:config:query_services:cons_service +bloxweb:config:query_services:cons_handler_config +bloxweb:config:query_services:cons_parameter +bloxweb:config:query_services:cons_group +bloxweb:config:query_services:cons_global_config +bloxweb:config:query_services:cons_service_client +bloxweb:config:query_services:cons_proxy_config +bloxweb:config:query_services:_cons_cors_rule +bloxweb:config:query_services:_cons_allowed_origin +bloxweb:config:query_services:_cons_allowed_method +bloxweb:config:query_services:_cons_allowed_header +bloxweb:config:auth_abbr:realm_by_name +bloxweb:measure:Op:Kind +bloxweb:measure:Term:Kind +bloxweb:measure:Comparison:Kind +bloxweb:measure:AggExpr:Grouping:Kind +bloxweb:measure:AggExpr:Grouping +bloxweb:measure:AggExpr:GroupingId +bloxweb:measure:AggExpr:Method +bloxweb:measure:Request:Kind +bloxweb:measure:Dimension:Hierarchy:Path +bloxweb:measure:Dimension:Hierarchy:PathId +bloxweb:measure:ModelRequest:Kind +bloxweb:measure:MeasureExpr:Kind +bloxweb:measure:CompositeExpr:Kind +bloxweb:measure:Dimension:Hierarchy +bloxweb:measure:Dimension:HierarchyId +bloxweb:measure:Dimension:Edge +bloxweb:measure:Dimension:EdgeId +bloxweb:measure:Dimension:Level +bloxweb:measure:Dimension:LevelId +bloxweb:measure:Dimension:Kind +bloxweb:measure:Type +bloxweb:measure:MeasureModel +bloxweb:measure:MeasureModelId +bloxweb:measure:OpDef +bloxweb:measure:OpDefId +bloxweb:measure:Hypercube +bloxweb:measure:HypercubeId +bloxweb:measure:MetricGroup +bloxweb:measure:MetricGroupId +bloxweb:measure:Dimensionality +bloxweb:measure:DimensionalityId +bloxweb:measure:Metric +bloxweb:measure:MetricId +bloxweb:measure:Predicate +bloxweb:measure:PredicateId +bloxweb:measure:Dialogue +bloxweb:measure:DialogueId +bloxweb:measure:MultiDimensionalLevelMap +bloxweb:measure:MultiDimensionalLevelMapId +bloxweb:measure:Dimension +bloxweb:measure:DimensionId +bloxweb:measure:Attribute +bloxweb:measure:AttributeId +bloxweb:measure:QualifiedLevel +bloxweb:measure:QualifiedLevelId +bloxweb:measure:Intersection +bloxweb:measure:IntersectionId +bloxweb:measure:Binding +bloxweb:measure:BindingId +bloxweb:measure:ModelRequest +bloxweb:measure:ModelRequestId +bloxweb:measure:ModelResponse +bloxweb:measure:ModelResponseId +bloxweb:measure:Request +bloxweb:measure:RequestId +bloxweb:measure:InstallRequest +bloxweb:measure:InstallRequestId +bloxweb:measure:QueryRequest +bloxweb:measure:QueryRequestId +bloxweb:measure:KeyRequest +bloxweb:measure:KeyRequestId +bloxweb:measure:ParamBinding +bloxweb:measure:ParamBindingId +bloxweb:measure:Response +bloxweb:measure:ResponseId +bloxweb:measure:Column +bloxweb:measure:ColumnId +bloxweb:measure:BoolColumn +bloxweb:measure:BoolColumnId +bloxweb:measure:IntColumn +bloxweb:measure:IntColumnId +bloxweb:measure:FloatColumn +bloxweb:measure:FloatColumnId +bloxweb:measure:StringColumn +bloxweb:measure:StringColumnId +bloxweb:measure:DecimalColumn +bloxweb:measure:DecimalColumnId +bloxweb:measure:MeasureExpr +bloxweb:measure:MeasureExprId +bloxweb:measure:WidenExpr +bloxweb:measure:WidenExprId +bloxweb:measure:DiceExpr +bloxweb:measure:DiceExprId +bloxweb:measure:AttributeExpr +bloxweb:measure:AttributeExprId +bloxweb:measure:Op +bloxweb:measure:OpId +bloxweb:measure:OpExpr +bloxweb:measure:OpExprId +bloxweb:measure:CompositeExpr +bloxweb:measure:CompositeExprId +bloxweb:measure:MetricExpr +bloxweb:measure:MetricExprId +bloxweb:measure:FilterExpr +bloxweb:measure:FilterExprId +bloxweb:measure:Comparison +bloxweb:measure:ComparisonId +bloxweb:measure:AggExpr +bloxweb:measure:AggExprId +bloxweb:measure:Term +bloxweb:measure:TermId +bloxweb:measure:ParamTerm +bloxweb:measure:ParamTermId +bloxweb:measure:ConstantTerm +bloxweb:measure:ConstantTermId +bloxweb:measure:PartitionResponse +bloxweb:measure:PartitionResponseId +bloxweb:measure:Op:Kind_value +bloxweb:measure:Term:Kind_value +bloxweb:measure:Comparison:Kind_value +bloxweb:measure:AggExpr:Grouping:Kind_value +bloxweb:measure:AggExpr:Grouping_kind +bloxweb:measure:AggExpr:Grouping_dimension +bloxweb:measure:AggExpr:Grouping_hierarchy +bloxweb:measure:AggExpr:Grouping_level +bloxweb:measure:AggExpr:Grouping_multi_dim_map +bloxweb:measure:AggExpr:Method_value +bloxweb:measure:Request:Kind_value +bloxweb:measure:Dimension:Hierarchy:Path_level +bloxweb:measure:Dimension:Hierarchy:Path_map_pred +bloxweb:measure:ModelRequest:Kind_value +bloxweb:measure:MeasureExpr:Kind_value +bloxweb:measure:CompositeExpr:Kind_value +bloxweb:measure:Dimension:Hierarchy_name +bloxweb:measure:Dimension:Hierarchy_path +bloxweb:measure:Dimension:Edge_source_level +bloxweb:measure:Dimension:Edge_target_level +bloxweb:measure:Dimension:Edge_map_pred +bloxweb:measure:Dimension:Level_name +bloxweb:measure:Dimension:Level_impl +bloxweb:measure:Dimension:Level_attribute +bloxweb:measure:Dimension:Kind_value +bloxweb:measure:Type_value +bloxweb:measure:MeasureModel_name +bloxweb:measure:MeasureModel_dimension +bloxweb:measure:MeasureModel_metric +bloxweb:measure:MeasureModel_multi_dim_level_map +bloxweb:measure:MeasureModel_operator +bloxweb:measure:MeasureModel_hypercube +bloxweb:measure:MeasureModel_metric_group +bloxweb:measure:MeasureModel_binding +bloxweb:measure:OpDef_name +bloxweb:measure:OpDef_impl +bloxweb:measure:OpDef_domain +bloxweb:measure:OpDef_range +bloxweb:measure:Hypercube_name +bloxweb:measure:Hypercube_default_metric +bloxweb:measure:Hypercube_default_metric_group +bloxweb:measure:Hypercube_metric_group +bloxweb:measure:Hypercube_caption +bloxweb:measure:MetricGroup_name +bloxweb:measure:MetricGroup_dim +bloxweb:measure:MetricGroup_metric +bloxweb:measure:MetricGroup_caption +bloxweb:measure:Dimensionality_dimension +bloxweb:measure:Metric_name +bloxweb:measure:Metric_inter +bloxweb:measure:Metric_type +bloxweb:measure:Metric_predicate +bloxweb:measure:Metric_dialogue +bloxweb:measure:Metric_caption +bloxweb:measure:Predicate_name +bloxweb:measure:Predicate_is_disjunctive_view +bloxweb:measure:Dialogue_domain +bloxweb:measure:Dialogue_request_pred +bloxweb:measure:Dialogue_response_pred +bloxweb:measure:MultiDimensionalLevelMap_name +bloxweb:measure:MultiDimensionalLevelMap_level_map_pred +bloxweb:measure:MultiDimensionalLevelMap_source_inter +bloxweb:measure:MultiDimensionalLevelMap_target_level +bloxweb:measure:Dimension_name +bloxweb:measure:Dimension_level +bloxweb:measure:Dimension_edge +bloxweb:measure:Dimension_hierarchy +bloxweb:measure:Dimension_default_hierarchy +bloxweb:measure:Dimension_top_level +bloxweb:measure:Dimension_unwinds +bloxweb:measure:Dimension_caption +bloxweb:measure:Dimension_kind +bloxweb:measure:Attribute_name +bloxweb:measure:Attribute_impl +bloxweb:measure:Attribute_type +bloxweb:measure:QualifiedLevel_dimension +bloxweb:measure:QualifiedLevel_hierarchy +bloxweb:measure:QualifiedLevel_level +bloxweb:measure:Intersection_qualified_level +bloxweb:measure:Binding_pred +bloxweb:measure:Binding_measure_text +bloxweb:measure:Binding_measure_expr +bloxweb:measure:ModelRequest_kind +bloxweb:measure:ModelResponse_exception +bloxweb:measure:ModelResponse_model +bloxweb:measure:Request_kind +bloxweb:measure:Request_query_request +bloxweb:measure:Request_install_request +bloxweb:measure:InstallRequest_measure_expr +bloxweb:measure:InstallRequest_measure_text +bloxweb:measure:QueryRequest_report_name +bloxweb:measure:QueryRequest_argument +bloxweb:measure:QueryRequest_row_limit +bloxweb:measure:QueryRequest_return_row_numbers +bloxweb:measure:QueryRequest_key +bloxweb:measure:QueryRequest_measure +bloxweb:measure:KeyRequest_qualified_level +bloxweb:measure:KeyRequest_attribute +bloxweb:measure:ParamBinding_param +bloxweb:measure:ParamBinding_constant +bloxweb:measure:Response_report_column +bloxweb:measure:Response_exception +bloxweb:measure:Column_bool_column +bloxweb:measure:Column_int_column +bloxweb:measure:Column_float_column +bloxweb:measure:Column_string_column +bloxweb:measure:Column_decimal_column +bloxweb:measure:BoolColumn_value +bloxweb:measure:IntColumn_value +bloxweb:measure:FloatColumn_value +bloxweb:measure:StringColumn_value +bloxweb:measure:DecimalColumn_value +bloxweb:measure:MeasureExpr_kind +bloxweb:measure:MeasureExpr_metric +bloxweb:measure:MeasureExpr_aggregation +bloxweb:measure:MeasureExpr_filter +bloxweb:measure:MeasureExpr_composite +bloxweb:measure:MeasureExpr_attribute +bloxweb:measure:MeasureExpr_term +bloxweb:measure:MeasureExpr_op +bloxweb:measure:MeasureExpr_widen +bloxweb:measure:MeasureExpr_dice +bloxweb:measure:WidenExpr_expr +bloxweb:measure:WidenExpr_inter +bloxweb:measure:DiceExpr_expr +bloxweb:measure:DiceExpr_dicer +bloxweb:measure:DiceExpr_is_disjunction +bloxweb:measure:AttributeExpr_qualified_level +bloxweb:measure:AttributeExpr_attribute +bloxweb:measure:Op_kind +bloxweb:measure:Op_name +bloxweb:measure:OpExpr_op +bloxweb:measure:OpExpr_expr +bloxweb:measure:CompositeExpr_kind +bloxweb:measure:CompositeExpr_expr +bloxweb:measure:MetricExpr_name +bloxweb:measure:MetricExpr_argument +bloxweb:measure:FilterExpr_expr +bloxweb:measure:FilterExpr_comparison +bloxweb:measure:FilterExpr_is_disjunction +bloxweb:measure:Comparison_op +bloxweb:measure:Comparison_term +bloxweb:measure:AggExpr_method +bloxweb:measure:AggExpr_expr +bloxweb:measure:AggExpr_grouping +bloxweb:measure:Term_kind +bloxweb:measure:Term_param +bloxweb:measure:Term_constant +bloxweb:measure:ParamTerm_name +bloxweb:measure:ParamTerm_type +bloxweb:measure:ConstantTerm_string_constant +bloxweb:measure:ConstantTerm_int_constant +bloxweb:measure:ConstantTerm_float_constant +bloxweb:measure:ConstantTerm_decimal_constant +bloxweb:measure:ConstantTerm_boolean_constant +bloxweb:measure:PartitionResponse_broadcast +bloxweb:measure:PartitionResponse_partitionID +bloxweb:measure:AggExpr:GroupingId:_$inverse +bloxweb:measure:Dimension:Hierarchy:PathId:_$inverse +bloxweb:measure:Dimension:HierarchyId:_$inverse +bloxweb:measure:Dimension:EdgeId:_$inverse +bloxweb:measure:Dimension:LevelId:_$inverse +bloxweb:measure:MeasureModelId:_$inverse +bloxweb:measure:OpDefId:_$inverse +bloxweb:measure:HypercubeId:_$inverse +bloxweb:measure:MetricGroupId:_$inverse +bloxweb:measure:DimensionalityId:_$inverse +bloxweb:measure:MetricId:_$inverse +bloxweb:measure:PredicateId:_$inverse +bloxweb:measure:DialogueId:_$inverse +bloxweb:measure:MultiDimensionalLevelMapId:_$inverse +bloxweb:measure:DimensionId:_$inverse +bloxweb:measure:AttributeId:_$inverse +bloxweb:measure:QualifiedLevelId:_$inverse +bloxweb:measure:IntersectionId:_$inverse +bloxweb:measure:BindingId:_$inverse +bloxweb:measure:ModelRequestId:_$inverse +bloxweb:measure:ModelResponseId:_$inverse +bloxweb:measure:RequestId:_$inverse +bloxweb:measure:InstallRequestId:_$inverse +bloxweb:measure:QueryRequestId:_$inverse +bloxweb:measure:KeyRequestId:_$inverse +bloxweb:measure:ParamBindingId:_$inverse +bloxweb:measure:ResponseId:_$inverse +bloxweb:measure:ColumnId:_$inverse +bloxweb:measure:BoolColumnId:_$inverse +bloxweb:measure:IntColumnId:_$inverse +bloxweb:measure:FloatColumnId:_$inverse +bloxweb:measure:StringColumnId:_$inverse +bloxweb:measure:DecimalColumnId:_$inverse +bloxweb:measure:MeasureExprId:_$inverse +bloxweb:measure:WidenExprId:_$inverse +bloxweb:measure:DiceExprId:_$inverse +bloxweb:measure:AttributeExprId:_$inverse +bloxweb:measure:OpId:_$inverse +bloxweb:measure:OpExprId:_$inverse +bloxweb:measure:CompositeExprId:_$inverse +bloxweb:measure:MetricExprId:_$inverse +bloxweb:measure:FilterExprId:_$inverse +bloxweb:measure:ComparisonId:_$inverse +bloxweb:measure:AggExprId:_$inverse +bloxweb:measure:TermId:_$inverse +bloxweb:measure:ParamTermId:_$inverse +bloxweb:measure:ConstantTermId:_$inverse +bloxweb:measure:PartitionResponseId:_$inverse +measure:schema:dimension +measure:schema:dimension_hasName +measure:schema:hierarchy +measure:schema:hierarchy_id +measure:schema:edge +measure:schema:edge_id +measure:schema:level +measure:schema:level_id +measure:schema:attribute +measure:schema:attribute_id +measure:schema:dimensionality +measure:schema:dimensionality_hasStrRep +measure:schema:intersection +measure:schema:intersection_hasStrRep +measure:schema:metric +measure:schema:metric_hasName +measure:schema:predicate +measure:schema:predicate_id +measure:schema:dialogue +measure:schema:dialogue_id +measure:schema:binding +measure:schema:binding_id +measure:schema:multiDimLevelMap +measure:schema:multiDimLevelMap_hasName +measure:schema:hypercube +measure:schema:hypercube_hasName +measure:schema:metricGroup +measure:schema:metricGroup_hasName +measure:schema:name +measure:schema:dimension_unwinds +measure:schema:hierarchy_fromDimensionName +measure:schema:edge_fromDimensionLevels +measure:schema:level_fromDimensionName +measure:schema:predicate_fromName +measure:schema:dialogue_fromPredPred +measure:schema:attribute_fromLevelName +measure:schema:dimension_hasCaption +measure:schema:dimension_hasKind +measure:schema:dimension_hasDefaultHierarchy +measure:schema:hierarchy_hasLevel +measure:schema:level_hasImplPredicate +measure:schema:level_hasAttribute +measure:schema:attribute_hasImplPredicate +measure:schema:attribute_hasType +measure:schema:level_map +measure:schema:metric_hasIntersection +measure:schema:metric_hasCaption +measure:schema:metric_hasType +measure:schema:metric_usesPredicate +measure:schema:metric_usesDialogue +measure:schema:binding_hasExpression +measure:schema:binding_hasPredicateName +measure:schema:multiDimLevelMap_hasPredicateName +measure:schema:multiDimLevelMap_hasSourceIntersection +measure:schema:multiDimLevelMap_hasTargetLevel +measure:schema:hypercube_hasCaption +measure:schema:hypercube_hasDefaultMetric +measure:schema:hypercube_hasDefaultMetricGroup +measure:schema:hypercube_hasMetricGroups +measure:schema:metricGroup_hasCaption +measure:schema:metricGroup_hasDimensionality +measure:schema:metricGroup_hasMetrics +measure:schema:dialogue_hasRequestPredName +measure:schema:dialogue_hasResponsePredName +measure:schema:dialogue_hasParam +measure:schema:hierarchy_hasName +measure:schema:hierarchy_levelAtIndex +measure:schema:level_hasName +measure:schema:attribute_hasName +measure:schema:dimension_hasHierarchy +measure:schema:dimension_hasLevel +measure:schema:dimension_hasEdge +measure:schema:dimensionality_hasDimension +measure:schema:intersection_hasLevel +measure:schema:predicate_hasName +measure:schema:dimension_hasName:_$inverse +measure:schema:hierarchy_id:_$inverse +measure:schema:edge_id:_$inverse +measure:schema:level_id:_$inverse +measure:schema:attribute_id:_$inverse +measure:schema:predicate_id:_$inverse +measure:schema:dialogue_id:_$inverse +measure:schema:binding_id:_$inverse +measure:schema:multiDimLevelMap_hasName:_$inverse +$measure_schema:_projection_t_YNCexcn_IHi +$measure_schema:_projection_t_YNCexcn_IHj +$measure_schema:_projection_t_YNCexcn_IHk +$measure_schema:_projection_t_YNCexcn_IHl +$measure_schema:_projection_t_YNCexcn_IHm +$measure_schema:_projection_t_YNCexcn_IHn +measure:schema:nonExistentMemberException +measure:schema:dimensionality_hasDimensionName +measure:schema:exn +measure:schema:intersection_hasName +measure:schema:dimLevelSeparator +measure:schema:intersectionSplit +measure:schema:intersection_hasLevelName +measure:schema:intersection_hasLevelName2 +measure:schema:intersection_hasDimName2 +measure:schema:intersection_levelDimOk +measure:config:dimension +measure:config:dimension_hasName +measure:config:hierarchy +measure:config:metric +measure:config:metric_hasName +measure:config:binding +measure:config:multiDimLevelMap +measure:config:multiDimLevelMap_hasName +measure:config:hypercube +measure:config:hypercube_hasName +measure:config:metricGroup +measure:config:metricGroup_hasName +measure:config:enable +measure:config:name +measure:config:dimension_hasCaption +measure:config:dimension_hasKind +measure:config:dimension_hasDefaultHierarchy +measure:config:dimension_unwinds +measure:config:dimension_hasEdge +measure:config:hierarchy_byDimName +measure:config:level +measure:config:attribute +measure:config:levelMap +measure:config:metric_hasCaption +measure:config:metric_hasIntersection +measure:config:metric_hasType +measure:config:metric_usesPredicate +measure:config:metric_usesDialogue +measure:config:metric_hasParam +measure:config:binding_hasExpression +measure:config:binding_hasPredicateName +measure:config:multiDimLevelMap_hasPredicateName +measure:config:multiDimLevelMap_hasSourceLevels +measure:config:multiDimLevelMap_hasTargetLevel +measure:config:hypercube_hasCaption +measure:config:hypercube_hasDefaultMetric +measure:config:hypercube_hasDefaultMetricGroup +measure:config:hypercube_hasMetricGroup +measure:config:metricGroup_hasCaption +measure:config:metricGroup_hasDimensionality +measure:config:metricGroup_hasMetric +$measure_config:_projection_t_YNCexcn_IIT +$measure_config:_projection_t_YNCexcn_IIU +measure:config:configMetric2schemaMetric +measure:config:configHier2schemaHier +measure:config:configDimension2schemaDimension +measure:config:configBinding2schemaBinding +measure:config:configMDMap2schemaMDMap +measure:config:configHypercube2schemaHypercube +measure:config:configMetricGroup2schemaMetricGroup +measure:schema2MetricMsg:dimensionalityAutoIndex +measure:schema2MetricMsg:dimensionalityAutoIndex_id +measure:schema2MetricMsg:measureModel +measure:schema2MetricMsg:_metricConstr +measure:schema2MetricMsg:_typeConstr +measure:schema2MetricMsg:_qlevelConstr +measure:schema2MetricMsg:dimensionality_hasAutoIndex +measure:schema2MetricMsg:schemaMetric2msgMetric +measure:schema2MetricMsg:schemaDimensionality2msgDimensionality +measure:schema2MetricMsg:schemaIntersection2msgIntersection +measure:schema2MetricMsg:schemaPred2msgPred +measure:schema2MetricMsg:schemaBinding2msgBinding +measure:schema2MetricMsg:schemaMDMap2msgMDMap +measure:schema2MetricMsg:schemaHypercube2msgHypercube +measure:schema2MetricMsg:_hyperConstr +measure:schema2MetricMsg:schemaMetricGroup2msgMetricGroup +measure:schema2MetricMsg:_groupConstr +measure:schema2MetricMsg:schemaDialogue2msgDialogue +measure:schema2MetricMsg:_dConstr +measure:schema2MetricMsg:dimensionalityAutoIndex_id:_$inverse +measure:schema2DimensionMsg:levelAttributeIndex +measure:schema2DimensionMsg:levelAttributeIndex_id +measure:schema2DimensionMsg:dimLevelIndex +measure:schema2DimensionMsg:dimLevelIndex_id +$measure_schema2DimensionMsg:_projection_t_YNCexcn_IMF +measure:schema2DimensionMsg:_levelConstr +measure:schema2DimensionMsg:_edgeConstr +measure:schema2DimensionMsg:_kindConstr +measure:schema2DimensionMsg:_attrConstr +measure:schema2DimensionMsg:_typeConstr +measure:schema2DimensionMsg:_pathConstr +measure:schema2DimensionMsg:schemaHier2msgHier +measure:schema2DimensionMsg:schemaDim2msgDim +measure:schema2DimensionMsg:schemaLevel2msgLevel +measure:schema2DimensionMsg:schemaAttribute2msgAttribute +measure:schema2DimensionMsg:levelAttributeIndex_fromLevelAttribute +measure:schema2DimensionMsg:dimLevelIndex_fromDimLevel +measure:schema2DimensionMsg:levelAttributeIndex_id:_$inverse +measure:schema2DimensionMsg:dimLevelIndex_id:_$inverse +$util_printSchema:_ +$util_printSchema:_hierarchy_pp +$util_printSchema:_agg_map_pp +$util_printSchema:_map_ppstring +pdx:prod:sku +pdx:prod:sku_id +pdx:prod:class +pdx:prod:class_id +pdx:prod:department +pdx:prod:department_id +pdx:loc:store +pdx:loc:store_id +pdx:loc:region +pdx:loc:region_id +pdx:loc:district +pdx:loc:district_id +pdx:loc:allloc +pdx:loc:allloc_id +pdx:cal:week +pdx:cal:week_id +pdx:cal:month +pdx:cal:month_id +pdx:cal:year +pdx:cal:year_id +pdx:cal:season +pdx:cal:season_id +auth:user +auth:user_id +distr +distr_id +pdx:prod:sku:class +pdx:prod:class:department +pdx:loc:store:region +pdx:loc:region:district +pdx:loc:district:allloc +pdx:cal:week:month +pdx:cal:month:year +pdx:cal:week:season +pdx:cal:season:year +pdx:sku:store:week:sales +pdx:class:store:week:sales +pdx:sku:region:week:sales +pdx:sku:allloc:week:sales +pdx:sku:store:week:returns +pdx:sku:store:week:netSales +pdx:sku:store:week:user +pdx:sku:region:week:returns +distr:sku +distr:store +distr:week +pdx:cal:week:offset +pdx:sku:store:week:sku_id +pdx:class:store:week:class_id +pdx:sku:store:week:store_id +pdx:sku:region:week:region_id +pdx:sku:store:week:store +pdx:sku:region:week:region +pdx:sku:store:store +pdx:sku:region:region +pdx:sku:store:week:week_id +pdx:sku:store:month:month_id +pdx:sku:week:sku_id +pdx:class:week:class_id +distrID_req +distrID_resp +distrStoreID_req +distrStoreID_resp +pdx:sku:store:week:distr +pdx:sku:store:distr +my_sales_response_predicate +my_filtered_sales_response +my_filtered_sales_request +my_user_predicate +userResponsibility +superUser +vendorResponsibility +vendorAuth_req +vendorAuth_resp +superUser_req +superUser_resp +userAuth_req +userAuth_resp +fm:subscription +pdx:week:distr:week_id +pdx:sku:store:activeProduct +pdx:sku:store:basicItem +pdx:sku:store:nonBillings +pdx:sku:region:week:returns:_derivationCounts +my_sales_response_predicate:_derivationCounts +measureService:Report_cloudpivot_reportGenPred_35a45c161ecfe2f1e6978870c6bd37a6f98d20d931d938c099e0a4908f2097_row +measureService:Report_cloudpivot_reportGenPred_35a45c161ecfe2f1e6978870c6bd37a6f98d20d931d938c099e0a4908f2097_row_nr +measureService:Report_cloudpivot_reportGenPred_35a45c161ecfe2f1e6978870c6bd37a6f98d20d931d938c099e0a4908f2097_column_Calendar_week_id +measureService:Report_cloudpivot_reportGenPred_35a45c161ecfe2f1e6978870c6bd37a6f98d20d931d938c099e0a4908f2097_column_Location_store_id +pred_a27640d55b0e3a684cdd9bec2ae279029534b01106b7bee4e4e03a383f4322980c7879035322e6dcef7f035f1e7976806a74581d48b1dd2684d4b4a5175543fe +pred_af19f40a4daf9ecb879db46a77e7243c5e0325464e478f2fb77a5d02686d3518b7b6e6b0110b86caca6a77f4fb8ff12cfe8bc67e99e7a640b6f5f35e2ea3f527 +pred_e0e7f493d26c622b1830d21c5b7bf375d521810bffc13248ef3d884698a0fb0a0ab2bc4b121f194e31b8d5b7d3791cf0b1675b2f5577acdd1ddb8d0e6ef1c069 +pred_59138dc1c7d57a62a1fef6daafed65707e116fbe2cc3fb359a81aeb323d22a50c2e29ac5a21006979da5493d573b9d298b8bb6d60b831e44c61679ba63202006 +pred_0ce084ea29ef5d30959063f7ef6c05f54cf83b90302de5620e4f1aaeb5d3ce686731b0d4c969faa3a221d47381ca978e0051beee399f94dc94c1d7a056f02dd7 +pred_9c7c8da88ad0ea15b54237e006ebd38273a8cf024cb639ed7d6ef1b01fcd5392973dc2a25b4e0d3b0d656370e4b19a5d2f407d9961af2696fbb22a49ece95cee +pred_e399c30cb5e220d7d15963101503f269b25a6c17bd3c9d79e50026a26da94a6242506e6787758be6fb4b306d0ff062e4ce40d0150b5d3e129a70e73a38ac17e3 +pred_263ffffd7e5d4e8dd640d335be26c8f89bc9e309d042ad8f9840a8ef7a06b46023ecee535ff4fceadd1efa2c651b2d4b380f2dbf13b49d5cd1e890dfecbbbfb1 +measureService:Report_cloudpivot_reportGenPred_35a45c161ecfe2f1e6978870c6bd37a6f98d20d931d938c099e0a4908f2097 +measureService:Report_cloudpivot_reportGenPred_35a45c161ecfe2f1e6978870c6bd37a6f98d20d931d938c099e0a4908f2097_tupleset +measureService:Report_cloudpivot_reportGenPred_35a45c161ecfe2f1e6978870c6bd37a6f98d20d931d938c099e0a4908f2097_rsk +measureService:Report_cloudpivot_reportGenPred_35a45c161ecfe2f1e6978870c6bd37a6f98d20d931d938c099e0a4908f2097_column_pred_a27640d55b0e3a684cdd9bec2ae279029534b01106b7bee4e4e03a383f4322980c7879035322e6dcef7f035f1e7976806a74581d48b1dd2684d4b4a5175543fe +measureService:Report_cloudpivot_reportGenPred_35a45c161ecfe2f1e6978870c6bd37a6f98d20d931d938c099e0a4908f2097_column_pred_9c7c8da88ad0ea15b54237e006ebd38273a8cf024cb639ed7d6ef1b01fcd5392973dc2a25b4e0d3b0d656370e4b19a5d2f407d9961af2696fbb22a49ece95cee +measureService:Report_cloudpivot_reportGenPred_35a45c161ecfe2f1e6978870c6bd37a6f98d20d931d938c099e0a4908f2097_column_pred_e0e7f493d26c622b1830d21c5b7bf375d521810bffc13248ef3d884698a0fb0a0ab2bc4b121f194e31b8d5b7d3791cf0b1675b2f5577acdd1ddb8d0e6ef1c069 +measureService:Report_cloudpivot_reportGenPred_35a45c161ecfe2f1e6978870c6bd37a6f98d20d931d938c099e0a4908f2097_row_nr:_$inverse +pred_59138dc1c7d57a62a1fef6daafed65707e116fbe2cc3fb359a81aeb323d22a50c2e29ac5a21006979da5493d573b9d298b8bb6d60b831e44c61679ba63202006:_derivationCounts +measureService:Report_cloudpivot_reportGenPred_a7b5a186481a4581496afe1ec18174ba3391cbfe9d84ca9a0c1ecec680aa_row +measureService:Report_cloudpivot_reportGenPred_a7b5a186481a4581496afe1ec18174ba3391cbfe9d84ca9a0c1ecec680aa_row_nr +measureService:Report_cloudpivot_reportGenPred_a7b5a186481a4581496afe1ec18174ba3391cbfe9d84ca9a0c1ecec680aa_column_Calendar_week_id +measureService:Report_cloudpivot_reportGenPred_a7b5a186481a4581496afe1ec18174ba3391cbfe9d84ca9a0c1ecec680aa_column_Location_store_id +pred_b88d3c5844a03a1a70a11cdf71b3b2525a81a422b94b3e8ae92871936af9dc244044c4a1f3a1be76750a5709e75cefcb4987fe4a6c0070381128e7f4016e39fa +pred_33379248fd05c744eb9cdb3d253c22773db2d5add5df8f5e021760375c3d4b9c085e5107549993fbff7e2740dc552aad89c000651612492e494472bacc036e45 +measureService:Report_cloudpivot_reportGenPred_a7b5a186481a4581496afe1ec18174ba3391cbfe9d84ca9a0c1ecec680aa +measureService:Report_cloudpivot_reportGenPred_a7b5a186481a4581496afe1ec18174ba3391cbfe9d84ca9a0c1ecec680aa_tupleset +measureService:Report_cloudpivot_reportGenPred_a7b5a186481a4581496afe1ec18174ba3391cbfe9d84ca9a0c1ecec680aa_rsk +measureService:Report_cloudpivot_reportGenPred_a7b5a186481a4581496afe1ec18174ba3391cbfe9d84ca9a0c1ecec680aa_column_pred_a27640d55b0e3a684cdd9bec2ae279029534b01106b7bee4e4e03a383f4322980c7879035322e6dcef7f035f1e7976806a74581d48b1dd2684d4b4a5175543fe +measureService:Report_cloudpivot_reportGenPred_a7b5a186481a4581496afe1ec18174ba3391cbfe9d84ca9a0c1ecec680aa_column_pred_9c7c8da88ad0ea15b54237e006ebd38273a8cf024cb639ed7d6ef1b01fcd5392973dc2a25b4e0d3b0d656370e4b19a5d2f407d9961af2696fbb22a49ece95cee +measureService:Report_cloudpivot_reportGenPred_a7b5a186481a4581496afe1ec18174ba3391cbfe9d84ca9a0c1ecec680aa_column_pred_b88d3c5844a03a1a70a11cdf71b3b2525a81a422b94b3e8ae92871936af9dc244044c4a1f3a1be76750a5709e75cefcb4987fe4a6c0070381128e7f4016e39fa +measureService:Report_cloudpivot_reportGenPred_a7b5a186481a4581496afe1ec18174ba3391cbfe9d84ca9a0c1ecec680aa_column_pred_e0e7f493d26c622b1830d21c5b7bf375d521810bffc13248ef3d884698a0fb0a0ab2bc4b121f194e31b8d5b7d3791cf0b1675b2f5577acdd1ddb8d0e6ef1c069 +measureService:Report_cloudpivot_reportGenPred_a7b5a186481a4581496afe1ec18174ba3391cbfe9d84ca9a0c1ecec680aa_row_nr:_$inverse +measureService:Report_cloudpivot_reportGenPred_1c7032e4f6478d62dcf1ea70e4707dd575b4a6ade7d3d228c88707878ddd5c0_row +measureService:Report_cloudpivot_reportGenPred_1c7032e4f6478d62dcf1ea70e4707dd575b4a6ade7d3d228c88707878ddd5c0_row_nr +measureService:Report_cloudpivot_reportGenPred_1c7032e4f6478d62dcf1ea70e4707dd575b4a6ade7d3d228c88707878ddd5c0_column_Calendar_month_id +measureService:Report_cloudpivot_reportGenPred_1c7032e4f6478d62dcf1ea70e4707dd575b4a6ade7d3d228c88707878ddd5c0_column_Location_store_id +pred_77ea5d0798c88e5e4d2f08f071b55d9f187261d0f42b2eef7c3a972688e757fab7d4878db04222d027266dbd985c1ce13fa1f10276d6b3d5503e0ff9e65ce0e5 +pred_6fc809bd7068ea05a01c601c83d52194778c835df5e533bb6bd7f9f585d2acb2c82af67afd3ecd404ac8fc3cd956684a59cf151174521372280b626ef5ff4635 +pred_614b7991028f078078b92ff6bc42fa6ea4ef52c174b6b66325df59e909da6f276e5a84d7b2fe304215d5219471513c4988baae7ae7f0c0b45c6029bc3687957d +pred_62a9d14b089be552764abdb8d0ad35fc135c256daf61b6de3c5430d2420cba9010fe5d9a80d3de17eff5c3865e1438efe94c369ca211bc4221e7b6e93914c1fc +pred_1e238b8c1133181ebb31e3d6f1f159641b65c39ce09063b02411a44924ab76ea4c4d5ac2ea6f1762d7600036de85a7602a15b0d7d00fea2450157867531170f9 +pred_81477c573226073cc0055f555bf047a9daf4524c73cd0a25c5cb5651e9c13288e0b79d3aef61f5515822cb5b57d5f0a214187ea523de01ec401381a075fb3d36 +pred_6f0508d436d154af425455c7af8d8e10c318e2053f60bb09e68369e24a83a0301f168081fcbd9d96ddb43bbedffa6bd5753377a6029301cf2097767917c20640 +measureService:Report_cloudpivot_reportGenPred_1c7032e4f6478d62dcf1ea70e4707dd575b4a6ade7d3d228c88707878ddd5c0 +measureService:Report_cloudpivot_reportGenPred_1c7032e4f6478d62dcf1ea70e4707dd575b4a6ade7d3d228c88707878ddd5c0_tupleset +measureService:Report_cloudpivot_reportGenPred_1c7032e4f6478d62dcf1ea70e4707dd575b4a6ade7d3d228c88707878ddd5c0_rsk +measureService:Report_cloudpivot_reportGenPred_1c7032e4f6478d62dcf1ea70e4707dd575b4a6ade7d3d228c88707878ddd5c0_column_pred_77ea5d0798c88e5e4d2f08f071b55d9f187261d0f42b2eef7c3a972688e757fab7d4878db04222d027266dbd985c1ce13fa1f10276d6b3d5503e0ff9e65ce0e5 +measureService:Report_cloudpivot_reportGenPred_1c7032e4f6478d62dcf1ea70e4707dd575b4a6ade7d3d228c88707878ddd5c0_column_pred_81477c573226073cc0055f555bf047a9daf4524c73cd0a25c5cb5651e9c13288e0b79d3aef61f5515822cb5b57d5f0a214187ea523de01ec401381a075fb3d36 +measureService:Report_cloudpivot_reportGenPred_1c7032e4f6478d62dcf1ea70e4707dd575b4a6ade7d3d228c88707878ddd5c0_column_pred_614b7991028f078078b92ff6bc42fa6ea4ef52c174b6b66325df59e909da6f276e5a84d7b2fe304215d5219471513c4988baae7ae7f0c0b45c6029bc3687957d +measureService:Report_cloudpivot_reportGenPred_1c7032e4f6478d62dcf1ea70e4707dd575b4a6ade7d3d228c88707878ddd5c0_row_nr:_$inverse +pred_62a9d14b089be552764abdb8d0ad35fc135c256daf61b6de3c5430d2420cba9010fe5d9a80d3de17eff5c3865e1438efe94c369ca211bc4221e7b6e93914c1fc:_derivationCounts +measureService:Report_cloudpivot_reportGenPred_e6191c9673dad9a6701451b9318697ad7155da5251fa579bc070a73f7514c2d1_row +measureService:Report_cloudpivot_reportGenPred_e6191c9673dad9a6701451b9318697ad7155da5251fa579bc070a73f7514c2d1_row_nr +measureService:Report_cloudpivot_reportGenPred_e6191c9673dad9a6701451b9318697ad7155da5251fa579bc070a73f7514c2d1_column_Calendar_month_id +measureService:Report_cloudpivot_reportGenPred_e6191c9673dad9a6701451b9318697ad7155da5251fa579bc070a73f7514c2d1_column_Location_store_id +measureService:Report_cloudpivot_reportGenPred_e6191c9673dad9a6701451b9318697ad7155da5251fa579bc070a73f7514c2d1_column_Product_sku_id +pred_0daddca72eebe8abb7370c5a7ff694085451cd78505810e155847305d1380254eb329cf5105ed8ab612dd0bfbdb0dde8ed8c02f94be164d44388a12730d8cb9a +pred_05e6dbb75f5a5763f246c838ef8ced1e7455ef028390c75778cfbdc2badf927d3ffd3679c332b6fff1c0b78d2e3c5a3beaca5dc963f4b7adb74a7904a43b21a2 +pred_20059ca79106a6b7e81bb256ce57828915519e454ea5834d221350ad7d8d1729a58bd74cd2fc0ecb9e39ef8fcbb37ec175f6dab2fa5bf4a5140db3f217bff374 +pred_01f26ebf800a3f2c49548e751b1eabf47ed0d34bed50346c77e5aec2627ace2940162bedd3b72f4bc7ed3c40e739d5de32db7fa4a01c9b05c37d5671e69971ea +pred_c1fdad41a73545a735245970f7e87ed12d50688dbe3b00545a357160bdc6fea6c6b169492002931f67f1bc80f90cb921e2021464feae5ac014fef57e9b352ea3 +pred_dd0a89cd8da02202e64a74b4f6f7aa821150864e10dda7163d8352a18f032653c45e2b4ec3e408b08d53d7b9176e62ffd999a160e3eb3b3a3c0a160799c64110 +pred_1f20e48e13774d80810342d35b292422ce164883739d5e6b36edfd9b43009de327f56b073c59f0423a1f5181ced1770e8ea35baa8b70bdffff01ced8cba853d7 +measureService:Report_cloudpivot_reportGenPred_e6191c9673dad9a6701451b9318697ad7155da5251fa579bc070a73f7514c2d1 +measureService:Report_cloudpivot_reportGenPred_e6191c9673dad9a6701451b9318697ad7155da5251fa579bc070a73f7514c2d1_tupleset +measureService:Report_cloudpivot_reportGenPred_e6191c9673dad9a6701451b9318697ad7155da5251fa579bc070a73f7514c2d1_rsk +measureService:Report_cloudpivot_reportGenPred_e6191c9673dad9a6701451b9318697ad7155da5251fa579bc070a73f7514c2d1_column_pred_0daddca72eebe8abb7370c5a7ff694085451cd78505810e155847305d1380254eb329cf5105ed8ab612dd0bfbdb0dde8ed8c02f94be164d44388a12730d8cb9a +measureService:Report_cloudpivot_reportGenPred_e6191c9673dad9a6701451b9318697ad7155da5251fa579bc070a73f7514c2d1_column_pred_dd0a89cd8da02202e64a74b4f6f7aa821150864e10dda7163d8352a18f032653c45e2b4ec3e408b08d53d7b9176e62ffd999a160e3eb3b3a3c0a160799c64110 +measureService:Report_cloudpivot_reportGenPred_e6191c9673dad9a6701451b9318697ad7155da5251fa579bc070a73f7514c2d1_column_pred_20059ca79106a6b7e81bb256ce57828915519e454ea5834d221350ad7d8d1729a58bd74cd2fc0ecb9e39ef8fcbb37ec175f6dab2fa5bf4a5140db3f217bff374 +measureService:Report_cloudpivot_reportGenPred_e6191c9673dad9a6701451b9318697ad7155da5251fa579bc070a73f7514c2d1_row_nr:_$inverse +pred_01f26ebf800a3f2c49548e751b1eabf47ed0d34bed50346c77e5aec2627ace2940162bedd3b72f4bc7ed3c40e739d5de32db7fa4a01c9b05c37d5671e69971ea:_derivationCounts \ No newline at end of file diff --git a/node_modules/ace_tree/list_demo.html b/node_modules/ace_tree/list_demo.html new file mode 100644 index 00000000..5fb5d962 --- /dev/null +++ b/node_modules/ace_tree/list_demo.html @@ -0,0 +1,71 @@ + + + + + + Ace Tree + + + + +
      +
      + + + + + + + diff --git a/node_modules/ace_tree/package.json b/node_modules/ace_tree/package.json new file mode 100644 index 00000000..f25821e7 --- /dev/null +++ b/node_modules/ace_tree/package.json @@ -0,0 +1,6 @@ +{ + "name": "ace_tree", + "version": "0.1.0", + "devDependencies": { + } +} \ No newline at end of file diff --git a/node_modules/architect-build/.gitignore b/node_modules/architect-build/.gitignore new file mode 100644 index 00000000..3c3629e6 --- /dev/null +++ b/node_modules/architect-build/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/node_modules/architect-build/LICENSE b/node_modules/architect-build/LICENSE new file mode 100644 index 00000000..788f78c1 --- /dev/null +++ b/node_modules/architect-build/LICENSE @@ -0,0 +1,21 @@ +The MIT License + +Copyright (c) 2012 ajax.org B.V + +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. diff --git a/node_modules/architect-build/README.md b/node_modules/architect-build/README.md new file mode 100644 index 00000000..b99b5ca1 --- /dev/null +++ b/node_modules/architect-build/README.md @@ -0,0 +1 @@ +Work in Progress diff --git a/node_modules/architect-build/build.js b/node_modules/architect-build/build.js new file mode 100644 index 00000000..48888813 --- /dev/null +++ b/node_modules/architect-build/build.js @@ -0,0 +1,380 @@ +var fs = require("fs"); +var path = require("path"); +var async = require("async"); +var mkdirp = require("mkdirp"); +var moduleDeps = require("./module-deps"); + +function build(config, opts, callback){ + if (!opts.configFile) { + opts.configFile = "\nrequire.plugins = " + + JSON.stringify(config, null, 4) + + ";\n"; + } + + // Load all architect modules as main files + var mains = [], options = {}; + config.forEach(function(pkg){ + if (typeof pkg == "string") { + mains.push(pkg); + } + else if (pkg.packagePath) { + mains.push({ + id: pkg.packagePath, + parent: {id: "#root"}, + plugin: pkg + }); + options[pkg.packagePath] = pkg; + } + }); + + // Add additional packages + (opts.additional || []).forEach(function(relPath, i){ + mains.unshift(typeof relPath === "object" ? relPath : { + id : null, + path : path.resolve(__dirname + "/" + relPath), + order : -i, + literal : true + }); + }); + + if (!mains.length) + return callback(new Error("Config contains no packages")); + + // Add Architect + if (!opts.noArchitect) { + mains.push("lib/architect/architect"); + (opts.ignore || (opts.ignore = [])).push( + //path.resolve(__dirname + "/../architect/events"), + path.resolve(__dirname + "/../architect/path"), + path.resolve(__dirname + "/../architect/fs") + ); + } + + // Add RequireJS + if (opts.withRequire) { + mains.unshift({ + id: null, + path: path.resolve(__dirname + "/build_support/mini_require.js"), + order: -1000, + noRequire: true, + mini_require: true + }); + } + + if (opts.moduleLoadUrl) { + opts.transforms = opts.transforms || []; + opts.transforms.push(function(module) { + if (module.mini_require) { + module.source = module.source.replace(/^\s*var\s+MODULE_LOAD_URL\s*=\s*["'].*["']/m, 'var MODULE_LOAD_URL = "' + opts.moduleLoadUrl + '"'); + } + }); + } + + // Find their deps + var stream = moduleDeps(mains, opts); + stream.on("end", function() { + // sort modules + var sources = []; + var modules = opts.modules; + var added = Object.create(null); + function addModule(id) { + var pkg = modules[id] || {}; + if (added[pkg.id]) + return; + added[pkg.id] = true; + if (!pkg.source) + return; + if (pkg.deps) + pkg.deps.forEach(addModule); + sources.push(pkg); + pkg.pkgIndex = sources.length; + added[pkg.id] = true; + } + Object.keys(modules).forEach(addModule); + + // Filter sources + (opts.filter || []).forEach(function(filter){ + sources = sources.filter(function(pkg){ + return pkg.id.indexOf(filter) !== 0; + }); + }); + + sources.sort(function(a, b) { + return ((a.order|0) - (b.order|0)) || (a.pkgIndex - b.pkgIndex); + }); + + if (opts.compileLess) + return compileLess(opts, sources, callback); + + if (opts.stripLess) + stripLess(sources); + + + var afterRead = typeof opts.afterRead == "function" + ? [opts.afterRead] + : opts.afterRead || []; + afterRead.push(rewriteDefines); + + afterRead.forEach(function(f) { + sources = f(sources, opts) || sources; + }); + + // Include the architect config at the end in the same way as the tests + if (!opts.noArchitect) + includeArchitect(opts, sources); + + + opts.quiet || console.log("Processing " + sources.length + " files."); + opts.quiet || console.log("Compressing: ", opts.compress); + + // Concatenate all files using uglify2 with source maps + var result; + if (opts.compress) + result = require("./compress")(sources, opts); + else { + result = { + code : sources.map(function(src){ return src.source.trim(); }).join("\n\n") + "\n", + map : "" + }; + } + + result.sources = sources; + if (opts.beforeWrite) { + opts.beforeWrite.forEach(function(f) { + f(result, opts) || sources; + }); + } + + if (typeof opts.outputFolder == "string") { + writeToFile(result, opts, callback); + } + else { + callback(null, result); + } + }); + stream.on("error", function(e) { + callback(e); + }); +} + +// TODO +function createOutputFolder(opts, cb) { + var output = (opts.outputFolder || ".") + "/" + (opts.outputFile || ""); + output = path.dirname(output); + mkdirp(output, cb); +} + +function compileLess(opts, sources, callback) { + var less = stripLess(sources); + var code = []; + var cache = opts.cache; + if (cache && !cache.less) + cache.less = Object.create(null); + + async.forEachSeries(less, function(file, next) { + var plugin = file.pkg.parent.plugin || {}; + + if (file.pkg.id.match(/(keyframes|font-awesome)\.css$/)) { + code.push(file.code + .replace(/@\{image-path\}/g, plugin.staticPrefix + "/images") + .replace(/@\{icon-path\}/g, plugin.staticPrefix + "/icons") + .replace(/@\{base-path\}/g, plugin.staticPrefix) + ); + + return next(); + } + var root = path.join(opts.basepath, (plugin.packagePath ? path.dirname(plugin.packagePath) : "/")); + + var cacheKey; + if (cache && opts.lessLibCacheKey) { + cacheKey = [opts.lessLibCacheKey, plugin.staticPrefix, file.pkg.id].join("|"); + if (cache.less[cacheKey]) { + code.push(cache.less[cacheKey]); + return next(); + } + } + + compileLessFragment(file.code, opts.lessLibs, root, plugin.staticPrefix, file.path, opts.compress, function(err, css) { + if (err) + return callback(err); + + if (cacheKey) + cache.less[cacheKey] = css; + code.push(css); + next(); + }); + }, function(err) { + if (opts.lessLibs.css) { + code.push(opts.lessLibs.css); + } + callback(err, { + code: code.join("\n") + }); + }); +} + +function compileLessFragment(css, libs, root, staticPrefix, path, compress, callback) { + var less = require("less"); + var baseLib = lessPathLib(staticPrefix || libs.staticPrefix); + var parser = new less.Parser({ + paths: ["/"], + filename: root + '/unknown.less', + }); + + if (!libs.compiled) { + parser.parse(lessPathLib(libs.staticPrefix) + libs.join("\n"), function(err, tree) { + libs.compiled = tree; // actually parse isn't async + }); + + libs.css = libs.compiled.toCSS().trim(); + } + // Parse Less Code + var code = baseLib + "\n" + css; + + // Complete paths, but not subdirectories like foo/images/bar.png + code = code.replace(/(["(])(images|icons)\//g, "$1" + staticPrefix + "/$2/"); + + console.log("[Less] compiling ", path || "skin", root); + parser.parse(code, function (err, tree) { + if (err) + return callback(err); + if (libs.compiled) + tree.rules = libs.compiled.rules.concat(tree.rules); + var css = tree.toCSS({ compress: compress }); + if (libs.css && css.substring(0, libs.css.length) == libs.css) { + css = css.substr(libs.css.length); + } else { + console.warn("couldn't strip default less"); + } + callback(null, css); + }); +} + +function lessPathLib(staticPrefix) { + if (!staticPrefix) return ""; + return "@base-path : \"" + staticPrefix + "\";\n" + + "@image-path : \"" + staticPrefix + "/images\";\n" + + "@icon-path : \"" + staticPrefix + "/icons\";\n"; +} + +function stripLess(sources) { + var less = []; + + function addLessFile(pkg, code, file) { + less.push({ + pkg: pkg, + code: code, + path: file + }); + } + + sources.forEach(function(pkg){ + if (pkg.id && (pkg.id.indexOf("text!") > -1) && pkg.id.match(/text\!.*\.(less|css)$/)) { + var source = pkg.source; + pkg.source = ""; + + // ignore certain less files + if (pkg.id.match(/(default-dark|default-white|lesshat|compile_dark|compile_.*?)\.(less|css)/)) + return; + + // console.log("dropping less", pkg.id); + addLessFile(pkg, source, pkg.file); + } + else if (pkg.id && pkg.id.match(/^text\!.*\.xml$/) && pkg.source.match(/<\!\[CDATA\[)([\s\S]*?)(\]\]>)/g, function(m, open, css, close) { + style += css + "\n"; + // console.log("dropping css in skin", pkg.id); + return open + close; + }); + if (style) + addLessFile(pkg, style); + } + }); + + return less; +} + +// Rewrite all the defines to include the id as first arg +function rewriteDefines(sources, opts){ + var keepDeps = opts && opts.keepDepArrays; + sources.forEach(function(pkg){ + if (!pkg.source && !pkg.id) + console.log(pkg); + if (!pkg.id) { + // include literal + } + else if (pkg.id.indexOf("text!") > -1) { + var source = pkg.source.replace(/\\/g, '\\\\').replace(/\n/g, "\\n").replace(/"/g, '\\"'); + pkg.source = 'define("' + pkg.id + '",[],"' + + source + + '");'; + } + else { + var deps = []; + if (keepDeps) { + deps.push("require", "exports", "module"); + if (keepDeps == "all") + deps = deps.concat(pkg.deps); + } + pkg.source = pkg.source.replace(/define\(\s*(?:(\[[^\]]*\]),\s*)?(f)/, function(_, depArray, code) { + return 'define(\"' + pkg.id + '\",' + (depArray || JSON.stringify(deps)) + ', ' + code; + }); + } + }); +} + +function includeArchitect(opts, sources) { + var source; + if (opts.includeConfig) { + source = opts.configFile + ";"; + } + else { + source = 'require(["architect", "./architect-config"], function (architect, plugins) {\n' + + ' architect.resolveConfig(plugins, function (err, config) {\n' + + ' if (err) throw err;\n' + + ' architect.createApp(config);\n' + + ' });\n' + + '});\n'; + + var output = (opts.outputFolder || ".") + "/" + (opts.outputFile || "architect-config.js"); + fs.writeFile(output, opts.configFile, function(err){ + if (!err) + console.log("Written config file in '" + output + "'."); + }); + } + + sources.push({ + id : "bootstrap", + file : "bootstrap", + source : source + }); + +} + + +function writeToFile(result, opts, callback) { + // Write output code + createOutputFolder(opts, function() { + var output = (opts.outputFolder || ".") + "/" + (opts.outputFile || "build.js"); + fs.writeFile(output, result.code, function(err){ + if (err) return callback(err); + if (!opts.quiet) + console.log("Written output in '" + output + "'"); + callback(err, result); + }); + + // Write map file + if (opts.mapFile && result.map) { + output = (opts.outputFolder || ".") + "/" + opts.mapFile; + fs.writeFile(output, result.map, function(err){ + if (err) return callback(err); + if (!opts.quiet) + console.log("Written map file in '" + output + "'"); + }); + } + }); +} + +module.exports = build; +build.writeToFile = writeToFile; diff --git a/node_modules/architect-build/build_support/mini_require.js b/node_modules/architect-build/build_support/mini_require.js new file mode 100644 index 00000000..2236743e --- /dev/null +++ b/node_modules/architect-build/build_support/mini_require.js @@ -0,0 +1,218 @@ +(function() { + +var ACE_NAMESPACE = ""; +var MODULE_LOAD_URL = "/load/module"; + +var global = (function() { return this; })(); +if (!global && typeof window != "undefined") global = window; // can happen in strict mode + + +if (!ACE_NAMESPACE && typeof requirejs !== "undefined") + return; + + +var _define = function(module, deps, payload) { + if (typeof module !== 'string') { + if (_define.original) + _define.original.apply(window, arguments); + else { + console.error('dropping module because define wasn\'t a string.'); + console.trace(); + } + return; + } + + if (arguments.length == 2) + payload = deps; + + _define.amd = true; + if (!_define.modules) { + _define.modules = {}; + _define.payloads = {}; + } + if (_define.modules[module]) + return; + _define.payloads[module] = payload; + _define.modules[module] = null; +}; + +/** + * Get at functionality define()ed using the function above + */ +var _require = function(parentId, module, callback) { + if (Object.prototype.toString.call(module) === "[object Array]") { + var params = []; + for (var i = 0, l = module.length; i < l; ++i) { + var moduleName = normalizeModule(parentId, module[i]); + var dep = lookup(parentId, moduleName); + if (!dep && _require.load) { + return _require.load(moduleName, function() { + if (lookup(parentId, moduleName)) + _require(parentId, module, callback); + }); + } + params.push(dep); + } + if (callback) { + callback.apply(null, params); + } + } + else if (typeof module === 'string') { + var payload = lookup(parentId, module); + if (!payload && _require.original) + return _require.original.apply(this, arguments); + + if (callback) { + callback(); + } + + return payload; + } + else { + if (_require.original) + return _require.original.apply(this, arguments); + } +}; + +var normalizeModule = function(parentId, moduleName) { + // normalize plugin requires + if (moduleName.indexOf("!") !== -1) { + var chunks = moduleName.split("!"); + return normalizeModule(parentId, chunks[0]) + "!" + normalizeModule(parentId, chunks[1]); + } + // normalize relative requires + if (moduleName.charAt(0) == ".") { + var base = parentId.split("/").slice(0, -1).join("/"); + moduleName = (base || parentId) + "/" + moduleName; + + while(moduleName.indexOf(".") !== -1 && previous != moduleName) { + var previous = moduleName; + moduleName = moduleName.replace(/\/\.\//, "/").replace(/[^\/]+\/\.\.\//, ""); + } + } + + return moduleName; +}; + +/** + * Internal function to lookup moduleNames and resolve them by calling the + * definition function if needed. + */ +var lookup = function(parentId, moduleName) { + moduleName = normalizeModule(parentId, moduleName); + + var module = _define.modules[moduleName]; + if (!module) { + module = _define.payloads[moduleName]; + var exports = {}; + if (typeof module === 'function') { + var mod = { + id: moduleName, + uri: '', + exports: exports, + packaged: true + }; + + var req = function(module, callback) { + return _require(moduleName, module, callback); + }; + + req.toUrl = require.toUrl; + _define.modules[moduleName] = exports; + + var returnValue = module(req, exports, mod); + exports = returnValue || mod.exports; + _define.modules[moduleName] = exports; + delete _define.payloads[moduleName]; + } else { + exports = module; + } + module = _define.modules[moduleName] = exports; + } + return module; +}; + +function exportAce(ns) { + var root = global; + if (ns) { + if (!global[ns]) + global[ns] = {}; + root = global[ns]; + } + + if (!root.define || !root.define.packaged) { + _define.original = root.define; + root.define = _define; + root.define.packaged = true; + } + + if (!root.require || !root.require.packaged) { + // _require.original = root.require || _require.original; + root.require = require; + root.require.packaged = true; + } + root.miniRequire = require; +} +var require = function(module, callback) { + return _require("", module, callback); +}; +require.MODULE_LOAD_URL = MODULE_LOAD_URL; + +require.toUrl = function(url) { + var root = "/static"; + var urlMap = require.urlMap || {}; + var parts = url.split("/"); + var top = parts[0]; + parts.shift(); + return [root, urlMap[top] || top].concat(parts).join("/"); +}; + +var loadScript = function(path, callback) { + var head = document.head || document.documentElement; + var s = document.createElement('script'); + + s.src = path; + head.appendChild(s); + + s.onload = s.onreadystatechange = function(_, isAbort) { + if (isAbort || !s.readyState || s.readyState == "loaded" || s.readyState == "complete") { + s = s.onload = s.onreadystatechange = null; + if (!isAbort) + callback(); + } + }; +}; + +_require.load = function(module, callback) { + var i = module.indexOf("!") + 1; + if (i) { + var plugin = module.substring(0, i); + module = module.substr(i); + if (require[plugin]) { + require[plugin](module, callback); + } else { + console.error("require plugin " + plugin + "missing"); + } + } else { + loadScript(require.MODULE_LOAD_URL + "/" + module + ".js", callback); + } +}; + +require["text!"] = function(module, callback) { + var cb = function(e, val) { + if (e) console.error("Couldn't load module " + module, e); + _define.modules["text!" + module] = val; + callback(); + }; + var url = require.MODULE_LOAD_URL + "/" + module; + var xhr = new window.XMLHttpRequest(); + xhr.open("GET", url + "?access_token=fake_token", true); + xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"); + xhr.onload = function(e) { cb(null, xhr.responseText); }; + xhr.onabort = xhr.onerror = function(e) { cb(e); }; + xhr.send(""); +}; + +exportAce(ACE_NAMESPACE); + +})(); diff --git a/node_modules/architect-build/compress.js b/node_modules/architect-build/compress.js new file mode 100644 index 00000000..f4e52eaa --- /dev/null +++ b/node_modules/architect-build/compress.js @@ -0,0 +1,126 @@ +var UglifyJS = require("uglify-js"); + + +function compress(sources, opts) { + if (!opts) + opts = {}; + if (typeof sources == "string") + sources = [{source: sources, file: ""}]; + + var toplevel = null; + var literals = []; + + sources.forEach(function(pkg){ + if (/^"disable compress"/.test(pkg.source)) + return literals.push(pkg.source); + + if (pkg.file) console.log("Adding '" + pkg.file + "'."); + + toplevel = UglifyJS.parse(pkg.source, { + filename: pkg.file.replace(new RegExp("^" + opts.basepath + "/"), ""), //@todo remove prefix + toplevel: toplevel + }); + }); + + if (!toplevel) { + return { code: literals.join("\n"), map: null }; + } + + /** + * UglifyJS contains a scope analyzer that you need to call manually before + * compressing or mangling. Basically it augments various nodes in the AST + * with information about where is a name defined, how many times is a name + * referenced, if it is a global or not, if a function is using eval or the + * with statement etc. I will discuss this some place else, for now what's + * important to know is that you need to call the following before doing + * anything with the tree: + */ + toplevel.figure_out_scope(); + + var compressor = UglifyJS.Compressor({ + warnings: !!opts.verbose, + unsafe: false + }); + var compressed_ast = toplevel.transform(compressor); + + /** + * After compression it is a good idea to call again figure_out_scope + * (since the compressor might drop unused variables / unreachable code and + * this might change the number of identifiers or their position). + * Optionally, you can call a trick that helps after Gzip (counting + * character frequency in non-mangleable words). + */ + compressed_ast.figure_out_scope(); + compressed_ast.compute_char_frequency(); + + // Right now this breaks the LogicBlox workspace; needs further investigation + if (opts.obfuscate) { + compressed_ast.mangle_names({except: ["$", "require", "exports", "initBaseUrls", "initSender"]}); + } + + var outputOptions = opts.oneLine ? {} : { + quote_keys : false, // quote all keys in object literals? + space_colon : false, // add a space after colon signs? + ascii_only : false, // output ASCII-safe? (encodes Unicode characters as ASCII) + inline_script : false, // escape " 200) // no newlines or far apart + return true; +} + +module.exports = compressDir; diff --git a/node_modules/architect-build/copy.js b/node_modules/architect-build/copy.js new file mode 100644 index 00000000..f250cdb6 --- /dev/null +++ b/node_modules/architect-build/copy.js @@ -0,0 +1,133 @@ +var fs = require('fs'); +var path = require('path'); +var mkdirSync = require('mkdirp').sync; + +function convertPath(dir){ + if (process.platform == 'win32' && dir[0] == '/') + dir = dir.replace(/(?:\/cygdrive)?\/(\w)\//, '$1:/'); + return dir; +} + +function copyBinaryFile(srcFile, destFile) { + var BUF_LENGTH = 64*1024; + var buf = new Buffer(BUF_LENGTH); + var bytesRead = BUF_LENGTH; + var pos = 0; + var fdr = fs.openSync(srcFile, 'r'); + var fdw = fs.openSync(destFile, 'w'); + + while (bytesRead === BUF_LENGTH) { + bytesRead = fs.readSync(fdr, buf, 0, BUF_LENGTH, pos); + fs.writeSync(fdw, buf, 0, bytesRead); + pos += bytesRead; + } + + fs.closeSync(fdr); + fs.closeSync(fdw); +} + +function $testFn(re) { + if (!re || typeof re == "function") return re; + return function(name) { return re.test(name); }; +} + +function copy(from, to, options) { + from = convertPath(from); + to = convertPath(to); + if (!options) options = {}; + var exclude = $testFn(options.exclude); + var include = $testFn(options.include); + if (!options.onError) options.onError = logError; + + function excludePath(name, parent) { + if ((exclude && exclude(name, parent)) && !(include && include(name, parent))) + return true; + } + + function filterCopyDir(from, to) { + var files; + try { + files = fs.readdirSync(from); + } catch(e) { + return options.onError(e); + } + var dirCreated = false; + files.forEach(function(x) { + if (excludePath(x, from)) + return; + var stat; try { + stat = fs.lstatSync(from + '/' + x); + } catch(e) { + return options.onError(e); + } + + if (stat.isSymbolicLink()) + return; + if (stat.isDirectory()) { + if (options.shallow) + return; + filterCopyDir(from + '/' + x, to + '/' + x); + } else { + if (!dirCreated) { + if (options.onDir && options.onDir(from, to) === false) + return; + try { + mkdirSync(to); + } catch (e) { + return options.onError(e); + } + dirCreated = true; + } + try { + copy.file(from+ '/' + x, to+ '/' + x, options.replace); + } catch(e) { + return options.onError(e); + } + } + }); + } + filterCopyDir(from, to); +} +copy.dirs = function(from, to, dirs, options) { + dirs.forEach(function(d) { + copy(from + "/" + d, to + "/" + d, options); + }); +}; +copy.file = function(from, to, replace) { + from = convertPath(from); + to = convertPath(to); + + if (replace) { + var data = fs.readFileSync(from, "utf8"); + if (Array.isArray(replace)) + data = replace.reduce(function(a, f) {return f(a)}, data); + else if (replace) + data = replace(data); + } + + function write() { + if (replace) + fs.writeFileSync(to, data, "utf8"); + else + copyBinaryFile(from, to); + } + try { + write(); + } catch(e) { + if (e.code == "ENOENT") { + mkdirSync(path.dirname(to)); + write(); + } else { + throw e; + } + } + +}; + +function logError() { + console.error.apply(console, arguments); +} + +copy.convertPath = convertPath; +module.exports = copy; + diff --git a/node_modules/architect-build/module-deps.js b/node_modules/architect-build/module-deps.js new file mode 100644 index 00000000..94ab2b85 --- /dev/null +++ b/node_modules/architect-build/module-deps.js @@ -0,0 +1,401 @@ +var fs = require('fs'); +var pathLib = require('path'); + +var through = require('through'); + +var nativeNodeModules = ["fs", "path", "require", "exports", "module"]; + +module.exports = function(mains, opts) { + if (!Array.isArray(mains)) mains = [mains].filter(Boolean); + + opts = opts || Object.create(null); + opts.modules = Object.create(null); // {id, path, contents, deps} + + var cache = opts.cache; + if (cache) + cache.files = cache.files || Object.create(null); + + if (!opts.ignore) + opts.ignore = []; + else + opts.ignore = opts.ignore.reduce(function(map, ignore) { + map[ignore] = true; + return map; + }, {}); + + if (opts.debug) + opts.transforms = [wrapUMD, debugSrc]; + + if (!opts.transforms) + opts.transforms = []; + + opts.transforms.push(removeLicenceComments, wrapUMD); + + if (opts.pathConfig) { + opts.paths = opts.paths || opts.pathConfig.paths; + opts.root = opts.root || opts.pathConfig.root; + opts.packages = opts.packages || opts.pathConfig.packages; + opts.pathMap = opts.pathMap || opts.pathConfig.pathMap; + } + + var root = opts.root || ""; + var paths = opts.paths || {}; + var pathMap = opts.pathMap; + opts.packages && opts.packages.forEach(function(pkg) { + paths[pkg.name] = pkg; + }); + + function idToPath(mod, cb) { + if (!mod.id && mod.path) + return cb(null, mod.path); + var id = mod.id; + + if (id.indexOf("!") != -1) { + var chunks = id.split("!"); + id = chunks[1]; + mod.loaderModule = chunks[0]; + } + + id = resolveModuleId(id, paths); + if (pathMap) + id = resolveModulePath(id, pathMap); + if (!mod.loaderModule && !/\.js$/.test(id)) + id += ".js"; + cb(null, id); + } + + function readModule(mod, cb) { + if (typeof mod == "string") + mod = {id: mod}; + + var id = mod.id; + if (opts.modules[id]) { + return cb(null, null); + } + + if (opts.ignore[id]) { + ignoreDep(mod); + return cb(); + } + + opts.modules[id] = mod; + + idToPath(mod, function(err, path) { + var filepath = absolutePath(root, path); + mod.path = path; + mod.file = filepath; + + if (cache && cache.files[mod.file] != undefined) { + return setModuleSource(mod, cache.files[mod.file], cb); + } + + fs.readFile(filepath, 'utf8', function (err, src) { + if (err) { + if (err.code == 'ENOENT' || err.code == "ENOTDIR") { + ignoreDep(mod); + cb(); + return; + } + if (err.code == 'EMFILE') { + opts.modules[id] = null; + wait(err, mod, cb); + return; + } + return output.emit('error', err); + } + setModuleSource(mod, src, cb); + }); + }); + } + + function setModuleSource(mod, src, cb) { + if (cache) + cache.files[mod.file] = src; + mod.source = src; + // todo: support loaders other than text? + if (!mod.noRequire && !mod.literal && !mod.loaderModule && !mod.noDeps) { + mod.deps = getDeps(src, mod.id); + // console.log(mod.id, mod.deps) + mod.deps.forEach(function(dep) { + addToQueue(dep, mod); + }); + } + cb(null, mod); + } + + function ignoreDep(mod) { + var parent = mod.parent || {}; + if (nativeNodeModules[mod.id] === -1) { + console.log("file '" + mod.file + "' doesn't exisit"); + console.log("ignoring dependency '" + mod.id + "' of '" + parent.id + "'"); + } + if (!parent.ignoredDeps) + parent.ignoredDeps = []; + parent.ignoredDeps.push(mod); + } + + var output = through(); + + var pending = []; + var active = 0; + var maxActive = 100; + var waitT = 0, timer; + + function addToQueue(id, parent) { + var mod = typeof id == "string" + ? {id: id, parent: parent} + : id; + pending.push(mod); + } + + function wait(err, mod) { + active--; + pending.push(mod); + if (active > 0) { + if (active > 2 && active < maxActive) + maxActive = active; + } else if (waitT < 5000) { + if (!timer) { + waitT = 1.5 * waitT + 1 +0.001 * waitT * waitT; + timer = setTimeout(function() { + timer = null; + takeFromQueue(); + if (active) + waitT = 0; + }, waitT); + } + } else { + output.emit('error', err); + } + } + + function takeFromQueue() { + while (active < maxActive) { + var mod = pending.pop(); + if (!mod) + break; + active++; + readModule(mod, onModuleReady); + } + } + + function onModuleReady(err, module) { + active--; + // console.log("pending", pending) + if (module && module.source != undefined) { + applyTransforms(module); + output.queue(module); + } else if (module) { + module.parent = null; + console.dir(module); + } + + if (pending.length || active) + takeFromQueue(); + else + end(); + } + + function end() { + opts._createDepMap && fs.writeFileSync("dep_map.js", JSON.stringify(opts.modules, function(key, val) { + if (key == "source") + return val && val[0]; + if (key == "parent") + return val && val.id; + return val; + }, 4)); + process.nextTick(function() { + output.emit("end"); + }); + } + + function applyTransforms(module) { + if (!module.source || module.literal) + return; // console.log(module) + var transforms = module.transforms || opts.transforms; + transforms.forEach(function(transform) { + transform(module); + }); + } + + + mains.forEach(function(dep) { + addToQueue(dep, {id: "#root"}); + }); + takeFromQueue(); + + return output; +}; + + +function normalizeModule(parentId, moduleName) { + // normalize plugin requires + if (moduleName.indexOf("!") !== -1) { + var chunks = moduleName.split("!"); + return normalizeModule(parentId, chunks[0]) + "!" + normalizeModule(parentId, chunks[1]); + } + // normalize relative requires + if (moduleName.charAt(0) == ".") { + var base = parentId.split("/").slice(0, -1).join("/"); + moduleName = (base || parentId) + "/" + moduleName; + + while (moduleName.indexOf(".") !== -1 && previous != moduleName) { + var previous = moduleName; + moduleName = moduleName.replace(/\/\.\//, "/").replace(/[^\/]+\/\.\.\//, ""); + } + } + return moduleName; +} +function getSubmodules(src, name) { + var m = src.replace(/^\s*\/\/.+|^\s*\/\*[\s\S]*?\*\//gm, "") + .match(/require\(\[([^\]]+)\]/gm); + if (!m) + return []; + var deps = []; + m.forEach(function(dep) { + var re = /["']([^"']+?)["']/g; + var m; + while ((m = re.exec(dep))) { + deps.push(normalizeModule(name, m[1])); + } + }); + // console.log(deps); + return deps; +} +function getReqDeps(src, name) { + var m = src.replace(/^\s*\/\/.+|^\s*\/\*[\s\S]*?\*\//gm, "") + .match(/require\s*\(\s*(["'][^"'\n\r]+["'])\s*\)/gm); + if (!m) + return []; + + return m.map(function(r) { + r = r.match(/["']([^"']+?)["']/)[1]; + r = normalizeModule(name, r); + return r; + }); +} +function getAmdDeps(src, name) { + var m = src.match(/define\(\[[^\]]+\]/gm); + if (!m) + return []; + + var deps = []; + m.forEach(function(dep) { + var re = /["']([^"']+?)["']/g; + var m; + while ((m = re.exec(dep))) { + deps.push(normalizeModule(name, m[1])); + } + }); + // console.log(deps); + return deps; +} +function getDeps(src, name) { + return getReqDeps(src, name).concat(getAmdDeps(src, name)); +} +function resolveModuleId(id, paths) { + var chunks = id.split("/"); + + var alias = paths[chunks[0]]; + if (typeof alias == "string") { + chunks[0] = alias; + } else if (alias) { + chunks[0] = alias.location; + if (chunks.length == 1) + chunks.push(alias.main || alias.name); + } else if (alias === false) { + return ""; + } + + return chunks.join("/"); +} +function resolveModulePath(id, pathMap) { + var testPath = id, tail = ""; + if (testPath[0] != "/") + testPath = "/" + testPath; + while (testPath) { + if (pathMap[testPath]) { + return pathMap[testPath] + (tail && "/" + tail); + } + var i = testPath.lastIndexOf("/"); + if (i === -1) break; + tail = testPath.substr(i + 1) + (tail && "/" + tail); + testPath = testPath.slice(0, i); + } + return id; +} + + +function absolutePath(root, relative) { + // console.log(root, relative) + if (relative[0] == "/" || relative[1] == ":") + return relative; + return pathLib.join(root, relative); +} + + +// src transformations +function removeUseStrict(module) { + module.source = module.source.replace(/['"]use strict['"];/g, ""); +} + +function removeLicenceComments(module) { + module.source = module.source.replace(/(?:(;)|\n|^)\s*\/\*[\d\D]*?\*\/|(\n|^)\s*\/\/.*/g, "$1"); +} +function removeLicenceCommentsKeepLines(module) { + return module.source = module.source.replace(/(?:(;)|\n|^)\s*\/\*[\d\D]*?\*\/|\n\s*\/\/.*/g, function(cm, start) { + return (start||"") + cm.replace(/.+/g, ""); + }); +} + +function wrapUMD(module) { + if (module.loaderModule || module.noRequire) + return; + var firstDefineCall = module.source.match(/define\([^)]*/); + if (firstDefineCall) { + // check if it is a normal define or some crazy umd trick + if (/define\(function\s*\(/.test(firstDefineCall[0])) + return; + if (/define\(\[[^\]]*\],\s*function\(/.test(firstDefineCall[0])) + return; + } + console.log("wrapping module " + module.id); + + + module.source = 'define(function(require, exports, module) {\n' + + 'var _ = {require: require, exports: exports, module: module};\n' + + 'exports = undefined; module = undefined;\n' + + 'function define(name, deps, m) {\n' + + ' if (typeof name == "function") {\n' + + ' m = name; deps = ["require", "exports", "module"]; name = _.module.id\n' + + ' }\n' + + ' if (typeof name == "object") {\n' + + ' m = deps; deps = name; name = _.module.id\n' + + ' }\n' + + ' if (typeof deps == "function") {\n' + + ' m = deps; deps = [];\n' + + ' }\n' + + ' var ret = m ? m.apply(_.module, deps.map(function(n){return _[n] || require(n)})) : deps\n' + + ' if (ret) _.module.exports = ret;\n' + + '}\n' + + 'define.amd = true;' + + module.source + + '});'; + +} + +function debugSrc(module) { + if (module.loaderModule) + return; + var url = "http://localhost:8181/" + module.id; + module.source = "try{eval(" + quote(module.source + "\n//@ sourceURL=" + url) + ");}catch(e){throw e.message + url}"; +} + +function quote(str) { + return "'" + + str.replace(/[\\']/g, "\\$&").replace(/\n/g, "\\n") + + "'"; +} + + +module.exports.resolveModulePath = resolveModulePath; \ No newline at end of file diff --git a/node_modules/architect-build/npm_build.js b/node_modules/architect-build/npm_build.js new file mode 100644 index 00000000..702a4d00 --- /dev/null +++ b/node_modules/architect-build/npm_build.js @@ -0,0 +1,208 @@ +var patchTemplate = ";(" +function() { + // automatically generated by architect-build + /*global main*/ + var moduleMap = require("./module-map.json"); + var Module = require("module"); + var root = __dirname; + var path = require('path'); + Module._resolveFilename_orig = Module._resolveFilename; + function relPath(filename) { + return path.relative(root, filename + "").replace(/\\/g, "/"); + } + Module._resolveFilename = function(id, parent) { + var parentId = parent && relPath(parent.filename); + var key = /^[.][.\/]/.test(id) + ? relPath(path.join(path.dirname(parentId), id)) + : id + "|" + parentId; + + if (moduleMap[key]) + return path.join(root, moduleMap[key]); + var realPath = Module._resolveFilename_orig(id, parent); + // if (realPath != id) console.log(id, key); + return realPath; + }; + main.onResolvePlugins = function(plugins, base) { + var resolvedConfig = moduleMap["!config"]; + plugins.forEach(function(plugin, index) { + // Shortcut where string is used for plugin without any options. + if (typeof plugin === "string") + plugin = plugins[index] = { packagePath: plugin }; + plugin.disableUnpackagedClient = true; + // The plugin is a package on the disk. We need to load it. + if (plugin.hasOwnProperty("packagePath") && !plugin.hasOwnProperty("setup")) { + try { + var defaults = resolvedConfig[plugin.packagePath]; + plugin.packagePath = path.join(root, defaults.packagePath); + plugin.consumes = defaults.consumes; + plugin.provides = defaults.provides; + plugin.setup = require(plugin.packagePath); + } catch(e) {} + } + }); + }; +} + ")();"; + +////////////////////////////////////////////////////////////////////////// + +var Module = require("module"); +var path = require("path"); +var fs = require("fs"); +var convertPath = require("./copy").convertPath; +var loaded, moduleMap, root; +var ignore; + +function addModule(id, parent) { + if (ignore && ignore(id)) return; + if (!parent) { + parent = { + relPath: id, + id: id, + filename: root, + paths: [root] // Module._nodeModulePaths(path.dirname(filename)) + }; + } + var filename, text; + if (id.indexOf("!") != -1) { + + } + try { + filename = Module._resolveFilename(id, parent); + } catch(e) { + console.error(id); + } + if (filename == parent.filename) + return; + var key = /^[.][.\/]/.test(id) + ? relPath(path.join(path.dirname(parent.id), id)) + : id + "|" + parent.relPath; + + if (!/[\\\/]/.test(filename) || moduleMap[key] !== undefined) + return; + try { + text = fs.readFileSync(filename, "utf8") + .replace(/^\s*\/\/.+|^\s*\/\*[\s\S]*?\*\//gm, ""); + } catch(e) { + moduleMap[key] = ""; + return; + } + var re = /require\s*\(([^\)]+)\)/g, m; + var children = []; + while ((m = re.exec(text))) { + var name = m[1].trim(); + if (!/^(['"])([^'"]*)\1$/.test(name)) { + m = /^(['"])([^'"]+)\1\s*[+]\s*\w+(\s*[+]\s*['"]\.js['"])?$/.exec(name); + if (m) { + var dirname = m[2]; + if (dirname.slice(-1) !== "/") + dirname = path.dirname(dirname) + "/"; + var dirpath = path.join(path.dirname(filename), dirname); + try { + var files = fs.readdirSync(dirpath); + files.forEach(function(f) { + var ext = f.substr(f.lastIndexOf(".")); + if (ext != ".js") return; + if (!m[3]) f = f.slice(0, -ext.length); + children.push(dirname + f); + }); + console.warn("adding drectory ", dirpath, "for", id); + continue; + } catch(e) {} + } + console.error("non static require ", name, "from", id); + } else { + children.push(name.slice(1, -1)); + } + } + var module = { + relPath: relPath(filename), + id: filename, + filename: filename, + paths: Module._nodeModulePaths(path.dirname(filename)) + }; + + loaded[filename] = module; + moduleMap[key] = module.relPath; + children.forEach(function(id) { + addModule(id, module); + }); +} + +function relPath(filename) { + return path.relative(root, filename).replace(/\\/g, "/"); +} + +function build(base, args, cb) { + root = path.resolve(base); + args.push("--_getConfig", "true"); + loaded = Object.create(null); + moduleMap = Object.create(null); + + var server = require(root + "/server"); + server.onResolvePlugins = function(plugins, base) { + base = relPath(base); + plugins.forEach(function(plugin, index) { + if (typeof plugin === "string") + plugin = plugins[index] = { packagePath: plugin }; + plugin.packagePath_orig = plugin.packagePath; + }); + }; + server(args, null, function(err, config) { + addModule("server.js"); + config.forEach(function(plugin) { + if (plugin.packagePath) + addModule(relPath(plugin.packagePath)); + }); + var resolvedConfig = moduleMap["!config"] = {}; + config.forEach(function(plugin) { + if (plugin.packagePath && plugin.packagePath_orig) { + resolvedConfig[plugin.packagePath_orig] = { + packagePath: relPath(Module._resolveFilename(plugin.packagePath)), + consumes: plugin.consumes, + provides: plugin.provides + }; + } + }); + function unique(array) { + var map = Object.create(null); + array.forEach(function(x) {map[x] = 1}); + return Object.keys(map); + } + var roots = unique(Object.keys(loaded).map(function(x) { + x = x.replace(/([\\\/](?:plugins|node_modules)[\\\/][^\\\/]+).*?$/, "$1"); + return relPath(x); + })); + + // console.log(loaded) + + cb && cb(null, { + roots: roots, + moduleMap: moduleMap, + loaded: loaded + }); + }); +} + +/* +root = "/newclient" +dest = "/build/webkitbuilds/app.nw" +var args = ["local","-s", "local"]; +*/ +module.exports = function(options, cb) { + var dest = convertPath(options.dest); + var root = convertPath(options.root); + var args = options.args; + ignore = options.ignore && function(id) { + return options.ignore.test(id); + }; + build(root, args, function(err, result) { + var serverSource = fs.readFileSync(root + "/server.js", "utf8"); + serverSource = serverSource.replace(/^(#.*|"use strict";?|\s)*/, function(a) { + return a.trim() + "\n\n" + patchTemplate + "\n\n"; + }); + fs.writeFileSync(dest + "/server.js", serverSource, "utf8"); + fs.writeFileSync(dest + "/module-map.json", JSON.stringify(result.moduleMap), "utf8"); + + cb(null, result); + }); +}; + diff --git a/node_modules/architect-build/package.json b/node_modules/architect-build/package.json new file mode 100644 index 00000000..731f226d --- /dev/null +++ b/node_modules/architect-build/package.json @@ -0,0 +1,32 @@ +{ + "name": "architect-build", + "description": "Concatenates and uglifies an architect config into one file with source map and incremental update support", + "version": "0.1.0", + "author": "Ajax.org B.V. ", + "contributors": [ + { + "name": "Ruben Daniels", + "email": "ruben@c9.io" + } + ], + "main": "build.js", + "repository": { + "type": "git", + "url": "http://github.com/c9/architect-build.git" + }, + "dependencies": { + "through": "2.2.0", + "async": "", + "mkdirp": "" + }, + "devDependencies": {}, + "optionalDependencies": { + "uglify-js": "2.4.14" + }, + "licenses": [ + { + "type": "MIT", + "url": "http://github.com/c9/architect-build/raw/master/LICENSE" + } + ] +} diff --git a/node_modules/architect/.gitignore b/node_modules/architect/.gitignore new file mode 100644 index 00000000..bdf8ef1d --- /dev/null +++ b/node_modules/architect/.gitignore @@ -0,0 +1,3 @@ +/node_modules/ +.settings.xml +.c9revisions diff --git a/node_modules/architect/.jamignore b/node_modules/architect/.jamignore new file mode 120000 index 00000000..93cc3ad3 --- /dev/null +++ b/node_modules/architect/.jamignore @@ -0,0 +1 @@ +.npmignore \ No newline at end of file diff --git a/node_modules/architect/.npmignore b/node_modules/architect/.npmignore new file mode 100644 index 00000000..cb5fc203 --- /dev/null +++ b/node_modules/architect/.npmignore @@ -0,0 +1 @@ +demos diff --git a/node_modules/architect/LICENSE b/node_modules/architect/LICENSE new file mode 100644 index 00000000..64d23692 --- /dev/null +++ b/node_modules/architect/LICENSE @@ -0,0 +1,21 @@ +The MIT License + +Copyright (c) 2012 ajax.org B.V + +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. \ No newline at end of file diff --git a/node_modules/architect/README.markdown b/node_modules/architect/README.markdown new file mode 100644 index 00000000..05ad1db0 --- /dev/null +++ b/node_modules/architect/README.markdown @@ -0,0 +1,108 @@ +# Architect + +Architect is a simple but powerful structure for Node.js applications. Using Architect, +you set up a simple configuration and tell Architect which plugins you want to load. Each +plugin registers itself with Architect, so other plugins can use its functions. Plugins can +be maintained as NPM packages so they can be dropped in to other Architect apps. + +## Plugin Interface + +```js +// auth.js + +/* All plugins must export this public signature. + * @options is the hash of options the user passes in when creating an instance + * of the plugin. + * @imports is a hash of all services this plugin consumes. + * @register is the callback to be called when the plugin is done initializing. + */ +module.exports = function setup(options, imports, register) { + + // "database" was a service this plugin consumes + var db = imports.database; + + register(null, { + // "auth" is a service this plugin provides + auth: { + users: function (callback) { + db.keys(callback); + }, + authenticate: function (username, password, callback) { + db.get(username, function (user) { + if (!(user && user.password === password)) { + return callback(); + } + callback(user); + }); + } + } + }); +}; +``` + +Each plugin is a node module complete with a package.json file. It need not +actually be in npm, it can be a simple folder in the code tree. + +```json +{ + "name": "auth", + "version": "0.0.1", + "main": "auth.js", + "private": true, + "plugin": { + "consumes": ["database"], + "provides": ["auth"] + } +} +``` + +## Config Format + +The `loadConfig` function below can read an architect config file. This file can be either JSON or JS (or anything that node's require can read). + +The sample calculator app has a config like this: + +```js +module.exports = [ + { packagePath: "architect-http", port: 8080 }, + { packagePath: "architect-http-static", root: "www" }, + "./plugins/calculator", + "./plugins/db", + "./plugins/auth" +] +``` + +Notice that the config is a list of plugin config options. If the only option in the config is `packagePath`, then a string can be used in place of the object. If you want to pass other options to the plugin when it's being created, you can put arbitrary properties here. + +The `plugin` section in each plugin's package.json is also merged in as a prototype to the main config. This is where `provides` and `consumes` properties are usually set. + +## Architect main API + +The architect module exposes two functions as it's main API. + +### createApp(config, [callback]) + +This function starts an architect config. The return value is an `Architect` instance. The optional callback will listen for both "error" and "ready" on the app object and report on which one happens first. + +### loadConfig(configPath) + +This is a sync function that loads a config file and parses all the plugins into a proper config object for use with `createApp`. While this uses sync I/O all steps along the way are memoized and I/O only occurs on the first invocation. It's safe to call this in an event loop provided a small set of configPaths are used. + +## Class: Architect + +Inherits from `EventEmitter`. + +The `createApp` function returns an instance of `Architect`. + +### Event: "service" (name, service) + +When a new service is registered, this event is emitted on the app. Name is the short name for the service, and service is the actual object with functions. + +### Event: "plugin" (plugin) + +When a plugin registers, this event is emitted. + +### Event: "ready" (app) + +When all plugins are done, the "ready" event is emitted. The value is the Architect instance itself. + diff --git a/node_modules/architect/architect.js b/node_modules/architect/architect.js new file mode 100644 index 00000000..512f2994 --- /dev/null +++ b/node_modules/architect/architect.js @@ -0,0 +1,597 @@ +( // Module boilerplate to support node.js and AMD. + (typeof module !== "undefined" && function (m) { module.exports = m(require('events')); }) || + (typeof define === "function" && function (m) { define(["events"], m); }) +)(function (events) { +"use strict"; +var EventEmitter = events.EventEmitter; + +var exports = {}; + +var DEBUG = typeof location != "undefined" && location.href.match(/debug=[12]/) ? true : false; + +// Only define Node-style usage using sync I/O if in node. +if (typeof module === "object") (function () { + var dirname = require('path').dirname; + var resolve = require('path').resolve; + var existsSync = require('fs').existsSync || require('path').existsSync; + var realpathSync = require('fs').realpathSync; + var exists = require('fs').exists || require('path').exists; + var realpath = require('fs').realpath; + var packagePathCache = {}; + + exports.loadConfig = loadConfig; + exports.resolveConfig = resolveConfig; + + // This is assumed to be used at startup and uses sync I/O as well as can + // throw exceptions. It loads and parses a config file. + function loadConfig(configPath, callback) { + var config = require(configPath); + var base = dirname(configPath); + + return resolveConfig(config, base, callback); + } + + function resolveConfig(config, base, callback) { + if (!callback) + return resolveConfigSync(config, base); + else + resolveConfigAsync(config, base, callback); + } + + function resolveConfigSync(config, base) { + config.forEach(function (plugin, index) { + // Shortcut where string is used for plugin without any options. + if (typeof plugin === "string") { + plugin = config[index] = { packagePath: plugin }; + } + // The plugin is a package on the disk. We need to load it. + if (plugin.hasOwnProperty("packagePath") && !plugin.hasOwnProperty("setup")) { + var defaults = resolveModuleSync(base, plugin.packagePath); + Object.keys(defaults).forEach(function (key) { + if (!plugin.hasOwnProperty(key)) { + plugin[key] = defaults[key]; + } + }); + plugin.packagePath = defaults.packagePath; + plugin.setup = require(plugin.packagePath); + } + }); + return config; + } + + function resolveConfigAsync(config, base, callback) { + function resolveNext(i) { + if (i >= config.length) { + return callback(null, config); + } + + var plugin = config[i]; + + // Shortcut where string is used for plugin without any options. + if (typeof plugin === "string") { + plugin = config[i] = { packagePath: plugin }; + } + // The plugin is a package on the disk. We need to load it. + if (plugin.hasOwnProperty("packagePath") && !plugin.hasOwnProperty("setup")) { + resolveModule(base, plugin.packagePath, function(err, defaults) { + if (err) return callback(err); + + Object.keys(defaults).forEach(function (key) { + if (!plugin.hasOwnProperty(key)) { + plugin[key] = defaults[key]; + } + }); + plugin.packagePath = defaults.packagePath; + try { + plugin.setup = require(plugin.packagePath); + } catch(e) { + return callback(e); + } + + return resolveNext(++i); + }); + return; + } + + return resolveNext(++i); + } + + resolveNext(0); + } + + // Loads a module, getting metadata from either it's package.json or export + // object. + function resolveModuleSync(base, modulePath) { + var packagePath; + try { + packagePath = resolvePackageSync(base, modulePath + "/package.json"); + } + catch (err) { + if (err.code !== "ENOENT") throw err; + } + var metadata = packagePath && require(packagePath).plugin || {}; + if (packagePath) { + modulePath = dirname(packagePath); + } else { + modulePath = resolvePackageSync(base, modulePath); + } + var module = require(modulePath); + metadata.provides = metadata.provides || module.provides || []; + metadata.consumes = metadata.consumes || module.consumes || []; + metadata.packagePath = modulePath; + return metadata; + } + + // Loads a module, getting metadata from either it's package.json or export + // object. + function resolveModule(base, modulePath, callback) { + resolvePackage(base, modulePath + "/package.json", function(err, packagePath) { + //if (err && err.code !== "ENOENT") return callback(err); + + var metadata = {}; + if (!err) { + try { + metadata = packagePath && require(packagePath).plugin || {}; + } catch(e) { + return callback(e); + } + } + + (function(next) { + if (err) { + //@todo Fabian what is a better way? + resolvePackage(base, modulePath + ".js", next); + } + else if (packagePath) { + next(null, dirname(packagePath)); + } + else { + resolvePackage(base, modulePath, next); + } + })(function(err, modulePath) { + if (err) return callback(err); + + var module; + try { + module = require(modulePath); + } catch(e) { + return callback(e); + } + + metadata.provides = metadata.provides || module.provides || []; + metadata.consumes = metadata.consumes || module.consumes || []; + metadata.packagePath = modulePath; + callback(null, metadata); + }); + }); + } + + // Node style package resolving so that plugins' package.json can be found relative to the config file + // It's not the full node require system algorithm, but it's the 99% case + // This throws, make sure to wrap in try..catch + function resolvePackageSync(base, packagePath) { + var originalBase = base; + if (!(base in packagePathCache)) { + packagePathCache[base] = {}; + } + var cache = packagePathCache[base]; + if (packagePath in cache) { + return cache[packagePath]; + } + var newPath; + if (packagePath[0] === "." || packagePath[0] === "/") { + newPath = resolve(base, packagePath); + if (!existsSync(newPath)) { + newPath = newPath + ".js"; + } + if (existsSync(newPath)) { + newPath = realpathSync(newPath); + cache[packagePath] = newPath; + return newPath; + } + } + else { + while (base) { + newPath = resolve(base, "node_modules", packagePath); + if (existsSync(newPath)) { + newPath = realpathSync(newPath); + cache[packagePath] = newPath; + return newPath; + } + base = resolve(base, '..'); + } + } + var err = new Error("Can't find '" + packagePath + "' relative to '" + originalBase + "'"); + err.code = "ENOENT"; + throw err; + } + + function resolvePackage(base, packagePath, callback) { + var originalBase = base; + if (!packagePathCache.hasOwnProperty(base)) { + packagePathCache[base] = {}; + } + var cache = packagePathCache[base]; + if (cache.hasOwnProperty(packagePath)) { + return callback(null, cache[packagePath]); + } + if (packagePath[0] === "." || packagePath[0] === "/") { + var newPath = resolve(base, packagePath); + exists(newPath, function(exists) { + if (exists) { + realpath(newPath, function(err, newPath) { + if (err) return callback(err); + + cache[packagePath] = newPath; + return callback(null, newPath); + }); + } else { + var err = new Error("Can't find '" + packagePath + "' relative to '" + originalBase + "'"); + err.code = "ENOENT"; + return callback(err); + } + }); + } + else { + tryNext(base); + } + + function tryNext(base) { + if (base == "/") { + var err = new Error("Can't find '" + packagePath + "' relative to '" + originalBase + "'"); + err.code = "ENOENT"; + return callback(err); + } + + var newPath = resolve(base, "node_modules", packagePath); + exists(newPath, function(exists) { + if (exists) { + realpath(newPath, function(err, newPath) { + if (err) return callback(err); + + cache[packagePath] = newPath; + return callback(null, newPath); + }); + } else { + var nextBase = resolve(base, '..'); + if (nextBase === base) + tryNext("/"); // for windows + else + tryNext(nextBase); + } + }); + } + } + + +}()); + +// Otherwise use amd to load modules. +else (function () { + exports.loadConfig = loadConfig; + exports.resolveConfig = resolveConfig; + + function loadConfig(path, callback) { + require([path], function (config) { + resolveConfig(config, callback); + }); + } + + function resolveConfig(config, base, callback) { + if (typeof base == "function") { + callback = base; + base = ""; + } + + var paths = [], pluginIndexes = {}; + config.forEach(function (plugin, index) { + // Shortcut where string is used for plugin without any options. + if (typeof plugin === "string") { + plugin = config[index] = { packagePath: plugin }; + } + // The plugin is a package over the network. We need to load it. + if (plugin.hasOwnProperty("packagePath") && !plugin.hasOwnProperty("setup")) { + paths.push((base || "") + plugin.packagePath); + pluginIndexes[plugin.packagePath] = index; + } + }); + // Mass-Load path-based plugins using amd's require + require(paths, function () { + var args = arguments; + paths.forEach(function (name, i) { + var module = args[i]; + var plugin = config[pluginIndexes[name]]; + plugin.setup = module; + plugin.provides = module.provides || []; + plugin.consumes = module.consumes || []; + }); + callback(null, config); + }); + } +}()); + +exports.createApp = createApp; +exports.Architect = Architect; + +// Check a plugin config list for bad dependencies and throw on error +function checkConfig(config, lookup) { + + // Check for the required fields in each plugin. + config.forEach(function (plugin) { + if (plugin.checked) { return; } + if (!plugin.hasOwnProperty("setup")) { + throw new Error("Plugin is missing the setup function " + JSON.stringify(plugin)); + } + if (!plugin.hasOwnProperty("provides")) { + throw new Error("Plugin is missing the provides array " + JSON.stringify(plugin)); + } + if (!plugin.hasOwnProperty("consumes")) { + throw new Error("Plugin is missing the consumes array " + JSON.stringify(plugin)); + } + }); + + return checkCycles(config, lookup); +} + +function checkCycles(config, lookup) { + var plugins = []; + config.forEach(function(pluginConfig, index) { + plugins.push({ + packagePath: pluginConfig.packagePath, + provides: pluginConfig.provides.concat(), + consumes: pluginConfig.consumes.concat(), + i: index + }); + }); + + var resolved = { + hub: true + }; + var changed = true; + var sorted = []; + + while(plugins.length && changed) { + changed = false; + + plugins.concat().forEach(function(plugin) { + var consumes = plugin.consumes.concat(); + + var resolvedAll = true; + for (var i=0; i", + "contributors": [ + { + "name": "Tim Caswell", + "email": "tim@c9.io" + }, + { + "name": "Fabian Jakobs", + "email": "fabian@c9.io" + }, + { + "name": "Christoph Dorn", + "email": "christoph@christophdorn.com" + } + ], + "main": "architect.js", + "repository": { + "type": "git", + "url": "http://github.com/c9/architect.git" + }, + "dependencies": {}, + "devDependencies": {}, + "optionalDependencies": {}, + "licenses": [ + { + "type": "MIT", + "url": "http://github.com/c9/architect/raw/master/LICENSE" + } + ] +} diff --git a/node_modules/architect/plugins/architect.log/log-service.js b/node_modules/architect/plugins/architect.log/log-service.js new file mode 100644 index 00000000..57cf7808 --- /dev/null +++ b/node_modules/architect/plugins/architect.log/log-service.js @@ -0,0 +1,36 @@ +"use strict"; + +module.exports = function startup(options, imports, register) { + var logger = new LogService(); + + register(null, { + log: { + log: logger.log.bind(logger), + info: logger.info.bind(logger), + warn: logger.warn.bind(logger), + error: logger.error.bind(logger) + } + }); +}; + +var LogService = module.exports.LogService = function() {}; + +(function() { + + this.log = function() { + console.log.apply(console, arguments); + }; + + this.info = function() { + console.info.apply(console, arguments); + }; + + this.warn = function() { + console.warn.apply(console, arguments); + }; + + this.error = function() { + console.error.apply(console, arguments); + }; + +}).call(LogService.prototype); \ No newline at end of file diff --git a/node_modules/architect/plugins/architect.log/package.json b/node_modules/architect/plugins/architect.log/package.json new file mode 100644 index 00000000..7e0b4dec --- /dev/null +++ b/node_modules/architect/plugins/architect.log/package.json @@ -0,0 +1,13 @@ +{ + "name": "architect.log", + "version": "0.0.1", + + "main": "./log-service", + + "plugin": { + "module": "./log-service", + "provides": [ + "log" + ] + } +} \ No newline at end of file diff --git a/node_modules/c9/assert.js b/node_modules/c9/assert.js new file mode 100644 index 00000000..905d9c82 --- /dev/null +++ b/node_modules/c9/assert.js @@ -0,0 +1,44 @@ +/** + * Cloud9 assertion support. + * + * @copyright 2011, Ajax.org B.V. + * @license GPLv3 + */ +define(function(require, exports, module) { + + var assert = function(value, message) { + if (!value) + throw new Error("Assertion failed: " + (message || value)); + }; + + var assertEqual = function(value1, value2, message) { + if (value1 != value2) + throw new Error("Assertion failed. " + (message || "") + " got\n " + value1 + "expected\n " + value2); + }; + + module.exports = function(value, message) { + assert(value, message); + }; + + module.exports.equal = function(value1, value2, message) { + assertEqual(value1, value2, message); + }; + + if (typeof process === "undefined") + return; + + if (process.versions && process.versions['node-webkit']) + return; + + // Use node's assert module + require(["assert"], function(nodeAssert) { + assert = nodeAssert; + assertEqual = nodeAssert.equal; + }); + + // Use v8 assert if possible + if (Error.captureStackTrace) { + assert = require("assert"); + assertEqual = assert.equal; + } +}); diff --git a/node_modules/c9/async_tools.js b/node_modules/c9/async_tools.js new file mode 100644 index 00000000..3fe90764 --- /dev/null +++ b/node_modules/c9/async_tools.js @@ -0,0 +1,77 @@ +"use strict"; + +exports.throttle = function(timeout, callback) { + var blocked = false; + return function() { + + if (blocked) + return; + + blocked = true; + setTimeout(function() { + blocked = false; + }, timeout); + + callback(); + }; +}; + +exports.once = function(callback) { + var called = false; + return function() { + if (called) return; + + called = true; + return callback.apply(this, arguments); + }; +}; + +exports.retry = function(fn, minDelay, maxDelay, maxTries, callback) { + var delay = minDelay; + var tries = 0; + + tryNext(); + + function tryNext() { + fn(function(err) { + if (!err) return callback.apply(null, arguments); + + if (++tries >= maxTries) + return callback(new Error("Operation timed")); + + setTimeout(tryNext, delay); + delay = Math.min(delay * delay, maxDelay); + }); + } +}; + +exports.timeout = function(fn, options, callback) { + if (arguments.length == 2) + return exports.timeout(fn, {}, options); + + var cancel = options.cancel || function() {}; + var timeout = options.timeout || 2000; + var error = options.error || function() { + var err = new Error("Operation timed out"); + err.code = "ETIMEOUT"; + err.timeout = timeout; + return err; + }; + + var done = false; + var timer = setTimeout(function() { + if (done) return; + done = true; + + var err = error(); + cancel(); + callback(err); + }, timeout); + + fn(function() { + if (done) return; + done = true; + clearTimeout(timer); + callback.apply(this, arguments); + }); +}; \ No newline at end of file diff --git a/node_modules/c9/async_tools_test.js b/node_modules/c9/async_tools_test.js new file mode 100755 index 00000000..68d4f06f --- /dev/null +++ b/node_modules/c9/async_tools_test.js @@ -0,0 +1,152 @@ +"use strict"; + +"use server"; + +var assert = require("assert"); +var sinon = require("sinon"); +var async_tools = require("./async_tools"); + +module.exports = { + + "test operation doesn't timeout": function() { + var clock = sinon.useFakeTimers(); + var cb = sinon.stub(); + + async_tools.timeout(function(cb) { + setTimeout(function() { + cb(null, "foo", "bar"); + }, 100); + }, { + timeout: 200 + }, cb); + + sinon.assert.callCount(cb, 0); + clock.tick(90); + sinon.assert.callCount(cb, 0); + clock.tick(20); + sinon.assert.callCount(cb, 1); + sinon.assert.calledWith(cb, null, "foo", "bar"); + + clock.restore(); + }, + + "test timed out operation should return a timeout error": function() { + var clock = sinon.useFakeTimers(); + var cb = sinon.stub(); + + async_tools.timeout(function(cb) { + setTimeout(function() { + cb(null, "foo"); + }, 300); + }, { + timeout: 200 + }, cb); + + sinon.assert.callCount(cb, 0); + clock.tick(190); + sinon.assert.callCount(cb, 0); + clock.tick(20); + sinon.assert.callCount(cb, 1); + assert.equal(cb.args[0][0].code, "ETIMEOUT"); + + clock.tick(100); + sinon.assert.callCount(cb, 1); + + clock.restore(); + }, + + "test customize timeout error reporting": function() { + var clock = sinon.useFakeTimers(); + var cb = sinon.stub(); + + async_tools.timeout(function(cb) { + setTimeout(function() { + cb(null, "foo"); + }, 300); + }, { + timeout: 200, + error: function() { + return { + my: "custom error" + }; + } + }, cb); + + clock.tick(210); + assert.equal(cb.args[0][0].my, "custom error"); + + clock.restore(); + }, + + "test timeout should call cancel function": function() { + var clock = sinon.useFakeTimers(); + var cb = sinon.stub(); + var cancel = sinon.stub(); + + async_tools.timeout(function(cb) { + setTimeout(function() { + cb(null, "foo"); + }, 300); + }, { + timeout: 200, + cancel: cancel + }, cb); + + clock.tick(210); + sinon.assert.called(cancel); + + clock.restore(); + }, + + "test callback should be called max every 2sec": function() { + var clock = sinon.useFakeTimers(); + + var cb = sinon.stub(); + var throttle = async_tools.throttle(2000, cb); + + sinon.assert.callCount(cb, 0); + + throttle(); + sinon.assert.callCount(cb, 1); + + throttle(); + sinon.assert.callCount(cb, 1); + + clock.tick(1000); + throttle(); + sinon.assert.callCount(cb, 1); + + clock.tick(999); + throttle(); + sinon.assert.callCount(cb, 1); + + clock.tick(2); + throttle(); + sinon.assert.callCount(cb, 2); + + clock.tick(2000); + throttle(); + sinon.assert.callCount(cb, 3); + + clock.restore(); + }, + + "test once should be called exactly once": function() { + var cb = sinon.stub(); + + var o = async_tools.once(cb); + + o(1, 2, 3); + sinon.assert.callCount(cb, 1); + sinon.assert.calledWith(cb, 1, 2, 3); + + o(); + sinon.assert.callCount(cb, 1); + + o(); + sinon.assert.callCount(cb, 1); + } + +}; + +!module.parent && require("asyncjs").test.testcase(module.exports).exec(); \ No newline at end of file diff --git a/node_modules/c9/atomic.js b/node_modules/c9/atomic.js new file mode 100644 index 00000000..929ef0a8 --- /dev/null +++ b/node_modules/c9/atomic.js @@ -0,0 +1,27 @@ +var fs = require("fs"); +var tmp = require("tmp"); +var async = require("async"); +var dirname = require("path").dirname; + +exports.writeFile = function(path, data, options, callback) { + if (typeof options == "function") + return exports.writeFile(path, data, null, options); + + async.waterfall([ + tmp.file.bind(null, {dir: dirname(path)}), + function(tmpFile, fd, nextOrRemoveCallback, next) { + if (!next) next = nextOrRemoveCallback; // api changed between tmp 0.23 and 0.24 + fs.close(fd, function(err) { + next(err, tmpFile); + }); + }, + function(tmpFile, next) { + fs.writeFile(tmpFile, data, options, function(err) { + next(err, tmpFile); + }); + }, + function(tmpFile, next) { + fs.rename(tmpFile, path, next); + } + ], callback); +}; \ No newline at end of file diff --git a/node_modules/c9/crypt.js b/node_modules/c9/crypt.js new file mode 100644 index 00000000..9630bb53 --- /dev/null +++ b/node_modules/c9/crypt.js @@ -0,0 +1,28 @@ +var crypto = require("crypto"); + +exports.crypt = function(sessionId, secret) { + var cipher = crypto.createCipher("aes256", secret); + return ( + cipher.update(sessionId, "ascii", "base64") + + cipher.final("base64") + ).replace(/\=+$/, ""); +}; + +exports.decrypt = function(encrypted, secret) { + var cipher = crypto.createDecipher("aes256", secret); + + var data = [ + cipher.update(encrypted, "base64", "ascii"), + cipher.final("ascii") + ]; + + return data.join("").replace(/\=+$/, ""); +}; + +exports.uid = function(length) { + return (require("crypto") + .randomBytes(length) + .toString("base64") + .slice(0, length) + ); +}; \ No newline at end of file diff --git a/node_modules/c9/crypt_test.js b/node_modules/c9/crypt_test.js new file mode 100644 index 00000000..542f21e9 --- /dev/null +++ b/node_modules/c9/crypt_test.js @@ -0,0 +1,25 @@ +"use strict"; + +"use server"; + +var assert = require("assert"); +var crypt = require("./crypt"); + +module.exports = { + + name: "cookie crypt", + + "test encrpyt and decrypt should return input" : function() { + var sessionId = "vOcRVvhaBBauiYexVvWyJpPb.AqmabaXkhpmlR8AUkORJHu%2FB7WA57EsDqzled0VoKAg"; + var secret = "geheim"; + + assert.equal(crypt.crypt(sessionId, secret), "C+kRJ4UWhmjgqo7DVv31cJLfZ9LIPLZB7OuMdN8i07ZdZHKlusCClMKaqBEwHDiKH3uFKf8IUZOxoVHU6+eNrkLArr32HrBDLr8qfnKfAgY"); + + assert.equal( + crypt.decrypt(crypt.crypt(sessionId, secret), secret), + sessionId + ); + } +}; + +!module.parent && require("asyncjs").test.testcase(module.exports).exec(); diff --git a/node_modules/c9/git.js b/node_modules/c9/git.js new file mode 100644 index 00000000..dcbf0328 --- /dev/null +++ b/node_modules/c9/git.js @@ -0,0 +1,96 @@ +"use strict"; + +var Url = require("url"); +var Fs = require("fs"); +var Path = require("path"); +var exec = require("child_process").exec; + +exports.isValidUrl = function(url) { + return !!exports.parse(url); +}; + +exports.parse = function(url) { + var m = url.match(/^(git)@([\w\.\d\-\_]+)(?:\/|:)([\w\.\d\-\_\/]+)/); + if (m) { + return { + protocol: "ssh:", + auth: m[1], + hostname: m[2], + pathname: m[3] + }; + } + + var parsed = Url.parse(url); + if ( + parsed && + parsed.protocol && + parsed.protocol.match(/^(git|http|https):$/) && + parsed.hostname && + parsed.slashes && + parsed.pathname + ) + return { + protocol: parsed.protocol, + auth: parsed.auth || "", + hostname: parsed.hostname, + pathname: parsed.pathname.replace(/^\/+/, ""), + full: url + }; + else + return null; +}; + +exports.getHeadRevision = function(path, callback) { + exec("git rev-parse HEAD", { + cwd: path + }, function(code, stdout, stderr) { + if (code) + return callback(stderr.toString()); + + return callback(null, stdout.toString().split("\n")[0]); + }); +}; + +exports.getHeadRevisionSync = function(path) { + var ref = Fs.readFileSync(Path.join(path, ".git/HEAD"), "ascii"); + + ref = ref.replace(/^ref\:\s+/, "").trim(); + + // if it already is a commit id + if (ref.match(/^[a-z0-9]{40}$/)) { + return ref; + } + + var revision; + try { + revision = Fs.readFileSync(Path.join(path, ".git", ref), "ascii"); + } + catch (ex) { + // the link may be pruned by git, try the info/refs file + var info = Fs.readFileSync(Path.join(path, ".git/info/refs"), "ascii"); + var lines = info.split(/[\r\n]+/); + for (var parts, i = 0, l = lines.length; i < l; ++i) { + parts = lines[i].split(/[\s\t]+/); + if (parts[1] == ref) { + revision = parts[0]; + break; + } + } + } + + // trim new lines + revision = revision.trim(); + + return revision; +}; + +exports.getHeadBranch = function(path, callback) { + exec("git rev-parse --abbrev-ref HEAD", { + cwd: path + }, function(code, stdout, stderr) { + if (code) + return callback(stderr.toString()); + + return callback(null, stdout.toString().split("\n")[0]); + }); +}; diff --git a/node_modules/c9/git_test.js b/node_modules/c9/git_test.js new file mode 100644 index 00000000..690eb76e --- /dev/null +++ b/node_modules/c9/git_test.js @@ -0,0 +1,75 @@ +"use strict"; + +"use server"; + +var assert = require("assert"); +var git = require("./git"); + +module.exports = { + + "test validate urls" : function() { + assert.equal(git.isValidUrl("git@github.com:fjakobs/lispjs.git"), true); + assert.equal(git.isValidUrl("https://fjakobs@github.com/fjakobs/lispjs.git"), true); + assert.equal(git.isValidUrl("fjakobs@github.com/fjakobs/lispjs.git"), false); + assert.equal(git.isValidUrl("ftp://fjakobs@github.com/fjakobs/lispjs.git"), false); + assert.equal(git.isValidUrl("git://github.com/fjakobs/lispjs.git"), true); + assert.equal(git.isValidUrl("github.com:fjakobs/lispjs.git"), false); + assert.equal(git.isValidUrl("134"), false); + assert.equal(git.isValidUrl("god"), false); + }, + + "test parse ssh url" : function() { + var url = git.parse("git@github.com:fjakobs/lispjs.git"); + assert.equal(url.protocol, "ssh:"); + assert.equal(url.auth, "git"); + assert.equal(url.hostname, "github.com"); + assert.equal(url.pathname, "fjakobs/lispjs.git"); + }, + + "test parse git url" : function() { + var url = git.parse("git://github.com/fjakobs/lispjs.git"); + assert.equal(url.protocol, "git:"); + assert.equal(url.hostname, "github.com"); + assert.equal(url.pathname, "fjakobs/lispjs.git"); + }, + + "test parse https url" : function() { + var url = git.parse("https://fjakobs@github.com/fjakobs/lispjs.git"); + assert.equal(url.protocol, "https:"); + assert.equal(url.auth, "fjakobs"); + assert.equal(url.hostname, "github.com"); + assert.equal(url.pathname, "fjakobs/lispjs.git"); + }, + + "test parse Bitbucket url" : function() { + var url = git.parse("git@bitbucket.org/Richard/expressling.git"); + assert.equal(url.protocol, "ssh:"); + assert.equal(url.auth, "git"); + assert.equal(url.hostname, "bitbucket.org"); + assert.equal(url.pathname, "Richard/expressling.git"); + }, + + "test get head revision": function(next) { + git.getHeadRevision(__dirname, function(err, rev) { + assert.equal(err, null); + assert.equal(rev.length, 40); + next(); + }); + }, + + "test get head revision sync": function(next) { + var rev = git.getHeadRevisionSync(__dirname + "/../"); + assert.equal(rev.length, 40); + + next(); + }, + + "test get head branch": function(next) { + git.getHeadBranch(__dirname, function(err, rev) { + assert.equal(err, null); + next(); + }); + } +} + +!module.parent && require("asyncjs").test.testcase(module.exports).exec(); diff --git a/node_modules/c9/hashing.js b/node_modules/c9/hashing.js new file mode 100644 index 00000000..bf08de2a --- /dev/null +++ b/node_modules/c9/hashing.js @@ -0,0 +1,14 @@ +var Crypto = require("crypto"); + +/** + * Return md5 hash of the given string and optional encoding, + * defaulting to hex. + * + * @param {String} str + * @param {String} encoding + * @return {String} + * @api public + */ +exports.md5 = function(str, encoding){ + return Crypto.createHash("md5").update(str).digest(encoding || "hex"); +}; \ No newline at end of file diff --git a/node_modules/c9/hostname.js b/node_modules/c9/hostname.js new file mode 100644 index 00000000..5371df02 --- /dev/null +++ b/node_modules/c9/hostname.js @@ -0,0 +1,23 @@ +var fs = require("fs"); + +exports.parse = function(hostname) { + var parts = hostname.split("-"); + return { + type: parts[0], + provider: parts[1], + region: parts[2], + index: parts[3], + env: parts[4] + }; +}; + +exports.get = function() { + var hostname; + try { + hostname = fs.readFileSync("/etc/hostname", "utf8").trim(); + } catch (e) { + hostname = "localhost"; + } + + return hostname; +}; \ No newline at end of file diff --git a/node_modules/c9/inline-mocha.js b/node_modules/c9/inline-mocha.js new file mode 100644 index 00000000..a5c92d7d --- /dev/null +++ b/node_modules/c9/inline-mocha.js @@ -0,0 +1,17 @@ +module.exports = function(module, reporter) { + if (typeof module !== "undefined" && module === require.main) { + if (typeof global.onload === "undefined") + global.onload = undefined; + var file = module.filename; + var Mocha = require("mocha"); + var mocha = new Mocha(); + mocha.reporter(reporter || "spec"); + var suite = mocha.suite; + suite.emit('pre-require', global, file, mocha); + suite.emit('require', require(file), file, mocha); + setTimeout(function() { + suite.emit('post-require', global, file, mocha); + mocha.run(process.exit); + }, 0); + } +}; \ No newline at end of file diff --git a/node_modules/c9/instance_cache.js b/node_modules/c9/instance_cache.js new file mode 100644 index 00000000..9271238a --- /dev/null +++ b/node_modules/c9/instance_cache.js @@ -0,0 +1,134 @@ +"use strict"; +var async = require("asyncjs"); + +/** + * Cache instances by ID for a certain periode of time + */ +var InstanceCache = module.exports = function(timeout, factory, onDestroy) { + this.interval = timeout; + this.instances = {}; + this.instCallbacks = {}; + this.factory = factory; + this.onDestroy = onDestroy; +}; + +module.exports.lazyCreate = function(id, cache, callbackStore, factory, callback) { + var item = cache[id]; + if (item) + return callback(null, item); + + if (callbackStore[id]) { + callbackStore[id].push(callback); + return; + } + + callbackStore[id] = [callback]; + + factory(function(err, item) { + var callbacks = callbackStore[id]; + delete callbackStore[id]; + + if (!err) + cache[id] = item; + + callbacks.forEach(function(cb) { + cb(err, item); + }); + }); +}; + +(function() { + + /** + * If callback is provided the factory is assumed to be async + */ + this.get = function(id, args, callback) { + if (!args && !callback) + return this.instances[id] || null; + + var self = this; + + self.lazyCreate( + id, + this.instances, + this.instCallbacks, + this._create.bind(this, id, args), + function(err, inst) { + if (err) + return callback(err); + + self._updateTimeout(id, inst); + callback(null, inst.instance); + } + ); + }; + + this.has = function(id) { + return !!this.instances[id]; + }; + + this.remove = function(id, callback) { + var inst = this.instances[id]; + if (!inst) + return callback && callback(); + + delete this.instances[id]; + this.onDestroy(id, inst.instance, callback || function() {}); + }; + + this.forEach = function(callback) { + for (var id in this.instances) { + callback(this.instances[id].instance); + } + }; + + /** + * Get all cached instances (synchronous) + */ + this.getAll = function() { + var self = this; + + return Object.keys(self.instances).map(function (id) { + return self.instances[id].instance; + }); + }; + + /** + * If callback is provided the factory is assumed to be async + */ + this._create = function(id, args, callback) { + this.factory.apply(null, args.concat(function(err, instance) { + if (err) + return callback(err, instance); + + return callback(null, { + instance: instance + }); + })); + }; + + this._updateTimeout = function(id, inst) { + if (inst.timeout) + clearTimeout(inst.timeout); + + if (inst.interval > 0) + inst.timeout = setTimeout(this.remove.bind(this, id), this.interval); + }; + + this.destroy = function(callback) { + var self = this; + + async.forEach(Object.keys(this.instances), function(id, next) { + self.remove(id); + next(); + }, callback); + }; + + /** + * Looks up an object by ID from a cache. If the item is not in the cache it is + * created on demand using the factory function. Intermitted calls to the same + * id are pooled until the object is created + */ + this.lazyCreate = module.exports.lazyCreate; + +}).call(InstanceCache.prototype); \ No newline at end of file diff --git a/node_modules/c9/instance_cache_test.js b/node_modules/c9/instance_cache_test.js new file mode 100644 index 00000000..3ee9ae90 --- /dev/null +++ b/node_modules/c9/instance_cache_test.js @@ -0,0 +1,71 @@ +"use strict"; + +"use server"; + +var assert = require("assert"); + +var InstanceCache = require("./instance_cache"); + + +module.exports = { + //"test lazy create " + + "test lazy create should not call factory if object is in cache": function(next) { + InstanceCache.lazyCreate("foo", {foo: "bar"}, {}, null, function(err, item) { + assert.equal(err, null); + assert.equal(item, "bar"); + next(); + }); + }, + + "test lazy create should call factory if object is not in the cache": function(next) { + InstanceCache.lazyCreate("foo", {}, {}, function(callback) { + callback(null, "bar"); + }, function(err, item) { + assert.equal(err, null); + assert.equal(item, "bar"); + next(); + }); + }, + + "test lazy create should call factory only once": function(next) { + var called = false; + var factory = function(callback) { + assert.equal(called, false); + called = true; + setTimeout(function() { + callback(null, "bar"); + }, 10); + }; + var cache = {}; + var callbackStore = {}; + + InstanceCache.lazyCreate("foo", cache, callbackStore, factory, function(err, item) { + assert.equal(err, null); + assert.equal(item, "bar"); + + InstanceCache.lazyCreate("foo", cache, callbackStore, factory, function(err, item) { + assert.equal(err, null); + assert.equal(item, "bar"); + next(); + }); + }); + }, + + "test failed create should not be stored in the cache": function(next) { + var cache = new InstanceCache(0, function(callback) { + return callback("error"); + }); + + cache.get("id1", [], function(err) { + assert.equal(err, "error"); + assert.equal(arguments.length, 1); + + assert.ok(!cache.has("id1")); + + next(); + }); + } +}; + +!module.parent && require("asyncjs").test.testcase(module.exports).exec(); \ No newline at end of file diff --git a/node_modules/c9/manifest.js b/node_modules/c9/manifest.js new file mode 100644 index 00000000..6298ae8f --- /dev/null +++ b/node_modules/c9/manifest.js @@ -0,0 +1,14 @@ +var git = require("./git"); +var hostname = require("./hostname"); + +exports.load = function(root) { + var manifest = require(root + "/package.json"); + manifest.revision = + manifest.revision || + git.getHeadRevisionSync(root); + + manifest.hostname = hostname.get(); + + return manifest; +}; + diff --git a/node_modules/c9/package.json b/node_modules/c9/package.json new file mode 100644 index 00000000..86dd673e --- /dev/null +++ b/node_modules/c9/package.json @@ -0,0 +1,16 @@ +{ + "name": "c9", + "version": "0.1.0", + "private": true, + "description": "Global helper functions and modules used in Cloud9", + "author": "Cloud9 Inc. ", + + "dependencies": { + "async": "~0.2.7", + "tmp": "~0.0.20" + }, + + "scripts": { + "test": "for file in *_test.js; do node $file; done" + } +} \ No newline at end of file diff --git a/node_modules/c9/passcrypt.js b/node_modules/c9/passcrypt.js new file mode 100644 index 00000000..05295bf8 --- /dev/null +++ b/node_modules/c9/passcrypt.js @@ -0,0 +1,28 @@ +/** + * Password encrypting and verifying + * Passwords are first hashed using md5 then encrypted using bcrypt. + * + */ + +var hashing = require('./hashing'); +var bcrypt = require('bcrypt'); +var SALT_LENGTH = 8; + +exports.encrypt = function(password, callback) { + var passwordHashed = hashing.md5(password); + bcrypt.hash(passwordHashed, SALT_LENGTH, function(err, passwordEncrypted) { + if (err) return callback(err); + callback(null, passwordEncrypted); + }); +}; + +exports.compare = function(password, encrypted, callback) { + var passwordHashed = hashing.md5(password); + if (passwordHashed == encrypted) { // Some passwords may still only be hashed, not bcrypted, so see if that worked first. + return callback(null, true); + } + bcrypt.compare(passwordHashed, encrypted, function (err, result) { // Password is stored hashed then bcrypted, so we compare using the hashed password. + if (err) return callback(err); + callback(null, result); + }); +}; \ No newline at end of file diff --git a/node_modules/c9/passcrypt_test.js b/node_modules/c9/passcrypt_test.js new file mode 100644 index 00000000..d1dabfbc --- /dev/null +++ b/node_modules/c9/passcrypt_test.js @@ -0,0 +1,83 @@ +/*global describe it before after beforeEach afterEach define*/ +"use strict"; +"use client"; +"use server"; +"use mocha"; + +// Test flags +// +// "use root"; the unit test will be executed as root (using sudo); use with care! (ex. back-up / restore tests) +// "use non-osx"; test will be skipped if the operating system is Mac OS +// "use server"; tests are supposed to run on server-side (either with node or mocha) +// "use client"; tests are run by means of Selenium on client side +// "use mocha"; tests can be run by mocha or by node; this label indicates needs be run using mocha. + +if (typeof define === "undefined") { + require("c9/inline-mocha")(module); + require("amd-loader"); + require("../../test/setup_paths"); +} + +define(function(require, exports, module) { + +var assert = require("ace/test/assertions"); +var passcrypt = require('./passcrypt'); +var bcrypt = require('bcrypt'); + + +describe("c9/passcrypt", function(){ + this.timeout(2000); + + describe("encrypt", function() { + it("Should md5 then bcrypt a password, not just straight bcrypt", function(done) { + var pass = "password"; + passcrypt.encrypt(pass, function (err, encrypted) { + if (err) return done(err); + assert.equal(encrypted.length, 60); + bcrypt.compare(pass, encrypted, function (err, result) { + if (err) return done(err); + assert.equal(result, false); // We want to ensure normal bcrypt compare doesn't work as it's md5'd then encrypted + done(); + }); + }); + }); + + it("Should work with compare", function (done) { + var pass = "password"; + passcrypt.encrypt(pass, function (err, encrypted) { + if (err) return done(err); + passcrypt.compare(pass, encrypted, function(err, result) { + if (err) return done(err); + assert.equal(result, true); + done(); + }); + }); + }); + }); + + describe("compare", function() { + it("Should work when the encrypted password is still only a md5 hash", function (done) { + var pass = "password"; + var encrypted = "5f4dcc3b5aa765d61d8327deb882cf99"; + passcrypt.compare(pass, encrypted, function (err, result) { + if (err) return done(err); + assert.equal(result, true); + done(); + }); + }); + + it("Should work when the encrypted password is bcrypt encrypted", function (done) { + var pass = "password"; + var encrypted = "$2a$08$RYLeOqfDc3KSkdUpvQhpTe8HdlbcQmzTx8E61cXQTXgtGsrB9A1tS"; + passcrypt.compare(pass, encrypted, function (err, result) { + if (err) return done(err); + assert.equal(result, true); + done(); + }); + }); + }); +}); + +if (typeof onload !== "undefined") + onload(); +}); diff --git a/node_modules/c9/proxies.js b/node_modules/c9/proxies.js new file mode 100644 index 00000000..e921555c --- /dev/null +++ b/node_modules/c9/proxies.js @@ -0,0 +1,38 @@ +define(function(require, exports, module) { + + /** + * Attempts to create a proxy object that will only allow you to access + * known properties of an object. + * + * @param name The "name" of this object to use in error messages. + * @param knownProperties Optional: a list of known properties of the object. + */ + exports.createKnownPropertyProxy = function(object, name, knownProperties) { + /*global Proxy*/ + if (typeof Proxy === "undefined") + return object; + + if (!knownProperties) + knownProperties = Object.keys(object); + + return Proxy.create({ + get: function(proxy, property) { + if (property === "inspect") + return object.inspect; + if (!(property in object) && knownProperties.indexOf(property) === -1) + throw Error("Invalid property accessed: " + name + "." + property); + if (property === "innerObject") + return object; + return object[property]; + }, + set: function(proxy, property, value) { + object[property] = value; + return true; + }, + getPropertyNames: function() { + return Object.keys(object); + } + }); + }; + +}); \ No newline at end of file diff --git a/node_modules/c9/ratelimit.js b/node_modules/c9/ratelimit.js new file mode 100644 index 00000000..404c6dfa --- /dev/null +++ b/node_modules/c9/ratelimit.js @@ -0,0 +1,32 @@ +var error = require("http-error"); + +/** + * In memory rate limiter as connect middleware + */ +module.exports = ratelimit; + +function ratelimit(key, duration, max) { + var limit = {}; + return function(req, res, next) { + var handle = req.params[key]; + + var lim = limit[handle] || (limit[handle] = []); + var now = Date.now(); + for (var i = 0; i < lim.length; i++) { + if (now - lim[i] > duration) { + lim.splice(i, 1); + i--; + } + else break; + } + if (lim.length > max) { + var err = new error.TooManyRequests("Rate limit exceeded"); + err.retryIn = duration - (Date.now() - lim[0]); + next(err); + return; + } + lim.push(Date.now()); + + return next(); + }; +} diff --git a/node_modules/c9/request_timeout.js b/node_modules/c9/request_timeout.js new file mode 100644 index 00000000..76f24360 --- /dev/null +++ b/node_modules/c9/request_timeout.js @@ -0,0 +1,6 @@ +module.exports = function(timeout) { + return function(req, res, next) { + req.setTimeout(timeout); + next(); + }; +}; \ No newline at end of file diff --git a/node_modules/c9/rest_client.js b/node_modules/c9/rest_client.js new file mode 100644 index 00000000..0ff3db0c --- /dev/null +++ b/node_modules/c9/rest_client.js @@ -0,0 +1,137 @@ +var error = require("http-error"); +var http = require("http"); +var https = require("https"); +var _ = require("lodash"); +var once = require("./async_tools").once; +var debug = require("debug")("rest:client"); + +/* + * Example: + * optional config.username & config.password for Basic Auth + * var client = new RestClient("localhost", "3131", {protocol: "https", username: "abc", password: "def"}); + */ +function RestClient(host, port, config) { + var protocol = config.protocol || "http"; + if (protocol !== "https" && protocol !== "http") + return console.error("Unknown protocol:", protocol); + + var proto = protocol === "https" ? https : http; + + var log = config.logger || debug; + + this.request = function request(method, path, body, callback) { + if (!callback) { + callback = body; + body = undefined; + } + + var done = once(callback); + + method = method.toLowerCase(); + var payload = ""; + if (body && (method == "put" || method == "post" || method == "delete")) { + payload = JSON.stringify(body); + } + + var headers = _.extend({ + "Accept": "application/json", + "Content-Type": "application/json", + "Content-Length": payload.length + }, config.headers || {}); + + var options = { + hostname: host, + port: port, + path: path, + method: method, + headers: headers + }; + if (config.username) + options.auth = config.username + ":" + config.password; + + var req = proto.request(options, onResponse(done, options, body)); + + req.on("error", function(e) { + log("ERROR %s %s://%s:%s%s %s", + options.method, + protocol, options.hostname, options.port, options.path, + e.stack || e.message + ); + done(e); + }); + + req.end(payload); + }; + + var that = this; + ["get", "post", "put", "delete", "options"].forEach(function (method) { + that[method] = that.request.bind(that, method); + }); + + function onResponse(callback, options, body) { + return function(res) { + var data = ""; + var json; + + res.on("data", function(d) { + data += d; + }); + + res.on("end", function() { + try { + json = JSON.parse(data); + } catch (e) { + json = data; + } + + if (res.statusCode >= 300) { + var msg = + (json.error && json.error.message) || + "Request failed with status code " + res.statusCode; + + var err = new error.HttpError(msg, res.statusCode); + + if (json.error) { + for (var key in json.error) + err[key] = json.error[key]; + } + + + done(err, json); + } + else { + done(null, json); + } + }); + + res.on("error", function(e) { + done(e); + }); + + var called = false; + function done(err, json) { + if (called) + return; + + if (err) { + log("ERROR %d %s %s://%s:%s%s REQ %j RES %j %j", + res.statusCode, options.method, + protocol, options.hostname, options.port, options.path, + body || {}, data, err + ); + } else { + log("%d %s %s://%s:%s%s REQ %j RES %j", + res.statusCode, options.method, + protocol, options.hostname, options.port, options.path, + body || {}, data + ); + } + + called = true; + callback(err, json); + } + }; + } +} + +module.exports = RestClient; diff --git a/node_modules/c9/ssh.js b/node_modules/c9/ssh.js new file mode 100644 index 00000000..3dddbeb9 --- /dev/null +++ b/node_modules/c9/ssh.js @@ -0,0 +1,148 @@ +/** + * @copyright Copyright(c) 2011 Ajax.org B.V. + * @author Fabian Jakobs + * @author Mike de Boer + * @license http://github.com/ajaxorg/node-sftp/blob/master/LICENSE MIT License + */ + +var child_process = require("child_process"); +var fs = require("fs"); +var uuid = require("node-uuid"); + +exports.buildArgs = function(prvkeyFile, host) { + var args = [ + "-o", "PasswordAuthentication=no", + "-o", "IdentityFile=" + prvkeyFile, + "-o", "UserKnownHostsFile=/dev/null", + "-o", "StrictHostKeyChecking=no", + "-F", "/dev/null", // use empty config file to not depend on local settings + // force pseudo terminal to make sure that the remote process is killed + // when the local ssh process is killed + "-t", "-t", + "-o", "BatchMode=yes", + "-o", "ConnectTimeout=10" // default timeout is 2 minutes, which is quite long + ]; + + if (host) { + host = host.split(":"); + args.push("-p", host[1] || 22); + args.push(host[0]); + } + + return args; +}; + +exports.spawnWithKeyFile = function(prvkeyFile, host, command, args) { + var sshArgs = exports.buildArgs(prvkeyFile, host); + + var args = sshArgs.concat(command ? [command] : []).concat(args || []); + console.log("executing: ssh " + args.join(" ")); + + return child_process.spawn("ssh", args); +}; + +exports.writeKeyFile = function(prvkey, callback) { + var filename = Util.DEFAULT_TMPDIR + "/" + uuid(); + fs.writeFile(filename, prvkey, function(err) { + if (err) + return callback(err); + + fs.chmod(filename, "0600", function(err) { + callback(err, filename); + }); + }); +}; + +exports.writeKeyFiles = function(prvkey, pubkey, callback) { + var filename = Util.DEFAULT_TMPDIR + "/" + uuid(); + fs.writeFile(filename, prvkey, function(err) { + if (err) + return callback(err); + + fs.chmod(filename, "0600", function(err) { + fs.writeFile(filename + ".pub", pubkey, function(err) { + if (err) + return callback(err); + + fs.chmod(filename + ".pub", "0600", function(err) { + callback(err, filename); + }); + }); + }); + }); +}; + +exports.spawn = function(prvkey, host, command, args, callback) { + exports.writeKeyFile(prvkey, function(err, filename) { + var child = exports.spawnWithKeyFile(filename, host, command, args); + + child.on("exit", function(code) { + fs.unlink(filename, function() {}); + }); + + callback(null, child); + }); +}; + +exports.exec = function(prvkey, host, command, args, callback) { + exports.spawn(prvkey, host, command, args, function(err, child) { + if (err) + return callback(err); + + var out = err = ""; + + child.stdout.on("data", function (data) { + out += data; + }); + + child.stderr.on("data", function (data) { + err += data; + }); + + child.on("exit", function(code) { + callback(code, out, err); + }); + }); +}; + +exports.generateKeyPair = function(email, callback) { + var tmp = process.env.TMP || process.env.TMPDIR || process.env.TMP_DIR || "/tmp"; + var filename = tmp + "/" + uuid(); + var phrase = ""; + + var command = "ssh-keygen -t rsa " + + "-f \"" + filename + "\" " + + "-P \"" + phrase + "\" " + + "-C \"" + email + "\" "; + + child_process.exec(command, function (err, stdout, stderr) { + if (err) + return callback(err); + + fs.readFile(filename + ".pub", function (err, pubkey) { + if (err) + return callback(err); + + fs.readFile(filename, function (err, prvkey) { + if (err) + return callback(err); + + fs.unlink(filename + ".pub", function() { + fs.unlink(filename, function() { + callback(null, pubkey.toString(), prvkey.toString()); + }); + }); + + }); + }); + }); +}; + +exports.validateSSHKey = function(prvkey, host, callback) { + exports.exec(prvkey, host, "", [], function(err, stdout, stderr) { + //console.log("out >> " + stdout) + //console.log("err >> " + stderr) + //console.log(err) + callback(null, !stderr.match(/Permission denied \(.*publickey/)); + }); +}; diff --git a/node_modules/c9/string.js b/node_modules/c9/string.js new file mode 100644 index 00000000..5e3714ce --- /dev/null +++ b/node_modules/c9/string.js @@ -0,0 +1,47 @@ +define(function(require, exports, module) { + "use strict"; + +/* + * Casts the first character in a string to uppercase. + * + * @param {String} str + * @type {String} + */ +exports.uCaseFirst = function(str) { + return str.substr(0, 1).toUpperCase() + str.substr(1); +}; + +/* + * Removes spaces and other space-like characters from the left and right ends + * of a string + * + * @param {String} str + * @type {String} + */ +exports.trim = function(str) { + return str.replace(/[\s\n\r]*$/, "").replace(/^[\s\n\r]*/, ""); +}; + +/* + * Concatenate a string with itself n-times. + * + * @param {String} str + * @param {Number} times Number of times to repeat the String concatenation + * @type {String} + */ +exports.repeat = function(str, times) { + return new Array(times + 1).join(str); +}; + +/* + * Count the number of occurences of substring 'str' inside a string + * + * @param {String} str + * @param {String} substr + * @type {Number} + */ +exports.count = function(str, substr){ + return str.split(substr).length - 1; +}; + +}); \ No newline at end of file diff --git a/node_modules/c9/uid.js b/node_modules/c9/uid.js new file mode 100644 index 00000000..51573ede --- /dev/null +++ b/node_modules/c9/uid.js @@ -0,0 +1,12 @@ +var crypto = require("crypto"); + +module.exports = function(length) { + var uid = ""; + while (uid.length <= length) { + uid += crypto + .randomBytes(256) + .toString("base64") + .replace(/[^a-zA-Z0-9]/g, ""); + } + return uid.slice(0, length); +}; \ No newline at end of file diff --git a/node_modules/connect-architect/.gitignore b/node_modules/connect-architect/.gitignore new file mode 100644 index 00000000..40b878db --- /dev/null +++ b/node_modules/connect-architect/.gitignore @@ -0,0 +1 @@ +node_modules/ \ No newline at end of file diff --git a/node_modules/connect-architect/.npmignore b/node_modules/connect-architect/.npmignore new file mode 100644 index 00000000..df7c2e38 --- /dev/null +++ b/node_modules/connect-architect/.npmignore @@ -0,0 +1,3 @@ +node_modules/ +/demo/ +/tests/ \ No newline at end of file diff --git a/node_modules/connect-architect/.travis.yml b/node_modules/connect-architect/.travis.yml new file mode 100644 index 00000000..81112458 --- /dev/null +++ b/node_modules/connect-architect/.travis.yml @@ -0,0 +1,4 @@ +language: node_js +node_js: + - 0.6 + - 0.8 \ No newline at end of file diff --git a/node_modules/connect-architect/LICENSE b/node_modules/connect-architect/LICENSE new file mode 100644 index 00000000..64d23692 --- /dev/null +++ b/node_modules/connect-architect/LICENSE @@ -0,0 +1,21 @@ +The MIT License + +Copyright (c) 2012 ajax.org B.V + +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. \ No newline at end of file diff --git a/node_modules/connect-architect/README.md b/node_modules/connect-architect/README.md new file mode 100644 index 00000000..a5f54e67 --- /dev/null +++ b/node_modules/connect-architect/README.md @@ -0,0 +1,19 @@ +connect-architect +================= + +[Connect](https://github.com/senchalabs/connect) for [architect](https://github.com/c9/connect-architect). + + +Demo +==== + + npm install + cd ./demo + node server + open http://localhost:8080 + +Test +==== + + npm install + npm test diff --git a/node_modules/connect-architect/connect.basicauth/basicauth-plugin.js b/node_modules/connect-architect/connect.basicauth/basicauth-plugin.js new file mode 100644 index 00000000..c65b2ba3 --- /dev/null +++ b/node_modules/connect-architect/connect.basicauth/basicauth-plugin.js @@ -0,0 +1,14 @@ +"use strict"; + +module.exports = function(options, imports, register) { + if (!options.username || !options.password) + return register(); + + var connect = imports.connect; + connect.useSetup(connect.getModule().basicAuth(options.username, options.password)); + + console.log("Using basic authentication"); + + register(); +}; + diff --git a/node_modules/connect-architect/connect.basicauth/package.json b/node_modules/connect-architect/connect.basicauth/package.json new file mode 100644 index 00000000..078b827c --- /dev/null +++ b/node_modules/connect-architect/connect.basicauth/package.json @@ -0,0 +1,14 @@ +{ + "name": "c9.connect.basicauth", + "version": "0.0.1", + + "main": "./basicauth-plugin.js", + "private": true, + + "plugin": { + "consumes": [ + "connect" + ], + "provides": [] + } +} \ No newline at end of file diff --git a/node_modules/connect-architect/connect.bodyparser/bodyparser.js b/node_modules/connect-architect/connect.bodyparser/bodyparser.js new file mode 100644 index 00000000..957e4990 --- /dev/null +++ b/node_modules/connect-architect/connect.bodyparser/bodyparser.js @@ -0,0 +1,9 @@ +"use strict"; + +module.exports = function(options, imports, register) { + imports.connect.useSetup(imports.connect.getModule().urlencoded()); + imports.connect.useSetup(imports.connect.getModule().json()); + register(null, { + "connect.bodyparser": {} + }); +}; diff --git a/node_modules/connect-architect/connect.bodyparser/package.json b/node_modules/connect-architect/connect.bodyparser/package.json new file mode 100644 index 00000000..cd11d91d --- /dev/null +++ b/node_modules/connect-architect/connect.bodyparser/package.json @@ -0,0 +1,16 @@ +{ + "name": "c9.connect.bodyparser", + "version": "0.0.1", + + "main": "./bodyparser.js", + "private": true, + + "plugin": { + "consumes": [ + "connect" + ], + "provides": [ + "connect.bodyparser" + ] + } +} \ No newline at end of file diff --git a/node_modules/connect-architect/connect.cookieparser/cookieparser.js b/node_modules/connect-architect/connect.cookieparser/cookieparser.js new file mode 100644 index 00000000..aefa884f --- /dev/null +++ b/node_modules/connect-architect/connect.cookieparser/cookieparser.js @@ -0,0 +1,8 @@ +"use strict"; + +module.exports = function(options, imports, register) { + imports.connect.useSetup(imports.connect.getModule().cookieParser()); + register(null, { + "connect.cookieparser": {} + }); +}; diff --git a/node_modules/connect-architect/connect.cookieparser/package.json b/node_modules/connect-architect/connect.cookieparser/package.json new file mode 100644 index 00000000..413e516c --- /dev/null +++ b/node_modules/connect-architect/connect.cookieparser/package.json @@ -0,0 +1,16 @@ +{ + "name": "c9.connect.cookieparser", + "version": "0.0.1", + + "main": "./cookieparser.js", + "private": true, + + "plugin": { + "consumes": [ + "connect" + ], + "provides": [ + "connect.cookieparser" + ] + } +} \ No newline at end of file diff --git a/node_modules/connect-architect/connect.cors/cors.js b/node_modules/connect-architect/connect.cors/cors.js new file mode 100644 index 00000000..9f306f85 --- /dev/null +++ b/node_modules/connect-architect/connect.cors/cors.js @@ -0,0 +1,44 @@ +"use strict"; + +module.exports = function(options, imports, register) { + register(null, { + "connect.cors": { + cors: cors + } + }); +}; + +function cors(origin, options) { + return function(req, res, next) { + options = options || {}; + var writeHead = res.writeHead; + + res.writeHead = function(status, headers) { + headers = headers || {}; + + for (var key in headers) + if (key.toLowerCase().indexOf("access-control") === 0) + delete(headers[key]); + + headers["Access-Control-Allow-Origin"] = origin; + headers["Access-Control-Allow-Methods"] = options.methods || "GET, OPTIONS"; + if (options.headers) + headers["Access-Control-Allow-Headers"] = options.headers.join(", "); + if (options.exposeHeaders) + headers["Access-Control-Expose-Headers"] = options.exposeHeaders.join(", "); + headers["Access-Control-Max-Age"] = options.maxAge || 100 * 24 * 60 * 60; + if (origin !== "*") + headers["Access-Control-Allow-Credentials"] = "true"; + + return writeHead.call(res, status, headers); + }; + + if (req.method == "OPTIONS") { + res.writeHead(200); + res.end(); + return; + } + + next(); + }; +} \ No newline at end of file diff --git a/node_modules/connect-architect/connect.cors/package.json b/node_modules/connect-architect/connect.cors/package.json new file mode 100644 index 00000000..4c15556f --- /dev/null +++ b/node_modules/connect-architect/connect.cors/package.json @@ -0,0 +1,16 @@ +{ + "name": "c9.connect.cors", + "version": "0.0.1", + + "main": "./cors.js", + "private": true, + + "plugin": { + "consumes": [ + "connect" + ], + "provides": [ + "connect.cors" + ] + } +} \ No newline at end of file diff --git a/node_modules/connect-architect/connect.csp/csp.js b/node_modules/connect-architect/connect.csp/csp.js new file mode 100644 index 00000000..6afd93b8 --- /dev/null +++ b/node_modules/connect-architect/connect.csp/csp.js @@ -0,0 +1,150 @@ +"use strict"; + +var UAParser = require("ua-parser-js"); + +module.exports = function(options, imports, register) { + imports.connect.useSetup(csp()); + register(null, { + "connect.csp": { + csp: function(varargs) { + var args = arguments; + return function(req, res, next) { + res.csp.apply(res, args); + next(); + }; + } + } + }); +}; + +function csp() { + + return function(req, res, next) { + res._csp_policy = { + "default-src": "'self'", + "script-src": {}, + "object-src": {}, + "img-src": {}, + "media-src": {}, + "frame-src": {}, + "font-src": {}, + "connect-src": {}, + "style-src": {}, + "report-uri": "" + }; + res._csp_has_policy = false; + + var keywords = { + "none": 1, + "self": 1, + "unsafe-inline": 1, + "unsafe-eval": 1 + }; + + var presets = { + "facebook": { + "frame-src": "https://www.facebook.com", + "style-src": "unsafe-inline" + }, + "twitter": { + "script-src": "https://platform.twitter.com", + "frame-src": "http://platform.twitter.com", + "style-src": "unsafe-inline" + } + }; + + res.csp = function(directive, value) { + if (arguments.length === 1) { + if (Array.isArray(directive)) { + directive.forEach(function(arg) { + res.csp(arg); + }); + } + else if (typeof directive === "string" && presets[directive]) { + return res.csp(presets[directive]); + } + else if (typeof directive == "object") { + for (var key in directive) + res.csp(key, directive[key]); + } + else { + throw new TypeError("Invalud argument 'directive'"); + } + return; + } + + if (arguments.length == 2) { + if (Array.isArray(value)) { + value.forEach(res.csp.bind(res, directive)); + return; + } + } + + res._csp_has_policy = true; + + if (keywords[value]) + value = "'" + value + "'"; + + if (directive === "report-uri" || directive === "default-src") + res._csp_policy[directive] = value; + else + res._csp_policy[directive][value] = 1; + }; + + res.on("header", function() { + if (!res._csp_has_policy) + return; + + var parser = new UAParser(); + var uaHeader = req.headers['user-agent']; + parser.setUA(uaHeader); + var ua = parser.getBrowser(); + var browser = ua.browser || {}; + var engine = ua.engine || {}; + + if ( + // old firefox doesn't support CSP properly + engine.name == "Gecko" && parseInt(engine.version, 10) <= 23 || + (uaHeader || "").indexOf("Googlebot") >= 0 + ) { + return; + } + + var policyValue = Object.keys(res._csp_policy) + .map(function(key) { + var value = res._csp_policy[key]; + if (value) { + if (typeof value !== "string") { + if (value["noself"]) + delete value["noself"]; + else + value["'self'"] = 1; + value = Object.keys(value).join(" "); + } + + if (value) { + return key + " " + value; + } + } + return null; + }) + .filter(function(chunk) { + return !!chunk; + }) + .join("; "); + + res.setHeader("Content-Security-Policy", policyValue); + if ( + ua.engine == "Gecko" && parseInt(ua.engine.version, 10) <= 23 || + browser.name == "Chrome" && parseInt(browser.major, 10) >= 25 || + browser.name == "Safari" && parseInt(browser.major, 10) >= 7 + ) { + return; + } + + res.setHeader("X-Content-Security-Policy", policyValue); + res.setHeader("X-WebKit-CSP", policyValue); + }); + next(); + }; +} \ No newline at end of file diff --git a/node_modules/connect-architect/connect.csp/package.json b/node_modules/connect-architect/connect.csp/package.json new file mode 100644 index 00000000..8eb75851 --- /dev/null +++ b/node_modules/connect-architect/connect.csp/package.json @@ -0,0 +1,17 @@ +{ + "name": "c9.connect.csp", + "version": "0.0.1", + + "main": "./csp.js", + "private": true, + + "plugin": { + "consumes": [ + "connect", + "session" + ], + "provides": [ + "connect.csp" + ] + } +} \ No newline at end of file diff --git a/node_modules/connect-architect/connect.csrf/csrf.js b/node_modules/connect-architect/connect.csrf/csrf.js new file mode 100644 index 00000000..b046e000 --- /dev/null +++ b/node_modules/connect-architect/connect.csrf/csrf.js @@ -0,0 +1,51 @@ +"use strict"; + +var assert = require("assert"); +var url = require("url"); +var error = require("http-error"); + +module.exports = function(options, imports, register) { + assert(options.allowedHosts, "option 'allowedHosts' is required"); + + register(null, { + "connect.csrf": { + csrf: function() { + return csrf(options.allowedHosts); + } + } + }); +}; + +function csrf(allowedHosts) { + if (typeof allowedHosts == "string") + return csrf([allowedHosts]); + + allowedHosts = allowedHosts.reduce(function(map, host) { + map[host] = true; + return map; + }, {}); + + return function(req, res, next) { + if (req.method !== "POST") return next(); + + var origin; + if ("origin" in req.headers) { + origin = req.headers.origin; + } else { + var referrer = req.headers.referrer; + if (referrer) { + referrer = url.parse(referrer, false, false); + origin = referrer.protocol + "//" + referrer.host + (referrer.port ? ":" + referrer.port : ""); + } + } + + if (!origin) return forbidden(); + if (!allowedHosts[origin]) return forbidden(); + + next(); + + function forbidden() { + next(new error.Forbidden("Request not allowed from " + origin)); + } + }; +} \ No newline at end of file diff --git a/node_modules/connect-architect/connect.csrf/package.json b/node_modules/connect-architect/connect.csrf/package.json new file mode 100644 index 00000000..6740e5d4 --- /dev/null +++ b/node_modules/connect-architect/connect.csrf/package.json @@ -0,0 +1,17 @@ +{ + "name": "c9.connect.csrf", + "version": "0.0.1", + + "main": "./csrf.js", + "private": true, + + "plugin": { + "consumes": [ + "connect", + "session" + ], + "provides": [ + "connect.csrf" + ] + } +} \ No newline at end of file diff --git a/node_modules/connect-architect/connect.ensure-login/ensure-login.js b/node_modules/connect-architect/connect.ensure-login/ensure-login.js new file mode 100644 index 00000000..9eafbe7e --- /dev/null +++ b/node_modules/connect-architect/connect.ensure-login/ensure-login.js @@ -0,0 +1,13 @@ +"use strict"; + +var login = require("connect-ensure-login"); + +module.exports = function(options, imports, register) { + var loginUrl = options.loginUrl || "/login.html"; + + register(null, { + "connect.ensure-login": { + ensureLoggedIn: login.ensureLoggedIn.bind(null, loginUrl) + } + }); +}; diff --git a/node_modules/connect-architect/connect.ensure-login/package.json b/node_modules/connect-architect/connect.ensure-login/package.json new file mode 100644 index 00000000..6b8e77a1 --- /dev/null +++ b/node_modules/connect-architect/connect.ensure-login/package.json @@ -0,0 +1,16 @@ +{ + "name": "c9.connect.ensure-login", + "version": "0.0.1", + + "main": "./ensure-login.js", + "private": true, + + "plugin": { + "consumes": [ + "connect.redirect" + ], + "provides": [ + "connect.ensure-login" + ] + } +} \ No newline at end of file diff --git a/node_modules/connect-architect/connect.flash/flash.js b/node_modules/connect-architect/connect.flash/flash.js new file mode 100644 index 00000000..0ea1359a --- /dev/null +++ b/node_modules/connect-architect/connect.flash/flash.js @@ -0,0 +1,10 @@ +"use strict"; + +var flash = require('connect-flash'); + +module.exports = function(options, imports, register) { + imports.session.use(flash()); + register(null, { + "connect.flash": {} + }); +}; diff --git a/node_modules/connect-architect/connect.flash/package.json b/node_modules/connect-architect/connect.flash/package.json new file mode 100644 index 00000000..80e13bb6 --- /dev/null +++ b/node_modules/connect-architect/connect.flash/package.json @@ -0,0 +1,16 @@ +{ + "name": "c9.connect.flash", + "version": "0.0.1", + + "main": "./flash.js", + "private": true, + + "plugin": { + "consumes": [ + "session" + ], + "provides": [ + "connect.flash" + ] + } +} \ No newline at end of file diff --git a/node_modules/connect-architect/connect.logger/logger.js b/node_modules/connect-architect/connect.logger/logger.js new file mode 100644 index 00000000..a8949e49 --- /dev/null +++ b/node_modules/connect-architect/connect.logger/logger.js @@ -0,0 +1,8 @@ +"use strict"; + +module.exports = function(options, imports, register) { + imports.connect.useStart(imports.connect.getModule().logger(options.format || "tiny")); + register(null, { + "connect.logger": {} + }); +}; diff --git a/node_modules/connect-architect/connect.logger/package.json b/node_modules/connect-architect/connect.logger/package.json new file mode 100644 index 00000000..bfdd5576 --- /dev/null +++ b/node_modules/connect-architect/connect.logger/package.json @@ -0,0 +1,16 @@ +{ + "name": "c9.connect.logger", + "version": "0.0.1", + + "main": "./logger.js", + "private": true, + + "plugin": { + "consumes": [ + "connect" + ], + "provides": [ + "connect.logger" + ] + } +} \ No newline at end of file diff --git a/node_modules/connect-architect/connect.query/package.json b/node_modules/connect-architect/connect.query/package.json new file mode 100644 index 00000000..fecb7752 --- /dev/null +++ b/node_modules/connect-architect/connect.query/package.json @@ -0,0 +1,16 @@ +{ + "name": "c9.connect.query", + "version": "0.0.1", + + "main": "./query.js", + "private": true, + + "plugin": { + "consumes": [ + "connect" + ], + "provides": [ + "connect.query" + ] + } +} \ No newline at end of file diff --git a/node_modules/connect-architect/connect.query/query.js b/node_modules/connect-architect/connect.query/query.js new file mode 100644 index 00000000..3a2399e9 --- /dev/null +++ b/node_modules/connect-architect/connect.query/query.js @@ -0,0 +1,8 @@ +"use strict"; + +module.exports = function(options, imports, register) { + imports.connect.useSetup(imports.connect.getModule().query()); + register(null, { + "connect.query": {} + }); +}; diff --git a/node_modules/connect-architect/connect.redirect/package.json b/node_modules/connect-architect/connect.redirect/package.json new file mode 100644 index 00000000..d914c228 --- /dev/null +++ b/node_modules/connect-architect/connect.redirect/package.json @@ -0,0 +1,14 @@ +{ + "name": "c9.connect.redirect", + "version": "0.0.1", + + "main": "./redirect.js", + "private": true, + + "plugin": { + "consumes": ["connect"], + "provides": [ + "connect.redirect" + ] + } +} \ No newline at end of file diff --git a/node_modules/connect-architect/connect.redirect/redirect.js b/node_modules/connect-architect/connect.redirect/redirect.js new file mode 100644 index 00000000..cbeef3fb --- /dev/null +++ b/node_modules/connect-architect/connect.redirect/redirect.js @@ -0,0 +1,28 @@ +"use strict"; + +var http = require("http"); + +module.exports = function(options, imports, register) { + + imports.connect.addResponseMethod("redirect", function(location) { + this.writeHead(302, {Location: location}); + this.end(""); + }); + imports.connect.addResponseMethod("returnTo", function(req, defaultReturn) { + var url = defaultReturn || "/"; + if (req.session && req.session.returnTo) { + url = req.session.returnTo; + delete req.session.returnTo; + } + + this.redirect(url); + }); + imports.connect.addResponseMethod("moved", function(location) { + this.writeHead(301, {Location: location}); + this.end(""); + }); + + register(null, { + "connect.redirect": {} + }); +}; diff --git a/node_modules/connect-architect/connect.remote-address/package.json b/node_modules/connect-architect/connect.remote-address/package.json new file mode 100644 index 00000000..72e1e51b --- /dev/null +++ b/node_modules/connect-architect/connect.remote-address/package.json @@ -0,0 +1,16 @@ +{ + "name": "c9.connect.remote-address", + "version": "0.0.1", + + "main": "./remote-address.js", + "private": true, + + "plugin": { + "consumes": [ + "connect" + ], + "provides": [ + "connect.remote-address" + ] + } +} \ No newline at end of file diff --git a/node_modules/connect-architect/connect.remote-address/remote-address.js b/node_modules/connect-architect/connect.remote-address/remote-address.js new file mode 100644 index 00000000..963ba9cf --- /dev/null +++ b/node_modules/connect-architect/connect.remote-address/remote-address.js @@ -0,0 +1,22 @@ +"use strict"; + +module.exports = function(options, imports, register) { + imports.connect.useSetup(remoteAddress); + register(null, { + "connect.remote-address": {} + }); +}; + +function remoteAddress(req, res, next) { + req.remoteAddress = + req.headers['x-forwarded-for'] || + req.socket.remoteAddress || + req.connection.remoteAddress || + req.connection.socket.remoteAddress; + + req.proto = + req.headers["x-forwarded-proto"] || + (req.socket.encrypted ? "https" : "http"); + + next(); +} \ No newline at end of file diff --git a/node_modules/connect-architect/connect.render.ejs/package.json b/node_modules/connect-architect/connect.render.ejs/package.json new file mode 100644 index 00000000..70e51494 --- /dev/null +++ b/node_modules/connect-architect/connect.render.ejs/package.json @@ -0,0 +1,16 @@ +{ + "name": "connect.render.ejs", + "version": "0.0.1", + + "main": "./render-ejs.js", + "private": true, + + "plugin": { + "provides": [ + "connect.render.ejs" + ], + "consumes": [ + "connect.render" + ] + } +} \ No newline at end of file diff --git a/node_modules/connect-architect/connect.render.ejs/render-ejs.js b/node_modules/connect-architect/connect.render.ejs/render-ejs.js new file mode 100644 index 00000000..708745fe --- /dev/null +++ b/node_modules/connect-architect/connect.render.ejs/render-ejs.js @@ -0,0 +1,58 @@ +"use strict"; + +var ejs = require("ejs"); + +module.exports = function(options, imports, register) { + + imports["connect.render"].registerEngine("ejs", createView); + + ejs.filters.JSONToJS = function(obj, indent) { + return JSON.stringify(obj, null, indent).replace(/<\/?script|[\u2028\u2029]/g, function(a) { + var h = a.charCodeAt(0).toString(16); + return (h.length == 2 ? "\\x" : "\\u") + h + a.substr(1); + }); + }; + + var helper = { + timeSpan: function(ts) { + var sec = 1000; + var min = 60 * sec; + var hour = 60 * min; + + return pad(~~(ts / hour)) + ":" + pad(~~((ts % hour) / min)) + ":" + pad(~~((ts % min) / sec)); + + function pad(d) { + if (d < 10) + return "0" + d; + else + return d; + } + }, + timeSpanSince: function(ts) { + return helper.timeSpan(Date.now() - ts); + } + }; + + + function createView(path, callback) { + return callback(null, function(res, options, callback) { + options.helper = helper; + ejs.renderFile(path, options, function(err, template) { + if (err) return callback(err); + + callback(null, { + headers: {"Content-Type": "text/html"}, + body: template + }); + }); + }); + } + + register(null, { + "connect.render.ejs": { + addHelper: function(name, helper) { + helper[name] = helper; + } + } + }); +}; \ No newline at end of file diff --git a/node_modules/connect-architect/connect.render/package.json b/node_modules/connect-architect/connect.render/package.json new file mode 100644 index 00000000..db4fd48f --- /dev/null +++ b/node_modules/connect-architect/connect.render/package.json @@ -0,0 +1,16 @@ +{ + "name": "connect.render", + "version": "0.0.1", + + "main": "./render.js", + "private": true, + + "plugin": { + "provides": [ + "connect.render" + ], + "consumes": [ + "connect" + ] + } +} \ No newline at end of file diff --git a/node_modules/connect-architect/connect.render/render.js b/node_modules/connect-architect/connect.render/render.js new file mode 100644 index 00000000..e8679853 --- /dev/null +++ b/node_modules/connect-architect/connect.render/render.js @@ -0,0 +1,124 @@ +"use strict"; + +var http = require("http"); +var error = require("http-error"); +var path = require("path"); +var fs = require("fs"); +var extname = path.extname; +var exists = fs.exists || path.exists; +var async = require("async"); + +module.exports = function(options, imports, register) { + + var defaultTemplatePath = options.templatePath; + + var viewCache = {}; + var engines = {}; + function registerEngine(name, handler) { + engines[name] = handler; + } + + imports.connect.addResponseMethod("setTemplatePath", function(path) { + this._templatePaths = this._templatePaths || []; + this._templatePaths.push(path); + }); + + imports.connect.addResponseMethod("resetTemplatePath", function() { + if (this._templatePaths) + this._templatePaths.pop(); + }); + + imports.connect.addResponseMethod("render", function(name, options, next) { + var res = this; + + var paths = this._templatePaths || []; + if (!paths.length && defaultTemplatePath) + paths.push(defaultTemplatePath); + + var isAbsolute = path.sep === "/" + ? name[0] === "/" + : name[1] === ":"; + var key = isAbsolute + ? name + : paths.join("&") + "&" + name; + + getView(function(err, view) { + if (err) return next(err); + + view(res, res.getOptions(options), function(err, rendered) { + if (err) return next(err); + + if (next && next.length == 2) + return next(null, rendered.body); + + var statusCode = options.statusCode || 200; + res.writeHead(statusCode, rendered.headers || {}); + res.end(rendered.body); + }); + }); + + function getView(callback) { + var view = viewCache[key]; + if (view) + return callback(null, view); + + var ext = extname(name); + if (!ext) + return callback(new error.InternalServerError("View doesn't have an extension: " + name)); + + var engine = engines[ext.slice(1)]; + if (!engine) + return callback(new error.InternalServerError("Unsupported view type: " + ext)); + + if (isAbsolute) { + exists(name, function(exists) { + withPath(exists ? name : null); + }); + } + else { + var fileName; + async.each(paths, function(p, next) { + fileName = path.join(p, name); + exists(fileName, function(exists) { + if (exists) + withPath(fileName); + else + next(); + }); + }, function(exists) { + withPath(null); + }); + } + + function withPath(fileName) { + if (!fileName) + return callback(new error.NotFound("View not found: " + name)); + + engine(fileName, function(err, view) { + if (err) return callback(err); + + view = viewCache[key] = view; + return callback(null, view); + }); + } + } + }); + + register(null, { + "connect.render": { + registerEngine: registerEngine, + setTemplatePath: function(path) { + return function(req, res, next) { + res.setTemplatePath(path); + next(); + }; + }, + resetTemplatePath: function() { + return function(req, res, next) { + res.resetTemplatePath(); + next(); + }; + } + } + }); +}; \ No newline at end of file diff --git a/node_modules/connect-architect/connect.session.file/package.json b/node_modules/connect-architect/connect.session.file/package.json new file mode 100644 index 00000000..84c1d260 --- /dev/null +++ b/node_modules/connect-architect/connect.session.file/package.json @@ -0,0 +1,11 @@ +{ + "name": "connect.session.file", + "version": "0.0.1", + "main": "session-ext.js", + "private": true, + + "plugin": { + "provides": ["session-store"], + "consumes": ["connect"] + } +} \ No newline at end of file diff --git a/node_modules/connect-architect/connect.session.file/session-ext.js b/node_modules/connect-architect/connect.session.file/session-ext.js new file mode 100644 index 00000000..2863d2be --- /dev/null +++ b/node_modules/connect-architect/connect.session.file/session-ext.js @@ -0,0 +1,169 @@ +var assert = require("assert"); +var path = require("path"); +var fs = require("fs"); +var Store = require("connect/lib/middleware/session/store"); + +module.exports = function startup(options, imports, register) { + + assert(options.sessionsPath, "option 'sessionsPath' is required"); + + if (!path.existsSync(path.dirname(options.sessionsPath))) { + fs.mkdir(path.dirname(options.sessionsPath), 0755); + } + if (!path.existsSync(options.sessionsPath)) { + fs.mkdir(options.sessionsPath, 0755); + } + + var sessionStore = new FileStore({ + basePath: options.sessionsPath, + reapInterval: 60 * 60 * 1000 // 1 hour + }); + + register(null, { + "session-store": { + on: sessionStore.on.bind(sessionStore), + get: sessionStore.get.bind(sessionStore), + set: sessionStore.set.bind(sessionStore), + destroy: sessionStore.destroy.bind(sessionStore), + regenerate: sessionStore.regenerate.bind(sessionStore), + createSession: sessionStore.createSession.bind(sessionStore) + } + }); + +}; + + +var FileStore = function(options) { + var self = this; + self.basePath = options.basePath; + self.reapInterval = options.reapInterval || -1; + if (self.reapInterval > 0) { + setInterval(function() { + fs.readdir(self.basePath, function(err, files) { + if (err) { + console.error(err); + return; + } + files.forEach(function(file) { + fs.readFile(self.basePath + "/" + file, function(err, data) { + if (err) { + console.error(err); + return; + } + var sess = JSON.parse(data); + var expires = (typeof sess.cookie.expires === 'string') + ? new Date(sess.cookie.expires) + : sess.cookie.expires; + if (!expires || new Date < expires) { + // session ok + } else { + self.destroy(file); + } + }); + }); + }); + }, self.reapInterval); + } +}; + +FileStore.prototype.__proto__ = Store.prototype; + +FileStore.prototype.get = function(sid, fn){ + var self = this; + sid = sid.replace(/\//g, "_"); + path.exists(self.basePath + "/" + sid, function(exists) { + if (exists) { + fs.readFile(self.basePath + "/" + sid, function(err, data) { + if (err) { + fn && fn(err); + } + else { + var sess; + try { + sess = JSON.parse(data); + } catch(e) { + console.warn("Error '" + e + "' reading session: " + sid, data); + self.destroy(sid, fn); + return; + } + var expires = (typeof sess.cookie.expires === 'string') + ? new Date(sess.cookie.expires) + : sess.cookie.expires; + if (!expires || new Date < expires) { + fn(null, sess); + } else { + self.destroy(sid, fn); + } + } + }); + } + else { + fn(); + } + }); +}; + +FileStore.prototype.set = function(sid, sess, fn){ + var self = this; + sid = sid.replace(/\//g, "_"); + var path = self.basePath + "/" + sid; + var tmpPath = path + "~" + new Date().getTime(); + fs.writeFile(path, JSON.stringify(sess), function(err) { + if (err) + return fn && fn(err); + + fs.rename(tmpPath, path, function(err) { + fn && fn(err); + }); + }); +}; + +FileStore.prototype.destroy = function(sid, fn){ + var self = this; + sid = sid.replace(/\//g, "_"); + path.exists(self.basePath + "/" + sid, function(exists) { + if (exists) { + fs.unlink(self.basePath + "/" + sid, function(err) { + if (err) { + fn && fn(err); + } + else { + fn && fn(); + } + }); + } else { + fn && fn(); + } + }); +}; + +FileStore.prototype.all = function(fn){ + var self = this; + fs.readdir(self.basePath, function(err, files) { + if (err) { + fn && fn(err); + return; + } + var arr = []; + files.forEach(function(file) { + // TODO: Make this async. + arr.push(JSON.parse(fs.readFileSync(self.basePath + "/" + file))); + }); + fn && fn(arr); + }); +}; + +FileStore.prototype.clear = function(fn){ + throw new Error("NYI"); +/* + this.sessions = {}; + fn && fn(); +*/ +}; + +FileStore.prototype.length = function(fn){ + throw new Error("NYI"); +/* + fn(null, Object.keys(this.sessions).length); +*/ +}; diff --git a/node_modules/connect-architect/connect.session.memory/package.json b/node_modules/connect-architect/connect.session.memory/package.json new file mode 100644 index 00000000..2e67d10c --- /dev/null +++ b/node_modules/connect-architect/connect.session.memory/package.json @@ -0,0 +1,10 @@ +{ + "name": "connect.session.memory", + "version": "0.0.1", + "main": "session-ext.js", + "private": true, + + "plugin": { + "provides": ["session-store"] + } +} \ No newline at end of file diff --git a/node_modules/connect-architect/connect.session.memory/session-ext.js b/node_modules/connect-architect/connect.session.memory/session-ext.js new file mode 100644 index 00000000..10a5001d --- /dev/null +++ b/node_modules/connect-architect/connect.session.memory/session-ext.js @@ -0,0 +1,17 @@ +var MemoryStore = require("connect").session.MemoryStore; + +module.exports = function startup(options, imports, register) { + + var sessionStore = new MemoryStore({ reapInterval: -1 }); + + register(null, { + "session-store": { + on: sessionStore.on.bind(sessionStore), + get: sessionStore.get.bind(sessionStore), + set: sessionStore.set.bind(sessionStore), + destroy: sessionStore.destroy.bind(sessionStore), + regenerate: sessionStore.regenerate.bind(sessionStore), + createSession: sessionStore.createSession.bind(sessionStore) + } + }); +}; diff --git a/node_modules/connect-architect/connect.session.mongodb/package.json b/node_modules/connect-architect/connect.session.mongodb/package.json new file mode 100644 index 00000000..fbff36ad --- /dev/null +++ b/node_modules/connect-architect/connect.session.mongodb/package.json @@ -0,0 +1,10 @@ +{ + "name": "connect.session.mongodb", + "version": "0.0.1", + "main": "session-ext.js", + "private": true, + + "plugin": { + "provides": ["session-store"] + } +} \ No newline at end of file diff --git a/node_modules/connect-architect/connect.session.mongodb/session-ext.js b/node_modules/connect-architect/connect.session.mongodb/session-ext.js new file mode 100644 index 00000000..8372260e --- /dev/null +++ b/node_modules/connect-architect/connect.session.mongodb/session-ext.js @@ -0,0 +1,21 @@ +var connect = require("connect"); +var MongoStore = require("connect-mongo")(connect); +var assert = require("assert"); + +module.exports = function startup(options, imports, register) { + assert(options.host, "Option 'host' is required"); + assert(options.db, "Option 'db' is required"); + + var sessionStore = new MongoStore(options); + + register(null, { + "session-store": { + on: sessionStore.on.bind(sessionStore), + get: sessionStore.get.bind(sessionStore), + set: sessionStore.set.bind(sessionStore), + destroy: sessionStore.destroy.bind(sessionStore), + regenerate: sessionStore.regenerate.bind(sessionStore), + createSession: sessionStore.createSession.bind(sessionStore) + } + }); +}; diff --git a/node_modules/connect-architect/connect.session.redis/multi-region-store.js b/node_modules/connect-architect/connect.session.redis/multi-region-store.js new file mode 100644 index 00000000..91449128 --- /dev/null +++ b/node_modules/connect-architect/connect.session.redis/multi-region-store.js @@ -0,0 +1,63 @@ + + +// master +// slave + +var debug = require('debug')('connect:redis-multi-region'); + +module.exports = function(connect) { + + var Store = connect.session.Store; + var RedisStore = require("connect-redis")(connect); + + function RedisMultiRegionStore(options) { + options.master.prefix = options.prefix; + options.slave.prefix = options.prefix; + + this.master = new RedisStore(options.master); + this.slave = new RedisStore(options.slave); + } + + + RedisMultiRegionStore.prototype.__proto__ = Store.prototype; + + /** + * Attempt to fetch session by the given `sid`. + * + * @param {String} sid + * @param {Function} fn + * @api public + */ + RedisMultiRegionStore.prototype.get = function(sid, fn) { + debug('GET "%s"', sid); + this.slave.get(sid, fn); + }; + + /** + * Commit the given `sess` object associated with the given `sid`. + * + * @param {String} sid + * @param {Session} sess + * @param {Function} fn + * @api public + */ + RedisMultiRegionStore.prototype.set = function(sid, sess, fn) { + debug("SET %s %j", sid, sess); + this.master.set(sid, sess); + this.slave.set(sid, sess, fn); + }; + + /** + * Destroy the session associated with the given `sid`. + * + * @param {String} sid + * @api public + */ + RedisMultiRegionStore.prototype.destroy = function(sid, fn) { + debug("DESTROY %s", sid); + this.master.destroy(sid); + this.slave.destroy(sid, fn); + }; + + return RedisMultiRegionStore; +}; diff --git a/node_modules/connect-architect/connect.session.redis/package.json b/node_modules/connect-architect/connect.session.redis/package.json new file mode 100644 index 00000000..ddfd56a1 --- /dev/null +++ b/node_modules/connect-architect/connect.session.redis/package.json @@ -0,0 +1,10 @@ +{ + "name": "connect.session.redis", + "version": "0.0.1", + "main": "session-ext.js", + "private": true, + + "plugin": { + "provides": ["session-store"] + } +} \ No newline at end of file diff --git a/node_modules/connect-architect/connect.session.redis/session-ext.js b/node_modules/connect-architect/connect.session.redis/session-ext.js new file mode 100644 index 00000000..5924e2ff --- /dev/null +++ b/node_modules/connect-architect/connect.session.redis/session-ext.js @@ -0,0 +1,53 @@ +var connect = require("connect"); +var RedisStore = require("connect-redis")(connect); +var MultiRegionRedisStore = require("./multi-region-store")(connect); +var assert = require("assert"); + +module.exports = function startup(options, imports, register) { + + assert(options.master, "option 'master' is required"); + assert(options.master.host, "option 'master.host' is required"); + assert(options.master.port, "option 'master.port' is required"); + + if (options.slave) { + assert(options.slave.host, "option 'slave.host' is required is slave is set"); + assert(options.slave.port, "option 'slave.port' is required is slave is set"); + } + + var sessionStore; + if ( + options.slave && options.master && + (options.slave.host !== options.master.host || options.master.port !== options.slave.port) + ) { + sessionStore = new MultiRegionRedisStore({ + master: options.master, + slave: options.slave, + prefix: options.prefix || "" + }); + } + else { + sessionStore = new RedisStore({ + port: options.master.port, + host: options.master.host, + pass: options.master.pass || "", + prefix: options.prefix || "" + }); + } + + register(null, { + "session-store": { + on: sessionStore.on.bind(sessionStore), + get: sessionStore.get.bind(sessionStore), + set: sessionStore.set.bind(sessionStore), + destroy: sessionStore.destroy.bind(sessionStore), + regenerate: sessionStore.regenerate.bind(sessionStore), + createSession: sessionStore.createSession.bind(sessionStore), + set generate(fn) { + sessionStore.generate = fn; + }, + get generate() { + return sessionStore.generate; + } + } + }); +}; \ No newline at end of file diff --git a/node_modules/connect-architect/connect.session/package.json b/node_modules/connect-architect/connect.session/package.json new file mode 100644 index 00000000..c9d15bd8 --- /dev/null +++ b/node_modules/connect-architect/connect.session/package.json @@ -0,0 +1,15 @@ +{ + "name": "connect.session", + "version": "0.0.1", + "main": "session-ext.js", + "private": true, + + "plugin": { + "provides": ["session"], + "consumes": [ + "connect", + "connect.cookieparser", + "session-store" + ] + } +} \ No newline at end of file diff --git a/node_modules/connect-architect/connect.session/session-ext.js b/node_modules/connect-architect/connect.session/session-ext.js new file mode 100644 index 00000000..367125a8 --- /dev/null +++ b/node_modules/connect-architect/connect.session/session-ext.js @@ -0,0 +1,43 @@ +var Session = require("connect").session; +var assert = require("assert"); + +module.exports = function startup(options, imports, register) { + + assert(options.key, "option 'key' is required"); + assert(options.secret, "option 'secret' is required"); + + var connect = imports.connect; + var sessionStore = imports["session-store"]; + + var sessionOptions = { + store: sessionStore, + key: options.key, + secret: options.secret, + cookie: {} + }; + if ("proxy" in options) + sessionOptions.proxy = options.proxy; + + var cookie = sessionOptions.cookie; + if ("secure" in options) + cookie.secure = options.secure; + + if ("maxAge" in options) + cookie.maxAge = options.maxAge; + + var connectModule = imports.connect.getModule(); + var sessionRoutes = connectModule(); + connect.useSession(sessionRoutes); + + sessionRoutes.use(Session(sessionOptions, cookie)); + + register(null, { + session: { + getKey: function() { + return options.key; + }, + get: sessionStore.get, + use: sessionRoutes.use.bind(sessionRoutes) + } + }); +}; \ No newline at end of file diff --git a/node_modules/connect-architect/connect.static/package.json b/node_modules/connect-architect/connect.static/package.json new file mode 100644 index 00000000..f2eb1d06 --- /dev/null +++ b/node_modules/connect-architect/connect.static/package.json @@ -0,0 +1,15 @@ +{ + "name": "connect-architect.static", + "version": "0.0.1", + "main": "./static-plugin.js", + "private": true, + + "plugin": { + "provides": [ + "connect.static" + ], + "consumes": [ + "connect" + ] + } +} \ No newline at end of file diff --git a/node_modules/connect-architect/connect.static/static-plugin.js b/node_modules/connect-architect/connect.static/static-plugin.js new file mode 100644 index 00000000..a1e0f645 --- /dev/null +++ b/node_modules/connect-architect/connect.static/static-plugin.js @@ -0,0 +1,78 @@ +module.exports = function startup(options, imports, register) { + + var prefix = options.prefix || "/static"; + var rjs = { + "paths": {}, + "packages": [], + "baseUrl": prefix + }; + + var workerPrefix = options.workerPrefix || "/static"; + + var connect = imports.connect.getModule(); + var staticServer = connect.createServer(); + imports.connect.useMain(options.bindPrefix || prefix, staticServer); + + imports.connect.setGlobalOption("staticPrefix", prefix); + imports.connect.setGlobalOption("workerPrefix", workerPrefix); + imports.connect.setGlobalOption("requirejsConfig", rjs); + + var mounts = []; + + register(null, { + "connect.static": { + addStatics: function(statics) { + mounts.push.apply(mounts, statics); + statics.forEach(function(s) { + var mount = s.mount.replace(/^\/?/, "/"); + if (s.router) { + var server = connect.static(s.path); + staticServer.use(mount, function(req, res, next) { + s.router(req, res); + server(req, res, next); + }); + } else { + staticServer.use(mount, connect.static(s.path)); + } + + var libs = s.rjs || {}; + for (var name in libs) { + if (typeof libs[name] === "string") { + rjs.paths[name] = join(prefix, libs[name]); + } else { + rjs.packages.push(libs[name]); + } + } + }); + }, + + getMounts: function() { + return mounts; + }, + + getRequireJsPaths: function() { + return rjs.paths; + }, + + getRequireJsPackages: function() { + return rjs.packages; + }, + + getStaticPrefix: function() { + return prefix; + }, + + getRequireJsConfig: function() { + return rjs; + }, + + getWorkerPrefix: function() { + return workerPrefix; + } + } + }); + + function join(prefix, path) { + return prefix.replace(/\/*$/, "") + "/" + path.replace(/^\/*/, ""); + } +}; diff --git a/node_modules/connect-architect/connect/connect-plugin.js b/node_modules/connect-architect/connect/connect-plugin.js new file mode 100644 index 00000000..6e646868 --- /dev/null +++ b/node_modules/connect-architect/connect/connect-plugin.js @@ -0,0 +1,224 @@ +var utils = require("connect/lib/utils"); +var netutil = require("netutil"); +var connect = require("connect"); +var http = require("http"); +var https = require("https"); + +module.exports = function startup(options, imports, register) { + var globalOptions = options.globals ? merge([options.globals]) : {}; + + var requestMethods = {}; + var responseMethods = {}; + + var app = connect(); + + var hookNames = [ + "Start", + "Setup", + "Main", + "Session" + ]; + var api = { + getModule: function() { + return connect; + }, + getUtils: function() { + return utils; + }, + /** + * set per request options. Used e.g. for the view rendering + */ + setOptions: function(options) { + return function(req, res, next) { + res.setOptions(options); + next(); + }; + }, + resetOptions: function() { + return function(req, res, next) { + res.resetOptions(); + next(); + }; + }, + setGlobalOption: function(key, value) { + globalOptions[key] = value; + }, + getGlobalOption: function(key) { + return globalOptions[key]; + }, + addResponseMethod: function(name, method) { + responseMethods[name] = method; + }, + addRequestMethod: function(name, method) { + requestMethods[name] = method; + } + + }; + + api.addResponseMethod("setOptions", function(options) { + this._options = this._options || []; + this._options.push(options); + }); + + api.addResponseMethod("getOptions", function(options) { + var opts = [globalOptions].concat(this._options || []); + if (options) + opts = opts.concat(options); + + return merge(opts); + }); + + api.addResponseMethod("resetOptions", function() { + if (this._options) + this._options.pop(); + }); + + + hookNames.forEach(function(name) { + var hookServer = connect(); + app.use(hookServer); + api["use" + name] = hookServer.use.bind(hookServer); + }); + + var connectHook = connectError(); + app.use(connectHook); + api.useError = connectHook.use; + + api.useSetup(connect.cookieParser()); + api.useSetup(connect.urlencoded()); + api.useSetup(connect.json()); + + api.addRoute = app.addRoute; + api.use = api.useMain; + + api.on = app.on; + api.emit = app.emit; + + api.useSetup(function(req, res, next) { + for (var name in requestMethods) + req[name] = requestMethods[name]; + + for (var name in responseMethods) + res[name] = responseMethods[name]; + + next(); + }); + + function startListening (port, host) { + api.getPort = function () { + return port; + }; + api.getHost = function () { + return host; + }; + + var server; + var proto; + if (options.secure) { + proto = "https"; + server = https.createServer(options.secure , app); + } + else { + proto = "http"; + server = http.createServer(app); + } + + server.listen(port, host, function(err) { + if (err) + return register(err); + + console.log("Connect server listening at " + proto + "://" + host + ":" + port); + + register(null, { + "onDestruct": function(callback) { + app.close(); + app.on("close", callback); + }, + "connect": api, + "http": { + getServer: function() { + return server; + } + } + }); + }); + + if (options.websocket) + attachWsServer(server, app); + + function attachWsServer(server, app) { + server.on("upgrade", function(req, socket, head) { + var res = new http.ServerResponse(req); + req.ws = { + socket: socket, + head: head + }; + req.method = "UPGRADE"; + + res.write = function() { + // console.log("RES WRITE", arguments); + }; + res.writeHead = function() { + // console.log("RES WRITEHEAD", arguments); + }; + res.end = function() { + // console.log("RES END", arguments); + socket.end(); + }; + + app.handle(req, res, function(err) { + if (err) { + console.error("Websocket error", err); + } + + socket.end(); + }); + }); + } + } + + if (options.port instanceof Array) { + netutil.findFreePort(options.port[0], options.port[1], options.host, function(err, port) { + if (err) + return register(err); + + startListening(port, options.host || "localhost"); + }); + } else { + startListening(options.port, options.host || "localhost"); + } + + function connectError() { + var filters = []; + + function handle(err, req, res, out) { + var rest = filters.concat(); + + function next(err) { + var filter = rest.shift(); + if (!filter) + return out(err); + + filter(err, req, res, next); + } + next(err); + } + + handle.use = function(middleware) { + filters.push(middleware); + }; + + return handle; + } +}; + +function merge(objects) { + var result = {}; + for (var i=0; i
    4. '; + } + else { + return res; + } + } + + var selfrx = /(^|\|)(?!\@|text\(\)|\.\.|[\w\-\:]+?\:\:)/g; // inject self regexp + + function _injself(s){ // self inject helper func + return s.charAt?s.replace(selfrx, "$1self::"):s; + } + + apf.$lmx = null; + + function _async(_n,_c,_a,_w,_f,_this,obj,func,args){ // Async handling + var i = _a.i, v; + + if (!_a.ret)_a.ret = []; + + if (_a[i]) + return _a.ret[i]; + + _a[i] = true; // flag this ID so args dont get computed again + + if (!obj.exec) + return _a.ret[i]=(func)?obj[func].apply(obj,args):obj.apply(obj,args); + + var cb = function(data, state, extra) { + if (_w) + delete _w._pc; + + if (state != apf.SUCCESS) { + _c(null, state, extra); + } + else{ + apf.$lmx = extra; + _a.ret[i] = data; + + if (_w) + _f.call(_this,_n,_c,_w,_a); + else + _f.call(_this,_n,_c,_a); + } + }; + + if (_w && _w._pc) { + _w._pc = { + obj: obj, + func: func, + args: args, + message: obj.createMessage && obj.createMessage(func, args), + _c: _c, + cb: cb + }; + }else{ + obj.exec(func, args, cb); + } + throw({ + x: 1 + }); + } + + function _precall(_w){ // precall + var o; + if (typeof(o = _w._pc) != "object" || !o) + return; + + o.obj.exec(o.func, o.args, o.cb, {message: o.message}); + + throw({x:1}); + } + + var _clut = apf.color?apf.color.colorshex:{}, _cparse = /^(rgb|hsv|hsb)\(\s+(\d+)\s+,\s+(\d+)\s+,\s+(\d+)\)/ + + function sort(set, xpath, options) { + var s = new apf.Sort(); + options = options || {}; + if (!xpath.charAt)xpath = ""; + if (xpath.charAt(0)=='@'){ + xpath = xpath.slice(1); + options.getValue = function(n) { + return n.getAttribute(xpath); + } + }else{ + options.getValue = function(n) { + return apf.queryValue(n,xpath); + } + } + s.set(options); + return s.apply(apf.getArrayFromNodelist(set)); + } + + function _cthex(c) { + var t; + if ((t=typeof(c))=='string'){ + if (c.indexOf('#')==0) { + if (c.length==7) return parseInt(c.slice(-1),16); + return parseInt(c.slice(-1),16); // compute repeat + } + if (t = _clut[a])return t; + if (c=c.match(_cparse)){ + if ((t=c[1]) == 'rgb'){ + return (((t=c[2])<0?0:(t>255?255:parseInt(t)))<<16)+ + (((t=c[3])<0?0:(t>255?255:parseInt(t)))<<8)+ + (((t=c[4])<0?0:(t>255?255:parseInt(t)))); + } else { // hsv + var h=parseFloat(c[2]),s=parseFloat(c[3]),v=parseFloat(c[4]), + i,m=v*(1-s),n=v*(1-s*((i=floor(((h<0?-h:h)%1)*6))?h-i:1-(h-i))); + switch(i) { + case 6:case 0: return ((v&0xff)<<16)+((n&0xff)<<8)+(m&0xff); + case 1: return ((n&0xff)<<16)+((v&0xff)<<8)+(m&0xff); + case 2: return ((m&0xff)<<16)+((v&0xff)<<8)+(n&0xff); + case 3: return ((m&0xff)<<16)+((n&0xff)<<8)+(v&0xff); + case 4: return ((n&0xff)<<16)+((m&0xff)<<8)+(v&0xff); + default: case 5: return ((v&0xff)<<16)+((m&0xff)<<8)+(n&0xff); + } + } + } + } else if (t=='number')return t; + return null; + } + + function lin(f, a, b) { + var fa = parseFloat(a), fb = parseFloat(b), fm = 1-(f = f<0?0:(f>1?1:f)); + if (fa!=a || fb!=b) + return (((fa=_cthex(a))&0xff0000)*f+((fb=_cthex(b))&0xff0000)*fm)&0xff0000| + ((fa&0xff00)*f+(fb&0xff00)*fm)&0xff00 | + ((fa&0xff)*f+(fb&0xff)*fm)&0xff; + return f*fa+fm*fb; + } + + var abs = Math.abs, acos = Math.acos, asin = Math.asin, + atan = Math.atan, atan2 = Math.atan2, ceil = Math.ceil, + cos = Math.cos, exp = Math.exp, floor = Math.floor, + log = Math.log, max = Math.max, min = Math.min, + pow = Math.pow, random = Math.random, round = Math.round, + sin = Math.sin, sqrt = Math.sqrt, tan = Math.tan, linear = lin; + + function tsin(x){ return 0.5*sin(x)+0.5;} + function tcos(x){ return 0.5*cos(x)+0.5;} + function usin(x){ return 0.5-0.5*sin(x);} + function ucos(x){ return 0.5-0.5*cos(x);} + function snap(a,b){ return round(a/b)*b; } + function clamp(a,b,c){ return ac?c:a); } + + this.compile = function(code) { + // up-scope much used functions + var _ret = __ret, _val = __val,_valm = __valm, _nod = __nod, + _nodm = __nodm, _cnt = __cnt, _cntm = __cntm, _lng = __lng, _valattr = __valattr; + + eval(code); + + return _f; + } + + this.compileWith = function(code, withs) { + // up-scope much used functions + var _ret = __ret, _val = __val,_valm = __valm, _nod = __nod, + _nodm = __nodm, _cnt = __cnt, _cntm = __cntm, _lng = __lng, _valattr = __valattr; + + eval(code); + + return _f; + } + + var LMBEGINCACHE; + /*LIVEMARKUP BEGIN CACHE + var _ret = __ret, _val = __val,_valm = __valm, _nod = __nod, + _nodm = __nodm, _cnt = __cnt, _cntm = __cntm, _lng = __lng, _valattr = __valattr; + this.c342 = function(_n,_a,_w) { + ..cached LM function.. + } + this.c342.type = 2; + this.c342.xpaths = {...}; + this.c342.props = {...}; + this.c723 = function(....){ + + } + // replace + d.replace(/var_LMBEGINCACHE;[\s\S]*var_LMBEGINCACHE;/,"code"); + _async(_n,_c,_a,_w,_f,this, + _async(_n,_c,_a,_w,apf.lm_exec.c342,this, + LIVEMARKUP END CACHE*/ + var LMENDCACHE; + +})(); + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * An object that represents a URI, broken down to its parts, according to [RFC3986](http://tools.ietf.org/html/rfc3986). + * + * All parts are publicly accessible after parsing, like 'url.port' or 'url.host'. + * + * #### Example + * + * ```javascript + * var url = new apf.url('http://usr:pwd@www.test.com:81/dir/dir.2/index.htm?q1=0&&test1&test2=value#top'); + * alert(url.port); //will show '81' + * alert(url.host); //will show 'www.test.com' + * alert(url.isSameLocation()) // will show 'true' when the browser is surfing on the www.test.com domain + * ``` + * + * @class apf.url + * @parser + * @default_private + * + * @author Mike de Boer + * @version %I%, %G% + * @since 1.0 + */ +apf.url = function(str) { + var base; + var location = (window.location && window.location.toString()) || ""; + if (str.indexOf(":") == -1 && (base = location).indexOf(":") != -1) { + base = new apf.url(base); + str = apf.getAbsolutePath(base.protocol + "://" + base.host + + (base.directory.charAt(0) == "/" ? "" : "/") + + (base.directory.charAt(base.directory.length - 1) == "/" + ? base.directory + : base.directory + '/'), str).replace(/\/\/\/\//, "///"); + } + var o = apf.url.options, + m = o.parser[o.strictMode ? "strict" : "loose"].exec(str), + i = 14; + this.uri = str.toString(); //copy string + + while (i--) + this[o.key[i]] = m[i] || ""; + + this[o.q.name] = {}; + var _self = this; + this[o.key[12]].replace(o.q.parser, function($0, $1, $2) { + if ($1) + _self[o.q.name][$1] = $2; + }); + + /** + * Checks if the [same origin policy](http://developer.mozilla.org/index.php?title=En/Same_origin_policy_for_JavaScript) is in effect for this URI. + * + * @returns {Boolean} `true` if it's the same. + */ + this.isSameLocation = function(){ + // filter out anchors + if (this.uri.length && this.uri.charAt(0) == "#") + return false; + // totally relative -- ../../someFile.html + if (!this.protocol && !this.port && !this.host) + return true; + + // scheme relative with port specified -- foo.com:8080 + if (!this.protocol && this.host && this.port + && window.location.hostname == this.host + && window.location.port == this.port) { + return true; + } + // scheme relative with no-port specified -- foo.com + if (!this.protocol && this.host && !this.port + && window.location.hostname == this.host + && window.location.port == 80) { + return true; + } + return window.location.protocol == (this.protocol + ":") + && window.location.hostname == this.host + && (window.location.port == this.port || !window.location.port && !this.port); + } +}; + +apf.url.options = { + strictMode: false, + key: ["source", "protocol", "authority", "userInfo", "user", "password", + "host", "port", "relative", "path", "directory", "file", "query", + "anchor"], + q: { + name: "queryKey", + parser: /(?:^|&)([^&=]*)=?([^&]*)/g + }, + parser: { + strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/, + loose: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/ + } +}; + + + + + + + +/** + * @private + */ +apf.runXpath = function(){ + +/** + * Workaround for the lack of having an XPath parser on safari. + * It works on Safari's document and XMLDocument object. + * + * It doesn't support the full XPath spec, but just enought for + * the skinning engine which needs XPath on the HTML document. + * + * Supports: + * - Compilation of xpath statements + * - Caching of XPath statements + * + * @parser + * @private + */ +apf.XPath = { + cache: {}, + + getSelf: function(htmlNode, tagName, info, count, num, sResult) { + var numfound = 0, result = null, data = info[count]; + + if (data) + data[0](htmlNode, data[1], info, count + 1, numfound++ , sResult); + else + sResult.push(htmlNode); + }, + + getChildNode: function(htmlNode, tagName, info, count, num, sResult) { + var numfound = 0, result = null, data = info[count]; + + var nodes = htmlNode.childNodes; + if (!nodes) return; //Weird bug in Safari + for (var i = 0; i < nodes.length; i++) { + //if (nodes[i].nodeType != 1) + //continue; + + if (tagName && (tagName != nodes[i].tagName) && (nodes[i].style + ? nodes[i].tagName.toLowerCase() + : nodes[i].tagName) != tagName) + continue;// || numsearch && ++numfound != numsearch + + htmlNode = nodes[i]; + + if (data) + data[0](nodes[i], data[1], info, count + 1, numfound++ , sResult); + else + sResult.push(nodes[i]); + } + + //commented out : && (!numsearch || numsearch == numfound) + }, + + doQuery: function(htmlNode, qData, info, count, num, sResult) { + var result = null, data = info[count]; + var query = qData[0]; + var returnResult = qData[1]; + try { + var qResult = eval(query); + }catch(e) { + apf.console.error(e.name + " " + e.type + ":" + apf.XPath.lastExpr + "\n\n" + query); + //throw new Error(e.name + " " + e.type + ":" + apf.XPath.lastExpr + "\n\n" + query); + return; + } + + if (returnResult) + return sResult.push(qResult); + if (!qResult || qResult.dataType == apf.ARRAY && !qResult.length) + return; + + if (data) + data[0](htmlNode, data[1], info, count + 1, 0, sResult); + else + sResult.push(htmlNode); + }, + + getTextNode: function(htmlNode, empty, info, count, num, sResult) { + var data = info[count], + nodes = htmlNode.childNodes; + + for (var i = 0; i < nodes.length; i++) { + if (nodes[i].nodeType != 3 && nodes[i].nodeType != 4) + continue; + + if (data) + data[0](nodes[i], data[1], info, count + 1, i, sResult); + else + sResult.push(nodes[i]); + } + }, + + getAnyNode: function(htmlNode, empty, info, count, num, sResult) { + var data = info[count], + nodes = htmlNode.getElementsByTagName("*");//childNodes; + + for (var i = 0; i < nodes.length; i++) { + if (data) + data[0](nodes[i], data[1], info, count + 1, i, sResult); + else + sResult.push(nodes[i]); + } + }, + + getAttributeNode: function(htmlNode, attrName, info, count, num, sResult) { + if (!htmlNode || htmlNode.nodeType != 1) return; + + if (attrName == "*") { + var nodes = htmlNode.attributes; + for (var i = 0; i < nodes.length; i++) { + arguments.callee.call(this, htmlNode, nodes[i].nodeName, info, + count, i, sResult); + } + return; + } + + var data = info[count], + value = htmlNode.getAttributeNode(attrName);//htmlNode.attributes[attrName];// + + if (data) + data[0](value, data[1], info, count + 1, 0, sResult); + else if (value) + sResult.push(value); + }, + + getAllNodes: function(htmlNode, x, info, count, num, sResult) { + var data = info[count], + tagName = x[0], + inclSelf = x[1], + prefix = x[2], + nodes, i, l; + + if (inclSelf && (htmlNode.tagName == tagName || tagName == "*" || tagName == "node()")) { + if (data) + data[0](htmlNode, data[1], info, count + 1, 0, sResult); + else + sResult.push(htmlNode); + } + + if (tagName == "node()") { + tagName = "*"; + prefix = ""; + if (apf.isIE) { + nodes = htmlNode.getElementsByTagName("*"); + } + else { + nodes = []; + (function recur(x) { + for (var n, i = 0; i < x.childNodes.length; i++) { + n = x.childNodes[i]; + if (n.nodeType != 1) + continue; + nodes.push(n); + + recur(n); + } + })(htmlNode); + } + } + else { + nodes = htmlNode.getElementsByTagName((prefix + && (apf.isGecko || apf.isOpera || htmlNode.nodeFunc) ? prefix + ":" : "") + tagName); + } + + for (i = 0, l = nodes.length; i < l; i++) { + if (data) + data[0](nodes[i], data[1], info, count + 1, i, sResult); + else + sResult.push(nodes[i]); + } + }, + + getAllAncestorNodes: function(htmlNode, x, info, count, num, sResult) { + var data = info[count], + tagName = x[0], + inclSelf = x[1], + i = 0, + s = inclSelf ? htmlNode : htmlNode.parentNode; + while (s && s.nodeType == 1) { + if (s.tagName == tagName || tagName == "*" || tagName == "node()") { + if (data) + data[0](s, data[1], info, count + 1, ++i, sResult); + else + sResult.push(s); + } + s = s.parentNode + } + }, + + getParentNode: function(htmlNode, empty, info, count, num, sResult) { + var data = info[count], + node = htmlNode.parentNode; + + if (data) + data[0](node, data[1], info, count + 1, 0, sResult); + else if (node) + sResult.push(node); + }, + + //precsiblg[3] might not be conform spec + getPrecedingSibling: function(htmlNode, tagName, info, count, num, sResult) { + var data = info[count], + node = htmlNode.previousSibling; + + while (node) { + if (tagName != "node()" && (node.style + ? node.tagName.toLowerCase() + : node.tagName) != tagName) { + node = node.previousSibling; + continue; + } + + if (data) + data[0](node, data[1], info, count+1, 0, sResult); + else if (node) { + sResult.push(node); + break; + } + } + }, + + //flwsiblg[3] might not be conform spec + getFollowingSibling: function(htmlNode, tagName, info, count, num, sResult) { + var result = null, data = info[count]; + + var node = htmlNode.nextSibling; + while (node) { + if (tagName != "node()" && (node.style + ? node.tagName.toLowerCase() + : node.tagName) != tagName) { + node = node.nextSibling; + continue; + } + + if (data) + data[0](node, data[1], info, count+1, 0, sResult); + else if (node) { + sResult.push(node); + break; + } + } + }, + + multiXpaths: function(contextNode, list, info, count, num, sResult) { + for (var i = 0; i < list.length; i++) { + info = list[i][0]; + var rootNode = (info[3] + ? contextNode.ownerDocument.documentElement + : contextNode);//document.body + info[0](rootNode, info[1], list[i], 1, 0, sResult); + } + + sResult.makeUnique(); + }, + + compile: function(sExpr) { + var isAbsolute = sExpr.match(/^\//);//[^\/]/ + + sExpr = sExpr.replace(/\[(\d+)\]/g, "/##$1") + .replace(/\|\|(\d+)\|\|\d+/g, "##$1") + .replace(/\.\|\|\d+/g, ".") + .replace(/\[([^\]]*)\]/g, function(match, m1) { + return "/##" + m1.replace(/\|/g, "_@_"); + }); //wrong assumption think of | + + if (sExpr == "/" || sExpr == ".") + return sExpr; + + //Mark // elements + //sExpr = sExpr.replace(/\/\//g, "/[]/self::"); + + //Check if this is an absolute query + return this.processXpath(sExpr.replace(/\/\//g, "descendant::"), isAbsolute); + }, + + processXpath: function(sExpr, isAbsolute) { + var results = [], + i, l, m, query; + sExpr = sExpr.replace(/'[^']*'/g, function(m) { + return m.replace("|", "_@_"); + }); + + sExpr = sExpr.split("\|"); + for (i = 0, l = sExpr.length; i < l; i++) + sExpr[i] = sExpr[i].replace(/_\@\_/g, "|");//replace(/('[^']*)\_\@\_([^']*')/g, "$1|$2"); + + if (sExpr.length == 1) { + sExpr = sExpr[0]; + } + else { + for (i = 0, l = sExpr.length; i < l; i++) + sExpr[i] = this.processXpath(sExpr[i]); + results.push([this.multiXpaths, sExpr]); + return results; + } + + var sections = sExpr.split("/"); + for (i = 0, l = sections.length; i < l; i++) { + if (sections[i] == "." || sections[i] == "") + continue; + else if (sections[i] == "..") + results.push([this.getParentNode, null]); + else if (sections[i].match(/^[\w\-_\.]+(?:\:[\w\-_\.]+){0,1}$/)) + results.push([this.getChildNode, sections[i]]);//.toUpperCase() + else if (sections[i].match(/^\#\#(\d+)$/)) + results.push([this.doQuery, ["num+1 == " + parseInt(RegExp.$1)]]); + else if (sections[i].match(/^\#\#(.*)$/)) { + //FIX THIS CODE + query = RegExp.$1; + m = [query.match(/\(/g), query.match(/\)/g)]; + if (m[0] || m[1]) { + while (!m[0] && m[1] || m[0] && !m[1] + || m[0].length != m[1].length) { + if (!sections[++i]) break; + query += "/" + sections[i]; + m = [query.match(/\(/g), query.match(/\)/g)]; + } + } + + results.push([this.doQuery, [this.compileQuery(query)]]); + } + else if (sections[i] == "*") + results.push([this.getChildNode, null]); //FIX - put in def function + else if (sections[i].substr(0,2) == "[]") + results.push([this.getAllNodes, ["*", false]]);//sections[i].substr(2) || + else if (sections[i].match(/descendant-or-self::node\(\)$/)) + results.push([this.getAllNodes, ["*", true]]); + else if (sections[i].match(/descendant-or-self::([^\:]*)(?:\:(.*)){0,1}$/)) + results.push([this.getAllNodes, [RegExp.$2 || RegExp.$1, true, RegExp.$1]]); + else if (sections[i].match(/descendant::([^\:]*)(?:\:(.*)){0,1}$/)) + results.push([this.getAllNodes, [RegExp.$2 || RegExp.$1, false, RegExp.$1]]); + else if (sections[i].match(/ancestor-or-self::([^\:]*)(?:\:(.*)){0,1}$/)) + results.push([this.getAllAncestorNodes, [RegExp.$2 || RegExp.$1, true, RegExp.$1]]); + else if (sections[i].match(/ancestor::([^\:]*)(?:\:(.*)){0,1}$/)) + results.push([this.getAllAncestorNodes, [RegExp.$2 || RegExp.$1, false, RegExp.$1]]); + else if (sections[i].match(/^\@(.*)$/)) + results.push([this.getAttributeNode, RegExp.$1]); + else if (sections[i] == "text()") + results.push([this.getTextNode, null]); + else if (sections[i] == "node()") + results.push([this.getChildNode, null]);//FIX - put in def function + else if (sections[i].match(/following-sibling::(.*)$/)) + results.push([this.getFollowingSibling, RegExp.$1.toLowerCase()]); + else if (sections[i].match(/preceding-sibling::(.*)$/)) + results.push([this.getPrecedingSibling, RegExp.$1.toLowerCase()]); + else if (sections[i] == "self::node()") + results.push([this.getSelf, null]); + else if (sections[i].match(/self::(.*)$/)) + results.push([this.doQuery, ["apf.XPath.doXpathFunc(htmlNode, 'local-name') == '" + RegExp.$1 + "'"]]); + else { + //@todo FIX THIS CODE + //add some checking here + query = sections[i]; + m = [query.match(/\(/g), query.match(/\)/g)]; + if (m[0] || m[1]) { + while (!m[0] && m[1] || m[0] && !m[1] || m[0].length != m[1].length) { + if (!sections[++i]) break; + query += "/" + sections[i]; + m = [query.match(/\(/g), query.match(/\)/g)]; + } + } + + results.push([this.doQuery, [this.compileQuery(query), true]]) + + //throw new Error("---- APF Error ----\nMessage : Could not match XPath statement: '" + sections[i] + "' in '" + sExpr + "'"); + } + } + + results[0][3] = isAbsolute; + return results; + }, + + compileQuery: function(code) { + return new apf.CodeCompilation(code).compile(); + }, + + doXpathFunc: function(contextNode, type, nodelist, arg2, arg3, xmlNode, force) { + if (!nodelist || nodelist.length == 0) + nodelist = ""; + + if (type == "not") + return !nodelist; + + if (!force) { + var arg1, i, l; + if (typeof nodelist == "object" || nodelist.dataType == apf.ARRAY) { + if (nodelist && !nodelist.length) + nodelist = [nodelist]; + + var res = false, value; + for (i = 0, l = nodelist.length; i < l; i++) { + xmlNode = nodelist[i]; + if (!xmlNode || typeof xmlNode == "string" + || "position|last|count|local-name|name".indexOf(type) > -1) { + value = xmlNode; + } + else { + if (xmlNode.nodeType == 1 && xmlNode.firstChild && xmlNode.firstChild.nodeType != 1) + xmlNode = xmlNode.firstChild; + value = xmlNode.nodeValue; + } + + if (res = arguments.callee.call(this, contextNode, type, value, arg2, arg3, xmlNode, true)) + return res; + } + return res; + } + else { + arg1 = nodelist; + } + } + else { + arg1 = nodelist; + } + + switch(type) { + case "position": + return apf.getChildNumber(contextNode) + 1; + case "format-number": + return apf.formatNumber(arg1); //@todo this should actually do something + case "floor": + return Math.floor(arg1); + case "ceiling": + return Math.ceil(arg1); + case "starts-with": + return arg1 ? arg1.substr(0, arg2.length) == arg2 : false; + case "string-length": + return arg1 ? arg1.length : 0; + case "count": + return arg1 ? arg1.length : 0; + case "last": + return arg1 ? arg1[arg1.length-1] : null; + case "name": + var c = xmlNode || contextNode; + return c.nodeName || c.tagName; + case "local-name": + var c = xmlNode || contextNode; + if (c.nodeType != 1) return false; + return c.localName || (c.tagName || "").split(":").pop();//[apf.TAGNAME] + case "substring": + return arg1 && arg2 ? arg1.substring(arg2, arg3 || 0) : ""; + case "contains": + return arg1 && arg2 ? arg1.indexOf(arg2) > -1 : false; + case "concat": + var str = "" + for (i = 1, l = arguments.length; i < l; i++) { + if (typeof arguments[i] == "object") { + str += getNodeValue(arguments[i][0]); + continue; + } + str += arguments[i]; + } + return str; + case "translate": + for (i = 0, l = arg2.length; i < l; i++) + arg1 = arg1.replace(arg2.substr(i,1), arg3.substr(i,1)); + return arg1; + } + }, + + selectNodeExtended: function(sExpr, contextNode, match) { + var sResult = this.selectNodes(sExpr, contextNode); + + if (sResult.length == 0) + return null; + if (!match) + return sResult; + + for (var i = 0, l = sResult.length; i < l; i++) { + if (String(getNodeValue(sResult[i])) == match) + return [sResult[i]]; + } + + return null; + }, + + getRoot: function(xmlNode) { + while (xmlNode.parentNode && xmlNode.parentNode.nodeType == 1) + xmlNode = xmlNode.parentNode; + + return xmlNode.parentNode; + }, + + selectNodes: function(sExpr, contextNode) { + if (!this.cache[sExpr]) + this.cache[sExpr] = this.compile(sExpr); + + + + if (typeof this.cache[sExpr] == "string"){ + if (this.cache[sExpr] == ".") + return [contextNode]; + if (this.cache[sExpr] == "/") { + return [(contextNode.nodeType == 9 + ? contextNode.documentElement + : this.getRoot(contextNode))]; + } + } + + if (typeof this.cache[sExpr] == "string" && this.cache[sExpr] == ".") + return [contextNode]; + + var info = this.cache[sExpr][0], + rootNode = (info[3] + ? (contextNode.nodeType == 9 + ? contextNode.documentElement + : this.getRoot(contextNode)) + : contextNode),//document.body*/ + sResult = []; + + if (rootNode) + info[0](rootNode, info[1], this.cache[sExpr], 1, 0, sResult); + + return sResult; + } +}; + +function getNodeValue(sResult) { + if (sResult.nodeType == 1) + return sResult.firstChild ? sResult.firstChild.nodeValue : ""; + if (sResult.nodeType > 1 || sResult.nodeType < 5) + return sResult.nodeValue; + return sResult; +} + +/** + * @constructor + * @private + */ +apf.CodeCompilation = function(code) { + this.data = { + F: [], + S: [], + I: [], + X: [] + }; + + this.compile = function(){ + code = code.replace(/ or /g, " || ") + .replace(/ and /g, " && ") + .replace(/!=/g, "{}") + .replace(/=/g, "==") + .replace(/\{\}/g, "!="); + + // Tokenize + this.tokenize(); + + // Insert + this.insert(); + + code = code.replace(/, \)/g, ", htmlNode)"); + + return code; + }; + + this.tokenize = function(){ + //Functions + var data = this.data.F; + code = code.replace(/(translate|format-number|contains|substring|local-name|last|position|round|starts-with|string|string-length|sum|floor|ceiling|concat|count|not)\s*\(/g, + function(d, match) { + return (data.push(match) - 1) + "F_"; + } + ); + + //Strings + data = this.data.S; + code = code.replace(/'([^']*)'/g, function(d, match) { + return (data.push(match) - 1) + "S_"; + }) + .replace(/"([^"]*)"/g, function(d, match) { + return (data.push(match) - 1) + "S_"; + }); + + //Xpath + data = this.data.X; + code = code.replace(/(^|\W|\_)([\@\.\/A-Za-z\*][\*\.\@\/\w\:\-]*(?:\(\)){0,1})/g, + function(d, m1, m2) { + return m1 + (data.push(m2) - 1) + "X_"; + }) + .replace(/(\.[\.\@\/\w]*)/g, function(d, m1, m2) { + return (data.push(m1) - 1) + "X_"; + }); + + //Ints + data = this.data.I; + code = code.replace(/(\d+)(\W)/g, function(d, m1, m2) { + return (data.push(m1) - 1) + "I_" + m2; + }); + }; + + this.insert = function(){ + var data = this.data; + code = code.replace(/(\d+)X_\s*==\s*(\d+S_)/g, function(d, nr, str) { + return "apf.XPath.selectNodeExtended('" + + data.X[nr].replace(/'/g, "\\'") + "', htmlNode, " + str + ")"; + }) + .replace(/(\d+)([FISX])_/g, function(d, nr, type) { + var value = data[type][nr]; + + if (type == "F") { + return "apf.XPath.doXpathFunc(htmlNode, '" + value + "', "; + } + else if (type == "S") { + return "'" + value + "'"; + } + else if (type == "I") { + return value; + } + else if (type == "X") { + return "apf.XPath.selectNodeExtended('" + + value.replace(/'/g, "\\'") + "', htmlNode)"; + } + }) + .replace(/, \)/g, ")"); + }; +}; + +}; + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * An element containing all the binding rules for the data + * bound elements referencing this element. + * + * #### Example + * + * ```xml + * + * + * + * + * + * + * + * + * + * + * + * + * ``` + * + * @see apf.smartbinding + * @baseclass + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.8 + * + * @default_private + */ +apf.BindingRule = function(struct, tagName) { + this.$init(tagName || true, apf.NODE_HIDDEN, struct); +}; + +(function(){ + this.$bindingRule = true; + + this.compile = function(prop) { + return (this["c" + prop] = apf.lm.compile(this[prop], { + xpathmode: 3, + injectself: true + })); + }; + + this.$compile = function(prop, options) { + return (this["c" + prop + "2"] = apf.lm.compile(this[prop], options)); + }; + + //1 = force no bind rule, 2 = force bind rule + this.$attrExcludePropBind = apf.extend({ + value: 1, + match: 1 + }, this.$attrExcludePropBind); + + this.$booleanProperties["hasaml"] = true; + + this.$propHandlers["value"] = + this.$propHandlers["match"] = function(value, prop) { + delete this["c" + prop]; + + if (this.$amlLoaded) { + //Find parent that this rule works on + var node = this; + while (node && node.$bindingRule) + node = node.parentNode; + + if (!node) return; + + //Reload parent to propagate change + apf.queue.add("reload" + node.$uniqueId, function(){ + node.reload(); + }); + + //Recompile ruleset + if (node.$bindings.$isCompiled) + node.$bindings.$compiled = node.$bindings.compile( + this.localName != "each" && this.localName); + } + }; + + // *** DOM Handlers *** // + + /*this.addEventListener("DOMAttrModified", function(e) { + + });*/ + + this.addEventListener("DOMNodeInserted", function(e) { + //Find parent that this rule works on + var node = this; + while (node.$bindingRule) + node = node.parentNode; + + //Reload parent to propagate change + //@todo trigger should be maintained on node itself to prevent dual reload + if ("expanded|collapsed".indexOf(this.localName) == -1) + apf.queue.add("reload" + node.$uniqueId, function(){ + node.reload(); + }); + + //If this node is added, add to set + if (e.currentTarget == this) { + (node.$bindings[this.localName] + || (node.$bindings[this.localName] = [])).pushUnique(this); + } + //@todo apf3.0 test if proc instr and cdata needs to be serialized + //Else just update the binding value + else if (!this.attributes.getNamedItem("value")) + this.value = apf.serializeChildren(this); + //Or do nothing + else return; + + //Recompile ruleset + if (node.$bindings.$isCompiled) + node.$bindings.$compiled = node.$bindings.compile( + this.localName != "each" && this.localName); + }); + + this.addEventListener("DOMNodeRemoved", function(e) { + if (this.$amlDestroyed) + return; + + //Find parent that this rule works on + var first, node = this; + while (node && node.$bindingRule) + node = node.parentNode; + + if (!node) + return; + + //If this node is removed, remove to set + if (e.currentTarget == this) { + if (node.$bindings && node.$bindings[this.localName]) + node.$bindings[this.localName].remove(this); + else + return; + } + //@todo apf3.0 test if proc instr and cdata needs to be serialized + //Else just update the binding value + else if (!this.attributes.getNamedItem("value") && (first = this.firstChild)) { + if (first.nodeType == this.NODE_PROCESSING_INSTRUCTION) { + if (first.target == "lm") + this.value = "{" + first.nodeValue + "}"; + else + this.value = first.nodeValue; + } + else + this.value = apf.serializeChildren(this).trim(); + } + //Or do nothing + else return; + + //Reload parent to propagate change + if ("expanded|collapsed".indexOf(this.localName) == -1) + apf.queue.add("reload" + node.$uniqueId, function(){ + if (!node.$amlDestroyed) + node.reload(); + }); + + //Recompile ruleset + if (node.$bindings.$isCompiled) + node.$bindings.$compiled = node.$bindings.compile( + this.localName != "each" && this.localName); + }); + + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + + + var first; + if (!this.value && this.localName != "each" && (first = this.$aml + && this.$aml.firstChild || this.firstChild)) { + if (first.nodeType == this.NODE_PROCESSING_INSTRUCTION) { + if (first.target == "lm") + this.value = "{" + first.nodeValue + "}"; + else + this.value = first.nodeValue; + } + else + this.value = apf.serializeChildren(this.$aml).trim(); + } + + //Find the parent this rule works on + var pNode = this.parentNode; + while (pNode.$bindingRule) + pNode = pNode.parentNode; + + //Add the rule to the set + var bindings = pNode.$bindings || (pNode.$bindings = new apf.ruleList()); + (bindings[this.localName] || (bindings[this.localName] = [])).push(this); + + //Compile if necessary + if (pNode.localName != "bindings" && (this.localName != "each" || !this.childNodes.length)) { + var ns = this; + while ((ns = ns.nextSibling) && ns.nodeType != 1); + + if (!ns || !ns.$bindingRule) { + pNode.$cbindings = pNode.$bindings.compile( + pNode.$bindings.$isCompiled ? this.localName : null); + + pNode.dispatchEvent("bindingsload", { + bindings: pNode.$bindings, + compiled: pNode.$cbindings + }); + pNode.$checkLoadQueue(); + } + } + }); +}).call(apf.BindingRule.prototype = new apf.AmlElement()); + +apf.aml.setElement("icon", apf.BindingRule); +apf.aml.setElement("image", apf.BindingRule); +apf.aml.setElement("caption", apf.BindingRule); +apf.aml.setElement("tooltip", apf.BindingRule); +apf.aml.setElement("css", apf.BindingRule); +apf.aml.setElement("selectable", apf.BindingRule); +apf.aml.setElement("value", apf.BindingRule); +apf.aml.setElement("src", apf.BindingRule); +apf.aml.setElement("collapsed", apf.BindingRule); +apf.aml.setElement("expanded", apf.BindingRule); +apf.aml.setElement("empty", apf.BindingRule); + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * Define some action rules. + * + * @class apf.ActionRule + * @inherits apf.AmlElement + */ +// @todo Doc do all of these. +/* + * @attribute {String} match + */ +/* + * @attribute {String} set + */ +/* + * @attribute {String} undo + */ +/* + * @attribute {String} lock + */ +// @todo Doc ALL of these +/* + * @define update + */ +/* + * @attribute {String} get + */ +/* + * @attribute {String} parent + */ +/* + * @define add + */ +/* + * @attribute {Boolean} get + */ +/* + * @attribute {Boolean} parent + */ +apf.ActionRule = function(struct, tagName) { + this.$init(tagName || true, apf.NODE_HIDDEN, struct); +}; + +(function(){ + this.$actionRule = true; + + this.compile = function(prop, options) { + return (this["c" + prop] = apf.lm.compile(this[prop], + options || {xpathmode: 2})); + } + + //1 = force no bind rule, 2 = force bind rule + this.$attrExcludePropBind = apf.extend({ + set: 1, + get: 1, + undo: 1, + lock: 1, + match: 1, + parent: 1 + }, this.$attrExcludePropBind); + + this.$propHandlers["set"] = + this.$propHandlers["get"] = + this.$propHandlers["parent"] = + this.$propHandlers["match"] = function(value, prop) { + delete this["c" + prop]; + } + + // *** DOM Handlers *** // + + this.addEventListener("DOMNodeInserted", function(e) { + if (e.currentTarget == this) { + var pNode = this.parentNode; + if (!pNode.$actions) + pNode.$actions = new apf.ruleList(); + + (pNode.$actions[this.localName] + || (pNode.$actions[this.localName] = [])).push(this); + } + else { + if (this.attributes.getNamedItem("value")) + return; + + //@todo apf3.0 test if proc instr and cdata needs to be serialized + this.value = apf.serializeChildren(this); + } + }); + + this.addEventListener("DOMNodeRemoved", function(e) { + if (this.$amlDestroyed) + return; + + if (e.currentTarget == this) { + this.parentNode.$actions[this.localName].remove(this); + } + else { + if (this.attributes.getNamedItem("value")) + return; + + //@todo apf3.0 test if proc instr and cdata needs to be serialized + this.value = apf.serializeChildren(this); + } + }); + + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + if (!this.get) + this.get = apf.serializeChildren(this.$aml).trim(); + + var actions = this.parentNode.$actions + || (this.parentNode.$actions = new apf.ruleList()); + + (actions[this.localName] || (actions[this.localName] = [])).push(this); + }); +}).call(apf.ActionRule.prototype = new apf.AmlElement()); + +apf.aml.setElement("rename", apf.ActionRule); +apf.aml.setElement("remove", apf.ActionRule); +apf.aml.setElement("add", apf.ActionRule); +apf.aml.setElement("update", apf.ActionRule); +apf.aml.setElement("copy", apf.ActionRule); +apf.aml.setElement("move", apf.ActionRule); +apf.aml.setElement("check", apf.ActionRule); +apf.aml.setElement("change", apf.ActionRule); + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + +/** + * This element allows you to define some rules containing all the action rules for the data + * bound elements referencing this element. + * + * @allowchild {actions} + * + * @class apf.actions + * @inherits apf.AmlElement + * @define actions + * @logic + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.8 + * + * @default_private + */ +apf.actions = function(struct, tagName) { + this.$init(tagName || "actions", apf.NODE_HIDDEN, struct); + + this.$actions = new apf.ruleList(); + this.$amlNodes = {}; +}; + +(function(){ + this.$smartbinding = null; + + this.register = function(amlNode) { + if (amlNode.localName == "smartbinding") { + this.$smartbinding = amlNode; + this.$smartbinding.add(this); //Assuming only at init + return; + } + + this.$amlNodes[amlNode.$uniqueId] = amlNode; + amlNode.$actions = this.$actions; + amlNode.$actionsElement = this; + amlNode.dispatchEvent("actionsload", {bindings: this}); + } + + this.unregister = function(amlNode) { + //unregister element + this.$amlNodes[amlNode.$uniqueId] = null; + delete this.$amlNodes[amlNode.$uniqueId]; + + delete amlNode.$actionsElement; + delete amlNode.$actions; + amlNode.dispatchEvent("actionsunload", {bindings: this}); + }; + + // *** DOM Handlers *** // + + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + var nodes = this.childNodes; + for (var node, i = 0, l = nodes.length; i < l; i++) { + if ((node = nodes[i]).nodeType != 1) + continue; + + node.dispatchEvent("DOMNodeInsertedIntoDocument"); + } + + this.register(this.parentNode); + }); +}).call(apf.actions.prototype = new apf.AmlElement()); + +apf.aml.setElement("actions", apf.actions); + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * This element the keeps track of all user actions that are triggered in GUI + * elements. + * + * This element maintains a stack of actions, and knows how to + * undo and redo them. It is also aware of how to synchronize the changes to the + * backend data store. + * + * + * #### Remarks + * + * With offline support enabled, the actiontracker can + * serialize both its undo stack and its execution stack such that these can + * be kept in-between application sessions. This means that a user will be able + * to close the application and start it at a later date whilst keeping his or + * her entire undo/redo stack. Furthermore, all changes done whilst being offline + * will be synchronized to the data store when the application comes online. + * + * @class apf.actiontracker + * @define actiontracker + * @logic + * + * @inherits apf.Class + * @inherits apf.AmlElement + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.8 + * + */ +/** + * @event afterchange Fires after a change to the action stack occurs + * @param {Object} e The standard event object. It contains the following property: + * - action ([[String]]): the name of the action that was executed + */ +/** + * @event beforechange Fires before a change to the action stack will occur + * @cancelable Prevents the execution of the action. + * @param {Object} e The standard event object. It contains the following property: + * - `action` ([[String]]): The action to be executed + * - `args` ([[Array]]): The arguments for the action + * - `[xmlActionNode]` ([[XMLNode]]): The rules to synchronize the changes to the server + * for both execution and undo. + * - `[amlNode]` ([[apf.AmlNode]]): The GUI element that triggered the action + * - `[selNode]` ([[XMLNode]]): The relevant {@link term.datanode data node} to + * which the action node works on + * - `[timestamp]` ([[Number]]): The start of the action that is now executed. + */ +/** + * @event actionfail Fires when an action fails to be sent to the server. + * @bubbles + * @param {Object} e The standard event object. It contains the following property: + * - `error` ([[Error]]): The error object that is thrown when the event + * callback doesn't return false. + * - `state` ([[Number]]): The state of the call. It can be one of the following values: + * - `apf.SUCCESS`: The request was successfull + * - `apf.TIMEOUT`: The request has timed out. + * - `apf.ERROR`: An error has occurred while making the request. + * - `apf.OFFLINE`: The request was made while the application was offline. + * - `userdata` (`Mixed`): Data that the caller wanted to be available in + * the callback of the HTTP request. + * - `http` ([[XMLHttpRequest]]): the object that executed the actual HTTP request. + * - `url` ([[String]]): The URL that was requested. + * - `tpModule` ([[apf.http]]): The teleport module that is making the request. + * - `id` ([[Number]]): The id of the request. + * - `message` ([[String]]): The error message. + * @see term.locking + */ +/** + * @event actionsuccess Fires when an action is successfully sent to the server. + * @bubbles + * @param {Object} e The standard event object. It contains the following property: + * - `state` ([[Number]]): The state of the call. It can be one of the following values: + * - `apf.SUCCESS`: The request was successfull + * - `apf.TIMEOUT`: The request has timed out. + * - `apf.ERROR`: An error has occurred while making the request. + * - `apf.OFFLINE`: The request was made while the application was offline. + * - `userdata` (`Mixed`): Data that the caller wanted to be available in + * the callback of the HTTP request. + * - `http` ([[XMLHttpRequest]]): The object that executed the actual HTTP request. + * - `url` ([[String]]): The URL that was requested. + * - `tpModule` ([[apf.http]]): The teleport module that is making the request. + * - `id` ([[Number]]): The id of the request. + * + */ +apf.actiontracker = function(struct, tagName) { + this.$init(tagName || "actiontracker", apf.NODE_HIDDEN, struct); + + this.$undostack = []; + this.$redostack = []; + this.$execstack = []; + +}; + +(function(){ + this.$lastExecStackItem = null; + this.$paused = false; + + this.realtime = true; + this.undolength = 0; + this.redolength = 0; + + + /** + * @attribute {Number} undolength Sets or gets the length of the undo stack. + * + */ + /** + * @attribute {Number} redolength Sets or gets the length of the redo stack. + */ + /** + * @attribute {Number} length Sets or gets the length of the undo/redo stack combined. + * Use this attribute to bind a slider's max + * attribute to. + */ + /** + * @attribute {Number} position Sets or gets the position within the total length (the same + * value as [[apf.actiontracker.undolength]]). Use this attribute + * to bind a slider's value attribute to. + */ + /** + * @attribute {Boolean} realtime Sets or gets whether changes are immediately sent to + * the datastore, or held back until [[apf.actiontracker.purge]] is called. + */ + this.$booleanProperties = {}; + this.$booleanProperties["realtime"] = true; + this.$supportedProperties = ["realtime", "undolength", "redolength", "alias", "length", "position"]; + this.$handlePropSet = function(prop, value, force) { + if (this.$booleanProperties[prop]) + value = apf.isTrue(value); + + //Read only properties + switch (prop) { + case "undolength": + this.undolength = this.$undostack.length; + + break; + case "redolength": + this.redolength = this.$redostack.length; + break; + + + default: + this[prop] = value; + } + }; + + /*this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + if (this.parentNode) + this.parentNode.$at = this; + });*/ + + + + /** + * Adds a new action handler which can be used by any actiontracker. + * @param {String} action Specifies the name of the action + * @param {Function} func Specifies the function that is executed when + * executing or undoing the action. + */ + this.define = function(action, func) { + apf.actiontracker.actions[action] = func; + }; + + /** + * Searches for the action tracker that functions as a parent for this one. + * @return {apf.actiontracker} Returns the parent action tracker + */ + this.getParent = function(){ + return this.parentNode && this.parentNode.getActionTracker + ? this.parentNode.getActionTracker(true) + : (apf.window.$at != this ? apf.window.$at : null); + }; + + this.getDone = function(time) { + if (typeof time != "number") + return []; + for (var o, i = this.$undostack.length; i >= 0; --i) { + if (!(o = this.$undostack[i]) || !o.timestamp) continue; + if (o.timestamp >= time) + return this.$undostack.slice(i); + } + return []; + }; + + this.getUndone = function(time) { + if (typeof time != "number") + return []; + for (var o, i = 0, l = this.$redostack.length; i < l; ++i) { + if (!(o = this.$redostack[i]) || !o.timestamp) continue; + if (o.timestamp <= time) + return this.$redostack.slice(0, i + 1); + } + return []; + }; + + /** + * Executes an action, which later can be undone and which the execution + * can be synchronized to the data store. + * @param {Object} options The details of the execution. It contains the following properties: + * Properties: + * - `action` ([[String]]): The action to be executed + * - `args` ([[Array]]): The arguments for the action + * - `[xmlActionNode]` ([[XMLNode]]): The rules to synchronize the changes to the + * server for both execution and undo. + * - `[amlNode]` ([[apf.AmlNode]]): The GUI element that triggered the action + * - `[selNode]` ([[XMLNode]]): The relevant {@link term.datanode data node} + * to which the action node works on + * - `[timestamp]` ([[Number]]): The start of the action that is now executed. + * - `[annotator]` ([[String]]): The name or identifier of the entity that is + * responsible for the action + */ + this.execute = function(options) { + if (this.dispatchEvent("beforechange", options) === false) + return false; + + //Execute action + var UndoObj = new apf.UndoData(options, this); + if (options.action && !options.transaction) + apf.actiontracker.actions[options.action](UndoObj, false, this); + + if (!this.$paused) { + //Add action to stack + UndoObj.id = this.$undostack.push(UndoObj) - 1; + } + + this.setProperty("undolength", this.$undostack.length); + + + + //Respond + if (UndoObj.multiple) + this.$addToQueue(UndoObj.multiple, false, true); + else + this.$addToQueue(UndoObj, false); + + //Reset Redo Stack + // @todo for rdb refactor we have to deal with collision handling within the at + if (!options.rdb) { + this.$redostack.length = 0; + this.setProperty("redolength", this.$redostack.length); + + + } + + this.dispatchEvent("afterchange", { + action: "do" + }) + + //return stack id of action + return UndoObj; + }; + + this.pauseTracking = function() { + this.$paused = true; + }; + + this.resumeTracking = function() { + this.$paused = false; + }; + + this.isTracking = function() { + return !this.$paused; + }; + + //deprecated?? + /*this.$addActionGroup = function(done, rpc) { + var UndoObj = new apf.UndoData("group", null, [ + //@todo apf.copyArray is deprecated and no longer exists + apf.copyArray(done, UndoData), apf.copyArray(rpc, UndoData) + ]); + this.$undostack.push(UndoObj); + this.setProperty("undolength", this.$undostack.length); + + //@todo reset redo here? + + + + this.dispatchEvent("afterchange", {action: "group", done: done}); + };*/ + + // @todo I don't really know if this stacking into the parent is still used, for instance for apf.Transaction. please think about it. + /** + * Synchronizes all held back changes to the data store. + * + */ + this.purge = function(nogrouping, forcegrouping){//@todo, maybe add noReset argument + //var parent = this.getParent(); + + //@todo Check if this still works together with transactions + if (true) {//nogrouping && parent + if (this.$execstack.length) { + this.$execstack[0].undoObj.saveChange(this.$execstack[0].undo, this); + this.$lastExecStackItem = this.$execstack[this.$execstack.length - 1]; + } + } + else if (parent) { + /* + Copy Stacked Actions as a single + grouped action to parent ActionTracker + */ + //parent.$addActionGroup(this.$undostack, stackRPC); + + //Reset Stacks + this.reset(); + } + }; + + + + /** + * Empties the action stack. After this method is run, running undo + * or redo will not do anything. + */ + this.reset = function(){ + this.$undostack.length = this.$redostack.length = 0; + this.$paused = false; + + this.setProperty("undolength", 0); + this.setProperty("redolength", 0); + + + this.dispatchEvent("afterchange", {action: "reset"}); + }; + + /** + * Revert the most recent action on the action stack. + */ + this.undo = function(id, single, rollback) { + change.call(this, id, single, true, rollback); + }; + + /** + * Re-executes the last undone action. + */ + this.redo = function(id, single, rollback) { + change.call(this, id, single, false, rollback); + }; + + function change(id, single, undo, rollback) { + var undoStack = undo ? this.$undostack : this.$redostack, //local vars switch + redoStack = undo ? this.$redostack : this.$undostack; //local vars switch + + if (!undoStack.length) return; + + if (single) { + var UndoObj = undoStack[id]; + if (!UndoObj) return; + + + undoStack.length--; + redoStack.push(UndoObj); //@todo check: moved from outside if(single) + + + + //Undo Client Side Action + if (UndoObj.action) + apf.actiontracker.actions[UndoObj.action](UndoObj, undo, this); + + if (!rollback) { + if (UndoObj.multiple) + this.$addToQueue(UndoObj.multiple, undo, true); + else + this.$addToQueue(UndoObj, undo); + } + + //Set Changed Value + this.setProperty("undolength", this.$undostack.length); + this.setProperty("redolength", this.$redostack.length); + return UndoObj; + } + + if (this.dispatchEvent("beforechange") === false) + return; + + + + //Undo the last X places - where X = id; + if (id == -1) + id = undoStack.length; + + if (!id) + id = 1; + + var i = 0; + while (i < id && undoStack.length > 0) { + if (!undoStack[undoStack.length - 1]) { + undoStack.length--; + + + + this.$undostack = []; + this.$redostack = []; + + + + return false; + } + else { + change.call(this, undoStack.length - 1, true, undo, rollback); + i++; + } + } + + this.dispatchEvent("afterchange", { + action: undo ? "undo" : "redo", + rollback: rollback + }) + } + + this.$receive = function(data, state, extra, UndoObj, callback) { + if (state == apf.TIMEOUT + && extra.tpModule.retryTimeout(extra, state, this) === true) + return true; + + if (state != apf.SUCCESS) { + //Tell anyone that wants to hear about our failure :( + if (this.dispatchEvent("actionfail", apf.extend(extra, { + state: state, + message: "Could not sent Action RPC request for control " + + this.name + + "[" + this.localName + "] \n\n" + + extra.message, + bubbles: true + })) === false) { + + + + return true; //don't delete the call from the queue + } + + /* + Undo the failed action. We're only undoing one item of the stack + if the developer has told us using the @ignore-fail attribute + that it's ok, the data will be safe if we undo only this one. + + @todo: Shouldn't the stackUndone be cleared after this... or + is it intuitive enough for the user that redo will + let the user retry the action?? + */ + if (typeof apf.offline != "undefined" && !apf.offline.reloading) + this.undo(UndoObj.id, extra.userdata, true); + + if (callback) + callback(!extra.userdata); + + if (!extra.userdata) { + /* + Clearing the execStack, none of the changes will be send to + the server. This seems the best way right now and is related + to the todo item above. + + @todo: Think about adding ignore-fail to settings and + actiontracker. + */ + this.$execstack = []; + + var oError = new Error(apf.formatErrorString(0, this, + "Executing action", + "Error sending action to the server:\n" + + (extra.url ? "Url:" + extra.url + "\n\n" : "") + + extra.message)); + + //(UndoObj && UndoObj.xmlActionNode || extra.amlNode || apf) + if (this.dispatchEvent("error", apf.extend({ + error: oError, + state: state, + bubbles: true + }, extra)) === false) + return; + + throw oError; + } + } + else { + //Tell anyone that wants to hear about our success + this.dispatchEvent("actionsuccess", apf.extend(extra, { + state: state, + bubbles: true + }, extra)); + + + //Send out the RDB message, letting friends know of our change + UndoObj.processRsbQueue(); + + + if (callback) + callback(); + } + + this.$queueNext(UndoObj, callback); + }; + + this.$addToQueue = function(UndoObj, undo, isGroup) { + /* + Remove item from the execution stack if it's not yet executed + to keep the stack clean + */ + //@todo Implement this for isGroup if deemed useful + if (!isGroup && this.$execstack.length && !UndoObj.state + && this.$execstack[this.$execstack.length - 1].undoObj == UndoObj) { + this.$execstack.length--; + + + + + UndoObj.clearRsbQueue(); + + + return; + } + + var idx, undoObj, qItem; + // Add the item to the queue + if (isGroup) { + //@todo currently no offline support for grouped actions + //@todo Why not just pop()? + var undoObj, qItem = this.$execstack.shift(); + for (var i = 0; i < UndoObj.length; i++) { + undoObj = UndoObj[i]; + this.$execstack.unshift({ + undoObj: (undoObj.tagName + ? undoObj + : new apf.UndoData(undoObj, this)).preparse(undo, this), + undo: undo + }); + } + if (qItem) + this.$execstack.unshift(qItem); + + if (!this.$execstack[0].undoObj.state) + this.$execstack[0].undoObj.saveChange(this.$execstack[0].undo, this); + + return; + } + + qItem = { + undoObj: UndoObj.preparse(undo, this), + undo: undo + + }; + this.$execstack.push(qItem) - 1; + + + + //The queue was empty, yay! we're gonna exec immediately + if (this.$execstack.length == 1 && this.realtime) + UndoObj.saveChange(undo, this); + }; + + this.$queueNext = function(UndoObj, callback) { + /* + These thow checks are so important, that they are also executed + in release mode. + */ + if (!this.$execstack[0] || this.$execstack[0].undoObj != UndoObj) { + throw new Error(apf.formatErrorString(0, this, "Executing Next \ + action in queue", "The execution stack was corrupted. This is \ + a fatal error. The application should be restarted. You will \ + lose all your changes. Please contact the administrator.")); + } + + //Reset the state of the undo item + UndoObj.state = null; + + //Remove the action item from the stack + var lastItem = this.$execstack.shift(); + + + + //Check if there is a new action to execute; + if (!this.$execstack[0] || lastItem == this.$lastExecStackItem) + return; + + // @todo you could optimize this process by using multicall, but too much for now + + //Execute action next in queue + this.$execstack[0].undoObj.saveChange(this.$execstack[0].undo, this, callback); + }; + + +}).call(apf.actiontracker.prototype = new apf.AmlElement()); + +apf.aml.setElement("actiontracker", apf.actiontracker); + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * @todo description + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.4 + */ +apf.application = function(){ + this.$init("application", apf.NODE_HIDDEN); + + if (!apf.isO3) { + this.$int = document.body; + this.$tabList = []; //Prevents documentElement from being focussed + this.$focussable = apf.KEYBOARD; + this.focussable = true; + this.visible = true; + this.$isWindowContainer = true; + this.focus = function(){ this.dispatchEvent("focus"); }; + this.blur = function(){ this.dispatchEvent("blur"); }; + + + apf.window.$addFocus(this); + + } +}; +apf.application.prototype = new apf.AmlElement(); +apf.aml.setElement("application", apf.application); + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * This element specifies the settings of the APF application. + * + * @class apf.appsettings + * @define appsettings + * @logic + * @inherits apf.AmlElement + * @allowchild auth, authentication, offline, printer, defaults + * + */ +// @todo describe defaults +/** + * @attribute {Boolean} debug Sets or gets whether the debug screen is shown at startup. + * + */ +/** + * @attribute {String} name Sets or gets the name of the application; used by many different services to uniquely identify the application. + */ +/** + * @attribute {Boolean} disable-right-click Sets or gets whether a user can get the browser's contextmenu when the right mouse button is clicked. + * @see apf.contextmenu + */ +/** + * @attribute {Boolean} allow-select Sets or gets whether general text in the application can be selected. + */ +/** + * @attribute {Boolean} allow-blur Sets or gets whether its possible to blur an element while not giving the focus to another element. Defaults to `true`. + */ +/** + * @attribute {Boolean} auto-disable-actions Sets or gets whether smartbinding actions are by default disabled. + * @see term.action + */ +/** + * @attribute {Boolean} auto-disable Sets or gets whether elements that don't have content loaded are automatically disabled. + */ +/** + * @attribute {Boolean} disable-f5 Sets or gets whether the F5 key for refreshing is disabled. + */ +/** + * @attribute {Boolean} auto-hide-loading Sets or gets whether the load screen defined by the loader element is automatically hidden. Setting this to `false` enables you to control when the loading screen is hidden. + * + * The following code shows how this can be done: + * + * ```javascript + * apf.document.getElementsByTagName("a:loader")[0].hide() + * //or + * loaderId.hide() + * ``` + */ +/** + * @attribute {Boolean} disable-space Sets or gets whether the space button default behavior of scrolling the tab is disabled. + */ +/** + * @attribute {Boolean} disable-backspace Sets or gets whether the backspace button default behavior of going to the previous history state is disabled. + */ +/** + * @attribute {String} default-tab Sets or gets the name of the default tab if none is specified using the `#`. Defaults to `"home"`. + * @see apf.history + */ +/** + * @attribute {Boolean} undokeys Sets or gets whether the undo and redo keyboard bindings are enabled. + * @see apf.actiontracker + */ +/** + * @attribute {String | Boolean} outline Sets or gets whether an outline of an element is shown while dragging or resizing. + * @see apf.Interactive + */ +/** + * @attribute {String | Boolean} drag-outline Sets or gets whether an outline of an element is shown while dragging. + * @see apf.Interactive + */ +/** + * @attribute {String | Boolean} resize-outline Sets or gets whether an outline of an element is shown while resizing. + * @see apf.Interactive + */ +/** + * @attribute {String} baseurl Sets or gets the basepath for any relative url used throughout your application. This included teleport definitions and {@link term.datainstruction data instructions}. + * + */ +/** + * @attribute {String} loading-message Sets or gets the global value for the loading message of elements during a loading state. + * @see apf.DataBinding.loading-message + */ +/** + * @attribute {String} offline-message Sets or gets the global value for the offline message of elements not able to display content while offline. + * @see apf.DataBinding.offline-message + */ +/** + * @attribute {String} empty-message Sets or gets the global value for the empty message of elements containing no contents. + * @see apf.DataBinding.empty-message + */ +/** + * @attribute {String} model Sets or gets the default model for this application. + * @see apf.model + */ +/** + * @attribute {String} realtime Sets or gets the global value whether bound values are updated realtime. When set to `false`, elements do not update until they lose focus. + * + */ +/** + * @attribute {String} skinset Sets or gets the skin set used by the application. + * @see apf.Presentation.skinset + */ +/** + * @attribute {String} storage Sets or gets the storage provider to be used for key/value storage. + * + */ +/** + * @attribute {String} offline Sets or gets the storage provider to be used for offline support. + * + */ +/** + * @attribute {String} login Sets or gets the {@link term.datainstruction data instruction} which logs a user into the application. + * + */ +/** + * @attribute {String} logout Sets or gets the {@link term.datainstruction data instruction} which logs a user out of the application. + * + */ +/** + * @attribute {String} iepngfix Sets or gets whether the fix for PNG images with transparency should be applied. Default is `false`. + */ +/** + * @attribute {String} iepngfix-elements Sets or gets a comma-seperated list of CSS identifiers (classes) to which the transparent-PNG fix will be applied. + */ +/** + * @attribute {Boolean} iphone-fullscreen Sets or gets whether the application should cover the entire screen of the iPhone. Default is ztruez. + */ +/** + * @attribute {String} iphone-statusbar Sets or gets the style of the statusbar of the iPhone webbrowser. Posssible values: `'default'`, `'black-translucent'` or `'black'`. + */ +/** + * @attribute {String} iphone-icon Sets or gets path pointing to the icon that should be used when this application is put on the iPhone Dashboard. + */ +/** + * @attribute {Boolean} iphone-icon-is-glossy Sets or gets whether the icon specified with 'iphone-icon' already is glossy or if the iPhone OS should apply that effect. Default is `false`. + */ +/** + * @attribute {Boolean} iphone-fixed-viewport Sets or gets whether the viewport of the application is fixed and whether the zoom should be enabled. Default is `true`. + */ +apf.appsettings = function(struct, tagName) { + this.$init(tagName || "appsettings", apf.NODE_HIDDEN, struct); +}; + +(function(){ + this.$parsePrio = "001"; + + //1 = force no bind rule, 2 = force bind rule + this.$attrExcludePropBind = { + language: 1, + login: 1, + logout: 1 + }; + + this.$supportedProperties = ["debug", "name", "baseurl", "resource-path", + "disable-right-click", "allow-select", "allow-blur", + "auto-disable-actions", "auto-disable", "disable-f5", + "auto-hide-loading", "disable-space", "disable-backspace", "undokeys", + "initdelay", "default-tab", "query-append", "outline", "drag-outline", + "resize-outline", "resize-outline", "iepngfix", "iepngfix-elements", + "iphone-fullscreen", "iphone-statusbar", "iphone-icon", + "iphone-icon-is-glossy", "iphone-fixed-viewport", "skinset", + "language", "storage", "offline", "login"]; + this.$booleanProperties = { + + "debug":1, + "disable-right-click":1, + "allow-select":1, + "allow-blur":1, + "auto-disable-actions":1, + "auto-disable":1, + "disable-f5":1, + "auto-hide-loading":1, + "disable-space":1, + "disable-backspace":1, + "undokeys":1, + "initdelay":1, + "outline":1, + "iepngfix":1, + "iphone-fullscreen":1, + "iphone-icon-is-glossy":1, + "iphone-fixed-viewport":1 + }; + + var $setProperty = this.setProperty; + this.setProperty = function(prop, value, forceOnMe, setAttr, inherited) { + if (inherited != 2) + $setProperty.apply(this, arguments); + } + + this.$handlePropSet = function(prop, value, force) { + if (this.$booleanProperties[prop]) + value = apf.isTrue(value); + + this[prop] = value; + + apf.config.setProperty(prop, value); + }; + + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + + }); +}).call(apf.appsettings.prototype = new apf.AmlElement()); + +apf.aml.setElement("appsettings", apf.appsettings); + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * @define auth Centralized authentication handling. Not being logged in, after being + * offline for a while can put the application + * in a complex undefined state. The auth element makes sure the state is always + * properly managed. When it gets signalled 'authentication required' it dispatches the + * appropriate events to display a login box. It can automatically retry logging + * in to one or more services using in memory stored username/password + * combinations. It will queue all requests that require authentication until + * the application is logged in again and will then empty the queue. + * Example: + * This example sets up apf.auth with two services that it can log into. + * + * + * + * + * + * + * + * + * Example: + * A login window with different states managed by apf.auth + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * Username + * + * + * Password + * + * + * + * Log in + * + * Log out + * + * + * @event beforelogin Fires before the log in request is sent to the service + * cancelable: Prevents the log in from happening + * @event beforelogout Fires before the log out request is sent to the service + * cancelable: Prevents the log out from happening + * @event logincheck Fires when log in data is received. Login is sometimes very complex, this event is dispatched to allow a custom check if a log in succeeded. + * bubbles: yes + * @param {Object} e + * {Object} data the data received from the log in request + * {Number} state the return code of the log in request + * @event loginfail Fires when a log in attempt has failed + * @event loginsuccess Fires when a log in attempt succeeded + * @event logoutcheck Fires when log out data is received. Login is sometimes very complex, this event is dispatched to allow a custom check if a log out succeeded. + * bubbles: yes + * @param {Object} e + * {Object} data the data received from the log out request + * {Number} state the return code of the log out request + * @event logoutfail Fires when a log out attempt has failed + * @event logoutsuccess Fires when a log out attempt succeeded + * @event authrequired Fires when log in credentials are required, either because they are incorrect, or because they are unavailable. + * bubbles: yes + * + * @inherits apf.Class + * + * @attribute {String} login the {@link term.datainstruction data instruction} on how to log in to a service. + * @attribute {String} logout the {@link term.datainstruction data instruction} on how to log out of a service. + * @attribute {Boolean} autostart whether to fire authrequired at startup. Defaults to true. + * @attribute {String} window the id of the window element that offers a log in form to the user. DEPRECATED. + * @attribute {String} authreq-state the id of the state element which is activated when logging in failed because the credentials where incorrect. + * @attribute {String} login-state the id of the state element which is activated when logging in succeeded. + * @attribute {String} waiting-state the id of the state element which is activated when the user is waiting while the application is logging in. + * @attribute {String} fail-state the id of the state element which is activated when logging in failed because the credentials where incorrect. + * @attribute {String} error-state the id of the state element which is activated when logging in failed because of an error (i.e. network disconnected). + * @attribute {String} logout-state the id of the state element which is activated when the user is logged out. + * @attribute {String} model the id of the model element which gets the data loaded given at login success. + * @attribute {String} remember whether to remember the login credentials after the first successful login attempt. Will only be used i.c.w. RPC + * @allowchild service + * @define service Element specifying a server to log into. + * @attribute {String} name the unique identifier of the service + * @attribute {String} login the {@link term.datainstruction data instruction} on how to log in to a service + * @attribute {String} logout the {@link term.datainstruction data instruction} on how to log out of a service + * @see apf.appsettings + * + * @default_private + */ + +apf.auth = function(struct, tagName) { + this.$init(tagName || "auth", apf.NODE_HIDDEN, struct); + + this.$services = {}; + this.$cache = {}; + this.$queue = []; + this.$credentials = null; +}; + +apf.aml.setElement("auth", apf.auth); + +(function(){ + this.autostart = true; + this.authenticated = false; + this.enablequeue = false; + + this.$retry = true; + this.loggedIn = false; + this.$needsLogin = false; + this.$hasHost = false; + + /** + * Indicates the state of the log in process. + * Possible values: + * 0 idle + * 1 logging in + * 2 logging out + */ + this.inProcess = 0; + + //1 = force no bind rule, 2 = force bind rule + this.$attrExcludePropBind = apf.extend({ + login: 1, + logout: 1 + }, this.$attrExcludePropBind); + + this.$booleanProperties["autostart"] = true; + this.$booleanProperties["remember"] = true; + + this.$supportedProperties.push("login", "logout", "fail-state", "error-state", + "login-state", "logout-state", "waiting-state", "window", "autostart", + "remember", "authenticated", "enablequeue"); + + this.$propHandlers["login"] = + this.$propHandlers["login-state"] = function(value) { + this.$services["default"] = value ? this : null; + this.$needsLogin = value ? true : false; + }; + + this.register = function(node) { + this.$services[node.name] = node; + this.$needsLogin = true; + }; + + this.unregister = function(node) { + var prop; + delete this.$services[node.name]; + if (!(prop in this.$services)) + this.$needsLogin = false; + }; + + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + this.inited = true; + + if (this.parentNode && this.parentNode.$setAuth) { + this.parentNode.$setAuth(this); + this.$hasHost = true; + } + + if (this.autostart && !this.$hasHost) { + var _self = this; + apf.addEventListener("load", function(){ + apf.addEventListener("login", function(){ + _self.authRequired(); + apf.removeEventListener("load", arguments.callee); + }); + }); + } + }); + + this.addEventListener("authrequired", function(){ + if (self[this.window]) { + this.win = self[this.window]; + if (this.win) { + this.win.show(); + return false; + } + } + + if (self[this["authreq-state"]]) { + this.state = self[this["authreq-state"]]; + if (this.state) { + this.state.activate(); + return false; + } + } + }); + + this.addEventListener("beforelogin", function(){ + if (self[this["waiting-state"]]) { + this.state = self[this["waiting-state"]]; + if (this.state) + this.state.activate(); + } + }); + + var knownHttpAuthErrors = {401:1, 403:1} + function failFunction(e) { + var st = (e.state == apf.TIMEOUT || !knownHttpAuthErrors[e.status] + ? self[this["error-state"]] + : self[this["fail-state"]]) || self[this["fail-state"]] + + if (st) { + this.state = st; + if (this.state) { + this.state.activate(); + return false; + } + } + } + + this.addEventListener("loginfail", failFunction); + this.addEventListener("logoutfail", failFunction); + + this.addEventListener("logoutsuccess", function(){ + if (self[this["logout-state"]]) { + this.state = self[this["logout-state"]]; + if (this.state) + this.state.activate(); + } + }); + + this.addEventListener("loginsuccess", function(e) { + if (self[this.window]) { + this.win = self[this.window]; + if (this.win) + this.win.hide(); + } + + if (self[this["login-state"]]) { + this.state = self[this["login-state"]]; + if (this.state) + this.state.activate(); + } + + + if (e.data && this.model) { + this.model = apf.nameserver.get("model", this.model); + if (this.model) + this.model.load(e.data); + } + + }); + + /** + * Log in to one or more services + * @param {String} username the username portion of the credentials used to log in with + * @param {String} password the password portion of the credentials used to log in with + * @param {Function} [callback] code to be called when the application succeeds or fails logging in + * @param {Object} [options] extra settings and variables for the login. These variables will be available in the {@link term.datainstruction data instruction} which is called to execute the actual log in. + * Properties: + * {Array} services a list of names of services to be logged in to + * {String} service the name of a single service to log in to + */ + this.logIn = function(username, password, callback, options) { + if (!options) options = {}; + + options.username = username; + options.password = password; + + if (this.dispatchEvent("beforelogin", options) === false) + return false; + + this.inProcess = 1; //Logging in + + var pos = 0, + len = 0, + _self = this, + doneCallback = function() { + if (len != ++pos) + return; + + _self.inProcess = 0; //Idle + _self.loggedIn = true; + _self.clearQueue(); + + if (callback) + callback(); + }; + + if (this.$hasHost) { // child of Teleport element + this.$credentials = options; + callback = this.$hostCallback; + this.$hostCallback = null; + len = 1; + doneCallback(); + this.dispatchEvent("loginsuccess", { + state: 1, + data: null, + bubbles: true, + username: username, + password: password + }); + if (!this.remember) + this.$credentials = null; + } + else { + if (!options.service) { + var s = options.$services || this.$services; + for (var name in s) { + len++; + this.$do(name, options, "in", null, doneCallback); + } + } + else if (options.service) { + len = 1; + this.$do(options.service, options, "in", null, doneCallback); + } + } + }; + + this.relogin = function(){ + if (this.dispatchEvent("beforerelogin") === false) + return false; + + + + //@todo shouldn't I be using inProces here? + var name, pos = 0, len = 0, _self = this, + doneCallback = function(){ + if (len != ++pos) + return; + + _self.inProcess = 0; //Idle + _self.loggedIn = true; + _self.clearQueue(); + }; + + for (name in this.$services) { + if (!this.$cache[name]) + return false; + len++; + this.$do(name, this.$cache[name], "in", true, doneCallback); + } + + return true; + }; + + this.$do = function(service, options, type, isRelogin, callback) { + var xmlNode = this.$services[service], + _self = options.userdata = this; + + + + + + //Execute login call + options.callback = function(data, state, extra) { + if (state == apf.TIMEOUT && extra.retries < apf.maxHttpRetries) + return extra.tpModule.retry(extra.id); + + /* + Login is sometimes very complex, so this check is + here to test the data for login information + */ + var result = _self.dispatchEvent("log" + type + "check", + apf.extend({ + state: state, + data: data, + service: service, + bubbles: true + }, extra)), + + loginFailed = typeof result == "boolean" + ? !result + : !(state == apf.SUCCESS || type == "out" && extra.status == 401); + + if (loginFailed) { + _self.inProcess = 0; //Idle + + if (isRelogin) //If we're retrying then we'll step out here + return _self.authRequired(); + + + + var commError = new Error(apf.formatErrorString(0, null, + "Logging " + type, "Error logging in: " + extra.message)); + + if (_self.dispatchEvent("log" + type + "fail", apf.extend({ + error: commError, + service: service, + state: state, + data: data, + bubbles: true, + username: options.username, + password: options.password + }, extra)) !== false) + throw commError; //@todo ouch, too harsh? + + //@todo Call auth required again?? + + _self.setProperty("authenticated", false); + + return; + } + + if (type == "in") { + //If we use retry, cache the login information + if (!isRelogin && _self.$retry) { + var cacheItem = {}; + for (var prop in options) { + if ("object|array".indexOf(typeof options[prop]) == -1) + cacheItem[prop] = options[prop]; + } + _self.$cache[service || "default"] = cacheItem; + } + } + else { + //Remove cached credentials + if (_self.$cache[service || "default"]) + _self.$cache[service || "default"] = null; + + //_self.authRequired(); + } + + if (callback) + callback(); + + _self.dispatchEvent("log" + type + "success", apf.extend({}, extra, { + state: state, + service: service, + data: data, + bubbles: true, + username: options.username, + password: options.password + })); + + + + _self.setProperty("authenticated", true); + }; + apf.saveData(xmlNode.getAttribute("log" + type), options); + }; + + this.clearQueue = function(){ + if (!this.loggedIn) //Queue should only be cleared when we're logged in + return; + + var queue = this.$queue.slice(); + this.$queue.length = 0; + + for (var i = 0; i < queue.length; i++) { + var qItem = queue[i]; + + //We might be logged out somewhere in this process (think sync) + if (!this.loggedIn) { + this.$queue.push(qItem); + continue; + } + + //Specialty retry (protocol specific) + if (qItem.retry) + qItem.$retry.call(qItem.object); + + //Standard TelePort Module retry + else if (qItem.id) + qItem.tpModule.retry(qItem.id); + + + } + + //The queue might be filled somehow + if (this.$queue.length) + this.clearQueue(); + }; + + /** + * Log out of one or more services + * @param {Function} [callback] code to be called when the application succeeds or fails logging out + * @param {Object} [options] extra settings and variables for the login. These variables will be available out the {@link term.datainstruction data instruction} which is called to execute the actual log out. + * Properties: + * {Array} services a list of names of services to be logged out of + * {String} service the name of a single service to log out of + */ + this.logOut = function(callback, options) { + if (!options) options = {}; + + if (this.dispatchEvent("beforelogout", options) === false) + return; + + this.loggedIn = false; + + if (!options.service) { + for (var name in this.$services) + this.$do(name, options, "out", null, callback); + } + else if (options.service) + this.$do(options.service, options, "out", null, callback); + + }; + + this.getCredentials = function(service) { + var cache = this.$cache[service || "default"]; + return !cache ? ["", ""] : [cache.username, cache.password]; + }; + + /** + * Signals services that a log in is required and fires authrequired event + * @param {Object} [options] information on how to reconstruct a failed action, that detected a log in was required. (i.e. When an HTTP call fails with a 401 Auth Required the options object contains information on how to retry the http request) + * @param {Object} [forceNoRetry] don't try to log in with stored credentials. + */ + this.authRequired = function(options, forceNoRetry) { + // If we're already logging in return + if (options && options.userdata == this) + return; + + // If we're supposed to be logged in we'll try to log in automatically + if (this.loggedIn && !forceNoRetry && this.$retry && this.relogin()) { + var result = false; + } + else if (this.inProcess != 1) { //If we're not already logging in + if (this.$hasHost && typeof options == "function") { //inside Teleport element + if (this.$credentials) + return options(); + this.$hostCallback = options; + } + /* + Apparently our credentials aren't valid anymore, + or retry is turned off. If this event returns false + the developer will call apf.auth.login() at a later date. + */ + var result = this.dispatchEvent("authrequired", apf.extend({ + bubbles: true, + data: options && options.data + }, options)); + } + + this.loggedIn = false; + + if (result === false) { + if (this.enablequeue && options) //Add communication to queue for later processing + this.$queue.push(options); + + return true; //cancels error state in protocol + } + }; + +}).call(apf.auth.prototype = new apf.AmlElement()); + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * This element displays a skinnable rectangle which can contain other + * AML elements. Often, it's also used in place of a regular HTML `
      `. + * + * + * #### Example + * + * ```xml, demo + * + * + * + * + * + * + * + * + * + * + * + * ``` + * + * #### Remarks + * + * This component is used in the accordion element to create its sections. In + * the `apf.statusbar`, the panel element is an alias of [[apf.bar]]. + * + * @class apf.bar + * @inherits apf.Presentation + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.4 + * + * @define bar + * @container + * @allowchild button + * @allowchild {elements}, {anyaml} + * + */ +/** + * @attribute {String} icon Sets or gets the URL pointing to the icon image. + */ +/** + * @attribute {Boolean} [collapsed=false] Sets or gets the collapse panel on load + * + */ +/** + * @attribute {String} title Sets or gets the title string + */ +apf.section = function(struct, tagName) { + this.$init(tagName || "section", apf.NODE_VISIBLE, struct); +}; + +apf.menubar = function(struct, tagName) { + this.$init(tagName || "menubar", apf.NODE_VISIBLE, struct); +}; + +apf.bar = function(struct, tagName) { + this.$init(tagName || "bar", apf.NODE_VISIBLE, struct); +}; + +(function(){ + this.$focussable = false; + this.$canLeechSkin = true; + this.$isLeechingSkin = false; + + this.$propHandlers["caption"] = function(value) { + this.$int.innerHTML = value; + } + + //@todo apf3.0 refactor + this.addEventListener("AMLReparent", + function(beforeNode, pNode, withinParent) { + if (!this.$amlLoaded) + return; + + if (this.$isLeechingSkin && !withinParent + && this.skinName != pNode.skinName + || !this.$isLeechingSkin + && this.parentNode.$hasLayoutNode + && this.parentNode.$hasLayoutNode(this.localName)) { + this.$isLeechingSkin = true; + this.$forceSkinChange(this.parentNode.skinName.split(":")[0] + ":" + skinName); + } + }); + + this.$draw = function(){ + //Build Main Skin + this.$ext = this.$getExternal(this.$isLeechingSkin + ? this.localName + : "main"); + + //Draggable area support, mostly for a:toolbar + if (this.oDrag) //Remove if already exist (skin change) + this.oDrag.parentNode.removeChild(this.oDrag); + + this.oDrag = this.$getLayoutNode(this.$isLeechingSkin + ? this.localName + : "main", "dragger", this.$ext); + + this.$int = this.$getLayoutNode(this.$isLeechingSkin + ? this.localName + : "main", "container", this.$ext); + }; + + this.$loadAml = function(x) { + + }; + + + this.$skinchange = function(){ + + } + +}).call(apf.bar.prototype = new apf.Presentation()); + +apf.menubar.prototype = +apf.section.prototype = apf.bar.prototype; + +apf.aml.setElement("bar", apf.bar); +apf.aml.setElement("menubar", apf.menubar); +apf.aml.setElement("section", apf.section); + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/* + * @todo docs + */ +apf.BindingColorRule = function(struct, tagName) { + this.$init(tagName, apf.NODE_HIDDEN, struct); +}; + +(function(){ + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + //@todo This should support multiple color rules, by inserting the rules at the right place. + if (this.$bindings && this.$bindings.color) { + var clr = this.$bindings.color[0]; + apf.setStyleRule("." + this.$baseCSSname + (apf.isIE + ? " .records .highlight SPAN" + : " .records .highlight span"), "color", clr.getAttribute("text"), null, this.oWin); + apf.setStyleRule("." + this.$baseCSSname + (apf.isIE + ? " .records .highlight SPAN" + : " .records .highlight span"), "backgroundColor", clr.getAttribute("row"), null, this.oWin); + apf.setStyleRule("." + this.$baseCSSname + (apf.isIE + ? " .records .highlight" + : " .records .highlight"), "backgroundColor", clr.getAttribute("row"), null, this.oWin); + /*apf.importCssString("." + this.$baseCSSname + " .records div.highlight{background-color:" + + clr.getAttribute("row") + ";} ." + + this.$baseCSSname + " .records div.highlight span{color:" + + clr.getAttribute("text") + ";}");*/ + } + + //"." + this.$baseCSSname + " .headings + apf.importStylesheet([ + ["." + this.className, + "width:" + this.$width + (this.$isPercentage ? "%;" : "px;") + + "text-align:" + h.align], + ["." + this.className, + "width:" + this.$width + (this.$isPercentage ? "%;" : "px;") + + "text-align:" + h.align] + ]); + + this.$draw(); + }); +}).call(apf.BindingColorRule.prototype = new apf.BindingRule()); + +apf.aml.setElement("color", apf.BindingColorRule); + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * @attribute {String} icon + * @attribute {String} caption + * @attribute {String} width + * @attribute {String} options + * @attribute {String} editor + * @attribute {String} colspan + * @attribute {String} align + * @attribute {String} css + * @attribute {Boolean} tree + */ +apf.BindingColumnRule = function(struct, tagName) { + this.$init(tagName || "column", apf.NODE_VISIBLE, struct); + + this.$className = "col" + this.$uniqueId; +}; + +(function(){ + this.$defaultwidth = "100"; + this.$width = 0; + + this.$sortable = true; //@todo set defaults based on localName of element to which its applied + this.$resizable = true; + this.$movable = true; + this.$cssInit = false; + + this.visible = true; + + //1 = force no bind rule, 2 = force bind rule + this.$attrExcludePropBind = apf.extend({ + css: 1, + icon: 1, + caption: 1, + eachcaption: 1, + eachvalue: 1, + each: 1, + icon: 1 + }, this.$attrExcludePropBind); + + this.$supportedProperties.push("tree", "icon", "caption", "width", "options", + "check", "Editor", "colspan", "align", "css", "sorted", "each", + "eachvalue", "eachcaption", "model"); + + this.$booleanProperties["tree"] = true; + this.$booleanProperties["check"] = true; + this.$booleanProperties["sorted"] = true; + this.$booleanProperties["visible"] = true; + + this.$setParentFixedWidth = function(){ + var pNode = this.parentNode; + var vLeft = (pNode.$fixed) + "px"; + if (!this.$isFixedGrid) { + //apf.setStyleRule("." + this.$baseCSSname + " .headings ." + hFirst.$className, "marginLeft", "-" + vLeft); //Set + //apf.setStyleRule("." + this.$baseCSSname + " .records ." + hFirst.$className, "marginLeft", "-" + vLeft); //Set + apf.setStyleRule("." + pNode.$baseCSSname + " .row" + pNode.$uniqueId, + "paddingRight", vLeft, null, this.oWin); //Set +// apf.setStyleRule("." + pNode.$baseCSSname + " .row" + pNode.$uniqueId, +// "marginRight", "-" + vLeft, null, pNode.oWin); //Set + + //headings and records have same padding-right + if (pNode.$container) + pNode.$container.style.paddingRight = vLeft; + if (pNode.$head) + pNode.$head.style.paddingRight = vLeft; + } + } + + this.$propHandlers["width"] = function(value, prop) { + if (!value) + return; + + var diff = value - this.$width; + + this.$isPercentage = value && String(value).indexOf("%") > -1; + this.$width = parseFloat(value); + + var pNode = this.parentNode; + + if (this.$isPercentage) { + apf.setStyleRule("." + this.$className, "width", this.$width + "%"); + + //if (apf.z && !this.resizing) + //this.resize(this.$width, pNode, true); + } + else { + apf.setStyleRule("." + this.$className, "width", this.$width + "px", null, pNode.oWin); //Set + + if (pNode.$amlLoaded) { + if (this.visible) + pNode.$fixed += diff; + + this.$setParentFixedWidth(); + } + } + } + + this.$propHandlers["options"] = function(value, prop) { + this.$sortable = value.indexOf("sort") > -1; + this.$resizable = value.indexOf("size") > -1; + this.$movable = value.indexOf("move") > -1; + } + + this.$propHandlers["visible"] = function(value, prop, el, force) { + var pNode = this.parentNode; + + if (!force && !this.$amlLoaded) + return; + + if (value) { + apf.setStyleRule("." + this.$className, + "display", "inline-block", null, this.oWin); + + var size = this.$isPercentage + ? (this.$ext.offsetWidth - (pNode.$widthdiff - 3)) + : this.$width; + + this.resize(size, pNode, true); + } + else { + apf.setStyleRule("." + this.$className, + "display", "none", null, this.oWin); + + this.resize(0, pNode, true); + } + } + + this.resize = function(newsize, pNode, toggleShowHide) { + var hN; + + if (this.$isPercentage) { + var oldsize = (this.visible && this.$ext.offsetWidth + ? this.$ext.offsetWidth - (pNode.$widthdiff - 3) + : 0), + ratio = oldsize ? newsize / oldsize : 1, //div 0 ?? + next = [], + fixed = [], + total = 0, + node = toggleShowHide + ? this.$ext.parentNode.firstChild + : this.$ext.nextSibling; + + while (node && node.getAttribute("hid")) { + hN = apf.all[node.getAttribute("hid")]; + if (hN.visible !== false) { + if (hN.$isPercentage) { + next.push(hN); + total += hN.$width; + } + else fixed.push(hN); + } + node = node.nextSibling; + } + + if (fixed.length && !next.length) + return fixed[0].resize(fixed[0].$width + (oldsize - newsize), pNode); + + var diffPerc, diffRatio; + if (ratio == 1 && total < 101) { + ratio = total/101; + diffRatio = 1/ratio; + } + else if (total > 101) { + ratio = ratio * 101/total + diffRatio = ratio; + } + else { + diffPerc = (ratio - 1) * this.$width; + diffRatio = (total - diffPerc) / total; + if (diffRatio < 0.01 && diffRatio > 0) { + if (newsize < 20) return; + return this.resize(newsize - 10, pNode);//pNode.resizeColumn(nr, newsize - 10); + } + } + + for (var n, i = 0; i < next.length; i++) { + n = next[i]; + if (n == this) + continue; + + n.setProperty("width", String(n.$width * diffRatio) + "%", false, true); + } + + if (this.visible !== false) { + this.setProperty("width", String(ratio * this.$width) + "%", false, true); + } + } + else if (toggleShowHide) { + var diff = newsize; + pNode.$fixed += diff; + this.$setParentFixedWidth(); + } + else { + if (apf.isIE && pNode.oIframe) + this.$ext.style.width = newsize + "px"; + + this.setProperty("width", newsize, false, true); + } + }; + + this.hide = function(){ + this.setProperty("visible", false, false, true); + return this; + }; + + this.show = function(){ + this.setProperty("visible", true, false, true); + return this; + }; + + /** + * Sorts a column. + * @param {Number} hid the heading number; this number is based on the sequence of the column elements. + */ + this.sort = function(pNode, initial) { + if (pNode.$lastSorted == this) { + apf.setStyleClass(this.$int, + pNode.toggleSortOrder() + ? "ascending" + : "descending", ["descending", "ascending"]); + return; + } + + var h; + if (h = pNode.$lastSorted) { + apf.setStyleRule("." + h.$className, "background", "white"); //This breaks row coloring + apf.setStyleClass(h.$int, "", ["descending", "ascending"]); + } + + apf.setStyleRule("." + this.$className, "background", "#f3f3f3"); + apf.setStyleClass(this.$int, "ascending", ["descending", "ascending"]); + + pNode.resort({ + order: "ascending", + xpath: (this.cvalue || this.compile("value")).xpaths[1], + type: this["data-type"] + }, false, initial || !pNode.length); + + + //@todo needs more thought + /*if (pNode.$lastSorted) + pNode.$lastSorted.setProperty("sorted", false); + this.setProperty("sorted", true);*/ + + pNode.$lastSorted = this; + }; + + /** + * Moves a column to another position. + * @param {Number} fromHid the heading number of the column to move; this number is based on the sequence of the column elements. + * @param {Number} toHid the position the column is moved to; + */ + this.move = function(hTo, pNode) { + if (hTo && this == hTo) + return; + + var hFrom = this, + childNrFrom = apf.getChildNumber(hFrom.$int), + childNrTo = hTo && apf.getChildNumber(hTo.$int); + + pNode.$head.insertBefore(hFrom.$int, hTo && hTo.$int || null); + + if (!pNode.length) + return; + + (function _recur(nodes) { + for (var node, i = 0; i < nodes.length; i++) { + if (nodes[i].nodeType != 1) + continue; + //if (pNode.$withContainer && ((i+1) % 2) == 0) + //continue; + + node = nodes[i]; + if (pNode.$isTreeArch && node.tagName == "BLOCKQUOTE") { //@todo small hack + _recur(node.childNodes); + } + else { + node.insertBefore(node.childNodes[childNrFrom], + childNrTo != undefined && node.childNodes[childNrTo] || null); + } + } + })(pNode.$container.childNodes); + + /*if (this.$first == from || this.$first == to) { + var hReset = this.$first == from ? hFrom : hTo; + + apf.setStyleRule("." + this.$baseCSSname + " .headings ." + + hReset.className, "marginLeft", "-5px"); //Reset + apf.setStyleRule("." + this.$baseCSSname + " .records ." + + hReset.className, "marginLeft", "-5px"); //Reset + + this.$first = pNode.$head.firstChild.getAttribute("hid"); + var h = headings[this.$first]; + var vLeft = "-" + (this.$fixed + 5) + "px"; + + apf.setStyleRule("." + this.$baseCSSname + " .headings ." + + h.className, "marginLeft", vLeft); //Set + apf.setStyleRule("." + this.$baseCSSname + " .records ." + + h.className, "marginLeft", vLeft); //Set + }*/ + } + + this.$draw = function(pNode, caption, width, className) { + //Find the parent this rule works on + var pNode = pNode || this.parentNode; + while (pNode.$bindingRule) + pNode = pNode.parentNode; + + if (!pNode.hasFeature(apf.__PRESENTATION__)) + return; + + if (width) + this.$propHandlers["width"].call(this, width); + + //"." + this.$baseCSSname + " .headings + //if initial + //only needs once if this works + + apf.importStylesheet([ + ["." + this.$className, + "width:" + this.$width + (this.$isPercentage ? "%;" : "px;") + + "text-align:" + this.align + ";display: inline-block"], + ]); + + //Add to htmlRoot + pNode.$getNewContext("headitem"); + var $head = pNode.$getLayoutNode("headitem"); + $head.setAttribute("class", this.$className + (className ? " " + className : "")); + $head.setAttribute("hid", this.$uniqueId); + + var hCaption = pNode.$getLayoutNode("headitem", "caption"); + /*if (this.icon) { + this.$sortable = false; + $head.setAttribute("style", "background-image:url(" + + apf.getAbsolutePath(pNode.iconPath, this.icon) + + ")"); + hCaption.nodeValue = " "; + } + else*/ + hCaption.nodeValue = this.caption || caption || ' '; + + this.$ext = this.$int = apf.insertHtmlNode($head, pNode.$head || pNode.$container); + + var dragging = false; + var _self = this; + + if (this.sorted) + this.sort(pNode, true); + + /*this.$int.onmouseover = function(e) { + if (!e) e = event; + + if (pNode.disabled) return; + + clearTimeout(this.$timer); + + apf.setStyleClass(this, "hover", ["down"]); + };*/ + + this.$int.onmouseup = function(e) { + if (!e) e = event; + + if (pNode.disabled || !apf.isChildOf(dragging, this, true)) + return; + + apf.setStyleClass(this, "hover", ["down"]); + + if (_self.$sortable) + _self.sort(pNode); + + //@todo pNode or Self? + pNode.dispatchEvent("sortcolumn", _self); + }; + + this.$int.onmousedown = function(e) { + if (!e) e = event; + dragging = target = this; + + if (pNode.disabled) return; + + //Resizing + var pos = apf.getAbsolutePosition(target), + sLeft = pNode.$head.scrollLeft; + var d = e.clientX - pos[0] + sLeft; + if (d < 4 || target.offsetWidth - d - 8 < 3 + && apf.getChildNumber(_self.$int) < pNode.$headings.length - 1) { + var t = d < 4 && target.previousSibling || target; + + if (_self.$resizable) { + pos = apf.getAbsolutePosition(t); + apf.setStyleClass(pNode.$pointer, "size_pointer", ["move_pointer"]); + pNode.$pointer.style.display = "block"; + pNode.$pointer.style.left = (t.offsetLeft - sLeft - 1) + "px"; + pNode.$pointer.style.width = (t.offsetWidth - pNode.$widthdiff + 1) + "px"; + + + apf.plane.show(pNode.$pointer, null, true); + + + dragging = true; + document.onmouseup = function(){ + if (!e) e = event; + + document.onmouseup = + document.onmousemove = null; + + apf.all[t.getAttribute("hid")].resize(pNode.$pointer.offsetWidth, pNode); + + dragging = false; + pNode.$pointer.style.display = "none"; + + + apf.plane.hide(); + + + }; + + document.onmousemove = function(e) { + if (!e) e = event; + + pNode.$pointer.style.width = Math.max(10, + Math.min(pNode.$container.offsetWidth - pNode.$pointer.offsetLeft - 20, + e.clientX - pos[0] - 1 + sLeft)) + "px"; + }; + + return; + } + } + + apf.setStyleClass(target, "down", ["hover"]); + + //Moving + if (!_self.$movable) { + document.onmouseup = function(e) { + document.onmouseup = null; + dragging = false; + }; + + return; + } + + apf.setStyleClass(pNode.$pointer, "move_pointer", ["size_pointer"]); + + var x = e.clientX - target.offsetLeft, sX = e.clientX, + y = e.clientY - target.offsetTop, sY = e.clientY, + copy; + + document.onmouseup = function(e) { + if (!e) e = event; + + document.onmouseup = + document.onmousemove = null; + + dragging = false; + pNode.$pointer.style.display = "none"; + + if (!copy) + return; + + copy.style.top = "-100px"; + + var el = document.elementFromPoint(e.clientX, e.clientY); + if (el.parentNode == copy.parentNode) { + var pos = apf.getAbsolutePosition(el); + var beforeNode = (e.clientX - pos[0] > el.offsetWidth / 2 + ? el.nextSibling + : el); + + _self.move(beforeNode ? apf.all[beforeNode.getAttribute("hid")] : null, pNode); + } + + apf.destroyHtmlNode(copy); + }; + + document.onmousemove = function(e) { + if (!e) e = event; + + if (!copy) { + if (Math.abs(e.clientX - sX) < 3 && Math.abs(e.clientY - sY) < 3) + return; + + copy = target.cloneNode(true); + copy.style.position = "absolute"; + var diff = apf.getWidthDiff(target); + copy.style.width = (target.offsetWidth - diff + - pNode.$widthdiff + 2) + "px"; + copy.style.left = target.offsetLeft; + copy.style.top = target.offsetTop; + copy.style.margin = 0; + copy.removeAttribute("hid") + + apf.setStyleClass(copy, "drag", ["ascending", "descending"]); + target.parentNode.appendChild(copy); + } + + copy.style.top = "-100px"; + pNode.$pointer.style.display = "none"; + + var el = document.elementFromPoint(e.clientX, e.clientY); + if (el.parentNode == copy.parentNode) { + var pos = apf.getAbsolutePosition(el); + pNode.$pointer.style.left = (el.offsetLeft + + ((e.clientX - pos[0] > el.offsetWidth / 2) + ? el.offsetWidth - 8 + : 0)) + "px"; + pNode.$pointer.style.display = "block"; + } + + copy.style.left = (e.clientX - x) + 'px'; + copy.style.top = (e.clientY - y) + 'px'; + }; + }; + + this.$int.onmouseout = function(e) { + if (!e) e = event; + + if (pNode.disabled) + return; + + var _self = this; + this.$timer = setTimeout(function(){ + pNode.$ext.style.cursor = ""; + apf.setStyleClass(_self, "", ["hover", "down"]); + }, 10); + }; + + this.$int.onmousemove = function(e) { + if (dragging || pNode.disabled) + return; + + if (!e) e = event; + + var pos = apf.getAbsolutePosition(this), + sLeft = pNode.$head.scrollLeft; + var d = e.clientX - pos[0] + sLeft; + + if (d < 4 || this.offsetWidth - d - pNode.$widthdiff < 3 + && apf.getChildNumber(_self.$int) < pNode.$headings.length - 1) { + var t = d < 4 ? this.previousSibling : this; + pNode.$ext.style.cursor = t && _self.$resizable + ? (apf.isWebkit ? "ew-resize" : "w-resize") + : "default"; + + apf.setStyleClass(this, "", ["hover", "down"]); + } + else { + pNode.$ext.style.cursor = "default"; + apf.setStyleClass(this, "hover", ["down"]); + } + }; + + if (!this.options && pNode.options) + this.$propHandlers["options"].call(this, + this.options = pNode.options); + + if (this.visible === false) + this.$propHandlers["visible"].call(this, false, null, null, true); + + return this; + } + + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + this.$draw(); + }); + + this.addEventListener("DOMNodeRemovedFromDocument", function(e) { + if (!this.$int) + return; + + this.$int.onmouseover = + this.$int.onmouseup = + this.$int.onmousedown = + this.$int.onmousemove = + this.$int.onmouseout = null; + }); + +}).call(apf.BindingColumnRule.prototype = new apf.BindingRule()); + +apf.aml.setElement("column", apf.BindingColumnRule); + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * @attribute {String} target + * @attribute {String} action + * @attribute {Boolean} copy + */ +apf.BindingDndRule = function(struct, tagName) { + this.$init(tagName, apf.NODE_HIDDEN, struct); +}; + +(function(){ + this.compile = function(prop) { + if (!this[prop]) + return; + + var compileData; + if (prop == "value") + compileData = apf.lm.compile(this[prop], { + xpathmode: 3 + }); + else if (prop == "match") + compileData = apf.lm.compile(this[prop], { + xpathmode: 3, + injectself: true + }); + else if (prop == "target") + compileData = apf.lm.compile(this[prop], { + xpathmode: 2, + injectself: true + }); + else if (prop == "action") + compileData = apf.lm.compile(this[prop], { + nostring: true + }); + else if (prop == "copy") + compileData = apf.lm.compile(this[prop], { + withopt: true, + nostring: true + }); + else + throw new Error("Missing property handler for compile"); + + return (this["c" + prop] = compileData); + } + + //1 = force no bind rule, 2 = force bind rule + this.$attrExcludePropBind = apf.extend({ + target: 1, + parent: 1, + action: 1, + copy: 1 + }, this.$attrExcludePropBind); + + this.$propHandlers["target"] = + this.$propHandlers["parent"] = + this.$propHandlers["action"] = + this.$propHandlers["copy"] = function(value, prop) { + delete this["c" + prop]; + } + + this.$noderegister = function(e) { + apf.GuiElement.propHandlers["drop"].call(e.amlNode, true); + } + + //@todo removal + + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + //Find parent that this rule works on + var pNode = this; + while (pNode && pNode.$bindingRule) + pNode = pNode.parentNode; + + if (!pNode) + return; + + if (pNode.localName == "bindings") { + pNode.addEventListener("noderegister", this.$noderegister); + + var nodes = pNode.$amlNodes; + for (var i = 0; i < nodes.length; i++) + apf.GuiElement.propHandlers["drop"].call(nodes[i], true); + } + else { + apf.GuiElement.propHandlers["drop"].call(pNode, true); + } + }); +}).call(apf.BindingDndRule.prototype = new apf.BindingRule()); + +apf.aml.setElement("drag", apf.BindingDndRule); +apf.aml.setElement("drop", apf.BindingDndRule); + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * @binding each Determines the list of elements for which each + * gets a visual representation within the element. It also can determine + * the sequence of how the elements are visualized by offering a way to + * specify the sort order. The sorting mechanism is very similar to + * that of XSLT. + * + * #### Example + * + * This example contains a list that displays elements with the tagName + * `'mail'` that do not have a deleted attribute set to 1. + * + * ```xml + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * ``` + * + * #### Example + * + * This example shows how to use the each rule to order files based + * on their modified data. + * + * ```xml + * + * + * + * + * + * + * + * + * + * + * + * ``` + * + * #### Example + * + * This example shows how to do complex sorting using a JavaScript callback function. + * + * ```xml + * + * + * + * + * + * + * + * + * + * + * + * function sth_compare(value, args, xmlNode) { + * + * } + * + * + * + * + * + * ``` + * + */ +/** + * @attribute {String} match Sets or gets an XPath statement which selects the nodes + * which will be rendered. + */ +/** + * @attribute {String} sort Sets or gets an XPath statement which selects the value + * which is subject to the sorting algorithm. + */ +/** + * @attribute {String} data-type Sets or gets the way sorting is executed. + * The possible values include: + * + * - `string`: Sorts alphabetically + * - `number`: Sorts based on numerical value (_i.e._, 9 is lower than 10). + * - `date`: Sorts based on the date sequence (`21-6-1980` is lower than `1-1-2000`). + */ +/** + * @attribute {String} date-format Sets or gets the format of the date on which is sorted. + * + * The possible values include: + * + * - `YYYY`: Full year + * - `YY`: Short year + * - `DD`: Day of month + * - `MM`: Month + * - `hh`: Hours + * - `mm`: Minutes + * - `ss`: Seconds + * + * + * #### Example + * + * ``` + * date-format="DD-MM-YYYY" + * ``` + */ +/** + * @attribute {String} sort-method Sets or gets the name of a JavaScript function to execute + * to determine the value to sort on. + */ +/** + * @attribute {String} order Sets or gets the order of the sorted list. + * + * The possible values include: + * + * - `ascending`: Default sorting order + * - `descending`: Reverses the default sorting order + */ +/** + * @attribute {String} case-order Sets or gets whether upper case characters have preference + * above lower case characters. + * + * The possible values include: + * + * - `upper-first`: Upper case characters are higher. + * - `lower-first`: Lower case characters are higher. + */ +apf.BindingEachRule = function(struct, tagName) { + this.$init(tagName, apf.NODE_HIDDEN, struct); + + var _self = this; + this.$noderegister = function(e) { + e.amlNode.$handleBindingRule(_self.match, "each"); + + + e.amlNode.$sort = _self.sort ? new apf.Sort(_self) : null; + + } +}; + +(function(){ + //1 = force no bind rule, 2 = force bind rule + this.$attrExcludePropBind = apf.extend({ + "sort" : 1, + "data-type" : 1, + "date-format" : 1, + "sort-method" : 1, + "order" : 1, + "case-order" : 1 + }, this.$attrExcludePropBind); + + this.$booleanProperties["animate"] = true; + + this.$propHandlers["sort"] = + this.$propHandlers["data-type"] = + this.$propHandlers["date-format"] = + this.$propHandlers["order"] = + this.$propHandlers["case-order"] = function(value, prop) { + delete this["c" + prop]; + + //@todo apf3.0 change sort + } + + this.$updateEach = function(value) { + var pNode = this.parentNode;//@todo apf3.0 get a list via $bindings + if (pNode.localName == "bindings") { + var nodes = pNode.$amlNodes, + i = 0, + l = nodes.length; + for (; i < l; ++i) + if (nodes[i].each != value) + nodes[i].$handleBindingRule(value, "each"); + } + else + if (pNode.each != value) + pNode.$handleBindingRule(value, "each"); + } + + this.$getFilteredMatch = function(value) { + if (!value) + return this.match; + + var keywords = value.trim().toLowerCase().split(" "); + + var each = this.match.charAt(0) == "[" && this.match.charAt(this.match.length - 1) == "]" + ? this.match.replace(/^\[|\]$/g, "") + : this.match; + + var model; + if (each.indexOf("::") > -1) { + var parsed = each.split("::"); //@todo could be optimized + if (!apf.xPathAxis[parsed[0]]) { + model = parsed[0]; + each = parsed[1]; + } + } + + // show search results + var search = [], word, words, fields = this.$fields || ["text()"]; + for (var i = 0, l = keywords.length; i < l; i++) { + words = [], word = keywords[i]; + for (var j = 0, jl = fields.length; j < jl; j++) { + words.push("contains(translate(" + fields[j] + ", 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), '" + word + "')"); + } + search.push(words.join(" or ")); + } + + var filter = "(" + search.join(") and (") + ")"; + var groups = this["filter-groups"] ? this["filter-groups"].split("|") : []; + + each = each.split("|"); + var newEach = []; + for (i = 0, l = each.length; i < l; i++) { + if (!groups.contains(each[i])) + newEach.push(each[i] + "[" + filter + "]"); + } + + var subEach = newEach.join("|"); + + for (i = 0; i < groups.length; i++) { + newEach.push(groups[i] + "[" + subEach + "]"); + } + + return newEach.join("|"); + } + + /* + * + */ + + this.$propHandlers["filter"] = function(value, prop) { + if (!this.$amlLoaded) + return; + + this.$updateEach(this.$getFilteredMatch(value)); + } + this.$propHandlers["filter-fields"] = function(value, prop) { + this.$fields = value.splitSafe(","); + } + + this.addEventListener("prop.match", function(e) { + if (!this.$amlLoaded) + return; + + if (this.filter) + this.$propHandlers["filter"].call(this, this.filter); + else + this.$updateEach(this.match); + }); + + //@todo apf3.0 optimize + var f; + this.addEventListener("DOMNodeInserted", f = function(e) { + if (e.currentTarget != this) + return; + + var match = this.$getFilteredMatch(this.filter); + var pNode = this.parentNode;//@todo apf3.0 get a list via $bindings + if (pNode.localName == "bindings") { + pNode.addEventListener("noderegister", this.$noderegister); + + var nodes = pNode.$amlNodes, + i = 0, + l = nodes.length; + for (; i < l; ++i) { + nodes[i].$handleBindingRule(match, "each"); + + + nodes[i].$sort = this.sort ? new apf.Sort(this) : null; + + } + } + else { + pNode.$handleBindingRule(match, "each"); + + + pNode.$sort = this.sort ? new apf.Sort(this) : null; + + } + }); + + this.addEventListener("DOMNodeRemoved", function(e) { + if (e.currentTarget != this) + return; + + //@todo apf3.0 how does this conflict with setting it through an attribute. + //this.$clearDynamicProperty("each"); + //pNode.setProperty("each", null);//@todo double? + //@todo remove model? + + //@todo this should be near $handleBindingRule... + var pNode = this.parentNode;//@todo apf3.0 get a list via $bindings + if (pNode.localName == "bindings") { + pNode.removeEventListener("noderegister", this.$noderegister); + + var nodes = pNode.$amlNodes, + i = 0, + l = nodes.length; + for (; i < l; ++i) { + //delete nodes[i].each; //@todo apf3.x is already set by new one + + + delete nodes[i].$sort; + + } + } + else { + //delete pNode.each; //@todo apf3.x is already set by new one + + + delete pNode.$sort; + + } + }); + + this.addEventListener("DOMNodeInsertedIntoDocument", f); + +}).call(apf.BindingEachRule.prototype = new apf.BindingRule()); + +apf.aml.setElement("each", apf.BindingEachRule); + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/* + * @todo docs + */ +apf.BindingLoadRule = function(struct, tagName) { + this.$init(tagName, apf.NODE_HIDDEN, struct); +}; + +(function(){ + //1 = force no bind rule, 2 = force bind rule + this.$attrExcludePropBind = apf.extend({ + get: 1 + }, this.$attrExcludePropBind); + + this.$propHandlers["get"] = function(value, prop) { + delete this["c" + prop]; + } +}).call(apf.BindingLoadRule.prototype = new apf.BindingRule()); + +apf.aml.setElement("load", apf.BindingLoadRule); +apf.aml.setElement("insert", apf.BindingLoadRule); + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/* + * @todo docs + */ +apf.BindingQuicksandRule = function(struct, tagName) { + this.$init(tagName, apf.NODE_HIDDEN, struct); +}; + +(function(){ + function getFilteredNodes(pNode) { + pNode = pNode || this.$parent; + var attr, tmp, + res = [], + dataIDs = [], + xmlNodes = pNode.$getDataNode("quicksand", pNode.xmlRoot, false, null, true), + domNodes = pNode.$ext.childNodes, + i = 0, + l = xmlNodes.length; + if (!domNodes.length || !l) + return res; + + for (; i < l; ++i) + dataIDs.push(xmlNodes[i].getAttribute("a_id")); + + for (i = 0, l = domNodes.length; i < l; ++i) { + if (!domNodes[i] || !(attr = domNodes[i].getAttribute("id"))) + continue; + tmp = attr.split("|"); + tmp.pop(); + if (dataIDs.indexOf(tmp.join("|")) > -1) + res.push(domNodes[i]); + } + + return res; + } + + function nodeInFilter(node, filtered) { + var i = 0, + l = filtered.length, + s = node.getAttribute("id"); + for (; i < l; ++i) { + if (filtered[i].getAttribute("id") == s) + return filtered[i]; + } + return null; + } + + function quicksand(parent, customOptions) { + parent = this.$parent.$ext; + + var i, l, dest, src, offset, + _self = this, + coll = getFilteredNodes.call(this), // destination (target) collection + //sourceHeight = apf.getStyle(parent, "height"), // used to keep height and document flow during the animation + parentOffset = apf.getAbsolutePosition(parent), // offset of visible container, used in animation calculations + offsets = [], // coordinates of every source collection item + callbackFunction = typeof(arguments[1]) == "function" + ? arguments[1] + : typeof arguments[2] == "function" ? arguments[2] : apf.K, + // Gets called when any animation is finished + //var postCallbackPerformed = 0; // prevents the function from being called more than one time + postCallback = function() { + _self.dispatchEvent("afterquicksand"); + callbackFunction.call(_self); + /*if (!postCallbackPerformed) { + parent.innerHTML = $dest.innerHTML; // put target HTML into visible source container + $("[data-quicksand-owner=" + cssPath(parent) + "]").remove(); // remove all temporary containers + if (typeof callbackFunction == "function") + callbackFunction.call(this); + postCallbackPerformed = 1; + }*/ + }, + options = { + steps: 60, + anim: apf.tween.easeInOutQuad, + onfinish: postCallback, + // put false if you don't want the plugin to adjust height of container to fit all the items + adjustHeight: true + }; + apf.extend(options, customOptions);; + + // Replace the collection and quit if IE6 + if (apf.isIE && apf.isIE < 7) { + parent.innerHTML = ""; + for (i = 0, l = coll.length; i < l; i++) + parent.appendChild(coll[i]); + return; + } + + var $source = parent.childNodes; // source collection items + + // Position: relative situations + var correctionOffset = [0, 0]; + /*var $correctionParent = parent.offsetParent(); + var correctionOffset = apf.getAbsolutePosition($correctionParent); + if (apf.getStyle($correctionParent, "position") == "relative") { + if ($correctionParent.get(0).nodeName.toLowerCase() == "body") { + + } + else { + correctionOffset[0] += parseFloat($correctionParent.css("border-top-width")); + correctionOffset[1] += parseFloat($correctionParent.css("border-left-width")); + } + } else { + correctionOffset[0] -= parseFloat($correctionParent.css("border-top-width")); + correctionOffset[1] -= parseFloat($correctionParent.css("border-left-width")); + correctionOffset[0] -= parseFloat($correctionParent.css("margin-top")); + correctionOffset[1] -= parseFloat($correctionParent.css("margin-left")); + }*/ + + + // keeps nodes after source container, holding their position + parent.style.height = parent.offsetHeight + "px"; + + // stops previous animations on source container + apf.tween.clearQueue(parent, true);//$(this).stop(); + + // get positions of source collections + for (i = 0, l = $source.length; i < l; ++i) { + src = $source[i]; + offsets[i] = apf.getAbsolutePosition(src, parent, false); + } + for (i = 0, l = $source.length; i < l; ++i) { + src = $source[i]; + // This doesn"t move any element at all, just sets position to absolute + // and adjusts top & left to make them compatible with position: absolute + with (src.style) { + position = "absolute"; + margin = "0"; + top = (offsets[i][1] - parentOffset[1]) + "px";// - parseFloat(apf.getStyle(src, "margin-top")) + "px"; + left = (offsets[i][0] - parentOffset[0]) + "px";// - parseFloat(apf.getStyle(src, "margin-left")) + "px"; + } + } + + // create temporary container with destination collection + var $dest = parent.cloneNode(false); + $dest.setAttribute("id", ""); + //$dest.setAttribute("data-quicksand-owner", parent.selector); + //$dest.style.height = "auto"; + //$dest.style.width = parent.offsetWidth + "px"; + + for (i = 0, l = coll.length; i < l; ++i) { + $dest.appendChild(coll[i].cloneNode(true)); + coll[i].$offset = apf.getAbsolutePosition(coll[i]); + } + // insert node into HTML + // Note that the node is under visible source container in the exactly same position + // The browser render all the items without showing them (opacity: 0.0) + // No offset calculations are needed, the browser just extracts position from underlayered destination items + // and sets animation to destination positions. + parent.parentNode.insertBefore($dest, parent); + //$dest.setAttribute("data-quicksand-owner", cssPath(parent)); + with ($dest.style) { + zIndex = 1; + opacity = 0; + margin = 0; + position = "absolute"; + top = parentOffset[1] - correctionOffset[1] + "px"; + left = parentOffset[0] - correctionOffset[0] + "px"; + } + + // If destination container has different height than source container + // the height can be animated, adjusting it to destination height + if (false) {//options.adjustHeight) { + apf.tween.single(parent, { + steps: options.steps, + anim: options.anim, + type: "height", + from: parent.offsetHeight, + to: $dest.offsetHeight + });//parent.animate({height: $dest.height()}, options.duration, options.easing); + } + + // Now it's time to do shuffling animation + // First of all, we need to identify same elements within source and destination collections + var insets = []; + for (i = 0, l = $source.length; i < l; ++i) { + src = $source[i]; + //var destElement = coll.filter("[" + options.attribute + "=" + src.getAttribute(options.attribute) + "]"); + if (dest = nodeInFilter(src, coll)) {//destElement.length) { + // The item is both in source and destination collections + // If it's under different position, let's move it + offset = insets.shift() || offsets[i]; + options.tweens = [{ + type: "top", + from: dest.$offset[1] - parentOffset[1], + to: offset[1] - parentOffset[1] + }, { + type: "left", + from: dest.$offset[0] - parentOffset[0], + to: offset[0] - parentOffset[0] + }, { + type: "opacity", + from: apf.getStyle(src, "opacity"), + to: 1 + }]; + if (apf.supportCSSAnim) { + options.tweens.push({ + type: "transform", + subType: "scale", + from: 0, + to: 1.0 + }); + } + apf.tween.multi(src, options); + } + else { + // The item from source collection is not present in destination collections + // Let's remove it + options.tweens = [{ + type: "opacity", + from: apf.getStyle(src, "opacity"), + to: 0 + }]; + if (apf.supportCSSAnim) { + options.tweens.push({ + type: "transform", + subType: "scale", + from: 1.0, + to: 0 + }); + } + insets.push(offsets[i]); + apf.tween.multi(src, options); + } + } + + for (i = 0, l = coll.length; i < l; ++i) { + var item = coll[i]; + // Grab all items from target collection not present in visible source collection + if (!nodeInFilter(item, $source)) { + // No such element in source collection... + dest = nodeInFilter(item, coll); + + options.tweens = [{ + type: "opacity", + from: 0, + to: 1 + }]; + if (!apf.isIE) { + // @todo add scaleTo animation (CSS3) to 0.0 + } + + // Let's create it + offset = apf.getAbsolutePosition(dest); + dest = dest.cloneNode(true); + + with (dest.style) { + position = "absolute"; + margin = "0"; + top = (offset[1] - parentOffset[1]) + "px"; + left = (offset[0] - parentOffset[0]) + "px"; + opacity = "0"; + transform = "scale(.0)"; + } + parent.appendChild(dest); + apf.tween.multi(dest, options); + } + } + } + + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + //Find parent that this rule works on + var pNode = this; + while (pNode && pNode.$bindingRule) + pNode = pNode.parentNode; + this.$parent = pNode; + + if (!pNode) + return; + + var _self = this; + setTimeout(function() { + quicksand.call(_self); + }); + }); +}).call(apf.BindingQuicksandRule.prototype = new apf.BindingRule()); + +apf.aml.setElement("quicksand", apf.BindingQuicksandRule); + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * An element containing all the binding rules for the data + * bound elements referencing this element. + * + * + * #### Example: + * + * ```xml + * + * + * + * + * + * + * + * + * + * + * + * + * ``` + * + * @see apf.smartbinding + * + * @class apf.bindings + * @define bindings + * @inherits apf.AmlElement + * @apfclass + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.8 + * + * @default_private + */ +apf.bindings = function(struct, tagName) { + this.$init(tagName || "bindings", apf.NODE_HIDDEN, struct); + + this.$bindings = new apf.ruleList(); + this.$amlNodes = {}; +}; + +(function(){ + this.$smartbinding = null; + + this.register = function(amlNode) { + if (amlNode.localName == "smartbinding") { + this.$smartbinding = amlNode; + this.$smartbinding.add(this); //Assuming only at init + return; + } + + if (!amlNode.hasFeature(apf.__DATABINDING__)) + return; + + this.$amlNodes[amlNode.$uniqueId] = amlNode; + + if (!this.$amlLoaded) + return; + + if (!this.$bindings.$isCompiled) + this.$cbindings = this.$bindings.compile(); + + amlNode.$bindings = this.$bindings; + amlNode.$cbindings = this.$cbindings; + amlNode.$bindingsElement = this; + + //@todo apf3.0 should be deprecated + amlNode.dispatchEvent("bindingsload", { + bindings: this.$bindings, + compiled: this.$cbindings + }); + this.dispatchEvent("noderegister", { + amlNode: amlNode + }); + amlNode.$checkLoadQueue(); + }; + + this.unregister = function(amlNode) { + //unregister element + this.$amlNodes[amlNode.$uniqueId] = null; + delete this.$amlNodes[amlNode.$uniqueId]; + + amlNode.$bindingsElement = + amlNode.$bindings = + amlNode.$cbindings = false; + + amlNode.dispatchEvent("bindingsunload", { + bindings: this.$bindings, + compiled: this.$cbindings + }); + }; + + this.reload = function(){ + for (var id in this.$amlNodes) { + this.$amlNodes[id].reload(); + } + } + + // *** DOM Handlers *** // + + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + var nodes = this.childNodes; + for (var node, i = 0, l = nodes.length; i < l; i++) { + if (!(node = nodes[i]).$amlLoaded && node.nodeType == 1) + node.dispatchEvent("DOMNodeInsertedIntoDocument"); //{relatedParent : nodes[j].parentNode} + } + + this.register(this.parentNode); + + for (var id in this.$amlNodes) + this.register(this.$amlNodes[id]); + }); +}).call(apf.bindings.prototype = new apf.AmlElement()); + +apf.ruleList = function(){ + this.$compiled = {}; +} +apf.ruleList.prototype = { + $isCompiled: false, + + getRule: function(name, xmlNode) { + var rules = this[name]; + if (!rules) return false; + + //@todo Shouldn't allow async calls..., should always give a function + for (var func, rule, i = 0, l = rules.length; i < l; i++) { + rule = rules[i]; + if (!rule.match) + return rule; + + func = rule.cmatch || rule.compile("match", {injectself: true, xpathmode: 2}); + if (func && func(xmlNode)) + return rule; + } + }, + + compile: function(name) { + var rules, s, c = this.$compiled, hasAml = false; + + if (name) { + s = []; + rules = this[name]; + for (var rule, i = 0, l = rules.length; i < l; i++) { + if (!(rule = rules[i]).match && !rule.value) + continue; + + s.push(rule.match, rule.value); + + } + + //always give a function, no async calls (could also just error on execution) + c[name] = apf.lm.compileMatch(s); + + + + return c; + } + + for (name in this) { + if (name == "each") + continue; + + rules = this[name]; + if (rules.dataType != apf.ARRAY) + continue; + + s = [], hasAml = false; + for (var rule, i = 0, l = rules.length; i < l; i++) { + if (!(rule = rules[i]).match && !rule.value) + continue; + + s.push(rule.match, rule.value); + + } + + //always give a function, no async calls (could also just error on execution) + c[name] = apf.lm.compileMatch(s); + + + } + + this.$isCompiled = true; + + return c; + }, + + getRuleIndex: function(name, index) { + var rule = this[name][index]; + if (rule.value) { + if (!rule.cvalue) + rule.compile("value"); + } + else if (rule.match) { + if (!rule.cmatch) + rule.compile("match"); + } + return rule; + }, + + getDataNode: function(name, xmlNode, createNode, ruleList, multiple) { + var i, l, func, node, rule, rules = this[name]; + if (!rules) + return; + + //@todo Shouldn't allow async calls..., should always give a function + for (rule, i = 0, l = rules.length; i < l; i++) { + rule = rules[i]; + + func = rule.cvaluematch; + if (!func) { //@todo apf3.0 cleanup + if (rule.match && rule.value && rule.value.match(/^\[.*\]$/)) + rule.valuematch = "{_n = " + rule.match + "; %[child::" + + rule.value.substr(1, rule.value.length - 2) + .split("|").join("|child::") + "]}"; + else + rule.valuematch = rule.match || rule.value; + + func = rule.$compile("valuematch", { + xpathmode: multiple ? 4 : 3, + injectself: rule.match ? true : false + }); + } + + if (func && (node = func(xmlNode, createNode))) { + if (ruleList) + ruleList.push(rule); + + return node; + } + } + + return false; + } +} + +apf.aml.setElement("bindings", apf.bindings); + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +// @todo doc +/* + * @attribute {String} formula + * @attribute {Number} length + * @attribute {String} delimiter + * @attribute {String} split + * @attribute {String} css + */ +apf.BindingSeriesRule = function(struct, tagName) { + this.$init(tagName || "series", apf.NODE_HIDDEN, struct); +}; + +(function(){ + //1 = force no bind rule, 2 = force bind rule + this.$attrExcludePropBind = apf.extend({ + formula: 1 + }, this.$attrExcludePropBind); + + this.$propHandlers["formula"] = function(value, prop) { + delete this["c" + prop]; + } + + /*this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + //Find parent that this rule works on + var pNode = this; + while (pNode && pNode.$bindingRule) + pNode = pNode.parentNode; + + if (!pNode) + return; + });*/ +}).call(apf.BindingSeriesRule.prototype = new apf.BindingRule()); + +apf.aml.setElement("series", apf.BindingSeriesRule); + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * @todo description + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.4 + */ + + + +apf.AmlConfig = function(){ + this.$init("config", apf.NODE_VISIBLE); +}; + +(function(){ + this.focussable = false; + this.$canLeechSkin = true; + + this.$draw = function(){ + //Build Main Skin + this.$ext = this.$int = this.$getExternal(this.$isLeechingSkin + ? this.localName + : "main"); + }; + +}).call(apf.AmlConfig.prototype = new apf.Presentation()); + +apf.aml.setElement("config", apf.AmlConfig); + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * Element displaying the rendered contents of an URL. + * + * @constructor + * + * @define browser + * + * @inheritsElsewhere apf.XForms + * @inherits apf.StandardBinding + * @inherits apf.DataAction + * + * @event load + * @event error + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.4 + * + * @binding value Determines the way the value for the element is retrieved + * from the bound data. + * Example (BROKEN): + * Sets the url based on data loaded into this component. + * + * + * + * + * + * + * Example: + * A shorter way to write this is: + * + * + * + * + * + * + */ +apf.browser = function(struct, tagName) { + this.$init(tagName || "browser", apf.NODE_VISIBLE, struct); +}; +(function(){ + this.implement( + + + apf.DataAction + + + ,apf.StandardBinding + + ); + + /** + * @attribute {String} src the url to be displayed in this element + * @attribute {String} value alias for the 'url' attribute + */ + this.$supportedProperties.push("value", "src"); + this.$propHandlers["src"] = + this.$propHandlers["value"] = function(value, force) { + try { + this.$browser.src = value || "about:blank"; + } + catch (e) { + this.$browser.src = "about:blank"; + } + }; + this.$propHandlers["border"] = apf.Presentation.prototype.$propHandlers["border"]; + + this.getValue = function() { + return this.value || this.src; + }; + + /** + * Retrieves the current url that is displayed. + */ + this.getURL = function(){ + return this.$browser.src; + }; + + /** + * Browses to the previous tab + */ + this.back = function(){ + this.$browser.contentWindow.history.back(); + }; + + /** + * Browses to the next tab + */ + this.forward = function(){ + this.$browser.contentWindow.history.forward(); + }; + + /** + * Reload the current tab + */ + this.reload = function(){ + this.$browser.src = this.$browser.src; + }; + + /** + * Print the currently displayed tab + */ + this.print = function(){ + this.$browser.contentWindow.print(); + }; + + /** + * Execute a string of javascript on the tab. This is subject to browser + * security and will most likely only work when the browsed tab is loaded + * from the same domain. + * @param {String} str javascript string to be executed. + * @param {Boolean} noError whether the execution can throw an exception. Defaults to false. + */ + this.runCode = function(str, noError) { + if (noError) { + try { + this.$browser.contentWindow.eval(str); + } catch (e) {} + } + else { + this.$browser.contentWindow.eval(str); + } + }; + + this.$draw = function(parentNode) { + if (!parentNode) + parentNode = this.$pHtmlNode; + + //Build Main Skin + if (apf.cannotSizeIframe) { + //parentNode.appendChild(document.createElement("iframe"));// + var _iframe = document.createElement("iframe"); + _iframe.setAttribute("frameborder","0"); + this.$ext = parentNode.appendChild(document.createElement("DIV")) + .appendChild(_iframe).parentNode; + this.$ext.style.width = "100px"; + this.$ext.style.height = "100px"; + this.$browser = this.$ext.firstChild; + //this.$browser = this.$ext; + this.$browser.style.width = "100%"; + this.$browser.style.height = "100%"; + this.$browser.frameBorder = 0; + } + else { + this.$ext = parentNode.appendChild(document.createElement("iframe")); + this.$ext.setAttribute("frameborder","0"); + //this.$ext.style.width = "100px"; + //this.$ext.style.height = "100px"; + this.$browser = this.$ext; + this.$ext.style.border = "1px solid #999"; + this.$ext.style.background = "white"; + } + this.$ext.className = "apfbrowser" + + if (this.getAttribute("style")) + this.$ext.setAttribute("style", this.getAttribute("style")); + + var _self = this; + apf.addListener(this.$browser, "load", function(){ + var loc = this.contentWindow.location.href; + _self.dispatchEvent("load", {href: loc}); + if (loc) + _self.setProperty("src", loc); + }); + + apf.addListener(this.$browser, "error", function(){ + _self.dispatchEvent("error"); + if (this.contentWindow.location.href) + _self.setProperty("src", this.contentWindow.location.href); + }); + + //this.$browser = this.$ext.contentWindow.document.body; + this.$ext.host = this; + //this.$browser.host = this; + }; +}).call(apf.browser.prototype = new apf.GuiElement()); + +apf.aml.setElement("browser", apf.browser); + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * Element displaying a clickable rectangle that visually confirms to the + * user when the area is clicked and then executes a command. + * + * + * #### Example: Working with Events + * + * ```xml, demo + * + * + * Onclick event + * + * Example button + * Onmouseover event + * + * Example button + * Onmouseout event + * + * Example button + * + * + * ``` + * + * #### Example: Interactions and Colors + * + * ```xml, demo + * + * + * + * + * Click me to resize Test button to 200px + * + * Click me to resize Test button to 50px + * Test + * + * + * + * ``` + * + * @class apf.button + * @inherits apf.BaseButton + * @define button + * + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.4 + * @form + * @inherits apf.BaseButton + */ +apf.submit = function(struct, tagName) { + this.$init(tagName || "submit", apf.NODE_VISIBLE, struct); +}; + + +apf.trigger = function(struct, tagName) { + this.$init(tagName || "trigger", apf.NODE_VISIBLE, struct); +}; + +apf.reset = function(struct, tagName) { + this.$init(tagName || "reset", apf.NODE_VISIBLE, struct); +}; + +apf.button = function(struct, tagName) { + this.$init(tagName || "button", apf.NODE_VISIBLE, struct); +}; + +(function() { + this.$useExtraDiv; + this.$childProperty = "caption"; + this.$inited = false; + this.$isLeechingSkin = false; + this.$canLeechSkin = true; + + // *** Properties and Attributes *** // + + this.$focussable = apf.KEYBOARD; // This object can get the focus + this.value = null; + + this.$init(function(){ + //@todo reparenting + var forceFocus, _self = this, lastDefaultParent; + this.$propHandlers["default"] = function(value) { + if (parseInt(value) != value) + value = apf.isTrue(value) ? 1 : 0; + + this["default"] = parseInt(value); + + if (!this.focussable && value || forceFocus) + this.setAttribute("focussable", forceFocus = value); + + if (lastDefaultParent) { + lastDefaultParent.removeEventListener("focus", setDefault); + lastDefaultParent.removeEventListener("blur", removeDefault); + } + + if (!value) + return; + + var pNode = this.parentNode; + while (pNode && !pNode.focussable && --value) + pNode = pNode.parentNode; + + //Currrently only support for parentNode, this might need to be expanded + if (pNode) { + pNode.addEventListener("focus", setDefault); + pNode.addEventListener("blur", removeDefault); + } + }; + + function setDefault(e) { + if (e.defaultButtonSet || e.returnValue === false) + return; + + e.defaultButtonSet = true; + + if (this.$useExtraDiv) + _self.$ext.appendChild(apf.button.$extradiv); + + _self.$setStyleClass(_self.$ext, _self.$baseCSSname + "Default"); + + if (e.toElement != _self && e.toElement) { + // _self.$focusParent + e.toElement.addEventListener("keydown", btnKeyDown); + } + } + + function removeDefault(e) { + if (this.$useExtraDiv && apf.button.$extradiv.parentNode == _self.$ext) + _self.$ext.removeChild(apf.button.$extradiv); + + _self.$setStyleClass(_self.$ext, "", [_self.$baseCSSname + "Default"]); + + if (e.fromElement != _self && e.fromElement) { + //_self.$focusParent + e.fromElement.removeEventListener("keydown", btnKeyDown); + } + } + + function btnKeyDown(e) { + var ml; + + var f = apf.document.activeElement; + if (f) { + if (f.hasFeature(apf.__MULTISELECT__)) + return; + + ml = f.multiline; + } + + if (!_self.$ext.onmouseup) + return; + + if (ml && ml != "optional" && e.keyCode == 13 + && e.ctrlKey || (!ml || ml == "optional") + && e.keyCode == 13 && !e.ctrlKey && !e.shiftKey && !e.altKey) { + apf.preventDefault(e.htmlEvent); + _self.$ext.onmouseup(e.htmlEvent, true); + } + } + + this.addEventListener("focus", setDefault); + this.addEventListener("blur", removeDefault); + + this.$enable = function(){ + if (this["default"]) { + setDefault({}); + if (apf.document.activeElement) + apf.document.activeElement.focus(true); + } + + if (this.state && this.value) + this.$setState("Down", {}); + else if (this.$mouseOver) + this.$updateState({}, "mouseover"); + else + this.$doBgSwitch(1); + }; + + this.$disable = function(){ + if (this["default"]) + removeDefault({}); + + this.$doBgSwitch(4); + this.$setStyleClass(this.$ext, "", + [this.$baseCSSname + "Over", this.$baseCSSname + "Down"]); + }; + }); + + /** + * @attribute {String} icon Sets or gets the url from which the icon image is loaded. + */ + /** + * @attribute {Boolean} state Sets or gets whether this boolean is a multi state button. + */ + /** + * @attribute {String} value Sets or gets the initial value of a state button. + */ + /** + * @attribute {String} color Sets or gets the text color of the caption of this element. + */ + /** + * @attribute {String} caption Sets or gets the text displayed on this element indicating the action when the button is pressed. + */ + /** + * @attribute {String} action Sets or gets one of the default actions this button can perform when pressed. + * + * The possible values include: + * + * - `undo`: Executes undo on the action tracker of the target element. + * - `redo`: Executes redo on the action tracker of the target element. + * - `remove`: Removes the selected node(s) of the target element. + * - `add`: Adds a node to the target element. + * - `rename`: Starts the rename function on the target element. + * - `login`: Calls log in on the auth element with the values of the textboxes of type username and password. + * - `logout`: Calls lot out on the auth element. + * - `submit`: Submits the data of a model specified as the target. + * - `ok`: Executes a `commitTransaction()` on the target element, and closes or hides that element. + * - `cancel`: Executes a `rollbackTransaction()` on the target element, and closes or hides that element. + * - `apply`: Executes a `commitTransaction()` on the target element. + * - `close`: Closes the target element. + */ + /** + * @attribute {String} target Sets or gets the id of the element to apply the action to. Defaults to the parent container. + */ + /** + * @attribute {Number} default Sets or gets the search depth for which this button is the default action. `1` specifies the direct parent, `2` specifies the parent of this parent, _.e.t.c._ + */ + /** + * @attribute {String} submenu Sets or gets the name of the contextmenu to display when the button is pressed. + */ + //this.$booleanProperties["default"] = true; + this.$booleanProperties["state"] = true; + this.$supportedProperties.push("icon", "value", "tooltip", "state", + "color", "caption", "action", "target", "default", "submenu", "hotkey"); + + this.$propHandlers["icon"] = function(value) { + + if (!this.oIcon) return; + + + if (value) + this.$setStyleClass(this.$ext, this.$baseCSSname + "Icon"); + else + this.$setStyleClass(this.$ext, "", [this.$baseCSSname + "Icon"]); + + apf.skins.setIcon(this.oIcon, value, this.iconPath); + }; + + this.$propHandlers["value"] = function(value) { + if (!this.state && !this.submenu) + return; + + if (value === undefined) + value = !this.value; + this.value = value; + + if (this.value) { + this.$setState("Down", {}); + this.$setStyleClass(this.$ext, this.$baseCSSname + "Checked") + } + else { + this.$setState("Out", {}); + this.$setStyleClass(this.$ext, "", [this.$baseCSSname + "Checked"]) + } + }; + + this.$propHandlers["state"] = function(value) { + if (value) + this.$setStateBehaviour(this.value); + else + this.$setNormalBehaviour(); + }; + + this.$propHandlers["color"] = function(value) { + if (this.oCaption) + this.oCaption.parentNode.style.color = value; + }; + + this.$propHandlers["caption"] = function(value) { + if (!this.oCaption) + return; + + if (value) + this.$setStyleClass(this.$ext, "", [this.$baseCSSname + "Empty"]); + else + this.$setStyleClass(this.$ext, this.$baseCSSname + "Empty"); + + if (this.oCaption.nodeType == 1) + this.oCaption.innerHTML = String(value || "").trim(); + else + this.oCaption.nodeValue = String(value || "").trim(); + }; + + + /** + * @attribute {String} hotkey Sets or gets the key combination a user can press + * to active the function of this element. Use any combination of + * [[keys: Ctrl]], [[keys: Shift]], [[keys: Alt]], [[keys: F1]]-[[keys: F12]], and alphanumerical characters. Use a + * space, a minus or plus sign as a seperator. + * + * #### Example + * + * ```xml + * Undo + * ``` + */ + this.$propHandlers["hotkey"] = function(value) { + if (this.$hotkey) + apf.setNodeValue(this.$hotkey, value); + + if (this.$lastHotkey) { + apf.hotkeys.remove(this.$lastHotkey[0], this.$lastHotkey[1]); + delete this.$lastHotkey[0]; + } + + if (value) { + this.$lastHotkey = [value]; + var _self = this; + apf.hotkeys.register(value, this.$lastHotkey[1] = function(){ + //hmm not very scalable... + _self.$setState("Over", {}); + + $setTimeout(function(){ + _self.$setState("Out", {}); + }, 200); + + if (_self.$clickHandler && _self.$clickHandler()) + _self.$updateState(e || event, "click"); + else + _self.dispatchEvent("click"); + }); + } + + if (this.tooltip) + apf.GuiElement.propHandlers.tooltip.call(this, this.tooltip); + } + + + + + //@todo move this to menu.js + function menuKeyHandler(e) { + return; + var key = e.keyCode; + + var next, nr = apf.getChildNumber(this); + if (key == 37) { //left + next = nr == 0 + ? this.parentNode.childNodes.length - 1 + : nr - 1; + this.parentNode.childNodes[next].dispatchEvent("mouseover"); + } + else if (key == 39) { //right + next = (nr >= this.parentNode.childNodes.length - 1) + ? 0 + : nr + 1; + this.parentNode.childNodes[next].dispatchEvent("mouseover"); + } + } + + function menuDown(e) { + var menu = self[this.submenu] || this.submenu, + $button1; + + this.value = !this.value; + + if (this.value) + this.$setState("Down", {}); + + + + var menuPressed = this.parentNode.menuIsPressed; + if (menuPressed && menuPressed != this) { + menuPressed.setValue(false); + var oldMenu = self[menuPressed.submenu] || menuPressed.submenu; + if (oldMenu != (self[this.submenu] || this.submenu)) + oldMenu.$propHandlers["visible"].call(oldMenu, false, true); + } + + if (!this.value) { + menu.hide(); + this.$setState("Over", {}, "toolbarover"); + + if ($button1 = this.parentNode.$button1) + $button1.$setState("Over", {}, "toolbarover"); + + this.parentNode.menuIsPressed = false; + if (this.parentNode.hasMoved) + this.value = false; + + if (apf.hasFocusBug) + apf.window.$focusfix(); + + return false; + } + + this.parentNode.menuIsPressed = this; + + menu.display(null, null, false, this, + null, null, this.$ext.offsetWidth - 2); + + this.parentNode.hasMoved = false; + + if (e && e.htmlEvent) + apf.stopPropagation(e.htmlEvent); + + return false; + } + + function menuOver(){ + var menuPressed = this.parentNode.menuIsPressed; + + if (!menuPressed || menuPressed == this) + return; + + var menu = self[this.submenu] || this.submenu; + if (menu.pinned) + return; + + menuPressed.setValue(false); + var oldMenu = self[menuPressed.submenu] || menuPressed.submenu; + oldMenu.$propHandlers["visible"].call(oldMenu, false, true);//.hide(); + + this.setValue(true); + this.parentNode.menuIsPressed = this; + + + + //var pos = apf.getAbsolutePosition(this.$ext, menu.$ext.offsetParent); + +// menu.display(pos[0], +// pos[1] + this.$ext.offsetHeight, true, this, +// null, null, this.$ext.offsetWidth - 2); + + menu.display(null, null, true, this, + null, null, this.$ext.offsetWidth - 2); + + //apf.window.$focus(this); + this.$focus(); + + this.parentNode.hasMoved = true; + + return false; + } + + this.$propHandlers["submenu"] = function(value) { + if (!value) { + if (this.value && this.parentNode) { + + menuDown.call(this); + + } + + this.$focussable = true; + this.$setNormalBehaviour(); + this.removeEventListener("mousedown", menuDown); + this.removeEventListener("mouseover", menuOver); + this.removeEventListener("keydown", menuKeyHandler, true); + return; + } + + this.$focussable = false; + this.$setStateBehaviour(); + + this.addEventListener("mouseover", menuOver); + this.addEventListener("mousedown", menuDown); + this.addEventListener("keydown", menuKeyHandler, true); + }; + + + // *** Public Methods *** // + + + + /** + * Sets the value of this element. This should be one of the values + * specified in the `values` attribute. + * @param {String} value the new value of this element + */ + this.setValue = function(value) { + this.setProperty("value", value, false, true); + }; + + /** + * If this button is a submenu, this method shows it. + */ + this.showMenu = function(){ + if (this.submenu && !this.value) + menuDown.call(this); + }; + /** + * If this button is a submenu, this method hides it. + */ + this.hideMenu = function(){ + if (this.submenu && this.value) + menuDown.call(this); + }; + + /** + * Sets the text displayed as a caption of this element. + * + * @param {String} value The string to display. + * @see apf.Validation + */ + this.setCaption = function(value) { + this.setProperty("caption", value, false, true); + }; + + /** + * Sets the URL of the icon displayed on this element. + * + * @param {String} value The URL to the location of the icon. + */ + this.setIcon = function(url) { + this.setProperty("icon", url, false, true); + }; + + + + // *** Private state methods *** // + + this.$setStateBehaviour = function(value) { + this.value = value || false; + this.isBoolean = true; + this.$setStyleClass(this.$ext, this.$baseCSSname + "Bool"); + + if (this.value) { + this.$setStyleClass(this.$ext, this.$baseCSSname + "Down"); + this.$doBgSwitch(this.states["Down"]); + } + }; + + this.$setNormalBehaviour = function(){ + this.value = null; + this.isBoolean = false; + this.$setStyleClass(this.$ext, "", [this.$baseCSSname + "Bool"]); + }; + + this.$setState = function(state, e, strEvent) { + var parentNode = this.parentNode; + //if (this.disabled) + //return; + + if (strEvent && this.dispatchEvent(strEvent, {htmlEvent: e}) === false) + return; + + if (parentNode && parentNode.$button2 && parentNode.$button2.value && !this.submenu) + return; + + this.$doBgSwitch(this.states[state]); + var bs = this.$baseCSSname; + this.$setStyleClass(this.$ext, (state != "Out" ? bs + state : ""), + [(this.value ? "" : bs + "Down"), bs + "Over"]); + + if (this.submenu) { + bs = this.$baseCSSname + "menu"; + this.$setStyleClass(this.$ext, (state != "Out" ? bs + state : ""), + [(this.value ? "" : bs + "Down"), bs + "Over"]); + } + + //if (state != "Down") + //e.cancelBubble = true; + }; + + this.$clickHandler = function(){ + // This handles the actual OnClick action. Return true to redraw the button. + if (this.isBoolean && !this.submenu && this.auto !== false) { + this.setProperty("value", !this.value); + return true; + } + }; + + + this.$submenu = function(hide, force) { + if (hide && this.submenu) { + this.setValue(false); + this.$setState("Out", {}, "mouseout"); + if (this.parentNode) + this.parentNode.menuIsPressed = false; + } + }; + + + // *** Init *** // + + this.addEventListener("$skinchange", function(e) { + if (this.tooltip) + apf.GuiElement.propHandlers.tooltip.call(this, this.tooltip); + }); + + this.$draw = function(){ + var pNode, isToolbarButton = (pNode = this.parentNode) + && pNode.parentNode && pNode.parentNode.localName == "toolbar"; + + if (isToolbarButton) { + if (typeof this.focussable == "undefined") + this.focussable = false; + + this.$focussable = apf.KEYBOARD; + } + + //Build Main Skin + this.$ext = this.$getExternal(); + this.oIcon = this.$getLayoutNode("main", "icon", this.$ext); + this.oCaption = this.$getLayoutNode("main", "caption", this.$ext); + + this.$useExtraDiv = apf.isTrue(this.$getOption("main", "extradiv")); + if (!apf.button.$extradiv && this.$useExtraDiv) { + (apf.button.$extradiv = document.createElement("div")) + .className = "extradiv" + } + + if (this.localName == "submit") + this.action = "submit"; + else if (this.localName == "reset") + this.action = "reset"; + + this.$setupEvents(); + }; + + + this.addEventListener("$skinchange", function(){ + if (this.caption) + this.$propHandlers["caption"].call(this, this.caption); + + if (this.icon) + this.$propHandlers["icon"].call(this, this.icon); + + this.$updateState({reset:1}); + //this.$blur(); + + //if (this.$focussable !== true && this.hasFocus()) + //apf.window.$focusLast(this.$focusParent); + }); + + + + + +}).call(apf.button.prototype = new apf.BaseButton()); + +// submit, trigger, reset, button +apf.submit.prototype = +apf.trigger.prototype = +apf.reset.prototype = apf.button.prototype; + +apf.aml.setElement("submit", apf.submit); +apf.aml.setElement("trigger", apf.trigger); +apf.aml.setElement("reset", apf.reset); +apf.aml.setElement("button", apf.button); + + + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * This element displays a clickable rectangle with two states that + * can be toggled by user interaction. + * + * #### Example: Setting and Retrieving Values + * + * ```xml, demo + * + * + * Full + * + * + * + * ``` + * + * #### Example: Disabled Values + * + * ```xml, demo + * + * + * Option 1 + * Option 2 + * Option 3 + * Option 4 + * + * + * + * + * ``` + * + * @class apf.checkbox + * + * @define checkbox + * + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.4 + * @form + * @inherits apf.BaseButton + * @inheritsElsewhere apf.XForms + * + */ +/** + * @binding value Determines the way the value for the element is retrieved + * from the bound data. + * + * #### Example + * + * Sets the value of the checkbox based on data loaded into this component. + * ```xml + * + * + * + * Caption + * ``` + * + * A shorter way to write this is: + * + * ```xml + * + * + * + * Caption + * ``` + */ +apf.checkbox = function(struct, tagName) { + this.$init(tagName || "checkbox", apf.NODE_VISIBLE, struct); +}; + +(function() { + this.implement( + + + apf.DataAction + + ); + + //Options + this.$focussable = apf.KEYBOARD; // This object can get the focus + this.checked = false; + + // *** Properties and Attributes *** // + + this.$booleanProperties["checked"] = true; + this.$supportedProperties.push("value", "checked", "label", "values"); + + /** + * @attribute {String} value Sets or gets the value of this element. + */ + this.$propHandlers["value"] = function(value) { + value = (typeof value == "string" ? value.trim() : value); + + if (value == "" && this["default"]) + value = this.value = apf.isTrue(this["default"]); + + if (this.$values) { + this.checked = (typeof value != "undefined" && value !== null + && value.toString() == this.$values[0].toString()); + } + else { + this.checked = apf.isTrue(value); + } + + if (this.checked) + apf.setStyleClass(this.$ext, this.$baseCSSname + "Checked"); + else + apf.setStyleClass(this.$ext, "", [this.$baseCSSname + "Checked"]); + }; + + /** + * @attribute {Boolean} checked Sets or gets whether the element is in the checked state. + */ + this.$propHandlers["checked"] = function(value) { + if (!this.$values) { + if (this.getAttribute("values")) + this.$propHandler["values"].call(this, this.getAttribute("values")); + //else + //this.$values = [true, false]; + } + this.setProperty("value", this.$values ? this.$values[value ? 0 : 1] : true); + }; + + /** + * @attribute {String} label Sets or gets the caption of the label explaining what + * the meaning of the checked state of this element is. + */ + this.$propHandlers["label"] = function(value) { + if (!this.$ext) + return; + + var lbl = this.$getLayoutNode("main", "label", this.$ext); + if (!lbl) + return; + + if (lbl.nodeType == 1) + lbl.innerHTML = value; + else + lbl.nodeValue = value; + }; + + /** + * @attribute {String} values Sets or gets a pipe seperated list of two values which + * correspond to the two states of the checkbox. The first for the checked + * state, the second for the unchecked state. + */ + this.$propHandlers["values"] = function(value) { + this.$values = typeof value == "string" + ? value.split("\|") + : (value || [1, 0]); + + this.$propHandlers["value"].call(this, this.value); + }; + + // *** Public Methods *** // + + + + /** + * Sets the value of this element. This should be one of the values + * specified in the [[apf.checkbox.values]] attribute. + * @param {String} value The new value of this element + */ + this.setValue = function(value) { + if (!this.$values) return; + this.setProperty("value", value, false, true); + }; + + /** + * Returns the current value. + */ + this.getValue = function(){ + return this.xmlRoot ? (this.$values + ? this.$values[this.checked ? 0 : 1] + : this.checked) : this.value; + }; + + /** + * Sets the checked state (and related value). + */ + this.check = function(){ + this.setProperty("value", this.$values + ? this.$values[0] + : true, false, true); + }; + + /** + * Sets the unchecked state (and related value). + */ + this.uncheck = function(){ + this.setProperty("value", this.$values + ? this.$values[1] + : false, false, true); + }; + + + + // *** Private state handling methods *** // + + this.addEventListener("$clear", function(){ + this.setProperty("value", this.$values ? this.$values[1] : false); + }); + + this.$enable = function(){ + if (this.$input) this.$input.disabled = false; + this.$doBgSwitch(1); + }; + + this.$disable = function(){ + if (this.$input) this.$input.disabled = true; + this.$doBgSwitch(4); + }; + + this.$setState = function(state, e, strEvent) { + //if (this.disabled) return; + + this.$doBgSwitch(this.states[state]); + this.$setStyleClass(this.$ext, (state != "Out" ? this.$baseCSSname + state : ""), + [this.$baseCSSname + "Down", this.$baseCSSname + "Over"]); + this.state = state; // Store the current state so we can check on it coming here again. + + if (strEvent) + this.dispatchEvent(strEvent, {htmlEvent: e}); + + /*if (state == "Down") + apf.cancelBubble(e, this); + else + e.cancelBubble = true;*/ + }; + + this.$clickHandler = function(){ + //this.checked = !this.checked; + this.change(this.$values + ? this.$values[(!this.checked) ? 0 : 1] + : !this.checked); + + + if (this.validate) //@todo rewrite button + this.validate(true); + + + return true; + }; + + // *** Init *** // + + this.$draw = function(){ + //Build Main Skin + this.$ext = this.$getExternal(); + this.$input = this.$getLayoutNode("main", "input", this.$ext); + this.$notfromext = this.$input && this.$input != this.$ext; + + this.$setupEvents(); + }; + + this.$childProperty = "label"; + + + this.addEventListener("$skinchange", function(){ + if (this.label) + this.$propHandlers["label"].call(this, this.label); + }) + + + +}).call(apf.checkbox.prototype = new apf.BaseButton()); + +apf.aml.setElement("checkbox", apf.checkbox); + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * Element giving the user a visual choice to pick a color just like Photoshop + * does it! + * + * @constructor + * @define colorpicker + * + * + * @author Mike de Boer (mike AT javeline DOT com) + * @version %I%, %G% + * @since 3.0 + * + * @inherits apf.StandardBinding + * @inherits apf.DataAction + * + * @attribute {String} value the color that is selected in the color picker. + * + * @binding value Determines the way the value for the element is retrieved + * from the bound data. + * Example: + * Sets the color based on data loaded into this component. + * + * + * + * + * + * + */ +apf.colorpicker = function(struct, tagName) { + this.$init(tagName || "colorpicker", apf.NODE_VISIBLE, struct); +}; + +(function(){ + this.value = "ff0000"; + this.changeTimer = null; + + var c = apf.color; + + this.$supportedProperties.push("color", "red", "green", "blue", "hue", + "saturation", "brightness", "hex", "skin-textbox", "skin-spinner"); + + this.$propHandlers["red"] = + this.$propHandlers["green"] = + this.$propHandlers["blue"] = + this.$propHandlers["hue"] = + this.$propHandlers["saturation"] = + this.$propHandlers["brightness"] = + this.$propHandlers["hex"] = function(val, prop) { + if (this.$ignoreSetProperty) + return; + clearTimeout(this.changeTimer); + var _self = this; + this.changeTimer = $setTimeout(function() { + _self.$change(prop); + }); + }; + + this.$propHandlers["value"] = function(val) { + this.$restoreOriginal(); + }; + + this.$restoreOriginal = function() { + var hsb = c.hexToHSB(this.value); + this.hue = hsb.h; + this.saturation = hsb.s; + this.brightness = hsb.b; + this.$change(); + this.oCustomColor.style.backgroundColor = + (this.value.substr(0, 1) != "#" ? "#" : "") + this.value; + }; + + this.$change = function(prop) { + if (!prop || /hsb|hue|saturation|brightness/.test(prop)) { + prop = "hsb"; + var hsb = c.fixHSB({h: this.hue, s: this.saturation, b: this.brightness}); + var hex = c.HSBToHex(hsb); + var rgb = c.HSBToRGB(hsb); + } else if (/red|green|blue|rgb/.test(prop)) { + prop = "rgb"; + var rgb = c.fixRGB({r: this.red, g: this.green, b: this.blue}); + var hex = c.RGBToHex(rgb); + var hsb = c.RGBToHSB(rgb); + } else { + prop = "hex"; + var hex = c.fixHex(this.hex); + var hsb = c.hexToHSB(hex); + var rgb = c.hexToRGB(hex); + } + + this.oNewColor.style.backgroundColor = "#" + hex; + + this.$ignoreSetProperty = true; + if (prop != "rgb") { + this.setProperty("red", rgb.r); + this.setProperty("green", rgb.g); + this.setProperty("blue", rgb.b); + } + if (prop != "hsb") { + this.setProperty("hue", hsb.h); + this.setProperty("saturation", hsb.s); + this.setProperty("brightness", hsb.b); + } + if (prop != "hex") + this.setProperty("hex", hex); + this.$ignoreSetProperty = false; + + this.oSelector.style.background = "#" + c.HSBToHex({h: hsb.h, s: 100, b: 100}); + this.oHue.style.top = parseInt(150 - 150 * hsb.h / 360, 10) + "px"; + this.oSelectorInd.style.left = parseInt(150 * hsb.s / 100, 10) + "px"; + this.oSelectorInd.style.top = parseInt(150 * (100 - hsb.b) / 100, 10) + "px"; + }; + + this.$draw = function() { + if (!this.id) + this.setProperty("id", "colorpicker" + this.$uniqueId); + + //Build Main Skin + this.$ext = this.$getExternal(); + this.oSelector = this.$getLayoutNode("main", "selector", this.$ext); + this.oSelectorInd = this.$getLayoutNode("main", "selector_indic", this.$ext); + this.oHue = this.$getLayoutNode("main", "hue", this.$ext); + this.oNewColor = this.$getLayoutNode("main", "newcolor", this.$ext); + this.oCustomColor = this.$getLayoutNode("main", "customcolor", this.$ext); + this.oInputs = this.$getLayoutNode("main", "inputs", this.$ext); + + this.$restoreOriginal(); + + //attach behaviours + var _self = this, + doc = (!document.compatMode || document.compatMode == 'CSS1Compat') + ? document.html : document.body; + function stopMoving() { + document.onmousemove = document.onmouseup = null; + _self.$change(); + return false; + } + function selectorDown() { + var el = this, + pos = apf.getAbsolutePosition(el); + + function selectorMove(e) { + e = e || event; + var pageX = e.pageX || e.clientX + (doc ? doc.scrollLeft : 0), + pageY = e.pageY || e.clientY + (doc ? doc.scrollTop : 0); + // only the saturation and brightness change... + _self.brightness = parseInt(100 * (150 - Math.max(0, Math.min(150, + (pageY - pos[1])))) / 150, 10); + _self.saturation = parseInt(100 * (Math.max(0, Math.min(150, + (pageX - pos[0])))) / 150, 10); + _self.$change(); + pos = apf.getAbsolutePosition(el); + return false; + } + document.onmousemove = selectorMove; + document.onmouseup = function(e) { + selectorMove(e); + return stopMoving(e); + }; + } + + function hueDown(e) { + var el = this, + pos = apf.getAbsolutePosition(el); + + function hueMove(e) { + e = e || event; + var pageY = e.pageY || e.clientY + (doc ? doc.scrollTop : 0); + _self.hue = parseInt(360 * (150 - Math.max(0, + Math.min(150, (pageY - pos[1])))) / 150, 10); + _self.$change(); + pos = apf.getAbsolutePosition(el); + } + document.onmousemove = hueMove; + document.onmouseup = function(e) { + hueMove(e); + return stopMoving(e); + }; + } + this.oSelector.onmousedown = selectorDown; + this.oHue.parentNode.onmousedown = hueDown; + this.oCustomColor.onmousedown = function() { + _self.$restoreOriginal(); + }; + + function spinnerChange(e) { + var o = e.currentTarget; + var isRGB = false; + if (o.id.indexOf("hue") > -1) { + _self.hue = e.value; + } + else if (o.id.indexOf("saturation") > -1) { + _self.saturation = e.value; + } + else if (o.id.indexOf("brightness") > -1) { + _self.brightness = e.value; + } + else if (o.id.indexOf("red") > -1) { + _self.red = e.value; + isRGB = true; + } + else if (o.id.indexOf("green") > -1) { + _self.green = e.value; + isRGB = true; + } + else if (o.id.indexOf("blue") > -1) { + _self.blue = e.value; + isRGB = true; + } + + _self.$change(isRGB ? "red" : "hue"); + } + + //append APF widgets for additional controls + var skin = apf.getInheritedAttribute(this.parentNode, "skinset"); + new apf.hbox({ + htmlNode: this.oInputs, + skinset: skin, + left: 212, + top: 52, + width: 150, + padding: 3, + childNodes: [ + new apf.vbox({ + padding: 3, + edge: "0 10 0 0", + childNodes: [ + new apf.hbox({ + childNodes: [ + new apf.label({ + width: 14, + caption: "R:", + "for": this.id + "_red" + }), + new apf.spinner({ + id: this.id + "_red", + skin: this["skin-spinner"], + realtime: true, + width: 45, + min: 0, + max: 255, + value: "{" + this.id + ".red}", + onafterchange: spinnerChange + }) + ] + }), + new apf.hbox({ + edge: "0 0 3 0", + childNodes: [ + new apf.label({ + width: 14, + caption: "G:", + "for": this.id + "_green" + }), + new apf.spinner({ + id: this.id + "_green", + skin: this["skin-spinner"], + realtime: true, + width: 45, + min: 0, + max: 255, + value: "{" + this.id + ".green}", + onafterchange: spinnerChange + }) + ] + }), + new apf.hbox({ + edge: "0 0 3 0", + childNodes: [ + new apf.label({ + width: 14, + caption: "B:", + "for": this.id + "_blue" + }), + new apf.spinner({ + id: this.id + "_blue", + skin: this["skin-spinner"], + realtime: true, + width: 45, + min: 0, + max: 255, + value: "{" + this.id + ".blue}", + onafterchange: spinnerChange + }) + ] + }) + ] + }), + new apf.vbox({ + padding: 3, + childNodes: [ + new apf.hbox({ + childNodes: [ + new apf.label({ + width: 14, + caption: "H:", + "for": this.id + "_hue" + }), + new apf.spinner({ + id: this.id + "_hue", + skin: this["skin-spinner"], + realtime: true, + width: 45, + min: 0, + max: 360, + value: "{" + this.id + ".hue}", + onafterchange: spinnerChange + }) + ] + }), + new apf.hbox({ + edge: "0 0 3 0", + childNodes: [ + new apf.label({ + width: 14, + caption: "S:", + "for": this.id + "_saturation" + }), + new apf.spinner({ + id: this.id + "_saturation", + skin: this["skin-spinner"], + realtime: true, + width: 45, + min: 0, + max: 100, + value: "{" + this.id + ".saturation}", + onafterchange: spinnerChange + }) + ] + }), + new apf.hbox({ + edge: "0 0 3 0", + childNodes: [ + new apf.label({ + width: 14, + caption: "B:", + "for": this.id + "_brightness" + }), + new apf.spinner({ + id: this.id + "_brightness", + skin: this["skin-spinner"], + realtime: true, + width: 45, + min: 0, + max: 100, + value: "{" + this.id + ".brightness}", + onafterchange: spinnerChange + }) + ] + }) + ] + }) + ] + }); + + new apf.label({ + htmlNode: this.oInputs, + skinset: skin, + left: 212, + top: 144, + width: 14, + caption: "#", + "for": this.id + "_hex" + }); + + this.$input = new apf.textbox({ + htmlNode: this.oInputs, + skinset: skin, + skin: this["skin-textbox"], + mask: " + * + * + * Choice 1! + * Choice 2! + * + * + * + * The Netherlands + * United States of America + * Poland + * + * + * Right-click on the list to reveal the context menu! + * + * ``` + * + * @class apf.contextmenu + * @define contextmenu + * @inherits apf.AmlElement + * @selection + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.4 + */ +/** + * @attribute {String} menu Sets or gets the id of the menu element. + */ +/** + * @attribute {String} select Sets or gets the XPath executed on the selected element of the databound element which determines whether this context menu is shown. + * + * + */ +apf.contextmenu = function(){ + this.$init("contextmenu", apf.NODE_HIDDEN); +}; + +(function(){ + this.$amlNodes = []; + + //1 = force no bind rule, 2 = force bind rule + this.$attrExcludePropBind = apf.extend({ + "match" : 1 + }, this.$attrExcludePropBind); + + this.register = function(amlParent) { + if (!amlParent.contextmenus) + amlParent.contextmenus = []; + amlParent.contextmenus.push(this); + }; + + this.unregister = function(amlParent) { + amlParent.contextmenus.remove(this); + }; + + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + this.register(this.parentNode); + }); +}).call(apf.contextmenu.prototype = new apf.AmlElement()); + +apf.aml.setElement("contextmenu", apf.contextmenu); + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * This element provides a sortable, selectable grid containing scrollable + * information. The grid columns can be reordered and resized. + * + * #### Example + * + * ```xml, demo + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * ``` + * + * @class apf.datagrid + * @define datagrid + * @selection + * + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.4 + * + * @inherits apf.Cache + * @inherits apf.StandardBinding + * @inherits apf.Rename + * @inherits apf.MultiselectBinding + * + */ +/** + * @binding invalidmsg Determines the error message that is shown when a cell is not valid. + */ +/** + * @binding description Determines the text that is displayed under the expanded row. + */ +apf.datagrid = function(struct, tagName) { + this.$init(tagName || "datagrid", apf.NODE_VISIBLE, struct); + + this.$headings = [], + this.$cssRules = []; //@todo Needs to be reset; + this.$lastOpened = {}; + + this.$editors = {}; + + + this.$dynCssClasses = []; + +}; + +(function(){ + var treeState = this.$treeState; + + + this.implement( + apf.DataAction + ); + + + /*this.$init(function() { + this.addEventListener("keydown", keyHandler, true); + });*/ + + this.bufferselect = false; + this.$useTable = false; + this.$focussable = true; + this.$isWindowContainer = -1; + + this.$widthdiff = 0; + this.$defaultwidth = 0; + this.$useiframe = 0; + this.$needsDepth = true; + this.$fixed = 0; + + + this.canrename = false; //@todo remove rename from basetree and move to tree.js + + + /** + * @attribute {Boolean} iframe Sets or gets whether this element is rendered inside an iframe. This is only supported for IE. Default is `false` for datagrid and `true` for spreadsheet and propedit. + */ + this.$booleanProperties["iframe"] = true; + + + + /** + * @attribute {String} mode Sets or gets the way this element interacts with the user. + * + * Possible values include: + * + * - `check`: The user can select a single item from this element. The selected item is indicated. + * - `radio`: The user can select multiple items from this element. Each selected item is indicated. + */ + this.$mode = 0; + this.$propHandlers["mode"] = function(value) { + if ("check|radio".indexOf(value) > -1) { + if (!this.hasFeature(apf.__MULTICHECK__)) + this.implement(apf.MultiCheck); + + this.addEventListener("afterrename", $afterRenameMode); //what does this do? + + this.multicheck = value == "check"; //radio is single + this.$mode = this.multicheck ? 1 : 2; + } + else { + //@todo undo actionRules setting + this.removeEventListener("afterrename", $afterRenameMode); + //@todo unimplement?? + this.$mode = 0; + } + }; + + //@todo apf3.0 retest this completely + function $afterRenameMode(){ + } + + + + this.$propHandlers["options"] = function(value) { + for (var i = 0, l = this.$headings.length; i < l; i++) { + this.$headings[i].setAttribute("options", value); + } + }; + + function scrollIntoView(){ + var Q = (this.current || this.$selected), + o = this.$container; + o.scrollTop = (Q.offsetTop) - 21; + } + + // *** Keyboard Support *** // + + + /*function keyHandler(e) { + var key = e.keyCode, + ctrlKey = e.ctrlKey, + shiftKey = e.shiftKey, + selHtml = this.$selected || this.$caret; + + if (!e.force && (!selHtml || this.renaming)) //@todo how about allowdeselect? + return; + + var selXml = this.caret || this.selected, + oInt = this.$useiframe ? this.oDoc.documentElement : this.$container, + margin, node, hasScroll, hasScrollX, hasScrollY, items, lines; + + switch (key) { + case 13: + if (this.$tempsel) + this.$selectTemp(); + + this.choose(selHtml); + break; + case 32: + if (ctrlKey || !this.isSelected(this.caret)) + this.select(this.caret, true); + return false; + case 109: + case 46: + //DELETE + if (this.disableremove) + return; + + if (this.celledit) { + this.rename(this.caret || this.selected, ""); + return; + } + + if (this.$tempsel) + this.$selectTemp(); + + this.remove(this.mode ? this.caret : null); //this.mode != "check" + break; + case 36: + //HOME + this.$setTempSelected (this.getFirstTraverseNode(), false, shiftKey); + this.$container.scrollTop = 0; + return false; + case 35: + //END + this.$setTempSelected (this.getLastTraverseNode(), false, shiftKey); + this.$container.scrollTop = this.$container.scrollHeight; + return false; + case 107: + //+ + if (this.more) + this.startMore(); + break; + case 37: + //LEFT + if (this.$tempsel) + this.$selectTemp(); + + if (this.cellselect) { + if (this.$lastcell) { + if (this.$lastcell.previousSibling) { + this.selectCell({target:this.$lastcell.previousSibling}, + this.$selected); + } + } + else { + this.selectCell({target:this.$selected.firstChild}, + this.$selected); + } + } + else if (this.$withContainer) + this.slideToggle(this.$caret || this.$selected, 2) + return false; + case 107: + case 39: + //RIGHT + if (this.$tempsel) + this.$selectTemp(); + + if (this.cellselect) { + if (this.$lastcell) { + if (this.$lastcell.nextSibling) { + this.selectCell({target:this.$lastcell.nextSibling}, + this.$selected); + } + } + else { + this.selectCell({target:this.$selected.firstChild}, + this.$selected); + } + } + else if (this.$withContainer) + this.slideToggle(this.$caret || this.$selected, 1) + + return false; + case 38: + //UP + if (!selXml && !this.$tempsel) + return false; + + node = this.$tempsel + ? apf.xmldb.getNode(this.$tempsel) + : selXml; + + margin = apf.getBox(apf.getStyle(selHtml, "margin")); + hasScroll = oInt.scrollHeight > oInt.offsetHeight; + items = Math.floor((oInt.offsetWidth + - (hasScroll ? 15 : 0)) / (selHtml.offsetWidth + + margin[1] + margin[3])); + + node = this.getNextTraverseSelected(node, false, items); + if (node) + this.$setTempSelected (node, ctrlKey, shiftKey); + else + return false; + + selHtml = apf.xmldb.findHtmlNode(node, this); + if (selHtml.offsetTop <= oInt.scrollTop) { + oInt.scrollTop = (Array.prototype.indexOf.call(this.getTraverseNodes(), node) < items + ? 0 + : selHtml.offsetTop - margin[0]) + - parseInt(apf.getStyle(oInt, "paddingTop")); + } + return false; + case 40: + //DOWN + if (!selXml && !this.$tempsel) + return false; + + node = this.$tempsel + ? apf.xmldb.getNode(this.$tempsel) + : selXml; + + margin = apf.getBox(apf.getStyle(selHtml, "margin")); + hasScroll = oInt.scrollHeight > oInt.offsetHeight; + items = Math.floor((oInt.offsetWidth + - (hasScroll ? 15 : 0)) / (selHtml.offsetWidth + + margin[1] + margin[3])); + + node = this.getNextTraverseSelected(node, true, items); + if (node) + this.$setTempSelected (node, ctrlKey, shiftKey); + else + return false; + + selHtml = apf.xmldb.findHtmlNode(node, this); + if (selHtml.offsetTop + selHtml.offsetHeight + > oInt.scrollTop + oInt.offsetHeight) // - (hasScroll ? 10 : 0) + oInt.scrollTop = selHtml.offsetTop + - oInt.offsetHeight + selHtml.offsetHeight + + margin[0]; //+ (hasScroll ? 10 : 0) + + return false; + case 33: + //PGUP + if (!selXml && !this.$tempsel) + return false; + + node = this.$tempsel + ? apf.xmldb.getNode(this.$tempsel) + : selXml; + + margin = apf.getBox(apf.getStyle(selHtml, "margin")); + hasScrollY = oInt.scrollHeight > oInt.offsetHeight; + hasScrollX = oInt.scrollWidth > oInt.offsetWidth; + items = Math.floor((oInt.offsetWidth + - (hasScrollY ? 15 : 0)) / (selHtml.offsetWidth + + margin[1] + margin[3])) || 1; + lines = Math.floor((oInt.offsetHeight + - (hasScrollX ? 15 : 0)) / (selHtml.offsetHeight + + margin[0] + margin[2])); + + node = this.getNextTraverseSelected(node, false, items * lines); + if (!node) + node = this.getFirstTraverseNode(); + if (node) + this.$setTempSelected (node, ctrlKey, shiftKey); + else + return false; + + selHtml = apf.xmldb.findHtmlNode(node, this); + if (selHtml.offsetTop < oInt.scrollTop) { + oInt.scrollTop = (Array.prototype.indexOf.call(this.getTraverseNodes(), node) < items + ? 0 + : selHtml.offsetTop - margin[0]) + - parseInt(apf.getStyle(oInt, "paddingTop")); + } + return false; + case 34: + //PGDN + if (!selXml && !this.$tempsel) + return false; + + node = this.$tempsel + ? apf.xmldb.getNode(this.$tempsel) + : selXml; + + margin = apf.getBox(apf.getStyle(selHtml, "margin")); + hasScrollY = oInt.scrollHeight > oInt.offsetHeight; + hasScrollX = oInt.scrollWidth > oInt.offsetWidth; + items = Math.floor((oInt.offsetWidth - (hasScrollY ? 15 : 0)) + / (selHtml.offsetWidth + margin[1] + margin[3])) || 1; + lines = Math.floor((oInt.offsetHeight - (hasScrollX ? 15 : 0)) + / (selHtml.offsetHeight + margin[0] + margin[2])); + + node = this.getNextTraverseSelected(selXml, true, items * lines); + if (!node) + node = this.getLastTraverseNode(); + if (node) + this.$setTempSelected (node, ctrlKey, shiftKey); + else + return false; + + selHtml = apf.xmldb.findHtmlNode(node, this); + if (selHtml.offsetTop + selHtml.offsetHeight + > oInt.scrollTop + oInt.offsetHeight) // - (hasScrollY ? 10 : 0) + oInt.scrollTop = selHtml.offsetTop + - oInt.offsetHeight + selHtml.offsetHeight + + margin[0]; //+ 10 + (hasScrollY ? 10 : 0) + return false; + default: + if (this.celledit) { + if (!ctrlKey && !e.altKey && (key > 46 && key < 112 || key > 123)) + this.startRename(null, true); + return; + } + else if (key == 65 && ctrlKey) { + this.selectAll(); + return false; + } + //@todo make this work with the sorted column + else if (this.caption || (this.bindingRules || {})["caption"]) { + if (!this.xmlRoot) return; + + //this should move to a onkeypress based function + if (!this.lookup || new Date().getTime() + - this.lookup.date.getTime() > 300) + this.lookup = { + str: "", + date: new Date() + }; + + this.lookup.str += String.fromCharCode(key); + + var nodes = this.getTraverseNodes(); //@todo start at current indicator + for (var v, i = 0; i < nodes.length; i++) { + v = this.$applyBindRule("caption", nodes[i]); + if (v && v.substr(0, this.lookup.str.length) + .toUpperCase() == this.lookup.str) { + + if (!this.isSelected(nodes[i])) { + if (this.mode == "check") + this.setCaret(nodes[i]); + else + this.select(nodes[i]); + } + + if (selHtml) + this.$container.scrollTop = selHtml.offsetTop + - (this.$container.offsetHeight + - selHtml.offsetHeight) / 2; + return; + } + } + return; + } + break; + }; + + this.lookup = null; + //return false; + }*/ + + + + // *** Focus *** // + // Too slow for IE + + + this.$getCaptionElement = function(){ + if (!this.$selected) + return false; + + var nodes = this.$head.childNodes, + htmlNodes = this.$selected.childNodes, i = 0; + + nodeIter = htmlNodes[i]; + while (nodeIter) { + if (nodeIter.nodeType != 1) { + nodeIter = nodeIter.nextSibling; + continue; + } + + h = apf.all[nodes[i].getAttribute("hid")]; + if (h.tree || h.rename) + return this.$getLayoutNode(h.tree ? "treecell" : "cell", "caption", nodeIter) || nodeIter; + + i++; + nodeIter = nodeIter.nextSibling; + } + + throw new Error("Datagrid without rename column specified"); + }; + + + this.$focus = function(){ + if (!this.$ext || (apf.isIE && this.$useiframe && this.cssfix)) //@todo fix this by fixing focussing for this component + return; + + this.$setStyleClass(this.$ext, this.$baseCSSname + "Focus"); + + if (this.oDoc) + this.$setStyleClass(this.oDoc.documentElement, this.$baseCSSname + "Focus"); + }; + + this.$blur = function(){ + //@todo fix this by fixing focussing for this component + if (!this.$ext || (apf.isIE && this.$useiframe && this.cssfix)) + return; + + this.$setStyleClass(this.$ext, "", [this.$baseCSSname + "Focus"]); + + if (this.oDoc) + this.$setStyleClass(this.oDoc.documentElement, "", [this.$baseCSSname + "Focus"]); + + hideEditor.call(this); + }; + + // *** Databinding *** // + + this.addEventListener("bindingsload", this.$loaddatabinding = function(e) { + var rules = e.bindings["column"]; + if (!rules || !rules.length) + return; + + this.$cssRules = []; + this.$headings = rules; + + this.clearAllCache(); + + var fixed = 0, found = false; + for (var h, i = 0, l = rules.length; i < l; i++) { + h = rules[i]; + + + + if (h.visible !== false) { + if (!h.$isPercentage) + fixed += parseFloat(h.$width) || 0; + else + found = true; + } + } + + if (!found) { //@todo removal??? + this.$isFixedGrid = true; + this.$setStyleClass(this.$ext, "fixed"); + + if (this.$useiframe) + this.$setStyleClass(this.oDoc.documentElement, "fixed"); + } + else { + //@todo remove + } + + if (fixed > 0 && !this.$isFixedGrid) { + var vLeft = fixed; + + //first column has total -1 * fixed margin-left. - 5 + //cssRules[0][1] += ";margin-left:-" + vLeft + "px;"; + //cssRules[1][1] += ";margin-left:-" + vLeft + "px;"; + this.$cssRules.push(["." + this.$baseCSSname + " .row" + this.$uniqueId, + "padding-right:" + vLeft + "px;"]); //margin-right:-" + vLeft + "px + + //headings and records have same padding-right + this.$container.style.paddingRight = (vLeft - 1) + "px"; + this.$head.style.paddingRight = (vLeft - 2) + "px"; + } + + this.$fixed = fixed; + this.$first = 0; + + this.$withContainer = e.bindings.description ? true : false; + + //Activate CSS Rules + apf.importStylesheet(this.$cssRules, window); + + if (this.$useiframe) + apf.importStylesheet(this.$cssRules, this.oWin); + }); + + this.$initNode = function(xmlNode, state, Lid, depth) { + //Build Row + this.$getNewContext("item"); + var oRow = this.$getLayoutNode("item"); + oRow.setAttribute("id", Lid); + + //@todo if treearch + oRow.setAttribute("class", oRow.getAttribute("class") + " " + + treeState[state] + " item" + this.$uniqueId);//"width:" + (totalWidth+40) + "px"); + this.$setStyleClass(this.$getLayoutNode("item", "container"), treeState[state]) + + oRow.setAttribute("ondblclick", 'var o = apf.lookup(' + this.$uniqueId + ');o.choose(null, true);' + + (this.$withContainer ? 'o.slideToggle(this, null, true);' : '') + + (this.celledit && !this.namevalue ? 'o.startRename(null, null, true);' : '')); + + if (this.hasFeature(apf.__DRAGDROP__)) { + oRow.setAttribute("onmouseout", 'this.hasPassedDown = false;'); + oRow.setAttribute("onmousedown", 'var o = apf.lookup(' + this.$uniqueId + ');\ + var xmlNode = apf.xmldb.findXmlNode(this);\ + var isSelected = o.isSelected(xmlNode);\ + this.hasPassedDown = true;\ + if (!o.hasFeature(apf.__DRAGDROP__) || !isSelected && !apf.getCtrlKey(event))\ + o.select(this, apf.getCtrlKey(event), event.shiftKey, -1);' + + (this.cellselect || this.namevalue ? 'o.selectCell(event, this, isSelected);' : '')); + + oRow.setAttribute("onmouseup", 'if (!this.hasPassedDown) return;\ + var o = apf.lookup(' + this.$uniqueId + ');\ + var xmlNode = apf.xmldb.findXmlNode(this);\ + var isSelected = o.isSelected(xmlNode);\ + if (o.hasFeature(apf.__DRAGDROP__))\ + o.select(this, apf.getCtrlKey(event), event.shiftKey, -1);'); + } //@todo add DRAGDROP ifdefs + else { + oRow.setAttribute("onmousedown", 'var o = apf.lookup(' + this.$uniqueId + ');\ + var wasSelected = o.$selected == this;\ + o.select(this, apf.getCtrlKey(event), event.shiftKey, -1);' + + (this.cellselect || this.namevalue ? 'o.selectCell(event, this, wasSelected);' : '')); + } + + //Build the Cells + for (var cellType, cell, h, i = 0; i < this.$headings.length; i++) { + h = this.$headings[i]; + + if (h.tree && h.check) { + cellType = "treecheckcell"; + + this.$getNewContext("treecheckcell"); + cell = this.$getLayoutNode("treecheckcell"); + var oc = this.$getLayoutNode("treecheckcell", "openclose"); + oc.setAttribute("style", "margin-left:" + (((depth||0)) * 15 + 4) + "px;"); + oc.setAttribute("onmousedown", + "var o = apf.lookup(" + this.$uniqueId + ");\ + o.slideToggle(this, null, null, true);\ + event.cancelBubble = true;\ + apf.window.$mousedown(event);"); + + oc.setAttribute("ondblclick", "event.cancelBubble = true"); + } + else if (h.tree) { + cellType = "treecell"; + + this.$getNewContext("treecell"); + cell = this.$getLayoutNode("treecell"); + var oc = this.$getLayoutNode("treecell", "openclose"); + oc.setAttribute("style", "margin-left:" + (((depth||0)) * 15 + 4) + "px;"); + oc.setAttribute("onmousedown", + "var o = apf.lookup(" + this.$uniqueId + ");\ + o.slideToggle(this, null, null, true);\ + event.cancelBubble = true;\ + apf.window.$mousedown(event);"); + + oc.setAttribute("ondblclick", "event.cancelBubble = true"); + + /*cell.setAttribute("style", "background-position: " + + ((((depth||0)+1) * 15) - 10) + "px 50%");*/ + } + else { + + cellType = h.check ? "checkcell" : "cell"; + + + this.$getNewContext(cellType); + cell = this.$getLayoutNode(cellType); + } + + + if (this.$mode && h.check) { + var elCheck = this.$getLayoutNode(cellType, "check"); + if (elCheck) { + elCheck.setAttribute("onmousedown", + "var o = apf.lookup(" + this.$uniqueId + ");\ + o.checkToggle(this, true);\o.$skipSelect = true;"); + + if (apf.isTrue(this.$applyBindRule("checked", xmlNode))) { + this.$checkedList.push(xmlNode); + this.$setStyleClass(oRow, "checked"); + } + else if (this.isChecked(xmlNode)) + this.$setStyleClass(oRow, "checked"); + } + else { + + return false; + } + } + + + apf.setStyleClass(cell, h.$className); + + if (h.css) + apf.setStyleClass(cell, (apf.lm.compile(h.css, {nostring: true}))(xmlNode)); //@todo cashing of compiled function? + + if (h.icon) { + var node = this.$getLayoutNode(cellType, "caption", oRow.appendChild(cell)); + node = (node.nodeType == 1 && node || node.parentNode); + node.setAttribute("style", "background-image:url(" + + apf.getAbsolutePath(this.iconPath, + ((h.cicon || h.$compile("icon", {nostring: true}))(xmlNode) || "")) + + ");"); + this.$setStyleClass(node, "iconCell", []); + } + + if (h.value) { + if (!h.cvalue2) { + h.$compile("value", {nostring: true}); + + + } + + + { + apf.setNodeValue(this.$getLayoutNode(cellType, + "caption", oRow.appendChild(cell)), + h.cvalue2(xmlNode) || ' '); + } + } + } + + if (this.$bindings && this.$bindings.color) { + var colorRule = this.$getDataNode("color", xmlNode); + this.$setStyleClass(oRow, colorRule ? "highlight" : null, colorRule ? ["highlight"] : null); + } + + + var cssClass = this.$applyBindRule("css", xmlNode); + if (cssClass) { + this.$setStyleClass(oRow, cssClass); + if (cssClass) + this.$dynCssClasses.push(cssClass); + } + + + /*if (this.$withContainer) { + var desc = this.$applyBindRule("description", xmlNode); + this.$getNewContext("container"); + var oDesc = this.$getLayoutNode("container"); + apf.setNodeValue(this.$getLayoutNode("container", "container", + oDesc), desc); + oDesc.setAttribute("class", (oDesc.getAttribute("class") || "") + + " row" + this.$uniqueId); + + if (htmlParentNode) + apf.insertHtmlNode(oDesc, htmlParentNode, beforeNode); + else + this.$nodes.push(oDesc); + }*/ + + return oRow; + }; + + this.$updateNode = function(xmlNode, htmlNode) { + if (!htmlNode) return; + + var nodes = this.$head.childNodes, + htmlNodes = htmlNode.childNodes, + cell, p; + + if (!this.namevalue && this.$curBtn) + p = this.$curBtn.parentNode; + + var nodeIter, h, i = 0; + nodeIter = htmlNodes[0]; + while (nodeIter) { + if (nodeIter.nodeType != 1) { + nodeIter = nodeIter.nextSibling; + continue; + } + + h = apf.all[nodes[i].getAttribute("hid")]; + + //@todo fake optimization + cell = this.$getLayoutNode(h.tree ? "treecell" : "cell", "caption", nodeIter) || nodeIter;//htmlNodes[i].firstChild || + + if (h.css) + apf.setStyleClass(cell, (apf.lm.compile(h.css, {nostring: true}))(xmlNode)); //@todo cashing of compiled function? + + if (h.tree) { + + //@todo + + + /*var oc = this.$getLayoutNode("treecell", "openclose", cell); + oc.setAttribute("style", "margin-left:" + (((depth||0)) * 15 + 4) + "px;"); + oc.setAttribute("onmousedown", + "var o = apf.lookup(" + this.$uniqueId + ");\ + o.slideToggle(this, null, null, true);");*/ + } + + if (h.value) { + if (!h.cvalue2) { + h.$compile("value", {nostring: true}); + + + } + + + cell.innerHTML = h.cvalue2(xmlNode) || " "; + } + + if (h.icon) { + (cell.nodeType == 1 && cell || cell.parentNode).style.backgroundImage = + "url(" + apf.getAbsolutePath(this.iconPath, + ((h.cicon || h.$compile("icon", {nostring: true}))(xmlNode) || "")) + + ")"; + } + + i++; + nodeIter = nodeIter.nextSibling; + } + + //return; //@todo fake optimization + + if (this.$bindings && this.$bindings.color) { + var colorRule = this.$getDataNode("color", xmlNode); + this.$setStyleClass(htmlNode, colorRule ? "highlight" : null, + colorRule ? ["highlight"] : null); + } + + + var cssClass = this.$applyBindRule("css", xmlNode); + if (cssClass || this.$dynCssClasses.length) { + this.$setStyleClass(htmlNode, cssClass, this.$dynCssClasses); + if (cssClass && !this.$dynCssClasses.contains(cssClass)) + this.$dynCssClasses.push(cssClass); + } + + + /*if (this.$withContainer) { + htmlNode.nextSibling.innerHTML + = this.$applyBindRule("description", xmlNode) || ""; + }*/ + }; + + this.$dblclick = function(htmlNode) { + var _self = this, id, cell; + while (!(id = htmlNode.getAttribute(apf.xmldb.htmlIdTag)) || id.indexOf("|") == -1) { + htmlNode = (cell = htmlNode).parentNode; + if (!htmlNode || htmlNode.nodeType != 1) + return; + } + + if (this.$lastEditor && this.$lastEditor[3] == htmlNode) + return; + + var h, colId = cell.className.match(/(col\d+)/)[1]; + for (var i = 0; i < this.$headings.length; i++) { + if (this.$headings[i].$className == colId) { + h = this.$headings[i]; + break; + } + } + + if (!h.editor) //No editor specified + return; + + if (this.dispatchEvent("beforeEdit", {heading: h}) === false) + return; + + /*if (this.$lastEditor) { + //this.$lastEditor[0].$blur(); + this.$lastEditor[0].setProperty("visible", false); + + var nodes = this.$lastEditor[1].childNodes; + for (var i = 0, l = nodes.length; i < l; i++) { + if (!nodes[i].host) + nodes[i].style.display = ""; + } + }*/ + + var xmlNode = apf.xmldb.getNode(htmlNode); + /* + - editor (name of widget, lm function returning amlNode or lm template ref) + - children being aml nodes + */ + var editParent = h.tree + ? this.$getLayoutNode("cell", "caption", cell) + : cell; + + var oEditor, editor = h.editor; + var ceditor = apf.lm.compile(editor, {xpathmode: 2}); //@todo can this be more efficient? + + var nodes = editParent.childNodes; + for (var i = 0, l = nodes.length; i < l; i++) { + if (!nodes[i].host) { + if (nodes[i].nodeType == 1) + nodes[i].style.display = "none"; + else { + this.$lastTextValue = nodes[i].nodeValue; + nodes[i].nodeValue = ""; //@todo + } + } + } + + if (ceditor.type == 2) { + if (!this.$editors[h.$uniqueId + ":" + editor]) { + var constr = apf.namespaces[apf.ns.aml].elements[editor]; + var info = { + htmlNode: editParent, + style: "position:relative;z-index:10000", + value: "[{" + this.id + ".selected}::" + + (v = (h.match || h.value)).substr(1, v.length - 2) //only xpath value's supported for now + + "]", + focussable: false + }; + + if (h.tree) + info.width = "100% - " + (editParent.offsetLeft + parseInt(this.$getOption("treecell", "editoroffset"))); + else + info.width = "100%"; + + //@todo copy all non-known properties of the prop element + + if (constr.prototype.hasFeature(apf.__MULTISELECT__)) { + info.caption = h.eachcaption || "[text()]"; + info.eachvalue = h.eachvalue; // || "[@value]"; + + var model; + if (model = h.getAttribute("model")) { + info.model = model; + info.each = h.each; + } + else { + /*var each = h.each; + if (each.charAt(0) == "[") + each = each.substr(1, each.length - 2); + info.each = "[{" + this.id + ".selected}::" + each + "]";*/ + info.model = "{" + this.id + ".selected}" + info.each = h.each; + } + } + + if (h.skin) + info.skin = h.skin; + if (h["class"]) + info["class"] = h["class"]; + if (h.fill) + info.fill = h.fill; + + oEditor = this.$editors[h.$uniqueId + ":" + editor] = new constr(info); + + var box = apf.getBox(apf.getStyle(oEditor.$ext, "margin")); + if (box[1] || box[3]) { + oEditor.setAttribute("width", "100%+2-" + (box[1] + box[3])); + } + //else if (!box[3]) + //oEditor.$ext.style.marginLeft = "-1px"; + + //oEditor.$focussable = false; + oEditor.addEventListener("blur", function(){ + hideEditor.call(_self); + }); + oEditor.parentNode = this; + oEditor.realtime = false; + oEditor.$focusParent = this; + oEditor.setAttribute("focussable", "true"); + //delete oEditor.parentNode; + + oEditor.addEventListener("keyup", function(e) { + if (e.keyCode == 13) { + hideEditor.call(_self); + _self.$focus(); + } + else if (e.keyCode == 27) { + oEditor.removeAttribute("value"); //@todo this bugs in slider + hideEditor.call(_self); + //_self.getActionTracker().undo(); + } + }); + + //@todo set actiontracker + + //Patch oEditor to forward change + oEditor.$executeAction = function(){ + this.parentNode.$executeAction.apply(this.parentNode, arguments); + } + + this.dispatchEvent("editor.create", { + editor: oEditor + }); + } + else { + oEditor = this.$editors[h.$uniqueId + ":" + editor]; + + if (oEditor.hasFeature(apf.__MULTISELECT__) && !h.model) { + //oEditor.setAttribute("model", "{" + this.id + ".selected}"); + /*var each = h.each; + if (each.charAt(0) == "[") + each = each.substr(1, each.length - 2); + oEditor.setAttribute("each", "[{" + this.id + ".selected}::" + each + "]");*/ + /*apf.queue.empty();*/ + oEditor.setAttribute("value", "[{" + this.id + ".selected}::" + + (v = h.value).substr(1, v.length - 2) + + "]"); + } + else { + oEditor.setAttribute("value", "[{" + this.id + ".selected}::" + + (v = (h.match || h.value)).substr(1, v.length - 2) + + "]"); + } + + oEditor.setProperty("visible", true); + editParent.appendChild(oEditor.$ext); + + oEditor.setAttribute("width", h.tree + ? "100% - " + (editParent.offsetLeft + parseInt(this.$getOption("treecell", "editoroffset"))) + : "100%"); + } + + /*setTimeout(function(){ + oEditor.focus(); + });*/ + } + else { + //Create dropdown + + var obj = ceditor.call(this, this.xmlRoot); + if (obj.localName == "template") { + //add template contents to dropped area + } + else { + //add xml into dropped area + } + } + + if (oEditor.localName == "textbox") + oEditor.select(); + + oEditor.focus(); + oEditor.$focus(); + + this.$setStyleClass(htmlNode, "editing"); + + this.$lastEditor = [oEditor, editParent, xmlNode, htmlNode, this.getActionTracker().undolength]; + } + + this.addEventListener("mousedown", function(e) { + if (this.$lastEditor + && !apf.isChildOf(this.$lastEditor[1], + e.htmlEvent.srcElement || e.htmlEvent.target, true)) + hideEditor.call(this); + }); + + var hideEditor = function(e) { + if (this.$lastEditor) { + var ed = this.$lastEditor; + this.$lastEditor = null; + + if (ed[0].hasFeature(apf.__MULTISELECT__)) // && !ed[0].model + ed[0].$clearDynamicProperty("value"); + + //this.$lastEditor[0].$blur(); + ed[0].setProperty("visible", false); + + var nodes = ed[1].childNodes; + for (var i = 0, l = nodes.length; i < l; i++) { + if (!nodes[i].host) { + if (nodes[i].nodeType == 1) + nodes[i].style.display = ""; + else if (!ed[0].value || ed[0].value == this.$lastTextValue) { + nodes[i].nodeValue = this.$lastTextValue; //@todo + } + } + } + + this.$setStyleClass(ed[3], "", ["editing"]); + + this.focus(); + } + }; + this.addEventListener("beforeselect", hideEditor); + + // *** Column management *** // + + /** + * Returns a column definition object based on the column number. + * @param {Number} nr The heading number; this number is based on the sequence of the column elements. + */ + this.getColumn = function(nr) { + return this.$headings[nr || this.$lastcol || 0]; + }; + + /** + * Resizes a column. + * @param {Number} nr The heading number; this number is based on the sequence of the column elements. + * @param {Number} newsize The new size of the column. + * + */ + this.resizeColumn = function(nr, newsize){ // @todo optimize but bringing down the string concats + var h = this.$headings[nr]; + h.resize(newsize); + }; + + /** + * Hides a column. + * @param {Number} nr The heading number; this number is based on the sequence of the column elements. + */ + this.hideColumn = function(nr) { + var h = this.$headings[nr]; + h.hide(); + }; + + /** + * Shows a hidden column. + * @param {Number} nr The heading number; this number is based on the sequence of the column elements. + */ + this.showColumn = function(nr) { + var h = this.$headings[nr]; + h.show(); + }; + + /** + * Sorts a column. + * @param {Number} hid The heading number; this number is based on the sequence of the column elements. + */ + this.sortColumn = function(hid) { + var h = this.$headings[nr]; + h.sort(); + }; + + /** + * Moves a column to another position. + * @param {Number} from The heading number of the column to move; this number is based on the sequence of the column elements. + * @param {Number} to The position to move the column to + */ + this.moveColumn = function(from, to) { + var h = this.$headings[nr]; + h.move(to); + } + + // *** Init *** // + + this.$draw = function(){ + this.$drawBase(); + + var _self = this; + this.$ext.onmousedown = function(e) { + _self.dispatchEvent("mousedown", {htmlEvent: e || event}); + } + + //@todo rename 'body' to 'container' + + //Build Main Skin + this.$head = this.$getLayoutNode("main", "head", this.$ext); + this.$pointer = this.$getLayoutNode("main", "pointer", this.$ext); + + if (this.$head.firstChild) + this.$head.removeChild(this.$head.firstChild); + if (this.$container.firstChild) + this.$container.removeChild(this.$container.firstChild); + + var widthdiff = this.$widthdiff = this.$getOption("main", "widthdiff") || 0; + this.$defaultwidth = this.$getOption("main", "defaultwidth") || "100"; + this.$useiframe = apf.isIE && (apf.isTrue(this.$getOption("main", "iframe")) || this.iframe); + + //Initialize Iframe + if (this.$useiframe && !this.oIframe) { + //this.$container.style.overflow = "hidden"; + //var sInt = this.$container.outerHTML + var sClass = this.$container.className; + //this.$container.parentNode.removeChild(this.$container); + this.oIframe = this.$container.appendChild(document.createElement(apf.isIE + ? "" + : "iframe")); + this.oIframe.frameBorder = 0; + this.oWin = this.oIframe.contentWindow; + this.oDoc = this.oWin.document; + this.oDoc.write('\ + \ + \ + \ + \ + '); + //Import CSS + //this.oDoc.body.innerHTML = sInt; + this.$container = this.oDoc.body;//.firstChild; + this.$container.className = sClass;//this.oIframe.parentNode.className; + this.oDoc.documentElement.className = this.$ext.className; + //this.oDoc.body.className = this.$ext.className; + + apf.skins.loadCssInWindow(this.skinName, this.oWin, this.mediaPath, this.iconPath); + + if (apf.isIE) //@todo this can be removed when focussing is fixed for this component + this.$setStyleClass(this.oDoc.documentElement, this.$baseCSSname + "Focus"); + + apf.convertIframe(this.oIframe, true); + + if (apf.getStyle(this.oDoc.documentElement, "overflowY") == "auto") { + //@todo ie only + this.oIframe.onresize = function(){ + _self.$head.style.marginRight = + _self.oDoc.documentElement.scrollHeight > _self.oDoc.documentElement.offsetHeight + ? "16px" : "0"; + } + + this.addEventListener("afterload", this.oIframe.onresize); + this.addEventListener("xmlupdate", this.oIframe.onresize); + } + + this.oDoc.documentElement.onscroll = + function(){ + if (_self.$isFixedGrid) + _self.$head.scrollLeft = _self.oDoc.documentElement.scrollLeft; + }; + } + else { +// if (apf.getStyle(this.$container, "overflowY") == "auto") { +// this.$resize = function(){ +// _self.$head.style.marginRight = +// _self.$container.scrollHeight > _self.$container.offsetHeight +// ? "16px" : "0"; +// } +// +// +// apf.layout.setRules(this.$ext, this.$uniqueId + "_datagrid", +// "var o = apf.all[" + this.$uniqueId + "];\ +// if (o) o.$resize()"); +// apf.layout.queue(this.$ext); +// +// +// this.addEventListener("afterload", this.$resize); +// this.addEventListener("xmlupdate", this.$resize); +// } + + this.$container.onscroll = + function(){ + if (_self.$isFixedGrid) + _self.$head.scrollLeft = _self.$container.scrollLeft; + }; + } + + this.$container[this.clickedit ? "onmousedown" : "ondblclick"] = function(e) { + if (!e) e = event; + _self.$dblclick(e.srcElement || e.target); + } + }; + + this.$destroy = function(){ + //@todo destroy this.$txt here + + this.$ext.onclick = this.$container.onresize = null; + + + apf.layout.removeRule(this.$container, "dg" + this.$uniqueId); + apf.layout.activateRules(this.$container); + + }; +}).call(apf.datagrid.prototype = new apf.BaseTree()); + +apf.aml.setElement("datagrid", apf.datagrid); +//apf.aml.setElement("column", apf.BindingRule); +apf.aml.setElement("description", apf.BindingRule); +apf.aml.setElement("color", apf.BindingRule); +apf.aml.setElement("contents", apf.BindingRule); + + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +/** + * Element displaying a divider. For use in toolbars, menus, and such. + * @class apf.divider + * @define divider + * @inherits apf.Presentation + */ +apf.divider = function(struct, tagName) { + this.$init(tagName || "divider", apf.NODE_VISIBLE, struct); +}; + +(function() { + this.$focussable = false; + + this.minwidth = 0; + this.minheight = 0; + + this.implement(apf.ChildValue); + this.$childProperty = "caption"; + + //@todo apf3.0 fix this + this.addEventListener("AMLReparent", function(beforeNode, pNode, withinParent) { + if (!this.$amlLoaded) + return; + + if (!withinParent && this.skinName != pNode.skinName) { + //@todo for now, assuming dom garbage collection doesn't leak + this.loadAml(); + } + }); + + /** + * @attribute {String} caption the text displayed in the area defined by this + * element. + */ + this.$supportedProperties.push("caption", "value", "for", "textalign"); + this.$propHandlers["caption"] = function(value) { + if (this.$caption) { + this.$setStyleClass(this.$ext, this.$baseCSSname + "Caption"); + this.$caption.innerHTML = value; + } + else { + this.$setStyleClass(this.$ext, "", [this.$baseCSSname + "Caption"]); + } + }; + + this.$canLeechSkin = true; + + /** + * @private + */ + this.$draw = function() { + if (this.parentNode.isPaged && this.parentNode.$buttons) + this.$pHtmlNode = this.parentNode.$buttons; + + if (this.$isLeechingSkin) { + this.$ext = apf.insertHtmlNode( + this.parentNode.$getLayoutNode("divider"), this.$pHtmlNode); + } + else { + this.$ext = this.$getExternal("main"); + this.$caption = this.$getLayoutNode("main", "caption", this.$ext); + } + }; +}).call(apf.divider.prototype = new apf.Presentation); + +apf.aml.setElement("divider", apf.divider); + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * An element allowing a user to select a value from a list, which is + * displayed when the user clicks a button. + * + * #### Example: Simple Dropdown + * + * ```xml, demo + * + * + * + * America + * Armenia + * The Netherlands + * + * + * + * ``` + * + * #### Example: Loading Items From XML + * + * ```xml, demo + * + * + * + * + * + * ``` + * + * #### Example: Capturing and Emitting Events + * + * A databound dropdown using the bindings element + * + * ```xml, demo + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * Slide Down + * Slide Up + * + * + * + * ``` + * + * #### Example: Dynamically Adding Entries + * + * ```xml, demo + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * New Name? + * + * + * ``` + * + * @class apf.dropdown + * @define dropdown + * @form + * @allowchild item, {smartbinding} + * + * + * @inherits apf.BaseList + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.4 + */ +/** + * @event slidedown Fires when the dropdown slides open. + * @cancelable Prevents the dropdown from sliding open + */ +/** + * @event slideup Fires when the dropdown slides up. + * @cancelable Prevents the dropdown from sliding up + * + */ +apf.dropdown = function(struct, tagName) { + this.$init(tagName || "dropdown", apf.NODE_VISIBLE, struct); +}; + +(function(){ + this.$animType = 1; + this.$animSteps = 5; + this.$animSpeed = 20; + this.$itemSelectEvent = "onmouseup"; + + // *** Properties and Attributes *** // + + this.dragdrop = false; + this.reselectable = true; + this.$focussable = apf.KEYBOARD; + this.autoselect = false; + this.multiselect = false; + this.disableremove = true; + this.delayedselect = false; + this.maxitems = 5; + + this.$booleanProperties["disableremove"] = true; + this.$supportedProperties.push("maxitems", "disableremove", + "initial-message", "fill"); + + /** + * @attribute {String} initial-message Sets or gets the message displayed by this element + * when it doesn't have a value set. This property is inherited from parent + * nodes. When none is found it is looked for on the appsettings element. + * + */ + /** + * @attribute {Number} maxitems Sets or gets the number of items that are shown at the + * same time in the container. + */ + this.$propHandlers["maxitems"] = function(value) { + this.sliderHeight = value + ? (Math.min(this.maxitems || 100, value) * this.itemHeight) + : 10; + this.containerHeight = value + ? (Math.min(this.maxitems || 100, value) * this.itemHeight) + : 10; + /*if (this.containerHeight > 20) + this.containerHeight = Math.ceil(this.containerHeight * 0.9);*/ + }; + + this.addEventListener("prop.class", function(e) { + this.$setStyleClass(this.oSlider, e.value); + }); + + // *** Public methods *** // + + /* + * Toggles the visibility of the container with the list elements. It opens + * or closes it using a slide effect. + * @private + */ + this.slideToggle = function(e, userAction) { + if (!e) e = event; + if (userAction && this.disabled) + return; + + if (this.isOpen) + this.slideUp(); + else + this.slideDown(e); + }; + + /* + * Shows the container with the list elements using a slide effect. + * @private + */ + this.slideDown = function(e) { + if (this.dispatchEvent("slidedown") === false) + return false; + + this.isOpen = true; + + this.$propHandlers["maxitems"].call(this, this.xmlRoot && this.each + ? this.getTraverseNodes().length : this.childNodes.length); //@todo apf3.0 count element nodes + + this.oSlider.style.display = "block"; + if (!this.ignoreOverflow) { + this.oSlider.style[apf.supportOverflowComponent + ? "overflowY" + : "overflow"] = "visible"; + this.$container.style.overflowY = "hidden"; + } + + this.oSlider.style.display = ""; + + this.$setStyleClass(this.$ext, this.$baseCSSname + "Down"); + + //var pos = apf.getAbsolutePosition(this.$ext); + this.oSlider.style.height = (this.sliderHeight - 1) + "px"; + this.oSlider.style.width = (this.$ext.offsetWidth - 2 - this.widthdiff) + "px"; + + var _self = this; + var _popupCurEl = apf.popup.getCurrentElement(); + apf.popup.show(this.$uniqueId, { + x: 0, + y: this.$ext.offsetHeight, + animate: true, + container: this.$getLayoutNode("container", "contents", this.oSlider), + ref: this.$ext, + width: this.$ext.offsetWidth - this.widthdiff, + height: this.containerHeight, + allowTogether: (_popupCurEl && apf.isChildOf(_popupCurEl.$ext, _self.$ext)), + callback: function(container) { + if (!_self.ignoreOverflow) { + _self.$container.style.overflowY = "auto"; + } + } + }); + }; + + /* + * Hides the container with the list elements using a slide effect. + * @private + */ + this.slideUp = function(){ + if (this.isOpen == 2) return false; + if (this.dispatchEvent("slideup") === false) return false; + + this.isOpen = false; + if (this.selected) { + var htmlNode = apf.xmldb.findHtmlNode(this.selected, this); + if (htmlNode) this.$setStyleClass(htmlNode, '', ["hover"]); + } + + this.$setStyleClass(this.$ext, '', [this.$baseCSSname + "Down"]); + if (apf.popup.last == this.$uniqueId) + apf.popup.hide(); + return false; + }; + + // *** Private methods and event handlers *** // + + //@todo apf3.0 why is this function called 6 times on init. + this.$setLabel = function(value) { + + this.oLabel.innerHTML = value || this["initial-message"] || ""; + + + this.$setStyleClass(this.$ext, value ? "" : this.$baseCSSname + "Initial", + !value ? [] : [this.$baseCSSname + "Initial"]); + }; + + this.addEventListener("afterselect", function(e) { + if (!e) e = event; + + this.slideUp(); + if (!this.isOpen) + this.$setStyleClass(this.$ext, "", [this.$baseCSSname + "Over"]); + + this.$setLabel(e.selection.length + ? this.$applyBindRule("caption", this.selected) + : ""); + }); + + function setMaxCount() { + if (this.isOpen == 2) + this.slideDown(); + } + + this.addEventListener("afterload", setMaxCount); + this.addEventListener("xmlupdate", function(){ + setMaxCount.call(this); + this.$setLabel(this.$applyBindRule("caption", this.selected)); + }); + + // Private functions + this.$blur = function(){ + this.slideUp(); + //this.$ext.dispatchEvent("mouseout") + if (!this.isOpen) + this.$setStyleClass(this.$ext, "", [this.$baseCSSname + "Over"]) + + this.$setStyleClass(this.$ext, "", [this.$baseCSSname + "Focus"]); + }; + + /*this.$focus = function(){ + apf.popup.forceHide(); + this.$setStyleClass(this.oFocus || this.$ext, this.$baseCSSname + "Focus"); + }*/ + + this.$setClearMessage = function(msg) { + this.$setLabel(msg); + }; + + this.$removeClearMessage = function(){ + this.$setLabel(""); + }; + + this.addEventListener("popuphide", this.slideUp); + + // *** Keyboard Support *** // + + + this.addEventListener("keydown", function(e) { + var key = e.keyCode; + //var ctrlKey = e.ctrlKey; << unused + //var shiftKey = e.shiftKey; + + if (!this.xmlRoot) return; + + var node; + + switch (key) { + case 32: + this.slideToggle(e.htmlEvent); + break; + case 38: + //UP + if (e.altKey) { + this.slideToggle(e.htmlEvent); + return; + } + + if (!this.selected) + return; + + node = this.getNextTraverseSelected(this.caret + || this.selected, false); + + if (node) + this.select(node); + break; + case 40: + //DOWN + if (e.altKey) { + this.slideToggle(e.htmlEvent); + return; + } + + if (!this.selected) { + node = this.getFirstTraverseNode(); + if (!node) + return; + } + else + node = this.getNextTraverseSelected(this.selected, true); + + if (node) + this.select(node); + + break; + default: + if (key == 9 || !this.xmlRoot) return; + + //if(key > 64 && key < + if (!this.lookup || new Date().getTime() - this.lookup.date.getTime() > 1000) + this.lookup = { + str: "", + date: new Date() + }; + + this.lookup.str += String.fromCharCode(key); + + var caption, nodes = this.getTraverseNodes(); + for (var i = 0; i < nodes.length; i++) { + caption = this.$applyBindRule("caption", nodes[i]); + if (caption && caption.indexOf(this.lookup.str) > -1) { + this.select(nodes[i]); + return; + } + } + return; + } + + return false; + }, true); + + + // *** Init *** // + + this.$draw = function(){ + this.$getNewContext("main"); + this.$getNewContext("container"); + + this.$animType = this.$getOption("main", "animtype") || 1; + this.clickOpen = this.$getOption("main", "clickopen") || "button"; + + //Build Main Skin + this.$ext = this.$getExternal(null, null, function(oExt) { + oExt.setAttribute("onmouseover", 'var o = apf.lookup(' + this.$uniqueId + + ');o.$setStyleClass(o.$ext, o.$baseCSSname + "Over", null, true);'); + oExt.setAttribute("onmouseout", 'var o = apf.lookup(' + this.$uniqueId + + ');if(o.isOpen) return;o.$setStyleClass(o.$ext, "", [o.$baseCSSname + "Over"], true);'); + + //Button + var oButton = this.$getLayoutNode("main", "button", oExt); + if (oButton) { + oButton.setAttribute("onmousedown", 'apf.lookup(' + + this.$uniqueId + ').slideToggle(event, true);'); + } + + //Label + var oLabel = this.$getLayoutNode("main", "label", oExt); + if (this.clickOpen == "both") { + oLabel.parentNode.setAttribute("onmousedown", 'apf.lookup(' + + this.$uniqueId + ').slideToggle(event, true);'); + } + }); + this.oLabel = this.$getLayoutNode("main", "label", this.$ext); + + + if (this.oLabel.nodeType == 3) + this.oLabel = this.oLabel.parentNode; + + + this.oIcon = this.$getLayoutNode("main", "icon", this.$ext); + if (this.$button) + this.$button = this.$getLayoutNode("main", "button", this.$ext); + + this.oSlider = apf.insertHtmlNode(this.$getLayoutNode("container"), + document.body); + this.$container = this.$getLayoutNode("container", "contents", this.oSlider); + this.$container.host = this; + + //Set up the popup + this.$pHtmlDoc = apf.popup.setContent(this.$uniqueId, this.oSlider, + apf.skins.getCssString(this.skinName)); + + //Get Options form skin + //Types: 1=One dimensional List, 2=Two dimensional List + this.listtype = parseInt(this.$getLayoutNode("main", "type")) || 1; + + this.itemHeight = this.$getOption("main", "item-height") || 18.5; + this.widthdiff = this.$getOption("main", "width-diff") || 0; + this.ignoreOverflow = apf.isTrue(this.$getOption("main", "ignore-overflow")) || false; + }; + + this.addEventListener("DOMNodeInsertedIntoDocument", function(){ + if (typeof this["initial-message"] == "undefined") + this.$setInheritedAttribute("initial-message"); + + if (!this.selected && this["initial-message"]) + this.$setLabel(); + }); + + this.$destroy = function(){ + apf.popup.removeContent(this.$uniqueId); + apf.destroyHtmlNode(this.oSlider); + this.oSlider = null; + }; + + +}).call(apf.dropdown.prototype = new apf.BaseList()); + +apf.config.$inheritProperties["initial-message"] = 1; + +apf.aml.setElement("dropdown", apf.dropdown); + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * An element showing an error message when the attached element + * is in erroneous state and has the `invalidmsg=""` attribute specified. + * + * In most cases, the errorbox element is implicit and will be created + * automatically. + * + * #### Example + * + * ```xml + * + * Invalid e-mail address entered. + * + * ``` + * + * #### Remarks + * + * In most cases the errorbox element is not created directly, but implicitly + * by a validationgroup. An element that goes into an error state will + * show the errorbox. + * + * ```xml + * + * Phone number + * + * + * Password + * + * Validate + * + * ``` + * + * To check if the element has valid information entered, leaving the textbox + * (focussing another element) will trigger a check. A programmatic check + * can be done using the following code: + * + * ```javascript + * txtPhone.validate(); + * + * //Or use the html5 syntax + * txtPhone.checkValidity(); + * ``` + * + * To check for the entire group of elements use the validation group. For only + * the first non-valid element the errorbox is shown. That element also receives + * focus. + * + * ```javascript + * vgForm.validate(); + * ``` + * + * @class apf.errorbox + * @define errorbox + * + * @allowchild {anyxhtml} + * + * + * @inherits apf.Presentation + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.4 + */ +apf.errorbox = function(struct, tagName) { + this.$init(tagName || "errorbox", apf.NODE_VISIBLE, struct); +}; + +(function(){ + this.$positioning = "basic"; + this.display = function(host) { + this.host = host; + + var refHtml = + + host.$ext; + + document.body.appendChild(this.$ext); + /*var pos = apf.getAbsolutePosition(refHtml, document.body); + + if (document != refHtml.ownerDocument) { + var pos2 = apf.getAbsolutePosition(refHtml.ownerDocument.parentWindow.frameElement, document.body); + pos[0] += pos2[0]; + pos[1] += pos2[1]; + }*/ + + var x = (parseFloat(host.$getOption && host.$getOption("main", "erroffsetx") || 0)), + y = (parseFloat(host.$getOption && host.$getOption("main", "erroffsety") || 0)); + //this.$ext.style.left = x + "px" + //this.$ext.style.top = y + "px" + + this.show(); + apf.popup.show(this.$uniqueId, { + x: x, + y: y, + animate: false, + ref: refHtml, + allowTogether: true + }); + + this.$setStyleClass(this.$ext, + x + this.$ext.offsetWidth > this.$ext.offsetParent.offsetWidth + ? "rightbox" + : "leftbox", ["leftbox", "rightbox"]); + }; + + /** + * Sets the message of the errorbox. + * @param {String} value The message to set. + */ + this.setMessage = function(value) { + if (value && value.indexOf(";") > -1) { + value = value.split(";"); + value = "" + value.shift() + "" + value.join(";"); + } + this.$int.innerHTML = value || ""; + }; + + this.$draw = function(){ + //Build Main Skin + this.$ext = this.$getExternal(); + this.$int = this.$getLayoutNode("main", "container", this.$ext); + this.oClose = this.$getLayoutNode("main", "close", this.$ext); + + if (this.oClose) { + var _self = this; + this.oClose.onclick = function(){ + _self.hide(); + + if (apf.document.activeElement) + apf.document.activeElement.focus(true, {mouse:true}); + }; + } + + this.$ext.onmousedown = function(e) { + (e || event).cancelBubble = true; + + + } + + apf.popup.setContent(this.$uniqueId, this.$ext, "", null, null); + }; + + this.$loadAml = function(x) { + if (!apf.isTrue(this.getAttribute("visible"))) + this.hide(); + }; + + this.$destroy = function(){ + if (this.oClose) + this.oClose.onclick = null; + + this.$ext.onmousedown = null; + + apf.popup.removeContent(this.$uniqueId); + }; +}).call(apf.errorbox.prototype = new apf.Presentation()); + +apf.aml.setElement("errorbox", apf.errorbox); + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * Displays a popup element with a message with optionally an icon at the + * position specified by the position attribute. After the timeout has passed + * the popup will dissapear automatically. When the mouse hovers over the popup + * it doesn't dissapear. + * + * @class apf.event + * @define event + * @inherits apf.AmlElement + * + */ +/** + * @event click Fires when the user clicks on the representation of this event. + */ +apf.event = function(struct, tagName) { + this.$init(tagName || "event", apf.NODE_HIDDEN, struct); +}; + +(function() { + this.$hasInitedWhen = false; + + this.$booleanProperties["repeat"] = true; + this.$supportedProperties.push("when", "message", "icon", "repeat"); + + this.$propHandlers["when"] = function(value) { + if (this.$hasInitedWhen && value && this.parentNode && this.parentNode.popup) { + var _self = this; + $setTimeout(function() { + _self.parentNode.popup(_self.message, _self.icon, _self); + }); + } + this.$hasInitedWhen = true; + + if (this.repeat) + delete this.when; + }; + + this.$loadAml = function(x) {}; +}).call(apf.event.prototype = new apf.AmlElement()); + +apf.aml.setElement("event", apf.event); + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +apf.filler = function(struct, tagName) { + this.$init(tagName || "filler", apf.NODE_VISIBLE, struct); +}; + +(function() { + this.$focussable = false; + this.flex = 1; + + this.$draw = function() { + this.$ext = this.$pHtmlNode.appendChild(this.$pHtmlNode.ownerDocument.createElement("div")); + }; +}).call(apf.filler.prototype = new apf.GuiElement()); + +apf.aml.setElement("filler", apf.filler); + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * This element displays a frame with a caption that can contain other elements. It's + * element is analogous to the `
      ` in HTML. + * + * #### Example + * + * ```xml, demo + * + * + * + * Option 1 + * Option 2 + * Option 3 + * Option 4 + * + * + * + * ``` + * + * @class apf.frame + * @define frame + * @container + * @allowchild {elements}, {anyaml} + * + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.9 + * + * @inherits apf.Presentation + */ +apf.panel = function(struct, tagName) { + this.$init(tagName || "panel", apf.NODE_VISIBLE, struct); +}; + +apf.fieldset = function(struct, tagName) { + this.$init(tagName || "fieldset", apf.NODE_VISIBLE, struct); +}; + +apf.frame = function(struct, tagName) { + this.$init(tagName || "frame", apf.NODE_VISIBLE, struct); +}; + +(function(){ + this.implement(apf.BaseStateButtons); + + this.$focussable = false; + + + + // *** Properties and Attributes *** // + + /** + * @attribute {String} caption Sets or gets the caption text. + */ + this.$supportedProperties.push("caption", "url"); + this.$propHandlers["caption"] = function(value) { + if (!this.oCaption) return; + + if (this.oCaption.nodeType == 1) + this.oCaption.innerHTML = value; + else + this.oCaption.nodeValue = value; + }; + + /** + * @attribute {String} icon Sets or gets the location of the image. + */ + this.$propHandlers["icon"] = function(value) { + var oIcon = this.$getLayoutNode("main", "icon", this.$ext); + if (!oIcon) return; + + if (oIcon.nodeType == 1) + oIcon.style.display = value ? "block" : "none"; + apf.skins.setIcon(oIcon, value, this.iconPath); + }; + + /** + * @attribute {String} icon Sets or gets the URL location (if this is an iframe). + */ + this.$propHandlers["url"] = function(value) { + var node = this.oCaption; + if (node.tagName == "A" || node.nodeType != 1) + node = node.parentNode; + + node.innerHTML = "" + + this.caption + ""; + this.oCaption = this.oCaption.firstChild; + }; + + this.$propHandlers["activetitle"] = function(value) { + var node = this.oCaption.parentNode; + // if (node.nodeType != 1) node = node.parentNode; + var _self = this; + node.addEventListener("click", function(e) { + if (e.target == node) + _self.$toggle(value); + }, false); + }; + + /** + * Sets the text of the title of this element. + * @param {String} value The text of the title. + */ + this.setTitle = function(value) { + this.setProperty("title", value); + }; + + // *** Init *** // + + this.$draw = function(){ + //Build Main Skin + this.$ext = this.$getExternal(null, null, function(oExt) { + this.$initButtons(oExt); + }); + this.oCaption = this.$getLayoutNode("main", "caption", this.$ext); + this.$int = this.$getLayoutNode("main", "container", this.$ext); + this.$buttons = this.$getLayoutNode("main", "buttons", this.$ext); + + /*if (this.oCaption) { + this.oCaption = this.oCaption.nodeType == 1 + ? this.oCaption + : this.oCaption.parentNode; + }*/ + }; + + this.$loadAml = function(x) { + // not implement now. + }; + + +}).call(apf.frame.prototype = new apf.Presentation()); + +apf.panel.prototype = +apf.fieldset.prototype = apf.frame.prototype; + +apf.aml.setElement("panel", apf.panel); +apf.aml.setElement("fieldset", apf.fieldset); +apf.aml.setElement("frame", apf.frame); + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +/** + * A container that stacks its children vertically. + * + * #### Example + * + * ```xml, demo + * + * + * + * Button 1 + * Button 2 + * Button 3 + * + * + * + * ``` + * + * @class apf.vbox + * @layout + * @define vbox + * + * + * @see element.hbox + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.9 + * @layout + */ +/** + * A container that stacks its children horizontally. + * + * #### Example + * + * ```xml, demo + * + * + * + * Button 1 + * Button 2 + * Button 3 + * + * + * + * ``` + * + * + * #### Remarks + * + * Firefox has some issues: + * + * 1. Sometimes it's necessary to put a fixed width to have it calculate the right + * height value. + * 2. Using flex="1" on non fixed height/width tree's will give unexpected results. + * + * + * + * @class apf.hbox + * @inherits apf.GuiElement + * @define hbox + * @layout + * + * @see element.vbox + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.9 + */ +apf.hbox = function(struct, tagName) { + this.$init(tagName || "hbox", apf.NODE_VISIBLE, struct); +}; +apf.vbox = function(struct, tagName) { + this.$init(tagName || "vbox", apf.NODE_VISIBLE, struct); +}; + +(function(){ + this.minwidth = 0; + this.minheight = 0; + + // *** Properties and Attributes *** // + + this.$focussable = false; + this.$useLateDom = true; + this.$box = true; + this.$layout = true; + + var MOZSTACK = "-moz-stack"; + var input = {"INPUT":1, "SELECT":1, "TEXTAREA":1} + + /** + * @attribute {String} [padding=2] Sets or gets the space between each element. + */ + /** + * @attribute {Boolean} reverse Sets or gets whether the sequence of the elements is in reverse order. + */ + /** + * @attribute {String} [edge="5,5,5,5"] Sets or gets the space between the container and the elements, space seperated in pixels for each side. Similar to CSS in the sequence (_.i.e._. `top right bottom left`). + * + * #### Example + * + * ```xml + * + * ``` + */ + // @todo Doc + /** + * @attribute {String} pack + * + * Possible values include: + * + * - `"start"`: + * - `"center"`: + * - `"end"`: + */ + /** + * @attribute {Boolean} align + * + * Possible values include: + * + * - `"start"`: + * - `"center"`: + * - `"end"`: + * - `"stretch"`: + */ + this.$booleanProperties["splitters"] = true; + this.$supportedProperties.push("padding", "reverse", "edge", "pack", "align", "splitters"); + + this.$propHandlers["padding"] = function(value) { + this.padding = parseInt(value); + + var node, nodes = this.childNodes, elms = []; + for (var i = 0, l = nodes.length; i < l; i++) { + if ((node = nodes[i]).nodeFunc == apf.NODE_VISIBLE + && node.$ext && node.visible !== false) + elms.push(node); + } + + if (!elms.length) + return; + + for (var last, b, el, i = elms.length - 2; i >= 0; i--) { + b = (el = elms[i]).margin && apf.getBox(el.margin) || [0,0,0,0]; + + if ((!last || !last.$splitter) && !el.$splitter) { + b[this.$vbox ? 2 : 1] += this.padding; + + if (!apf.hasFlexibleBox && i != 0 && this.align == "stretch" && this.$vbox) + b[0] += this.padding; + } + + el.$ext.style.margin = b.join("px ") + "px"; + last = el; + } + b = (el = elms[elms.length - 1]).margin && apf.getBox(el.margin) || [0,0,0,0]; + el.$ext.style.margin = b.join("px ") + "px"; + + if (!apf.hasFlexibleBox) + this.$resize(); + } + + this.$propHandlers["reverse"] = function(value) { + if (apf.hasFlexibleBox) + this.$int.style[apf.CSSPREFIX + "BoxDirection"] = value ? "reverse" : "normal"; + else { + //@todo + } + }; + + this.$propHandlers["edge"] = function(value) { + var el = !apf.hasFlexibleBox && this.$vbox ? this.$ext : this.$int; + el.style.padding = (this.$edge = apf.getBox(value)).join("px ") + "px"; + + if (!apf.hasFlexibleBox) + this.$resize(); + }; + + this.$propHandlers["pack"] = function(value) { + if (apf.hasFlexibleBox) + this.$int.style[apf.CSSPREFIX + "BoxPack"] = value || "start"; + else if (this.$amlLoaded) { + if (this.$vbox) { + this.$int.style.verticalAlign = value == "center" ? "middle" : (value == "end" ? "bottom" : "top"); + } + else { + this.$int.style.textAlign = ""; + + var nodes = this.childNodes; + for (var i = 0, l = nodes.length; i < l; i++) { + if ((node = nodes[i]).nodeFunc != apf.NODE_VISIBLE || !node.$amlLoaded) //|| node.visible === false + continue; + + node.$ext.style.textAlign = apf.getStyle(node.$ext, "textAlign") || "left"; + } + + this.$int.style.textAlign = value == "center" ? "center" : (value == "end" ? "right" : "left"); + } + } + }; + + //@todo change overflow when height/width changes depending on $vbox + + this.$propHandlers["align"] = function(value) { + if (apf.hasFlexibleBox) { + this.$int.style[apf.CSSPREFIX + "BoxAlign"] = value || "stretch"; + + if (apf.isGecko) + this.$int.style.overflow = "visible"; + + //@todo this should probably be reinstated + var stretch = !value || value == "stretch"; + var nodes = this.childNodes; + var size = this.$vbox ? "width" : "height"; + + var isInFixed = false, loopNode = this; + while (!isInFixed && loopNode) { + isInFixed = loopNode[size] || loopNode.anchors || (loopNode.$vbox ? loopNode.top && loopNode.bottom : loopNode.left && loopNode.right); + if (!loopNode.flex) + break; + loopNode = loopNode.parentNode || loopNode.$parentNode; + } + + for (var i = 0, l = nodes.length; i < l; i++) { + if (!(node = nodes[i]).$ext || node.$ext.nodeType != 1) + continue; + + //(this[size] || this.anchors || (this.$vbox ? this.top && this.bottom : this.left && this.right) + if (stretch && !node[size]) //(node.$altExt || + node.$ext.style[size] = apf.isGecko && (this.flex || node.flex) + ? (isInFixed ? "1px" : "auto") + : (apf.isWebkit && input[node.$ext.tagName] + ? "100%" + : (false && apf.isWebkit && node[this.$vbox ? "minwidth" : "minheight"] && this.flex //nasty bug fix + ? "0px" + : "auto"));//(apf.isWebkit && node.flex && size == "height" ? "100%" : "auto"); // && (this.flex && node.flex) + else if (node[size]) + handlers["true"][size].call(node, node[size]); + } + } + else if (this.$amlLoaded) { + var stretch = !value || value == "stretch"; + + if (!this.$vbox) { + var nodes = this.childNodes; + for (var i = 0, l = nodes.length; i < l; i++) { + if ((node = nodes[i]).nodeFunc != apf.NODE_VISIBLE || !node.$amlLoaded) //|| node.visible === false + continue; + + node.$ext.style.verticalAlign = value == "center" ? "middle" : (value == "end" ? "bottom" : "top"); + } + } + else { + var el = !apf.hasFlexibleBox && this.$vbox ? this.$ext : this.$int; + el.style.textAlign = ""; + + var node, nodes = this.childNodes; + for (var i = 0, l = nodes.length; i < l; i++) { + if ((node = nodes[i]).nodeFunc != apf.NODE_VISIBLE || !node.$amlLoaded) //|| node.visible === false + continue; + + if (node.visible !== false) { + node.$ext.style.display = value == "stretch" ? "block" : apf.INLINE; + node.$br.style.display = value == "stretch" ? "none" : ""; + + if (apf.needZoomForLayout) + node.$ext.style.zoom = 1; + } + node.$ext.style.textAlign = apf.getStyle(node.$ext, "textAlign") || "left"; + } + + el.style.textAlign = value == "center" ? "center" : (value == "end" ? "right" : "left"); + } + } + }; + + function visibleHandler(e) { + + if (this.parentNode.splitters && !this.$splitter) { + if (!e.value) { + if (this.nextSibling && this.nextSibling.$splitter) + this.nextSibling.removeNode(); + else if (this.previousSibling && this.previousSibling.$splitter) + this.previousSibling.removeNode(); + } + else { + var isLast = isLastVisibleChild(this); + if (!isLast) { + if (!this.nextSibling.$splitter && !this.nextSibling.nosplitter + && !isFirstVisibleChild(this) && !this.nosplitter) { + this.parentNode.insertBefore( + this.ownerDocument.createElementNS(apf.ns.aml, "splitter"), + this.nextSibling); + } + } + else if (this.previousSibling && !this.previousSibling.$splitter + && !this.previousSibling.nosplitter) { + this.parentNode.insertBefore( + this.ownerDocument.createElementNS(apf.ns.aml, "splitter"), + this); + } + } + } + + + //@todo this can be more optimized by calcing if it WAS the last vis child. + if (this.parentNode.$propHandlers["padding"]) {// && isLastVisibleChild(this)) { + this.parentNode.$propHandlers["padding"] + .call(this.parentNode, this.parentNode.padding); + } + + apf.layout.forceResize(this.parentNode.$int); + + if (apf.hasFlexibleBox) { + if (this.$altExt) + this.$altExt.style.display = e.value + ? (apf.isGecko ? MOZSTACK : apf.CSSPREFIX2 + "-box") + : "none"; + return; + } + + if (e.value) { + this.$ext.style.display = this.parentNode.$vbox + && this.parentNode.align == "stretch" ? "block" : apf.INLINE; + if (apf.needZoomForLayout) + this.$ext.style.zoom = 1; + if (this.$br) + this.$br.style.display = this.parentNode.align == "stretch" ? "none" : ""; + } + else { + if (this.$br) + this.$br.style.display = "none"; + } + + this.parentNode.$resize(); + } + + function resizeHandler(){ + if (!this.flex) { + if (this.$isRszHandling || this.$lastSizeChild && + this.$lastSizeChild[0] == this.$ext.offsetWidth && + this.$lastSizeChild[1] == this.$ext.offsetHeight) + return; + + /*if (this.$skipResizeOnce) + delete this.$skipResizeOnce; + else*/ + this.parentNode.$resize(true); + + this.$lastSizeChild = [this.$ext.offsetWidth, this.$ext.offsetHeight]; + } + } + + var handlers = { + //Handlers for flexible box layout + "true" : { + "optimize" : function(value) { + this.optimize = apf.isTrue(value); + }, + + "width" : function(value) { + //@todo this should check the largest and only allow that one + //if (this.parentNode.$vbox && this.parentNode.align == "stretch") + //return; + + (this.$altExt || this.$ext).style.width = !apf.isNot(value) + ? (parseFloat(value) == value + ? value + "px" + : value) + : ""; + }, + + "height" : function(value) { + //@todo this should check the largest and only allow that one + //if (!this.parentNode.$vbox && this.parentNode.align == "stretch") + //return; + + (this.$altExt || this.$ext).style.height = !apf.isNot(value) + ? (parseFloat(value) == value + ? value + "px" + : value) + : (apf.isGecko && this.flex && this.parentNode.$vbox ? "auto" : ""); + }, + + "margin" : function(value) { + var b = apf.getBox(value); + if (!isLastVisibleChild(this)) + b[this.parentNode.$vbox ? 2 : 1] += this.parentNode.padding; + this.$ext.style.margin = b.join("px ") + "px"; + }, + + "flex" : function(value) { + this.flex = value = parseInt(value); + if (value) { + if (!this.optimize && !this.$altExt) { + this.$altExt = this.$ext.ownerDocument.createElement("div"); + this.parentNode.$int.replaceChild(this.$altExt, this.$ext); + this.$altExt.appendChild(this.$ext); + this.$altExt.style[apf.CSSPREFIX + "BoxSizing"] = "border-box"; + this.$altExt.style.display = apf.CSSPREFIX2 + "-box"; + this.$altExt.style[apf.CSSPREFIX + "BoxOrient"] = "vertical"; + this.$ext.style[apf.CSSPREFIX + "BoxFlex"] = 1; + var size = this.parentNode.$vbox ? "height" : "width"; + //var osize = this.parentNode.$vbox ? "width" : "height"; + + if (apf.isWebkit) { + if (!this.preventforcezero) + this.$altExt.style[size] = "0px"; + } + else if (apf.isGecko) { + this.$altExt.style[size] = "0px"; + + //Possible hack to not do this for $box elements + if (!this.$box) + this.$altExt.style.overflow = "hidden"; //Gecko + if (apf.getStyle(this.$ext, "overflow") == "visible") + this.$ext.style.overflow = "hidden"; //Gecko + this.$ext.style[size] = "1px"; + + this.$altExt.style.minHeight = this.$ext.style.minHeight; + this.$altExt.style.maxHeight = this.$ext.style.maxHeight; + this.$altExt.style.minWidth = this.$ext.style.minWidth; + this.$altExt.style.maxWidth = this.$ext.style.maxWidth; + } + } + + (this.$altExt || this.$ext).style[apf.CSSPREFIX + "BoxFlex"] = parseInt(value) || 1; + } + else if (this.$altExt) { + this.parentNode.$int.replaceChild(this.$ext, this.$altExt); + this.$ext.style[apf.CSSPREFIX + "BoxFlex"] = ""; + if (apf.isGecko) + this.$ext.style.overflow = ""; + delete this.$altExt; + } + } + }, + + //Handlers for older browsers + "false" : { + "width" : function(value) { + //@todo this should check the largest and only allow that one + //if (this.parentNode.$vbox && this.parentNode.align == "stretch") + //return; + + this.$ext.style.width = value + ? (parseFloat(value) == value + ? Math.max(0, value - apf.getWidthDiff(this.$ext)) + "px" + : value) + : ""; + }, + + "height" : function(value) { + //@todo this should check the largest and only allow that one + //if (this.parentNode.localName == "hbox" && this.parentNode.align == "stretch") + //return; + + this.$ext.style.height = value + ? (parseFloat(value) == value + ? Math.max(0, value - apf.getHeightDiff(this.$ext)) + "px" + : value) + : ""; + }, + + "margin" : function(value) { + var b = apf.getBox(value); + if (this.padding) { + if (!isLastVisibleChild(this)) + b[this.parentNode.$vbox ? 2 : 1] += this.padding; + if (this != this.parentNode.firstChild && this.parentNode.align == "stretch" && this.parentNode.$vbox) //@todo + b[0] += this.padding; + } + this.$ext.style.margin = b.join("px ") + "px"; + }, + + "flex" : function(value) { + this.flex = parseInt(value); + if (this.$amlLoaded) + this.parentNode.$resize(true); + } + } + } + + function isFirstVisibleChild(amlNode) { + var firstChild = amlNode.parentNode.firstChild; + while (firstChild && (firstChild.nodeFunc != apf.NODE_VISIBLE + || firstChild.visible === false + || firstChild.visible == 2 && apf.isFalse(firstChild.getAttribute("visible")))) { + firstChild = firstChild.nextSibling; + } + + return firstChild && firstChild == amlNode; + } + + function isLastVisibleChild(amlNode) { + var lastChild = amlNode.parentNode.lastChild; + while (lastChild && (lastChild.nodeFunc != apf.NODE_VISIBLE + || lastChild.visible === false + || lastChild.visible == 2 && apf.isFalse(lastChild.getAttribute("visible")))) { + lastChild = lastChild.previousSibling; + } + + return lastChild && lastChild == amlNode; + } + + //@todo move this to enableTable, disableTable + this.register = function(amlNode, insert) { + if (amlNode.$altExt) //@todo hack, need to re-arch layouting + return; + + amlNode.$propHandlers["left"] = + amlNode.$propHandlers["top"] = + amlNode.$propHandlers["right"] = + amlNode.$propHandlers["bottom"] = apf.K; + + var propHandlers = handlers[apf.hasFlexibleBox]; + for (var prop in propHandlers) { + amlNode.$propHandlers[prop] = propHandlers[prop]; + } + + if (amlNode.nodeFunc == apf.NODE_VISIBLE) { + if (apf.hasFlexibleBox) { + //if (apf.isGecko && apf.getStyle(amlNode.$ext, "display") == "block") + //amlNode.$ext.style.display = MOZSTACK; //@todo visible toggle + + //input elements are not handled correctly by firefox and webkit + if (amlNode.$ext.tagName == "INPUT" || apf.isWebkit && input[amlNode.$ext.tagName]) { + var doc = amlNode.$ext.ownerDocument; + amlNode.$altExt = doc.createElement("div"); + amlNode.parentNode.$int.replaceChild(amlNode.$altExt, amlNode.$ext); + amlNode.$altExt.style[apf.CSSPREFIX + "BoxSizing"] = "border-box"; + amlNode.$altExt.appendChild(amlNode.$ext); + + if (apf.isWebkit) { + var d = apf.getDiff(amlNode.$ext); + //amlNode.$altExt.style.padding = "0 " + d[0] + "px " + d[1] + "px 0"; + amlNode.$altExt.style.height = "100%"; + amlNode.$altExt.style.width = "0"; + amlNode.$altExt.style.lineHeight = 0; + amlNode.$altExt.style.margin = "-1px 0 0 0"; + amlNode.$ext.style.width = "100%"; + amlNode.$ext.style.height = "100%"; + amlNode.$ext.style.top = "1px"; + amlNode.$ext.style.position = "relative"; + } + else { + amlNode.$altExt.style.display = apf.CSSPREFIX2 + "-box"; + amlNode.$altExt.style[apf.CSSPREFIX + "BoxOrient"] = "horizontal"; + amlNode.$altExt.style[apf.CSSPREFIX + "BoxAlign"] = "stretch"; + amlNode.$ext.style[apf.CSSPREFIX + "BoxFlex"] = 1; + } + } + else { + if (apf.getStyle(amlNode.$ext, "display") == "inline") + amlNode.$ext.style.display = "block"; //@todo undo + //This is nice for positioning elements in the context of an hbox/vbox + //if (apf.getStyle(amlNode.$ext, "position") == "absolute") + //amlNode.$ext.style.position = "relative"; //@todo undo + } + + amlNode.$ext.style[apf.CSSPREFIX + "BoxSizing"] = "border-box"; + } + else { + if (this.$vbox) { + amlNode.$br = this.$int.insertBefore(amlNode.$ext.ownerDocument.createElement("br"), amlNode.$ext.nextSibling); + if (amlNode.visible === false) + amlNode.$br.style.display = "none"; + } + else { + if (amlNode.visible !== false) { + amlNode.$ext.style.display = apf.INLINE; + if (apf.needZoomForLayout) + amlNode.$ext.style.zoom = 1; + } + this.$int.style.whiteSpace = ""; + amlNode.$ext.style.whiteSpace = apf.getStyle(amlNode.$ext, "whiteSpace") || "normal"; + this.$int.style.whiteSpace = "nowrap"; + } + + this.$int.style.fontSize = "0"; + if (!amlNode.$box) { + var fontSize = apf.getStyle(amlNode.$ext, "fontSize"); + if (fontSize == "0px") { + amlNode.$ext.style.fontSize = ""; + var pNode = this.$int.parentNode; + while (apf.getStyle(pNode, "fontSize") == "0px") { + pNode = pNode.parentNode; + } + fontSize = apf.getStyle(pNode, "fontSize"); + } + amlNode.$ext.style.fontSize = fontSize;//apf.getStyle(amlNode.$ext, "fontSize") || "normal"; + } + + amlNode.addEventListener("resize", resizeHandler); + } + + amlNode.addEventListener("prop.visible", visibleHandler); + + this.$noResize = true; + + if (amlNode.height) + propHandlers.height.call(amlNode, amlNode.height); + if (amlNode.width) + propHandlers.width.call(amlNode, amlNode.width); + if (amlNode.margin) + propHandlers.margin.call(amlNode, amlNode.margin); + if (amlNode.flex) + propHandlers.flex.call(amlNode, amlNode.flex); + + //Ie somehow sets the visible flags in between registration + var isLast = isLastVisibleChild(amlNode); //apf.isIE ? this.lastChild == amlNode : + if (isLast || insert) { + this.$propHandlers["padding"].call(this, this.padding); + this.$propHandlers["align"].call(this, this.align); + + if (!apf.hasFlexibleBox) + this.$propHandlers["pack"].call(this, this.pack); + + if (amlNode.visible !== false) //insert && - removed because for new nodes that are being attached to the tree insert is not set + visibleHandler.call(amlNode, {value: true}); + + //@todo this needs more work + if (insert && amlNode.previousSibling) { + var prev = amlNode.previousSibling; + while (prev && (prev.nodeType != 1 || prev.localName == "splitter")) + prev = prev.previousSibling; + if (prev) + visibleHandler.call(prev, {value: true}); + } + } + + else if (this.splitters && !amlNode.$splitter && amlNode.visible !== false && !amlNode.nosplitter) { + if (amlNode.$ext.nextSibling != (amlNode.nextSibling + && (amlNode.nextSibling.$altExt || amlNode.nextSibling.$ext))) { + var _self = this; + setTimeout(function(){ + _self.insertBefore( + _self.ownerDocument.createElementNS(apf.ns.aml, "splitter"), + amlNode.nextSibling); + }); + } + else { + this.insertBefore( + this.ownerDocument.createElementNS(apf.ns.aml, "splitter"), + amlNode.nextSibling); + } + } + + + delete this.$noResize; + + if (!apf.hasFlexibleBox && isLast) + this.$resize(); + } + } + + this.unregister = function(amlNode) { + if (!amlNode.$propHandlers) + return; + + amlNode.$propHandlers["left"] = + amlNode.$propHandlers["top"] = + amlNode.$propHandlers["right"] = + amlNode.$propHandlers["bottom"] = null; + + var propHandlers = handlers[apf.hasFlexibleBox]; + for (var prop in propHandlers) { + delete amlNode.$propHandlers[prop]; + } + + //Clear css properties and set layout + if (amlNode.nodeFunc == apf.NODE_VISIBLE) { + if (amlNode.flex) { + var flex = amlNode.flex; + propHandlers.flex.call(amlNode, 0); + amlNode.flex = flex; + } + + if (apf.hasFlexibleBox) { + amlNode.$ext.style[apf.CSSPREFIX + "BoxSizing"] = ""; + + if (apf.isGecko) { + this.$int.style.overflow = "visible"; + + if (amlNode.$ext.style.display == "block") + amlNode.$ext.style.display = ""; + } + } + else { + amlNode.$ext.style.verticalAlign = ""; + amlNode.$ext.style.textAlign = ""; + amlNode.$ext.style.whiteSpace = ""; + //amlNode.$ext.style[apf.CSSFLOAT] = ""; + + if (amlNode.$br) { + amlNode.$br.parentNode.removeChild(amlNode.$br); + delete amlNode.$br; + //amlNode.$ext.style.fontSize = ""; + } + + amlNode.removeEventListener("resize", resizeHandler); + } + + amlNode.removeEventListener("prop.visible", visibleHandler); + + amlNode.$ext.style.display = amlNode.visible ? "block" : "none"; + + if (amlNode.margin) + amlNode.$ext.style.margin = ""; + + if (amlNode.width) + amlNode.$ext.style.width = ""; + + + if (this.splitters && !amlNode.$splitter) { + if (amlNode.nextSibling && amlNode.nextSibling.$splitter) + amlNode.nextSibling.removeNode(); + if (isLastVisibleChild(amlNode) && amlNode.previousSibling + && amlNode.previousSibling.$splitter) + amlNode.previousSibling.removeNode(); + } + + } + } + /* + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + this.register(this.parentNode); + }); + */ + + // *** DOM Hooks *** // + + this.addEventListener("DOMNodeRemoved", function(e) { + if (e.$doOnlyAdmin || e.currentTarget == this) + return; + + if (e.relatedNode == this) { + this.unregister(e.currentTarget); + //e.currentTarget.$setLayout(); + } + }); + + this.addEventListener("DOMNodeInserted", function(e) { + if (e.currentTarget == this) { + if (this.visible) + this.$ext.style.display = apf.CSSPREFIX2 + "-box"; //Webkit issue + return; + } + + if (e.currentTarget.nodeType != 1 + || e.currentTarget.nodeFunc != apf.NODE_VISIBLE) + return; + + if (e.relatedNode == this && !e.$isMoveWithinParent) { + e.currentTarget.$setLayout(this.localName, true); + + if (e.currentTarget.$altExt) { + + return false; + } + } + }); + + function myVisibleHandler(e) { + if (e.value) + this.$int.style.display = apf.CSSPREFIX2 + "-box"; + } + + function myHeightHandler(e) { + clearInterval(this.$heighttimer); + if (e.value || this.align != "stretch") { + delete this.$heighttimer; + } + else if (!this.$heighttimer) { + var _self = this; + this.$heighttimer = $setInterval(function(){ + if (_self.$amlDestroyed) + return; + + var nodes = _self.childNodes; + for (var $int, i = 0, l = nodes.length; i < l; i++) { + if (!($int = (node = nodes[i]).$int || node.$container)) + continue; + + if (Math.min($int.scrollHeight, node["maxheight"] || 10000) > $int.offsetHeight) + return _self.$resize(true); + } + + if (_self.flex) + clearInterval(this.$heighttimer); + }, this.flex ? 1 : 500); + } + } + + this.$draw = function(){ + var doc = this.$pHtmlNode.ownerDocument; + this.$ext = this.$pHtmlNode.appendChild(doc.createElement("div")); + if (this.getAttribute("style")) + this.$ext.setAttribute("style", this.getAttribute("style")); + this.$ext.className = this.localName; + + this.$vbox = this.localName == "vbox"; + this.$int = apf.isGecko && !(this.parentNode + && "hbox|vbox".indexOf(this.parentNode.localName) > -1) + || !apf.hasFlexibleBox && this.$vbox //@todo reparenting for gecko needs some admin work + ? this.$ext.appendChild(doc.createElement("div")) + : this.$ext; + this.$ext.host = this; + + if (apf.isGecko && !(this.parentNode + && "hbox|vbox".indexOf(this.parentNode.localName) > -1)) { + this.$int.style.width = "100%"; + this.$int.style.height = "100%"; + } + else if (!apf.hasFlexibleBox && this.$vbox) { + this.$int.style.display = apf.INLINE; + if (apf.needZoomForLayout) + this.$int.style.zoom = 1; + this.$int.style.width = "100%"; + } + + if (apf.hasFlexibleBox) { + this.$display = "-" + apf.CSSPREFIX +"-box"; + + this.$int.style.display = apf.CSSPREFIX2 + "-box"; + this.$int.style[apf.CSSPREFIX + "BoxOrient"] = this.localName == "hbox" ? "horizontal" : "vertical"; + if (apf.isGecko) //!webkit + this.$int.style[apf.CSSPREFIX + "BoxSizing"] = "border-box"; + this.$int.style[apf.CSSPREFIX + "BoxAlign"] = "stretch"; + + this.addEventListener("prop.visible", myVisibleHandler); + } + else { + if (!this.$vbox) { + this.$int.style.whiteSpace = "nowrap"; + this.addEventListener("prop.height", myHeightHandler); + } + + var spacer = (!apf.hasFlexibleBox && this.$vbox ? this.$ext : this.$int) + .appendChild(doc.createElement("strong")); + spacer.style.height = "100%"; + spacer.style.display = apf.INLINE; + if (apf.needZoomForLayout) + spacer.style.zoom = 1; + //spacer.style.marginLeft = "-4px"; + spacer.style.verticalAlign = "middle"; + + this.addEventListener("resize", this.$resize); + } + + if (this.getAttribute("class")) + apf.setStyleClass(this.$ext, this.getAttribute("class")); + + this.$originalMin = [this.minwidth || 0, this.minheight || 0]; + }; + + this.$resize = function(force) { + if (!this.$amlLoaded || this.$noResize) // || apf.isIE7 && force !== true) + return; + + //Protection for stretch re-resizing + if (force !== true && this.$lastSize && + this.$lastSize[0] == this.$int.offsetWidth && + this.$lastSize[1] == this.$int.offsetHeight) + return; + + if (!apf.window.vManager.check(this, this.$uniqueId, this.$resize)) + return; + + this.$noResize = true; + this.$lastSize = [this.$int.offsetWidth, this.$int.offsetHeight]; + + //this.$ext.style.border = "1px solid " + (["red", "green", "blue", "orange", "pink", "yellow"])[Math.round(Math.random() * 5)]; + + /*if (this.$table.offsetWidth >= this.$ext.offsetWidth) + this.$ext.style.minWidth = (this.minwidth = Math.max(0, this.$table.offsetWidth + - apf.getWidthDiff(this.$ext))) + "px"; + else { + this.$ext.style.minWidth = ""; + this.minwidth = this.$originalMin[0]; + } + + if (this.$table.offsetHeight >= this.$ext.offsetHeight) + this.$ext.style.minHeight = (this.minheight = Math.max(0, this.$table.offsetHeight + - apf.getHeightDiff(this.$ext))) + "px"; + else { + this.$ext.style.minHeight = ""; + this.minheight = this.$originalMin[1]; + }*/ + + //if (!this.$vbox) alert("here"); + + var total = 0; + var size = this.$vbox ? "width" : "height"; + var minsize = this.$vbox ? "minWidth" : "minHeight"; + var osize = this.$vbox ? "height" : "width"; + var scroll = this.$vbox ? "scrollWidth" : "scrollHeight"; + var offset = this.$vbox ? "offsetWidth" : "offsetHeight"; + var ooffset = this.$vbox ? "offsetHeight" : "offsetWidth"; + var getDiff = this.$vbox ? "getWidthDiff" : "getHeightDiff"; + var ogetDiff = this.$vbox ? "getHeightDiff" : "getWidthDiff"; + var inner = this.$vbox ? "getHtmlInnerWidth" : "getHtmlInnerHeight"; + var oinner = this.$vbox ? "getHtmlInnerHeight" : "getHtmlInnerWidth"; + var borders = this.$vbox ? "getVerBorders" : "getHorBorders"; + + var nodes = this.childNodes, hNodes = [], fW = 0, max = 0; + for (var node, i = 0; i < nodes.length; i++) { + if ((node = nodes[i]).nodeFunc != apf.NODE_VISIBLE || node.visible === false || !node.$amlLoaded) + continue; + + hNodes.push(node); + if (!node[size]) { + //if (!node.$skipResizeOnce) node.$skipResizeOnce = 1; + //else node.$skipResizeOnce++; + //node.$skipResizeOnce = 1 + //node.$ext.style[size] = ""; //@todo this is a sucky way of measuring + var m = node.margin && apf.getBox(node.margin); + if (m && this.$vbox) m.unshift(); + var mdiff = (m ? m[0] + m[2] : 0); + max = Math.max(max, mdiff + Math.min(node.$ext[scroll] + apf[borders](node.$ext), node["max" + size] || 10000)); + } + + if (parseInt(node.flex)) + total += parseFloat(node.flex); + else { + var m = node.margin && apf.getBox(node.margin); + if (m && !this.$vbox) m.shift(); + fW += node.$ext[ooffset] + (m ? m[0] + m[2] : 0); //this.padding + + } + } + if (!max && this[size]) { + max = this[size] + //- (this.$vbox ? this.$edge[0] + this.$edge[2] : this.$edge[1] + this.$edge[3]); + - apf[ogetDiff](this.$ext); + } + + /* + && (this[size] || this.flex) + */ + if (this.align == "stretch") { + //var hasSize = this[size] || this.flex; + var l = hNodes.length; + var pH = max;//this.$int[offset] - apf[getDiff](this.$int);// - (2 * this.padding); + for (var i = 0; i < l; i++) { + node = hNodes[i]; + + if (!node[size] && !this.$vbox || this.$vbox && input[node.$ext.tagName]) { + var m = node.margin && apf.getBox(node.margin); + if (m && this.$vbox) m.unshift(); + var mdiff = (m ? m[0] + m[2] : 0); + + /*shouldClear = !this[size] && !this.flex && node.$ext.offsetHeight == (pH - mdiff); + if (shouldClear) + node.$ext.style[size] = ""; + else + node.$ext.style[size] = Math.max(0, pH - apf[getDiff](node.$ext) - mdiff) + "px"; + node.$setResizeHeight = !shouldClear;*/ + + //!this[size] && !this.flex + if (max && Math.min(node.$ext[scroll], node["max" + size] || 10000) != max) + node.$ext.style[size] = Math.max(0, max - apf[getDiff](node.$ext) - mdiff) + "px"; + else + node.$ext.style[size] = ""; + + /*node.$ext.style[size] = !this[size] && !this.flex && node.$ext.offsetHeight == pH - mdiff + ? "" + : Math.max(0, pH - apf[getDiff](node.$ext) - mdiff) + "px";*/ + } + } + } + + //Flexing + if (total > 0) { + if (this.$vbox) + this.$int.style.height = "100%"; + this.$int.style.overflow = "hidden"; + + var splitterCount = apf.n(this).children("a:splitter").length() * 2; + + var rW = this.$int[ooffset] - apf[ogetDiff](this.$int) - fW + - ((hNodes.length - 1 - splitterCount) * this.padding);// - (2 * this.edge); + var lW = rW, done = 0; + for (var i = 0, l = hNodes.length; i < l; i++) { + if ((node = hNodes[i]).flex) { + var v = (i % 2 == 0 ? Math.floor : Math.ceil)((rW / total) * parseInt(node.flex)); + done += parseInt(node.flex); + var m = node.margin && apf.getBox(node.margin); + if (m && !this.$vbox) m.shift(); + node.$ext.style[osize] = Math.max(0, (done == total ? lW : v) - apf[ogetDiff](node.$ext) - (m ? m[0] + m[2] : 0)) + "px"; + lW -= v; + } + } + } + else { + if (this.$vbox) + this.$int.style.height = ""; + this.$int.style.overflow = ""; + } + + this.$noResize = false; + /*this.$noResize = true; + var _self = this; + setTimeout(function(){ + _self.$noResize = false; + });*/ + } + + this.$loadAml = function(x) { + if (this.padding == undefined) + this.padding = 0; + //this.$propHandlers.padding.call(this, this.padding = 0); + if (this.edge == undefined) + this.$propHandlers.edge.call(this, this.edge = 0); + if (this.pack == undefined) + this.$propHandlers.pack.call(this, this.edge = "start"); + if (this.align == undefined) + this.align = "stretch"; + //this.$propHandlers.align.call(this, this.align = "stretch"); + if (!apf.hasFlexibleBox && !this.$vbox && !this.height && this.align == "stretch") + myHeightHandler.call(this, {}); + }; +}).call(apf.vbox.prototype = new apf.GuiElement()); + +apf.hbox.prototype = apf.vbox.prototype; + +apf.aml.setElement("hbox", apf.hbox); +apf.aml.setElement("vbox", apf.vbox); + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * The element displays a picture. This element can read databound resources. + * + * #### Example + * + * This example shows a list with pictures. When one is selected its displayed + * in the `` element: + * + * ```xml, demo + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * ``` + * + * @class apf.img + * @define img + * @media + * @allowchild {smartbinding} + * + * + * @inherits apf.BaseSimple + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.4 + * + */ +/** + * @event click Fires when a user presses a mouse button while over this element. + * + */ +/** + * @binding value Determines the way the value for the element is retrieved + * from the bound data. + * + * #### Example + * + * Sets the image source based on data loaded into this component. + * + * ```xml + * + * + * + * + * ``` + */ +apf.img = function(struct, tagName) { + this.$init(tagName || "img", apf.NODE_VISIBLE, struct); +}; + +apf.preview = function(struct, tagName) { + this.$init(tagName || "preview", apf.NODE_VISIBLE, struct); +}; + +(function(){ + + + /** + * Sets the value of this element. This should be one of the values + * specified in the `values` attribute. + * @param {String} value The new value of this element + */ + this.setValue = function(value) { + this.setProperty("value", value, false, true); + }; + + /** + * Returns the current value of this element. + * @return {String} The current image + */ + this.getValue = function(value) { + return this.value; + }; + + + + this.$supportedProperties.push("value", "src"); + /** + * @attribute {String} value Sets or gets the url location of the image displayed. + */ + this.$propHandlers["src"] = + this.$propHandlers["value"] = function(value) { + if (this.oImage.nodeType == 1) + this.oImage.style.backgroundImage = "url(" + value + ")"; + else + this.oImage.nodeValue = value; + + //@todo resize should become a generic thing + if (this.oImage.nodeType == 2 && !this.$resize.done) { + if (this.oImg) { + + //@todo add this to $destroy + var pNode = apf.hasSingleRszEvent ? this.$pHtmlNode : this.$ext; + apf.layout.setRules(pNode, this.$uniqueId + "_image", + "var o = apf.all[" + this.$uniqueId + "];\ + if (o) o.$resize()"); + apf.layout.queue(pNode); + + this.oImg.onload = function(){ + apf.layout.forceResize(pNode); + } + + } + + this.$resize.done = true; + } + + if (this.oImg) { + this.oImg.style.display = value ? "block" : "none"; + + //RLD: disabled lines below for the preview element. the image is probably not loaded yet. + //if (value) + //this.$resize(); + } + }; + + this.refetch = function(){ + this.$propHandlers["value"].call(this, "") + this.$propHandlers["value"].call(this, this.value || this.src) + } + + this.addEventListener("$clear", function(){ + this.value = ""; + + if (this.oImg) + this.oImg.style.display = "none"; + }); + + // *** Init *** // + + this.$draw = function(){ + //Build Main Skin + this.$ext = this.$getExternal(); + this.$ext.onclick = function(e) { + this.host.dispatchEvent("click", {htmlEvent: e || event}); + }; + this.oImage = this.$getLayoutNode("main", "image", this.$ext); + if (this.oImage.nodeType == 1) + this.oImg = this.oImage.getElementsByTagName("img")[0]; + if (this.localName == "preview") { + var _self = this; + this.$ext.onclick = function() { + if (!_self.sPreview) return; + _self.$ext.innerHTML = _self.sPreview; + this.onclick = null; + }; + } + + var _self = this; + apf.addListener(this.$ext, "mouseover", function(e) { + if (!_self.disabled) + _self.dispatchEvent("mouseover", {htmlEvent: e}); + }); + + apf.addListener(this.$ext, "mouseout", function(e) { + if (!_self.disabled) + _self.dispatchEvent("mouseout", {htmlEvent: e}); + }); + }; + + this.addEventListener("DOMNodeInsertedIntoDocument", function() { + var node, + val = "", + i = this.childNodes.length; + + for (; i >= 0; --i) { + if ((node = this.childNodes[i]) && node.nodeName + && node.nodeName == "#cdata-section") { + val = node.nodeValue; + node.removeNode(); + } + } + + this.sPreview = val; + }); + + this.$resize = function(){ + var diff = apf.getDiff(this.$ext); + var wratio = 1, hratio = 1; + + this.oImg.style.width = ""; + this.oImg.style.height = ""; + + if (this.oImg.offsetWidth > this.$ext.offsetWidth) + wratio = this.oImg.offsetWidth / (this.$ext.offsetWidth - diff[0]); + if (this.oImg.offsetHeight > this.$ext.offsetHeight) + hratio = this.oImg.offsetHeight / (this.$ext.offsetHeight - diff[1]); + + if (wratio > hratio && wratio > 1) + this.oImg.style.width = "100%"; + else if (hratio > wratio && hratio > 1) + this.oImg.style.height = "100%"; + + this.oImg.style.top = ((this.$ext.offsetHeight - apf.getHeightDiff(this.$ext) + - this.oImg.offsetHeight) / 2) + "px"; + } +}).call(apf.img.prototype = new apf.BaseSimple()); + +apf.preview.prototype = apf.img.prototype; + +apf.aml.setElement("img", apf.img); +apf.aml.setElement("preview", apf.preview); + +apf.aml.setElement("name", apf.BindingRule); +apf.aml.setElement("image", apf.BindingRule); + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +/** + * Represents an item in a menu, displaying a clickable area. + * + * #### Example + * + * ```xml, demo + * + * + * + * Tutorials + * Contact + * + * + * + * File + * + * + * + * + * ``` + * + * @class apf.item + * @selection + * @define item + * @inherits apf.Presentation + * + */ +/** + * @event click Fires when a user presses the mouse button while over this element. + * @param {Object} e The standard event object. It contains the following properties: + * - xmlContext ([[XMLElement]]): The XML data node that was selected in the opener at the time of showing the context menu. + * - opener ([[apf.AmlElement]]): The element that was clicked upon when showing the context menu. + */ +apf.item = function(struct, tagName) { + this.$init(tagName || "item", apf.NODE_VISIBLE, struct); +}; + +(function(){ + this.$focussable = false; + this.$childProperty = "caption"; + this.$canLeechSkin = "item"; + + this.checked = false; + this.selected = false; + + this.implement(apf.ChildValue); + + // *** Properties and Attributes *** // + + //1 = force no bind rule, 2 = force bind rule + this.$attrExcludePropBind = apf.extend({ + "match" : 1 + }, this.$attrExcludePropBind); + + this.$booleanProperties["checked"] = true; + this.$booleanProperties["selected"] = true; + + this.$supportedProperties.push("submenu", "value", "match", "group", "icon", + "checked", "selected", "disabled", "caption", + "type", "values"); + + /** + * @attribute {String} submenu Sets or gets the id of the menu that is shown + * when the user hovers over this menu item. + * + * #### Example + * + * ```xml + * + * test + * test2 + * + * + * + * Sub menu + * + * + * + * + * File + * + * + * ``` + */ + this.$propHandlers["submenu"] = function(value) { + apf.setStyleClass(this.$ext, "submenu"); + } + + /** + * @attribute {String} value Sets or gets the value of this element. + */ + + /** + * @attribute {String} [select] Sets or gets the XPath statement which works on the + * XML context of the parent menu element to determine whether this + * item is shown. + * + * #### Example + * + * This example shows a list: + * + * ```xml + * + * Send an E-mail + * Call Number + * + * Remove + * + * View Pictures + * + * + * + * Reboot + * + * + * + * Please right-click on this plane + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * ``` + */ + this.$propHandlers["select"] = function(value) { + this.select = value + ? "self::" + value.split("|").join("|self::") + : value; + } + + /** + * @attribute {String} [group] Sets or gets the name of the group this item belongs + * to. + * + * #### Example + * + * ```xml + * + * item 1 + * item 2 + * item 3 + * item 4 + * + * ``` + */ + this.$propHandlers["group"] = function(value) { + if (this.$group && this.$group.$removeRadio) + this.$group.$removeRadio(this); + + if (!value) { + this.$group = null; + return; + } + + var group = typeof value == "string" + ? + + apf.nameserver.get("group", value) + + : value; + if (!group) { + + group = apf.nameserver.register("group", value, + new apf.$group()); + group.setAttribute("id", value); + group.dispatchEvent("DOMNodeInsertedIntoDocument"); + group.parentNode = this; + + } + this.$group = group; + + this.$group.$addRadio(this); + }; + + + /** + * @attribute {String} hotkey Sets or gets the key combination a user can press + * to active the function of this element. Use any combination of + * [[keys: Ctrl]], [[keys: Shift]], [[keys: Alt]], [[keys: F1]]-[[keys: F12]], and alphanumerical characters. Use a + * space, a minus or plus sign as a seperator. + * + * #### Example + * + * ```xml + * Quit + * ``` + */ + this.$propHandlers["hotkey"] = function(value) { + if (!this.$amlLoaded) { + var _self = this; + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + if (_self.$hotkey && _self.hotkey) + apf.setNodeValue(this.$hotkey, apf.isMac + ? apf.hotkeys.toMacNotation(_self.hotkey) : _self.hotkey); + }); + } + else if (this.$hotkey) + apf.setNodeValue(this.$hotkey, apf.isMac ? apf.hotkeys.toMacNotation(value) : value); + + if (this.$lastHotkey) { + apf.hotkeys.remove(this.$lastHotkey[0], this.$lastHotkey[1]); + delete this.$lastHotkey[0]; + } + + if (value) { + this.$lastHotkey = [value]; + var _self = this; + apf.hotkeys.register(value, this.$lastHotkey[1] = function(){ + if (_self.disabled || !_self.visible) + return; + + //hmm not very scalable... + if (_self.parentNode) { + var buttons = apf.document.getElementsByTagNameNS(apf.ns.aml, "button"); + for (var i = 0; i < buttons.length; i++) { + if (buttons[i].submenu == _self.parentNode.name) { + var btn = buttons[i]; + btn.$setState("Over", {}); + + $setTimeout(function(){ + btn.$setState("Out", {}); + }, 200); + + break; + } + } + } + + _self.$down(); + _self.$up(); + _self.$click(); + }); + } + } + + /** + * @attribute {String} icon Sets or gets the URL of the image used as an icon or + * a reference to an iconmap. + */ + this.$propHandlers["icon"] = function(value) { + if (this.$icon) + apf.skins.setIcon(this.$icon, value, this.parentNode.iconPath); + } + + /** + * @attribute {String} caption Sets or gets the text displayed on the item. + */ + this.$propHandlers["caption"] = function(value) { + if (this.$caption) + apf.setNodeValue(this.$caption, value); + } + + /** + * @attribute {String} type Sets or gets the function of this item. + * + * Possible values include: + * - `"item"` + * - `"check"` + * - `"radio"` + */ + this.$propHandlers["type"] = function(value) { + apf.setStyleClass(this.$ext, value, ["item", "check", "radio"]); + } + + this.$propHandlers["values"] = function(value) { + this.$values = typeof value == "string" + ? value.split("\|") + : (value || [1, 0]); + + this.$propHandlers["value"].call(this, this.value); + }; + + this.$propHandlers["value"] = function(value) { + if (this.type != "check") + return; + + value = (typeof value == "string" ? value.trim() : value); + + var checked; + if (this.$values) { + checked = (typeof value != "undefined" && value !== null + && value.toString() == this.$values[0].toString()); + } + else { + checked = apf.isTrue(value); + } + + if (checked != this.checked) { + this.checked = checked; + this.$propHandlers.checked.call(this, checked); + } + }; + + /** + * @attribute {Boolean} checked Sets or gets whether the item is checked. + */ + this.$propHandlers["checked"] = function(value) { + if (this.type != "check") + return; + + if (apf.isTrue(value)) + apf.setStyleClass(this.$ext, "checked"); + else + apf.setStyleClass(this.$ext, "", ["checked"]); + + if (!this.$values) { + if (this.getAttribute("values")) + this.$propHandlers["values"].call(this, this.getAttribute("values")); + //else + //this.$values = [true, false]; + } + + if (this.$values && this.$values[value ? 0 : 1] != this.value) + this.setProperty("value", this.$values ? this.$values[value ? 0 : 1] : true); + } + + this.select = function(){ + this.parentNode.select(this.group, this.value || this.caption); + } + + this.check = function(){ + this.setProperty("value", this.$values + ? this.$values[0] + : true); + } + this.uncheck = function(){ + this.setProperty("value", this.$values + ? this.$values[1] + : false); + } + + this.$check = function(){ + apf.setStyleClass(this.$ext, "selected"); + } + + this.$uncheck = function(){ + apf.setStyleClass(this.$ext, "", ["selected"]); + } + + /** + * @attribute {Boolean} selected Sets or gets whether the item is selected. + */ + this.$propHandlers["selected"] = function(value) { + if (this.type != "radio") + return; + + + if (apf.isTrue(value)) { + if (this.$group) + this.$group.setProperty("value", this.value); + this.$check(); + } + else + this.$uncheck(); + } + + /** + * @attribute {Boolean} disabled Sets or gets whether the item is active. + */ + this.$propHandlers["disabled"] = function(value) { + if (apf.isTrue(value) || value == -1) + apf.setStyleClass(this.$ext, "disabled"); + else + apf.setStyleClass(this.$ext, "", ["disabled"]); + } + + // *** Dom Hooks *** // + + //@todo apf3.0 + this.addEventListener("AMLReparent", function(beforeNode, pNode, withinParent) { + if (!this.$amlLoaded) + return; + + if (!withinParent && this.skinName != pNode.skinName) { + //@todo for now, assuming dom garbage collection doesn't leak + this.loadAml(); + } + }); + + // *** Events *** // + + this.$down = function(){ + + }; + + this.$up = function(){ + + + if (this.type == "radio") + this.parentNode.select(this.group, this.value || this.caption); + + else if (this.type == "check") { + this.setProperty("checked", !this.checked); + //this.$handlePropSet("checked", !this.checked); + } + + if (this.submenu) { + this.$over(null, true); + return; + } + + this.parentNode.$hideTree = true; + + //@todo This statement makes the menu loose focus. + if (!this.parentNode.sticky) + this.parentNode.hide();//true not focus?/ + + this.parentNode.dispatchEvent("itemclick", { + value: this.value || this.caption, + relatedNode: this, + checked: this.checked, + selected: this.selected + }); + + //@todo Anim effect here? + + this.dispatchEvent("click", { + xmlContext: this.parentNode.xmlReference, + opener: this.parentNode.opener + }); + + + }; + + this.$click = function(){ + + }; + + var timer; + this.$out = function(e) { + if (apf.isChildOf(this.$ext, e.toElement || e.explicitOriginalTarget) + || apf.isChildOf(this.$ext, e.srcElement || e.target)) //@todo test FF + return; + + clearTimeout(timer); + if (!this.submenu || this.$submenu(true)) { + apf.setStyleClass(this.$ext, "", ['hover']); + + var sel = this.parentNode.$selected; + if (sel && sel != this) + apf.setStyleClass(sel.$ext, "", ["hover"]); + + this.parentNode.$selected = null; + } + + + }; + + this.$over = function(e, force) { + if (this.parentNode.$selected == this && e) + return; + + if (this.parentNode.$selected) + apf.setStyleClass(this.parentNode.$selected.$ext, "", ["hover"]); + + apf.setStyleClass(this.$ext, "hover"); + this.parentNode.$selected = this; + + if (!force && (apf.isChildOf(this.$ext, e.toElement || e.explicitOriginalTarget) + || apf.isChildOf(this.$ext, e.fromElement || e.target))) //@todo test FF + return; + + var _self = this, ps = this.parentNode.$showingSubMenu; + if (ps && ps.name && ps.name == this.submenu) { + this.parentNode.$selected = null; + this.parentNode.$showingSubMenu = null; + _self.$submenu(); + return; + } + + clearTimeout(timer); + + if (ps && ps.visible) { + ps.hide(); + + if (_self.parentNode.$showingSubMenu == ps) + _self.parentNode.$showingSubMenu = null; + } + + function submenu(){ + if (_self.submenu && _self.parentNode.opener + && _self.parentNode.opener.visible) + _self.$submenu(); + } + + if (force) + submenu(); + else { + timer = $setTimeout(function(){ + submenu(); + timer = null; + }, 210); + } + }; + + this.$submenu = function(hide, force) { + if (!this.submenu) + return true; + + var menu = self[this.submenu] || this.submenu; + if (!menu) { + + + return; + } + + if (!hide) { + //if (this.parentNode.showingSubMenu == this.submenu) + //return; + + this.parentNode.$showingSubMenu = menu; + + var pos = apf.getAbsolutePosition(this.$ext, this.parentNode.$ext.offsetParent); + menu.display(pos[0] + this.$ext.offsetWidth - 3, + pos[1] + 3, true, this, + this.parentNode.xmlReference, this.parentNode.$uniqueId); + menu.setAttribute("zindex", (this.parentNode.zindex || this.parentNode.$ext.style.zIndex || 1) + 1); + } + else { + if (menu.visible && !force) { + return false; + } + + if (this.parentNode.$showingSubMenu == menu) + this.parentNode.$showingSubMenu = null; + + apf.setStyleClass(this.$ext, '', ['hover']); + menu.hide(); + return true; + } + }; + + // *** Init *** // + + this.$draw = function(isSkinSwitch) { + var p = this.parentNode; + while (p.$canLeechSkin == "item") + p = p.parentNode; + + //@todo apf3.0 rename doesnt work yet. + //@todo apf3.0 implement DOM Mutation events for multiselect widgets + //@todo apf3.0 implement attribute change triggers for icon, image, value, caption to updateNode this.$container + //@todo apf3.x this should be rearchitected + //@todo apf3.x the functions dont need to be overloaded if selectNodes would work properly + if (p.hasFeature(apf.__MULTISELECT__)) { + var _self = this; + + //@todo DOMNodeInserted should reset this + //@todo DOMNodeRemoved should reset this + if (!this.$hasSetSkinListener) { + var f; + this.parentNode.addEventListener("$skinchange", f = function(){ + if (_self.$amlDestroyed) //@todo apf3.x + return; + + if (_self.$ext.parentNode) + this.$deInitNode(_self, _self.$ext); + + var oInt = p == _self.parentNode ? p.$container : _self.parentNode.$container; + var node = oInt.lastChild;//@todo this should be more generic + p.$add(_self, _self.getAttribute(apf.xmldb.xmlIdTag) + "|" + this.$uniqueId, + _self.parentNode, oInt != p.$container && oInt, null); + p.$fill(); + + if (p.$isTreeArch) { + _self.$container = p.$getLayoutNode("item", "container", + _self.$ext = node && node.nextSibling || oInt.firstChild);//@todo this should be more generic + } + else _self.$ext = node && node.nextSibling || oInt.firstChild; + + var ns = _self; + while ((ns = ns.nextSibling) && ns.nodeType != 1); + + if (!ns || ns.$canLeechSkin != "item") + p.dispatchEvent("afterload"); + }); + this.addEventListener("DOMNodeRemoved", function(e) { + if (e.currentTarget == this) + this.parentNode.removeEventListener("$skinchange", f); + }); + + this.$hasSetSkinListener = true; + } + + if (!p.$itemInited) { + p.canrename = false; //@todo fix rename + p.$removeClearMessage(); //@todo this should be more generic + p.$itemInited = [p.getTraverseNodes, p.getFirstTraverseNode, p.getTraverseParent]; + + p.getTraverseNodes = function(xmlNode) { + return (xmlNode || p).getElementsByTagNameNS(apf.ns.apf, "item"); + } + p.getFirstTraverseNode = function(xmlNode) { + return (xmlNode || p).getElementsByTagNameNS(apf.ns.apf, "item")[0]; + } + p.getTraverseParent = function(xmlNode) { + return xmlNode && xmlNode.parentNode; + } + p.each = (this.prefix ? this.prefix + ":" : "") + "item"; + + //@todo this is all an ugly hack (copied to baselist.js line 868) + p.$preventDataLoad = true;//@todo apf3.0 add remove for this + + p.$initingModel = true; + p.$setDynamicProperty("icon", "[@icon]"); + p.$setDynamicProperty("image", "[@image]"); + p.$setDynamicProperty("caption", "[label/text()|@caption|text()]"); + p.$setDynamicProperty("eachvalue", "[value/text()|@value|text()]"); + p.$canLoadDataAttr = false; + + if (!p.xmlRoot) + p.xmlRoot = p; + } + + this.$loadAml = function(){ + //hack + if (!this.getAttribute("caption")) + this.setAttribute("caption", this.caption); + + var oInt = p == this.parentNode ? p.$container : this.parentNode.$container; + var node = oInt.lastChild;//@todo this should be more generic + if (!p.documentId) + p.documentId = apf.xmldb.getXmlDocId(this); + p.$add(this, apf.xmldb.nodeConnect(p.documentId, this, null, p), + this.parentNode, oInt != p.$container && oInt, null); + p.$fill(); + + if (p.$isTreeArch) { + this.$container = p.$getLayoutNode("item", "container", + this.$ext = node && node.nextSibling || oInt.firstChild);//@todo this should be more generic + } + else this.$ext = node && node.nextSibling || oInt.firstChild; + + var ns = this; + while ((ns = ns.nextSibling) && ns.nodeType != 1); + + if (!ns || ns.$canLeechSkin != "item") { + p.dispatchEvent("afterload"); + if (p.autoselect) + p.$selectDefault(this.parentNode); + } + } + + return; + } + + this.$ext = this.$getExternal(this.$isLeechingSkin + ? "item" //this.type + : "main", null, function($ext) { + var o = 'var o = apf.lookup(' + this.$uniqueId + '); if (!o || o.disabled) return; o'; + $ext.setAttribute("onmouseup", o + '.$up(event)'); + $ext.setAttribute("onmousemove", o + '.$over(event)'); + $ext.setAttribute("onmouseout", o + '.$out(event)'); + $ext.setAttribute("onmousedown", o + '.$down()'); + $ext.setAttribute("onclick", o + '.$click()'); + }); + + var _self = this; + apf.addListener(this.$ext, "mouseover", function(e) { + if (!_self.disabled) + _self.dispatchEvent("mouseover", {htmlEvent: e}); + }); + + apf.addListener(this.$ext, "mouseout", function(e) { + if (!_self.disabled) + _self.dispatchEvent("mouseout", {htmlEvent: e}); + }); + + /*p.$getNewContext("item"); + var elItem = p.$getLayoutNode("item");*/ + + //@todo if not elItem try using own skin + + //this.$ext = apf.insertHtmlNode(elItem, this.parentNode.$container); + this.$caption = this.$getLayoutNode("item", "caption", this.$ext) + this.$icon = this.$getLayoutNode("item", "icon", this.$ext); + this.$hotkey = this.$getLayoutNode("item", "hotkey", this.$ext); + + if (!isSkinSwitch && this.nextSibling && this.nextSibling.$ext) + this.$ext.parentNode.insertBefore(this.$ext, this.nextSibling.$ext); + }; + + /* + * @private + */ + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + //var x = this.$aml; + + //this.skinName = this.parentNode.skinName; + var isSkinSwitch = this.$ext ? true : false; + if (isSkinSwitch) { + if (typeof this.checked !== "undefined") + this.$handlePropSet("checked", this.checked); + else if (typeof this.selected !== "undefined") + this.$handlePropSet("selected", this.selected); + + if (this.disabled) + this.$handlePropSet("disabled", this.disabled); + + if (this.caption) + this.$handlePropSet("caption", this.caption); + } + }); +}).call(apf.item.prototype = new apf.Presentation()); + +//apf.aml.setElement("radio", apf.radio); +//apf.aml.setElement("check", apf.check); +apf.aml.setElement("item", apf.item); + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * A symbolic link to an AML element. The visibility of this element determines + * the true parent of the references AML element. Multiple junctions will compete + * to determine the parent. Make sure only one junction reference is visible + * at the same time. + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.4 + */ +apf.junction = function(){ + this.$init("junction", apf.NODE_HIDDEN); +}; + +(function(){ + this.$focussable = false; + + this.autoshow = true; + + /** + * @attribute {String} for + * @attribute {String} autoshow + */ + this.$booleanProperties["autoshow"] = true; + + this.$propHandlers["for"] = function(value) { + if (this.$amlLoaded) //@todo remove vManager + init.call(this); + } + + function init(e) { + var _self = this; + if (apf.window.vManager.permanent(this.parentNode, function(){ + //Show + _self.$reparent(); + }, function(){ + //Hide + + })) { + this.$reparent(); + } + } + + this.$reparent = function(){ + var amlNode = self[this["for"]]; + if (!amlNode) + return; //@todo warn? + + if (this.autoshow) + amlNode.show(); + + this.parentNode.insertBefore(amlNode, this); + } + + this.addEventListener("DOMNodeInsertedIntoDocument", init); +}).call(apf.junction.prototype = new apf.AmlElement()); + +apf.aml.setElement("junction", apf.junction); + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +/** + * An element displaying a text in the user interface, usually specifying + * a description of another element. When the user clicks on the label, it + * can set the focus to the connected AML element. + * + * #### Example: Connecting with "For" + * + * ```xml, demo + * + * + * + * + * Not Disabled + * + * + * + * ``` + * + * @class apf.label + * @define label + * @allowchild {smartbinding} + * + * @form + * @inherits apf.BaseSimple + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.4 + */ +/** + * @binding value Determines the way the value for the element is retrieved + * from the bound data. + * + * #### Example + * + * Sets the label text based on data loaded into this component. + * + * ```xml + * + * + * + * + * ``` + * + * A shorter way to write this is: + * + * ```xml + * + * + * + * + * ``` + */ +apf.label = function(struct, tagName) { + this.$init(tagName || "label", apf.NODE_VISIBLE, struct); +}; + +(function(){ + this.implement( + + apf.DataAction, + + apf.ChildValue + ); + + var _self = this; + + this.$focussable = false; + var forElement; + + + + /** + * Sets the value of this element. This should be one of the values + * specified in the values attribute. + * @param {String} value The new value of this element + */ + this.setValue = function(value) { + this.setProperty("value", value, false, true); + }; + + /** + * Returns the current value of this element. + * @return {String} The current value + */ + this.getValue = function(){ + return this.value; + } + + + + /** + * @attribute {String} caption Sets or gets the text displayed in the area defined by this + * element. Using the value attribute provides an alternative to using + * the text using a text node. + * + */ + /** + * @attribute {String} for Sets or gets the id of the element that receives the focus + * when the label is clicked on. + */ + /** + * @attribute {String} textalign Sets or gets the text alignment value for the label. + */ + this.$supportedProperties.push("caption", "for", "textalign"); + this.$propHandlers["caption"] = function(value) { + this.$caption.innerHTML = value; + }; + this.$propHandlers["for"] = function(value) { + forElement = typeof value == "string" ? self[value] : value; + }; + this.$propHandlers["textalign"] = function(value) { + this.$caption.style.textAlign = value || ""; + }; + + this.$draw = function(){ + //Build Main Skin + this.$ext = this.$getExternal(); + this.$caption = this.$getLayoutNode("main", "caption", this.$ext); + if (this.$caption.nodeType != 1) + this.$caption = this.$caption.parentNode; + + this.$ext.onmousedown = function(){ + if (forElement && forElement.$focussable && forElement.focussable) + forElement.focus(); + } + + var _self = this; + apf.addListener(this.$ext, "click", function(e) { + if (!_self.disabled) + _self.dispatchEvent("click", {htmlEvent: e}); + }); + + apf.addListener(this.$ext, "mouseover", function(e) { + if (!_self.disabled) + _self.dispatchEvent("mouseover", {htmlEvent: e}); + }); + + apf.addListener(this.$ext, "mouseout", function(e) { + if (!_self.disabled) + _self.dispatchEvent("mouseout", {htmlEvent: e}); + }); + }; + + this.$childProperty = "caption"; + +}).call(apf.label.prototype = new apf.BaseSimple()); + +apf.aml.setElement("label", apf.label); + + +apf.colorbox = function(struct, tagName) { + this.$init(tagName || "colorbox", apf.NODE_VISIBLE, struct); +}; + +(function(){ + this.implement( + + apf.DataAction, + + apf.ChildValue + ); + + var _self = this; + + this.$focussable = false; + var forElement; + + + + /** + * Sets the value of this element. This should be one of the values + * specified in the values attribute. + * @param {String} value The new value of this element + */ + this.setValue = function(value) { + this.setProperty("value", value, false, true); + }; + + /** + * Returns the current value of this element. + * @return {String} The current value + */ + this.getValue = function(){ + return this.value; + } + + + + /** + * @attribute {String} caption Sets or gets the text displayed in the area defined by this + * element. Using the value attribute provides an alternative to using + * the text using a text node. + * + */ + /** + * @attribute {String} for Sets or gets the id of the element that receives the focus + * when the colorbox is clicked on. + */ + /** + * @attribute {String} textalign Sets or gets the text alignment value for the colorbox. + */ + this.$supportedProperties.push("value"); + this.$propHandlers["value"] = function(value) { + this.$input.value = value; + }; + + this.$draw = function(){ + //Build Main Skin + this.$ext = this.$getExternal(); + this.$input = this.$getLayoutNode("main", "input", this.$ext); + + var _self = this; + this.$input.onchange = function(){ + _self.change(this.value); + } + }; + + this.$childProperty = "value"; + +}).call(apf.colorbox.prototype = new apf.BaseSimple()); + +apf.aml.setElement("colorbox", apf.colorbox); + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +/** + * This element displays a skinnable list of options which can be selected. + * + * Selection of multiple items is allowed. Items can be renamed + * and removed. The list can be used as a collection of checkboxes or + * radiobuttons. This is especially useful for use in forms. + * + * This element is one of the most often used elements. It can display lists + * of items in a CMS-style interface, or display a list of search results in + * a more website like interface. + * + * #### Example: A Simple List + * + * ```xml, demo + * + * + * + * The Netherlands + * United States of America + * United Kingdom + * + * + * + * ``` + * + * #### Example: Loading from a Model + * + * ```xml, demo + * + * + * + * + * + * + * ``` + * + * #### Example: Using XPaths + * + * ```xml, demo + * + * + * + * + * + * + * + * + * + * + * + * ``` + * @class apf.list + * @define list + * @allowchild {smartbinding} + * + * @selection + * @inherits apf.BaseList + * @inherits apf.Rename + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.4 + */ +/** + * @event click Fires when a user presses a mouse button while over this element. + */ + +apf.list = function(struct, tagName) { + this.$init(tagName || "list", apf.NODE_VISIBLE, struct); +}; + +apf.thumbnail = function(struct, tagName) { + this.$init(tagName || "thumbnail", apf.NODE_VISIBLE, struct); +}; + +apf.select = function(struct, tagName) { + this.$init(tagName || "select", apf.NODE_VISIBLE, struct); +}; + +apf.select1 = function(struct, tagName) { + this.$init(tagName || "selectl", apf.NODE_VISIBLE, struct); +}; + +(function(){ + this.morePos = "end"; + + + if (!apf.isIphone) + this.implement(apf.Rename); + + + + this.$getCaptionElement = function(){ + if (!(this.$caret || this.$selected)) + return; + + var x = this.$getLayoutNode("item", "caption", this.$caret || this.$selected); + if (!x) + return; + return x.nodeType == 1 ? x : x.parentNode; + }; + + + + + + + + // *** Properties and Attributes *** // + + this.$supportedProperties.push("appearance", "mode", "more", "thumbsize", "morepos"); + + this.$propHandlers["morepos"] = function(value) { + this.morePos = value; + }; + + this.$propHandlers["thumbsize"] = function(value) { + var className = this.thumbclass; + + if (apf.isIE) { //@todo detection?? + className = className.splitSafe(","); + for (var i = 0; i < className.length; i++) { + apf.setStyleRule(className[i], "width", value + "px"); + apf.setStyleRule(className[i], "height", value + "px"); + } + return; + } + + apf.setStyleRule(className, "width", value + "px"); + apf.setStyleRule(className, "height", value + "px"); + }; + + + /** + * @attribute {String} appearance Sets or gets the type of select this element is. + * This is an xforms property and only available if APF is compiled + * with `__WITH_XFORMS` set to `1`. + * + * Possible values include: + * + * - `"full"` : depending on the tagName this element is either a list of radio options or of checked options. + * - `"compact"`: this elements functions like a list with multiselect off. + * - `"minimal"`: this element functions as a dropdown element. + */ + this.$propHandlers["appearance"] = function(value) { + + }; + + + /** + * @attribute {String} more Adds a new item to the list and lets the users + * type in the new name. This is especially useful in the interface when + * the mode is set to check or radio--for instance in a form. + * + * #### Example + * + * This example shows a list in form offering the user several options. The + * user can add a new option. A server script could remember the addition + * and present it to all new users of the form. + * + * ```xml + * + * + * + * Suggestion 1 + * Suggestion 2 + * + * + * + * Which newspapers do you read? + * + * + * + * + * + * + * + * + * + * + * New Answer + * + * + * + * ``` + */ + this.$propHandlers["more"] = function(value) { + if (value) { + this.delayedselect = false; + this.addEventListener("xmlupdate", $xmlUpdate); + this.addEventListener("afterload", $xmlUpdate); + //this.addEventListener("afterrename", $afterRenameMore); + //this.addEventListener("beforeselect", $beforeSelect); + + this.$addMoreItem = function(msg) { + if (!this.moreItem) + this.$fill(); + if (this.morePos == "begin") + this.$container.insertBefore(this.moreItem, this.$container.firstChild); + else + this.$container.appendChild(this.moreItem); + }; + this.$updateClearMessage = function(){} + this.$removeClearMessage = function(){}; + } + else { + this.removeEventListener("xmlupdate", $xmlUpdate); + this.removeEventListener("afterload", $xmlUpdate); + //this.removeEventListener("afterrename", $afterRenameMore); + //this.removeEventListener("beforeselect", $beforeSelect); + } + }; + + function $xmlUpdate(e) { + if ((!e.action || "insert|add|synchronize|move".indexOf(e.action) > -1) && this.moreItem) { + if (this.morePos == "begin") + this.$container.insertBefore(this.moreItem, this.$container.firstChild); + else + this.$container.appendChild(this.moreItem); + } + } + + /*function $afterRenameMore(){ + var caption = this.$applyBindRule("caption", this.caret) + var xmlNode = this.findXmlNodeByValue(caption); + + var curNode = this.caret; + if (xmlNode != curNode || !caption) { + if (xmlNode && !this.isSelected(xmlNode)) + this.select(xmlNode); + this.remove(curNode); + } + else + if (!this.isSelected(curNode)) + this.select(curNode); + } + + function $beforeSelect(e) { + //This is a hack + if (e.xmlNode && this.isSelected(e.xmlNode) + && e.xmlNode.getAttribute('custom') == '1') { + this.setCaret(e.xmlNode); + this.selected = e.xmlNode; + $setTimeout(function(){ + _self.startRename() + }); + return false; + } + }*/ + + + // *** Keyboard support *** // + + + this.addEventListener("keydown", this.$keyHandler, true); + + + // *** Init *** // + + this.$draw = function(){ + this.appearance = this.getAttribute("appearance") || "compact"; + + //Build Main Skin + this.$ext = this.$getExternal(); + this.$container = this.$getLayoutNode("main", "container", this.$ext); + + if (apf.hasCssUpdateScrollbarBug && !this.mode) + this.$fixScrollBug(); + + var _self = this; + this.$ext.onclick = function(e) { + _self.dispatchEvent("click", { + htmlEvent: e || event + }); + } + + + + //Get Options form skin + //Types: 1=One dimensional List, 2=Two dimensional List + this.listtype = parseInt(this.$getOption("main", "type")) || 1; + //Types: 1=Check on click, 2=Check independent + this.behaviour = parseInt(this.$getOption("main", "behaviour")) || 1; + + this.thumbsize = this.$getOption("main", "thumbsize"); + this.thumbclass = this.$getOption("main", "thumbclass"); + }; + + this.$loadAml = function(x) { + }; + + this.$destroy = function(){ + if (this.$ext) + this.$ext.onclick = null; + apf.destroyHtmlNode(this.oDrag); + this.oDrag = null; + }; +}).call(apf.list.prototype = new apf.BaseList()); + +apf.thumbnail.prototype = +apf.select.prototype = +apf.select1.prototype = apf.list.prototype; + +apf.aml.setElement("thumbnail", apf.thumbnail); +apf.aml.setElement("select", apf.select); +apf.aml.setElement("select1", apf.select1); +apf.aml.setElement("list", apf.list); + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * @todo description + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.4 + */ +apf.loader = function(){ + this.$init("loader", apf.NODE_HIDDEN); + + this.show = function(){ + this.$ext.style.display = "block"; + } + + this.hide = function(){ + this.$ext.style.display = "none"; + } + + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + var pHtmlNode; + if (!(pHtmlNode = this.parentNode.$int)) + return; + + this.$ext = apf.insertHtmlNode(null, pHtmlNode, null, (this.$aml + ? (this.$aml.serialize ? this.$aml.serialize() : this.$aml.xml) + : this.serialize()).replace(/^<[^>]*>\s*|\s*<[^>]*>$/g, "")); + + if (!apf.loaded) { + var _self = this; + if (apf.config.loaderAnimIndicator) + _self.animateLoader(10); + apf.addEventListener("load", function(){ + if (apf.isTrue(apf.config.autoHideLoading)) { + apf.queue.empty(); + _self.hide(); + } + else { + if (apf.config.loaderAnimIndicator) + _self.animateLoader(20); + } + }); + } + }); + + this.lastLoaderStep = 0; + + /* + * Animates a loader indiacator + * + * the step is in the % of the total width of the indicator + * + */ + this.animateLoader = function(step) { + var _self = this, + loaderEl = document.getElementById(apf.config.loaderAnimIndicator); + if (!loaderEl) + return; + + step = apf.config.loaderWidth * (step/100); + + var fromStep = this.lastLoaderStep, + toStep = this.lastLoaderStep + step; + + this.lastLoaderStep = toStep; + + if (toStep > apf.config.loaderWidth) + toStep = apf.config.loaderWidth; + + apf.tween.single(document.getElementById('animatedLoader'), { + steps: 5, + anim: apf.tween.EASEOUT, + type: "width", + from: fromStep, + to: toStep, + onfinish: function() { + if (toStep >= apf.config.loaderWidth) { + apf.queue.empty(); + _self.hide(); + } + } + }); + }; +}; + +apf.loader.prototype = new apf.AmlElement(); + +apf.aml.setElement("loader", apf.loader); + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +/** + * This element displays a skinnable menu of items which can be choosen. + * + * Based on the context of the menu, items can be shown and hidden. + * + * + * #### Example + * + * ```xml, demo + * + * + * + * Tutorials + * Contact + * + * + * Tutorials + * + * Visit Ajax.org + * Exit + * + * + * + * + * File + * Edit + * + * + * + * + * + * ``` + * + * @class apf.menu + * @define menu + * @selection + * @allowchild item, divider, check, radio + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.4 + * + * @inherits apf.Presentation + */ +/** + * @event display Fires when the contextmenu is shown. + */ +/** + * @event itemclick Fires when a user presses the mouse button while over a child of this element. + * @param {Object} e The standard event object. The following property is available: + * - `value` ([[String]]): the value of the clicked element. + * + */ +apf.menu = function(struct, tagName) { + this.$init(tagName || "menu", apf.NODE_VISIBLE, struct); + + this.animate = apf.enableAnim; +}; + +(function(){ + this.$focussable = apf.MENU; + this.$positioning = "basic" + //var _self = this; + //var blurring = false; + + // *** Properties and Attributes *** // + + //this.zindex = 10000000; + this.visible = false; + this.matchhide = false; + + this.$booleanProperties["animate"] = true; + this.$booleanProperties["pinned"] = true; + this.$booleanProperties["sticky"] = true; + this.$booleanProperties["matchhide"] = true; + + this.$propHandlers["visible"] = function(value, prop, force, nofocus, hideOpener) { + if (!this.$ext) + return; + + if (value) { + this.$ext.style.display = "block"; + if (this.opener && this.opener.localName.indexOf('item') > -1) + this.opener.parentNode.$showingSubMenu = this; + } + else { + this.$ext.style.display = "none"; + + var lastFocus = apf.menu.lastFocus; + var opener = this.opener; + //@todo test this with a list being the opener of the menu + if (lastFocus != this.opener && this.opener && this.opener.$blur) + this.opener.$blur(); + + if (this.opener && this.opener.parentNode && this.opener.parentNode.localName == "menu") { + if (!this.$hideTree) + this.$hideTree = -1 + this.opener.parentNode.focus(); + } + + + else if (lastFocus) { + //We're being hidden because some other object gets focus + if (apf.window.$settingFocus) { + if (apf.window.$settingFocus != lastFocus && lastFocus.$blur) + lastFocus.$blur(); + this.$blur(); + + if (apf.window.$settingFocus.localName != "menu") //not menu walking + apf.menu.lastFocus = null; + } + //We're being hidden because window looses focus + + //We're just being hidden + else if (this.$hideTree) { + if (!this.$hideTree) + this.$hideTree = -1 + + var visTest = (lastFocus.disabled || lastFocus.$ext + && !lastFocus.$ext.offsetHeight || !lastFocus.visible) + && lastFocus != apf.document.documentElement; + + if (nofocus || visTest) { + if (lastFocus.$blur) + lastFocus.$blur(); + this.$blur(); + apf.document.activeElement = null; + + if (visTest && apf.window.moveNext() === false) + apf.window.$focusRoot(); + } + else { + lastFocus.focus(null, null, true); + } + + apf.menu.lastFocus = null; + } + } + + + clearTimeout(this.$submenuTimer); + + if (this.$showingSubMenu) { + this.$showingSubMenu.hide(); + this.$showingSubMenu = null; + } + + if (this.opener && this.opener.$submenu) { + this.opener.$submenu(true, true); + + //@todo problem with loosing focus when window looses focus + if (this.$hideTree === true && this.opener + && this.opener.parentNode + && this.opener.parentNode.localName == "menu" + && this.opener.parentNode.$hideTree != -1) { + this.opener.parentNode.$hideTree = true + this.opener.parentNode.hide(); + } + + this.opener = null; + } + this.$hideTree = null; + + if (this.$selected) { + apf.setStyleClass(this.$selected.$ext, "", ["hover"]); + this.$selected = null; + } + + this.dispatchEvent("hide", {opener: opener}); + } + }; + + // *** Public Methods *** // + + var lastFocus; + + /** + * Shows the menu, optionally within a certain context. + * @param {Number} x The left position of the menu. + * @param {Number} y The top position of the menu. + * @param {Boolean} noanim Whether to animate the showing of this menu. + * @param {apf.AmlElement} opener The element that is the context of this menu. + * @param {XMLElement} xmlNode The {@link term.datanode data node} that provides data context to the menu child nodes. + * @see apf.GuiElement@contextmenu + */ + this.display = function(x, y, noanim, opener, xmlNode, openMenuId, btnWidth) { + this.opener = opener; + + //Show / hide Child Nodes Based on XML + if (xmlNode && !this.disabled) { + var last, i, node, + nodes = this.childNodes, + c = 0, + l = nodes.length, result; + for (i = 0; i < l; i++) { + node = nodes[i]; + if (node.nodeType != 1 || node.localName != "item") + continue; + + result = !xmlNode || !node.match || (node.cmatch || (node.cmatch = apf.lm.compile(node.match, { + xpathmode: 3, + injectself: true + })))(xmlNode) + + if (result) { + if (this.matchhide) + node.show(); + else + node.enable(); + + if (node.localName == "divider" && this.matchhide) { + last = node; + if (c == 0) + node.hide(); + c = 0; + } + else c++; + } + else { + if (this.matchhide) + node.hide(); + else + node.disable(); + + if (!node.nextSibling && c == 0 && last) + last.hide(); + } + } + } + + if (this.oOverlay) { + if (btnWidth) { + this.oOverlay.style.display = "block"; + this.oOverlay.style.width = btnWidth + "px"; + } + else + this.oOverlay.style.display = "none"; + } + + function afterRender(){ + if (x === null) { + apf.popup.show(this.$uniqueId, { + x: 0, + y: this.ref ? 0 : opener.$ext.offsetHeight, + animate: noanim || !this.animate ? false : "fade", + steps: 10, + ref: (this.ref || opener).$ext, + allowTogether: openMenuId, + autohide: !this.pinned, + noleft: this.left !== undefined, + setZindex: this.zindex ? false : true, + up: (this.ref || opener).submenudir == "up" + }); + } + else { + //var bodyPos = apf.getAbsolutePosition(document.body); + apf.popup.show(this.$uniqueId, { + x: x, + y: y - (apf.isIE && apf.isIE < 8 ? 1 : 0), + animate: noanim || !this.animate ? false : "fade", + steps: 10, + //ref : this.$ext.offsetParent, + allowTogether: openMenuId, + autohide: !this.pinned, + setZindex: this.zindex ? false : true + //autoCorrect : false + }); + } + + var lastFocus = + apf.menu.lastFocus = opener && opener.$focussable === true + ? opener + : apf.menu.lastFocus || apf.document.activeElement; + + apf.popup.last = null; + + //if (!apf.isGecko) //This disables keyboard support for gecko - very strange behaviour + this.focus(); + + //Make the component that provides context appear to have focus + + if (lastFocus && lastFocus != this && lastFocus.$focus) + lastFocus.$focus(); + + this.xmlReference = xmlNode; + + //@todo consider renaming this to onshow and onhide + this.dispatchEvent("display", {opener: opener}); + } + + this.visible = false; + + if (!this.parentNode) + apf.document.documentElement.appendChild(this); + + if (this.$rendered !== false) { + this.show(); + afterRender.call(this); + } + else { + this.addEventListener("afterrender", afterRender); + this.show(); + } + }; + + /** + * Returns the current group value of this element. + * @return {String} The current selected value. + */ + this.getValue = function(group) { + return this.getSelected(group).value || ""; + }; + + /** + * Retrieves the selected element from a group of radio elements. + * @param {String} group The name of the group. + * @return {apf.radiobutton} The selected radio element. + */ + this.getSelected = function(group) { + var nodes = this.childNodes; + var i, l = nodes.length; + for (i = 0; i < l; i++) { + if (nodes[i].group != group) + continue; + + if (nodes[i].selected) + return nodes[i]; + } + + return false; + }; + + /** + * Selects an element within a radio group. + * @param {String} group The name of the group. + * @param {String} value The value of the item to select. + */ + this.select = function(group, value) { + var nodes = this.childNodes; + var i, l = nodes.length; + for (i = 0; i < l; i++) { + if (nodes[i].group != group) + continue; + + if (value && (nodes[i].value == value || !nodes[i].value && nodes[i].caption == value)) + nodes[i].setProperty("selected", true, false, true); + //nodes[i].$handlePropSet("selected", true); + else if (nodes[i].selected) + nodes[i].setProperty("selected", false, false, true); + //nodes[i].$handlePropSet("selected", false); + } + }; + + // *** Events *** // + + + this.addEventListener("keydown", function(e) { + var node, key = e.keyCode; + //var ctrlKey = e.ctrlKey; + //var shiftKey = e.shiftKey; + + switch (key) { + case 13: + if (!this.$selected) + return; + + node = this.$selected; + node.$down(); + node.$up(); + node.$click(); + break; + case 27: + this.hide(); + break; + case 38: + //UP + node = this.$selected && this.$selected.previousSibling + || this.lastChild; + + if (node && node.localName == "divider") + node = node.previousSibling; + + if (!node) + return; + + if (this.$selected) + apf.setStyleClass(this.$selected.$ext, "", ["hover"]); + + apf.setStyleClass(node.$ext, "hover"); + this.$selected = node; + break; + case 40: + //DOWN + node = this.$selected && this.$selected.nextSibling + || this.firstChild; + + if (node && node.localName == "divider") + node = node.nextSibling; + + if (!node) + return; + + if (this.$selected) + apf.setStyleClass(this.$selected.$ext, "", ["hover"]); + + apf.setStyleClass(node.$ext, "hover"); + this.$selected = node; + break; + case 37: + //LEFT + //if (this.$selected && this.$selected.submenu) + //this.$selected.$submenu(true, true); + + if (!this.opener) + return; + + if (this.opener.localName == "button") { + node = this.opener.previousSibling; + while (node && !node.submenu) + node = node.previousSibling; + + if (node) { + node.dispatchEvent("mouseover"); + + var btnMenu = node.parentNode.menuIsPressed; + if (btnMenu) { + self[btnMenu.submenu].dispatchEvent("keydown", { + keyCode: 40 + }); + } + } + } + else if (this.opener.parentNode.localName == "menu") { + //@todo Ahum bad abstraction boundary + var op = this.opener; + this.hide(); + apf.setStyleClass(op.$ext, "hover"); + op.parentNode.$showingSubMenu = null; + } + + break; + case 39: + //RIGHT + if (this.$selected && this.$selected.submenu) { + this.$selected.$submenu(null, true); + this.$showingSubMenu.dispatchEvent("keydown", { + keyCode: 40 + }); + + return; + } + + if (this.opener) { + var op = this.opener; + while (op && op.parentNode && op.parentNode.localName == "menu") + op = op.parentNode.opener; + + if (op && op.localName == "button") { + node = op.nextSibling; + while (node && !node.submenu) + node = node.nextSibling; + + if (node) { + node.dispatchEvent("mouseover"); + + var btnMenu = node.parentNode.menuIsPressed; + if (btnMenu) { + (self[btnMenu.submenu] || btnMenu.submenu).dispatchEvent("keydown", { + keyCode: 40 + }); + } + + return; + } + } + } + + if (!this.$selected) { + arguments.callee.call(this, { + keyCode: 40 + }); + } + + break; + default: + return; + } + + return false; + }, true); + + + //Hide menu when it looses focus or when the popup hides itself + function forceHide(e) { + if (this.$showingSubMenu || this.pinned + || apf.isChildOf(e.fromElement, e.toElement) + || apf.isChildOf(e.toElement, e.fromElement) + || apf.isChildOf(this, e.toElement) + || (e.name !== "popuphide" && !e.toElement) + || e.toElement && apf.popup.cache[e.toElement.$uniqueId]) + return; + + if (this.$hideTree != -1) { + this.$hideTree = true; + this.hide(); + } + + return false; + } + + this.addEventListener("focus", function(){ + apf.popup.last = this.$uniqueId; + }); + + this.addEventListener("blur", forceHide); + this.addEventListener("popuphide", forceHide); + + // *** Init *** // + + this.$draw = function(){ + this.$pHtmlNode = document.body; + + //Build Main Skin + this.$ext = this.$getExternal(); + this.oOverlay = this.$getLayoutNode("main", "overlay", this.$ext); + + apf.popup.setContent(this.$uniqueId, this.$ext, "", null, null); + }; + + this.$loadAml = function(x) { + this.$int = this.$getLayoutNode("main", "container", this.$ext); + }; + + this.$destroy = function(){ + apf.popup.removeContent(this.$uniqueId); + }; +}).call(apf.menu.prototype = new apf.Presentation()); + +apf.aml.setElement("menu", apf.menu); + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * element specifying a method available within the rpc element. + * + * @attribute {String} name the name of the method. This name will + * be available on the rpc object as a + * javascript method. + * Example: + * + * + * + * + * + * + * comm.save(data); + * + * + * @attribute {String} [callback] the name of the method that handles + * the return of the call. + * @attribute {Boolean} [async] whether the call is executed in the + * backround. Default is true. When set + * to false the application hangs while + * this call is executed. + * @attribute {Boolean} [caching] whether the call is cached. Default + * is false. When set to true any call + * with the same data will return immediately + * with the cached result. + * @attribute {Boolean} [ignore-offline] whether the method should not be stored + * for later execution when offline. + * @attribute {Boolean} [method-name] the name sent to the server. + * + * @attribute {String} [type] the type of the returned data + * Possible values: + * xml returns the response as an xml document + * + * @allowchild variable + */ +apf.method = function(struct, tagName) { + this.$init(tagName || "method", apf.NODE_HIDDEN, struct); + + this.async = true; + this.caching = false; + this["ignore-offline"] = false; +}; + +(function(){ + this.$parsePrio = "002"; + + this.$booleanProperties["async"] = true; + this.$booleanProperties["caching"] = true; + this.$booleanProperties["ignore-offline"] = true; + this.$booleanProperties["cors-with-credentials"] = true; + + this.$supportedProperties.push("name", "receive", "async", "caching", + "ignore-offline", "method-name", "type", "url", "cors-with-credentials"); + + this.$propHandlers["ignore-offline"] = function(value) { + this.ignoreOffline = value; + }; + + this.$propHandlers["method-name"] = function(value) { + this.methodName = value; + }; + + this.$propHandlers["cors-with-credentials"] = function(value) { + this.withCredentials = value; + }; + + // *** DOM Handlers *** // + + this.addEventListener("DOMNodeInserted", function(e) { + if (this.parentNode.$addMethod && e.currentTarget == this) + this.parentNode.$addMethod(this); + }); + + this.addEventListener("DOMNodeRemoved", function(e) { + if (this.parentNode.$removeMethod && e.currentTarget == this) + this.parentNode.$removeMethod(this); + }); + + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + if (this.parentNode.$addMethod) + this.parentNode.$addMethod(this); + }); +}).call(apf.method.prototype = new apf.AmlElement()); + +apf.aml.setElement("method", apf.method); + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/* + * @private + */ +apf.WinServer = { + count: 9000, + wins: [], + + setTop: function(win, norecur) { + if (win.zindex || win.modal) + return; + + if (win.$opened) { + if (win.$opened.visible) + return; + else + delete win.$opened; + } + + var topmost; + if (!norecur && this.wins.length) { + var topmost = this.wins[this.wins.length - 1]; + if (topmost == win) + return; + + if (!topmost.modal || !topmost.visible) + topmost = null; + else if (topmost && win.modal) { + win.$opener = topmost; + topmost.$opened = win; + topmost = null; + } + } + + this.count += 2; + + win.setProperty("zindex", this.count); + this.wins.remove(win); + this.wins.push(win); + + if (topmost) + this.setTop(topmost, true); + + return win; + }, + + setNext: function(){ + if (this.wins.length < 2) return; + var nwin, start = this.wins.shift(); + do { + if (this.setTop(nwin || start).visible) + break; + nwin = this.wins.shift(); + } while (start != nwin); + }, + + setPrevious: function(){ + if (this.wins.length < 2) return; + this.wins.unshift(this.wins.pop()); + var nwin, start = this.wins.pop(); + do { + if (this.setTop(nwin || start).visible) + break; + nwin = this.wins.pop(); + } while (start != nwin); + }, + + remove: function(win) { + this.wins.remove(win); + } +} + +/** + * This element displays a skinnable, draggable window. It can be given + * a minimum and miximum width and height, as well as keybindings and various buttons. + * + * + * #### Example + * + * ```xml, demo + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * ``` + * + * @class apf.window + * @define window + * @container + * @allowchild {elements}, {smartbinding}, {anyaml} + * + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.4 + * + * @inherits apf.Presentation + * @inheritsElsewhere apf.Transaction + * + */ + /** + * @event show Fires when the window is opened. + */ + /** + * @event close Fires when the window is closed. + */ + /** + * + * @event editstart Fires before the user edits the properties of this window. Used mostly for when this window is part of the portal. + */ + /** + * @event editstop Fires after the user edited the properties of this window. Used mostly for when this window is part of the portal. + * @cancelable Prevents the edit panel from being closed. + */ +/** + * @event statechange Fires after the state of this window changed. + * @param {Object} e The standard event object. The following properties are available: + * + * - `minimized` ([[Boolean]]): Specifies whether the window is minimized. + * - `maximized` ([[Boolean]]): Specifies whether the window is maximized. + * - `normal` ([[Boolean]]): Specifies whether the window has it's normal size and position. + * - `edit` ([[Boolean]]): Specifies whether the window is in the edit state. + * - `closed` ([[Boolean]]): Specifies whether the window is closed. + */ +apf.toolwindow = function(struct, tagName) { + this.$init(tagName || "toolwindow", apf.NODE_VISIBLE, struct); +}; + +apf.modalwindow = function(struct, tagName) { + this.$init(tagName || "modalwindow", apf.NODE_VISIBLE, struct); +}; + +apf.AmlWindow = function(struct, tagName) { + this.$init(tagName || "window", apf.NODE_VISIBLE, struct); +}; + +(function(){ + this.implement( + apf.BaseStateButtons + ); + + this.$isWindowContainer = true; + this.collapsedHeight = 30; + this.canHaveChildren = 2; + this.visible = false; + this.showdragging = false; + this.kbclose = false; + this.$focussable = apf.KEYBOARD; + this.$editableCaption = ["title"]; + + // *** Public Methods *** // + + + + /** + * Sets the title of the window. + * @chainable + * @param {String} caption The text of the title. + */ + this.setTitle = function(caption) { + this.setProperty("title", caption, false, true); + return this; + }; + + /** + * Sets the icon of the window. + * @chainable + * @param {String} icon The location of the image. + */ + this.setIcon = function(icon) { + this.setProperty("icon", icon, false, true); + return this; + }; + + //For modal elements + this.show = function(callback) { + this.execAction = callback; //@todo Proper error handling?? + this.setProperty("visible", true, false, true); + return this; + } + + + + + this.bringToFront = function(){ + apf.WinServer.setTop(this); + return this; + }; + + // *** Properties and Attributes *** // + + this.$booleanProperties["modal"] = true; + this.$booleanProperties["center"] = true; + this.$booleanProperties["transaction"] = true; + this.$booleanProperties["hideselects"] = true; + this.$booleanProperties["showdragging"] = true; + this.$booleanProperties["kbclose"] = true; + this.$supportedProperties.push("title", "icon", "modal", "minwidth", + "minheight", "hideselects", "center", "kbclose", + "maxwidth", "maxheight", "showdragging", "transaction"); + + /** + * @attribute {Boolean} modal Specifies whether the window prevents access to the + * layout below it. + */ + this.$propHandlers["modal"] = function(value) { + if (value) { + if (this.visible) + apf.plane.show(this.$ext, false, null, null, { + color: "black", + opacity: this.cover && this.cover.getAttribute("opacity") || 0.5, + protect: this.$uniqueId, + customCover: this.cover || "" + }); + } + else { + apf.plane.hide(this.$uniqueId); + } + }; + + /** + * @attribute {Boolean} center Centers the window relative to its parent's + * containing rect when shown. + */ + this.$propHandlers["center"] = function(value) { + this.$ext.style.position = "absolute"; //@todo no unset + }; + + /** + * @attribute {String} title Specifies the text of the title. + */ + this.$propHandlers["title"] = function(value) { + if (this.oTitle) + this.oTitle.nodeValue = value; + }; + + /** + * @attribute {String} icon Specifies the location of the image. + */ + this.$propHandlers["icon"] = function(value) { + if (!this.oIcon) return; + + this.oIcon.style.display = value ? "" : "none"; + apf.skins.setIcon(this.oIcon, value, this.iconPath); + }; + + this.$afterRender = function(){ + if (this.center && !this.left && !this.top && !this.right && !this.bottom && !this.anchors) { + + apf.layout.processQueue(); + + + var size = !this.$ext.offsetParent || this.$ext.offsetParent.tagName == "BODY" + ? [apf.getWindowWidth(), apf.getWindowHeight()] + : [this.$ext.offsetParent.offsetWidth, this.$ext.offsetParent.offsetHeight, 0, 0]; + + if (size.length == 2) { + size.push(document.documentElement.scrollLeft, + document.documentElement.scrollTop); + } + + //@todo it's better to add this to the layout queue + this.$ext.style.left = (Math.max(0, (( + size[0] - parseInt((this.width || this.$ext.offsetWidth) || 0))/2)) + size[2]) + "px"; + this.$ext.style.top = (Math.max(0, (( + size[1] - parseInt(this.$ext.offsetHeight || 0))/3)) + size[3]) + "px"; + } + + + //@todo make widget a tagname and alias + if (this.$amlLoaded && (this.model + || (!this.dockable || !this.aData) && !this.$isWidget + && this.localName != "toolwindow")) + this.focus(false, {mouse:true}); + + + this.dispatchEvent("show"); + } + + var hEls = [], wasVisible; + this.$propHandlers["visible"] = function(value) { + if (apf.isTrue(value)){ + if (this.dispatchEvent("beforeshow") === false) + return (this.visible = false); + + if (this.modal) { + apf.plane.show(this.$ext, false, null, null, { + color: "black", + opacity: this.cover && this.cover.getAttribute("opacity") || 0.5, + protect: this.$uniqueId, + customCover: this.cover || "" + }); + } + + this.state = this.state.split("|").remove("closed").join("|"); + + this.$ext.style.display = ""; //Some form of inheritance detection + + //if (this.modal) + //this.$ext.style.position = "fixed"; + + if (!apf.canHaveHtmlOverSelects && this.hideselects) { + hEls = []; + var nodes = document.getElementsByTagName("select"); + for (var i = 0; i < nodes.length; i++) { + var oStyle = apf.getStyle(nodes[i], "display"); + hEls.push([nodes[i], oStyle]); + nodes[i].style.display = "none"; + } + } + + //if (this.modal) + //this.$ext.style.zIndex = apf.plane.$zindex - 1; + + if (apf.isIE) { + var cls = this.$ext.className; + this.$ext.className = "rnd" + Math.random(); + this.$ext.className = cls; + } + + if (this.$rendered === false) + this.addEventListener("afterrender", this.$afterRender); + else + this.$afterRender(); + } + else { + if (this.modal) + apf.plane.hide(this.$uniqueId); + + this.$ext.style.display = "none"; + + if (!apf.canHaveHtmlOverSelects && this.hideselects) { + for (var i = 0; i < hEls.length; i++) { + hEls[i][0].style.display = hEls[i][1]; + } + } + + if (this.hasFocus()) + apf.window.moveNext(true, this, true);//go backward to detect modals + + this.visible = false; + + this.dispatchEvent("hide"); + } + + + if (apf.layout && this.$int) + apf.layout.forceResize(this.$int); //@todo this should be recursive down + + + wasVisible = value; + }; + + this.$propHandlers["zindex"] = function(value) { + this.$ext.style.zIndex = value + 1; + }; + + // *** Keyboard *** // + + + + this.addEventListener("keydown", function(e) { + var key = e.keyCode; + var ctrlKey = e.ctrlKey; + var shiftKey = e.shiftKey; + + /*if (key > 36 && key < 41) { + if (this.hasFeature && this.hasFeature(apf.__ANCHORING__)) + this.$disableAnchoring(); + }*/ + + var retValue = false; + switch (key) { + /*case 9: + break; + case 13: + break; + case 32: + break;*/ + case 38: + //UP + if (shiftKey && this.resizable) + this.setProperty("height", Math.max(this.minheight || 0, + this.$ext.offsetHeight - (ctrlKey ? 50 : 10))); + else if (this.draggable) + this.setProperty("top", + this.$ext.offsetTop - (ctrlKey ? 50 : 10)); + break; + case 37: + //LEFT + if (shiftKey && this.resizable) + this.setProperty("width", Math.max(this.minwidth || 0, + this.$ext.offsetWidth - (ctrlKey ? 50 : 10))); + else if (this.draggable) + this.setProperty("left", + this.$ext.offsetLeft - (ctrlKey ? 50 : 10)); + break; + case 39: + //RIGHT + if (shiftKey && this.resizable) + this.setProperty("width", Math.min(this.maxwidth || 10000, + this.$ext.offsetWidth + (ctrlKey ? 50 : 10))); + else if (this.draggable) + this.setProperty("left", + this.$ext.offsetLeft + (ctrlKey ? 50 : 10)); + break; + case 40: + //DOWN + if (shiftKey && this.resizable) + this.setProperty("height", Math.min(this.maxheight || 10000, + this.$ext.offsetHeight + (ctrlKey ? 50 : 10))); + else if (this.draggable) + this.setProperty("top", + this.$ext.offsetTop + (ctrlKey ? 50 : 10)); + break; + default: + retValue = null; + return; + } + + if (apf.hasSingleRszEvent) + apf.layout.forceResize(this.$int); + + return retValue; + }, true); + + this.addEventListener("keydown", function(e) { + if (e.keyCode == 27 && this.buttons.indexOf("close") > -1 + && (!this.dockable || !this.aData) && this.kbclose) + this.close(); + }); + + + + + // *** Init *** // + + this.$draw = function(){ + this.popout = apf.isTrue(this.getAttribute("popout")); + if (this.popout) + this.$pHtmlNode = document.body; + + this.$ext = this.$getExternal(null, null, function(oExt) { + this.$initButtons(oExt); + }); + this.oTitle = this.$getLayoutNode("main", "title", this.$ext); + this.oIcon = this.$getLayoutNode("main", "icon", this.$ext); + this.oDrag = this.$getLayoutNode("main", "drag", this.$ext); + this.$buttons = this.$getLayoutNode("main", "buttons", this.$ext); + this.cover = this.$getLayoutNode("cover"); + + if (this.popout) + this.$ext.style.position = "absolute"; + + if (this.oIcon) + this.oIcon.style.display = "none"; + + + + var _self = this; + if (this.oDrag) { + this.oDrag.host = this; + this.oDrag.onmousedown = function(e) { + if (!e) e = event; + + //because of some issue I don't understand oExt.onmousedown is not called + if (!_self.$isWidget && (!_self.aData || !_self.dockable || _self.aData.hidden == 3)) + apf.WinServer.setTop(_self); + + if (_self.$lastState.maximized) + return false; + + + if (_self.aData && _self.dockable) { + if (_self.$lastState.normal) //@todo + _self.startDocking(e); + return false; + } + + }; + } + + this.$ext.onmousedown = function(){ + + var p = apf.document.activeElement; + if (p && p.$focusParent != _self && p.$focusParent.modal) + return false; + + + //Set ZIndex on oExt mousedown + if (!_self.$isWidget && (!_self.aData || !_self.dockable || _self.aData.hidden == 3)) + apf.WinServer.setTop(_self); + + if (!_self.$lastState.normal) + return false; + } + this.$ext.onmousemove = function(){ + if (!_self.$lastState.normal) + return false; + } + + + + /*var v; + if (!((v = this.getAttribute("visible")).indexOf("{") > -1 || v.indexOf("[") > -1)) { + this.$aml.setAttribute("visible", "{" + apf.isTrue(v) + "}"); + }*/ + }; + + this.$loadAml = function(x) { + apf.WinServer.setTop(this); + + this.$int = this.$getLayoutNode("main", "container", this.$ext); + + + if (this.oTitle) { + var _self = this; + (this.oTitle.nodeType != 1 + ? this.oTitle.parentNode + : this.oTitle).ondblclick = function(e) { + if (_self.state.indexOf("normal") == -1) + _self.restore(); + else if (_self.buttons.indexOf("max") > -1) + _self.maximize(); + else if (_self.buttons.indexOf("min") > -1) + _self.minimize(); + } + } + + if (typeof this.draggable == "undefined") { + (this.$propHandlers.draggable + || apf.GuiElement.propHandlers.draggable).call(this, true); + this.draggable = true; + } + + if (typeof this.buttons == "undefined") + this.buttons = ""; + //this.setProperty("buttons", "min|max|close"); + + + if (this.modal === undefined) { + this.$propHandlers.modal.call(this, true); + this.modal = true; + } + + //Set default visible hidden + if (!this.visible) { + this.$ext.style.display = "none"; + } + + else if (this.modal) { + var _self = this; + apf.queue.add("focus", function(){ + _self.focus(false, {mouse:true}); + }); + } + + + if (this.minwidth === undefined) + this.minwidth = this.$getOption("Main", "min-width"); + if (this.minheight === undefined) + this.minheight = this.$getOption("Main", "min-height"); + if (this.maxwidth === undefined) + this.maxwidth = this.$getOption("Main", "max-width"); + if (this.maxheight === undefined) + this.maxheight = this.$getOption("Main", "max-height"); + + if (this.center && this.visible) { + this.visible = false; + this.$ext.style.display = "none"; /* @todo temp done for project */ + + var _self = this; + $setTimeout(function(){ + _self.setProperty("visible", true); + }); + } + }; + + + + + this.addEventListener("$skinchange", function(){ + if (this.title) + this.$propHandlers["title"].call(this, this.title); + + if (this.icon) + this.$propHandlers["icon"].call(this, this.icon); + }); + + + this.$destroy = function(skinChange) { + if (this.oDrag) { + this.oDrag.host = null; + this.oDrag.onmousedown = null; + apf.destroyHtmlNode(this.oDrag); + this.oDrag = null; + } + + this.oTitle = this.oIcon = null; + + if (this.$ext && !skinChange) { + this.$ext.onmousedown = null; + this.$ext.onmousemove = null; + } + }; +}).call(apf.modalwindow.prototype = new apf.Presentation()); + +apf.AmlWindow.prototype = apf.toolwindow.prototype = apf.modalwindow.prototype; + +apf.aml.setElement("toolwindow", apf.toolwindow); +apf.aml.setElement("modalwindow", apf.modalwindow); +apf.aml.setElement("window", apf.modalwindow); + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * This element functions as the central access point for XML data. Data can be + * retrieved from any data source using data instructions. Data can also be + * submitted using data instructions in a similar way to HTML form posts. + * + * The modal can be reset to its original state. It has support for offline use and + * synchronization between multiple clients. + * + * #### Example: Loading A Model + * + * + * + * + * + * + * + * + * + * + * + * List component: + * + * + * + * + * Datagrid component: + * + * + * + * + * + * + * + * + * + * #### Example + * + * A small form where the bound data is submitted to a server using a model: + * + * ```xml, demo + * + * + * + * + * + * + * + * Name + * + * Address + * + * Submit + * + * + * + * ``` + * + * @class apf.model + * @inherits apf.AmlElement + * @define model + * @logic + * @allowchild [cdata], instance, load, submission + * + * + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.8 + * + */ +/** + * @attribute {String} src Sets or gets the data instruction on how to load data from the data source into this model. + */ +/** + * @attribute {String} submission Sets or gets the data instruction on how to record the data from the data source from this model. + */ +/** + * @attribute {String} session Sets or gets the data instruction on how to store the session data from this model. + */ +/** + * @attribute {Boolean} autoinit Sets or gets whether to initialize the model immediately. If set to false you are expected to call init() when needed. This is useful when the system has to log in first. + */ +/** + * @attribute {Boolean} enablereset Sets or gets whether to save the original state of the data. This enables the use of the reset() call. + */ +/** + * @attribute {String} remote Sets or gets the id of the remote element to use for data synchronization between multiple clients. + */ +/** + * @event beforeretrieve Fires before a request is made to retrieve data. + * @cancelable Prevents the data from being retrieved. + */ +/** + * @event afterretrieve Fires when the request to retrieve data returns both on success and failure. + */ +/** + * @event receive Fires when data is successfully retrieved + * @param {Object} e The standard event object. It contains the following property: + * - `data` (([String])): the retrieved data + */ +/** + * @event beforeload Fires before data is loaded into the model. + * @cancelable + */ +/** + * @event afterload Fires after data is loaded into the model. + */ +/** + * @event beforesubmit Fires before data is submitted. + * @cancelable Prevents the submit. + * @param {Object} e The standard event object. It contains the following property: + * - `instruction` ([[String]]): the data instruction used to store the data. + */ +/** + * @event submiterror Fires when submitting data has failed. + */ +/** + * @event submitsuccess Fires when submitting data was successfull. + */ +/** + * @event aftersubmit Fires after submitting data. + */ +/** + * @event error Fires when a communication error has occured while making a request for this element. + * @cancelable Prevents the error from being thrown. + * @bubbles + * @param {Object} e The standard event object. It contains the following properties: + * - `error` ([[Error]]): the error object that is thrown when the event callback doesn't return false. + * - `state` ([[Number]]): the state of the call. Possible values include: + * - `apf.SUCCESS`: the request was successfull + * - `apf.TIMEOUT`: the request has timed out. + * - `apf.ERROR`: an error has occurred while making the request. + * - `apf.OFFLINE`: the request was made while the application was offline. + * - `userdata` (`Mixed`): data that the caller wanted to be available in the callback of the HTTP request. + * - `http` ([[XMLHttpRequest]]): The object that executed the actual HTTP request. + * - `url` ([[String]]): the URL that was requested. + * - `tpModule` ([[apf.http]]): the teleport module that is making the request. + * - `id` ([[Number]]): the id of the request. + * - `message` ([[String]]): the error message. + * + */ +apf.model = function(struct, tagName) { + this.$init(tagName || "model", apf.NODE_HIDDEN, struct); + + this.$amlNodes = {}; + this.$propBinds = {}; + + this.$listeners = {}; + this.$proplisteners = {}; +}; + +(function(){ + this.$parsePrio = "020"; + this.$isModel = true; + this.$createModel = true; + + this.canHaveChildren = false; + this.enablereset = false; + + this.$state = 0;//1 = loading + + //1 = force no bind rule, 2 = force bind rule + this.$attrExcludePropBind = apf.extend({ + submission: 1, + src: 1, + session: 1 + }, this.$attrExcludePropBind); + + this.$booleanProperties["whitespace"] = true; + this.$booleanProperties["create-model"] = true; + this.$booleanProperties["autoinit"] = true; + this.$booleanProperties.enablereset = true; + this.$supportedProperties = ["submission", "src", "session", "autoinit", + "enablereset", "remote", "whitespace", "create-model"]; + + this.$propHandlers["src"] = + this.$propHandlers["get"] = function(value, prop) { + if (this.$amlLoaded) + this.$loadFrom(value); + }; + + this.$propHandlers["create-model"] = function(value, prop) { + this.$createModel = value; + }; + + + //Connect to a remote databinding + this.$propHandlers["remote"] = function(value, prop) { + if (value) { + if (this.src && this.src.indexOf("rdb://") === 0) { + var _self = this; + apf.queue.add("rdb_load_" + this.$uniqueId, function(){ + _self.unshare(); + _self.share(); + }); + } + } + else + this.unshare(); + }; + + this.share = function(xpath) { + this.rdb = typeof this.remote == "string" + ? + + apf.nameserver.get("remote", this.remote) + + : this.remote; + + + + this.rdb.createSession(this.src, this, xpath); + }; + + this.unshare = function(xpath) { + if (!this.rdb) return; + this.rdb.endSession(this.src); + this.rdb = null; + }; + + + /** + * Registers an AML element to this model in order for the AML element to + * receive data loaded in this model. + * + * @param {apf.AmlElement} amlNode The AML element to be registered. + * @param {String} [xpath] The XPath query which is executed on the + * data of the model to select the node to be + * loaded in the `amlNode`. + * @return {apf.model} This model + * @private + */ + this.register = function(amlNode, xpath) { + if (!amlNode || !amlNode.load) //hasFeature(apf.__DATABINDING__)) + return this; + + var isReloading = amlNode.$model == this; + + //Remove previous model + if (amlNode.$model && !isReloading) + amlNode.$model.unregister(amlNode); + + //Register the AML node + var item = this.$amlNodes[amlNode.$uniqueId] = { + amlNode: amlNode, + xpath: xpath + }; + amlNode.$model = this; + + if (typeof amlNode.noloading == "undefined" + && amlNode.$setInheritedAttribute + && !amlNode.$setInheritedAttribute("noloading")) + amlNode.noloading = false; + + //amlNode.$model = this; + if (this.$state == 1) { + if (amlNode.clear && !amlNode.noloading) + amlNode.clear("loading");//@todo apf3.0 + } + else if (this.data) { + this.$loadInAmlNode(item); + //this.$loadInAmlProp(amlNode); + } + else { //@experimental + if (amlNode.hasFeature(apf.__CACHE__)) // amlNode.clear + amlNode.clear("empty"); + } + + var p, node, list = amlNode.$propsUsingMainModel, id = amlNode.$uniqueId; + for (var prop in list) { + this.$unbindXmlProperty(amlNode, prop); + p = this.$bindXmlProperty(amlNode, prop, + list[prop].xpath, list[prop].optimize); + + if (this.data) { + //if (node = p.root || p.listen ? this.data.selectSingleNode(p.root || p.listen) : this.data) { + if (node = p.listen ? this.data.selectSingleNode(p.listen) : this.data) { + amlNode.$execProperty(prop, node); + } + else + this.$waitForXml(amlNode, prop); + } + } + + return this; + }; + + this.$register = function(amlNode, xpath) { + //@todo apf3.0 update this.$propBinds; + + this.$amlNodes[amlNode.$uniqueId].xpath = xpath; + }; + + /* + * Removes an AML element from the group of registered AML elements. + * The AML element will not receive any updates from this model, however + * the data loaded in the AML element is not unloaded. + * + * @param {apf.AmlElement} amlNode The AML element to be unregistered. + * @private + */ + this.unregister = function(amlNode) { + delete this.$amlNodes[amlNode.$uniqueId]; + + var list = amlNode.$propsUsingMainModel; + for (var prop in list) + this.$unbindXmlProperty(amlNode, prop); + + amlNode.dispatchEvent("unloadmodel"); + }; + + /* + * @private + */ + this.getXpathByAmlNode = function(amlNode) { + var n = this.$amlNodes[amlNode.$uniqueId]; + if (!n) + return false; + + return n.xpath; + }; + + /* + * @private + */ + this.$loadInAmlNode = function(item) { + var xmlNode; + var xpath = item.xpath; + var amlNode = item.amlNode; + + if (this.data && xpath) { + xmlNode = this.data.selectSingleNode(xpath); + } + else + xmlNode = this.data || null; + + if (xmlNode) { + delete this.$listeners[amlNode.$uniqueId]; + if (amlNode.xmlRoot != xmlNode) + amlNode.load(xmlNode); + } + else + this.$waitForXml(amlNode); + }; + + this.$loadInAmlProp = function(id, xmlNode) { + var prop, node, p = this.$propBinds[id], amlNode = apf.all[id]; + if (!amlNode) { + delete this.$propBinds[id]; + return; + } + + + for (prop in p) { + if (xmlNode && (node = p[prop].listen + ? xmlNode.selectSingleNode(p[prop].listen) + : xmlNode)) { + apf.xmldb.addNodeListener(xmlNode, amlNode, + "p|" + id + "|" + prop + "|" + this.$uniqueId); + + delete this.$proplisteners[id + prop]; + amlNode.$execProperty(prop, node); + } + else + this.$waitForXml(amlNode, prop); + } + }; + + /* + We don't want to connect to the root, that would create a rush + of unnecessary update messages, so we'll find the element that's + closest to the node that is going to feed us the value + + mdlBlah: :bli/persons + mdlBlah: :bli/persons/person + + $attrBindings + //split / join, pop, indexOf + + + */ + this.$bindXmlProperty = function(amlNode, prop, xpath, optimize, listenRoot) { + var q ,p, id = amlNode.$uniqueId; + if (!this.$propBinds[id]) + this.$propBinds[id] = {}; + + /* + Store + 0 - Original xpath + 1 - Store point of change listener + 2 - Xpath to determine data node passed into load + */ + p = this.$propBinds[id][prop] = { + bind: xpath + }; + + //@todo apf3.0 + //Optimize root point, doesnt work right now because it doesnt change the original rule + if (optimize && false) { + //Find xpath for bind on this model of the amlNode + if ((q = this.$amlNodes[id]) && q.xpath) + xpath = (p.root = q.xpath) + "/" + xpath; + + var l = xpath.split("/"), z = l.pop(); + if (z.indexOf("@") == 0 + || z.indexOf("text()") > -1 + || z.indexOf("node()") > -1) { + p.listen = l.join("/"); + } + else p.listen = xpath; + } + else { + if ((q = this.$amlNodes[id]) && q.xpath) + p.listen = q.xpath; + } + + if (listenRoot) + p.listen = "."; + + if (this.data) { + var xmlNode = + + (p.listen ? this.data.selectSingleNode(p.listen) : this.data); + + if (xmlNode) { + apf.xmldb.addNodeListener(xmlNode, amlNode, + "p|" + amlNode.$uniqueId + "|" + prop + "|" + this.$uniqueId); + + return p; + } + } + + this.$waitForXml(amlNode, prop); + + return p; + }; + + this.$unbindXmlProperty = function(amlNode, prop) { + var id = amlNode.$uniqueId; + + //@todo apf3.0 + var p = this.$propBinds[id] && this.$propBinds[id][prop]; + if (!p) return; + + if (this.data) { + var xmlNode = p.listen ? this.data.selectSingleNode(p.listen) : this.data; + if (xmlNode) { + apf.xmldb.removeNodeListener(xmlNode, amlNode, + "p|" + id + "|" + prop + "|" + this.$uniqueId); + } + } + + delete this.$proplisteners[id + prop]; + delete this.$propBinds[id][prop]; + return p; + }; + + /** + * Gets a copy of current state of the XML of this model. + * + * @return {XMLNode} The context of this model, or `false` if there's no data + * + */ + this.getXml = function(){ + return this.data + ? apf.xmldb.cleanNode(this.data.cloneNode(true)) + : false; + }; + + /** + * Sets a value of an XMLNode based on an XPath statement executed on the data of this model. + * + * @param {String} xpath The xpath used to select a XMLNode. + * @param {String} value The value to set. + * @return {XMLNode} The changed XMLNode + */ + this.setQueryValue = function(xpath, value) { + if (!this.data) + return false; + + var node = apf.createNodeFromXpath(this.data, xpath); + if (!node) + return null; + + apf.setNodeValue(node, value, true); + //apf.xmldb.setTextNode(node, value); + return node; + }; + + /** + * Sets a value of a set of XML nodes based on an XPath statement executed on the data of this model. + * + * @param {String} xpath The xpath used to select a the nodeset. + * @param {String} value The value to set. + * @return {NodeList} The changed XMLNodeSet + */ + this.setQueryValues = function(xpath, value) { + if (!this.data) + return []; + + var nodes = this.data.selectNodes(xpath); + for (var i = 0, l = nodes.length; i < l; i++) + apf.setNodeValue(node, value, true); + + return nodes; + }; + + /** + * Gets the value of an XMLNode based on a XPath statement executed on the data of this model. + * + * @param {String} xpath The XPath used to select a XMLNode. + * @return {String} The value of the XMLNode + */ + this.queryValue = function(xpath) { + if (!this.data) + return false; + + return apf.queryValue(this.data, xpath); + }; + + /** + * Gets the values of an XMLNode based on a XPath statement executed on the data of this model. + * + * @param {String} xpath The xpath used to select a XMLNode. + * @return {[String]} The values of the XMLNode + */ + this.queryValues = function(xpath) { + if (!this.data) + return []; + + return apf.queryValue(this.data, xpath); + }; + + /** + * Executes an XPath statement on the data of this model + * + * @param {String} xpath The XPath used to select the XMLNode(s). + * @return {Mixed} The result of the selection, either an [[XMLNode]] or a [[NodeList]] + */ + this.queryNode = function(xpath) { + if (!this.data) + return null; + + return this.data.selectSingleNode(xpath) + }; + + /** + * Executes XPath statements on the data of this model + * + * @param {String} xpath The XPath used to select the XMLNode(s). + * @return {Mixed} The result of the selection, either an [[XMLNode]] or a [[NodeList]] + */ + this.queryNodes = function(xpath) { + if (!this.data) + return []; + + return this.data.selectNodes(xpath); + }; + + /** + * Appends a copy of the `xmlNode` or model to this model as a child + * of its root node + * @param {XMLNode} xmlNode The XML node to append + * @param {String} [xpath] The path to a node to append to + * @returns {XMLNode} The appended node + */ + this.appendXml = function(xmlNode, xpath) { + var insertNode = xpath + ? apf.createNodeFromXpath(this.data, xpath) + : this.data; + if (!insertNode) + return null; + + if (typeof xmlNode == "string") + xmlNode = apf.getXml(xmlNode); + else if (xmlNode.nodeFunc) + xmlNode = xmlNode.getXml(); + + if (!xmlNode) return; + + xmlNode = apf.xmldb.appendChild(insertNode, xmlNode); + + this.dispatchEvent("update", {xmlNode: xmlNode}); + return xmlNode; + }; + + /** + * Removes an XML node from this model. + */ + this.removeXml = function(xmlNode) { + if (!this.data) return; + + var xmlNodes; + if (typeof xmlNode === "string") { + xmlNodes = this.data.selectNodes(xmlNode); + } + else if (!xmlNode.length) { + xmlNodes = [xmlNode]; + } + + if (xmlNodes.length) { + apf.xmldb.removeNodeList(xmlNodes); + } + }; + + /** + * Clears the loaded data from this model. + */ + this.clear = function(){ + this.load(null); + doc = null; //Fix for safari refcount issue; + }; + + /** + * Resets data in this model to the last saved point. + * + */ + this.reset = function(){ + var doc = this.data.ownerDocument; + //doc.removeChild(this.data); + //var node = doc.appendChild(apf.isWebkit ? doc.importNode(this.$copy, true) : this.$copy); + this.data.parentNode.replaceChild(this.$copy, this.data); + this.load(this.$copy); + }; + + /** + * Sets a new saved point based on the current state of the data in this + * model. The `reset()` method returns the model to this point. + */ + this.savePoint = function(){ + this.$copy = apf.xmldb.getCleanCopy(this.data); + }; + + /** + * @private + */ + this.reloadAmlNode = function(uniqueId) { + if (!this.data) + return; + + var item = this.$amlNodes[uniqueId]; + var xmlNode = item.xpath + ? this.data.selectSingleNode(item.xpath) + : this.data; + item.amlNode.load(xmlNode); + }; + + //@todo refactor this to use .blah instead of getAttribute + //@todo move this to propHandlers + /* + * @private + */ + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + var x = this.$aml; + if (this.parentNode && this.parentNode.hasFeature(apf.__DATABINDING__)) { + if (!this.name) + this.setProperty("id", "model" + this.parentNode.$uniqueId); + //this.parentNode.$aml.setAttribute("model", this.name); //@todo don't think this is necesary anymore... + this.register(this.parentNode); + } + + //Load literal model + if (!this.src) { + var strXml, xmlNode = x; + if (xmlNode && xmlNode.childNodes.length) { + if (apf.getNode(xmlNode, [0])) { + if ((strXml = xmlNode.xml || xmlNode.serialize()).match(/^[\s\S]*?>([\s\S]*)<[\s\S]*?$/)) { + strXml = RegExp.$1; //@todo apf3.0 test this with json + if (!apf.supportNamespaces) + strXml = strXml.replace(/xmlns=\"[^"]*\"/g, ""); + } + + if (this.whitespace === false) + strXml = strXml.replace(/>[\s\n\r]*<"); + + return this.load(apf.getXmlDom(strXml).documentElement); + } + // we also support JSON data loading in a model CDATA section + else if (apf.isJson(xmlNode.childNodes[0].nodeValue)) { + return this.load(apf.getXmlDom(xmlNode.childNodes[0].nodeValue).documentElement); + } + } + + //Default data for XForms models without an instance but with a submission node + if (this.submission) + this.load(""); + } + + //Load data into model if allowed + if (!apf.isFalse(this.autoinit)) + this.init(); + + //@todo actions apf3.0 + + return this; + }); + + //callback here is private + /** + * Loads the initial data into this model. + * @see apf.model.init + */ + this.init = function(callback) { + if (this.session) { + this.$loadFrom(this.session, {isSession: true}); + } + else { + + + if (this.src) + this.$loadFrom(this.src, {callback: callback}); + } + }; + + /* *********** LOADING ****************/ + + /* + * Loads data into this model using a data instruction. + * @param {String} instruction The data instrution how to retrieve the data. + * @param {Object} options + * Properties: + * {XMLElement} xmlNode the {@link term.datanode data node} that provides context to the data instruction. + * {Function} callback the code executed when the data request returns. + * {Mixed} [] Custom properties available in the data instruction. + */ + this.$loadFrom = function(instruction, options) { + + if (instruction.indexOf("rdb://") === 0) { + this.src = instruction; //@todo + return this.$propHandlers["remote"].call(this, this.remote); + } + + var data = instruction.split(":"); + + if (!options) + options = {}; + + if (!options.isSession) { + this.src = instruction; + this.$srcOptions = [instruction, options]; + } + + //Loading data in non-literal model + this.dispatchEvent("beforeretrieve"); + + //Set all components on loading... + var uniqueId, item; + for (uniqueId in this.$amlNodes) { + if (!(item = this.$amlNodes[uniqueId]) || !item.amlNode) + continue; + + //@todo apf3.0 + if (!item.amlNode.noloading) + item.amlNode.clear("loading"); + } + + this.$state = 1; + if (!this.$callCount) + this.$callCount = 1; + else + this.$callCount++; + + var _self = this, + callCount = this.$callCount, + callback = options.callback; + options.callback = function(data, state, extra) { + if (callCount != _self.$callCount) + return; //another call has invalidated this one + + _self.dispatchEvent("afterretrieve"); + + + + if (state != apf.SUCCESS) { + var oError; + + oError = new Error(apf.formatErrorString(1032, + _self, "Loading xml data", "Could not load data\n" + + "Instruction: " + instruction + "\n" + + "Url: " + extra.url + "\n" + + "Info: " + extra.message + "\n\n" + data)); + + if (callback && callback.apply(this, arguments) === true) + return true; + + if (extra.tpModule && extra.tpModule.retryTimeout(extra, state, _self, oError) === true) + return true; + + _self.$state = 0; + + throw oError; + } + + if (options && options.isSession && !data) { + if (this.src) + return _self.$loadFrom(this.src); + } + else { + if (options && options.cancel) + return; + + _self.load(data); + _self.dispatchEvent("receive", { + data: data + }); + + if (callback) + callback.apply(this, arguments); + } + }; + + return apf.getData(instruction, options); + }; + + /** + * Loads the data from the datasource specified for [[apf.model.init]]. + */ + this.reload = function(){ + if (!this.data) + return; + + if (this.$srcOptions) + this.$loadFrom.apply(this, this.$srcOptions); + else if (this.src) + this.$loadFrom(this.src); + }; + + /** + * Loads data into this model. + * + * @param {Mixed} [xmlNode] The data to load in this model. A string specifies the data instruction how to retrieve the data, which can be an XML string. `null` will clear the data from this model. + * @param {Object} [options] Additional options to pass. This can contain the following properties: + * + * - `xmlNode` ([[XMLElement]]): the {@link term.datanode data node} that provides context to the data instruction. + * - `callback` ([[Function]]): the code executed when the data request returns. + * - `[]` (`Mixed`): custom properties available in the data instruction. + * - `[nocopy]` ([[Boolean]]): specifies whether the data loaded will not overwrite the reset point. + */ + this.load = function(xmlNode, options) { + if (typeof xmlNode == "string") { + if (xmlNode.charAt(0) == "<") { //xml + if (xmlNode.substr(0, 5).toUpperCase() == "")+1); + if (!apf.supportNamespaces) + xmlNode = xmlNode.replace(/xmlns\=\"[^"]*\"/g, ""); + xmlNode = apf.getXmlDom(xmlNode, null, true).documentElement; //@todo apf3.0 whitespace issue + } + + else + return this.$loadFrom(xmlNode, options); + } + + if (this.ownerDocument && this.ownerDocument.$domParser.$isPaused(this)) { + //if (!this.$queueLoading) { + var _self = this; + this.data = xmlNode; //@todo expirement //this.$copy = + apf.xmldb.getXmlDocId(xmlNode, this); //@todo experiment + + this.$queueLoading = true; + apf.queue.add("modelload" + this.$uniqueId, function(){ + if (_self.ownerDocument && _self.ownerDocument.$domParser.$isPaused(_self)) + apf.queue.add("modelload" + _self.$uniqueId, arguments.callee); + else { + _self.load(xmlNode, options); + _self.$queueLoading = false; + } + }); + //} + return; + } + else if (this.$queueLoading) + apf.queue.remove("modelload" + this.$uniqueId); + + this.$state = 0; + + if (this.dispatchEvent("beforeload", {xmlNode: xmlNode}) === false) + return false; + + var doc = xmlNode ? xmlNode.ownerDocument : null; //Fix for safari refcount issue; + + //if (apf.isIE && this.$aml && this.getAttribute("ns")) + //doc.setProperty("SelectionNamespaces", this.getAttribute("ns")); + + if (xmlNode) { + if (!apf.supportNamespaces) { + /* && (xmlNode.prefix || xmlNode.scopeName)) { + doc.setProperty("SelectionNamespaces", "xmlns:" + + (xmlNode.prefix || xmlNode.scopeName) + "='" + + xmlNode.namespaceURI + "'");*/ + var xmlns = [], attr = xmlNode.attributes; + for (var i = 0, l = attr.length; i < l; i++) { + if (attr[i].nodeName.substr(0, 5) == "xmlns") { + xmlns.push(attr[i].xml); + } + } + if (xmlns.length) + doc.setProperty("SelectionNamespaces", xmlns.join(" ")); + } + + apf.xmldb.addNodeListener(xmlNode, this); //@todo this one can be added for this.$listeners and when there are none removed + apf.xmldb.nodeConnect( + apf.xmldb.getXmlDocId(xmlNode, this), xmlNode, null, this); + + if ((!options || !options.nocopy) && this.enablereset) + this.$copy = apf.xmldb.getCleanCopy(xmlNode); + } + + this.data = xmlNode; + + this.dispatchEvent("afterload", {xmlNode: xmlNode}); + this.dispatchEvent("update", {xmlNode: xmlNode}); + + for (var id in this.$amlNodes) + this.$loadInAmlNode(this.$amlNodes[id]); + + for (id in this.$propBinds) + this.$loadInAmlProp(id, xmlNode); + + return this; + }; + + //Listening nodes should be removed in unregister + this.$waitForXml = function(amlNode, prop) { + if (prop) + this.$proplisteners[amlNode.$uniqueId + prop] = { + id: amlNode.$uniqueId, + amlNode: amlNode, + prop: prop + }; + else + this.$listeners[amlNode.$uniqueId] = amlNode; + + //When data is not available at model load but element had already data + //loaded, it is cleared here. + if (amlNode.xmlRoot) + amlNode.clear(); + }; + + this.$xmlUpdate = function(action, xmlNode, listenNode, UndoObj) { + //@todo optimize by only doing this for add, sync etc actions + + if (action == "replacenode" && xmlNode == this.data.ownerDocument.documentElement) { + var _self = this; + $setTimeout(function(){ + _self.load(xmlNode); + }); + return; + } + + + if (this.rdb && !this.$at && UndoObj) + this.$at = UndoObj.at; + + + + + var p, b; + for (var id in this.$listeners) { + if (xmlNode = this.data.selectSingleNode(this.$amlNodes[id].xpath || ".")) { + this.$listeners[id].load(xmlNode); + delete this.$listeners[id]; + } + } + + for (id in this.$proplisteners) { + p = this.$proplisteners[id]; + b = this.$propBinds[p.id][p.prop]; + if (xmlNode = b.listen ? this.data.selectSingleNode(b.listen) : this.data) { + delete this.$proplisteners[id]; + + apf.xmldb.addNodeListener(xmlNode, p.amlNode, + "p|" + p.id + "|" + p.prop + "|" + this.$uniqueId); + + p.amlNode.$execProperty(p.prop, b.root + ? this.data.selectSingleNode(b.root) + : this.data); + } + } + + this.dispatchEvent("update", {xmlNode: xmlNode, action: action, undoObj: UndoObj}); + }; + + // *** INSERT *** // + + /* + * Inserts data into the data of this model using a data instruction. + * @param {String} instruction The data instrution indicating how to retrieve the data. + * @param {Object} options Additional options to pass. This can contain the following properties: + * + * - `insertPoint` ([[XMLElement]]): the parent element for the inserted data. + * - `clearContents` ([[Boolean]]): whether the contents of the insertPoint should be cleared before inserting the new children. + * - `copyAttributes` ([[Boolean]]): whether the attributes of the merged element are copied. + * - `callback` ([[Function]]): the code executed when the data request returns. + * - `[]` (`Mixed`): custom properties available in the data instruction. + */ + this.$insertFrom = function(instruction, options) { + if (!instruction) return false; + + this.dispatchEvent("beforeretrieve"); + + + + var callback = options.callback, _self = this; + options.callback = function(data, state, extra) { + _self.dispatchEvent("afterretrieve"); + + if (!extra) + extra = {}; + + if (state != apf.SUCCESS) { + var oError; + + + + if (extra.tpModule.retryTimeout(extra, state, + options.amlNode || _self, oError) === true) + return true; + + if (callback + && callback.call(this, extra.data, state, extra) === false) + return; + + throw oError; + } + + //Checking for xpath + if (typeof options.insertPoint == "string") + options.insertPoint = _self.data.selectSingleNode(options.insertPoint); + + if (typeof options.clearContents == "undefined" && extra.userdata) + options.clearContents = apf.isTrue(extra.userdata[1]); //@todo is this still used? + + if (options.whitespace == undefined) + options.whitespace = _self.whitespace; + + //Call insert function + (options.amlNode || _self).insert(data, options); + + if (callback) + callback.call(this, extra.data, state, extra); + }; + + apf.getData(instruction, options); + }; + + /** + * Inserts data in this model as a child of the currently loaded data. + * + * @param {XMLElement} XMLRoot The {@link term.datanode data node} to insert into this model. + * @param {Object} options Additional options to pass. This can contain the following properties: + * + * - `insertPoint` ([[XMLElement]]): the parent element for the inserted data. + * - `clearContents` ([[Boolean]]): specifies whether the contents of the `insertPoint` should be cleared before inserting the new children. + * - `copyAttributes` ([[Boolean]]): specifies whether the attributes of the merged element are copied. + * - `callback` ([[Function]]): the code executed when the data request returns. + * - `[]` (`Mixed`): Custom properties available in the data instruction. + */ + this.insert = function(xmlNode, options) { + if (typeof xmlNode == "string") { + if (xmlNode.charAt(0) == "<") { + if (xmlNode.substr(0, 5).toUpperCase() == "")+1); + if (!apf.supportNamespaces) + xmlNode = xmlNode.replace(/xmlns\=\"[^"]*\"/g, ""); + + if (this.whitespace === false) + xmlNode = xmlNode.replace(/>[\s\n\r]*<"); + + xmlNode = apf.getXmlDom(xmlNode).documentElement; + } + + else + return this.$insertFrom(xmlNode, options); + } + + if (!options.insertPoint) + options.insertPoint = this.data; + + + + //if(this.dispatchEvent("beforeinsert", parentXMLNode) === false) return false; + + //Integrate XMLTree with parentNode + if (typeof options.copyAttributes == "undefined") + options.copyAttributes = true; + + var newNode = apf.mergeXml(xmlNode, options.insertPoint, options); + + //Call __XMLUpdate on all this.$listeners + apf.xmldb.applyChanges("insert", options.insertPoint);//parentXMLNode); + + //this.dispatchEvent("afterinsert"); + + return xmlNode; + }; + + /* *********** SUBMISSION ****************/ + + /** + * Serialize the full XML DOM to a format specified by 'type'. + * + * @param {String} type Indicates how to serialize the data. Possible values include: + * - `xml`, for `application/xml` + * - `form`, for `application/x-www-form-urlencoded` + * - `json`, for `application/json` + * @returns {String} The serialized XML. + */ + this.convertXml = function(type) { + if (!type) + return this.data.xml; + + return apf.convertXml(this.data, type); + }; + + /** + * Submit the data of the model to a data source. + * @param {String} instruction The instruction for sending the data, or the URL to send the data to. + * @param {String} [type] Indicates how to serialize the data. Possible values include: + * - `xml`, for `application/xml` + * - `form`, for `application/x-www-form-urlencoded` (the default) + * - `json`, for `application/json` + * @param {XMLElement} [xmlNode] The data node to send to the server. + * @param {Object} [options] A list of additional options to pass; these are the same as [[apf.saveData]]. Available properties include: + * {:saveDataOptions} + */ + this.submit = function(instruction, type, xmlNode, options){ //@todo rewrite this for apf3.0 + if (!instruction) + instruction = this.submission; + + if (!xmlNode) + xmlNode = this.data; + + + + if (!type) + type = "form"; + + if (this.dispatchEvent("beforesubmit", { + instruction: instruction + }) === false) + return false; + + var model = this; + function cbFunc(data, state, extra) { + if ((state == apf.TIMEOUT + || (model.retryOnError && state == apf.ERROR)) + && extra.retries < apf.maxHttpRetries) { + return extra.tpModule.retry(extra.id); + } + else { + if (state != apf.SUCCESS) { + model.dispatchEvent("submiterror", extra); + } + else { + model.dispatchEvent("submitsuccess", apf.extend({ + data: data + }, extra)); + } + } + } + + var data; + if (type.indexOf("xml") > -1) + data = apf.getXmlString(xmlNode); + else if (type.indexOf("form") > -1) + data = apf.convertXml(apf.xmldb.getCleanCopy(xmlNode), "cgiobjects"); + else if (type.indexOf("json") > -1) + data = apf.convertXml(xmlNode, "json"); + + apf.saveData(instruction, apf.extend({ + xmlNode: xmlNode, + data: data, + callback: cbFunc + }, options)); + + this.dispatchEvent("aftersubmit"); + }; + + this.$destroy = function(){ + if (this.session && this.data) + apf.saveData(this.session, {xmlNode: this.getXml()}); + }; +}).call(apf.model.prototype = new apf.AmlElement()); + +apf.aml.setElement("model", apf.model); + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +/** + * + * A notification element, which shows popups when events occur. Similar in concept + * to [growl](http://growl.info/) on the OSX platform. + * + * @class apf.notifier + * @define notifier + * @media + * @inherits apf.Presentation + * + * @version %I%, %G% + * + * @allowchild event + * + */ +/** + * @attribute {String} position Sets or gets the vertical and horizontal element's start + * position. The possible values include: + * - `"top-right"`: the element is placed in top-right corner of browser window (this is the default) + * - `"top-left"`: the element is placed in top-left corner of browser window + * - `"bottom-right"`: the element is placed in bottom-right corner of browser window + * - `"bottom-left"`: the element is placed in bottom-left corner of browser window + * - `"center-center"`: the element is placed in the middle of browser window + * - `"right-top"`: the element is placed in top-right corner of browser window + * - `"left-top"`: the element is placed in top-left corner of browser window + * - `"right-bottom"`: the element is placed in bottom-right corner of browser window + * - `"left-bottom"`: the element is placed in bottom-left corner of browser window + * - `"center-center"`: the element is placed in the middle of browser window + */ +/** + * @attribute {String} margin Defines the free space around a popup element. + * Defaults to '10 10 10 10' pixels + */ +/** + * @attribute {String|Number} columnsize Specifies the element's width and col width, where the + * element will be displayed. Defaults to 300px. + */ +/** + * @attribute {String} [arrange="vertical"] Sets or gets the how the popup elements are displayed, either rows (`"vertical"`) + * or columns (`"horizontal"`). + */ +/** + * @attribute {String} [timeout=2] After the timeout has passed, the popup + * disappears automatically. When the + * mouse is hovering over the popup, it doesn't + * disappears. + */ +/** + * @attribute {String} onclick An action executed after a user clicks + * on the notifier. + * + */ +apf.notifier = function(struct, tagName) { + this.$init(tagName || "notifier", apf.NODE_VISIBLE, struct); +}; + +(function() { + var _self = this; + this.timeout = 2000; + this.position = "top-right"; + this.columnsize = 300; + this.arrange = "vertical"; + this.margin = "10 10 10 10"; + this.startPadding = 0; + + this.lastPos = null; + this.showing = 0; + this.sign = 1; + + this.$supportedProperties.push("margin", "position", "timeout", + "columnsize", "arrange", "start-padding"); + + this.$propHandlers["position"] = function(value) { + this.lastPos = null; + }; + + this.$propHandlers["margin"] = function(value) { + this.margin = value; + }; + + this.$propHandlers["start-padding"] = function(value) { + this.startPadding = parseInt(value); + }; + + this.$propHandlers["timeout"] = function(value) { + this.timeout = parseInt(value) * 1000; + }; + + function getPageScroll() { + return [ + document.documentElement.scrollTop || document.body.scrollTop, + document.documentElement.scrollLeft || document.body.scrollLeft + ]; + } + + function getStartPosition(x, wh, ww, nh, nw, margin, startPadding) { + var scrolled = getPageScroll(); + + return [ + (x[0] == "top" + ? margin[0] + : (x[0] == "bottom" + ? wh - nh - margin[2] + : wh / 2 - nh / 2)) + scrolled[0] + startPadding, + (x[1] == "left" + ? margin[3] + : (x[1] == "right" + ? ww - nw - margin[1] + : ww / 2 - nw / 2)) + scrolled[1] + ]; + } + + /** + * Creates a new notification popup. + * + * @param {String} [message=""] The message content displayed in the popup element + * @param {String} [icon] The path to the icon file ,relative to "icon-path" which + * is set in the skin declaration + * + */ + this.popup = function(message, icon, ev) { + if (!this.$ext) + return; + + this.$ext.style.width = this.columnsize + "px"; + + var _self = this, + oNoti = this.$pHtmlNode.appendChild(this.$ext.cloneNode(true)), + ww = apf.isIE + ? document.documentElement.offsetWidth + : window.innerWidth, + wh = apf.isIE + ? document.documentElement.offsetHeight + : window.innerHeight, + + removed = false, + + oIcon = this.$getLayoutNode("notification", "icon", oNoti), + oBody = this.$getLayoutNode("notification", "body", oNoti); + + this.showing++; + + if (oIcon && icon) { + if (oIcon.nodeType == 1) { + oIcon.style.backgroundImage = "url(" + + this.iconPath + icon + ")"; + } + else { + oIcon.nodeValue = this.iconPath + icon; + } + + this.$setStyleClass(oNoti, this.$baseCSSname + "ShowIcon"); + } + + oBody.insertAdjacentHTML("beforeend", message || "[No message]"); + oNoti.style.display = "block"; + + var margin = apf.getBox(this.margin || "0"), + nh = oNoti.offsetHeight, + nw = oNoti.offsetWidth, + /* It's possible to set for example: position: top-right or right-top */ + x = this.position.split("-"), + _reset = false; + + if (x[1] == "top" || x[1] == "bottom" || x[0] == "left" || x[0] == "right") + x = [x[1], x[0]]; + /* center-X and X-center are disabled */ + if ((x[0] == "center" && x[1] !== "center") || (x[0] !== "center" && x[1] == "center")) + x = ["top", "right"]; + + /* start positions */ + if (!this.lastPos) { + this.lastPos = getStartPosition(x, wh, ww, nh, nw, margin, this.startPadding); + this.sign = 1; + _reset = true; + } + + if ((!_reset && x[0] == "bottom" && this.sign == 1) || + (x[0] == "top" && this.sign == -1)) { + if (this.arrange == "vertical") { + this.lastPos[0] += x[1] == "center" + ? 0 + : this.sign * (x[0] == "top" + ? margin[0] + nh + : (x[0] == "bottom" + ? - margin[2] - nh + : 0)); + } + else { + this.lastPos[1] += x[0] == "center" + ? 0 + : this.sign * (x[1] == "left" + ? margin[3] + nw + : (x[1] == "right" + ? - margin[1] - nw + : 0)); + } + } + + /* reset to next line, first for vertical, second horizontal */ + var scrolled = getPageScroll(); + + if (this.lastPos[0] > wh + scrolled[0] - nh || this.lastPos[0] < scrolled[0]) { + this.lastPos[1] += (x[1] == "left" + ? nw + margin[3] + : (x[1] == "right" + ? - nw - margin[3] + : 0)); + this.sign *= -1; + this.lastPos[0] += this.sign*(x[0] == "top" + ? margin[0] + nh + : (x[0] == "bottom" + ? - margin[2] - nh + : 0)); + } + else if (this.lastPos[1] > ww + scrolled[1] - nw || this.lastPos[1] < scrolled[1]) { + this.lastPos[0] += (x[0] == "top" + ? nh + margin[0] + : (x[0] == "bottom" + ? - nh - margin[0] + : 0)); + this.sign *= -1; + this.lastPos[1] += x[0] == "center" + ? 0 + : this.sign * (x[1] == "left" + ? margin[3] + nw + : (x[1] == "right" + ? - margin[1] - nw + : 0)); + } + + /* Start from begining if entire screen is filled */ + if (this.lastPos) { + if ((this.lastPos[0] > wh + scrolled[0] - nh || this.lastPos[0] < scrolled[1]) + && this.arrange == "horizontal") { + this.lastPos = getStartPosition(x, wh, ww, nh, nw, margin, this.startPadding); + this.sign = 1; + } + if ((this.lastPos[1] > ww + scrolled[1] - nw || this.lastPos[1] < scrolled[1]) + && this.arrange == "vertical") { + this.lastPos = getStartPosition(x, wh, ww, nh, nw, margin, this.startPadding); + this.sign = 1; + } + } + + oNoti.style.left = this.lastPos[1] + "px"; + oNoti.style.top = this.lastPos[0] + "px"; + + if ((x[0] == "top" && this.sign == 1) || (x[0] == "bottom" && this.sign == -1)) { + if (this.arrange == "vertical") { + this.lastPos[0] += x[1] == "center" + ? 0 + : this.sign * (x[0] == "top" + ? margin[0] + nh + : (x[0] == "bottom" + ? - margin[2] - nh + : 0)); + } + else { + this.lastPos[1] += x[0] == "center" + ? 0 + : this.sign * (x[1] == "left" + ? margin[3] + nw + : (x[1] == "right" + ? - margin[1] - nw + : 0)); + } + }; + + var isMouseOver = false; + + apf.tween.css(oNoti, "fade", { + anim: apf.tween.NORMAL, + steps: 10, + interval: 10, + onfinish: function(container) { + oNoti.style.filter = ""; + $setTimeout(hideWindow, _self.timeout) + } + }); + + function hideWindow() { + if (isMouseOver) + return; + + apf.tween.css(oNoti, "notifier_hidden", { + anim: apf.tween.NORMAL, + steps: 10, + interval: 20, + onfinish: function(container) { + apf.setStyleClass(oNoti, "", ["notifier_hover"]); + if (isMouseOver) + return; + + if (oNoti.parentNode) { + if (oNoti.parentNode.removeChild(oNoti) && !removed) { + _self.showing--; + removed = true; + } + } + + if (_self.showing == 0) + _self.lastPos = null; + } + }); + } + + /* Events */ + oNoti.onmouseover = function(e) { + e = (e || event); + var tEl = e.explicitOriginalTarget || e.toElement; + if (isMouseOver) + return; + if (tEl == oNoti || apf.isChildOf(oNoti, tEl)) { + apf.tween.css(oNoti, "notifier_hover", { + anim: apf.tween.NORMAL, + steps: 10, + interval: 20, + onfinish: function(container) { + apf.setStyleClass(oNoti, "", ["notifier_shown"]); + } + }); + + isMouseOver = true; + } + }; + + oNoti.onmouseout = function(e) { + e = (e || event); + var tEl = e.explicitOriginalTarget || e.toElement; + + if (!isMouseOver) + return; + + if (apf.isChildOf(tEl, oNoti) || + (!apf.isChildOf(oNoti, tEl) && oNoti !== tEl )) { + isMouseOver = false; + hideWindow(); + } + }; + + if (ev) { + oNoti.onclick = function() { + ev.dispatchEvent("click"); + }; + } + }; + + // *** Init *** // + + this.$draw = function() { + //Build Main Skin + this.$pHtmlNode = document.body; + + this.$ext = this.$getExternal("notification"); + this.$ext.style.display = "none"; + this.$ext.style.position = "absolute"; + apf.window.zManager.set("notifier", this.$ext); + }; +}).call(apf.notifier.prototype = new apf.Presentation()); + +apf.aml.setElement("notifier", apf.notifier); +apf.aml.setElement("event", apf.event); + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * A tab in a pageable element (_i.e._ a tab in {@link apf.pane}). + * + * #### Example + * + * ```xml, demo + * + * + * + * + * + * Example + * Example + * + * + * Test checkbox + * Test checkbox + * Test checkbox + * + * + * This ok? + * This better? + * + * + * + * + * + * ``` + * + * @class apf.tab + * @define tab + * @container + * @inherits apf.Presentation + * @allowchild {elements}, {anyaml} + * + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.8 + */ +apf.tab = function(struct, tagName) { + this.$init(tagName || "tab", apf.NODE_VISIBLE, struct); +}; + +(function(){ + this.canHaveChildren = true; + + this.$focussable = false; + this.closebtn = false; + this.autofocus = true; + + + + + /** + * Sets the caption of the button of this element. + * @param {String} caption The text displayed on the button of this element. + */ + this.setCaption = function(caption) { + this.setProperty("caption", caption, false, true); + }; + + /** + * Sets the icon of the button of this element. + * @param {String} icon The icon displayed on the button of this element. + */ + this.setIcon = function(icon) { + this.setProperty("icon", icon, false, true); + }; + + + // *** Delayed Render Support *** // + + + //Hack + this.addEventListener("beforerender", function(){ + this.parentNode.dispatchEvent("beforerender", { + tab: this + }); + }); + + this.addEventListener("afterrender", function(){ + this.parentNode.dispatchEvent("afterrender", { + tab: this + }); + }); + + + // *** Properties *** // + + this.$booleanProperties["visible"] = true; + this.$booleanProperties["fake"] = true; + this.$booleanProperties["closebtn"] = true; + this.$booleanProperties["autofocus"] = true; + this.$supportedProperties.push("fake", "caption", "icon", "tooltip", + "type", "buttons", "closebtn", "trans-in", "trans-out", "autofocus"); + + + /** + * @attribute {Boolean} closebtn Sets or gets whether this tab's button shows a close button inside it. + */ + this.$propHandlers["closebtn"] = function(value) { + //if (!this.$amlLoaded || !this.parentNode.$hasButtons) + // return; + var _self = this; + + if (value) { + var btncontainer = this.parentNode.$getLayoutNode("button", "container", this.$button); + + this.parentNode.$getNewContext("btnclose"); + var elBtnClose = this.parentNode.$getLayoutNode("btnclose"); + + if (elBtnClose) { + // if (elBtnClose.nodeType == 1) { + apf.setStyleClass(this.$button, "btnclose"); + + elBtnClose.addEventListener("mousedown", function(e) { + apf.cancelBubble(e, apf.lookup(_self.$uniqueId)); + }, false); + + elBtnClose.addEventListener("click", function(e) { + var tab = apf.lookup(_self.$uniqueId); + tab.parentNode.remove(tab, e); + }, false); + + btncontainer.appendChild(elBtnClose); + } + + } + }; + + + /** + * @attribute {String} caption Sets or gets the text displayed on the button of this element. + */ + this.$propHandlers["tooltip"] = function(value) { + if (!this.parentNode) + return; + + var node = this.parentNode + .$getLayoutNode("button", "caption", this.$button); + + (node.nodeType == 1 ? node : node.parentNode).setAttribute("title", value || ""); + } + + /** + * @attribute {String} caption Sets or gets the text displayed on the button of this element. + */ + this.$propHandlers["caption"] = function(value) { + if (!this.parentNode) + return; + + var node = this.parentNode + .$getLayoutNode("button", "caption", this.$button); + + if (node.nodeType == 1) + node.innerHTML = value; + else + node.nodeValue = value; + }; + + this.$propHandlers["icon"] = function(value) { + if (!this.parentNode) + return; + + var node = this.parentNode + .$getLayoutNode("button", "icon", this.$button); + + if (node && node.nodeType == 1) + apf.skins.setIcon(node, value, this.parentNode.iconPath); + }; + + this.$propHandlers["visible"] = function(value) { + if (!this.parentNode) + return; + + if (value) { + if (this.$fake) { + this.parentNode.set(this.$fake); + this.visible = false; + return; + } + + this.$ext.style.display = ""; + if (this.parentNode.$hasButtons) + this.$button.style.display = "block"; + + if (!this.parentNode.$activepage) + this.parentNode.set(this); + } + else { + if (this.$active) { + this.$deactivate(); + + // Try to find a next tab, if any. + var nextPage = this.parentNode.activepagenr + 1; + var pages = this.parentNode.getPages() + var len = pages.length + while (nextPage < len && !pages[nextPage].visible) + nextPage++; + + if (nextPage == len) { + // Try to find a previous tab, if any. + nextPage = this.parentNode.activepagenr - 1; + while (nextPage >= 0 && len && !pages[nextPage].visible) + nextPage--; + } + + if (nextPage >= 0) + this.parentNode.set(nextPage); + else { + this.parentNode.activepage = + this.parentNode.activepagenr = + this.parentNode.$activepage = null; + } + } + + this.$ext.style.display = "none"; + if (this.parentNode.$hasButtons) + this.$button.style.display = "none"; + } + }; + + /** + * @attribute {Boolean} fake Sets or gets whether this tab actually contains elements or + * only provides a button in the pageable parent element. + */ + this.$propHandlers["fake"] = function(value) { + if (this.$ext) { + apf.destroyHtmlNode(this.$ext); + this.$int = this.$ext = null; + } + }; + + this.$propHandlers["type"] = function(value) { + this.setProperty("fake", true); + + if (this.relPage && this.$active) + this.relPage.$deactivate(); + + this.relPage = this.parentNode.getPage(value); + if (this.$active) + this.$activate(); + }; + + // *** DOM Hooks *** // + + this.addEventListener("DOMNodeRemoved", function(e) { + if (e && e.currentTarget != this) + return; + + if (this.$button) { + if (this.$position & 1) + this.parentNode.$setStyleClass(this.$button, "", ["firstbtn", "firstcurbtn"]); + if (this.$position & 2) + this.parentNode.$setStyleClass(this.$button, "", ["lastbtn"]); + } + + if (!e.$doOnlyAdmin) { + if (this.$button) + this.$button.parentNode.removeChild(this.$button); + + if (this.parentNode && this.parentNode.$activepage == this) { + if (this.$button) + this.parentNode.$setStyleClass(this.$button, "", ["curbtn"]); + this.parentNode.$setStyleClass(this.$ext, "", ["curpage"]); + } + } + }); + + this.addEventListener("DOMNodeRemovedFromDocument", function(e) { + if (this.fake && this.parentNode && this.parentNode.$activepage == this) + this.$deactivate(); + }); + + this.addEventListener("DOMNodeInserted", function(e) { + if (e && e.currentTarget != this || !this.$amlLoaded) //|| !e.$oldParent + return; + + if (!e.$isMoveWithinParent + && this.skinName != this.parentNode.skinName) { + // this.$destroy(); //clean up button + var skin = this.parentNode.skinName.split(":"); + this.$forceSkinChange(skin[1], skin[0]); + } + else if (this.$button && (!e.$oldParent || e.$oldParent.$hasButtons) && this.parentNode.$buttons) + this.parentNode.$buttons.insertBefore(this.$button, + e.$beforeNode && e.$beforeNode.$button || null); + + if (this.type) + this.relPage = this.parentNode.getPage && this.parentNode.getPage(this.type); + + }, true); + + // *** Private state functions *** // + + this.$position = 0; + this.$first = function(remove) { + if (remove) { + this.$isFirst = false; + this.$position -= 1; + this.parentNode.$setStyleClass(this.$button, "", + ["firstbtn", "firstcurbtn"]); + } + else { + this.$isFirst = true; + this.$position = this.$position | 1; + this.parentNode.$setStyleClass(this.$button, "firstbtn" + + (this.parentNode.$activepage == this ? " firstcurbtn" : "")); + } + }; + + this.$last = function(remove) { + if (remove) { + this.$isLast = false; + this.$position -= 2; + this.parentNode.$setStyleClass(this.$button, "", ["lastbtn"]); + } + else { + this.$isLast = true; + this.$position = this.$position | 2; + this.parentNode.$setStyleClass(this.$button, "lastbtn"); + } + }; + + this.$deactivate = function(fakeOther) { + this.$active = false; + + if (!this.parentNode) + return; + + if (this.parentNode.$hasButtons) { + if (this.$position > 0) + this.parentNode.$setStyleClass(this.$button, "", ["firstcurbtn"]); + this.parentNode.$setStyleClass(this.$button, "", ["curbtn"]); + } + + if ((!this.fake || this.relPage) && !fakeOther) { + this.parentNode.$setStyleClass(this.fake + ? this.relPage.$ext + : this.$ext, "", ["curpage"]); + + if (this.fake) { + if (!this.relPage.visible) + this.relPage.$ext.style.display = "none"; + + this.relPage.dispatchEvent("prop.visible", {value:false}); + } + + this.dispatchEvent("prop.visible", {value:false}); + } + }; + + this.$deactivateButton = function() { + if (this.parentNode && this.parentNode.$hasButtons) { + if (this.$position > 0) + this.parentNode.$setStyleClass(this.$button, "", ["firstcurbtn"]); + this.parentNode.$setStyleClass(this.$button, "", ["curbtn"]); + } + }; + + this.$activate = function(){ + //if (this.disabled) + //return false; + + this.$active = true; + + if (!this.$drawn) { + var f; + this.addEventListener("DOMNodeInsertedIntoDocument", f = function(e) { + this.removeEventListener("DOMNodeInsertedIntoDocument", f); + if (!this.$active) + return; + + this.$activate(); + }); + return; + } + + if (this.parentNode.$hasButtons) { + if (this.$isFirst) + this.parentNode.$setStyleClass(this.$button, "firstcurbtn"); + this.parentNode.$setStyleClass(this.$button, "curbtn"); + } + + if (!this.fake || this.relPage) { + if (this.fake) { + if (this.relPage) { + this.relPage.$ext.style.display = ""; + this.parentNode.$setStyleClass(this.relPage.$ext, "curpage"); + this.relPage.$fake = this; + + + if (this.relPage.$render) + this.relPage.$render(); + + + this.relPage.dispatchEvent("prop.visible", {value:true}); + } + } + else { + this.parentNode.$setStyleClass(this.$ext, "curpage"); + } + + + if (apf.layout && this.relPage) + apf.layout.forceResize(this.fake ? this.relPage.$int : this.$int); + + } + + + if (this.$render) + this.$render(); + + + if (!this.fake) { + if (apf.isIE) { + var cls = this.$ext.className; + this.$ext.className = "rnd" + Math.random(); + this.$ext.className = cls; + } + + this.dispatchEvent("prop.visible", {value:true}); + } + }; + + this.$activateButton = function() { + if (this.$active) + return; + + if (!this.$drawn) { + var f; + this.addEventListener("DOMNodeInsertedIntoDocument", f = function(e) { + this.removeEventListener("DOMNodeInsertedIntoDocument", f); + this.$activateButton(); + }); + return; + } + + if (this.parentNode && this.parentNode.$hasButtons) { + if (this.$isFirst) + this.parentNode.$setStyleClass(this.$button, "firstcurbtn"); + this.parentNode.$setStyleClass(this.$button, "curbtn"); + } + + + if (this.$render) + this.$render(); + + }; + + this.addEventListener("$skinchange", function(){ + if (this.caption) + this.$propHandlers["caption"].call(this, this.caption); + + if (this.icon) + this.$propHandlers["icon"].call(this, this.icon); + }); + + this.$enable = function(){ + if (this.$button) + this.$setStyleClass(this.$button, null, ["btnDisabled"]);//@todo this.$baseCSSname + + }; + + this.$disable = function(){ + if (this.$button) + this.$setStyleClass(this.$button, "btnDisabled");//@todo this.$baseCSSname + + }; + + function $btnSet(oHtml) { + this.parentNode.set(this); + if (this.autofocus) + this.canHaveChildren = 2; + this.$setStyleClass(oHtml, "down", null, true); + } + + this.$btnDown = function(oHtml, htmlEvent) { + if (this.disabled) + return; + + if (htmlEvent.button == 2 && this.parentNode.contextmenu) { + this.parentNode.contextPage = this; + return; + } + + if (this.parentNode.dispatchEvent("tabselectclick", { + tab: this, + htmlEvent: htmlEvent + }) === false) + return; + + this.$btnPressed = true; + + //if (!this.parentNode.$order) + $btnSet.call(this, oHtml); + } + + this.$btnUp = function(oHtml) { + this.parentNode.$setStyleClass(oHtml, "", ["down"], true); + + if (this.disabled) + return; + + if (false && this.parentNode.$order && this.$btnPressed) { + this.$dragging = false; + + $btnSet.call(this, oHtml); + } + + this.$btnPressed = false; + + this.parentNode.dispatchEvent("tabselectmouseup"); + } + + this.$btnOut = function(oHtml) { + this.parentNode.$setStyleClass(oHtml, "", ["over"], true); + + this.canHaveChildren = true; + this.$dragging = false; + this.$btnPressed = false; + } + + // *** Init *** // + + this.$canLeechSkin = true; + + this.addEventListener("prop.class", function(e) { + apf.setStyleClass(this.$button, e.value, this.$lastClassValueBtn ? [this.$lastClassValueBtn] : null); + this.$lastClassValueBtn = e.value; + }); + + this.$draw = function(isSkinSwitch) { + this.skinName = this.parentNode.skinName; + + var sType = this.getAttribute("type") + if (sType) { + this.fake = true; + this.relPage = this.parentNode.getPage(sType) || null; + } + + if (this.parentNode.$hasButtons) { + //this.parentNode.$removeEditable(); //@todo multilingual support is broken when using dom + + this.parentNode.$getNewContext("button"); + var elBtn = this.parentNode.$getLayoutNode("button"); + elBtn.setAttribute(this.parentNode.$getOption("main", "select") || "onmousedown", + 'apf.lookup(' + this.$uniqueId + ').$btnDown(this, event);'); + elBtn.setAttribute("onmouseup", + 'apf.lookup(' + this.$uniqueId + ').$btnUp(this)'); + elBtn.setAttribute("onmouseover", 'var o = apf.lookup(' + + this.$uniqueId + ').parentNode;if(apf.lookup(' + this.$uniqueId + + ') != o.$activepage' + (this.parentNode.overactivetab ? " || true" : "") + ') o.$setStyleClass(this, "over", null, true);'); + elBtn.setAttribute("onmouseout", 'var o = apf.lookup(' + + this.$uniqueId + ');o&&o.$btnOut(this, event);'); + + //var cssClass = this.getAttribute("class"); + //if (cssClass) { + // apf.setStyleClass(elBtn, cssClass); + // this.$lastClassValueBtn = cssClass; + //} + + this.$button = apf.insertHtmlNode(elBtn, this.parentNode.$buttons); + + var closebtn = this.closebtn = this.getAttribute("closebtn"); + if ((apf.isTrue(closebtn) || ((this.parentNode.buttons || "").indexOf("close") > -1 && !apf.isFalse(closebtn)))) + this.$propHandlers["closebtn"].call(this, true); + + +// if (this.parentNode.$scale) { +// var w = apf.getHtmlInnerWidth(this.parentNode.$buttons); +// var l = this.parentNode.getPages().length; +// this.$button.style.width = Math.round(Math.min(w/l, this.parentNode.$maxBtnWidth)) + "px"; +// } + + + if (!isSkinSwitch && this.nextSibling && this.nextSibling.$button) + this.$button.parentNode.insertBefore(this.$button, this.nextSibling.$button); + + this.$button.host = this; + } + + if (this.fake) + return; + + if (this.$ext) + this.$ext.parentNode.removeChild(this.$ext); //@todo mem leaks? + + this.$ext = this.parentNode.$getExternal("tab", + this.parentNode.oPages, null, this); + this.$ext.host = this; + + this.$int = this.parentNode + .$getLayoutNode("Tab", "container", this.$ext); + //if (this.$int) + //this.$int.setAttribute("id", this.$int.getAttribute("id")); + + //@todo this doesnt support hidden nodes. + if (this.visible) { + if (this.$isLast) + this.$last(); + if (this.$isFirst) + this.$first(); + } + + var _self = this; + this.parentNode && this.parentNode.getPages().forEach(function(tab) { + if (tab && tab.type == _self.id) { + tab.relPage = _self; + if (tab.$active) { + _self.$fake = tab; + tab.$activate(); + } + _self.$button.style.display = "none"; + _self.visible = false; + } + }) + }; + + this.$destroy = function(){ + if (this.$button) { + if (this.parentNode && !this.parentNode.$amlDestroyed + && this.$button.parentNode) + this.$button.parentNode.removeChild(this.$button); + + this.$button.host = null; + this.$button = null; + } + }; + + +}).call(apf.tab.prototype = new apf.Presentation()); + +apf.aml.setElement("tab", apf.tab); + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * element specifying an argument of a method in an rpc element. + * @attribute {String} name the argument name. + * @attribute {String} [value] the value of the argument. + * @attribute {String} [default] the default value of the argument. If + * no value is specified when this function + * is called, the default value is used. + */ +apf.param = function(struct, tagName) { + this.$init(tagName || "param", apf.NODE_HIDDEN, struct); +}; + +apf.param.prototype = new apf.AmlElement(); +apf.param.prototype.$parsePrio = "002"; +apf.aml.setElement("variable", apf.param); //backwards compatibility +apf.aml.setElement("param", apf.param); + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * This element graphically represents a percentage value which increases + * automatically with time. + * + * This element is most often used to show the progress + * of a process. The progress can be either indicative or exact. + * + * #### Example: A Simple Progressbar + * + * ```xml, demo + * + * + * + * + * + * ``` + * + * #### Example: Progressbars with Varying Speeds + * + * ```xml, demo + * + * + * // + * + * + * // + * + * + * ``` + * + * #### Example: Dynmically Controlling the Progressbar + * + * ```xml, demo + * + * + * + * + * Start + * Pause + * Stop + * Clear + * Enable + * Disable + * + * + * ``` + * + * @class apf.progressbar + * @define progressbar + * @allowchild {smartbinding} + * + * @form + * @inherits apf.StandardBinding + * @inherits apf.DataAction + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.9 + */ +/** + * @binding value Determines the way the value for the element is retrieved + * from the bound data. + * + * #### Example + * + * Sets the progress position based on data loaded into this component. + * + * ```xml + * + * + * + * + * ``` + * + * A shorter way to write this is: + * + * ```xml + * + * + * + * + * ``` + */ +apf.progress = function(struct, tagName) { + this.$init(tagName || "progress", apf.NODE_VISIBLE, struct); +}; +apf.progressbar = function(struct, tagName) { + this.$init(tagName || "progressbar", apf.NODE_VISIBLE, struct); +}; + +(function(){ + + this.implement(apf.DataAction); + + + this.$focussable = false; // This object can get the focus + + // *** Properties and Attributes *** // + + this.value = 0; + this.min = 0; + this.max = 100; + + this.$running = false; + this.$timer; + + /** + * @attribute {Boolean} autostart Sets or gets whether the progressbar starts automatically. + */ + /** + * @attribute {Boolean} autohide Sets or gets whether the progressbar hides when the progress is at 100%. Setting this to `true` hides the progressbar at start when autostart is not set to `true`. + */ + this.$booleanProperties["autostart"] = true; + this.$booleanProperties["autohide"] = true; + + this.$supportedProperties.push("value", "min", "max", "autostart", "autohide"); + + /** + * @attribute {String} value Sets or gets the position of the progressbar stated between + * the min and max value. + */ + this.$propHandlers["value"] = function(value) { + this.value = parseInt(value) || this.min; + + if (this.value >= this.max) + apf.setStyleClass(this.$ext, this.$baseCSSname + "Complete", [this.$baseCSSname + "Running", this.$baseCSSname + "Half"]); + else + apf.setStyleClass(this.$ext, this.$baseCSSname + "Running", [this.$baseCSSname + "Complete"]); + + if (this.value >= this.max / 2) + apf.setStyleClass(this.$ext, this.$baseCSSname + "Half", []); + + this.oSlider.style.width = (this.value * 100 / (this.max - this.min)) + "%" + + /*Math.max(0, + Math.round((this.$ext.offsetWidth - 5) + * (this.value / (this.max - this.min)))) + "px";*/ + + this.oCaption.nodeValue = + Math.round((this.value / (this.max - this.min)) * 100) + "%"; + }; + + /** + * @attribute {Number} min Sets or gets the minimum value the progressbar may have. This is + * the value that the progressbar has when it is at its start position. + */ + this.$propHandlers["min"] = function(value) { + this.min = parseFloat(value); + }; + + /** + * @attribute {Number} max Sets or gets the maximum value the progressbar may have. This is + * the value that the progressbar has when it is at its end position. + */ + this.$propHandlers["max"] = function(value) { + this.max = parseFloat(value); + }; + + // *** Public Methods *** // + + + + /** + * Sets the value of this element. This should be one of the values + * specified in the `values` attribute. + * @param {String} value The new value of this element + */ + this.setValue = function(value) { + this.setProperty("value", value, false, true); + }; + + /** + * Returns the current value of this element. + * @return {String} The current value. + */ + this.getValue = function(){ + return this.value; + }; + + + + /** + * Resets the progress indicator. + */ + this.clear = function(){ + this.$clear(); + }; + + this.$clear = function(restart, restart_time) { + clearInterval(this.$timer); + this.setValue(this.min); + //this.oSlider.style.display = "none"; + apf.setStyleClass(this.$ext, "", [this.$baseCSSname + "Running", this.$baseCSSname + "Complete"]); + + if (restart) { + var _self = this; + this.$timer = setInterval(function(){ + _self.start(restart_time); + }); + } + + if (this.autohide) + this.hide(); + + this.$running = false; + }; + + /** + * Starts the progress indicator. + * @param {Number} start Sets or gets the time between each step in milliseconds. + */ + this.start = function(time) { + if (this.autohide) + this.show(); + + clearInterval(this.$timer); + + //if (this.value == this.max) + //this.setValue(this.min + (this.max - this.min) * 0.5); + + //this.oSlider.style.display = "block"; + var _self = this; + this.$timer = setInterval(function(){ + if (_self.$amlDestroyed) + clearInterval(_self.$timer); + else + _self.$step(); + }, time || 1000); + this.$setStyleClass(this.$ext, this.$baseCSSname + "Running"); + }; + + /** + * Pauses the progress indicator. + */ + this.pause = function(){ + clearInterval(this.$timer); + }; + + /** + * Stops the progress indicator from moving. + * @param {Boolean} restart Specifies whether a `this.$timer` should start with a new indicative progress indicator. + * @param {Number} [time=500] The internal (in milliseconds) + * @param {Number} [restart_time] The time for the next restart to occur + */ + this.stop = function(restart, time, restart_time) { + clearInterval(this.$timer); + this.setValue(this.max); + + var _self = this; + this.$timer = setInterval(function(){ + _self.$clear(restart, (restart_time || 0)); + }, time || 500); + }; + + // *** Private methods *** // + + this.$step = function(){ + if (this.value == this.max) + return; + + this.setValue(this.value + 1); + }; + + // *** Init *** // + + this.$draw = function(clear, parentNode, Node, transform) { + //Build Main Skin + this.$ext = this.$getExternal(); + this.oSlider = this.$getLayoutNode("main", "progress", this.$ext); + this.oCaption = this.$getLayoutNode("main", "caption", this.$ext); + }; + + this.$loadAml = function(x) { + if (this.autostart) + this.start(); + + if (this.autohide) + this.hide(); + }; + +}).call(apf.progressbar.prototype = new apf.StandardBinding()); + + +apf.progress.prototype = apf.progressbar.prototype; + +apf.aml.setElement("progress", apf.progress); +apf.aml.setElement("progressbar", apf.progressbar); + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +/** + * This element displays a two state button which is one of a grouped set. + * Only one of these buttons in the set can be selected at the same time. + * + * #### Example: Settings Groups + * + * ```xml, demo + * + * + * + * Options + * Choices + * Option 1 + * Choice 1 + * Option 2 + * Choice 2 + * + * + * + * ``` + * + * @class apf.radiobutton + * @define radiobutton + * @allowchild {smartbinding} + * + * @form + * @inherits apf.Presentation + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.4 + * + */ +/** + * @binding value Determines the way the value for the element is retrieved + * from the bound data. + * + * #### Example + * + * Sets the selection based on data loaded into this component. + * + * ```xml + * Choice 1 + * Choice 2 + * + * + * + * + * ``` + * + * A shorter way to write this is: + * + * ```xml + * Choice 1 + * Choice 2 + * ``` + * + */ +/** + * @event click Fires when the user presses a mousebutton while over this element and then lets the mousebutton go. + * @see apf.AmlNode@afterchange + */ +apf.radiobutton = function(struct, tagName) { + this.$init(tagName || "radiobutton", apf.NODE_VISIBLE, struct); + + /*this.$constructor = apf.radiobutton; + var fEl = apf.aml.setElement("radiobutton", function(){ + this.$init(tagName || "radiobutton", apf.NODE_VISIBLE, struct); + }); + fEl.prototype = apf.radiobutton.prototype; + apf.radiobutton = fEl;*/ +}; + +(function(){ + this.implement(apf.ChildValue); + this.$childProperty = "label"; + + this.$focussable = apf.KEYBOARD; // This object can get the focus + + //1 = force no bind rule, 2 = force bind rule + /*this.$attrExcludePropBind = apf.extend({ + selected: 1 + }, this.$attrExcludePropBind);*/ + + // *** Properties and Attributes *** // + + this.$booleanProperties["selected"] = true; + this.$supportedProperties.push("value", "background", "group", + "label", "selected", "tooltip", "icon"); + + /** + * @attribute {String} group Sets or gets the name of the group to which this radio + * button belongs. Only one item in the group can be selected at the same + * time. + * When no group is specified the parent container functions as the + * group; only one radiobutton within that parent can be selected. + */ + this.$propHandlers["group"] = function(value) { + if (!this.$ext) + return; + + if (this.$group && this.$group.$removeRadio) + this.$group.$removeRadio(this); + + if (!value) { + this.$group = null; + return; + } + + var group = typeof value == "string" + ? + + apf.nameserver.get("group", value) + + : value; + if (!group) { + + group = apf.nameserver.register("group", value, + new apf.$group()); + group.setAttribute("id", value); + group.dispatchEvent("DOMNodeInsertedIntoDocument"); + group.parentNode = this; + + } + this.$group = group; + + if (this.oInput) + this.oInput.setAttribute("name", value); + + this.$group.$addRadio(this); + }; + + /** + * @attribute {String} tooltip Sets or gets the tooltip of this radio button. + */ + this.$propHandlers["tooltip"] = function(value) { + this.$ext.setAttribute("title", value); + }; + + /** + * @attribute {String} icon Sets or gets the icon for this radiobutton + */ + this.$propHandlers["icon"] = function(value) { + + if (!this.oIcon) return; + + + if (value) + this.$setStyleClass(this.$ext, this.$baseCSSname + "Icon"); + else + this.$setStyleClass(this.$ext, "", [this.$baseCSSname + "Icon"]); + + apf.skins.setIcon(this.oIcon, value, this.iconPath); + }; + + /** + * @attribute {String} label Sets or gets the label for this radiobutton + */ + this.$propHandlers["label"] = function(value) { + if (value) + this.$setStyleClass(this.$ext, "", [this.$baseCSSname + "Empty"]); + else + this.$setStyleClass(this.$ext, this.$baseCSSname + "Empty"); + + if (this.oLabel) + this.oLabel.innerHTML = value; + }; + + /** + * @attribute {Boolean} selected Sets or gets whether this radiobutton is the selected one in the group it belongs to. + */ + this.$propHandlers["selected"] = function(value) { + if (!this.$group) + return; + + if (value) + this.$group.setProperty("value", this.value); + //else if (this.$group.value == this.value) + //this.$group.setProperty("value", ""); + }; + + this.addEventListener("prop.model", function(e) { + if (this.$group) + this.$group.setProperty("model", e.value); + }); + + /** + * @attribute {String} background Sets a multistate background. The arguments + * are seperated by pipes (`'|'`) and are in the order of: `'imagefilename|mapdirection|nrofstates|imagesize'` + * + * {:multiStateDoc} + * + * + * #### Example + * + * Here's a three state picture where each state is 16px high, vertically spaced: + * + * ```xml + * background="threestates.gif|vertical|3|16" + * ``` + * @see apf.BaseButton + */ + this.$propHandlers["background"] = function(value) { + var oNode = this.$getLayoutNode("main", "background", this.$ext); + if (value) { + var b = value.split("|"); + this.$background = b.concat(["vertical", 2, 16].slice(b.length - 1)); + + oNode.style.backgroundImage = "url(" + this.mediaPath + b[0] + ")"; + oNode.style.backgroundRepeat = "no-repeat"; + } + else { + oNode.style.backgroundImage = ""; + oNode.style.backgroundRepeat = ""; + this.$background = null; + } + }; + + // *** Public methods *** // + + + + /** + * Sets the value of this element. This should be one of the values + * specified in the `values` attribute. + * @param {String} value The new value of this element + */ + this.setValue = function(value) { + this.setProperty("value", value, false, true); + }; + + /** + * Returns the current value of this element. + * @return {String} The current value + */ + this.getValue = function(){ + return this.value; + }; + + this.select = function(){ + this.setProperty("selected", true, false, true); + }; + + /*this.uncheck = function(){ + this.setProperty("selected", false, false, true); + }*/ + + this.getGroup = function(){ + return this.$group; + }; + + + + /* + * Sets the selected state and related value + */ + this.$check = function(visually) { + this.$setStyleClass(this.$ext, this.$baseCSSname + "Selected"); + this.selected = true; + if (this.oInput) + this.oInput.selected = true; + this.doBgSwitch(2); + }; + + this.$uncheck = function(){ + this.$setStyleClass(this.$ext, "", [this.$baseCSSname + "Selected"]); + this.selected = false; + if (this.oInput) + this.oInput.selected = false; + this.doBgSwitch(1); + }; + + // *** Private methods *** // + + this.$enable = function(){ + if (this.oInput) + this.oInput.disabled = false; + + var _self = this; + this.$ext.onclick = function(e) { + if (!e) e = event; + if ((e.srcElement || e.target) == this) + return; + + _self.dispatchEvent("click", { + htmlEvent: e + }); + _self.$group.change(_self.value); + } + + this.$ext.onmousedown = function(e) { + if (!e) e = event; + if ((e.srcElement || e.target) == this) + return; + + apf.setStyleClass(this, _self.$baseCSSname + "Down"); + } + + this.$ext.onmouseover = function(e) { + if (!e) e = event; + if ((e.srcElement || e.target) == this) + return; + + apf.setStyleClass(this, _self.$baseCSSname + "Over"); + } + + this.$ext.onmouseout = + this.$ext.onmouseup = function(){ + apf.setStyleClass(this, "", [_self.$baseCSSname + "Down", _self.$baseCSSname + "Over"]); + } + }; + + this.$disable = function(){ + if (this.oInput) + this.oInput.disabled = true; + + this.$ext.onclick = + this.$ext.onmousedown = + this.$ext.onmouseover = + this.$ext.onmouseout = + this.$ext.onmouseup = null; + }; + + /** + * @private + */ + this.doBgSwitch = function(nr) { + if (this.bgswitch && (this.bgoptions[1] >= nr || nr == 4)) { + if (nr == 4) + nr = this.bgoptions[1] + 1; + + var strBG = this.bgoptions[0] == "vertical" + ? "0 -" + (parseInt(this.bgoptions[2]) * (nr - 1)) + "px" + : "-" + (parseInt(this.bgoptions[2]) * (nr - 1)) + "px 0"; + + this.$getLayoutNode("main", "background", this.$ext) + .style.backgroundPosition = strBG; + } + }; + + this.$focus = function(){ + if (!this.$ext) + return; + if (this.oInput && this.oInput.disabled) + return false; + + this.$setStyleClass(this.$ext, this.$baseCSSname + "Focus"); + }; + + this.$blur = function(){ + if (!this.$ext) + return; + this.$setStyleClass(this.$ext, "", [this.$baseCSSname + "Focus"]); + }; + + // *** Keyboard support *** // + + + this.addEventListener("keydown", function(e) { + var key = e.keyCode; + + if (key == 13 || key == 32) { + //this.check(); + //this.$group.current = this; + this.$group.change(this.value); + return false; + } + //Up + else if (key == 38) { + var node = this; + while (node && node.previousSibling) { + node = node.previousSibling; + if (node.localName == "radiobutton" && !node.disabled + && node.$group == this.$group) { + node.check(); + node.focus(); + return; + } + } + } + //Down + else if (key == 40) { + var node = this; + while (node && node.nextSibling) { + node = node.nextSibling; + if (node.localName == "radiobutton" && !node.disabled + && node.$group == this.$group) { + node.check(); + node.focus(); + return; + } + } + } + }, true); + + + // *** Init *** // + + this.$draw = function(){ + //Build Main Skin + this.$ext = this.$getExternal(); + this.oInput = this.$getLayoutNode("main", "input", this.$ext); + this.oLabel = this.$getLayoutNode("main", "label", this.$ext); + this.oIcon = this.$getLayoutNode("main", "icon", this.$ext); + + if (this.oLabel && this.oLabel.nodeType != 1) + this.oLabel = this.oLabel.parentNode; + + //Set events + this.$enable(); + }; + + this.$childProperty = "label"; + this.$loadAml = function(x) { + if (this.group) + this.$propHandlers["group"].call(this, this.group); + + else if (this.parentNode.localName == "group") + this.$propHandlers["group"].call(this, this.parentNode); + + if (!this.$group) { + this.$propHandlers["group"].call(this, + "group" + this.parentNode.$uniqueId); + } + }; + + this.$destroy = function(){ + if (this.$group) + this.$group.$removeRadio(this); + }; + + +}).call(apf.radiobutton.prototype = new apf.Presentation()); + +apf.aml.setElement("radiobutton", apf.radiobutton); + +/** + * An element that defines groups for radio buttons. + * + * #### Example + * + * This example shows radio buttons with an explicit group set: + * + * ```xml + * Options + * Option 1 + * Option 2 + * + * Choices + * + * Choice 1 + * Choice 2 + * + * ``` + * + * @class apf.group + * @define group + */ +apf.$group = apf.group = function(struct, tagName) { + this.$init(tagName || "group", apf.NODE_VISIBLE, struct); + + this.implement( + apf.StandardBinding, + + apf.DataAction + + + ); + + var radiobuttons = []; + + this.$supportedProperties.push("value", "selectedItem"); + this.$propHandlers["value"] = function(value) { + for (var i = 0; i < radiobuttons.length; i++) { + if (radiobuttons[i].value == value) { + return this.setProperty("selectedItem", radiobuttons[i]); + } + } + return this.setProperty("selectedItem", null); + }; + + var lastSelected; + this.$propHandlers["selectedItem"] = function(rb) { + if (lastSelected) + lastSelected.$uncheck(); + if (!rb) + return; + + rb.$check(); + lastSelected = rb; + + for (var i = 0; i < radiobuttons.length; i++) + radiobuttons[i].setProperty("selectedItem", rb); + }; + + this.$addRadio = function(rb) { + var id = radiobuttons.push(rb) - 1; + + if (!rb.value) + rb.setProperty("value", id); + + var _self = this; + rb.addEventListener("prop.value", function(e) { + if (this.selected) + _self.setProperty("value", e.value); + else if (_self.value == e.value) + this.select(); + }); + + if (this.value && rb.value == this.value) + this.setProperty("selectedItem", rb); + else if (rb.selected) + this.setProperty("value", rb.value); + }; + + this.$removeRadio = function(rb) { + radiobuttons.remove(rb); + + if (rb.value === rb.id) + rb.setProperty("value", ""); + + if (rb.selectedItem == rb) + this.setProperty("value", null); + }; + + /** + * Sets the current value of this element. + */ + this.setValue = function(value) { + this.setProperty("value", value); + }; + + /** + * Returns the current value of this element. + * @return {String} The current value. + */ + this.getValue = function(){ + return this.value; + }; + + this.$draw = function(){ + this.$ext = this.$int = this.$pHtmlNode; + }; +}; +apf.$group.prototype = new apf.GuiElement(); + +apf.aml.setElement("group", apf.$group); + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * Element allowing data synchronization between multiple clients using the same + * application or application part. This element is designed as thecore of + * collaborative application logic for Ajax.org Platform. The children of this + * element specify how the uniqueness of {@link term.datanode data nodes} is determined. By pointing + * models to this element, all changes to their data will be streamed through + * this element to all listening client over a choosen protocol. + * Example: + * This example shows a small application which is editable by all clients that + * have started it. Any change to the data is synchronized to all participants. + * + * + * + * + * + * + * + * + * mike + * ruben + * + * + * + * + * + * + * + * + * + * + * + * Remove + * Rename + * + * + * Login + * + * + * Remarks: + * Although locking is solved in smartbindings it is directly connected + * to remote databindings. When multiple people are working within the same + * application it's important to have a system that prevents corruption of data + * and data loss by either user overwriting records edited during the same period. + * Ajax.org Platform has built in support for optimistic and pessimistic locking + * in smartbindings. For more information please see {@link term.locking}. + * + * Advanced: + * There is a very small theoretical risk that a user initiates and finishes an + * action during the latency period of the rdb communication. Usually this + * latency is no more than 100 to 300ms which is near impossible for such action + * to be performed. Therefor this is deemed acceptable. + * + * Working in a multi user environment usually implies that data has a high + * probability of changing. This might become a problem when syncing offline + * changes after several hours. This should be a consideration for the + * application architect. + * + * Another concern for offline use is the offline messaging feature of certain + * collaborative protocols (i.e. xmpp). In many cases offline rdb messages should + * not be stored after the user has been offline for longer then a certain time. + * For instance 10 minutes. An accumulation of change messages would create a + * serious scaling problem and is not preferred. apf.offline has built in support + * for this type of timeout. By setting the rdb-timeout attribute it is aware + * of when the server has timed out. When this timeout is reached the application + * will reload all its data from the server and discard all offline rdb + * messages before reconnecting to the server. + * + * @attribute {String} transport the name of the teleport element that provides a + * bidirectional connection to (a pool of) other clients. + * + * + * + * @define remote + * @allowchild unique, {any} + * + * + * @define unique Element defining what is unique about a set of data elements. + * This enables remote databindings to point to xml data in the same way on all + * clients. This way changes that happen to these elements are described + * non-ambiguously. The tagName can be replaced by the tagName of the + * {@link term.datanode data node} for which the uniqueness is specified. + * Example: + * This example shows a complex data set and a remote databinding that + * specifies the uniqueness of all nodes concerned. + * + * + * + * + * + * 3564 + * 8104 + * + * + * Mike + * Rik + * + * + * + * + * + * + * + * @attribute {String} transport ID of a Teleport element that is able to serve + * as a transport for RDB message like xmpp + */ +/** + * @author Mike de Boer (mike AT ajax DOT org) + * @version %I%, %G% + * @since 3.0 + * + * @default_private + * @constructor + * + * @todo Think about wrapping multiple messages in a single call + * @todo Make RDB support different encoding protocols (think REX) + */ +apf.remote = function(struct, tagName) { + this.$init(tagName || "remote", apf.NODE_HIDDEN, struct); + +// this.lookup = {}; +// this.select = []; + this.$sessions = {}; + this.rdbQueue = {}; + this.queueTimer = null; + this.pendingTerminations = {}; + this.offlineQueue = []; +}; + +apf.remote.SESSION_INITED = 0x0001; //Session has not started yet. +apf.remote.SESSION_STARTED = 0x0002; //Session is started +apf.remote.SESSION_TERMINATED = 0x0004; //Session is terminated + +(function(){ + + + this.logprefix = ""; + if (!apf.isO3) { + this.log = function(msg) { + apf.console.log(msg); + } + } + + //1 = force no bind rule, 2 = force bind rule + this.$attrExcludePropBind = apf.extend({ + match: 1 + }, this.$attrExcludePropBind); + + this.$supportedProperties.push("transport"); + + /* @todo move this to the rdb-xmpp transport layer + function checkProtocol(uri) { + if (uri.indexOf("rdb__") === 0) + return "rdb:" + uri.substr(3).replace(/_/g, "/"); + return uri; + } */ + + this.$propHandlers["transport"] = function(value) { + this.transport = typeof value == "object" ? value : self[this["transport"]]; + + + + var _self = this; + this.transport.addEventListener("connect", function() { + var uri, oSession; + for (uri in _self.$sessions) { + oSession = _self.$sessions[uri]; + if (oSession.state == apf.remote.SESSION_STARTED) + continue; + + this.join(uri, function(uri, iTime) { + //_self.$startSession(uri, iTime); + }); + } + }); + + this.transport.addEventListener("disconnect", function() { + var uri, oSession; + for (uri in _self.$sessions) { + oSession = _self.$sessions[uri]; + oSession.state = apf.remote.SESSION_TERMINATED; + } + }); + + this.transport.addEventListener("update", function(e) { + _self.$update(e); + }); + + this.transport.addEventListener("join", function(e) { + if (!e.uri) + return; + + var uri = e.uri, + oSession = _self.$sessions[e.uri]; + //if document isn't passed this must be a join request from a peer + if (!e.document) { + + + return _self.dispatchEvent("joinrequest", e); + } + + //Create sesssion if it doesn't exist + if (!oSession) + oSession = _self.createSession(uri, null, null, e.document, e.basetime); + else { + oSession.model.load(e.document); + _self.$startSession(uri, e.basetime); + } + }); + + this.transport.addEventListener("leave", function(e) { + _self.endSession(e.uri); + }); + }; + + this.$update = function(e) { + var sData = e.message.args ? [e.message] : e.message; + var oData = typeof sData == "string" + ? apf.unserialize(sData) + : sData; + var oSession = this.$sessions[e.uri]; + var i = 0; + var l = oData.length; + + for (; i < l; i++) + this.$receiveChange(oData[i], oSession, e.annotator); + }; + + this.clear = function(){ + this.$sessions = {}; + }; + + /** + * Create a new RDB session based on a URI. + * @param uri + * @param model + * @param xpath + */ + this.createSession = function(uri, model, xpath, doc, iTime) { + this.log && this.log(this.logprefix + "Creating session for " + uri); + + if (!model) + model = this.dispatchEvent("modelfind", {uri: uri}); + if (model) { + delete model.src; + //@todo if this model is in a session stop that session + } + else + model = new apf.model(); //apf.nameserver.register("model", id, ); + + model.setProperty("remote", this); + model.rdb = this; + model.src = uri; + + var oSession = this.$addSession(uri, model, xpath); + + //We received the document and load it + if (doc) { + model.load(doc); + this.$startSession(uri, iTime); + } + //We did not receive a document and will issue a join request to the server + else { + //If the transport is already connected, let + if (this.transport && this.transport.isConnected()) { + var _self = this; + this.transport.join(uri, function(uri, iTime) { + _self.$startSession(uri, iTime); + }); + } + } + + return oSession; + }; + + /** + * Terminate an RDB session based on a URI. + * @param uri + */ + this.endSession = function(uri) { + if (!this.$sessions || !this.$sessions[uri]) + return; + + var oSession = this.$sessions[uri]; + if (this.transport && this.transport.isConnected() && oSession.state != apf.remote.SESSION_TERMINATED) + this.transport.leave(uri); + + oSession.state = apf.remote.SESSION_TERMINATED; + + delete this.$sessions[uri]; + }; + + this.$addSession = function(uri, model, xpath) { + delete this.$sessions[uri]; + + return this.$sessions[uri] = { + uri: uri, + model: model, + xpath: xpath, + state: apf.remote.SESSION_INITED + }; + }; + + this.$startSession = function(uri, basetime) { + var oSession = this.$sessions[uri]; + + if (!oSession) { + + return false; + } + + oSession.state = apf.remote.SESSION_STARTED; + if (basetime && !oSession.basetime) + oSession.basetime = basetime; + + + }; + + this.$queueMessage = function(args, model, qHost) { + if (!qHost.rdbQueue) + qHost.rdbQueue = {}; + + var uri = model.src; + var oSession = this.$sessions[uri]; + + + + if (!qHost.rdbQueue[uri]) { + qHost.rdbQueue[uri] = []; + qHost.rdbModel = model; + } + + for (var node, i = 0, l = args.length; i < l; ++i) { + if ((node = args[i]) && node.nodeType) { + //@todo some changes should not be sent to the server + if (args[0] == "setAttribute" && args[2] == "level" + && args[1] == args[1].ownerDocument.documentElement) + return false; //@todo refactor and make configurable + + args[i] = this.xmlToXpath(args[i], model.data); + } + else if (node && node.dataType == apf.ARRAY) { + for (var j = 0; j < node.length; j++) { + if (node[j] && node[j].nodeType) + node[j] = this.xmlToXpath(node[j], model.data); + } + } + } + + qHost.rdbQueue[uri].push({ + uri: uri, + args: args, + currdelta: (new Date()).toISOString() - oSession.basetime + }); + }; + + this.$processQueue = function(qHost) { + if (qHost === this) + clearTimeout(this.queueTimer); + if (apf.xmldb.disableRDB) + return; + + var list; + for (var uri in qHost.rdbQueue) { + if (!(list = qHost.rdbQueue[uri]).length) + continue; + + + + if (this.transport) + this.transport.sendUpdate(uri, JSON.stringify(list)); + + this.dispatchEvent("rdbsend", { + uri: uri, + message: list + }); + } + + qHost.rdbQueue = {}; + }; + + this.$receiveChange = function(oMessage, oSession, sAnnotator) { + //if (apf.xmldb.disableRDB) { + this.log && this.log(this.logprefix + "Receiving change. disableRDB=" + apf.xmldb.disableRDB); + //return; + //} + + + + if (!oSession && oMessage.uri) + oSession = this.$sessions[oMessage.uri]; + + if (!oSession) { + + return; + } + + //if (oMessage.timestamp < this.discardBefore) //@todo discardBefore + //return; + + var model = oSession.model; + if (!model) { + + return; + } + if (!model.$at) + model.$at = apf.window.$at; //@todo find better solution to the case of a missing ActionTracker... + + var oError, xmlNode, disableRDB = apf.xmldb.disableRDB; + apf.xmldb.disableRDB = 2; //Feedback prevention + + // Correct timestamp with the session basetime + var time = oSession.basetime + parseInt(oMessage.currdelta, 10); + + + + // Undo all items until state is equal to when message was executed on original client. + var aUndos = []; //model.$at.getDone(time), + var i = 0; + var l = aUndos.length; + if (l) { + for (; i < l; ++i) + aUndos[i].$dontapply = true; + model.$at.undo(l); + } + + //Fetch node based on their xpath + var q = oMessage.args.slice(); + var xpath = q[1]; + xmlNode = q[1] = this.xpathToXml(xpath, model.data); + if (xmlNode) { + var action = q.shift(); + + if (action == "addChildNode") + q[3] = this.xpathToXml(q[3], model.data); + else if (action == "appendChild") { + q[1] = typeof q[1] == "string" ? apf.getXml(q[1]) : q[1]; + q[2] = q[2] ? this.xpathToXml(q[2], model.data) : null; + } + else if (action == "moveNode") { + q[1] = this.xpathToXml(q[1], model.data); + q[2] = q[2] ? this.xpathToXml(q[2], model.data) : null; + } + else if (action == "replaceNode") { + q[0] = typeof q[1] == "string" ? apf.getXml(q[1]) : q[1]; + q[1] = xmlNode; + } + else if (action == "removeNodeList") { + var arr = q[0]; + for (var i = 0; i < arr.length; i++) { + arr[i] = this.xpathToXml(arr[i], model.data); + } + } + else if (action == "setValueByXpath") {} + + // pass the action to the actiontracker to execute it + model.$at.execute({ + action: action, + args: q, + annotator: sAnnotator, + message: oMessage, + rdb: true + }); + + this.dispatchEvent("change", { + uri: oMessage.uri, + model: model, + xmlNode: xmlNode, + message: oMessage + }); + } + + + if (l) { + model.$at.redo(l); + for (i = 0; i < l; ++i) + delete aUndos[i].$dontapply; + } + + apf.xmldb.disableRDB = disableRDB; + + if (oError) { + apf.console.error(this.logprefix + oError.message) + } + }; + + this.xmlToXpath = apf.xmlToXpath; + this.xpathToXml = apf.xpathToXml; + + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + + + + }); + + this.addEventListener("DOMNodeRemovedFromDocument", function(e) { + for (var i = 0, l = this.$sessions.length; i < l; ++i) + this.endSession(this.$sessions[i].uri); + }); +}).call(apf.remote.prototype = new apf.AmlElement()); + +apf.aml.setElement("remote", apf.remote); + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +/** + * Baseclass for rpc in teleport. Modules are available for + * SOAP, XML-RPC, CGI, JSON-RPC and several proprietary protocols. + * + * Example: + * Ajax.org Markup Language + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * //This function is called when the search returns + * function processSearch(data, state, extra) { + * alert(data) + * } + * + * //Execute a search for the product car + * comm.searchProduct('car', 10); + * + * + * + * Example: + * This example shows an rpc element using the xmlrpc protocol. It contains + * two methods which can be called. The return of the first method is handled + * by a javascript function called processSearch. + * + * + * + * + * + * // + * + * + * Example: + * Ajax.org Markup Language + * + * + * + * + * + * + * + * + * + * + * //This function is called when the search returns + * function processSearch(data, state, extra) { + * alert(data) + * } + * + * //Execute a search for the product car + * comm.searchProduct('car', 10); + * + * + * + * Example: + * Ajax.org Markup Language + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * //This function is called when the search returns + * function processSearch(data, state, extra) { + * alert(data) + * } + * + * //Execute a search for the product car + * comm.searchProduct('car', 10); + * + * + * + * Example: + * Ajax.org Markup Language + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * //This function is called when the search returns + * function processSearch(data, state, extra) { + * alert(data) + * } + * + * //Execute a search for the product car + * comm.searchProduct('car', 10); + * + * + * + * Example: + * Ajax.org Markup Language + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * //This function is called when the search returns + * function processSearch(data, state, extra) { + * alert(data) + * } + * + * //Execute a search for the product car + * comm.searchProduct('car', 10); + * + * + * + * @attribute {String} protocol the name of the plugin that is used + * to provide the messages. + * @attribute {Boolean} [multicall] whether the call is stacked until + * purge() is called. + * @attribute {String} [route-server] the location of the proxy script that + * allows for cross domain communication. + * @attribute {String} [http-method] the http method used to send the data. + * This attribute is only used by the cgi protocol. + * Possible values: + * post Used to store large chunks of data (on a resource). + * get Used to retrieve data from a resource. + * delete Used to delete a resource. + * head Returns only the headers. + * put Used to store data at a resource. + * @attribute {String} [method-name] the variable name used to sent the + * name of the method called to the + * server. This attribute is only used + * by the cgi protocol. + * @attribute {String} [soap-xmlns] the url that uniquely identifies the + * xml namespace for the message. This + * attribute is only used by the soap + * protocol. + * @attribute {String} [soap-prefix] the prefix that is paired with the + * message xml namespace. This attribute + * is only used by the soap protocol. + * @define rpc + * @allowchild method + * + * @constructor + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @author Mike de Boer (mike AT javeline DOT com) + * @version %I%, %G% + * @since 0.4 + * @default_private + */ +apf.rpc = function(struct, tagName) { + this.$init(tagName || "rpc", apf.NODE_HIDDEN, struct); + + if (!this.supportMulticall) + this.multicall = false; + this.stack = {}; + this.urls = {}; + this.$methods = {}; +}; + +(function(){ + this.useHTTP = true; + this.namedArguments = false; + + this["route-server"] = apf.host + "/cgi-bin/rpcproxy.cgi"; + this.autoroute = false; + + this.$auth = false; + + this.$booleanProperties["multicall"] = true; + + this.$supportedProperties.push("protocol", "type", "multicall", "http-method"); + + this.$propHandlers["route-server"] = function(value) { + this.autoroute = value ? true : false; + }; + + //@todo change this to use prototype + this.$propHandlers["protocol"] = function(value) { + if (!value) + return; + + if (!apf[value]) { + + return; + } + var _self = this; + // use a timeout, so that these protocols may override default methods + // inherited from http.js and the like. + $setTimeout(function() {_self.implement(apf[value]);}) + }; + + this.$propHandlers["type"] = function(value) { + this.$useXml = (typeof value == "string" && value.toUpperCase() == "XML"); + }; + + /** + * Sets the callback for a method on this object. + * Example: + * + * comm.setCallback("login", function(data, state, extra) { + * alert(data); + * }); + * + * comm.login(user, pass); + * + * @param {String} name the name of the method defined on this object. + * @param {Function} func the function that is called when the rpc method returns. + */ + this.setCallback = function(name, func) { + + + this.$methods[name].callback = func; + }; + + /** + * Sets the target url for a method on this object. + * Example: + * + * comm.setCallback("login", "scripts/login.php"); + * + * comm.login(user, pass); + * + * @param {String} name the name of the method defined on this object. + * @param {String} url the target url of method defined on this object. + */ + this.setUrl = function(name, url) { + + + this.$methods[name].setProperty("url", url); + }; + + this.$convertArgs = function(name, args) { + if (!this.namedArguments) + return Array.prototype.slice.call(args); + + var nodes = this.$methods[name].names; + if (!nodes || !nodes.length) + return {}; + + var value, j, i, l, result = {}; + for (j = 0, i = 0, l = nodes.length; i < l; i++) { + name = nodes[i].name; + value = nodes[i].value; + + if (value) { + value = apf.parseExpression(value); + } + else { + value = args[j++]; + + if (apf.isNot(value) && nodes[i]["default"]) + value = apf.parseExpression(nodes[i]["default"]); + } + + //Encode string optionally + value = apf.isTrue(nodes[i].encoded) + ? encodeURIComponent(value) + : value; + + result[name] = value; + } + + return result; + }; + + function getCallback(node) { + var p, f; + if (typeof node.callback == "string") { + // support objects and namespaced functions + p = node.callback.split("."), + f = self[p.shift()]; + while (f && p.length) + f = f[p.shift()]; + } + else { + f = node.callback; + } + return f || apf.K; + } + + this.call = function(name, args, options) { + var callback, + node = this.$methods[name]; + + if (typeof args[args.length - 1] == "function") { + args = Array.prototype.slice.call(args); //@todo optimize? + callback = args.pop(); + } + else { + callback = getCallback(node); + } + + args = this.$convertArgs(name, args); + + // Set up multicall + if (this.multicall) { + if (!this.stack[this.url]) + this.stack[this.url] = this.getMulticallObject + ? this.getMulticallObject() + : []; + + this.getSingleCall(name, args, this.stack[this.url]) + return true; + } + + // Get Data + var _self = this, + data = options && options.message + ? options.message + : this.createMessage(node["method-name"] || name, args); //function of module + + function pCallback(data, state, extra) { + extra.data = data; + + if (state != apf.SUCCESS) + callback.call(_self, null, state, extra); + else if (_self.isValid && !_self.isValid(extra)) + callback.call(_self, null, apf.ERROR, extra); + else + callback.call(_self, _self.unserialize(extra.data), state, extra); + } + + // Send the request + var auth, + url = apf.getAbsolutePath(this.baseurl || apf.config.baseurl, this.url), + o = apf.extend({ + callback: pCallback, + async: node.async, + userdata: node.userdata, + nocache: (this.nocache === false) ? false : true, + data: data, + useXML: this.$useXml || node.type == "xml", + caching: node.caching, + ignoreOffline: node["ignore-offline"], + withCredentials: node.withCredentials === false ? false : true + }, options); + + + //@todo this shouldn't be in here + if (node.auth && this.$auth) { + if (auth = this.$auth.$credentials) { + o.username = auth.username; + o.password = auth.password; + } + else { + return this.$auth.authRequired(function() { + auth = _self.$auth.$credentials + o.username = auth.username; + o.password = auth.password; + _self.$get(url, o); + }); + } + } + + + return this.$get(url, o); + }; + + /** + * Purge multicalled requests + */ + this.purge = function(callback, userdata, async, extradata) { + + + // Get Data + var data = this.createMessage("multicall", [this.stack[this.url]]), //function of module + url = apf.getAbsolutePath(this.baseurl || apf.config.baseurl, this.url); + if (extradata) { + for (var vars = [], i = 0; i < extradata.length; i++) { + vars.push(encodeURIComponent(extradata[i][0]) + "=" + + encodeURIComponent(extradata[i][1] || "")) + } + url = url + (url.match(/\?/) ? "&" : "?") + vars.join("&"); + } + + var info = this.$get(url, { + callback: callback, + async: async, + userdata: userdata, + nocache: true, + data: data, + useXML: this.$useXml + }); + + this.stack[this.url] = this.getMulticallObject + ? this.getMulticallObject() + : []; + + //return info[1]; + }; + + this.revert = function(modConst) { + this.stack[modConst.url] = this.getMulticallObject + ? this.getMulticallObject() + : []; + }; + + this.getStackLength = function(){ + return this.stack[this.url] ? this.stack[this.url].length : 0; + }; + + /** + * Loads aml definition + */ + this.$addMethod = function(amlNode) { + if (amlNode.localName != "method"){ + + return false; + } + + var name = amlNode.name, + cb = amlNode.receive || this.receive, + i = 0, + l = amlNode.childNodes.length, + node; + + this[name] = function(){ + return this.call(name, arguments); + }; + + if (cb) + amlNode.callback = cb; + + this.$methods[name] = amlNode; + + if (!amlNode.names) + amlNode.names = []; + for (; i < l; i++) { + node = amlNode.childNodes[i]; + if (node.localName == "param" || node.localName == "variable") //@todo deprecate variable + amlNode.names.push(node); + } + + return true; + }; + + this.$removeMethod = function(amlNode) { + var name = amlNode.name; + delete this[name]; + delete this.$methods[name]; + }; + + this.$setAuth = function(amlNode) { + this.$auth = amlNode; + }; + + /* + this.addEventListener("DOMNodeInserted", function(e) { + var node = e.currentTarget; + if (node.parentNode != this) + return; + + this.register(node); + }); + + this.addEventListener("DOMNodeRemoved", function(e) { + var node = e.currentTarget; + // we support two levels deep: + if (!(node.parentNode == this || node.parentNode.parentNode == this)) + return; + + this.unregister(node); + });*/ + + + this.exec = function(method, args, callback, options) { + if (!options) options = {}; + + //force multicall if needed; + if (options.multicall) + this.forceMulticall = true; + + //Set information later neeed + + + var props = this.$methods[method]; + + if (options.userdata) + props.userdata = options.userdata; + + if (!this.multicall) + props.callback = callback; //&& this[method].async + + //Call method + var retvalue = this.call(method, args, options); + + if (this.multicall) + return this.purge(callback, "&@^%!@"); //Warning!! @todo Make multicall work with offline + else if (options.multicall) { + this.forceMulticall = false; + return this; + } + + + + //Call callback for sync calls + if (!this.multicall && !props.async && callback) + callback(retvalue, apf.SUCCESS, {tpModule: this}); + }; + + + /* + * Post a form with ajax + * + * @param form form + * @param function callback Called when http result is received + * / + this.submitForm = function(form, callback, callName) { + this.addMethod('postform', callback); + this.urls['postform'] = form.action; + var args = []; + for (var i = 0; i < form.elements.length; i++) { + var name = form.elements[i].name.split("["); + for (var j = 0; j < name.length; j++) { + //Hmm problem with sequence of names... have to get that from the variable sequence... + } + args[] = form.elements[i].value; + } + + this['postform'].apply(this, args); + }; + */ +}).call(apf.rpc.prototype = new apf.Teleport()); + +apf.config.$inheritProperties["baseurl"] = 1; + +apf.aml.setElement("rpc", apf.rpc); + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * This element loads JavaScript into the application. + * + * #### Example + * + * ```xml + * + * ``` + * + * #### Example + * + * ```xml + * // + * ``` + * + * @class apf.script + * @inherits apf.AmlElement + * @define script + * @logic + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.4 + * + */ +/** + * @attribute {String} src the location of the script file. + * + * + */ +apf.script = function(){ + this.$init("script", apf.NODE_HIDDEN); +}; + +(function(){ + this.$propHandlers["src"] = function(value) { + if (!this.type) + this.type = this.getAttribute("type"); + + if (!this.type || this.type == "text/javascript") { + if (apf.isOpera) { + $setTimeout(function(){ + apf.window.loadCodeFile(apf.hostPath + + value); + }, 1000); + } + else { + apf.window.loadCodeFile(apf.getAbsolutePath(apf.hostPath, + value)); + } + } + else { + var _self = this; + apf.ajax(value, {callback: function(data, state, extra) { + if (state != apf.SUCCESS) { + return apf.console.warn("Could not load script " + value); + } + + _self.$execute(data); + }}); + } + } + + this.$execute = function(code, e) { + if (!this.type || this.type == "text/javascript") { + apf.jsexec(code); + } + else if (this.type.indexOf("livemarkup") > -1 + || this.type.indexOf("lm") > -1) { //@todo this is wrong, it should start in code mode + var func = apf.lm.compile(code, {event: true, parsecode: true, funcglobal: true, nostring: true}); + func(e || {}); + } + } + + this.addEventListener("DOMNodeInserted", function(e) { + if (e.currentTarget.nodeType == 3 || e.currentTarget.nodeType == 4) { + this.$execute(e.currentTarget.nodeValue, apf.isIE && window.event); + } + }); + + //@todo this should use text node insertion + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + var nodes = this.childNodes, s = []; + for (var i = 0, l = nodes.length; i < l; i++) { + s[s.length] = nodes[i].nodeValue; + } + + var code = s.join("\n"); + + this.$execute(code); + }); +}).call(apf.script.prototype = new apf.AmlElement()); + +apf.aml.setElement("script", apf.script); + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +//@todo: fix the stuff with all the uppercase variable and function names...wazzup? + +/** + * @constructor + * @private + */ +apf.scrollbar = function(struct, tagName) { + this.$init(tagName || "scrollbar", apf.NODE_VISIBLE, struct); +}; + +(function(){ + this.realtime = true; + this.visible = false; + this.overflow = "scroll"; + this.position = 0; + + this.$visible = true; + this.$scrollSizeValue = 0; + this.$stepValue = 0.03; + this.$bigStepValue = 0.1; + this.$timer = null; + this.$scrollSizeWait; + this.$slideMaxSize; + + this.$booleanProperties = ["showonscroll"]; + + this.addEventListener("focus", function(){ + this.$viewport.focus(); + }); + + this.$propHandlers["showonscroll"] = function(value) { + clearTimeout(this.$hideOnScrollTimer); + + if (value) { + this.$ext.style.display = "none"; + } + else { + this.$ext.style.display = "block"; + this.show(); //Trigger positioning event + } + }; + + this.$propHandlers["overflow"] = function(value) { + if (this.showonscroll) + return; + + if (value == "auto") { + this.$ext.style.display = "none"; + this.$resize(); + } + else if (value == "scroll") { + this.setProperty("visible", true); + } + } + + this.$propHandlers["for"] = function(value) { + if (value) { + var amlNode = typeof value == "string" ? self[value] : value; + if (!amlNode || !amlNode.$amlLoaded) { + var _self = this; + apf.queue.add("scrollbar" + this.$uniqueId, function(){ + if (!amlNode) { + amlNode = typeof value == "string" ? self[value] : value; + + if (!amlNode) { + throw new Error(apf.formatErrorString(0, _self, + "Attaching scrollbar to element", + "Could not find element to attach scrollbar to: " + value)); + } + } + _self.attach(amlNode); + }); + } + else + this.attach(amlNode); + } + } + + this.addEventListener("prop.visible", function(e) { + if (!this.$updating) { + this.$visible = e.value; + } + }); + + this.attach = function(viewport) { + if (viewport.nodeFunc) { + + if (viewport.hasFeature(apf.__VIRTUALVIEWPORT__)) + viewport = viewport.$viewport; + else + + viewport = new apf.ViewPortAml(viewport); + } + else if (viewport.style) + viewport = new apf.ViewPortHtml(viewport); + + this.$attach(viewport); + }; + + /** + * @todo detach + */ + this.$attach = function(viewport) { + if (!viewport) + return apf.console.warn("Scrollbar could not connect to viewport"); + + var _self = this; + + this.$viewport = viewport; + + if (this.$viewport.scrollbar != this) { + this.$viewport.setScrollbar(this, function(e) { + if (_self.$viewport != viewport) + return; + + _self.$update(); + + if (_self.showonscroll) { // && e.byUser) { + if (!_self.scrolling) + _self.$resize(); + + _self.scrolling = true; + + clearTimeout(_self.$hideOnScrollTimer); + if (_self.$hideOnScrollControl) + _self.$hideOnScrollControl.stop(); + + apf.setOpacity(_self.$ext, 1); + !_self.visible ? _self.show() : _self.$ext.style.display = "block"; + _self.$update(); + + _self.$hideOnScrollTimer = _self.animHideScrollbar(500, function(){ + _self.scrolling = false; + }); + } + }); + } + + this.$recalc(); + this.$update(); + + return this; + }; + + this.$resize = function(){ + if (!this.$viewport || !this.$viewport.isVisible()) + return; + + this.$recalc(); + this.$update(); + + if (!this.$viewport.virtual) + return; + + this.setScrollPosition(this.position, true); + } + + this.$recalc = function(){ + this.$viewheight = this.$viewport.getHeight(); + this.$scrollSizeheight = this.$viewheight; + this.$scrollSizeWait = 0;//(this.$host.len * COLS)/2; + this.$stepValue = (this.$viewheight / this.$scrollSizeheight) / 20; + this.$bigStepValue = this.$stepValue * 3; + this.$slideMaxSize = this.$caret.parentNode[this.$offsetSize] + - (this.$btnDown ? this.$btnDown[this.$offsetSize] : 0) + - (this.$btnUp ? this.$btnUp[this.$offsetSize] : 0); + } + + //@todo this function is called way too many times + this.$update = function(){ + // Commented this out because otherwise a tree expansion wouldn't + // show the scrollbar again + //if (this.animating || !this.$visible) + // return; + + if (this.showonscroll && !this.$ext.offsetHeight) + return; + + var viewport = this.$viewport; + if (!viewport || !viewport.isVisible()) + return; + + this.$updating = true; + + //Disable scrollbar + var vp = viewport.getHeight(); + var sz = viewport.getScrollHeight(); + + if (vp >= sz) { + if (this.overflow == "scroll") { + this.$caret.style.display = "none"; + this.disable(); + } + else if (this.visible) { + this.hide(); + + //this.$ext.style.display = "none"; + } + //if (this.id == "sbtest") console.log(vp + ":" + sz); + //oHtml.style.overflowY = "visible"; + } + //Enable scrollbar + else { + if (this.overflow == "scroll") { + this.$caret.style.display = "block"; + this.enable(); + } + else if (!this.visible) { + this.show(); + //this.$ext.style.display = "block"; + //this.$caret.style.display = "block"; + } + + if (!this.$slideMaxSize) + this.$recalc(); + if (!this.$slideMaxSize) + return; + + //oHtml.style.overflowY = "scroll"; + + //Set scroll size + this.$caret.style[this.$size] = (Math.max(5, (vp / sz + * this.$slideMaxSize)) - apf[this.$getDiff](this.$caret)) + "px"; + //if (this.$caret.offsetHeight - 4 == this.$slideMaxSize) + //this.$ext.style.display = "none"; + + this.position = viewport.getScrollTop() / (sz - vp); + + var bUpHeight = this.$btnUp ? this.$btnUp[this.$offsetSize] : 0; + this.$caret.style[this.$pos] = (bUpHeight + (apf[this.$getInner](this.$caret.parentNode) + - (bUpHeight * 2) - this.$caret[this.$offsetSize]) * this.position) + "px"; + } + + this.$updating = false; + } + + this.setScrollPosition = function(position, preventEvent) { + if (position == NaN) { + + return; + } + + if (position > 1) + position = 1; + if (position < 0) + position = 0; + + this.position = position; + + // Set the caret position + var bUpHeight = this.$btnUp ? this.$btnUp[this.$offsetSize] : 0; + this.$caret.style[this.$pos] = (bUpHeight + (apf[this.$getInner](this.$caret.parentNode) + - (bUpHeight * 2) - this.$caret[this.$offsetSize]) * this.position) + "px"; + + // Don't signal anything when animating or when not visible + if (this.animating || !this.$visible) + return; + + var vp = this.$viewport; + var to = (vp.getScrollHeight() - vp.getHeight()) * position; + + vp.setScrollTop(to, preventEvent); + } + + this.animShowScrollbar = function(timeout, cb) { + var _self = this; + return setTimeout(function(){ + _self.$ext.style.display = "block"; + + if (_self.$showOnScrollControl + && _self.$showOnScrollControl.state == apf.tween.RUNNING) + return; + + if (_self.$hideOnScrollControl) + _self.$hideOnScrollControl.stop(); + + _self.$resize(); + + apf.tween.single(_self.$ext, { + control: _self.$hideOnScrollControl = {}, + type: "fade", + from: 0, + to: 1, + onfinish: function(){ + cb && cb(); + } + }); + }, timeout) + } + + this.animHideScrollbar = function(timeout, cb) { + var _self = this; + return setTimeout(function(){ + if (_self.$hideOnScrollControl + && _self.$hideOnScrollControl.state == apf.tween.RUNNING) + return; + + if (_self.$showOnScrollControl) + _self.$showOnScrollControl.stop(); + apf.tween.single(_self.$ext, { + control: _self.$hideOnScrollControl = {}, + type: "fade", + from: 1, + to: 0, + steps: 20, + onfinish: function(){ + _self.$ext.style.display = "none"; + apf.setOpacity(_self.$ext, 1); + + cb && cb(); + } + }); + }, timeout) + } + + this.scrollUp = function (v) { + if (v > this.$caret[this.$offsetPos]) + return this.$ext.onmouseup(); + this.setScrollPosition(this.position + this.$bigStepValue); + + if (this.$slideFast) { + this.$slideFast.style[this.$size] = Math.max(1, this.$caret[this.$offsetPos] + - this.$btnUp[this.$offsetSize]) + "px"; + this.$slideFast.style[this.$pos] = this.$btnUp[this.$offsetSize] + "px"; + } + } + + this.scrollDown = function (v) { + if (v < this.$caret[this.$offsetPos] + this.$caret[this.$offsetSize]) + return this.$ext.onmouseup(); + this.setScrollPosition(this.position + this.$bigStepValue); + + if (this.$slideFast) { + this.$slideFast.style[this.$pos] = (this.$caret[this.$offsetPos] + this.$caret[this.$offsetSize]) + "px"; + this.$slideFast.style[this.$size] = Math.max(1, apf[this.$getInner](this.$caret.parentNode) - this.$slideFast[this.$offsetPos] + - this.$btnUp[this.$offsetSize]) + "px"; + } + } + + this.$draw = function(){ + //Build Skin + this.$getNewContext("main"); + this.$ext = this.$getExternal(); + //this.$ext.style.display = "none"; + + this.$caret = this.$getLayoutNode("main", "indicator", this.$ext); + this.$slideFast = this.$getLayoutNode("main", "slidefast", this.$ext); + this.$btnUp = this.$getLayoutNode("main", "btnup", this.$ext) + this.$btnDown = this.$getLayoutNode("main", "btndown", this.$ext); + + this.horizontal = apf.isTrue(this.$getOption("main", "horizontal")); + + this.$windowSize = this.horizontal ? "getWindowWidth" : "getWindowHeight"; + this.$offsetSize = this.horizontal ? "offsetWidth" : "offsetHeight"; + this.$size = this.horizontal ? "width" : "height"; + this.$offsetPos = this.horizontal ? "offsetLeft" : "offsetTop"; + this.$pos = this.horizontal ? "left" : "top"; + this.$scrollSize = this.horizontal ? "scrollWidth" : "scrollHeight"; + this.$scrollPos = this.horizontal ? "scrollLeft" : "scrollTop"; + this.$getDiff = this.horizontal ? "getWidthDiff" : "getHeightDiff"; + this.$getInner = this.horizontal ? "getHtmlInnerWidth" : "getHtmlInnerHeight"; + this.$eventDir = this.horizontal + ? (apf.isIE || apf.isWebkit ? "offsetX" : "layerX") + : (apf.isIE || apf.isWebkit ? "offsetY" : "layerY"); + this.$clientDir = this.horizontal ? "clientX" : "clientY"; + this.$posIndex = this.horizontal ? 0 : 1; + + this.$startPos = false; + + this.$caret.ondragstart = function(){ + return false + }; + + var _self = this; + if (this.$btnUp) { + this.$btnUp.onmousedown = function(e) { + if (_self.disabled) + return; + + if (!e) + e = event; + this.className = "btnup btnupdown"; + clearTimeout(_self.$timer); + + _self.setScrollPosition(_self.position - _self.$stepValue); + apf.stopPropagation(e); + + //apf.window.$mousedown(e); + + _self.$timer = $setTimeout(function(){ + _self.$timer = setInterval(function(){ + _self.setScrollPosition(_self.position - _self.$stepValue); + }, 20); + }, 300); + }; + + this.$btnUp.onmouseout = this.$btnUp.onmouseup = function(){ + if (_self.disabled) + return; + + this.className = "btnup"; + clearInterval(_self.$timer); + }; + } + + if (this.$btnDown) { + this.$btnDown.onmousedown = function(e) { + if (_self.disabled) + return; + + if (!e) + e = event; + this.className = "btndown btndowndown"; + clearTimeout(_self.$timer); + + _self.setScrollPosition(_self.position + _self.$stepValue) + apf.stopPropagation(e); + + //apf.window.$mousedown(e); + + _self.$timer = $setTimeout(function(){ + _self.$timer = setInterval(function(){ + _self.setScrollPosition(_self.position + _self.$stepValue) + }, 20); + }, 300); + }; + + this.$btnDown.onmouseout = this.$btnDown.onmouseup = function(){ + if (_self.disabled) + return; + + this.className = "btndown"; + clearInterval(_self.$timer); + }; + } + + this.$caret.onmousedown = function(e) { + if (_self.disabled) + return; + + if (!e) + e = event; + + var tgt = e.target || e.srcElement; + var pos = tgt != this + ? [tgt.offsetLeft, tgt.offsetTop] //Could be improved + : [0, 0]; + + var relDelta = e[_self.$eventDir] + pos[_self.$posIndex]; + _self.$startPos = relDelta + + (_self.$btnUp ? _self.$btnUp[_self.$offsetSize] : 0); + + if (this.setCapture) + this.setCapture(); + + _self.$setStyleClass(_self.$ext, _self.$baseCSSname + "Down"); + _self.dispatchEvent("mousedown", {}); + + _self.dragging = true; + + document.onmousemove = function(e) { + if (!e) + e = event; + //if(e.button != 1) return _self.onmouseup(); + if (_self.$startPos === false) + return false; + + var bUpHeight = _self.$btnUp ? _self.$btnUp[_self.$offsetSize] : 0; + var next = bUpHeight + (e[_self.$clientDir] - _self.$startPos + + (apf.isWebkit ? document.body : document.documentElement)[_self.$scrollPos] + - apf.getAbsolutePosition(_self.$caret.parentNode)[_self.horizontal ? 0 : 1]); // - 2 + var min = bUpHeight; + if (next < min) + next = min; + var max = (apf[_self.$getInner](_self.$caret.parentNode) + - bUpHeight - _self.$caret[_self.$offsetSize]); + if (next > max) + next = max; + //_self.$caret.style.top = next + "px" + + _self.setScrollPosition((next - min) / (max - min)); + }; + + document.onmouseup = function(){ + _self.$startPos = false; + if (!_self.realtime) + _self.setScrollPosition(_self.position); + + if (this.releaseCapture) + this.releaseCapture(); + + _self.$setStyleClass(_self.$ext, "", [_self.$baseCSSname + "Down"]); + _self.dispatchEvent("mouseup", {}); + + _self.dragging = false; + + document.onmouseup = + document.onmousemove = null; + }; + + apf.stopPropagation(e); + //apf.window.$mousedown(e); + + return false; + }; + + this.$ext.onmousedown = function(e) { + if (_self.disabled) + return; + if (!e) + e = event; + clearInterval(_self.$timer); + var offset; + if (e[_self.$eventDir] > _self.$caret[_self.$offsetPos] + _self.$caret[_self.$offsetSize]) { + _self.setScrollPosition(_self.position + _self.$bigStepValue); + + if (_self.$slideFast) { + _self.$slideFast.style.display = "block"; + _self.$slideFast.style[_self.$pos] = (_self.$caret[_self.$offsetPos] + + _self.$caret[_self.$offsetSize]) + "px"; + _self.$slideFast.style[_self.$size] = (apf[_self.$getInner](_self.$caret.parentNode) - _self.$slideFast[_self.$offsetPos] + - _self.$btnUp[_self.$offsetSize]) + "px"; + } + + offset = e[_self.$eventDir]; + _self.$timer = $setTimeout(function(){ + _self.$timer = setInterval(function(){ + _self.scrollDown(offset, null, null, true); + }, 20); + }, 300); + } + else if (e[_self.$eventDir] < _self.$caret[_self.$offsetPos]) { + _self.setScrollPosition(_self.position - _self.$bigStepValue); + + if (_self.$slideFast) { + _self.$slideFast.style.display = "block"; + _self.$slideFast.style[_self.$pos] = _self.$btnUp[_self.$offsetSize] + "px"; + _self.$slideFast.style[_self.$size] = (_self.$caret[_self.$offsetPos] - _self.$btnUp[_self.$offsetSize]) + "px"; + } + + offset = e[_self.$eventDir]; + _self.$timer = $setTimeout(function(){ + _self.$timer = setInterval(function(){ + _self.scrollUp(offset, null, null, true); + }, 20); + }, 300); + } + }; + + this.$ext.onmouseup = function(){ + if (_self.disabled) + return; + + clearInterval(_self.$timer); + if (!_self.realtime) + _self.setScrollPosition(_self.position); + if (_self.$slideFast) + _self.$slideFast.style.display = "none"; + }; + + this.$ext.onmouseover = function(e) { + _self.dispatchEvent("mouseover", {htmlEvent : e || event}); + }; + + this.$ext.onmouseout = function(e) { + _self.dispatchEvent("mouseout", {htmlEvent : e || event}); + }; + } + + this.$loadAml = function(){ + if (this.overflow == "scroll") + this.disable(); + else { + this.$caret.style.display = "block"; + this.enable(); + } + + this.addEventListener("resize", this.$resize); + this.$update(); + } +}).call(apf.scrollbar.prototype = new apf.Presentation()); +apf.aml.setElement("scrollbar", apf.scrollbar); + +apf.GuiElement.propHandlers["scrollbar"] = function(value) { + if (this.$sharedScrollbar == undefined) { + var values = value.split(" "); + var name = values[0]; + var top = values[1] || 0; + var right = values[2] || 0; + var bottom = values[3] || 0; + + var _self = this; + this.$sharedScrollbar = self[name] || false; + if (!this.$sharedScrollbar) + return; + + function hasOnScroll(){ + return sb && apf.isTrue(sb.getAttribute("showonscroll")); + } + + var oHtml = this.$container || this.$int || this.$ext, timer, sb; + var mouseMove; + apf.addListener(oHtml, "mousemove", mouseMove = function(e) { + if (!_self.$sharedScrollbar) + _self.$sharedScrollbar = self[name]; + + sb = _self.$sharedScrollbar; + + if (!sb.$addedMouseOut) { + apf.addListener(sb.$ext, "mouseout", function(e) { + if (!hasOnScroll()) + return; + + if (apf.findHost(e.fromElement) == sb && apf.findHost(e.toElement) != sb) { + clearTimeout(timer); + hideScrollbar(); + } + }); + sb.$addedMouseOut = true; + } + + if (!sb.$viewport || sb.$viewport.amlNode != _self) { + var pNode = (_self.$ext == oHtml ? _self.$ext.parentNode : _self.$ext); + pNode.appendChild(sb.$ext); + + if (apf.getStyle(pNode, "position") == "static") + pNode.style.position = "relative"; + + sb.setProperty("showonscroll", true); + sb.$ext.style.display = "block"; + sb.setAttribute("top", top); + sb.setAttribute("right", right); + sb.setAttribute("bottom", bottom); + sb.setAttribute("for", _self); + sb.$ext.style.display = "none"; + sb.dragging = false; + + if (sb.$hideOnScrollControl) + sb.$hideOnScrollControl.stop(); + } + + if (hasOnScroll() && e) { + clearTimeout(timer); + + var pos = apf.getAbsolutePosition(oHtml); + var rightPos = oHtml.offsetWidth - (e.clientX - pos[0]); + var show = rightPos < 25 && rightPos > right; + if (show && sb.$ext.style.display == "none" + || !show && sb.$ext.style.display == "block") { + if (show) + showScrollbar(); + else + hideScrollbar(); + } + else if (!show) + sb.showonscroll = true; + } + }); + + this.$sharedScrollbarMove = mouseMove; + + function showScrollbar(){ + sb.setProperty("showonscroll", false); + sb.$ext.style.display = "none"; + timer = sb.animShowScrollbar(200); + } + + function hideScrollbar(timeout) { + if (sb.scrolling) + return; + + if (!sb.dragging) + timer = sb.animHideScrollbar(timeout || 200, function(){ + sb.setProperty("showonscroll", true); + }); + else + apf.addListener(document, "mouseup", function(e) { + var tgt = apf.findHost(e.target); + if (tgt == sb) + return; + + if (tgt == _self) + mouseMove(e); + else + hideScrollbar(); + + apf.removeListener(document, "mouseup", arguments.callee); + }); + } + + apf.addListener(oHtml, "mouseout", function(e) { + if (!hasOnScroll()) + return; + + var el = apf.findHost(e.toElement || e.rangeParent); + if (el != sb && el != sbShared.$viewport.amlNode) { + clearTimeout(timer); + hideScrollbar(); + } + }); + } +}; + +apf.ViewPortAml = function(amlNode) { + this.amlNode = amlNode; + + var _self = this; + var update = function(){ + if (_self.scrollbar) + _self.scrollbar.$update(); + }; + + amlNode.addEventListener("resize", update); + if (amlNode.hasFeature(apf.__DATABINDING__)) { + amlNode.addEventListener("afterload", update); + amlNode.addEventListener("xmlupdate", update); + } + + amlNode.addEventListener("prop.value", update); + + if (amlNode.$isTreeArch) { + amlNode.addEventListener("collapse", update); + amlNode.addEventListener("expand", update); + } + + amlNode.addEventListener("mousescroll", function(e) { + _self.$mousescroll(e); + }); + + var htmlNode = _self.$getHtmlHost(); + apf.addListener(htmlNode, "scroll", function(){ + if (_self.scrollbar.animating || !_self.scrollbar.$visible) + return; + + _self.setScrollTop(this.scrollTop); + }); + + if ("HTML|BODY".indexOf(htmlNode.tagName) > -1) { + var lastHeight = htmlNode.scrollHeight; + setInterval(function(){ + if (lastHeight != htmlNode.scrollHeight) { + lastHeight = htmlNode.scrollHeight; + _self.scrollbar.$recalc(); + _self.scrollbar.$update(); + } + }, 100); + } +}; + +(function(){ + this.setScrollbar = function(scrollbar, onscroll) { + this.scrollbar = scrollbar; + + this.amlNode.addEventListener("scroll", onscroll); + } + + this.isVisible = function(){ + var htmlNode = this.$getHtmlHost(); + return htmlNode.offsetHeight || htmlNode.offsetWidth ? true : false; + } + + this.focus = function(){ + if (this.amlNode.focus && this.amlNode.$isWindowContainer !== true) + this.amlNode.focus(); + } + + this.getScrollTop = function(){ + var htmlNode = this.$getHtmlHost(); + return htmlNode.scrollTop; + } + + this.getScrollLeft = function(){ + var htmlNode = this.$getHtmlHost(); + return htmlNode.scrollLeft; + } + + this.getScrollHeight = function(){ + var htmlNode = this.$getHtmlHost(); + return (apf.isIE && htmlNode.lastChild + ? htmlNode.lastChild.offsetTop + + htmlNode.lastChild.offsetHeight + + apf.getBox(apf.getStyle(htmlNode, "padding"))[2] + + (parseInt(apf.getStyle(htmlNode, "marginBottom")) || 0) + : htmlNode.scrollHeight); + } + + this.getScrollWidth = function(){ + var htmlNode = this.$getHtmlHost(); + return (apf.isIE && htmlNode.lastChild + ? htmlNode.lastChild.offsetLeft + + htmlNode.lastChild.offsetWidth + + apf.getBox(apf.getStyle(htmlNode, "padding"))[1] + + (parseInt(apf.getStyle(htmlNode, "marginRight")) || 0) + : htmlNode.scrollWidth); + } + + this.getHeight = function(){ + var htmlNode = this.$getHtmlHost(); + return htmlNode.tagName == "HTML" || htmlNode.tagName == "BODY" + ? apf.getWindowHeight() + : apf.getHtmlInnerHeight(htmlNode); + } + + this.getWidth = function(){ + var htmlNode = this.$getHtmlHost(); + return htmlNode.tagName == "HTML" || htmlNode.tagName == "BODY" + ? apf.getWindowHeight() + : apf.getHtmlInnerWidth(htmlNode); + } + + this.setScrollTop = function(value, preventEvent, byUser) { + var htmlNode = this.$getHtmlHost(); + htmlNode.scrollTop = value; + + if (!preventEvent) { + this.amlNode.dispatchEvent("scroll", { + direction: "vertical", + byUser: byUser, + viewport: this, + scrollbar: this.scrollbar + }); + } + } + + this.setScrollLeft = function(value, preventEvent, byUser) { + var htmlNode = this.$getHtmlHost(); + htmlNode.scrollLeft = value; + + if (!preventEvent) { + this.amlNode.dispatchEvent("scroll", { + direction: "horizontal", + byUser: byUser, + viewport: this, + scrollbar: this.scrollbar + }); + } + } + + // *** Private *** // + + this.$getHtmlHost = function(){ + var htmlNode = this.amlNode.$int || this.amlNode.$container; + return (htmlNode.tagName == "BODY" || htmlNode.tagName == "HTML" + ? (apf.isSafari || apf.isChrome ? document.body : htmlNode.parentNode) + : htmlNode); + } + + this.$mousescroll = function(e) { + if (this.scrollbar.horizontal) + return; + + if (e.returnValue === false) + return; + + var oHtml = this.$getHtmlHost(); + + var sb = this.scrollbar; + var div = this.getScrollHeight() - this.getHeight(); + if (div) { + if (oHtml[sb.$scrollPos] == 0 && e.delta > 0) { + if (this.$lastScrollState === 0) + return; + setTimeout(function(){this.$lastScrollState = 0;}, 300); + } + else if (oHtml[sb.$scrollPos] == this.getScrollHeight() - oHtml[sb.$offsetSize] && e.delta < 0) { + if (this.$lastScrollState === 1) + return; + setTimeout(function(){this.$lastScrollState = 1;}, 300); + } + delete this.$lastScrollState; + + this.setScrollTop(this.getScrollTop() + + -1 * e.delta * Math.min(45, this.getHeight()/10), false, true); + + e.preventDefault(); + } + } +}).call(apf.ViewPortAml.prototype); + +apf.ViewPortHtml = function(htmlNode) { + // *** Private *** // + + this.$getHtmlHost = function(){ + return htmlNode; + } + + // *** Init *** // + + var _self = this; + + htmlNode = (htmlNode.tagName == "BODY" || htmlNode.tagName == "HTML" + ? (apf.isSafari || apf.isChrome ? document.body : htmlNode.parentNode) + : htmlNode); + + apf.addEventListener("mousescroll", function(e) { + if (htmlNode == e.target + || (htmlNode == document.documentElement && e.target == document.body)) + _self.$mousescroll(e); + }) + + apf.addListener(htmlNode, "scroll", function(){ + _self.setScrollTop(this.scrollTop); + }); + + if ("HTML|BODY".indexOf(htmlNode.tagName) > -1) { + var lastHeight = htmlNode.scrollHeight; + setInterval(function(){ + if (lastHeight != htmlNode.scrollHeight) { + lastHeight = htmlNode.scrollHeight; + _self.scrollbar.$recalc(); + _self.scrollbar.$update(); + } + }, 100); + } + + this.amlNode = new apf.Class().$init(); +} + +apf.ViewPortHtml.prototype = apf.ViewPortAml.prototype; + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +/** + * This element specifies the skin of an application. + * + * For Cloud9, the skin is provided for you, and thus, you generally won't need + * to provide a new skin for a piece of AML. + * + * #### Example + * + * ```xml + * + * ``` + * + * @class apf.skin + * @inherits apf.AmlElement + * @define skin + * @layout + * @allowchild style, presentation + * + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.4 + */ +/** + * @attribute {String} name Sets or gets the name of the skinset. + */ +/** + * @attribute {String} src Sets or gets the location of the skin definition. + */ +/** + * @attribute {String} media-path Sets or gets the basepath for the images of the skin. + */ +/** + * @attribute {String} icon-path Sets or gets the basepath for the icons used in the elements using this skinset. + */ +apf.skin = function(struct, tagName) { + this.$init(tagName || "skin", apf.NODE_HIDDEN, struct); +}; +apf.aml.setElement("skin", apf.skin); + +(function(){ + this.$parsePrio = "002"; + this.$includesRemaining = 0; + + this.$propHandlers["src"] = function(value) { + if (value.trim().charAt(0) == "<") { + apf.skins.Init(apf.getXml(value), this, this.$path); + return; + } + + this.$path = apf.getAbsolutePath(apf.hostPath, value) + getSkin.call(this, this.$path); + } + + this.$propHandlers["name"] = function(value) { + if (!this.src && !this.attributes.getNamedItem("src")) { + this.$path = apf.getAbsolutePath(apf.hostPath, value) + "/index.xml"; + getSkin.call(this, this.$path); + } + }; + + /** + * @private + */ + function checkForAmlNamespace(xmlNode) { + if (!xmlNode.ownerDocument.documentElement) + return false; + + var nodes = xmlNode.ownerDocument.documentElement.attributes; + for (var found = false, i=0; i]*>/, "") + .replace(/^[\r\n\s]*/, "") //.replace(/ /g, " ") + .replace(/xmlns\=\"[^"]*\"/g, ""); + + if (!xmlString) { + throw new Error(apf.formatErrorString(0, _self, + "Loading skin", + "Empty skin file. Maybe the file does not exist?", _self)); + } + + var xmlNode = apf.getXml(xmlString);//apf.getAmlDocFromString(xmlString); + + + + if (!xmlNode) { + throw new Error(apf.formatErrorString(0, _self, + "Loading skin", + "Could not parse skin. Maybe the file does not exist?", _self)); + } + + xmlNode.setAttribute("filename", extra.url); + + + { + + + finish.call(_self, xmlNode); + } + }, + async: true, + ignoreOffline: true + }); + } + + //@todo use mutation events to update + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + if (this.src || this.name) + return; + + apf.skins.Init(this.$aml || this); + + //@todo implied skin + /*if (this.parentNode && this.parentNode.parentNode) { + var name = "skin" + Math.round(Math.random() * 100000); + q.parentNode.setAttribute("skin", name); + apf.skins.skins[name] = {name: name, templates: {}}; + apf.skins.skins[name].templates[q.parentNode[apf.TAGNAME]] = q; + }*/ + }); +}).call(apf.skin.prototype = new apf.AmlElement()); + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/** + * An element containing information on how databound elements process data. + * + * The {@link term.smartbinding smartbinding} element specifies how data is transformed and rendered + * in databound elements. It also specifies how changes on the bound data are + * send to their original data source ({@link apf.actions actions}) and + * which {@link term.datanode data nodes} can be dragged and dropped ({@link apf.DragDrop dragdrop}). + * + * #### Remarks + * + * Each element has its own set of binding rules it uses to render the data + * elements. The same goes for it's actions. To give an example, a slider has + * one action called 'change'. This action is called when then value of the + * slider changes. A tree element has several actions - among others: 'add', + * 'remove', 'move', 'copy' and 'rename'. + * + * Smartbindings enable many other features in a Ajax.org Platform + * application. Actions done by the user can be undone by calling + * {@link apf.actiontracker.undo} of the element. The + * Remote Databinding element can send changes on data to other clients. + * + * This element is created especially for reuse. Multiple elements can reference + * a single smartbinding element by setting the value of the 'smartbinding' + * attribute to the ID of this smartbinding element. If an element is only used + * for a single other element it can be set as it's child. In fact, each of the + * children of the smartbinding element can exist outside the smartbinding + * element and referenced indepently. + * + * #### Example + * + * A simple example of a smartbinding transforming data into representation + * + * ```xml + * + * + * + * + * + * + * + * + * + * + * + * LCD Panel + * + * + * + * ``` + * + * #### Example + * + * This is an elaborate example showing how to create a filesystem tree with + * files and folders in a tree. The smartbinding element describes how the + * files and folders are transformed to tree elements and how actions within + * the tree are sent to the data source; in this case, WebDAV. + * is used. The drag and drop rules specify which elements can be dragged and + * where they can be dropped. + * + * ```xml + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * function filesort(value, args, xmlNode) { + * return (xmlNode.tagName == "folder" ? 0 : 1) + value; + * } + * + * function getIcon(xmlNode) { + * xmlNode.getAttribute('name').match(/\.([^\.]*)$/); + * + * var ext = RegExp.$1; + * return (SupportedIcons[ext.toUpperCase()] + * ? SupportedIcons[ext.toUpperCase()] + ".png" + * : "unknown.png"); + * } + * + * ``` + * + * #### Example + * + * This example shows a smartbinding element which references to its children as + * stand alone elements. + * + * ```xml + * + * ... + * + * + * ... + * + * + * ... + * + * + * + * + * + * + * + * ``` + * + * + * #### Example + * + * The shortest method to add binding rules to an element is as follows: + * + * ```xml + * + * ``` + * + * @see baseclass.databinding + * @see baseclass.databinding.attribute.smartbinding + * @see term.smartbinding + * @see term.binding + * @see term.action + * + * @define smartbinding + * @allowchild bindings, actions, ref, action, dragdrop, model + * + * + * @class apf.smartbinding + * @apfclass + * @inherits apf.AmlElement + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.8 + * + * @default_private + */ +apf.smartbinding = function(struct, tagName) { + this.$init(tagName || "smartbinding", apf.NODE_HIDDEN, struct); + + this.$bindNodes = {}; +}; + +(function(){ + this.$supportedProperties = ["bindings", "actions", "model"]; + this.$handlePropSet = function(prop, value, force) { + switch(prop) { + //@todo apf3 change this to use apf.setModel(); + case "model": + + if (typeof value == "string") + value = apf.nameserver.get("model", value); + this.model = apf.nameserver.register("model", this.name, value); + //this.modelBaseXpath = xpath; + + var amlNode; + for (var uniqueId in this.$bindNodes) { + amlNode = this.$bindNodes[uniqueId]; + this.model.unregister(amlNode); + this.model.register(amlNode, this.$modelXpath[amlNode.getHost + ? amlNode.getHost().$uniqueId + //this is a hack.. by making Models with links to other + //models possible, this should not be needed + : amlNode.$uniqueId] || this.modelBaseXpath); + //this.$bindNodes[uniqueId].load(this.model); + } + + break; + case "bindings": + if (this.$bindings) + this.remove(this.$bindings); + + this.$bindings = typeof value == "object" + ? value + : + + apf.nameserver.lookup("bindings", value); + + + this.add(this.$bindings); + + break; + case "actions": + if (this.$actions) + this.remove(this.$actions); + + this.$actions = typeof value == "object" + ? value + : + + apf.nameserver.lookup("actions", value); + + + this.add(this.$actions); + + break; + } + + this[prop] = value; + + + }; + + this.add = function(node) { + for (var uId in this.$bindNodes) + node.register(this.$bindNodes[uId]); + + this["$" + node.localName] = node; + }; + + this.remove = function(node) { + for (var uId in this.$bindNodes) + node.unregister(this.$bindNodes[uId]); + }; + + this.register = function(amlNode) { + this.$bindNodes[amlNode.$uniqueId] = amlNode; + + if (this.$bindings) + this.$bindings.register(amlNode); + if (this.$actions) + this.$actions.register(amlNode); + if (this.$model) + this.$model.register(amlNode); + }; + + this.unregister = function(amlNode) { + //unregister element + this.$bindNodes[amlNode.$uniqueId] = null; + delete this.$bindNodes[amlNode.$uniqueId]; + + if (this.$bindings) + this.$bindings.unregister(amlNode); + if (this.$actions) + this.$actions.unregister(amlNode); + if (this.$model) + this.$model.unregister(amlNode); + }; + + /** + * Loads XML data in the model of this smartbinding element. + * + * @param {Mixed} xmlNode the {@link term.datanode data node} loaded into + * the model of this smartbinding element. This can be an XMLElement, a + * string or null. + * @private + */ + this.load = function(xmlNode) { + //@todo fix this + new apf.model().register(this).load(xmlNode); + }; + + this.clear = function(state) { + //for all elements do clear(state); + }; + + /* + * @private + * + * @attribute {String} bindings the id of the bindings element that contains + * the {@link term.binding binding rules} for all elements connected to + * this smartbinding element + * + * #### Example + * + * ```xml + * + * ``` + * @see element.bindings + * @see term.binding + * @see term.smartbinding + * + * @attribute {String} actions the id of the actions element that provides + * the {@link term.action action rules} for all elements connected to + * this smartbinding element + * + * #### Example + * + * ```xml + * + * ``` + * @see apf.actions + * @see term.action + * @see term.smartbinding + * + * @attribute {String} dragdrop the id of the dragdrop element that provides + * the drag and drop rules for all elements connected to this smartbinding + * element + * + * #### Example + * + * ```xml + * + * ``` + * @see apf.DragDrop + * @see term.smartbinding + * + * @attribute {String} model the id of the model element that provides + * the data for all elements connected to this smartbinding element. + * + * #### Example + * + * ```xml + * + * ``` + * @see element.model + * @see term.smartbinding + * + * @define bindings element containing all the binding rules for the data + * bound elements referencing this element. + * + * #### Example + * + * ```xml + * + * + * + * + * + * + * + * ``` + * @see apf.smartbinding + * @allowchild {bindings} + * + * + */ + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + if (this.parentNode.hasFeature(apf.__DATABINDING__)) + this.register(this.parentNode); + + + }); +}).call(apf.smartbinding.prototype = new apf.AmlElement()); + +apf.aml.setElement("smartbinding", apf.smartbinding); + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * Element + * + * @constructor + * + * @define source + * + * + * @author Mike de Boer (mike AT javeline DOT com) + * @version %I%, %G% + * @since 3.0 + */ +apf.source = function(struct, tagName) { + this.$init(tagName || "source", apf.NODE_HIDDEN, struct); +}; + +(function(){ + this.$supportedProperties.push("src", "type"); + + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + if (this.parentNode.$addSource) + this.parentNode.$addSource(this); + }); +}).call(apf.source.prototype = new apf.AmlElement()); + +apf.aml.setElement("source", apf.source); + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +/** + * This element is used to choose a number via plus/minus buttons. + * + * When the plus button is clicked/held longer, the number increments faster. The same + * situation occurs for the minus button. It's also possible to increment and decrement + * value by moving mouse cursor up or down with clicked input. + * + * Max and min attributes define the range of allowed values. + * + * #### Example: Setting Maximum and Minimum Ranges + * + * ```xml, demo + * + * + * + * + * + * ``` + * + * #### Example: Loading Data + * + * ```xml, demo + * + * + * + * + * + * + * + * + * ``` + * + * #### Example: Connecting to a Textbox + * + * + * ```xml, demo + * + * + * + * + * + * + * + * + * + * + * ``` + * + * @class apf.spinner + * @define spinner + * @form + * @version %I%, %G% + * + * @inherits apf.StandardBinding + * @inherits apf.DataAction + * @inheritsElsewhere apf.XForms + * + */ +/** + * @attribute {Number} [max=64000] Sets or gets the maximum allowed value + */ +/** + * @attribute {Number} [min=-64000] Sets or gets the minimal allowed value + */ +/** + * @attribute {Number} value Sets or gets the actual value displayed in component + * + */ +/** + * @binding value Determines the way the value for the element is retrieved + * from the bound data. + */ +apf.spinner = function(struct, tagName) { + this.$init(tagName || "spinner", apf.NODE_VISIBLE, struct); + + this.max = 64000; + this.min = -64000; + this.focused = false; + this.value = 0; + + this.realtime = false; +}; + +(function() { + this.implement( + + apf.DataAction + + + ); + + this.$supportedProperties.push("width", "value", "max", "min", "caption", "realtime"); + + this.$booleanProperties["realtime"] = true; + + this.$propHandlers["value"] = function(value) { + value = parseInt(value) || 0; + + this.value = this.oInput.value = (value > this.max + ? this.max + : (value < this.min + ? this.min + : value)); + }; + + this.$propHandlers["min"] = function(value) { + if (!(value = parseInt(value))) return; + this.min = value; + if (value > this.value) + this.change(value); + }; + + this.$propHandlers["max"] = function(value) { + if (!(value = parseInt(value))) return; + this.max = value; + + if (value < this.value) + this.change(value); + }; + + /* ******************************************************************** + PUBLIC METHODS + *********************************************************************/ + + + + /** + * Sets the value of this element. This should be one of the values + * specified in the `values` attribute. + * @param {String} value The new value of this element + */ + this.setValue = function(value) { + this.setProperty("value", value, false, true); + }; + + /** + * Returns the current value of this element. + * @return {String} The current element value + */ + this.getValue = function() { + return this.value; + }; + + /** + * Increments the spinner by one. + */ + this.increment = function() { + this.change(parseInt(this.oInput.value) + 1); + }; + + /** + * Decrements the spinner by one. + */ + this.decrement = function() { + this.change(parseInt(this.oInput.value) - 1); + }; + + + + this.$enable = function() { + this.oInput.disabled = false; + this.$setStyleClass(this.oInput, "", ["inputDisabled"]); + }; + + this.$disable = function() { + this.oInput.disabled = true; + this.$setStyleClass(this.oInput, "inputDisabled"); + }; + + this.$focus = function(e) { + if (!this.$ext || this.focused) //this.disabled || + return; + + + + this.focused = true; + this.$setStyleClass(this.$ext, this.$baseCSSname + "Focus"); + + if (this.oLeft) + this.$setStyleClass(this.oLeft, "leftFocus"); + }; + + this.$blur = function(e) { + if (!this.$ext && !this.focused) + return; + + this.$setStyleClass(this.$ext, "", [this.$baseCSSname + "Focus"]); + + if (this.oLeft) + this.$setStyleClass(this.oLeft, "" ["leftFocus"]); + + this.setValue(this.oInput.value); + + this.focused = false; + }; + + /* *********************** + Keyboard Support + ************************/ + + this.addEventListener("keydown", function(e) { + var key = e.keyCode, + + keyAccess = (key < 8 || (key > 9 && key < 37 && key !== 12) + || (key > 40 && key < 46) || (key > 46 && key < 48) + || (key > 57 && key < 96) || (key > 105 && key < 109 && key !== 107) + || (key > 109 && key !== 189)); + + if (keyAccess) + return false; + + switch(key) { + case 38://Arrow up + this.increment(); + break; + case 40://Arrow down + this.decrement(); + break; + } + }, true); + + this.addEventListener("keyup", function(e) { + //this.setValue(this.oInput.value); + }, true); + + + this.increment = function() { + this.change(parseInt(this.oInput.value) + 1); + }; + + this.decrement = function() { + this.change(parseInt(this.oInput.value) - 1); + }; + + /** + * @event click Fires when the user presses a mousebutton while over this element and then lets the mousebutton go. + */ + /** + * @event mouseup Fires when the user lets go of a mousebutton while over this element. + */ + /** + * @event mousedown Fires when the user presses a mousebutton while over this element. + */ + this.$draw = function() { + var _self = this; + + //Build Main Skin + this.$ext = this.$getExternal(null, null, function(oExt) { + oExt.setAttribute("onmousedown", + 'if (!this.host.disabled) \ + this.host.dispatchEvent("mousedown", {htmlEvent : event});'); + oExt.setAttribute("onmouseup", + 'if (!this.host.disabled) \ + this.host.dispatchEvent("mouseup", {htmlEvent : event});'); + oExt.setAttribute("onclick", + 'if (!this.host.disabled) \ + this.host.dispatchEvent("click", {htmlEvent : event});'); + }); + + this.$int = this.$getLayoutNode("main", "container", this.$ext); + this.oInput = this.$getLayoutNode("main", "input", this.$ext); + this.$buttonPlus = this.$getLayoutNode("main", "buttonplus", this.$ext); + this.$buttonMinus = this.$getLayoutNode("main", "buttonminus", this.$ext); + this.oLeft = this.$getLayoutNode("main", "left", this.$ext); + + + + var timer, + doc = (!document.compatMode || document.compatMode == 'CSS1Compat') + ? document.html : document.body, + z = 0; + + /* Setting start value */ + this.oInput.value = this.value; + + this.oInput.onmousedown = function(e) { + if (_self.disabled) + return; + + e = e || window.event; + + clearTimeout(timer); + + var newval, + value = parseInt(this.value) || 0, + step = 0, + cy = e.clientY, + ot = _self.$int.offsetTop, ol = _self.$int.offsetLeft, + ow = _self.$int.offsetWidth, oh = _self.$int.offsetHeight, + func = function() { + clearTimeout(timer); + timer = $setTimeout(func, 10); + if (!step) + return; + + newval = value + step; + if (newval <= _self.max && newval >= _self.min) { + value += step; + value = Math.round(value); + _self.oInput.value = value; + + if (_self.realtime) + _self.change(value); + } + else { + _self.oInput.value = step < 0 + ? _self.min + : _self.max; + } + }; + func(); + + function calcStep(e) { + e = e || window.event; + var x = e.pageX || e.clientX + (doc ? doc.scrollLeft : 0), + y = e.pageY || e.clientY + (doc ? doc.scrollTop : 0), + nrOfPixels = cy - y; + + if ((y > ot && x > ol) && (y < ot + oh && x < ol + ow)) { + step = 0; + return; + } + + step = Math.pow(Math.min(200, Math.abs(nrOfPixels)) / 10, 2) / 10; + if (nrOfPixels < 0) + step = -1 * step; + } + + document.onmousemove = calcStep; + + document.onmouseup = function(e) { + clearTimeout(timer); + + var value = parseInt(_self.oInput.value); + + if (value != _self.value) + _self.change(value); + document.onmousemove = document.onmouseup = null; + }; + }; + + /* Fix for mousedown for IE */ + var buttonDown = false; + this.$buttonPlus.onmousedown = function(e) { + if (_self.disabled) + return; + + e = e || window.event; + buttonDown = true; + + var value = (parseInt(_self.oInput.value) || 0) + 1, + func = function() { + clearTimeout(timer); + timer = $setTimeout(func, 50); + z++; + value += Math.pow(Math.min(200, z) / 10, 2) / 10; + value = Math.round(value); + + _self.oInput.value = value <= _self.max + ? value + : _self.max; + + if (_self.realtime) + _self.change(value <= _self.max ? value : _self.max); + }; + + apf.setStyleClass(this, "plusDown", ["plusHover"]); + + func(); + }; + + this.$buttonMinus.onmousedown = function(e) { + if (_self.disabled) + return; + + e = e || window.event; + buttonDown = true; + + var value = (parseInt(_self.oInput.value) || 0) - 1, + func = function() { + clearTimeout(timer); + timer = $setTimeout(func, 50); + z++; + value -= Math.pow(Math.min(200, z) / 10, 2) / 10; + value = Math.round(value); + + _self.oInput.value = value >= _self.min + ? value + : _self.min; + + if (_self.realtime) + _self.change(value >= _self.min ? value : _self.min); + }; + + apf.setStyleClass(this, "minusDown", ["minusHover"]); + + func(); + }; + + this.$buttonMinus.onmouseout = function(e) { + if (_self.disabled) + return; + + clearTimeout(timer); + z = 0; + + var value = parseInt(_self.oInput.value); + + if (value != _self.value) + _self.change(value); + + apf.setStyleClass(this, "", ["minusHover"]); + + if (!_self.focused) + _self.$blur(e); + }; + + this.$buttonPlus.onmouseout = function(e) { + if (_self.disabled) + return; + + clearTimeout(timer); + z = 0; + + var value = parseInt(_self.oInput.value); + + if (value != _self.value) + _self.change(value); + + apf.setStyleClass(this, "", ["plusHover"]); + + if (!_self.focused) + _self.$blur(e); + }; + + this.$buttonMinus.onmouseover = function(e) { + if (_self.disabled) + return; + + apf.setStyleClass(this, "minusHover"); + }; + + this.$buttonPlus.onmouseover = function(e) { + if (_self.disabled) + return; + + apf.setStyleClass(this, "plusHover"); + }; + + this.$buttonPlus.onmouseup = function(e) { + if (_self.disabled) + return; + + e = e || event; + //e.cancelBubble = true; + apf.cancelBubble(e, this); + + apf.setStyleClass(this, "plusHover", ["plusDown"]); + + clearTimeout(timer); + z = 0; + + var value = parseInt(_self.oInput.value); + + if (!buttonDown) { + value++; + _self.oInput.value = value; + } + else { + buttonDown = false; + } + + if (value != _self.value) + _self.change(value); + }; + + this.$buttonMinus.onmouseup = function(e) { + if (_self.disabled) + return; + + e = e || event; + //e.cancelBubble = true; + apf.cancelBubble(e, this); + + apf.setStyleClass(this, "minusHover", ["minusDown"]); + + clearTimeout(timer); + z = 0; + + var value = parseInt(_self.oInput.value); + + if (!buttonDown) { + value--; + _self.oInput.value = value; + } + else { + buttonDown = false; + } + + + if (value != _self.value) + _self.change(value); + }; + + this.oInput.onselectstart = function(e) { + e = e || event; + e.cancelBubble = true; + }; + + this.oInput.host = this; + }; + + this.$destroy = function() { + this.oInput.onkeypress = + this.oInput.onmousedown = + this.oInput.onkeydown = + this.oInput.onkeyup = + this.oInput.onselectstart = + this.$buttonPlus.onmouseover = + this.$buttonPlus.onmouseout = + this.$buttonPlus.onmousedown = + this.$buttonPlus.onmouseup = + this.$buttonMinus.onmouseover = + this.$buttonMinus.onmouseout = + this.$buttonMinus.onmousedown = + this.$buttonMinus.onmouseup = null; + }; + + + + +}).call(apf.spinner.prototype = new apf.StandardBinding()); + + +apf.aml.setElement("spinner", apf.spinner); + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +/** + * + * A container that stacks two children vertically. + * + * Programatically, this is identical to a regular [[vbox]], except that it can + * only accept two children, and uses absolute positioning. Because of this, there + * is more work required to construct AML that matches a regular ``; however, + * the performance improvements in using a `` are massive. + * + * @class apf.vsplitbox + * @define vsplitbox + * @layout + * + * @inheritDoc apf.hsplitbox + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 3.0 + * @see element.hsplitbox + */ +/** + * + * A container that stacks two children horizontally. + * + * Programatically, this is identical to a regular [[apf.hbox]], except that it can + * only accept two children, and uses absolute positioning. Because of this, there + * is more work required to construct AML that matches a regular ``; however, + * the performance improvements in using a `` are massive. + * + * @class apf.hsplitbox + * @define hsplitbox + * @layout + * @inherits apf.GuiElement + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 3.0\ + * @see element.vsplitbox + */ +apf.hsplitbox = function(struct, tagName) { + this.$init(tagName || "hsplitbox", apf.NODE_VISIBLE, struct); +}; +apf.vsplitbox = function(struct, tagName) { + this.$init(tagName || "vsplitbox", apf.NODE_VISIBLE, struct); +}; + +(function(){ + this.minwidth = 0; + this.minheight = 0; + + this.padding = 0; + this.edge = 0; + this.$edge = [0,0,0,0]; + + // *** Properties and Attributes *** // + + this.$focussable = false; + this.$useLateDom = true; + this.$box = true; + this.$layout = true; + + /** + * @attribute {String} [padding="2"] Sets or gets the space between each element. + */ + /** + * @attribute {String} [edge="5 5 5 5"] Sets or gets the space between the container and the elements, space seperated in pixels for each side. Similar to CSS in the sequence of `top right bottom left`. + */ + this.$booleanProperties["splitter"] = true; + this.$supportedProperties.push("padding", "edge", "splitter"); + + this.$propHandlers["padding"] = function(value) { + this.padding = parseInt(value); + + if (!this.$amlLoaded) + return; + + if (this.$handle) + this.$handle.$ext.style[this.$vbox ? "height" : "width"] = value + "px"; + + var firstChild = this.getFirstChild(); + var lastChild = this.getSecondChild(); + + if (this.$vbox) { + //Two flex children + if (this.flexChild2) { + if (firstChild.height) { + //String(firstChild.height).indexOf("%") == -1 + lastChild.$ext.style.marginTop = firstChild.visible + ? (value + + apf.getHeightDiff(firstChild.$ext)) + "px" + : 0; + } + else { + firstChild.$ext.style.marginBottom = lastChild.visible + ? (value + + apf.getHeightDiff(lastChild.$ext)) + "px" + : 0; + } + } + else if (this.fixedChild && this.fixedChild.visible) { + //One flex child (first) + if (this.flexChild1 == firstChild) { + if (this.fixedChild.visible) { + this.flexChild1.$ext.style.bottom = + (parseInt(this.fixedChild.height) + value + this.$edge[2]) + "px"; + } + } + + //One flex child (last) + else if (lastChild && this.flexChild1 == lastChild) { + this.flexChild1.$ext.style.top = + (parseInt(this.fixedChild.height) + value + this.$edge[2]) + "px"; + } + } + } + else { + //Two flex children + if (this.flexChild2) { + if (firstChild.width) { + lastChild.$ext.style.marginLeft = + (value + + apf.getWidthDiff(firstChild.$ext) + + apf.getMargin(firstChild.$ext)[0]) + "px"; + } + else { + firstChild.$ext.style.marginRight = + (value + (lastChild + ? apf.getWidthDiff(lastChild.$ext) + + apf.getMargin(lastChild.$ext)[0] + : 0)) + "px"; + } + } + else if (this.fixedChild && this.fixedChild.visible) { + //One flex child (first) + if (this.flexChild1 == firstChild) { + this.flexChild1.$ext.style.right = + (parseInt(this.fixedChild.width) + value + this.$edge[1]) + "px"; + } + + //One flex child (last) + else if (lastChild && this.flexChild1 == lastChild) { + this.flexChild1.$ext.style.left = + (parseInt(this.fixedChild.width) + value + this.$edge[3]) + "px"; + } + } + } + } + + this.$propHandlers["splitter"] = function(value) { + if (value) { + if (this.$handle) + this.$handle.show(); + else { + this.$handle = this.insertBefore( + this.ownerDocument.createElementNS(apf.ns.aml, "splitter"), + this.lastChild); + } + } + else { + this.$handle && this.$handle.hide();//destroy(true, true); + } + } + + this.$propHandlers["edge"] = function(value, setSize) { + this.$edge = apf.getBox(value); + + if (!this.$amlLoaded) + return; + + var fNode = this.getFirstVisibleChild(); + if (!fNode) { + this.hide(); + return false; + } + fNode.$ext.style.left = (this.$edge[3] + fNode.$margin[3]) + "px"; + fNode.$ext.style.top = (this.$edge[0] + fNode.$margin[0]) + "px"; + if (this.$vbox) + fNode.$ext.style.right = (this.$edge[1] + fNode.$margin[1]) + "px"; + else + fNode.$ext.style.bottom = (this.$edge[2] + fNode.$margin[2]) + "px"; + + var lNode = this.getSecondVisibleChild(); + if (lNode && lNode.visible && lNode.$ext) { + lNode.$ext.style.right = (this.$edge[1] + lNode.$margin[1]) + "px"; + lNode.$ext.style.bottom = (this.$edge[2] + lNode.$margin[2]) + "px"; + if (this.$vbox) { + var isPercentage; + + lNode.$ext.style.left = (this.$edge[3] + lNode.$margin[3]) + "px"; + if (fNode.height || fNode.height === 0) { + isPercentage = String(fNode.height).indexOf("%") > -1; + lNode.$ext.style.top = isPercentage + ? fNode.height + : ((parseInt(fNode.height) + this.padding + + this.$edge[0] + fNode.$margin[0]) + "px"); + if (isPercentage) { + fNode.$ext.style.height = ""; + fNode.$ext.style.bottom = (100 - parseFloat(fNode.height)) + "%"; + } + + if (this.$handle) { + this.$handle.$ext.style.top = isPercentage + ? fNode.height + : ((parseInt(fNode.height) + this.$edge[0]) + "px"); +// this.$handle.$ext.style.marginTop = isPercentage +// ? this.padding + "px" +// : "0"; + } + } + else { + isPercentage = String(lNode.height).indexOf("%") > -1; + lNode.$ext.style.top = ""; + fNode.$ext.style.bottom = isPercentage + ? lNode.height + : ((parseInt(lNode.height) + this.padding + + this.$edge[2] + lNode.$margin[2]) + "px"); + if (isPercentage) { + lNode.$ext.style.height = ""; + lNode.$ext.style.top = (100 - parseFloat(lNode.height)) + "%"; + } + + if (this.$handle) { + this.$handle.$ext.style.bottom = isPercentage + ? lNode.height + : ((parseInt(lNode.height) + this.$edge[0]) + "px"); +// this.$handle.$ext.style.marginBottom = isPercentage +// ? this.padding + "px" +// : "0"; + } + } + + if (this.$handle) { + this.$handle.$ext.style.left = this.$edge[3] + "px"; + this.$handle.$ext.style.right = this.$edge[1] + "px"; + } + } + else { + lNode.$ext.style.top = this.$edge[0] + "px"; + + if (fNode.width || fNode.width === 0) { + var isPercentage = String(fNode.width).indexOf("%") > -1; + lNode.$ext.style.left = isPercentage + ? fNode.width + : ((parseInt(fNode.width) + this.padding + + this.$edge[3] + fNode.$margin[3]) + "px"); + if (isPercentage) { + fNode.$ext.style.width = ""; + fNode.$ext.style.right = (100 - parseFloat(fNode.width)) + "%"; + } + + if (this.$handle) { + this.$handle.$ext.style.left = isPercentage + ? fNode.width + : ((parseInt(fNode.width) + this.$edge[3]) + "px"); +// this.$handle.$ext.style.marginLeft = isPercentage +// ? this.padding + "px" +// : "0"; + } + } + else { + var isPercentage = String(lNode.width).indexOf("%") > -1; + lNode.$ext.style.left = ""; + fNode.$ext.style.right = isPercentage + ? lNode.width + : ((parseInt(lNode.width) + this.padding + + this.$edge[1] + lNode.$margin[1]) + "px"); + if (isPercentage) { + lNode.$ext.style.width = ""; + lNode.$ext.style.left = (100 - parseFloat(lNode.width)) + "%"; + } + + if (this.$handle) { + this.$handle.$ext.style.right = isPercentage + ? lNode.width + : ((parseInt(lNode.width) + this.$edge[3]) + "px"); +// this.$handle.$ext.style.marginRight = isPercentage +// ? this.padding + "px" +// : "0"; + } + } + + if (this.$handle) { + this.$handle.$ext.style.top = this.$edge[0] + "px"; + this.$handle.$ext.style.bottom = this.$edge[2] + "px"; + } + } + + if (this.$handle) + this.$handle.$ext.style.position = "absolute"; + } + else { + if (!this.$vbox) { + fNode.$ext.style.right = (this.$edge[1] + fNode.$margin[1]) + "px"; + fNode.$ext.style.width = ""; + } + else { + fNode.$ext.style.bottom = (this.$edge[2] + fNode.$margin[2]) + "px"; + fNode.$ext.style.height = ""; + } + + if (this.$handle) + this.$handle.hide(); + } + + if (setSize === true) { + var size = this.$vbox ? "height" : "width"; + fNode.$propHandlers[size].call(fNode, fNode[size]); + } + }; + + this.getFirstChild = function(startNode) { + var node = startNode || this.firstChild; + while (node && node.$splitter) { + node = node.nextSibling; + } + return node || false; + } + this.getSecondChild = function(){ + var node = this.getFirstChild(); + if (!node) + return false; + return node.nextSibling && this.getFirstChild(node.nextSibling); + } + + this.getFirstVisibleChild = function(startNode) { + var node = startNode || this.firstChild; + while (node && (!node.visible || node.$splitter)) { + node = node.nextSibling; + } + if (node && node.visible) + return node; + return false; + } + + this.getSecondVisibleChild = function(){ + var node = this.getFirstVisibleChild(); + if (!node) + return false; + return node.nextSibling && this.getFirstVisibleChild(node.nextSibling); + } + + function visibleHandler(e) { + if (this.parentNode.$handle) { + if (!e.value || this.parentNode.childNodes.length < 3) + this.parentNode.$handle.hide(); + else + this.parentNode.$handle.show(); + } + + if (e.value && !this.parentNode.visible) + this.parentNode.show(); + + this.parentNode.$propHandlers.edge + .call(this.parentNode, this.parentNode.edge, true); + + // apf.layout.forceResize(this.parentNode.$int); + + //Change margin + this.parentNode.$propHandlers.padding + .call(this.parentNode, this.parentNode.padding) + } + + var handlers = { + "width" : function(value, isLast) { + //@todo this should check the largest and only allow that one + //if (this.parentNode.$vbox && this.parentNode.align == "stretch") + //return; + + //@todo change fixedChild flexChild1 and flexChild2 based on this + + this.$ext.style.width = !apf.isNot(value) + ? (parseFloat(value) == value + ? (value - apf.getWidthDiff(this.$ext)) + "px" + : value) + : ""; + + //This can be optimized + if (this.$amlLoaded && isLast !== false) + this.parentNode.$propHandlers["edge"].call(this.parentNode, + this.parentNode.edge); + }, + + "height" : function(value, isLast) { + //@todo this should check the largest and only allow that one + //if (!this.parentNode.$vbox && this.parentNode.align == "stretch") + //return; + + //@todo change fixedChild flexChild1 and flexChild2 based on this + + this.$ext.style.height = !apf.isNot(value) + ? (parseFloat(value) == value + ? (value - apf.getHeightDiff(this.$ext)) + "px" + : value) + : ""; + + //This can be optimized + if (this.$amlLoaded && isLast !== false) + this.parentNode.$propHandlers["edge"].call(this.parentNode, + this.parentNode.edge); + }, + + "margin" : function(value, isLast) { + this.$margin = apf.getBox(value); + + //This can be optimized + if (this.$amlLoaded && isLast !== false) + this.parentNode.$propHandlers["edge"].call(this.parentNode, this.parentNode.edge); + } + } + + this.register = function(amlNode, insert) { + if (amlNode.$splitter || amlNode.nodeFunc != apf.NODE_VISIBLE) + return; + + amlNode.$margin = [0, 0, 0, 0]; + + amlNode.$propHandlers["left"] = + amlNode.$propHandlers["top"] = + amlNode.$propHandlers["right"] = + amlNode.$propHandlers["bottom"] = apf.K; + + for (var prop in handlers) { + amlNode.$propHandlers[prop] = handlers[prop]; + } + + if (this.flexChild1 && this.flexChild1 == amlNode){ } + else if (this.$vbox) { + if (!amlNode.height || String(amlNode.height).indexOf("%") > -1) + this[!this.flexChild1 ? "flexChild1" : "flexChild2"] = amlNode; + else + this.fixedChild = amlNode; + } + else { + if (!amlNode.width || String(amlNode.width).indexOf("%") > -1) + this[!this.flexChild1 ? "flexChild1" : "flexChild2"] = amlNode; + else + this.fixedChild = amlNode; + } + + amlNode.addEventListener("prop.visible", visibleHandler); + amlNode.$ext.style.position = "absolute"; + amlNode.$ext.style.margin = ""; + + if (amlNode.height) + handlers.height.call(amlNode, amlNode.height, false); + if (amlNode.width) + handlers.width.call(amlNode, amlNode.width, false); + if (amlNode.margin) + handlers.margin.call(amlNode, amlNode.margin, false); + + var isLast = this.lastChild.$amlLoaded || this.lastChild == amlNode; + if (isLast) { + this.$propHandlers["padding"].call(this, this.padding); + this.$propHandlers["edge"].call(this, this.edge, + !amlNode[this.$vbox ? "height" : "width"]); + } + + if (this.$handle && this.childNodes.length > 2) + this.$handle.show(); + } + + this.unregister = function(amlNode) { + if (amlNode.$splitter || amlNode.nodeFunc != apf.NODE_VISIBLE) + return; + + delete amlNode.$margin; + + amlNode.$propHandlers["left"] = + amlNode.$propHandlers["top"] = + amlNode.$propHandlers["right"] = + amlNode.$propHandlers["bottom"] = null; + + for (var prop in handlers) { + delete amlNode.$propHandlers[prop]; + } + + if (this.fixedChild == amlNode) + delete this.fixedChild; + else if (this.flexChild1 == amlNode) + delete this.flexChild1; + else if (this.flexChild2 == amlNode) + delete this.flexChild2; + + //Clear css properties and set layout + amlNode.removeEventListener("prop.visible", visibleHandler); + amlNode.$ext.style.display = amlNode.visible ? "block" : "none"; + + if (amlNode.width) + amlNode.$ext.style.width = ""; + if (amlNode.height) + amlNode.$ext.style.height = ""; + amlNode.$ext.style.position = + amlNode.$ext.style.margin = + amlNode.$ext.style.left = + amlNode.$ext.style.top = + amlNode.$ext.style.right = + amlNode.$ext.style.bottom = ""; + + if (this.$handle) + this.$handle.hide(); + } + + // *** DOM Hooks *** // + + this.addEventListener("DOMNodeRemoved", function(e) { + if (e.$doOnlyAdmin || e.currentTarget == this) + return; + + if (e.relatedNode == this) { + this.unregister(e.currentTarget); + //e.currentTarget.$setLayout(); + } + }); + + this.addEventListener("DOMNodeInserted", function(e) { + if (e.currentTarget == this) { + if (this.visible) + this.$ext.style.display = apf.CSSPREFIX2 + "-box"; //Webkit issue + return; + } + + if (e.currentTarget.nodeType != 1 + || e.currentTarget.nodeFunc != apf.NODE_VISIBLE) + return; + +// if (this.$handle) { +// var _self = this; +// setTimeout(function(){ +// if (_self.$handle.nextSibling != _self.lastChild) +// _self.insertBefore(_self.$handle, _self.lastChild); +// }); +// } + + if (e.relatedNode == this && !e.$isMoveWithinParent) { + e.currentTarget.$setLayout(this.localName, true); + + if (e.currentTarget.$altExt) { + + return false; + } + } + }); + + this.$draw = function(){ + var doc = this.$pHtmlNode.ownerDocument; + this.$ext = this.$pHtmlNode.appendChild(doc.createElement("div")); + if (this.getAttribute("style")) + this.$ext.setAttribute("style", this.getAttribute("style")); + this.$ext.className = this.localName; + + this.$vbox = this.localName == "vsplitbox"; + this.$int = this.$ext; + this.$ext.host = this; + + if (this.getAttribute("class")) + apf.setStyleClass(this.$ext, this.getAttribute("class")); + }; + + this.$loadAml = function(x) { + }; +}).call(apf.vsplitbox.prototype = new apf.GuiElement()); + +apf.hsplitbox.prototype = apf.vsplitbox.prototype; + +apf.aml.setElement("hsplitbox", apf.hsplitbox); +apf.aml.setElement("vsplitbox", apf.vsplitbox); + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * This element displays a skinnable rectangle that can contain other + * AML elements. + * + * It's used by other elements, such as the + * toolbar and statusbar elements, to specify sections. + * + * ```xml, demo + * + * + * + * + * + * + * + * ``` + * + * #### Remarks + * + * This component is used in the accordian element to create its sections. In + * the statusbar, the panel element is an alias of `bar`. + * + * @class apf.splitbutton + * @define splitbutton + * @container + * @allowchild button + * @allowchild {elements}, {anyaml} + * + * @inherits apf.GuiElement + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.4 + */ +/** + * @attribute {String} icon Sets or gets the url pointing to the icon image. + */ +/** + * @attribute {Boolean} [collapsed=false] Sets or gets collapse panel on load. + */ +/** + * @attribute {String} title Describes the content in a panel + */ +apf.splitbutton = function(struct, tagName) { + this.$init(tagName || "splitbutton", apf.NODE_VISIBLE, struct); +}; + +(function(){ + this.$focussable = false; + + this.$booleanProperties["disabled-split"] = 1; + //this.$supportedProperties.push("disabled-split", "button-skin"); + + this.$propHandlers["caption"] = function(value) { + this.$button1.setProperty("caption", value); + }; + + this.$propHandlers["icon"] = function(value) { + this.$button1.setProperty("icon", value); + }; + + this.$propHandlers["tooltip"] = function(value) { + this.$button1.setProperty("tooltip", value); + }; + + this.$propHandlers["hotkey"] = function(value) { + this.$button1.setProperty("hotkey", value); + }; + + this.$propHandlers["disabled"] = function(value) { + this.$button1.setProperty("disabled", value); + this.$button2.setProperty("disabled", value); + }; + + this.$propHandlers["disabled-split"]= function(value) { + this.$button2.setProperty("disabled", value); + }; + + this.$propHandlers["button-skin"] = function(value) { + this.$button1.setProperty("skin", value); + this.$button2.setProperty("skin", value); + }; + + this.$propHandlers["class"] = function(value) { + apf.setStyleClass(this.$ext, value, this.$lastClassValue ? [this.$lastClassValue] : null); + this.$lastClassValue = value; + }; + + this.$propHandlers["submenu"] = function(value) { + this.$button2.setProperty("submenu", value); + + var _self = this; + this.$button2.addEventListener("mousedown", function() { + var menu = self[value] || value; + + if (!menu.$splitInited) { + _self.dispatchEvent("submenu.init"); + menu.addEventListener("display", function(){ + var split = this.opener.parentNode; + var diff = apf.getAbsolutePosition(split.$button2.$ext)[0] + - apf.getAbsolutePosition(split.$button1.$ext)[0]; + + this.$ext.style.marginLeft = "-" + diff + "px"; + }); + menu.$splitInited = true; + } + + this.removeEventListener("mousedown", arguments.callee); + }); + }; + + this.$draw = function(){ + var _self = this; + this.$ext = this.$pHtmlNode.appendChild(document.createElement("div")); + + var skin = this["button-skin"] || this.getAttribute("skin") || this.localName; + + this.$button1 = new apf.button({ + htmlNode: this.$ext, + parentNode: this, + skinset: this.getAttribute("skinset"), + skin: skin, + "class": "main", + onmouseover: function() { + apf.setStyleClass(this.$ext, "primary"); + if (_self.$button2.disabled) + return; + _self.$button2.$setState("Over", {}); + + _self.dispatchEvent("mouseover", { button: this }); + }, + onmouseout: function() { + apf.setStyleClass(this.$ext, "", ["primary"]); + if (_self.$button2.disabled) + return; + _self.$button2.$setState("Out", {}); + + _self.dispatchEvent("mouseout", { button: this }); + }, + onclick: function(e) { + _self.dispatchEvent("click"); + } + }); + + this.$button2 = new apf.button({ + htmlNode: this.$ext, + parentNode: this, + skinset: this.getAttribute("skinset"), + skin: skin, + "class": "arrow", + onmouseover: function() { + apf.setStyleClass(this.$ext, "primary"); + _self.$button1.$setState("Over", {}); + + _self.dispatchEvent("mouseover", { button: this }); + }, + onmouseout: function() { + if (!_self.$button2.value) { + apf.setStyleClass(this.$ext, "", ["primary"]); + _self.$button1.$setState("Out", {}); + } + else { + apf.setStyleClass(this.$ext, "primary"); + _self.$button1.$setState("Over", {}); + } + + _self.dispatchEvent("mouseout", { button: this }); + }, + onclick: function(e) { + _self.dispatchEvent("split.click", e); + } + }); + }; + + this.$loadAml = function(x) { + + }; + +}).call(apf.splitbutton.prototype = new apf.GuiElement()); + +apf.aml.setElement("splitbutton", apf.splitbutton); + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * @constructor + * @private + */ +apf.splitter = function(struct, tagName) { + this.$init(tagName || "splitter", apf.NODE_VISIBLE, struct); +}; + +(function() { + this.minwidth = 0; + this.minheight = 0; + + this.$scale = 0; // 0 both, 1 left/top, 2 right/bottom + + this.$focussable = false; // This object can get the focus + this.$splitter = true; + + this.$booleanProperties["realtime"] = true; + + this.$propHandlers["realtime"] = function(value) { + this.$setStyleClass(this.$ext, value && (this.$baseCSSname + "Realtime") || "", + [this.$baseCSSname + "Realtime"]); + } + + this.$propHandlers["scale"] = function(value) { + this.$scale = value == "left" || value == "top" + ? 1 : (value == "right" || "bottom " + ? 2 : 0); + } + + this.$propHandlers["parent"] = function(value) { + this.$parent = typeof value == "object" ? value : self[value]; + } + + this.$propHandlers["type"] = function(value) { + this.$setStyleClass(this.$ext, value, + [value == "horizontal" ? "vertical" : "horizontal"]); + + if (value == "vertical") + this.$setStyleClass(this.$ext, "w-resize", ["n-resize"]); + else + this.$setStyleClass(this.$ext, "n-resize", ["w-resize"]); + + //Optimize this to not recalc for certain cases + if (value == "horizontal") { + this.$info = { + pos: "top", + opos: "left", + size: "width", + osize: "height", + offsetPos: "offsetTop", + offsetSize: "offsetHeight", + oOffsetPos: "offsetLeft", + oOffsetSize: "offsetWidth", + clientPos: "clientY", + d1 : 1, + d2 : 0, + x1 : 0, + x2 : 2 + }; + } + else { + this.$info = { + pos: "left", + opos: "top", + size: "height", + osize: "width", + offsetPos: "offsetLeft", + offsetSize: "offsetWidth", + oOffsetPos: "offsetTop", + oOffsetSize: "offsetHeight", + clientPos: "clientX", + d1 : 0, + d2 : 1, + x1 : 3, + x2 : 1 + } + } + } + + this.addEventListener("DOMNodeInserted", function(e) { + if (e.currentTarget != this) + return; + + /*if (e.$oldParent) { + e.$oldParent.removeEventListener("DOMNodeInserted", this.$siblingChange); + e.$oldParent.removeEventListener("DOMNodeRemoved", this.$siblingChange); + }*/ + + this.init && this.init(); + }); + + /*this.$siblingChange = function(e) { + //if (e.currentTarget + + //this.init(); + }*/ + + this.$draw = function(){ + //Build Main Skin + this.$ext = this.$getExternal(); + + var template = "vbox|hbox".indexOf(this.parentNode.localName) > -1 + ? "box" : "splitbox"; + + apf.extend(this, apf.splitter.templates[template]); + this.decorate(); + }; + + this.$loadAml = function(x) { + if (this.realtime !== false) // && (!apf.isIE || apf.isIE > 8)) + this.$propHandlers.realtime.call(this, this.realtime = true); + }; +}).call(apf.splitter.prototype = new apf.Presentation()); + +apf.splitter.templates = { + box: { + update: function(newPos, finalPass) { + with (this.$info) { + //var pos = Math.ceil(apf.getAbsolutePosition(this.$ext, this.parentNode.$int)[d1] - posPrev[d1]); + var max = this.$previous + ? this.$previous.$ext[offsetSize] + this.$next.$ext[offsetSize] + : (this.parentNode).getWidth(); + var method = finalPass ? "setAttribute" : "setProperty"; + if (apf.hasFlexibleBox) + newPos -= this.$previous ? apf.getAbsolutePosition(this.$previous.$ext, this.parentNode.$int)[d1] : 0; + + //Both flex + if (this.$previous && this.$next && (this.$previous.flex || this.$previous.flex === 0) && (this.$next.flex || this.$next.flex === 0)) { + if (!finalPass && !this.realtime) + newPos -= this.$ext[offsetSize]; + + //var totalFlex = this.$previous.flex + this.$next.flex - (finalPass && !this.realtime ? this.parentNode.padding : 0); + if (!this.$scale || this.$scale == 1) + this.$previous[method]("flex", newPos); + if (!this.$scale || this.$scale == 2) + this.$next[method]("flex", this.$totalFlex - newPos); + } + //Fixed + else { + if (this.$next && !this.$next.flex && (!this.$scale || this.$scale == 2)) + this.$next[method](osize, max - newPos); + if (this.$previous && !this.$previous.flex && (!this.$scale || this.$scale == 1)) + this.$previous[method](osize, newPos); + } + } + + if (apf.hasSingleResizeEvent) + apf.layout.forceResize(this.$ext.parentNode); + }, + + $setSiblings: function(){ + this.$previous = this.previousSibling; + while (this.$previous && (this.$previous.nodeType != 1 + || this.$previous.visible === false + || this.$previous.nodeFunc != apf.NODE_VISIBLE)) + this.$previous = this.$previous.previousSibling; + this.$next = this.nextSibling; + while (this.$next && (this.$next.nodeType != 1 + || this.$next.visible === false + || this.$next.nodeFunc != apf.NODE_VISIBLE)) + this.$next = this.$next.nextSibling; + }, + + init: function(size, refNode, oItem) { + //this.parentNode.addEventListener("DOMNodeInserted", this.$siblingChange); + //this.parentNode.addEventListener("DOMNodeRemoved", this.$siblingChange); + + this.$setSiblings(); + + this.$thickness = null; + if (this.parentNode && this.parentNode.$box) { + this.setProperty("type", this.parentNode.localName == "vbox" + ? "horizontal" + : "vertical"); + this.$thickness = parseInt(this.parentNode.padding); + } + + if (!this.$previous || !this.$next) + return this; + + with (this.$info) { + var diff = apf.getDiff(this.$ext); + if (!this.parentNode.$box) { + var iSize = Math.max( + this.$previous.$ext[offsetSize], this.$next.$ext[offsetSize]); + this.$ext.style[size] = (iSize - diff[d1]) + "px"; + } + + var iThick = this[osize] = this.$thickness + || (this.$next[oOffsetPos] - this.$previous[oOffsetPos] + - this.$previous[oOffsetSize]); + + this.$ext.style[osize] = (iThick - diff[d2]) + "px"; + } + + return this; + }, + + decorate: function(){ + var _self = this; + this.$ext.onmousedown = function(e) { + if (!e) + e = event; + + if (_self.dispatchEvent("dragstart") === false) + return; + + apf.dragMode = true; //prevent selection + + _self.$setSiblings(); + + var changedPosition, pHtml = _self.parentNode.$int, diff = 0; + if ("absolute|fixed|relative".indexOf(apf.getStyle(pHtml, "position")) == -1) { + pHtml.style.position = "relative"; + changedPosition = true; + } + + _self.$totalFlex = 0; + with (_self.$info) { + if (_self.$parent) { + if (!_self.$previous) { + var posNext = apf.getAbsolutePosition(_self.$next.$ext, _self.parentNode.$int); + var wd = _self.$parent.getWidth(); + + if (_self.$scale == 2) { + var max = posNext[d1] + _self.$next.$ext[offsetSize] - this[offsetSize]; + diff = (_self.parentNode.$int[offsetSize] - max); + var min = max - wd - diff; + } + } + else if (!_self.$next) { + //@todo + } + } + else { + if (_self.$previous) { + var posPrev = apf.getAbsolutePosition(_self.$previous.$ext, _self.parentNode.$int); + var min = _self.$scale + ? 0 + : (posPrev[d1] || 0) + (parseInt(_self.$previous.minwidth) || 0); + } + if (_self.$next) { + var posNext = apf.getAbsolutePosition(_self.$next.$ext, _self.parentNode.$int); + var max = posNext[d1] + _self.$next.$ext[offsetSize] + - this[offsetSize] - (parseInt(_self.$next.minwidth) || 0); + } + } + + //Set flex to pixel sizes + if (_self.$previous && _self.$next) { + if ((_self.$previous.flex || _self.$previous.flex === 0) + && (_self.$next.flex || _self.$next.flex === 0)) { + var set = [], nodes = _self.parentNode.childNodes, padding = 0; + for (var node, i = 0, l = nodes.length; i < l; i++) { + if ((node = nodes[i]).visible === false + || node.nodeFunc != apf.NODE_VISIBLE || node.$splitter) + continue; + + if (node.flex) + set.push(node, node.$ext[offsetSize] + + (apf.hasFlexibleBox && !_self.realtime && node == _self.$previous + ? 2 * _self.parentNode.padding : 0)); + } + for (var i = 0, l = set.length; i < l; i+=2) { + set[i].setAttribute("flex", set[i+1]); + } + } + + _self.$totalFlex += _self.$next.flex + _self.$previous.flex; + } + + var startPos, startOffset; + if (apf.hasFlexibleBox) { + var coords = apf.getAbsolutePosition(this); + startPos = e[clientPos] - coords[d1]; + + if (!_self.realtime) { + if (_self.$previous.flex && !_self.$next.flex) { + var mBox = apf.getBox(_self.$next.margin); + mBox[x1] = _self.parentNode.padding; + _self.$next.$ext.style.margin = mBox.join("px ") + "px"; + } + else { + var mBox = apf.getBox(_self.$previous.margin); + mBox[x2] = _self.parentNode.padding; + _self.$previous.$ext.style.margin = mBox.join("px ") + "px"; + } + + var diff = apf.getDiff(this); + this.style.left = coords[0] + "px"; + this.style.top = coords[1] + "px"; //(apf.getHtmlTop(this) - Math.ceil(this.offsetHeight/2)) + this.style.width = (this.offsetWidth - diff[0]) + "px"; + this.style.height = (this.offsetHeight - diff[1]) + "px"; + this.style.position = "absolute"; + } + } + else { + var coords = apf.getAbsolutePosition(this.offsetParent); + startOffset = apf.getAbsolutePosition(_self.$previous.$ext)[d1]; + startPos = e[clientPos] - coords[d1]; + + if (!_self.realtime) { + this.style.left = "0px"; + this.style.top = "0px"; + this.style.position = "relative"; + } + min = -1000; //@todo + } + } + + //e.returnValue = false; + //e.cancelBubble = true; + //apf.stopEvent(e); + + + apf.plane.show(this); + + + _self.$setStyleClass(this, _self.$baseCSSname + "Moving"); + + _self.$setStyleClass(document.body, + _self.type == "vertical" ? "w-resize" : "n-resize", + [_self.type == "vertical" ? "n-resize" : "w-resize"]); + + //@todo convert to proper way + document.onmouseup = function(e) { + if (!e) e = event; + + with (_self.$info) { + var newPos; + if (e[clientPos] >= 0) { + var coords = apf.getAbsolutePosition(_self.$ext.offsetParent); + newPos = (Math.min(max, Math.max(min, (e[clientPos] - coords[d1]) - + (apf.hasFlexibleBox ? startPos : startOffset)))) + diff; + } + } + + _self.$setStyleClass(_self.$ext, "", [_self.$baseCSSname + "Moving"]); + _self.$setStyleClass(document.body, "", ["n-resize", "w-resize"]); + + if (changedPosition) + pHtml.style.position = ""; + + if (apf.hasFlexibleBox && !_self.realtime) + (_self.$previous.flex && !_self.$next.flex + ? _self.$next : _self.$previous).$ext.style.margin + = apf.getBox(_self.$previous.margin).join("px ") + "px"; + + if (newPos) + _self.update(newPos, true); + + + apf.plane.hide(); + + + if (!_self.realtime) { + _self.$ext.style.left = ""; + _self.$ext.style.top = ""; + _self.$ext.style[_self.$info.size] = ""; + _self.$ext.style.position = ""; + } + + _self.dispatchEvent("dragdrop"); + + document.onmouseup = + document.onmousemove = null; + + apf.dragMode = false; //return to default selection policy + }; + + //@todo convert to proper way + document.onmousemove = function(e) { + if (!e) e = event; + + with (_self.$info) { + var newPos; + if (e[clientPos] >= 0) { + var coords = apf.getAbsolutePosition(_self.$ext.offsetParent); + newPos = (Math.min(max, Math.max(min, (e[clientPos] - coords[d1]) - + (apf.hasFlexibleBox || !_self.realtime ? startPos : startOffset)))) + diff; + + if (_self.realtime) + _self.update(newPos); + else { + _self.$ext.style[pos] = newPos + "px"; + } + } + } + + apf.stopEvent(e); + //e.returnValue = false; + //e.cancelBubble = true; + + _self.dispatchEvent("dragmove"); + }; + } + + apf.queue.add("splitter" + this.$uniqueId, function(){ + _self.init(); + }); + } + }, + + splitbox: { + update: function(newPos, finalPass) { + this[this.parentNode.$vbox ? "updateV" : "updateH"](newPos, finalPass); + }, + + updateV: function(newPos, finalPass) { + var method = finalPass ? "setAttribute" : "setProperty"; + + var pNode = this.$parent || this.parentNode; + var firstChild = pNode.firstChild; + if (firstChild.localName == "splitter") + firstChild = firstChild.nextSibling; + if (pNode.fixedChild) { + if (pNode.fixedChild == pNode.firstChild) { + pNode.fixedChild[method]("height", newPos - pNode.$edge[0]); + } + else { + pNode.fixedChild[method]("height", + apf.getHtmlInnerHeight(pNode.$int) - newPos + - pNode.padding - pNode.$edge[1]); + } + } + else if (firstChild.height) { + var total = apf.getHtmlInnerHeight(pNode.$int); + firstChild[method]("height", + ((newPos - pNode.$edge[0])/total*100) + "%"); + } + else { + var total = apf.getHtmlInnerHeight(pNode.$int) ; + pNode.lastChild[method]("height", + ((total - newPos - pNode.$edge[2] - pNode.padding)/total*100) + "%"); + } + + apf.dispatchEvent("splitter.resize", { splitter: this, final: finalPass }); + }, + + updateH: function(newPos, finalPass) { + var method = finalPass ? "setAttribute" : "setProperty"; + + var pNode = this.$parent || this.parentNode; + var firstChild = pNode.firstChild; + if (firstChild.localName == "splitter") + firstChild = firstChild.nextSibling; + if (pNode.fixedChild) { + if (pNode.fixedChild == pNode.firstChild) { + pNode.fixedChild[method]("width", newPos - pNode.$edge[3]); + } + else { + pNode.fixedChild[method]("width", + apf.getHtmlInnerWidth(pNode.$int) - newPos + - pNode.padding - pNode.$edge[2]); + } + } + else if (firstChild.width) { + var total = apf.getHtmlInnerWidth(pNode.$int); + firstChild[method]("width", + ((newPos - pNode.$edge[3])/total*100) + "%"); + } + else { + var total = apf.getHtmlInnerWidth(pNode.$int) ; + pNode.lastChild[method]("width", + ((total - newPos - pNode.$edge[1] - pNode.padding)/total*100) + "%"); + } + + apf.dispatchEvent("splitter.resize", { splitter: this, final: finalPass }); + }, + + $setSiblings: function(){ + this.$previous = this.parentNode.firstChild + this.$next = this.parentNode.lastChild; + }, + + decorate: function(){ + var _self = this; + + if (this.parentNode && this.parentNode.$box) { + this.setProperty("type", this.parentNode.$vbox + ? "horizontal" + : "vertical"); + } + + this.$ext.onmousedown = function(e) { + if (!e) + e = event; + + if (_self.dispatchEvent("dragstart") === false) + return; + + apf.dragMode = true; //prevent selection + + _self.$setSiblings(); + + var pNode = _self.$parent || _self.parentNode; + var firstChild = pNode.firstChild.$splitter ? pNode.childNodes[1] : pNode.firstChild; + if (pNode.$vbox) { + var min = parseInt(firstChild.minheight) + pNode.$edge[0]; + var max = apf.getHtmlInnerHeight(pNode.$ext) - pNode.lastChild.minheight + - pNode.$edge[2] - pNode.padding; + var offset = e.layerY || e.offsetY; + } + else { + var min = parseInt(firstChild.minwidth) + pNode.$edge[3]; + var max = apf.getHtmlInnerWidth(pNode.$ext) - pNode.lastChild.minwidth + - pNode.$edge[1] - pNode.padding; + var offset = e.layerX || e.offsetX; + } + + function update(e, final) { + var newPos, coords; + if (pNode.$vbox) { + if (e.clientY >= 0) { + coords = apf.getAbsolutePosition(_self.$parent ? _self.$parent.$ext : _self.$ext.offsetParent); + newPos = Math.min(max, Math.max(min, (e.clientY - coords[1] - offset))); + } + } + else { + if (e.clientX >= 0) { + coords = apf.getAbsolutePosition(_self.$parent ? _self.$parent.$ext : _self.$ext.offsetParent); + newPos = Math.min(max, Math.max(min, (e.clientX - coords[0] - offset))); + } + } + + if (!newPos) return; + + if (_self.realtime || final) + _self.update(newPos, final); + else { + _self.$ext.style[pNode.$vbox ? "top" : "left"] = newPos + "px"; + } + } + + + apf.plane.show(this); + + + _self.$setStyleClass(this, _self.$baseCSSname + "Moving"); + + _self.$setStyleClass(document.body, + _self.type == "vertical" ? "w-resize" : "n-resize", + [_self.type == "vertical" ? "n-resize" : "w-resize"]); + + //@todo convert to proper way + document.onmouseup = function(e) { + if (!e) e = event; + + _self.$setStyleClass(_self.$ext, "", [_self.$baseCSSname + "Moving"]); + _self.$setStyleClass(document.body, "", ["n-resize", "w-resize"]); + + update(e, true); + + + apf.plane.hide(); + + + if (!_self.realtime) { + _self.$ext.style.left = ""; + _self.$ext.style.top = ""; + _self.$ext.style[_self.$info.size] = ""; + _self.$ext.style.position = ""; + } + + _self.dispatchEvent("dragdrop"); + + document.onmouseup = + document.onmousemove = null; + + apf.dragMode = false; //return to default selection policy + }; + + //@todo convert to proper way + document.onmousemove = function(e) { + if (!e) e = event; + + update(e); + + apf.stopEvent(e); + //e.returnValue = false; + //e.cancelBubble = true; + + _self.dispatchEvent("dragmove"); + }; + } + } + } +}; + +apf.aml.setElement("splitter", apf.splitter); + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +/** + * An element that groups state elements together and + * provides a way to set a default state. + * + * #### Example + * + * ```xml + * + * + * + * + * + * + * ``` + * + * @class apf.stateGroup + * @define state-group + * @logic + * @inherits apf.AmlElement + * + * @see apf.state + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.4 + */ +apf.stateGroup = function(){ + this.$init("state-group", apf.NODE_HIDDEN); +}; +apf.aml.setElement("state-group", apf.stateGroup); + +(function(){ + this.$handlePropSet = function(prop, value, force) { + if (prop == "id") + return; + + var node, nodes = this.childNodes; + for (var i = 0, l = nodes.length; i < l; i++){ + node = nodes[i]; + + if (node.nodeType != 1 || node.localName != "state") + continue; + + if (!node[prop] || node.$inheritProperties[prop] == 2) { + node.$inheritProperties[prop] = 2; + node.setProperty(prop, value); + } + } + }; + + //@todo this should use text node insertion + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + if (!this.id) + this.id = "stategroup" + this.$uniqueId; + + //apf.StateServer.addGroup(this.id, null, this.parentNode); //@todo rearch this + + var nodes = this.childNodes; + for (var i = 0, l = nodes.length; i < l; i++){ + nodes[i].setProperty("group", this.id); + } + }); +}).call(apf.stateGroup.prototype = new apf.AmlElement()); + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +/** + * @private + */ +apf.StateServer = { + states: {}, + groups: {}, + locs: {}, + + removeGroup: function(name, elState) { + this.groups[name].remove(elState); + if (!this.groups[name].length) { + if (self[name]) { + self[name].destroy(); + self[name] = null; + } + + delete this.groups[name]; + } + }, + + addGroup: function(name, elState, pNode) { + if (!this.groups[name]) { + this.groups[name] = []; + + var pState = new apf.state({ + id: name + }); + pState.parentNode = pNode; + //pState.implement(apf.AmlNode); + //pState.name = name; + pState.toggle = function(){ + for (var next = 0, i = 0; i < apf.StateServer.groups[name].length; i++) { + if (apf.StateServer.groups[name][i].active) { + next = i + 1; + break; + } + } + + apf.StateServer.groups[name][ + (next == apf.StateServer.groups[name].length) ? 0 : next + ].activate(); + } + + this.groups[name].pState = self[name] = pState; + } + + if (elState) + this.groups[name].push(elState); + + return this.groups[name].pState; + }, + + removeState: function(elState) { + delete this.states[elState.name]; + }, + + addState: function(elState) { + this.states[elState.name] = elState; + } +} + +/** + * This element specifies a certain state of (a part of) the application. By + * "state", we mean a collection of properties on objects that have a certain + * value at one time. + * + * This element allows you to specify which properties on + * which elements should be set when a state is activated. This element can + * belong to a state-group containing multiple elements with a default state. + * + * #### Example + * + * ```xml, demo + * + * + * + * + * + * + * State - User + * State - Admin + * + * + * + * ``` + * + * @class apf.state + * @define state + * + * @logic + * @inherits apf.AmlElement + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.9 + */ +/** + * @event change Fires when the active property of this element changes. + * + */ +apf.state = function(struct, tagName) { + this.$init(tagName || "state", apf.NODE_HIDDEN, struct); + + this.$signalElements = []; + this.$groupAdded = {}; + this.$locationAdded = ''; +}; + +(function(){ + // *** Properties and Attributes *** // + + this.$supportedProperties.push("active"); + this.$booleanProperties["active"] = true; + + /** + * @attribute {Boolean} active whether this state is the active state + */ + this.$propHandlers["active"] = function(value) { + //Activate State + if (apf.isTrue(value)) { + if (this.group) { + var nodes = apf.StateServer.groups[this.group]; + if (!nodes) { + apf.StateServer.addGroup(this.group, this); + nodes = apf.StateServer.groups[this.group]; + } + + for (var i = 0; i < nodes.length; i++) { + if (nodes[i] != this && nodes[i].active !== false) + nodes[i].deactivate(); + } + } + + var q = this.$signalElements; + for (var i = 0; i < q.length; i++) { + if (!self[q[i][0]] || !self[q[i][0]].setProperty) { + + + continue; + } + + self[q[i][0]].setProperty(q[i][1], this[q[i].join(".")]); + } + + if (this.group) { + var attr = this.attributes; + for (var i = 0; i < attr.length; i++) { + if (attr[i].nodeName.match(/^on|^(?:group|id)$|^.*\..*$/)) + continue; + self[this.group].setProperty(attr[i].nodeName, + attr[i].nodeValue); + } + apf.StateServer.groups[this.group].pState.dispatchEvent("change"); + } + + this.dispatchEvent("activate"); + + + } + + //Deactivate State + else { + this.setProperty("active", false); + this.dispatchEvent("deactivate"); + + + } + }; + + + // *** Public methods *** // + + + + /** + * Sets the value of this element. This should be one of the values + * specified in the values attribute. + * @param {String} value Sets the new value of this element + */ + this.setValue = function(value) { + this.active = 9999; + this.setProperty("active", value, false, true); + }; + + /** + * Actives this state, setting all the properties on the elements that + * were specified. + */ + this.activate = function(){ + this.active = 9999; + this.setProperty("active", true, false, true); + }; + + /** + * Deactivates the state of this element. This is mostly a way to let all + * elements that have property bound to this state know it is no longer + * active. + */ + this.deactivate = function(){ + this.setProperty("active", false, false, true); + }; + + + + // *** Init *** // + + this.$propHandlers["group"] = function(value) { + if (value) { + apf.StateServer.addGroup(value, this); + this.$groupAdded = {'value' : value, elState : this}; + } + else { + apf.StateServer.removeGroup(this.$groupAdded.value, this.$groupAdded.elState); + this.$groupAdded = {}; + } + } + + this.$propHandlers["location"] = function(value) { + if (value) { + apf.StateServer.locs[value] = this; + this.$locationAdded = value; + } + else { + delete apf.StateServer.locs[this.$locationAdded]; + this.$locationAdded = ''; + } + } + + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + apf.StateServer.addState(this); + + //Properties initialization + var attr = this.attributes; + for (var s, i = 0; i < attr.length; i++) { + s = attr[i].nodeName.split("."); + if (s.length == 2) + this.$signalElements.push(s); + } + }); + + this.addEventListener("DOMNodeRemovedFromDocument", function(){ + this.$signalElements = null; + apf.StateServer.removeState(this); + if (this.group) + apf.StateServer.removeGroup(this.group, this); + }); +}).call(apf.state.prototype = new apf.AmlElement()); + +apf.aml.setElement("state", apf.state); + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * An element displaying a tab and several buttons allowing a + * user to switch between the pages. Each tab can contain + * arbitrary AML. Each tab can render its content during + * startup of the application, or when the tab is activated. + * + * #### Example + * + * ```xml, demo + * + * + * + * + * Example + * Example + * + * + * Test checkbox + * Test checkbox + * Test checkbox + * + * + * This ok? + * This better? + * + * + * + * + * ``` + * + * @class apf.pane + * @define pane + * @container + * @allowchild tab + * + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.1 + * + * @inherits apf.BaseTab + */ + +apf["switch"] = function(struct, tagName) { + this.$hasButtons = false; + this.$init(tagName || "switch", apf.NODE_VISIBLE, struct); +}; + +apf.pages = function(struct, tagName) { + this.$hasButtons = false; + this.$init(tagName || "pages", apf.NODE_VISIBLE, struct); + + this.$focussable = false; +}; + +apf.pane = function(struct, tagName) { + this.$hasButtons = true; + this.$init(tagName || "pane", apf.NODE_VISIBLE, struct); +}; + +(function(){ + this.$focussable = apf.KEYBOARD; // This object can get the focus from the keyboard + + // *** Init *** // + + this.$draw = function(bSkinChange) { + //Build Main Skin + this.$ext = this.$getExternal(); + this.$loadChildren(); + }; +}).call(apf.pane.prototype = new apf.BaseTab()); + +apf["switch"].prototype = +apf.pages.prototype = apf.pane.prototype; + +apf.aml.setElement("switch", apf["switch"]); +apf.aml.setElement("pages", apf.pages); +apf.aml.setElement("pane", apf.pane); + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +/** + * Any child element of this element is placed in a table. The size of the + * columns and rows of the table can be set by attributes. Child elements can + * span multiple columns. Using `'*' `as a size indicator will use the remaining + * size for that column or row, when the table's size is set. + * + * #### Example + * + * This example shows a window with a table and two buttons that change the + * orientation of the table runtime. The textarea and its label have a span set + * to `'*'`. This means they will span the entire width of all columns, no matter + * how many columns there are. + * + * ```xml, demo + * + * + * + * + * Name + * + * Address + * + * Country + * + * America + * Armenia + * The Netherlands + * + * + * Message + * + * + * + * + * + * + * + * + * + * ``` + * + * @class apf.table + * @define table + * @allowchild {elements}, {anyaml} + * + * @container + * @inherits apf.GuiElement + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 1.0 + */ +apf.table = function(struct, tagName) { + this.$init(tagName || "table", apf.NODE_VISIBLE, struct); +}; + +(function(){ + // *** Properties and Attributes *** // + + this.$focussable = false; + this.$useLateDom = true; + this.$layout = true; + + this.columns = null;//"150,200"; + this.padding = 2; + this.$edge = [5, 5, 5, 5]; + this.cellheight = 19; + + /** + * @attribute {Number | String} columns Sets or gets a comma seperated list of column sizes. + * A column size can be specified in a number (size in pixels), or using a number and a `"%"` sign to indicate a percentage. + * A `'*'` indicates the column spans the rest space. There can be only one `'*'` in the column string. + * + * #### Example + * + * ```xml + * + * ``` + * + */ + /** + * @attribute {String} [padding=2] Sets or gets the space between each element. + */ + /** + * @attribute {String} [edge="5 5 5 5"] Sets or gets the space between the container and the elements, space seperated in pixels for each side. Similar to CSS in the sequence of `top right bottom left`. + * + * #### Example + * + * ```xml + * + * ```` + */ + this.$supportedProperties.push("columns", "padding", "edge", + "cellheight", "span"); + + this.$propHandlers["columns"] = function(value) { + if (!value.match(/^((?:\d+\%?|\*)\s*(?:,\s*|\s*$))+$/)) { + + return; + } + + var col, colsize = this.$columns = value.splitSafe(","); + + var total = 0, cols = this.$table.getElementsByTagName("col"); + if (cols.length) { + for (var sz, i = 0, l = Math.min(cols.length, colsize.length); i < l; i++) { + cols[i].style.width = (sz = colsize[i]).indexOf("%") > -1 ? sz : sz + "px"; + total += parseInt(sz); + } + } + + var start = cols.length - colsize.length; + if (start > 0) { + for (var i = cols.length - start; i < cols.length; i++) { + cols[i].parentNode.removeChild(cols[i]); + } + } + else if (start < 0) { + for (var i = colsize.length + start; i < colsize.length; i++) { + col = this.$table.appendChild(document.createElement("col")); + col.style.width = (sz = colsize[i]).indexOf("%") > -1 ? sz : sz + "px"; + col.setAttribute("valign", "top"); + total += parseInt(sz); + } + } + + this.$table.style.width = String(value).indexOf("%") > -1 + ? "auto" + : (total + ((colsize.length - 1) * this.padding) + + this.$edge[0] + this.$edge[2]) + "px"; + + var cells = this.$tbody.firstChild.getElementsByTagName("td"); + for (var i = cells.length - 1; i >= 0; i--) + cells[i].parentNode.removeChild(cells[i]); + + for (var sz, c, i = 0; i < colsize.length; i++) { + c = this.$tbody.firstChild.appendChild(document.createElement("td")); + c.style.width = (sz = colsize[i]).indexOf("%") > -1 ? sz : sz + "px"; + + /*if (colsize[i].indexOf("%") > -1) + c.appendChild(document.createElement("div")).style.width = "50px";*/ + } + + if (start && this.$amlLoaded) + visibleHandler({sync: true, parentNode: this}); + + this.$resize(); + } + + this.$propHandlers["padding"] = function(value) { + if (!this.$columns) return; + var cells = this.$table.getElementsByTagName("td"); + var lastCol, lastRow, cell, lRow = this.$tbody.lastChild; + for (var i = this.$columns.length, l = cells.length; i < l; i++) { + lastCol = (cell = cells[i]).parentNode.lastChild == cell; + lastRow = cell.parentNode == lRow; + cell.style.padding = "0px " + (lastCol ? 0 : value) + "px " + (lastRow ? 0 : value) + "px 0px"; + } + this.$resize(); + } + + this.$propHandlers["edge"] = function(value) { + this.$table.style.padding = (this.$edge = apf.getBox(value)).join("px ") + "px"; + this.$resize(); + } + + function visibleHandler(e) { + var table = e.parentNode || this.parentNode; + if (e.sync || e.value && !this.$altExt || !e.value && this.$altExt) { + var nodes = table.childNodes; + + var cells = apf.getArrayFromNodelist(table.$tbody.getElementsByTagName("td")); + var rows = table.$tbody.getElementsByTagName("tr"); + var empty = [], row = 1, cs, rs, collen = table.$columns.length; + var z = table.$columns.length, lastCol; + for (var node, td, last, l = nodes.length, i = 0; i < l; i++) { + if ((node = nodes[i]).visible === false) + continue; + + td = node.$altExt = last = cells[z++]; + if (!td) break; + //td = node.$altExt = last = document.createElement("td"); + + if (!rows[row]) + table.$tbody.appendChild(document.createElement("tr")); + + rows[row].appendChild(td); + td.appendChild(node.$ext); + td.setAttribute("colspan", cs = Math.min(collen - (empty[0] || 0), parseInt(node.colspan || node.span || 1))); + td.setAttribute("rowspan", rs = parseInt(node.rowspan || 1)); + + //@todo this is wrong it should be cs * rs + if (!empty[0]) + empty[0] = 0; + empty[0] += cs; + + if (rs > 1) { + for (var k = 1; k < rs; k++) { + if (!empty[k]) + empty[k] = 0; + empty[k] += cs; + } + } + + if (empty[0] >= collen) { + lastCol = true; + empty.shift(); + row++; + } + else lastCol = false; + + td.style.padding = "0px " + (lastCol ? 0 : table.padding) + + "px " + (i == l - 1 ? 0 : table.padding) + "px 0px"; + } + + //Fix padding of last row + var lastCells = rows[rows.length - 1].getElementsByTagName("td"); + for (i = 0, il = lastCells.length; i < il; i++) { + lastCells[i].style.padding = "0 " + + (i == il - 1 ? 0 : table.padding) + "px 0 0" + } + + for (;z < cells.length; z++) + cells[z].parentNode.removeChild(cells[z]); + + if (e.sync) return; + + if (e.value) + table.$addTd(nodes[l - 1]); //what if it's not visible + else { + //last.parentNode.removeChild(last); + this.$altExt = null; + } + } + } + + this.$addTd = function(amlNode) { + var cells = this.$table.getElementsByTagName("td"); + var total = 0, collen = this.$columns.length; + for (var cell, i = 0; i < cells.length; i++) { + total += Math.min(collen, + (parseInt((cell = cells[i]).getAttribute("colspan") || 1) + * parseInt(cell.getAttribute("rowspan") || 1))); + } + + if (total % collen == 0) { //New Row + var row = this.$tbody.appendChild(document.createElement("tr")); + } + else + row = cells[cells.length - 1].parentNode; + + //Add a new cell in the last row + var cel = row.appendChild(document.createElement("td")); + cel.style.position = "relative"; + + if (amlNode.colspan || amlNode.span) + cel.setAttribute("colspan", amlNode.colspan || amlNode.span); + if (amlNode.rowspan) + cel.setAttribute("rowspan", amlNode.rowspan); + + cel.appendChild(amlNode.$ext); + + amlNode.$altExt = cel; + } + + var propHandlers = { + "width" : function(value) { + this.$ext.style.width = "";/*value + ? Math.max(0, value - apf.getWidthDiff(this.$ext)) + "px" + : "";*/ + }, + + "height" : function(value) { + this.$ext.style.height = value + ? Math.max(0, value - apf.getHeightDiff(this.$ext)) + "px" + : ""; + this.parentNode.$resize(); + }, + + "margin" : function(value) { + this.$ext.style.margin = apf.getBox(value).join("px ") + "px"; + this.parentNode.$resize(); + }, + + "colspan" : function(value) { + if (!value) + this.$altExt.removeAttribute("colspan"); + else + this.$altExt.setAttribute("colspan", value); + + visibleHandler.call(this, {sync: true}); + this.parentNode.$resize(); + }, + + "rowspan" : function(value) { + if (!value) + this.$altExt.removeAttribute("rowspan"); + else + this.$altExt.setAttribute("rowspan", value); + + visibleHandler.call(this, {sync: true}); + this.parentNode.$resize(); + }, + + "valign" : function(value) { + this.$altExt.valign = value; + }, + + "align" : function(value) { + if ("left|right".indexOf(value) == -1) + return; + + this.$altExt.align = value; + } + } + propHandlers.span = propHandlers.colspan; + + //@todo move this to enableTable, disableTable + this.register = function(amlNode) { + if (amlNode.$altExt) //@todo hack, need to rearch layouting + return; + + amlNode.$propHandlers["left"] = + amlNode.$propHandlers["top"] = + amlNode.$propHandlers["right"] = + amlNode.$propHandlers["bottom"] = apf.K; + + for (var prop in propHandlers) { + amlNode.$propHandlers[prop] = propHandlers[prop]; + } + + amlNode.addEventListener("prop.visible", visibleHandler); + + this.$addTd(amlNode); + + this.$noResize = true; + + if (amlNode.margin) + propHandlers.margin.call(amlNode, amlNode.margin); + + //Why was this commented out? + if (amlNode.$ext.tagName == "INPUT") { + //amlNode.$ext.style.width = "100%"; + } + else + amlNode.$ext.style.width = "auto"; + + if (this.lastChild == amlNode) + this.$propHandlers["padding"].call(this, this.padding); + + delete this.$noResize; + } + + this.unregister = function(amlNode) { + amlNode.$propHandlers["left"] = + amlNode.$propHandlers["top"] = + amlNode.$propHandlers["right"] = + amlNode.$propHandlers["bottom"] = null; + + for (var prop in propHandlers) { + delete amlNode.$propHandlers[prop]; + } + + amlNode.removeEventListener("prop.visible", visibleHandler); + visibleHandler.call(amlNode, {value: false}); //maybe parent is already reset here? + + if (amlNode.margin) + amlNode.$ext.style.margin = ""; + + if (amlNode.width) + amlNode.$ext.style.width = ""; + } + /* + this.addEventListener("DOMNodeInsertedIntoDocument", function(e) { + this.register(this.parentNode); + }); + */ + + // *** DOM Hooks *** // + + this.addEventListener("DOMNodeRemoved", function(e) { + if (e.$doOnlyAdmin || e.currentTarget == this) + return; + + if (e.relatedNode == this) { + this.unregister(e.currentTarget); + //e.currentTarget.$setLayout(); + } + }); + + this.addEventListener("DOMNodeInserted", function(e) { + if (e.currentTarget == this || e.currentTarget.nodeType != 1) + return; + + if (e.relatedNode == this) { + if (e.$isMoveWithinParent) { + visibleHandler.call(e.currentTarget, {sync: true}); + } + else { + e.currentTarget.$setLayout("table"); + if (e.currentTarget.nextSibling) + visibleHandler.call(e.currentTarget, {sync: true}); + } + } + }); + + this.$draw = function(){ + this.$ext = apf.insertHtmlNode(null, this.$pHtmlNode, null, + "
      "); + this.$table = this.$ext.firstChild; + this.$tbody = this.$table.firstChild; + this.$ext.className = "table " + (this.getAttribute("class") || ""); + //this.$ext.style.overflow = "hidden"; + this.$int = this.$ext; + this.$ext.host = this; + + if (this.getAttribute("class")) + apf.setStyleClass(this.$ext, this.getAttribute("class")); + + this.addEventListener("resize", this.$resize); + this.$originalMin = [this.minwidth || 0, this.minheight || 0]; + }; + + //@todo implement percentage by using fixed and add functionality here + this.$resize = function(){ + if (!this.$amlLoaded || this.$noResize) + return; + + if (this.$table.offsetWidth >= this.$ext.offsetWidth) + this.$ext.style.minWidth = (this.minwidth = Math.max(0, this.$table.offsetWidth + - apf.getWidthDiff(this.$ext))) + "px"; + else { + this.$ext.style.minWidth = ""; + this.minwidth = this.$originalMin[0]; + } + + if (this.$table.offsetHeight >= this.$ext.offsetHeight) + this.$ext.style.minHeight = (this.minheight = Math.max(0, this.$table.offsetHeight + - apf.getHeightDiff(this.$ext))) + "px"; + else { + this.$ext.style.minHeight = ""; + this.minheight = this.$originalMin[1]; + } + } + + this.$loadAml = function(x) { + this.$amlLoaded = false; //@todo hack + + if (!this.$columns) + this.$propHandlers.columns.call(this, this.columns = "150, 200"); + this.$amlLoaded = true; //@todo hack + }; +}).call(apf.table.prototype = new apf.GuiElement()); + +apf.aml.setElement("table", apf.table); + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +apf.aml.setElement("teleport", apf.AmlElement); + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * This element displays a rectangle containing arbitrary (X)HTML. + * + * This element can be databound and use databounding rules to + * convert data into (X)HTML using--for instance--XSLT or JSLT. + * + * #### Example: Some simple text + * + * ```xml, demo + * + * + * + * Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur congue, nunc sed convallis gravida, justo nunc egestas nisi, eu iaculis nunc ipsum vel orci. Morbi mauris urna, rutrum at imperdiet at, molestie eu risus. Curabitur eu tincidunt eros. Donec in massa ut dolor vulputate commodo. Cras pulvinar urna ut ipsum pulvinar mollis sit amet in dui. Nam lobortis ligula sed tortor dapibus eget tincidunt dui pretium. + * + * + * + * ``` + * + * #### Example: Using Scrolldown + * + * ```xml, demo + * + * + * + * Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur congue, nunc sed convallis gravida, justo nunc egestas nisi, eu iaculis nunc ipsum vel orci. Morbi mauris urna, rutrum at imperdiet at, molestie eu risus. Curabitur eu tincidunt eros. Donec in massa ut dolor vulputate commodo. Cras pulvinar urna ut ipsum pulvinar mollis sit amet in dui. Nam lobortis ligula sed tortor dapibus eget tincidunt dui pretium. Quisque semper sem dignissim quam ullamcorper et lobortis arcu eleifend. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Fusce ac commodo mi. Pellentesque sit amet magna sed velit volutpat volutpat. Nam lobortis sem sed tortor accumsan dictum. Donec scelerisque rhoncus cursus. Mauris dui dolor, vehicula quis lacinia quis, facilisis et eros. Nulla facilisi. Donec urna velit, adipiscing non sollicitudin at, sodales id lorem. Fusce fringilla, magna id pellentesque egestas, neque risus luctus mauris, vel porttitor libero tortor et augue. Integer euismod porttitor mi, at viverra nulla pharetra vel. Etiam odio elit, volutpat a porttitor eu, posuere nec augue. Phasellus placerat lacus ut augue tempor consectetur. + * + * + * Add a line + * + * + * + * ``` + * + * @class apf.text + * @define text + * + * @form + * @inherits apf.Cache + * @inherits apf.StandardBinding + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.1 + * + */ +// @todo Please refactor this object +apf.text = function(struct, tagName) { + this.$init(tagName || "text", apf.NODE_VISIBLE, struct); + + this.$nodes = []; +}; + +(function(){ + this.implement( + + apf.Cache, + + apf.ChildValue + ); + + this.$focussable = true; // This object can't get the focus + this.focussable = false; + this.textselect = true; + this.$hasStateMessages = true; + + this.$textTimer = this.$lastMsg = this.$lastClass = this.$changedHeight = null; + + // *** Properties and Attributes *** // + + /** + * @attribute {Boolean} scrolldown Sets or gets whether this element's viewport is always + * scrolled down. This is especially useful + * when this element is used to displayed + * streaming content such as a chat conversation. + * + */ + /** + * @attribute {Boolean} secure Sets or gets whether the content loaded in this element + * should be filtered in order for it to not + * be able to execute JavaScript. This is + * especially useful when the content does + * not come from a trusted source, like a + * web service or xmpp feed. + */ + this.$booleanProperties["scrolldown"] = true; + this.$booleanProperties["secure"] = true; + this.$booleanProperties["textselect"] = true; + this.$supportedProperties.push("behavior", "scrolldown", "secure", "value"); + + this.$isTextInput = function(){ + return this.textselect; + } + + this.$propHandlers["scrolldown"] = function(value) { + var _self = this; + + if (value) { + //this.addEventListener("resize", this.$resize); + this.$scrolldown = true; + apf.addListener(this.$scrollArea, "scroll", this.$scrollFunc = function(){ + _self.$scrolldown = this.scrollTop >= this.scrollHeight + - this.offsetHeight + apf.getVerBorders(this); + }); + this.addEventListener("scroll", this.$scroll); + this.addEventListener("afterload", this.$scroll); + this.addEventListener("resize", function(){ + if (_self.$scrollArea && _self.$scrolldown && _self.scrolldown) + _self.$scrollArea.scrollTop = _self.$scrollArea.scrollHeight; + }); + clearInterval(this.$textTimer); + this.$textTimer = setInterval(function(){ + if (_self.$scrollArea && _self.$scrolldown && _self.scrolldown) + _self.$scrollArea.scrollTop = _self.$scrollArea.scrollHeight; + }, 200); + } + else { + //this.removeEventListener("resize", this.$resize); + + this.removeEventListener("scroll", this.$scroll); + this.removeEventListener("afterload", this.$scroll); + clearInterval(this.$textTimer); + if (this.$scrollArea) + apf.removeListener(this.$scrollArea, "scoll", this.$scrollFunc); + } + } + + this.$scroll = function(e) { + var html = this.$scrollArea; + + if (e.name == "afterload") { + this.$scrolldown = true; + html.scrollTop = html.scrollHeight; + return; + } + + this.$scrolldown = html.scrollTop >= html.scrollHeight + - html.offsetHeight + apf.getVerBorders(html); + }; + + /*this.$resize = function(){ + if (this.scrolldown && this.$scrolldown) + this.$scrollArea.scrollTop = this.$scrollArea.scrollHeight; + }*/ + + /** + * @attribute {String} value Sets or gets the contents of this element. This can be text, html, xhtml. + */ + this.$propHandlers["value"] = function(value, prop, force, forceAdd) { + if (this.each) + return; + + if (typeof value != "string") { + if (value.nodeType) + value = value.nodeType > 1 && value.nodeType < 5 + ? value.nodeValue + : value.firstChild && value.firstChild.nodeValue || ""; + else + value = value ? value.toString() : ""; + } + + if (this.secure) { + value = value.replace(//g, "") + .replace(//g, "") + .replace(new RegExp("ondblclick|onclick|onmouseover|onmouseout" + + "|onmousedown|onmousemove|onkeypress|onkeydown|onkeyup|onchange" + + "|onpropertychange", "g"), "ona"); + } + + value = value.replace(/\<\?xml version="1\.0" encoding="UTF-16"\?\>/, ""); + + if (forceAdd) { + apf.insertHtmlNodes(null, this.$container, null, value); + if (!this.value) this.value = ""; + this.value += value; + } + else + this.$container.innerHTML = value;//.replace(//ig, "") + + //Iframe bug fix for IE (leaves screen white); + if (apf.cannotSizeIframe && this.oIframe) + this.oIframe.style.width = this.oIframe.offsetWidth + "px"; + + if (this.scrolldown && this.$scrolldown) + this.$scrollArea.scrollTop = this.$scrollArea.scrollHeight; + }; + + this.$eachHandler = function(value) { + this.$attrExcludePropBind = apf.extend({}, this.$attrExcludePropBind); + this.$attrExcludePropBind.value = value ? 2 : 0; + }; + this.addEventListener("prop.each", this.$eachHandler); + + this.addEventListener("$clear", function(){ + this.$container.innerHTML = ""; + this.value = ""; + this.dispatchEvent("prop.value", {value: ""}); + }); + + // @todo replace this stub with something that does something + this.$moveNode = function() {}; + + // *** Public methods *** // + + + + this.addValue = function(value) { + this.$propHandlers["value"].call(this, value, null, null, true); + this.dispatchEvent("prop.value", {value: this.value}); + }; + + /** + * Sets the value of this element. This should be one of the values + * specified in the `values` attribute. + * @param {String} value The new value of this element + */ + this.setValue = function(value) { + this.setProperty("value", value, false, true); + }; + + /** + * Returns the current value of this element. + * @return {String} The current value. + */ + this.getValue = function(){ + return this.$container.innerHTML; + }; + + + + // *** Keyboard Support *** // + + + this.addEventListener("keydown", function(e) { + var key = e.keyCode; + + switch (key) { + case 33: + //PGUP + this.$container.scrollTop -= this.$container.offsetHeight; + break; + case 34: + //PGDN + this.$container.scrollTop += this.$container.offsetHeight; + break; + case 35: + //END + this.$container.scrollTop = this.$container.scrollHeight; + break; + case 36: + //HOME + this.$container.scrollTop = 0; + break; + case 38: + this.$container.scrollTop -= 10; + break; + case 40: + this.$container.scrollTop += 10; + break; + default: + return; + } + + return false; + }, true); + + + // *** Private methods *** // + + this.$canLoadData = function(){ + return this.$attrBindings.value ? true : false; + } + + this.$add = function(xmlNode, Lid, xmlParentNode, htmlParentNode, beforeNode) { + var f = this.$attrBindings.value.cvalue; + var html = f(xmlNode); + html = "
      " + html + "
      "; + if (htmlParentNode) { + if (beforeNode) + beforeNode.insertAdjacentHTML("beforebegin", html); + else + this.$container.insertAdjacentHTML("beforeend", html); + //apf.insertHtmlNode(oItem, htmlParentNode, beforeNode); + + //Iframe bug fix for IE (leaves screen white); + if (apf.cannotSizeIframe && this.oIframe) + this.oIframe.style.width = this.oIframe.offsetWidth + "px"; + + if (this.scrolldown && this.$scrolldown) + this.$scrollArea.scrollTop = this.$scrollArea.scrollHeight; + } + else + this.$nodes.push(html); + } + + this.$fill = function(){ + //apf.insertHtmlNode(null, this.$container, null, this.$nodes.join("")); + this.$container.insertAdjacentHTML("beforeend", this.$nodes.join("")); + this.$nodes = []; + } + + this.$deInitNode = + this.$updateNode = + this.$moveNode = apf.K; + + // *** Init *** // + + this.$draw = function(){ + this.$ext = this.$getExternal(); + this.$container = this.$getLayoutNode("main", "container", this.$ext); + + if (apf.hasCssUpdateScrollbarBug && !apf.getStyle(this.$container, "padding")) + this.$fixScrollBug(); + + this.$scrollArea = this.oFocus ? this.oFocus.parentNode : this.$container; + + if (this.$container.tagName.toLowerCase() == "iframe") { + if (apf.isIE) { + this.oIframe = this.$container; + var iStyle = this.skin.selectSingleNode("iframe_style"); + this.oIframe.contentWindow.document.write( + "\ + \ + \ + \ + \ + "); + this.$container = this.oIframe.contentWindow.document.body; + } + else { + var node = document.createElement("div"); + this.$ext.parentNode.replaceChild(node, this.$ext); + node.className = this.$ext.className; + this.$ext = this.$container = node; + } + } + + if (this.getAttribute("each")) + this.$eachHandler(); + }; + + this.addEventListener("DOMNodeRemovedFromDocument", function() { + clearInterval(this.$textTimer); + apf.destroyHtmlNode(this.oDrag); + + if (this.$scrollArea) + this.$scrollArea.onscoll = this.$scrollArea = null; + + this.oDrag = this.oIframe = this.oFocus = this.$container = this.$ext = null; + }); +}).call(apf.text.prototype = new apf.StandardBinding()); + +apf.aml.setElement("text", apf.text); + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +//@todo DOCUMENT the modules too + + +/** + * This element displays a rectangular area which allows a + * user to type information. + * + * The information typed can be + * restricted by using `this.$masking`. The information can also + * be hidden from view when used in password mode. + * + * By adding an + * autocomplete element as a child, the + * value for the textbox can be looked up as you type. By setting the + * {@link apf.textbox.mask mask attribute}, complex data input + * validation is done while the user types. + * + * #### Example: Simple Boxes + * + * ```xml, demo + * + * + * + * + * + * + * + * + * ``` + * + * #### Example: Validation + * + * ```xml, demo + * + * + * Please enter a minimum of three characters + * + * Enter your email address + * + * + * + * + * + * + * + * + * + * + * + * ``` + * + * #### Example: A Regular Box + * + * ```xml, demo + * + * + * + * + * + * + * + * + * + * + * + * ``` + * + * @class apf.textbox + * @define textbox + * @allowchild autocomplete, {smartbinding} + * + * @form + * @inherits apf.StandardBinding + * @inheritsElsewhere apf.XForms + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.1 + * + * + */ +/** + * @binding value Determines the way the value for the element is retrieved + * from the bound data. + * + * #### Example + * + * Sets the value based on data loaded into this component. + * + * ```xml + * + * + * + * + * ``` + * + * A shorter way to write this is: + * ```xml + * + * + * + * + * ``` + * + */ +/** + * @event click Fires when the user presses a mousebutton while over this element and then let's the mousebutton go. + */ +/** + * @event mouseup Fires when the user lets go of a mousebutton while over this element. + */ +/** + * @event mousedown Fires when the user presses a mousebutton while over this element. + */ +/** + * @event keyup Fires when the user lets go of a keyboard button while this element is focussed. + * @param {Object} e The standard event object. It contains the following property: + * - keyCode ([[Number]]): which key was pressed. This is an ascii number. + */ +/** + * @event clear Fires when the content of this element is cleared. + */ +apf.input = function(struct, tagName) { + this.$init(tagName || "input", apf.NODE_VISIBLE, struct); +}; + +apf.secret = function(struct, tagName) { + this.$init(tagName || "secret", apf.NODE_VISIBLE, struct); +}; + +apf.password = function(struct, tagName) { + this.$init(tagName || "password", apf.NODE_VISIBLE, struct); +}; + +apf.textarea = function(struct, tagName) { + this.$init(tagName || "textarea", apf.NODE_VISIBLE, struct); + + this.multiline = true; +}; + +// HTML5 email element +apf.email = function(struct, tagName) { + this.$init(tagName || "email", apf.NODE_VISIBLE, struct); +}; + +apf.textbox = function(struct, tagName) { + this.$init(tagName || "textbox", apf.NODE_VISIBLE, struct); +}; + +(function(){ + this.implement( + + apf.DataAction + + + ); + + this.$focussable = true; // This object can get the focus + this.$masking = false; + this.$autoComplete = false; + + this.$childProperty = "value"; + + //this.realtime = false; + this.value = ""; + this.readonly = false; + this.$isTextInput = true; + this.multiline = false; + + /** + * @attribute {Boolean} realtime Defines whether the value of the bound data is + * updated as the user types it, or only when this element loses focus or + * the user presses enter. + */ + this.$booleanProperties["readonly"] = true; + this.$booleanProperties["focusselect"] = true; + this.$booleanProperties["realtime"] = true; + this.$booleanProperties["kbclear"] = true; + this.$supportedProperties.push("value", "mask", "initial-message", + "focusselect", "realtime", "type", "rows", "cols", "kbclear"); + + /** + * @attribute {String} value Sets or gets the text of this element + * + */ + this.$propHandlers["value"] = function(value, prop, force, initial) { + // @todo apf3.0 check use of this.$propHandlers["value"].call + if (!this.$input || !initial && this.getValue() == value) + return; + + // Set Value + if (!initial && !value && !this.hasFocus()) //@todo apf3.x research the use of clear + return this.$clear(); + else if (this.isHTMLBox) { + if (this.$input.innerHTML != value) + this.$input.innerHTML = value; + } + else if (this.$input.value != value) + this.$input.value = value; + + if (!initial) + apf.setStyleClass(this.$ext, "", [this.$baseCSSname + "Initial"]); + + if (this.$button) + this.$button.style.display = value && !initial ? "block" : "none"; + }; + + //See validation + //var oldPropHandler = this.$propHandlers["maxlength"]; + this.addEventListener("prop.maxlength", function(e) { + //Special validation support using nativate max-length browser support + if (this.$input.tagName.toLowerCase().match(/input|textarea/)) + this.$input.maxLength = parseInt(e.value) || null; + }); + + this.addEventListener("prop.editable", function(e) { + if (apf.isIE) + this.$input.unselectable = e.value ? "On" : "Off"; + else { + if (e.value) + apf.addListener(this.$input, "mousedown", apf.preventDefault); + else + apf.removeListener(this.$input, "mousedown", apf.preventDefault); + } + }); + + /** + * @attribute {String} mask Sets or gets a complex input pattern that the user should + * adhere to. + * + * This is a string which is a combination of special and normal + * characters. It is comma seperated, and thus has two options. The first option + * specifies whether the non-input characters (the chars not typed by the + * user) are in the value of this element. The second option specifies the + * character that is displayed when the user hasn't yet filled in a + * character. + * + * The following characters are possible: + * + * - `0`: any digit + * - `1`: the number 1 or 2. + * - `9`: any digit or a space. + * - `#`: user can enter a digit, space, plus or minus sign. + * - `L`: any alpha character, case insensitive. + * - `?`: any alpha character, case insensitive or space. + * - `A`: any alphanumeric character. + * - `a`: any alphanumeric character or space. + * - `X`: hexadecimal character, case insensitive. + * - `x`: hexadecimal character, case insensitive or space. + * - `&`: any whitespace. + * - `C`: any character. + * - `!`: causes the input mask to fill from left to right instead of from right to left. + * - `'`: the start or end of a literal part. + * - `"`: the start or end of a literal part. + * - `>`: converts all characters that follow to uppercase. + * - `<`: converts all characters that follow to lowercase. + * - `\`: cancel the special meaning of a character. + * + * #### Example + * + * An American phone number: + * + * ```xml + * + * ``` + * + * #### Example + * + * A Dutch postal code: + * + * ```xml + * + * ``` + * + * #### Example + * + * A date + * + * ```xml + * + * ``` + * + * #### Example + * + * A serial number + * + * ```xml + * + * ``` + * + * #### Example + * + * A MAC address + * + * ```xml + * + * ``` + */ + this.$propHandlers["mask"] = function(value) { + if (this.mask.toLowerCase() == "password")// || !apf.hasMsRangeObject) + return; + + if (!value) { + throw new Error("Not Implemented"); + } + + if (!this.$masking) { + this.$masking = true; + this.implement(apf.textbox.masking); + this.focusselect = false; + //this.realtime = false; + } + + this.setMask(this.mask); + }; + + //this.$propHandlers["ref"] = function(value) { + // this.$input.setAttribute("name", value.split("/").pop().split("::").pop() + // .replace(/[\@\.\(\)]*/g, "")); + //}; + + /** + * @attribute {String} initial-message Sets or gets the message displayed by this element + * when it doesn't have a value set. This property is inherited from parent + * nodes. When none is found, it is looked for on the appsettings element. + */ + this.$propHandlers["initial-message"] = function(value) { + if (value) { + + + //this.$propHandlers["value"].call(this, value, null, true); + } + + if (!this.value) + this.$clear(true); + + if (this.type == "password" && this.$inputInitFix) { + this.$inputInitFix.innerHTML = value; + apf.setStyleClass(this.$inputInitFix, "initFxEnabled"); + } + }; + + /** + * @attribute {Number} rows Sets or gets the row length for a text area. + */ + this.$propHandlers["rows"] = function(value) { + if (this.$input.tagName.toLowerCase() == "textarea" && value) { + this.setProperty("rows", value); + if (this.$ext) { + this.$ext.rows = value; + } + } + }; + + /** + * @attribute {Number} cols Sets or gets the column height for a text area. + */ + this.$propHandlers["cols"] = function(value) { + if (this.$input.tagName.toLowerCase() == "textarea" && value) { + this.setProperty("cols", value); + if (this.$ext) { + this.$ext.cols = value; + } + } + }; + + /** + * @attribute {Boolean} focusselect Sets or gets whether the text in this element is + * selected when this element receives focus. + */ + this.$propHandlers["focusselect"] = function(value) { + var _self = this; + this.$input.onmousedown = function(){ + _self.focusselect = false; + }; + + this.$input.onmouseup = + this.$input.onmouseout = function(){ + _self.focusselect = value; + }; + }; + + /** + * @attribute {String} type Sets or gets the type or function this element represents. + * This can be any arbitrary name, although there are some special values: + * + * - `"username"`: this element is used to type in the name part of login credentials. + * - `"password"`: this element is used to type in the password part of login credentials. + */ + this.$propHandlers["type"] = function(value) { + if (value && "password|username".indexOf(value) > -1 + && typeof this.focusselect == "undefined") { + this.focusselect = true; + this.$propHandlers["focusselect"].call(this, true); + } + }; + + this.$isTextInput = function(e) { + return true; + }; + + // *** Public Methods *** // + + + + /** + * Sets the value of this element. This should be one of the values + * specified in the `values` attribute. + * @param {String} value The new value of this element + */ + this.setValue = function(value) { + return this.setProperty("value", value, false, true); + }; + + /** + * Clears an element's value. + */ + this.clear = function(){ + this.setProperty("value", ""); + }; + + //@todo cleanup and put initial-message behaviour in one location + this.$clear = function(noEvent) { + if (this["initial-message"]) { + apf.setStyleClass(this.$ext, this.$baseCSSname + "Initial"); + this.$propHandlers["value"].call(this, this["initial-message"], null, null, true); + } + else { + this.$propHandlers["value"].call(this, "", null, null, true); + } + + if (!noEvent) + this.dispatchEvent("clear");//@todo this should work via value change + }; + + /** + * Returns the current value of this element. + * @return {String} The current value. + */ + this.getValue = function(){ + var v; + + if (this.isHTMLBox) { + if (this.$input.innerText) + v = this.$input.innerText; + else { + //Chrome has a bug, innerText is cleared when display property is changed + v = apf.html_entity_decode(this.$input.innerHTML + .replace(//g, "\n") + .replace(/<[^>]*>/g, "")); + } + if (v.charAt(v.length - 1) == "\n") + v = v.substr(0, v.length - 1); //Remove the trailing new line + } + else + v = this.$input.value; + + return v == this["initial-message"] ? "" : v.replace(/\r/g, ""); + }; + + + + /** + * Selects the text in this element. + */ + this.select = function(){ + this.$input.select(); + }; + + /** + * Deselects the text in this element. + */ + this.deselect = function(){this.$input.deselect();}; + + /**** Private Methods *****/ + + this.$enable = function(){this.$input.disabled = false;}; + this.$disable = function(){this.$input.disabled = true;}; + + this.$insertData = function(str) { + return this.setValue(str); + }; + + /** + * @private + */ + this.insert = function(text) { + if (apf.hasMsRangeObject) { + try { + this.$input.focus(); + } + catch (e) {} + var range = document.selection.createRange(); + if (this.oninsert) + text = this.oninsert(text); + range.pasteHTML(text); + range.collapse(true); + range.select(); + } + else { + this.$input.value += text; + } + }; + + this.addEventListener("$clear", function(){ + this.value = "";//@todo what about property binding? + + if (this["initial-message"] && apf.document.activeElement != this) { + this.$propHandlers["value"].call(this, this["initial-message"], null, null, true); + apf.setStyleClass(this.$ext, this.$baseCSSname + "Initial"); + } + else { + this.$propHandlers["value"].call(this, ""); + } + + if (!this.$input.tagName.toLowerCase().match(/input|textarea/i)) { + if (apf.hasMsRangeObject) { + try { + var range = document.selection.createRange(); + range.moveStart("sentence", -1); + //range.text = ""; + range.select(); + } + catch (e) {} + } + } + + this.dispatchEvent("clear"); //@todo apf3.0 + }); + + this.$keyHandler = function(key, ctrlKey, shiftKey, altKey, e) { + if (this.$button && key == 27 && this.kbclear) { + //this.$clear(); + if (this.value) { + this.change(""); + + this.dispatchEvent("keydown", { + keyCode: key, + ctrlKey: ctrlKey, + shiftKey: shiftKey, + altKey: altKey, + htmlEvent: e}); + + e.stopPropagation(); + } + //this.focus({mouse:true}); + } + + // Disabled this because it was being fired via the document as well + // Tested using the gotoline plugin + // if (this.dispatchEvent("keydown", { + // keyCode : key, + // ctrlKey : ctrlKey, + // shiftKey : shiftKey, + // altKey : altKey, + // htmlEvent : e}) === false) + // return false; + + /*// @todo: revisit this IF statement - dead code? + if (false && apf.isIE && (key == 86 && ctrlKey || key == 45 && shiftKey)) { + var text = window.clipboardData.getData("Text"); + if ((text = this.dispatchEvent("keydown", { + text: this.onpaste(text)}) === false)) + return false; + if (!text) + text = window.clipboardData.getData("Text"); + + this.$input.focus(); + var range = document.selection.createRange(); + range.text = ""; + range.collapse(); + range.pasteHTML(text.replace(/\n/g, "
      ").replace(/\t/g, "   ")); + + return false; + }*/ + }; + + this.$registerElement = function(oNode) { + if (!oNode) return; + if (oNode.localName == "autocomplete") + this.$autoComplete = oNode; + }; + + var fTimer; + this.$focus = function(e) { + if (!this.$ext || this.$ext.disabled) + return; + + this.$setStyleClass(this.$ext, this.$baseCSSname + "Focus"); + + var value = this.getValue(); + if (this["initial-message"] && !value) { + this.$propHandlers["value"].call(this, "", null, null, true); + apf.setStyleClass(this.$ext, "", [this.$baseCSSname + "Initial"]); + } + + var _self = this; + function delay(){ + try { + if (!fTimer || document.activeElement != _self.$input) { + _self.$input.focus(); + } + else { + clearInterval(fTimer); + return; + } + } + catch (e) {} + + if (_self.$masking) + _self.setPosition(); + + if (_self.focusselect) + _self.select(); + }; + + if ((!e || e.mouse) && apf.isIE) { + clearInterval(fTimer); + fTimer = setInterval(delay, 1); + } + else + delay(); + }; + + this.$blur = function(e) { + if (!this.$ext) + return; + + if (!this.realtime) + this.change(this.getValue()); + + if (e) + e.cancelBubble = true; + + this.$setStyleClass(this.$ext, "", [this.$baseCSSname + "Focus", "capsLock"]); + + var value = this.getValue(); + if (this["initial-message"] && !value) { + this.$propHandlers["value"].call(this, this["initial-message"], null, null, true); + apf.setStyleClass(this.$ext, this.$baseCSSname + "Initial"); + } + + /*if (apf.hasMsRangeObject) { + var r = this.$input.createTextRange(); + r.collapse(); + r.select(); + }*/ + + try { + if (apf.isIE || !e || e.srcElement != apf.window) + this.$input.blur(); + } + catch (e) {} + + // check if we clicked on the oContainer. ifso dont hide it + if (this.oContainer) { + $setTimeout("var o = apf.lookup(" + this.$uniqueId + ");\ + o.oContainer.style.display = 'none'", 100); + } + + clearInterval(fTimer); + }; + + // *** Init *** // + + this.$draw = function(){ + var _self = this, + typedBefore = false; + + + if (this.localName == "codeeditor") { + this.skin = "textarea"; + this.$loadSkin(); + } + + + //Build Main Skin + this.$ext = this.$getExternal(null, null, function(oExt) { + var mask = this.getAttribute("mask"); + + if ((typeof mask == "string" && mask.toLowerCase() == "password") + || "secret|password".indexOf(this.localName) > -1) { + this.type = "password"; + this.$getLayoutNode("main", "input").setAttribute("type", "password"); + } + + + + oExt.setAttribute("onmousedown", "if (!this.host.disabled) \ + this.host.dispatchEvent('mousedown', {htmlEvent : event});"); + oExt.setAttribute("onmouseup", "if (!this.host.disabled) \ + this.host.dispatchEvent('mouseup', {htmlEvent : event});"); + oExt.setAttribute("onclick", "if (!this.host.disabled) \ + this.host.dispatchEvent('click', {htmlEvent : event});"); + }); + this.$input = this.$getLayoutNode("main", "input", this.$ext); + this.$button = this.$getLayoutNode("main", "button", this.$ext); + this.$inputInitFix = this.$getLayoutNode("main", "initialfix", this.$ext); + + if (this.type == "password") + this.$propHandlers["type"].call(this, "password"); + + if (!apf.hasContentEditable && "input|textarea".indexOf(this.$input.tagName.toLowerCase()) == -1) { + var node = this.$input; + this.$input = node.parentNode.insertBefore(document.createElement("textarea"), node); + node.parentNode.removeChild(node); + this.$input.className = node.className; + if (this.$ext == node) + this.$ext = this.$input; + } + + if (this.$button) { + this.$button.onmouseup = function(){ + _self.$clear(); //@todo why are both needed for doc filter + _self.change(""); //@todo only this one should be needed + _self.focus({mouse:true}); + } + } + + //@todo for skin switching this should be removed + if (this.$input.tagName.toLowerCase() == "textarea") { + this.addEventListener("focus", function(e) { + //if (this.multiline != "optional") + //e.returnValue = false + }); + } + + this.$input.onselectstart = function(e) { + if (!e) e = event; + e.cancelBubble = true; + } + this.$input.host = this; + + this.$input.onkeydown = function(e) { + e = e || window.event; + + if (this.host.disabled) { + e.returnValue = false; + return false; + } + + //Change + if (!_self.realtime) { + var value = _self.getValue(); + if (e.keyCode == 13 && value != _self.value) + _self.change(value); + } + else if (apf.isWebkit && _self.xmlRoot && _self.getValue() != _self.value) //safari issue (only old??) + $setTimeout("var o = apf.lookup(" + _self.$uniqueId + ");\ + o.change(o.getValue())"); + + if (_self.readonly || _self.multiline == "optional" && e.keyCode == 13 && !e.shiftKey + || e.ctrlKey && (e.keyCode == 66 || e.keyCode == 73 + || e.keyCode == 85)) { + e.returnValue = false; + return false; + } + + if (typedBefore && this.getAttribute("type") == "password" && this.value != "") { + var hasClass = (_self.$ext.className.indexOf("capsLock") > -1), + capsKey = (e.keyCode === 20); + if (capsKey) // caps off + apf.setStyleClass(_self.$ext, hasClass ? null : "capsLock", hasClass ? ["capsLock"] : null); + } + + //Autocomplete + if (_self.$autoComplete || _self.oContainer) { + var keyCode = e.keyCode; + $setTimeout(function(){ + if (_self.$autoComplete) + _self.$autoComplete.fillAutocomplete(keyCode); + else + _self.fillAutocomplete(keyCode); + }); + } + + //Non this.$masking + if (!_self.mask) { + return _self.$keyHandler(e.keyCode, e.ctrlKey, + e.shiftKey, e.altKey, e); + } + }; + + this.$input.onkeyup = function(e) { + if (!e) + e = event; + + if (this.host.disabled) + return false; + + var keyCode = e.keyCode; + + if (_self.$button) + _self.$button.style.display = _self.getValue() ? "block" : "none"; + + if (_self.realtime) { + $setTimeout(function(){ + var v; + if (!_self.mask && (v = _self.getValue()) != _self.value) + _self.change(v); + if (apf.isIE) + _self.dispatchEvent("keyup", {keyCode : keyCode});//@todo + }); + } + else if (apf.isIE) { + _self.dispatchEvent("keyup", {keyCode : keyCode});//@todo + } + + + if (_self.isValid && _self.isValid() && e.keyCode != 13 && e.keyCode != 17) + _self.clearError(); + + }; + + + + if (apf.hasAutocompleteXulBug) + this.$input.setAttribute("autocomplete", "off"); + + if ("INPUT|TEXTAREA".indexOf(this.$input.tagName) == -1) { + this.isHTMLBox = true; + + this.$input.unselectable = "Off"; + this.$input.contentEditable = true; + //this.$input.style.width = "1px"; + + this.$input.select = function(){ + if (apf.hasMsRangeObject) { + var r = document.selection.createRange(); + r.moveToElementText(this); + r.select(); + } + else if (_self.isHTMLBox) { + var r = document.createRange(); + r.setStart(_self.$input.firstChild || _self.$input, 0); + var lastChild = _self.$input.lastChild || _self.$input; + r.setEnd(lastChild, lastChild.nodeType == 1 + ? lastChild.childNodes.length + : lastChild.nodeValue.length); + + var s = window.getSelection(); + s.removeAllRanges(); + s.addRange(r); + } + } + + this.$input.onpaste = function(e) { + if (apf.hasMsRangeObject) + return; + + if (e.clipboardData.types.indexOf("text/html") == -1) + return; + + var sel = window.getSelection(); + var range = sel.getRangeAt(0); + + setTimeout(function(){ + var range2 = sel.getRangeAt(0); + range2.setStart(range.startContainer, range.startOffset); + var c = range2.cloneContents(); + range2.deleteContents(); + + var d = document.body.appendChild(document.createElement("div")); + d.appendChild(c); + var p = d.innerText; + d.parentNode.removeChild(d); + + range2.insertNode(document.createTextNode(p)); + }); + }; + }; + + this.$input.deselect = function(){ + if (!document.selection) return; + + var r = document.selection.createRange(); + r.collapse(); + r.select(); + }; + + var f; + apf.addListener(this.$input, "keypress", f = function(e) { + if (_self.$input.getAttribute("type") != "password") + return apf.removeListener(_self.$input, "keypress", f); + e = e || window.event; + // get key pressed + var which = -1; + if (e.which) + which = e.which; + else if (e.keyCode) + which = e.keyCode; + + // get shift status + var shift_status = false; + if (e.shiftKey) + shift_status = e.shiftKey; + else if (e.modifiers) + shift_status = !!(e.modifiers & 4); + + if (((which >= 65 && which <= 90) && !shift_status) || + ((which >= 97 && which <= 122) && shift_status)) { + // uppercase, no shift key + apf.setStyleClass(_self.$ext, "capsLock"); + } + else { + apf.setStyleClass(_self.$ext, null, ["capsLock"]); + } + typedBefore = true; + }); + }; + + this.$loadAml = function() { + if (typeof this["initial-message"] == "undefined") + this.$setInheritedAttribute("initial-message"); + + if (typeof this.realtime == "undefined") + this.$setInheritedAttribute("realtime"); + } + + this.addEventListener("DOMNodeRemovedFromDocument", function(){ + if (this.$button) + this.$button.onmousedown = null; + + if (this.$input) { + this.$input.onkeypress = + this.$input.onmouseup = + this.$input.onmouseout = + this.$input.onmousedown = + this.$input.onkeydown = + this.$input.onkeyup = + this.$input.onselectstart = null; + } + }); + +}).call(apf.textbox.prototype = new apf.StandardBinding()); + + +apf.config.$inheritProperties["initial-message"] = 1; +apf.config.$inheritProperties["realtime"] = 1; + +apf.input.prototype = +apf.secret.prototype = +apf.password.prototype = +apf.textarea.prototype = +apf.email.prototype = apf.textbox.prototype; + +apf.aml.setElement("input", apf.input); +apf.aml.setElement("secret", apf.secret); +apf.aml.setElement("password", apf.password); +apf.aml.setElement("textarea", apf.textarea); +apf.aml.setElement("textbox", apf.textbox); + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +/** + * This element displays a bar containing buttons and other AML elements. + * + * This element is usually positioned in the top of an application allowing + * the user to choose from grouped buttons. + * + * #### Example + * + * ```xml, demo + * + * + * + * + * + * File + * Edit + * + * + * + * + * About us + * Help + * + * + * Tutorials + * Live Helps + * + * Visit Ajax.org + * Exit + * + * + * + * + * ``` + * + * @class apf.toolbar + * @define toolbar + * @container + * + * @allowchild bar, menubar + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.4 + * + * @inherits apf.Presentation + */ + +apf.toolbar = function(struct, tagName) { + this.$init(tagName || "toolbar", apf.NODE_VISIBLE, struct); +}; + +(function(){ + this.$focussable = false; + + // *** DOM Hooks *** // + + + // *** Init *** // + + this.$draw = function(){ + //Build Main Skin + this.$ext = this.$getExternal(); + this.$int = this.$getLayoutNode("main", "container", this.$ext); + }; +}).call(apf.toolbar.prototype = new apf.Presentation()); + +apf.aml.setElement("toolbar", apf.toolbar); + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * An element displaying data in a list, where each item in the list can contain + * such a list. + * + * This element gives the user the ability to walk through this + * tree of data by clicking open elements to show more elements. The tree + * can grow by fetching more data when the user requests it. + * + * + * #### Example: A Simple Tree + * + * ```xml, demo + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * ``` + * + * #### Example: Using a Model + * + * A tree using a model: + * + * ```xml, demo + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * ``` + * + * #### Example: An Inline Tree + * + * An inline tree that draws the same as the above example: + * + * ```xml, demo + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * ``` + * + * @class apf.tree + * @define tree + * @selection + * @allowchild {smartbinding} + * + * @inherits apf.BaseTree + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.4 + * + * + */ +/** + * @binding insert Determines how new data is loaded when the user expands + * an item. For instance by clicking on the + button. This way only the root nodes + * need to be loaded at the start of the application. All other children are + * received on demand when the user requests it by navigating throught the tree. + * + * #### Example + * + * This example shows an insert rule that only works on folder elements. It will + * read the directory contents using webdav and insert it under the selected + * tree node. + * + * ```xml + * + * + * + * + * + * + * + * ``` + * + */ +/** + * @attribute {String} get Sets or gets the {@link term.datainstruction data instruction} that is used to load the new data. + * + */ +/** + * @binding caption Determines the caption of a tree node. + */ +/** + * @binding icon Determines the icon of a tree node. + */ +/** + * @binding css Determines a css class for a tree node. + * + * #### Example + * + * In this example a node is bold when the folder contains unread messages: + * + * ```xml + * + * + * + * + * + * + * + * + * ``` + */ +/** + * @binding tooltip Determines the tooltip of a tree node. + */ +/** + * @binding empty Determines the empty message of a node. + * + * #### Example + * + * This example shows a grouped contact list that displays a message under + * empty groups. + * + * ```xml + * + * + * + * + * + * + * + * ``` + */ +apf.tree = function(struct, tagName) { + this.$init(tagName || "tree", apf.NODE_VISIBLE, struct); +}; + +(function(){ + var HAS_CHILD = 1 << 1, + IS_CLOSED = 1 << 2, + IS_LAST = 1 << 3, + IS_ROOT = 1 << 4, + treeState = this.$treeState; + + // *** Properties and Attributes *** // + + + + /** + * @attribute {String} mode Sets the way this element interacts with the user. + * + * The possible values are: + * - `"check"`: the user can select a single item from this element. The selected item is indicated. + * - `"radio"`: the user can select multiple items from this element. Each selected item is indicated. + */ + this.$mode = 0; + this.$propHandlers["mode"] = function(value) { + if ("check|radio".indexOf(value) > -1) { + if (!this.hasFeature(apf.__MULTICHECK__)) + this.implement(apf.MultiCheck); + + this.addEventListener("afterrename", $afterRenameMode); //what does this do? + + this.multicheck = value == "check"; //radio is single + this.$mode = this.multicheck ? 1 : 2; + } + else { + //@todo undo actionRules setting + this.removeEventListener("afterrename", $afterRenameMode); + //@todo unimplement?? + this.$mode = 0; + } + }; + + //@todo apf3.0 retest this completely + function $afterRenameMode(){ + + } + + + this.$initNode = function(xmlNode, state, Lid) { + //Setup Nodes Interaction + this.$getNewContext("item"); + + var hasChildren = state & HAS_CHILD || this.emptyMessage + && this.$applyBindRule("empty", xmlNode), + //should be restructured and combined events set per element + oItem = this.$getLayoutNode("item"); + //@todo this should use dispatchEvent, and be moved to oExt + oItem.setAttribute("onmouseover", + "var o = apf.lookup(" + this.$uniqueId + ");\ + o.$setStyleClass(this, 'hover', null, true);"); + oItem.setAttribute("onmouseout", + "var o = apf.lookup(" + this.$uniqueId + ");\ + o.$setStyleClass(this, '', ['hover'], true);"); + /*oItem.setAttribute("onmousedown", + "var o = apf.lookup(" + this.$uniqueId + ");\ + if (o.onmousedown) o.onmousedown(event, this);");*/ + + //Set open/close skin class & interaction + this.$setStyleClass(this.$getLayoutNode("item", "class"), treeState[state]).setAttribute(apf.xmldb.htmlIdTag, Lid); + this.$setStyleClass(this.$getLayoutNode("item", "container"), treeState[state]) + //this.$setStyleClass(oItem, xmlNode.tagName) + var elOpenClose = this.$getLayoutNode("item", "openclose"); + if (elOpenClose) { //hasChildren && + elOpenClose.setAttribute("children", hasChildren); + elOpenClose.setAttribute("onmousedown", + "if (this.getAttribute('children') == false) return;\ + var o = apf.lookup(" + this.$uniqueId + ");\ + o.slideToggle(this, null, null, true);\ + apf.cancelBubble(event, o);"); + + elOpenClose.setAttribute("ondblclick", "event.cancelBubble = true"); + } + + + if (this.$mode) { + var elCheck = this.$getLayoutNode("item", "check"); + if (elCheck) { + elCheck.setAttribute("onmousedown", + "var o = apf.lookup(" + this.$uniqueId + ");\ + o.checkToggle(this, true);\o.$skipSelect = true;"); + + if (apf.isTrue(this.$applyBindRule("checked", xmlNode))) { + this.$checkedList.push(xmlNode); + this.$setStyleClass(oItem, "checked"); + } + else if (this.isChecked(xmlNode)) + this.$setStyleClass(oItem, "checked"); + } + else { + + return false; + } + } + + + var ocAction = this.opencloseaction || "ondblclick"; + + //Icon interaction + var elIcon = this.$getLayoutNode("item", "icon"); + if (elIcon && elIcon != elOpenClose) { + if (ocAction != "ondblclick") { + elIcon.setAttribute(ocAction, + "var o = apf.lookup(" + this.$uniqueId + ");" + + (ocAction == "onmousedown" ? "o.select(this, apf.getCtrlKey(event), event.shiftKey, event.button);" : "") + + (true ? "o.slideToggle(this, null, null, true);" : "")); + } + if (ocAction != "onmousedown") { + elIcon.setAttribute("onmousedown", + "apf.lookup(" + this.$uniqueId + ").select(this, apf.getCtrlKey(event), event.shiftKey, event.button);"); + } + + elIcon.setAttribute("ondblclick", + "var o = apf.lookup(" + this.$uniqueId + ");\ + o.choose(null, true);" + + + "o.stopRename();" + + + (true && !ocAction == "ondblclick" ? "o.slideToggle(this, null, null, true);" : "") + + "apf.cancelBubble(event,o);"); + } + + //Select interaction + var elSelect = this.$getLayoutNode("item", "select"), + strMouseDown; + + + if (this.hasFeature(apf.__RENAME__) || this.hasFeature(apf.__DRAGDROP__)) { + strMouseDown = + 'var o = apf.lookup(' + this.$uniqueId + ');\ + var xmlNode = apf.xmldb.findXmlNode(this);\ + var isSelected = o.isSelected(xmlNode);\ + this.hasPassedDown = true;\ + if (event.button == 2) \ + o.stopRename();\ + else if (!o.renaming && o.hasFocus() && isSelected == 1) \ + this.dorename = true;\ + if (!o.hasFeature(apf.__DRAGDROP__) || !isSelected && !apf.getCtrlKey(event))\ + o.select(this, apf.getCtrlKey(event), event.shiftKey, event.button);\ + apf.cancelBubble(event, o);'; + + elSelect.setAttribute("onmouseout", 'this.hasPassedDown = false;' + (elSelect.getAttribute("onmouseout") || "")); + elSelect.setAttribute("onmouseup", 'if (!this.hasPassedDown) return;\ + var o = apf.lookup(' + this.$uniqueId + ');' + + + 'if (this.dorename && !o.mode)\ + o.startDelayedRename(event, null, true);' + + + 'this.dorename = false;\ + var xmlNode = apf.xmldb.findXmlNode(this);\ + var isSelected = o.isSelected(xmlNode);\ + if (o.hasFeature(apf.__DRAGDROP__))\ + o.select(this, apf.getCtrlKey(event), event.shiftKey, event.button);'); + } + else + + { + strMouseDown = "o.select(this, apf.getCtrlKey(event), event.shiftKey, event.button);\ + apf.cancelBubble(event, o);"; + } + + if (ocAction != "ondblclick") { + elSelect.setAttribute(ocAction, + "var o = apf.lookup(" + this.$uniqueId + ");" + + (ocAction == "onmousedown" ? strMouseDown : "") + + (true ? "o.slideToggle(this, null, null, true);" : "")); + } + if (ocAction != "onmousedown") { + elSelect.setAttribute("onmousedown", + "var o = apf.lookup(" + this.$uniqueId + ");" + strMouseDown); + } + + elSelect.setAttribute("ondblclick", + "var o = apf.lookup(" + this.$uniqueId + ");\ + o.choose(null, true);" + + + "o.stopRename();this.dorename=false;" + + + (ocAction == "ondblclick" ? "o.slideToggle(this, null, null, true);" : "") + + "apf.cancelBubble(event, o);"); + + //Setup Nodes Identity (Look) + if (elIcon) { + var iconURL = this.$applyBindRule("icon", xmlNode); + if (iconURL) { + if (elIcon.tagName.match(/^img$/i)) + elIcon.setAttribute("src", apf.getAbsolutePath(this.iconPath, iconURL)); + else + elIcon.setAttribute("style", "background-image:url(" + + apf.getAbsolutePath(this.iconPath, iconURL) + ")"); + } + } + + var elCaption = this.$getLayoutNode("item", "caption"); + if (elCaption) { + + { + apf.setNodeValue(elCaption, + this.$applyBindRule("caption", xmlNode)); + } + } + + var strTooltip = this.$applyBindRule("tooltip", xmlNode) + if (strTooltip) + oItem.setAttribute("title", strTooltip); + + + var cssClass = this.$applyBindRule("css", xmlNode); + if (cssClass) { + this.$setStyleClass(this.$getLayoutNode("item", null, oItem), cssClass); + this.$setStyleClass(this.$getLayoutNode("item", "container", oItem), cssClass); + this.$dynCssClasses.push(cssClass); + } + + + return oItem; + }; + + this.$updateNode = function(xmlNode, htmlNode) { + if (!htmlNode) return; + + var elIcon = this.$getLayoutNode("item", "icon", htmlNode), + iconURL = this.$applyBindRule("icon", xmlNode); + if (elIcon && iconURL) { + if (elIcon.tagName && elIcon.tagName.match(/^img$/i)) + elIcon.src = apf.getAbsolutePath(this.iconPath, iconURL); + else + elIcon.style.backgroundImage = "url(" + + apf.getAbsolutePath(this.iconPath, iconURL) + ")"; + } + + + //@todo + + + var elCaption = this.$getLayoutNode("item", "caption", htmlNode); + if (elCaption) { + //if (elCaption.nodeType != 1) + //elCaption = elCaption.parentNode; + + if (elCaption.nodeType == 1) { + + elCaption.innerHTML = this.$applyBindRule("caption", xmlNode); + } + else + elCaption.nodeValue = this.$applyBindRule("caption", xmlNode); + } + + var strTooltip = this.$applyBindRule("tooltip", xmlNode); + if (strTooltip) + htmlNode.setAttribute("title", strTooltip); + + + var cssClass = this.$applyBindRule("css", xmlNode); + if (cssClass || this.$dynCssClasses.length) { + this.$setStyleClass(htmlNode, cssClass, this.$dynCssClasses); //@todo overhead! + if (cssClass && !this.$dynCssClasses.contains(cssClass)) { + if (this.$dynCssClasses.indexOf(cssClass) == -1) + this.$dynCssClasses.push(cssClass); + } + } + + }; + + // *** Init *** // + + this.$draw = function(){ + this.$drawBase(); + }; +}).call(apf.tree.prototype = new apf.BaseTree()); + +apf.aml.setElement("tree", apf.tree); + +apf.aml.setElement("checked", apf.BindingRule); + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/* + * Element implementing WebDAV remote filesystem protocol. + * WebDAV stands for "Web-based Distributed Authoring and Versioning". It is a + * set of extensions to the HTTP protocol which allows users to collaboratively + * edit and manage files on remote web servers (from: {@link http://www.webdav.org}. + * This Object aims to be a complete implementation of {@link http://www.webdav.org/specs/rfc4918.html RFC4981} + * and provides a scriptable interface to any WebDAV server. + * Example: + * Writing to a file with a WebDAV connector + * + * + * + * + * // write the text 'bar' to a file on the server called 'foo.txt' + * myWebDAV.writeFile('http://my-webdav-server.com/dav_files/foo.txt', 'bar'); + * + * + * + * Remarks: + * Calls can be made to a server using a special {@link term.datainstruction data instruction} + * format. + * + * get="{myWebdav.authenticate([@username], [@password])}" + * get="{myWebdav.login(...alias for authenticate...)}" + * set="{myWebdav.logout()}" + * get="{myWebdav.read([@path])}" + * get="{myWebdav.create([@path], 'New File.txt', '')}" + * set="{myWebdav.write([@path], [@data])}" + * set="{myWebdav.store(...alias for write...)}" + * set="{myWebdav.save(...alias for write...)}" + * set="{myWebdav.copy([@path], [../@path])}" + * set="{myWebdav.cp(...alias for copy...)}" + * set="{myWebdav.rename([@name], [@path])}" + * set="{myWebdav.move([@path], [../@path])}" + * set="{myWebdav.mv(...alias for move...)}" + * set="{myWebdav.remove([@path])}" + * set="{myWebdav.rmdir(...alias for remove...)}" + * set="{myWebdav.rm(...alias for remove...)}" + * set="{myWebdav.mkdir([@path])}" + * get="{myWebdav.readdir([@path])}" + * get="{myWebdav.scandir(...alias for readdir...)}" + * load="{myWebdav.getroot()}" + * set="{myWebdav.lock([@path])}" + * set="{myWebdav.unlock([@path])}" + * + * + * @event authfailure Fires when the authentication process failed or halted. + * bubbles: yes + * cancelable: Prevents an authentication failure to be thrown + * @param {Object} e + * {String} username the username used for the login attempt + * {String} server the server address (URI) of the XMPP server + * {String} message a more detailed explanation of the error + * @event connectionerror Fires when the connection with the WebDAV server dropped. + * bubbles: yes + * cancelable: Prevents an connection error to be thrown + * @param {Object} e + * {String} username the username used for the last-active session + * {String} server the server address (URI) of the WebDAV server + * {String} message a more detailed explanation of the error + * @event onfilecontents Fires when a {@link teleport.webdav.method.read read} request has + * completed successfully and returns the content-body of the requested file + * bubbles: yes + * @param {Object} e + * {String} data the ASCI representation of the file content-body + * + * @define webdav + * + * + * @author Mike de Boer + * @version %I%, %G% + * @since 1.0 + * @constructor + * + * @inherits apf.Class + * @inherits apf.BaseComm + * @inherits apf.http + * + * + * @default_private + */ + +apf.webdav = function(struct, tagName) { + this.$init(tagName || "webdav", apf.NODE_HIDDEN, struct); + + this.$locks = {}; + this.$lockedStack = []; + this.$lockId = 0; + this.$serverVars = {}; + this.$fsCache = {}; +}; + +(function() { + this.useHTTP = true; + this.method = "GET"; + + this.$showHidden = false; + + /** + * @attribute {String} [show-hidden] Flag that specifies if hidden files + * should be passed + */ + this.$booleanProperties["showhidden"] = true; + this.$booleanProperties["extra-properties"] = true; + this.$supportedProperties.push("showhidden", "extra-properties", "force-host"); + + this.$propHandlers["showhidden"] = function(value) { + this.$showHidden = value; + }; + + /* + * Simple helper function to store session variables in the private space. + * + * @param {String} name + * @param {Mixed} value + * @type {Mixed} + * @private + */ + this.$regVar = function(name, value) { + this.$serverVars[name] = value; + + return value; + }; + + /* + * Simple helper function to complete remove variables that have been + * stored in the private space by register() + * + * @param {String} name + * + * @private + */ + function unregister() { + for (var i = 0; i < arguments.length; i++) { + if (typeof this.$serverVars[arguments[i]] != "undefined") { + this.$serverVars[arguments[i]] = null; + delete this.$serverVars[arguments[i]]; + } + } + } + + /* + * Simple helper function that retrieves a variable, stored in the private + * space. + * + * @param {String} name + * @type {Mixed} + * @private + */ + this.$getVar = function(name) { + return this.$serverVars[name] || ""; + }; + + /** + * Wrapper function that handles and executes each HTTP request. It also takes + * care of streams that are incomplete or different than usual, thus produce + * invalid XML that needs to be tidied prior to processing. + * It also takes care of processing authentication process/ negotiation + * + * @param {Function} fCallback Function to execute when the request was successful + * @param {String} sPath Path to the WebDAV resource + * @param {String} [sBody] Optional body text (used for PUTs, for example) + * @param {Object} [oHeaders] Additional headers in key: value format + * @param {Boolean} [bUseXml] Tells the function whether to return XML. Defaults to FALSE + * @param {Object} [oBinary] Object with properties for binary upload in modern browsers + * @param {Function} [fCallback2] Optional second callback, passed to fCallback as arguments. Used mainly by the data instructions + * + */ + this.doRequest = function(fCallback, sPath, sBody, oHeaders, bUseXml, oBinary, fCallback2) { + if (!this.$getVar("authenticated")) { + return onAuth.call(this, { + method: this.doRequest, + context: this, + args: arguments + }); + } + + if (bUseXml) { + if (!oHeaders) + oHeaders = {}; + oHeaders["Content-type"] = "text/xml; charset=utf-8"; + } + + var fHost = this["force-host"]; + if (fHost && sPath.indexOf(fHost) === -1) + sPath = fHost.replace(/[\/]+$/, "") + "/" + sPath.replace(/^[\/]+/, ""); + + var _self = this; + return this.get(sPath || this.$server, { + callback: function(data, state, extra) { + if (state != apf.SUCCESS) { + var oError; + + oError = WebDAVError.call(_self, "Url: " + extra.url + "\nInfo: " + extra.message); + + //if (extra.tpModule.retryTimeout(extra, state, _self, oError) === true) + // return true; + if (fCallback) + return fCallback.call(_self, data, state, extra, fCallback2); + else + throw oError; + } + + extra.headers = oHeaders; + + var iStatus = parseInt(extra.status, 10); + if (iStatus == 401) //authentication requested + return; // 401's are handled by the browser already, so no need for additional processing... + + var sResponse = (extra.http.responseText || ""); + if ((sResponse.length > 10 || sResponse.replace(/^[\s\n\r]+|[\s\n\r]+$/g, "") != "") + && sResponse.substr(0, 14) == ""} + : null, true); + }; + + /** + * Reads the properties of a resource on the server. + * + * + * @param {String} sPath Path to the resource on the WebDAV server + * @param {Function} callback Function to execute when the request was successful + * + */ + this.list = function(sPath, callback) { + return this.getProperties(sPath, 0, callback); + }; + + /** + * Write new contents (plaintext) to a file resource on the server, with or + * without an existing lock on the resource. + * + * @param {String} sPath Path to the file on the WebDAV server + * @param {String} sContent New content-body of the file + * @param {Boolean} [bLock] Whether to require a lock before write + * @param {Object} [oBinary] Object with properties for binary upload in modern browsers + * @param {Function} callback Function to execute when the request was successful + * + */ + this.writeFile = + this.write = function(sPath, sContent, bLock, oBinary, callback) { + if (bLock) { + var oLock = this.lock(sPath); + if (!oLock.token) + return updateLockedStack.call(this, oLock, "write", arguments); + } + // binary option has been added later, keep fallback possible + if (typeof callback == "undefined" && typeof oBinary == "function") { + callback = oBinary; + oBinary = null; + } + + this.method = "PUT"; + var _self = this; + this.doRequest(function(data, state, extra) { + var iStatus = parseInt(extra.status, 10); + if (state != apf.SUCCESS) { + var oError = WebDAVError.call(this, "Unable to write to file. Server says: " + + apf.webdav.STATUS_CODES[String(iStatus)]); + if (this.dispatchEvent("error", { + error: oError, + bubbles: true + }) === false && !callback) + throw oError; + return callback && callback.call(this, data, apf.ERROR, extra); + } + else { + _self.getProperties(sPath, 0, callback); + } + }, sPath, sContent, bLock && oLock.token + ? {"If": "<" + oLock.token + ">"} + : null, null, oBinary); + }; + + /** + * Copies a file or directory resource to any location on the same WebDAV + * server. + * + * @param {String} sFrom Path to the file on the WebDAV server to be copied + * @param {String} sTo New location to place the copy at + * @param {Boolean} [bOverwrite] Tells whether to overwrite any existing resource + * @param {Boolean} [bLock] Whether to require a lock before copy + * @param {Function} callback Function to execute when the request was successful + * + */ + this.copy = function(sFrom, sTo, bOverwrite, bLock, callback) { + if (!sTo || sFrom == sTo) + return (callback && callback("", apf.SUCCESS, {})); + + if (bLock) { + var oLock = this.lock(sFrom); + if (!oLock.token) + return updateLockedStack.call(this, oLock, "copy", arguments); + } + + this.method = "COPY"; + var oHeaders = { + "Destination": sTo || this.$server + }; + if (typeof bOverwrite == "undefined") + bOverwrite = true; + if (!bOverwrite) + oHeaders["Overwrite"] = "F"; + if (bLock && oLock.token) + oHeaders["If"] = "<" + oLock.token + ">"; + this.doRequest(function(data, state, extra) { + bLock && unregisterLock.call(this, sFrom); + var iStatus = parseInt(extra.status, 10); + if (iStatus == 400 || iStatus == 403 || iStatus == 409 || iStatus == 412 + || iStatus == 423 || iStatus == 424 || iStatus == 502 + || iStatus == 507) { + var oError = WebDAVError.call(this, "Unable to copy file '" + sFrom + + "' to '" + sTo + "'. Server says: " + + apf.webdav.STATUS_CODES[String(iStatus)]); + if (this.dispatchEvent("error", { + error: oError, + bubbles: true + }) === false && !callback) + throw oError; + } + callback && callback.call(this, data, state, extra); + }, sFrom, null, oHeaders); + }; + + /** + * Moves a file or directory resource to any location on the same WebDAV + * server. + * + * @param {String} sFrom Path to the file on the WebDAV server to be moved + * @param {String} sTo New location to move the resource to + * @param {Boolean} [bOverwrite] Tells whether to overwrite any existing resource + * @param {Boolean} [bLock] Whether to require a lock before move + * @param {Function} callback Function to execute when the request was successful + * + */ + this.rename = + this.move = function(sFrom, sTo, bOverwrite, bLock, callback) { + if (!sTo || sFrom == sTo) + return (callback && callback("", apf.SUCCESS, {})); + + if (bLock) { + var oLock = this.lock(sFrom); + if (!oLock.token) + return updateLockedStack.call(this, oLock, "move", arguments); + } + + this.method = "MOVE"; + var oHeaders = { + "Destination": sTo || this.$server + }; + if (typeof bOverwrite == "undefined") + bOverwrite = true; + if (!bOverwrite) + oHeaders["Overwrite"] = "F"; + if (bLock && oLock.token) + oHeaders["If"] = "<" + oLock.token + ">"; + this.doRequest(function(data, state, extra) { + bLock && unregisterLock.call(this, sFrom); + var iStatus = parseInt(extra.status, 10); + if (iStatus == 400 || iStatus == 403 || iStatus == 409 || iStatus == 412 + || iStatus == 423 || iStatus == 424 || iStatus == 501 || iStatus == 502 || iStatus == 500) { + var oError = WebDAVError.call(this, "Unable to move file '" + sFrom + + "' to '" + sTo + "'. Server says: " + + apf.webdav.STATUS_CODES[String(iStatus)]); + if (this.dispatchEvent("error", { + error: oError, + bubbles: true + }) === false && !callback) + throw oError; + } + else { //success!! + if (this.$fsCache[sFrom]) { + this.$fsCache[sTo] = this.$fsCache[sFrom]; + this.$fsCache[sTo].path = sTo; + delete this.$fsCache[sFrom]; + } + } + callback && callback.call(this, data, state, extra); + }, sFrom, null, oHeaders); + }; + + /** + * Removes an existing directory or file resource from the WebDAV server. + * + * @param {String} sPath Path to the resource to be removed from the WebDAV server + * @param {Boolean} [bLock] Whether to require a lock before remove + * @param {Function} callback Function to execute when the request was successful + * + */ + this.remove = function(sPath, bLock, callback) { + if (bLock) { + var oLock = this.lock(sPath); + if (!oLock.token) + return updateLockedStack.call(this, oLock, "remove", arguments); + } + + this.method = "DELETE"; + this.doRequest(function(data, state, extra) { + bLock && unregisterLock.call(this, sPath); + var iStatus = parseInt(extra.status, 10); + if (iStatus == 400 || iStatus == 423 || iStatus == 424) { //Failed dependency (collections only) + var oError = WebDAVError.call(this, "Unable to remove file '" + sPath + + "'. Server says: " + + apf.webdav.STATUS_CODES[String(iStatus)]); + if (this.dispatchEvent("error", { + error: oError, + bubbles: true + }) === false && !callback) + throw oError; + } + callback && callback.call(this, data, state, extra); + }, sPath, null, bLock && oLock.token + ? {"If": "<" + oLock.token + ">"} + : null); + }; + + this.report = function(sPath, reportName, oProperties, callback) { + var aCont = ['', + '']; + if (oProperties) { + for (var prop in oProperties) { + aCont.push("" + apf.escapeXML(oProperties[prop]) + "" + : "/>")); + } + } + aCont.push(""); + + this.method = "REPORT"; + + return this.doRequest(function(data, state, extra) { + var iStatus = parseInt(extra.status, 10); + if (state != apf.SUCCESS) { + var oError = WebDAVError.call(this, "Unable to fetch report on '" + sPath + + "'. Server says: " + + apf.webdav.STATUS_CODES[String(iStatus)]); + if (this.dispatchEvent("error", { + error: oError, + bubbles: true + }) === false && !callback) + throw oError; + } + callback && callback.call(this, data, state, extra); + }, sPath, aCont.join("")); + }; + + /** + * Wrapper function that centrally manages locking of resources. Files and + * directories (resources) can be locked prior to any modifying operation to + * prevent the resource being modified by another user before the transaction + * of this user has finished or even started. + * + * + * @param {String} sPath Path to the resource on the server to be locked + * @param {Number} [iDepth] Depth of lock recursion down the tree, should be '1' or 'Infinity' + * @param {Number} [iTimeout] Lifetime of the lock, in seconds. Defaults to Infinite. + * @param {String} [sLock] Previous lock token + * @param {Function} [callback] Function that is executed upon a successful LOCK request + * @type {Object} + */ + this.lock = function(sPath, iDepth, iTimeout, sLock, callback) { + // first, check for existing lock + var oLock = this.$locks[sPath]; + if (oLock && oLock.token) { + //@todo renew the lock (if needed - check timeout)... + return oLock; + } + + this.method = "LOCK" + + iTimeout = iTimeout ? "Infinite, Second-4100000000" : "Second-" + iTimeout; + var oHeaders = { + "Timeout": iTimeout + }; + if (iDepth) + oHeaders["Depth"] = iDepth || "Infinity"; + if (sLock) + oHeaders["If"] = "<" + sLock + ">"; + var xml = '' + + '' + + '' + + '' + + '' + + document.location.toString().escapeHTML() + + + '' + + ''; + this.doRequest(registerLock, sPath, xml, oHeaders, true, null, callback); + return newLock.call(this, sPath); + }; + + /** + * Wrapper function that centrally manages the unlocking of resources that + * have been locked earlier on. + * + * @param {Object} oLock Object representing a Lock on a resource + * @param {Function} callback Function that is executed upon a successful UNLOCK request + * + */ + this.unlock = function(oLock, callback) { + if (typeof oLock == "string") + oLock = this.$locks[oLock]; + if (!oLock || !oLock.token) return; + + this.method = "UNLOCK"; + this.doRequest(function(data, state, extra) { + unregisterLock.call(this, extra.url.replace(this.$server, "")); + }, oLock.path, null, { + "Lock-Token": "<" + oLock.token + ">" + }, true, callback); + }; + + /* + * Add a new lock token/ object to the stack + * + * @path {String} sPath Path pointing to the resource on the server + * @type {Object} + * @private + */ + function newLock(sPath) { + return this.$locks[sPath] = { + path: sPath, + id: this.$lockId++, + token: null + }; + } + + /* + * Handler function that registers a lock globally when a LOCK request was + * successful. It parses all the info it received from the server response + * and caches that info for reuse. + * + * @param {XmlDocument} data Actual XML data, received from the server + * @param {Number} state Internal - APF defined - state of the request + * @param {Object} extra Simple object that contains additional request data + * + * @private + */ + function registerLock(data, state, extra) { + var iStatus = parseInt(extra.status, 10), + sPath = extra.url.replace(this.$server, ""), + oLock = this.$locks[sPath] || newLock.call(this, sPath); + if (iStatus == 400 || iStatus == 409 || iStatus == 423 || iStatus == 412) { + // lock failed, so unregister it immediately + unregisterLock.call(this, extra.url.replace(this.$server, "")); + var oError = WebDAVError.call(this, "Unable to apply lock to '" + sPath + + "'. Server says: " + + apf.webdav.STATUS_CODES[String(iStatus)]); + if (this.dispatchEvent("error", { + error: oError, + bubbles: true + }) === false) + throw oError; + } + + var NS = apf.webdav.NS, + oOwner = $xmlns(data, "owner", NS.ns0)[0], + oToken = $xmlns(data, "locktoken", NS.D)[0]; + oLock.path = sPath; + oLock.type = "write"; + oLock.scope = $xmlns(data, "exclusive", NS.D).length ? "exclusive" : "shared"; + oLock.depth = $xmlns(data, "depth", NS.D)[0].firstChild.nodeValue; + oLock.owner = $xmlns(oOwner, "href", NS.ns0)[0].firstChild.nodeValue; + oLock.timeout = $xmlns(data, "timeout", NS.D)[0].firstChild.nodeValue; + oLock.token = $xmlns(oToken, "href", NS.D)[0].firstChild.nodeValue.split(":")[1]; + + purgeLockedStack.call(this, oLock); + } + + /* + * Removes a Lock token/ object from the stack. + * + * @param {String} sPath Path pointing to the resource on the server + * + * @private + */ + function unregisterLock(sPath) { + var oLock = this.$locks[sPath]; + if (!oLock) return; + purgeLockedStack.call(this, oLock, true); + this.$locks[sPath] = oLock = null; + delete this.$locks[sPath]; + } + + /* + * Update the stack of lock requests (NOT the stack of valid locks!) with a + * new Lock, or an updated one (lifetime may have changed) + * + * @param {Object} oLock Object that contains specific info about the Lock + * @param {String} sFunc Name of the function that requested the lock + * @param {Array} aArgs List of arguments that should get passed to that function when the lock is available + * @type {Object} + * @private + */ + function updateLockedStack(oLock, sFunc, aArgs) { + return this.$lockedStack.push({ + lockId: oLock.id, + func: sFunc, + args: aArgs + }); + } + + /* + * Purge the stack of lock requests, called when a lock request returned a + * result. If bFailed is set to TRUE, the function that requested the lock + * will be executed. + * + * @param {Object} oLock Simple object that represents a validated Lock + * @param {Boolean} bFailed Tells whether the requesting function may be excuted + * + * @private + */ + function purgeLockedStack(oLock, bFailed) { + for (var i = this.$lockedStack.length - 1; i >= 0; i--) { + if (this.$lockedStack[i].lockId != oLock.id) continue; + if (!bFailed) + this[this.$lockedStack[i].func].apply(this, this.$lockedStack[i].args); + this.$lockedStack.remove(i); + } + } + + /** + * Request the server to list the properties of a specific resource and, + * possibly, its children. + * + * @param {String} sPath Path pointing to the resource on the server + * @param {Number} iDepth Depth of lock recursion down the tree, should be '1' or 'Infinity' + * @param {Function} callback Function that is executed upon a successful LOCK request + * @param {Object} oHeaders Additional headers in key: value format + * + */ + this.getProperties = function(sPath, iDepth, callback, oHeaders) { + // Note: caching is being done by an external model + this.method = "PROPFIND"; + // XXX maybe we want to change this to allow getting selected props + var xml = '' + + '' + + '' + + ''; + oHeaders = oHeaders || {}; + oHeaders["Depth"] = typeof iDepth != "undefined" ? iDepth : 1 + this.doRequest(parsePropertyPackets, sPath, xml, oHeaders, true, null, callback); + }; + + /** + * Request the server to change and set properties of a specific resource + * with different values. + * @todo Untested functionality + * + * @param {String} sPath Path pointing to the resource on the server + * @param {Object} oPropsSet A mapping from namespace to a mapping of key/value pairs (where value is an *entitized* XML string) + * @param {Object} oPropsDel A mapping from namespace to a list of names + * @param {String} sLock Lock identifier + * @private + */ + this.setProperties = function(sPath, oPropsSet, oPropsDel, sLock) { + this.method = "PROPPATCH"; + + this.doRequest(function(data, state, extra) { + + }, sPath, buildPropertiesBlock.call(this, oPropsSet, oPropsDel), + sLock ? {"If": "<" + sLock + ">"} : null, true); + }; + + /* + * create the XML for a PROPPATCH request. + * + * @param {Object} oPropsSet A mapping from namespace to a mapping of key/value pairs (where value is an *entitized* XML string) + * @param {Object} oPropsDel A mapping from namespace to a list of names + * @type {String} + * @private + */ + function buildPropertiesBlock(oPropsSet, oPropsDel) { + var aOut = ['', + '']; + + var bHasProps = false, ns, i, j; + for (ns in oPropsSet) { + bHasProps = true; + break; + } + if (bHasProps) { + aOut.push(""); + for (ns in oPropsSet) { + for (i in oPropsSet[ns]) + aOut.push("", oPropsSet[ns][i], "") + } + aOut.push(""); + } + bHasProps = false; + for (ns in oPropsDel) { + bHasProps = true; + break; + } + if (bHasProps) { + aOut.push(""); + for (ns in oPropsDel) { + for (i = 0, j = oPropsDel[ns].length; i < j; i++) + aOut.push('<', oPropsDel[ns][i], ' xmlns="', ns, '"/>') + } + aOut.push(""); + } + + aOut.push(""); + return aOut.join(""); + } + + /* + * Handler function that parses the response of a successful PROPFIND + * request. It parses all the info it received from the server response + * and caches that info for reuse. + * + * @param {XmlDocument} data Actual XML data, received from the server + * @param {Number} state Internal - APF defined - state of the request + * @param {Object} extra Simple object that contains additional request data + * @param {Function} callback Function to be executed when all the property packets have been parsed + * + * @private + */ + function parsePropertyPackets(oXml, state, extra, callback) { + var status = parseInt(extra.status, 10); + if (status == 403 || status == 401 || !oXml) + return callback ? callback.call(this, null, state, extra) : notAuth.call(this); + + if (typeof oXml == "string") + oXml = apf.getXml(oXml); + + var aResp = $xmlns(oXml, "response", apf.webdav.NS.D); + var aOut = []; + if (aResp.length) //we got a valid result set, so assume that any possible AUTH has succeeded + this.$regVar("authenticated", true); + + var sPath; + for (var sa = [], data, i = 0, j = aResp.length; i < j; i++) { + // Exclude requesting URL if it matches node's HREF (same node) + sPath = decodeURIComponent($xmlns(aResp[i], "href", apf.webdav.NS.D)[0].firstChild.nodeValue); + if (sPath === extra.url) + continue; + + parseItem.call(this, aResp[i], data = {}); + if (data.data) { + sa.push({ + toString: function(){ + return this.v; + }, + data: data.data, + v: (data.data.type == "file" ? 1 : 0) + "" + data.data.name.toLowerCase() + }); + } + } + + sa.sort(); + + for (var i = 0, l = sa.length; i < l; i++) { + aOut.push(sa[i].data.xml); + } + +// var start = (extra.headers && typeof extra.headers.Depth != "undefined" && extra.headers.Depth == 0) ? 0 : 1; +// for (var i = start, j = aResp.length; i < j; i++) +// aOut.push(parseItem.call(this, aResp[i])); + + callback && callback.call(this, "" + aOut.join("") + "", state, extra); + } + + /* + * Turn an XML WebDAV node that represents a resource and turn it into a + * reusable JS object, cache it so that it can be reused later. + * + * @param {XmlNode} oNode + * @type {String} + * @private + */ + function parseItem(oNode, extra) { + var NS = apf.webdav.NS, + sPath = decodeURIComponent($xmlns(oNode, "href", NS.D)[0].firstChild + .nodeValue.replace(/[\\\/]+$/, "")), + sName = sPath.split("/").pop(), + bHidden = (sName.charAt(0) == "."); + + if (!this.$showHidden && bHidden) + return ""; + + var t, oItem, + sType = $xmlns(oNode, "collection", NS.D).length > 0 ? "folder" : "file", + aCType = $xmlns(oNode, "getcontenttype", NS.D), + aExec = $xmlns(oNode, "executable", NS.lp2); + oItem = this.$fsCache[sPath] = apf.extend(this.$fsCache[sPath] || {}, { + path: sPath, + type: sType, + size: parseInt(sType == "file" + ? (t = $xmlns(oNode, "getcontentlength", NS.lp1)).length ? t[0].firstChild.nodeValue : 0 + : 0, 10), + name: sName, + contentType: (sType == "file" && aCType.length + ? aCType[0].firstChild.nodeValue + : ""), + creationDate: (t = $xmlns(oNode, "creationdate", NS.lp1)).length ? t[0].firstChild.nodeValue : "", + lastModified: (t = $xmlns(oNode, "getlastmodified", NS.lp1)).length ? t[0].firstChild.nodeValue : "", + etag: (t = $xmlns(oNode, "getetag", NS.lp1)).length ? t[0].firstChild.nodeValue : "", + lockable: ($xmlns(oNode, "locktype", NS.D).length > 0), + executable: (aExec.length > 0 && aExec[0].firstChild.nodeValue == "T") + }); + + if (extra) + extra.data = oItem; + + var aXml = ["<" + sType + " path=\"" + apf.escapeXML(sPath) + + "\" type=\"" + sType + "\" size=\"" + oItem.size + "\" name=\"" + + apf.escapeXML(oItem.name) + "\" contenttype=\"" + oItem.contentType + + "\" modifieddate=\"" + oItem.lastModified + "\" creationdate=\"" + + oItem.creationDate + "\" lockable=\"" + oItem.lockable.toString() + + "\" hidden=\"" + bHidden.toString() + "\" executable=\"" + + oItem.executable.toString() + "\""]; + + if (this["extra-properties"]) { + var oNode, + aNodes = oNode.selectNodes("//a:*"), + i = 0, + l = aNodes.length; + for (; i < l; ++i) { + oNode = aNodes[i]; + if (oNode.firstChild && oNode.firstChild.nodeValue) { + aXml.push(" " + oNode.localName + "=\"" + + oNode.firstChild.nodeValue + "\""); + } + } + } + + return oItem.xml = aXml.join("") + "/>"; + } + + + + /** + * Instruction handler for WebDav protocols. + */ + this.exec = function(method, args, callback) { + var cb = function(data, state, extra) { + extra.originalArgs = args + if (typeof args[args.length - 1] == "function") + args[args.length - 1](data, state, extra); + callback && callback(data, state, extra); + }; + // RULE for case aliases: first, topmost match is the preferred term for any + // action and should be used in demos/ examples in + // favor of other aliases. + switch (method) { + case "login": + case "authenticate": + this.authenticate(args[0], args[1], cb); + break; + case "logout": + this.reset(); + break; + case "exists": + this.exists(args[0], cb); + break; + case "read": + this.readFile(args[0], cb); + break; + case "create": + var path = args[0] ? args[0] : ""; + if (path.charAt(path.length - 1) != "/") + path = path + "/"; + this.writeFile(path + args[1], args[2], args[3] || false, cb); + break; + case "write": + case "store": + case "save": + this.writeFile(args[0], args[1], args[2] || false, cb); + break; + case "copy": + case "cp": + this.copy(args[0], args[1], args[2] || true, args[3] || false, cb); + break; + case "rename": + var sBasepath = args[1].substr(0, args[1].lastIndexOf("/") + 1); + this.rename(args[1], sBasepath + args[0], args[2] || false, args[3] || false, cb); + break; + case "move": + case "mv": + path = args[1]; + if (path.charAt(path.length - 1) != "/") + path = path + "/"; + this.rename(args[0], path + args[0].substr(args[0].lastIndexOf("/") + 1), + args[2] || false, args[3] || false, cb); + break; + case "remove": + case "rmdir": + case "rm": + this.remove(args[0], args[1] || false, cb); + break; + case "readdir": + case "scandir": + this.readdir(args[0], cb); + break; + case "getroot": + this.getProperties(this.$rootPath, 0, cb); + break; + case "mkdir": + path = args[0] ? args[0] : ""; + if (path.charAt(path.length - 1) != "/") + path = path + "/"; + this.mkdir(path + args[1], args[2] || false, cb) + break; + case "lock": + this.lock(args[0], null, null, null, cb); + break; + case "unlock": + this.unlock(args[0], cb); + break; + case "report": + this.report(args[0], args[1], args[2], cb); + break; + default: + + break; + } + }; + + +}).call(apf.webdav.prototype = new apf.Teleport()); + +apf.aml.setElement("webdav", apf.webdav); + +// Collection of shorthands for all namespaces known and used by this class +apf.webdav.NS = { + D: "DAV:", + ns0 : "DAV:", + lp1 : "DAV:", + lp2 : "http://apache.org/dav/props/" +}; + +apf.webdav.STATUS_CODES = { + "100": "Continue", + "101": "Switching Protocols", + "102": "Processing", + "200": "OK", + "201": "Created", + "202": "Accepted", + "203": "None-Authoritive Information", + "204": "No Content", + "1223": "No Content", + "205": "Reset Content", + "206": "Partial Content", + "207": "Multi-Status", + "300": "Multiple Choices", + "301": "Moved Permanently", + "302": "Found", + "303": "See Other", + "304": "Not Modified", + "305": "Use Proxy", + "307": "Redirect", + "400": "Bad Request", + "401": "Unauthorized", + "402": "Payment Required", + "403": "Forbidden", + "404": "Not Found", + "405": "Method Not Allowed", + "406": "Not Acceptable", + "407": "Proxy Authentication Required", + "408": "Request Time-out", + "409": "Conflict", + "410": "Gone", + "411": "Length Required", + "412": "Precondition Failed", + "413": "Request Entity Too Large", + "414": "Request-URI Too Large", + "415": "Unsupported Media Type", + "416": "Requested range not satisfiable", + "417": "Expectation Failed", + "422": "Unprocessable Entity", + "423": "Locked", + "424": "Failed Dependency", + "500": "Internal Server Error", + "501": "Not Implemented", + "502": "Bad Gateway", + "503": "Service Unavailable", + "504": "Gateway Time-out", + "505": "HTTP Version not supported", + "507": "Insufficient Storage"//, +// 12002 ERROR_INTERNET_TIMEOUT +// 12007 ERROR_INTERNET_NAME_NOT_RESOLVED +// 12029 ERROR_INTERNET_CANNOT_CONNECT +// 12030 ERROR_INTERNET_CONNECTION_ABORTED +// 12031 ERROR_INTERNET_CONNECTION_RESET +// 12152 ERROR_HTTP_INVALID_SERVER_RESPONSE +}; + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * UndoData is the command object for the actiontracker. Each instance of this class + * contains information about a single event in the application. It can be undone, + * and it knows how to synchronize the change to a (remote) data source. + * + * @class apf.UndoData + * @default_private + */ +apf.UndoData = function(settings, at) { + this.localName = "UndoData"; + this.extra = {}; + + this.rdbQueue = {}; + + apf.extend(this, settings); + + if (!this.timestamp) + this.timestamp = (new Date()).getUTCTime(); + + if (at) + this.at = at; + //Copy Constructor + else if (settings && settings.tagName == "UndoData") { + this.args = settings.args.slice(); + + this.rdbArgs = settings.rdbArgs.slice(); + + } + //Constructor + else { + /* + @todo: Please check the requirement for this and how to solve + this. Goes wrong with multiselected actions! + */ + this.selNode = this.selNode || (this.action == "removeNode" + ? this.args[0] + : (this.amlNode + ? this.amlNode.selected + : null)); + } + + var options, _self = this; + + + + + //Send RDB Message.. + this.processRsbQueue = function(){ + if (this.rdbModel) + this.rdbModel.rdb.$processQueue(this); + }; + + this.clearRsbQueue = function(){ + this.rdbQueue = + this.rdbModel = null; + }; + + + /** + * Save the change to a data source. + * @param {Boolean} undo Specifies whether the change is undone. + */ + this.saveChange = function(undo, at, callback) { + //Grouped undo/redo support + if (this.action == "group") { + var rpcNodes = this.args[1]; + at.$addToQueue(rpcNodes, undo, true); + return at.$queueNext(this); + } + + var dataInstruction; + if (this.xmlActionNode) { + dataInstruction = this.xmlActionNode.getAttribute(undo ? "undo" : "set"); + if (undo && !dataInstruction) + dataInstruction = this.xmlActionNode.getAttribute("set"); + } + + if (!dataInstruction) { + + this.processRsbQueue(); + + return at.$queueNext(this); + } + + this.state = undo ? "restoring" : "saving"; + + if (!options.asyncs) { //Precall didnt contain any async calls + return at.$receive(null, apf.SUCCESS, {amlNode: this.amlNode}, + this, callback); + } + + options.ignoreOffline = true; + apf.saveData(dataInstruction, options); + }; + + this.preparse = function(undo, at, multicall, callback) { + var dataInstruction; + if (this.xmlActionNode) { + dataInstruction = this.xmlActionNode.getAttribute(undo ? "undo" : "set"); + if (undo && !dataInstruction) + dataInstruction = this.xmlActionNode.getAttribute("set"); + } + + if (!dataInstruction) + return this; + + options = apf.extend({ + xmlNode: this.action == "multicall" + ? this.args[0].xmlNode + : this.selNode || this.xmlNode, + userdata: apf.isTrue(this.xmlActionNode.getAttribute("ignore-fail")), + multicall: multicall, + undo: undo, + precall: true, + + //Callback is only for async calls + callback: function(data, state, extra) { + if (options.asyncs) { //Set by apf.saveData + extra.amlNode = _self.amlNode; + return at.$receive(data, state, extra, _self, callback); + } + } + }, this.extra); + + + + apf.saveData(dataInstruction, options); //@todo please check if at the right time selNode is set + + return this; + }; +}; + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +/** + * Default actions, that are known to the actiontracker + * @todo test if the .extra speed impact matters + * @todo ifdef the undo sections to only be there when the actiontracker is enabled + * @private + */ +apf.actiontracker.actions = { + "setTextNode" : function(undoObj, undo) { + var q = undoObj.args; + + // Set Text Node + if (!undo) + apf.xmldb.setTextNode(q[0], q[1], q[2], undoObj); + else //Undo Text Node Setting + apf.xmldb.setTextNode(q[0], undoObj.extra.oldValue, q[2], undoObj); + }, + + "setAttribute" : function(undoObj, undo) { + var q = undoObj.args; + + // Set Attribute + if (!undo) { + //Set undo info + undoObj.extra.name = q[1]; + undoObj.extra.oldValue = q[0].getAttribute(q[1]); + + apf.xmldb.setAttribute(q[0], q[1], q[2], q[3], undoObj); + } + // Undo Attribute Setting + else { + if (!undoObj.extra.oldValue) + apf.xmldb.removeAttribute(q[0], q[1], null, undoObj); + else + apf.xmldb.setAttribute(q[0], q[1], undoObj.extra.oldValue, q[3], undoObj); + } + }, + + "removeAttribute" : function(undoObj, undo) { + var q = undoObj.args; + + // Remove Attribute + if (!undo) { + // Set undo info + undoObj.extra.name = q[1]; + undoObj.extra.oldValue = q[0].getAttribute(q[1]); + + apf.xmldb.removeAttribute(q[0], q[1], q[2], undoObj); + } + //Undo Attribute Removal + else + apf.xmldb.setAttribute(q[0], q[1], undoObj.extra.oldValue, q[2], undoObj); + }, + + "replaceNode" : function(undoObj, undo) { + var q = undoObj.args; + + //Set Attribute + if (!undo) + apf.xmldb.replaceNode(q[0], q[1], q[2], undoObj); + //Undo Attribute Setting + else + apf.xmldb.replaceNode(q[1], q[0], q[2], undoObj); + }, + + "addChildNode" : function(undoObj, undo) { + var q = undoObj.args; + + //Add Child Node + if (!undo) + apf.xmldb.addChildNode(q[0], q[1], q[2], q[3], undoObj); + //Remove Child Node + else + apf.xmldb.removeNode(undoObj.extra.addedNode, null, undoObj); + }, + + "appendChild" : function(undoObj, undo) { + var q = undoObj.args; + + //Append Child Node + if (!undo) + apf.xmldb.appendChild(q[0], q[1], q[2], q[3], q[4], undoObj); + //Remove Child Node + else + apf.xmldb.removeNode(undoObj.xmlNode, null, undoObj);//q[1] + }, + + "moveNode" : function(undoObj, undo) { + var q = undoObj.args; + + //Move Node + if (!undo) + apf.xmldb.moveNode(q[0], q[1], q[2], q[3], undoObj); + //Move Node to previous position + else + apf.xmldb.moveNode(undoObj.extra.oldParent, q[1], + undoObj.extra.beforeNode, q[3], undoObj); + }, + + "removeNode" : function(undoObj, undo) { + var q = undoObj.args; + + //Remove Node + if (!undo) + apf.xmldb.removeNode(q[0], q[1], undoObj); + //Append Child Node + else + apf.xmldb.appendChild(undoObj.extra.parent, + undoObj.extra.removedNode, undoObj.extra.beforeNode, + null, null, undoObj); + }, + + /** + * @deprecated Use "multicall" from now on + */ + "removeNodeList" : function(undoObj, undo) { + if (undo) { + var d = undoObj.extra.removeList; + for (var i = d.length - 1; i >= 0; i--) { + apf.xmldb.appendChild(d[i].pNode, + d[i].removedNode, d[i].beforeNode, null, null, undoObj); + } + } + else + apf.xmldb.removeNodeList(undoObj.args, undoObj); + }, + + "group" : function(undoObj, undo, at) { + if (!undoObj.$undostack) { + var done = undoObj.args[0]; + undoObj.$undostack = done; + undoObj.$redostack = []; + } + + at[undo ? "undo" : "redo"](undoObj.$undostack.length, false, + undoObj.$undostack, undoObj.$redostack); + }, + + /*"setProperty" : function(undoObj, undo) { + var q = undoObj.args;//amlNode, name, value + + if (!undo) { + undoObj.extra.oldValue = q[0][q[1]]; + q[0].setProperty(q[1], q[2], q[3], q[4]); + } + // Undo + else { + q[0].setProperty(q[1], undoObj.extra.oldValue); + } + },*/ + + "setValueByXpath" : function(undoObj, undo) { + var newNode, q = undoObj.args;//xmlNode, value, xpath + + // Setting NodeValue and creating the node if it doesnt exist + if (!undo) { + if (newNode = undoObj.extra.newNode) { + if (newNode.nodeType == 2) { + apf.xmldb.setAttribute(undoObj.extra.ownerElement, + newNode.nodeName, newNode.nodeValue); + undoObj.extra.newNode = undoObj.extra.ownerElement + .getAttributeNode(newNode.nodeName); + } + else + apf.xmldb.appendChild(undoObj.extra.parentNode, + undoObj.extra.newNode, null, null, null, undoObj); + } + else { + var newNodes = []; + apf.setNodeValue(q[0], q[1], true, { + undoObj: undoObj, + xpath: q[2], + newNodes: newNodes, + forceNew: q[3] + }); + + newNode = undoObj.extra.newNode = newNodes[0]; + if (newNode) { + if (newNode.nodeType == 2) + undoObj.extra.ownerElement = newNode.ownerElement + || newNode.selectSingleNode(".."); + else + undoObj.extra.parentNode = undoObj.extra.newNode.parentNode; + } + } + } + // Undo Setting NodeValue + else { + if (newNode = undoObj.extra.newNode) { + if (newNode.nodeType == 2) + apf.xmldb.removeAttribute(undoObj.extra.ownerElement, + newNode.nodeName, null, undoObj); + else + apf.xmldb.removeNode(undoObj.extra.newNode, null, undoObj); + } + else + apf.setNodeValue(undoObj.extra.appliedNode, + undoObj.extra.oldValue, true, {undoObj: undoObj}); + } + }, + + //@todo please change .func to .action for consistency reasons + "multicall" : function(undoObj, undo, at) { + var q = undoObj.args; + + var dUpdate = apf.xmldb.delayUpdate; + apf.xmldb.delayUpdate = true; + + // Set Calls + if (!undo) { + for (var i = 0; i < q.length; i++) { + if (!q[i].extra) + q[i].extra = {}; + + if (q[0].rdbModel) + q[i].rdbQueue = q[0].rdbQueue; + + apf.actiontracker.actions[q[i].action](q[i], false, at); + } + + if (q[0].rdbModel) { + undoObj.rdbModel = q[0].rdbModel; + undoObj.rdbQueue = q[0].rdbQueue; + } + + } + // Undo Calls + else { + for (var i = q.length - 1; i >= 0; i--) + apf.actiontracker.actions[q[i].action](q[i], true, at); + } + + apf.xmldb.delayUpdate = dUpdate; + + //if (!dUpdate) + //apf.xmldb.notifyQueued(); + } +}; + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * Implementation of the Common Gateway Interface (CGI) as a module for the RPC + * plugin of apf.teleport. + * Example: + * Ajax.org Markup Language + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * //This function is called when the search returns + * function processSearch(data, state, extra) { + * alert(data) + * } + * + * //Execute a search for the product car + * comm.searchProduct('car', 10); + * + * + * Remarks: + * Calls can be made to a server using cgi variables with a special + * {@link term.datainstruction data instruction} + * format. + * + * get="http://www.bla.nl?blah=10&foo=[@bar]&example=[10+5]" + * set="post http://www.bla.nl?blah=10&foo={/bar}&example=[10+5]" + * + * + * @addenum rpc[@protocol]:cgi + * + * @constructor + * + * @inherits apf.Teleport + * @inherits apf.http + * @inherits apf.rpc + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.4 + * + * @default_private + */ +apf.cgi = function(){ + this.supportMulticall = false; + this.namedArguments = true; + + this.unserialize = function(str) { + return str; + }; + + this.getSingleCall = function(name, args, obj) { + obj.push(args); + }; + + // Create message to send + this.createMessage = function(functionName, args) { + var prop, + vars = []; + + function recur(o, stack) { + if (o && o.dataType == apf.ARRAY) { + for (var j = 0; j < o.length; j++) + recur(o[j], stack + "%5B" + j + "%5D");//" + j + " + } + else if (o && typeof o == "object") { + if (o.nodeType) { + try{ + var s = o.outerHTML || o.serialize && o.serialize() + || apf.getCleanCopy(o).xml; + } + catch (e) { + var s = "Could not serialize object"; + } + vars.push(stack + "=" + encodeURIComponent(s)); + } + else { + for (prop in o) { + + + if (typeof o[prop] == "function") + continue; + recur(o[prop], stack + "%5B" + encodeURIComponent(prop) + "%5D"); + } + } + } + else { + if (typeof o != "undefined" && o !== null) + vars.push(stack + "=" + encodeURIComponent(o)); + } + }; + + if (this.multicall) { + vars.push("func" + "=" + this.mcallname); + for (var i = 0; i < args[0].length; i++) + recur(args[0][i], "f%5B" + i + "%5D"); + } + else { + for (prop in args) { + + + recur(args[prop], prop); + } + } + + if (!this.baseUrl) + this.baseUrl = this.url; + + this.url = this.$methods[functionName].url + ? this.$methods[functionName].url + : this.baseUrl; + + if (this.method != "GET") + return vars.join("&"); + + this.url = this.url + (vars.length + ? (this.url.indexOf("?") > -1 ? "&" : "?") + vars.join("&") + : ""); + + return ""; + }; + + this.addEventListener("DOMNodeInsertedIntoDocument", function() { + this.method = (this["http-method"] || "GET").toUpperCase(); + this.contentType = this.method == "GET" + ? null + : "application/x-www-form-urlencoded"; + }); + + /** + * Submit a form with ajax (GET) + * + * @param {HTMLElement} form the html form element to submit. + * @param {Function} callback called when the http call returns. + */ + this.submitForm = function(form, callback) { + if (!this['postform']) + this.addMethod('postform', callback); + + var args = []; + for (var i = 0, l = form.elements.length; i < l; i++) { + if (!form.elements[i].name) + continue; + if (form.elements[i].tagname == "input" + && (form.elements[i].type == "checkbox" + || form.elements[i].type == "radio") + && !form.elements[i].checked) + continue; + + if (form.elements[i].tagname = "select" && form.elements[i].multiple) { + for (var j = 0; j < form.elements[i].options.length; j++) { + if (form.elements[i].options[j].selected) + args.push(form.elements[i].name + + "=" + + encodeURIComponent(form.elements[i].options[j].value)); + } + } + else { + args.push(form.elements[i].name + + "=" + + encodeURIComponent(form.elements[i].value)); + } + } + + var loc = (form.action || location.href); + this.urls['postform'] = loc + (loc.indexOf("?") > -1 ? "&" : "?") + args.join("&"); + this['postform'].call(this); + + return false; + }; +}; + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * Implementation of the Common Gateway Interface (REST) as a module for the RPC + * plugin of apf.teleport. + * Example: + * Ajax.org Markup Language + * + * + * + * + * + * + * + * //This function is called when the search returns + * function processSearch(data, state, extra) { + * alert(data) + * } + * + * //Execute a search for the product car + * comm.searchProduct('car', 10); + * + * + * Remarks: + * Calls can be made to a server using rest variables with a special + * {@link term.datainstruction data instruction} + * format. + * + * get="http://www.bla.nl?blah=10&foo=[@bar]&example=[10+5]" + * set="post http://www.bla.nl?blah=10&foo={/bar}&example=[10+5]" + * + * + * @addenum rpc[@protocol]:rest + * + * @constructor + * + * @inherits apf.Teleport + * @inherits apf.http + * @inherits apf.rpc + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @author Mike de Boer (mike AT javeline DOT com) + * @version %I%, %G% + * @since 0.4 + * + * @default_private + */ +apf.rest = function(){ + this.supportMulticall = false; + this.namedArguments = false; + this.nocache = false; + + this.unserialize = function(str) { + return str; + }; + + this.getSingleCall = function(name, args, obj) { + obj.push(args); + }; + + // Create message to send + this.createMessage = function(functionName, args) { + if (!this.baseUrl) + this.baseUrl = this.url; + + var options = this.$methods[functionName]; + + + + var body = "NOTIFY|SEND|POST|PUT".indexOf(options["http-method"].toUpperCase()) > -1 ? args.pop() : "", + url; + + this.method = options["http-method"]; + if (options["content-type"]) + this.contentType = options["content-type"]; + + var i = 0, + l = args.length; + for (; i < l; ++i) + args[i] = encodeURIComponent(args[i]); + + this.url = (url = options.url + ? options.url + : this.baseUrl) + (l + ? (url.charAt(url.length - 1) == "/" + ? "" + : "/") + args.join("/") + : ""); + + this.contentType = body ? "application/x-www-form-urlencoded" : null; + return body; + }; +}; + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + +/** + * @constructor + * @private + */ +apf.textbox.masking = function(){ + /* + Special Masking Values: + - PASSWORD + + + */ + + var _FALSE_ = 9128748732; + + var _REF = { + "0" : "\\d", + "1" : "[12]", + "9" : "[\\d ]", + "#" : "[\\d +-]", + "L" : "[A-Za-z]", + "?" : "[A-Za-z ]", + "A" : "[A-Za-z0-9]", + "a" : "[A-Za-z0-9 ]", + "X" : "[0-9A-Fa-f]", + "x" : "[0-9A-Fa-f ]", + "&" : "[^\s]", + "C" : "." + }; + + var lastPos = -1; + var masking = false; + var oInput = this.$input; + var pos = []; + var initial, myvalue, format, fcase, replaceChar; + + this.setPosition = function(setpos) { + setPosition(setpos || lastPos || 0); + }; + + this.addEventListener("$clear", function(){ + this.value = ""; + if (this.mask) + return this.setValue(""); + }); + + this.$propHandlers["value"] = function(value) { + var data = ""; + if (this.includeNonTypedChars) { + for (var i = 0; i < initial.length; i++) { + if (initial.substr(i, 1) != value.substr(i, 1)) + data += value.substr(i, 1);//initial.substr(i,1) == replaceChar + } + } + + this.$insertData(data || value); + setPosition(myvalue.length); + }; + + //Char conversion + var numpadKeys = { + "96": "0", + "97": "1", + "98": "2", + "99": "3", + "100": "4", + "101": "5", + "102": "6", + "103": "7", + "104": "8", + "105": "9", + "106": "*", + "107": "+", + "109": "-", + "110": ".", + "110": "/" + }; + + this.addEventListener("keydown", function(e) { + var key = e.keyCode, + stop = false; + + switch (key) { + case 39: + //RIGHT + setPosition(lastPos + 1); + stop = true; + break; + case 37: + //LEFT + setPosition(lastPos - 1); + stop = true; + break; + case 35: + case 34: + setPosition(myvalue.length); + stop = true; + break; + case 33: + case 36: + setPosition(0); + stop = true; + break; + case 8: + //BACKSPACE + deletePosition(lastPos - 1); + setPosition(lastPos - 1); + stop = true; + break; + case 46: + //DEL + deletePosition(lastPos); + setPosition(lastPos); + stop = true; + break; + default: + if (key == 67 && e.ctrlKey) { + window.clipboardData.setData("Text", this.getValue()); + stop = true; + } + break; + } + + //@todo why isnt the conversion not always good? Check backtick. + var chr = numpadKeys[key] || String.fromCharCode(key); + if (setCharacter(chr)) + setPosition(lastPos + 1); + + var value, pos = lastPos; + if (this.realtime && (value = this.getValue()) != this.value) { + this.change(value); + setPosition(pos); + } + + if (apf.isCharacter(e.keyCode) || stop) + return false; + }, true); + + /* *********************** + Init + ************************/ + + this.$initMasking = function(){ + ///this.keyHandler = this._keyHandler; + this.$keyHandler = null; //temp solution + masking = true; + + this.$input[apf.isIphone ? "onclick" : "onmouseup"] = function(e) { + var pos = Math.min(calcPosFromCursor(), myvalue.length); + setPosition(pos); + return false; + }; + + this.$input.onpaste = function(e) { + e = e || window.event; + e.returnValue = false; + this.host.setValue(window.clipboardData.getData("Text") || ""); + //setPosition(lastPos); + $setTimeout(function(){ + setPosition(lastPos); + }, 1); //HACK good enough for now... + }; + + this.getValue = function(){ + if (this.includeNonTypedChars) + return initial == this.$input.value + ? "" + : this.$input.value.replace(new RegExp(replaceChar, "g"), ""); + else + return myvalue.join(""); + }; + + this.setValue = function(value) { + this.$propHandlers["value"].call(this, value); + }; + }; + + this.setMask = function(m) { + if (!masking) + this.$initMasking(); + + m = m.split(";"); + replaceChar = m.pop(); + this.includeNonTypedChars = parseInt(m.pop(), 10) !== 0; + var mask = m.join(""); //why a join here??? + var validation = ""; + var visual = ""; + var mode_case = "-"; + var strmode = false; + var startRight = false; + var chr; + pos = []; + format = ""; + fcase = ""; + + for (var looppos = -1, i = 0; i < mask.length; i++) { + chr = mask.substr(i, 1); + + if (!chr.match(/[\!\'\"\>\<\\]/)) { + looppos++; + } + else { + if (chr == "!") + startRight = true; + else if (chr == "<" || chr == ">") + mode_case = chr; + else if (chr == "'" || chr == "\"") + strmode = !strmode; + continue; + } + + if (!strmode && _REF[chr]) { + pos.push(looppos); + visual += replaceChar; + format += chr; + fcase += mode_case; + validation += _REF[chr]; + } + else + visual += chr; + } + + this.$input.value = visual; + initial = visual; + //pos = pos; + myvalue = []; + //format = format; + //fcase = fcase; + replaceChar = replaceChar; + + //setPosition(0);//startRight ? pos.length-1 : 0); + + //validation.. + //forgot \ escaping... + }; + + function checkChar(chr, p) { + var f = format.substr(p, 1); + var c = fcase.substr(p, 1); + + if (chr.match(new RegExp(_REF[f])) == null) + return _FALSE_; + if (c == ">") + return chr.toUpperCase(); + if (c == "<") + return chr.toLowerCase(); + return chr; + } + + function setPosition(p) { + if (p < 0) + p = 0; + + if (apf.hasMsRangeObject) { + var range = oInput.createTextRange(); + range.expand("textedit"); + range.select(); + + if (pos[p] == null) { + range.collapse(false); + range.select(); + lastPos = pos.length; + return false; + } + + range.collapse(); + range.moveStart("character", pos[p]); + range.moveEnd("character", 1); + range.select(); + } + else { + if (typeof pos[p] == "undefined") { + oInput.selectionStart = oInput.selectionEnd = pos[pos.length - 1] + 1; + lastPos = pos.length; + return false; + } + oInput.selectionStart = pos[p]; + oInput.selectionEnd = pos[p] + 1; + } + + lastPos = p; + } + + function setCharacter(chr) { + if (pos.length && pos[lastPos] == null) + return false; + + chr = checkChar(chr, lastPos); + if (chr == _FALSE_) + return false; + + if (apf.hasMsRangeObject) { + var range = oInput.createTextRange(); + range.expand("textedit"); + range.collapse(); + range.moveStart("character", pos[lastPos]); + range.moveEnd("character", 1); + range.text = chr; + if (apf.document.activeElement == this) + range.select(); + } + else { + var val = oInput.value; + var start = oInput.selectionStart; + var end = oInput.selectionEnd; + oInput.value = val.substr(0, start) + chr + val.substr(end); + oInput.selectionStart = start; + oInput.selectionEnd = end; + } + + myvalue[lastPos] = chr; + + return true; + } + + function deletePosition(p) { + if (pos[p] == null) + return false; + + if (apf.hasMsRangeObject) { + var range = oInput.createTextRange(); + range.expand("textedit"); + range.collapse(); + + range.moveStart("character", pos[p]); + range.moveEnd("character", 1); + range.text = replaceChar; + range.select(); + } + else { + var val = oInput.value; + var start = pos[p]; + var end = pos[p] + 1; + oInput.value = val.substr(0, start) + replaceChar + val.substr(end); + oInput.selectionStart = start; + oInput.selectionEnd = end; + } + + //ipv lastPos + myvalue[p] = " "; + } + + this.$insertData = function(str) { + if (str == this.getValue()) + return; + + var i, j; + + try { + if (!apf.hasMsRangeObject && oInput.selectionStart == oInput.selectionEnd) + setPosition(0); // is this always correct? practice will show... + } + catch (ex) { + // in FF (as we know it), we cannot access the selectStart property + // when the control/ input doesn't have the focus or is not visible. + // A workaround is provided here... + if (!str) + return; + var chr, val; + for (i = 0, j = str.length; i < j; i++) { + lastPos = i; + if (pos[lastPos] == null) + continue; + chr = checkChar(str.substr(i, 1), i); + if (chr == _FALSE_) + continue; + val = oInput.value; + oInput.value = val.substr(0, pos[i]) + chr + val.substr(pos[i] + 1); + } + if (str.length) + lastPos++; + return; // job done, bail out + } + + str = this.dispatchEvent("insert", { data : str }) || str; + + if (!str) { + if (!this.getValue()) return; //maybe not so good fix... might still flicker when content is cleared + for (i = this.getValue().length - 1; i >= 0; i--) + deletePosition(i); + setPosition(0); + return; + } + + for (i = 0, j = str.length; i < j; i++) { + lastPos = i; + setCharacter(str.substr(i, 1)); + if (!apf.hasMsRangeObject) + setPosition(i + 1); + } + if (str.length) + lastPos++; + }; + + function calcPosFromCursor(){ + var range, lt = 0; + + if (!apf.hasMsRangeObject) { + lt = oInput.selectionStart; + } + else { + range = document.selection.createRange(); + var r2 = range.duplicate(); + r2.expand("textedit"); + r2.setEndPoint("EndToStart", range); + lt = r2.text.length; + } + + for (var i = 0; i < pos.length; i++) { + if (pos[i] > lt) + return (i == 0) ? 0 : i - 1; + } + + return myvalue.length; // always return -a- value... + } +}; + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + +/** + * Live Markup processor for a processing instruction + * + * @author Ruben Daniels (ruben AT ajax DOT org) + * @version %I%, %G% + * @since 0.9 + */ + +apf.LiveMarkupPi = function(){ + //this.$data; + this.$init(); +}; + +/* + @todo optimize the pi, possible with this code: + var div, doc = this.ownerDocument, domParser = doc.$domParser, + docFrag = doc.createDocumentFragment(), + sStart = "", + sEnd = ""; + + docFrag.$int = div; + + domParser.parseFromXml(apf.getXml(sStart + this.$bindingQueue[i] + sEnd), { //@todo might be optimized by doing it only once + doc: doc, + amlNode: docFrag, + beforeNode: null, + include: true + }); +*/ +(function(){ + this.mainBind = "data"; + + this.implement(apf.StandardBinding); + + this.getDocument = function(){ + return this.$data && this.$data.ownerDocument; + }; + + this.clear = function(msg) { + if (msg == "loading" && apf.getInheritedAttribute(this, "loading-message")) { + this.$propHandlers["calcdata"].call(this, "Loading..."); + this.calcdata = ""; + } + }; + + this.$propHandlers["calcdata"] = function(data) { + if (this.$skipChange) //Used by liveedit.js + return; + + if (this.$data) { + + + var nodes = this.$data.childNodes; + for (var i = nodes.length - 1; i >= 0; i--) + nodes[i].destroy(true); + } + + //var dt = new Date().getTime(); + + //if (!this.xmlRoot) + //return this.$ext.innerHTML = "loading..."; + + if (typeof data == "string" && data.indexOf(" -1) { //@todo use the .hasAml attribute + this.$ext.innerHTML = "";//data; + + var doc = this.ownerDocument.$domParser.parseFromString("" + data + "", "text/xml", { + htmlNode: this.$ext, + host: this + //nodelay : true + }) + this.$data = doc.documentElement; + + //apf.queue.empty(); + + //alert(new Date().getTime() - dt); + } + else { + if (this.$data) { + var nodes = this.$data.childNodes; + for (var i = 0; i < nodes.length; i++) + nodes[i].destroy(true); + } + if (this.$ext) + this.$ext.innerHTML = data || ""; + } + }; +}).call(apf.LiveMarkupPi.prototype = new apf.AmlProcessingInstruction(true)); + +apf.aml.setProcessingInstruction("lm", apf.LiveMarkupPi); +apf.aml.setProcessingInstruction("lm-debug", apf.LiveMarkupPi); +apf.aml.setProcessingInstruction("livemarkup", apf.LiveMarkupPi); + + + + + + + + +//Conditional compilation workaround... (can this be improved??) +if (document.all) { + var oldWinError = window.onerror, z; + window.onerror = z = function(m) { + apf.console.error("Error caught from early startup. Might be a html parser syntax error (not your fault). " + m); + + if (!arguments.caller) + return true; + } +} +apf.Init.addConditional(function(){ + if (document.all && window.onerror == z) //Conditional compilation workaround... (can this be improved??) + window.onerror = oldWinError; + + apf.dispatchEvent("domready"); +}, null, ["body", "class"]); + +/*if(document.body) + apf.Init.run("body"); +else*/ + apf.addDomLoadEvent(function(){apf.Init.run('body');}); + +//Start +apf.start(); + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + +/* + * Bootloader for Ajax.org Platform + * + * Include apf.js, then just go about it as you would with the + * packaged version. Adapt this file to include your preferred modules + */ + + + + + + +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * + */ + +/* + * Bootloader for Ajax.org Platform + * + * Include apf.js, then just go about it as you would with the + * packaged version. Adapt this file to include your preferred modules + */ + register(null, {apf: apf}); + } diff --git a/plugins/c9.fs/net.js b/plugins/c9.fs/net.js new file mode 100644 index 00000000..b5101467 --- /dev/null +++ b/plugins/c9.fs/net.js @@ -0,0 +1,103 @@ +define(function(require, exports, module) { + main.consumes = ["vfs", "Plugin"]; + main.provides = ["net"]; + return main; + + function main(options, imports, register) { + var vfs = imports.vfs; + var Plugin = imports.Plugin; + + /***** Initialization *****/ + + var plugin = new Plugin("Ajax.org", main.consumes); + var emit = plugin.getEmitter(); + + /***** Register and define API *****/ + + /** + * Provides access to opened ports in the connected workspace. + * + * Example: + * + * net.connect(80, {}, function(err, stream) { + * if (err) throw err; + * + * stream.on("data", function(chunk) { + * console.log(chunk); + * }); + * stream.write("GET /"); + * }); + * @singleton + **/ + plugin.freezePublicAPI({ + _events: [ + /** + * @event beforeConnect Fires right before a connection is made + * @cancellable + * @param {Object} e + * @param {Number} e.port the path to the file to execute + * @param {Object} e.options the options passed to the spawn function + */ + "beforeConnect", + /** + * @event afterConnect Fires right after a connection is made + * @param {Object} e + * @param {Number} e.port the path to the file to execute + * @param {proc.Stream} e.stream the process object returned by spawn + * @param {Error} e.error the error object if an error occured. + */ + "afterConnect" + ], + + /** + * Connects a regular socket to a port in the workspace. + * + * Example: + * + * net.connect(80, {}, function(err, stream) { + * if (err) throw err; + * + * stream.on("data", function(chunk) { + * console.log(chunk); + * }); + * stream.write("GET /"); + * }); + * + * @param {Number} port + * @param {Object} [options] + * @param {Number} [options.retries="5"] the number of times + * the connection should be retried to establish before giving up. + * @param {Number} [options.retryDelay="50"] the delay in + * milliseconds between each retry + * @param {String} [options.encoding="utf8"] the encoding of + * the stream. + * @param {Function} callback + * @param {Error} callback.err a connection error. + * @param {proc.Stream} callback.stream the readable and writable + * stream that allows you to interact with the connection. + * @fires beforeConnect + * @fires afterConnect + */ + connect: function(port, options, callback) { + emit("beforeConnect", {port: port, options: options}); + + if (!options.encoding) + options.encoding = "utf8"; + + vfs.connect(port, options, function(err, meta) { + callback(err, meta && meta.stream) + + emit("afterConnect", { + port: port, + stream: meta && meta.stream, + error: err + }); + }); + } + }); + + register(null, { + net: plugin + }); + } +}); \ No newline at end of file diff --git a/plugins/c9.fs/net_test.js b/plugins/c9.fs/net_test.js new file mode 100644 index 00000000..359281b2 --- /dev/null +++ b/plugins/c9.fs/net_test.js @@ -0,0 +1,82 @@ +/*global describe it before*/ + +"use client"; + +require(["lib/architect/architect", "lib/chai/chai"], function (architect, chai) { + var expect = chai.expect; + + expect.setupArchitectTest([ + { + packagePath: "plugins/c9.core/c9", + startdate: new Date(), + debug: true, + hosted: true, + local: false + }, + "plugins/c9.core/http-xhr", + "plugins/c9.core/ext", + "plugins/c9.fs/net", + "plugins/c9.fs/proc", + "plugins/c9.vfs.client/vfs_client", + "plugins/c9.vfs.client/endpoint", + "plugins/c9.ide.auth/auth", + + //Mock Plugins + { + consumes: ["Plugin"], + provides: ["auth.bootstrap", "info", "dialog.error"], + setup: expect.html.mocked + }, + { + consumes: ["net", "proc"], + provides: [], + setup: main + } + ], architect); + + function main(options, imports, register) { + var net = imports.net; + var proc = imports.proc; + + describe('net', function() { + describe('connect()', function() { + this.timeout(10000); + + it("should connect to a port", function(done) { + var code = + "var server = require('net').createServer(function(c) {" + + "c.write('1');" + + "c.pipe(c);" + + "});" + + "server.listen(18000, function() {});"; + + proc.spawn("node", { args: ["-e", code] }, + function(err, child) { + if (err) throw err.message; + + expect(child).ok; + expect(child).property("stdout").ok; + expect(child).property("stdin").ok; + child.stderr.on("data", function(data) { + throw new Error(data); + }); + child.stdin.on("data", function(data) { + throw new Error(data); + }); + + net.connect(18000, {}, function(err, stream) { + if (err) throw err.message; + stream.on("data", function(chunk) { + expect(chunk).equal("1"); + child.kill(); + done(); + }); + }); + }); + }); + }); + }); + + onload && onload(); + } +}); \ No newline at end of file diff --git a/plugins/c9.fs/proc.apigen.js b/plugins/c9.fs/proc.apigen.js new file mode 100644 index 00000000..9c04baf1 --- /dev/null +++ b/plugins/c9.fs/proc.apigen.js @@ -0,0 +1,218 @@ +define(function(require, exports, module) { + main.consumes = ["Plugin", "proc"]; + main.provides = ["proc.apigen"]; + return main; + + function main(options, imports, register) { + var proc = imports.proc; + var Plugin = imports.Plugin; + + function ApiGenerator(options) { + var runtime = options.runtime; + var basepath = options.basepath; + var errorCheck = options.errorCheck; + var env = options.env; + + /***** Initialization *****/ + + var plugin = new Plugin("Ajax.org", main.consumes); + // var emit = plugin.getEmitter(); + + /***** Methods *****/ + + function spawn(args, callback, cbExit, noAuthCheck) { + proc.pty(runtime, { + args: args, + cwd: basepath, + env: env + }, function(err, pty) { + if (err) + return callback(err); + + var control = { + kill: function(){ pty.kill() }, + write: function(value){ pty.write(value) }, + discard: function(keep) { + if (keep) pty.off("data", ondata); + pty.off("exit", onexit); + } + }; + + function ondata(data) { + var err = errorCheck(data, noAuthCheck, control); + if (err) { + control.discard(); + return callback(err); + } + + callback(null, data, control); + } + function onexit(data) { + return cbExit ? cbExit() : callback("No data received"); + } + + pty.on("data", ondata); + pty.on("exit", onexit); + }); + } + + function parseArg(options, arg, found, data) { + if (arg instanceof RegExp) { + var m = data.match(arg); + return m.length > 1 ? m[1] : m[0]; + } + else if (typeof arg == "object") { + var obj = {}; + for (var prop in arg) + obj[prop] = parseArg(options, arg[prop], found, data); + return obj; + } + else if (typeof arg == "string") { + return arg.replace(/\\\{|\{(.*?)\}/g, function(m, name) { + if (m == "\\{") return m; + // Replace $n in regexpses + if (name.charAt(0) == "$") + return found[name.substr(1)]; + // Replace {name} in strings + return options[name]; + }); + } + return arg; + } + + function createMethod(def) { + return function(options, callback) { + var parse = parseArg.bind(this, options); + var args = typeof def.args == "function" + ? def.args(options) + : def.args.map(parse); + + var buffer = ""; + spawn(args, function(err, data, control) { + if (err) + return callback(err); + + if (def.buffer) { + buffer += data; + return; + } + + if (def.write) { + def.write.forEach(function(item) { + var found; + if (typeof item.match == "string") + found = data.indexOf(item.match) > -1; + else + found = data.match(item.match); + + if (found) + control.write(parse(item.text, found, data)); + }); + } + if (def.exit) { + var found; + + for (var i = 0; i < def.exit.length; i++) { + var item = def.exit[i]; + + if (typeof item.match == "string") + found = data.indexOf(item.match) > -1; + else + found = data.match(item.match); + + if (found) { + if (item.error) + callback(item.result + ? parse(item.result, found, data) + : data); + else + callback(null, parse(item.result, found, data)); + + control.discard(); + if (item.error || item.kill) + control.kill(); + break; + } + } + } + + if (def.stream) { + callback(null, data, control); + return; + } + }, function(){ + if (def.buffer) { + try { + callback(null, + def.parse ? def.parse(buffer) : buffer); + } + catch (e) { + console.error(e); + callback(e); + } + } + else { + callback(def.defaultSuccess ? null : "No proper data received"); + } + }, def.noauth); + } + } + + /***** Register and define API *****/ + + /** + * Factory object for the {@link ApiGenerator}. + * @class proc.apigen + * @extends Object + */ + /** + * Create an instance of ApiGenerator. + * @method create + * @param {Object} options + * @param {String} options.runtime The path to the CLI in the workspace + * @param {String} options.basepath The basepath to the file in the workspace + * @param {Object} [options.env] Key value pairs of strings that + * specify the environment variables to set when executing the CLI. + * @param {Function} options.errorCheck This function is + * called when data comes in from a command and should be used to + * check for errors. This function should not return an object + * or string when an error has occured. When an auth error has + * occurred return an Error object with a property "code" set to + * 100. + * @param {String} options.errorCheck.data The output from the command. + * @param {Boolean} options.errorCheck.noAuthCheck Whether to ignore any auth check. + * @return {ApiGenerator} + */ + /** + * Helps to create an API based on a CLI. + * @class ApiGenerator + **/ + plugin.freezePublicAPI({ + /** + * Start the CLI process and process it's output. + * @param {Array} args The arguments to send to the CLI + * @param {Function} callback Called each time data is received from the process + * @param {String} callback.data The data received + * @param {Object} callback.control + * @param {Function} callback.control.kill Kills the process + * @param {Function} callback.control.write Write to the process + * @param {Function} callback.control.discard Discard any further changes + * @param {Function} cbExit This callback is called when the process exits successfully. + * @param {Boolean} [noAuthCheck=false] Whether to perform a check for authentication + */ + spawn: spawn, + + /** + * + */ + createMethod: createMethod + }); + + return plugin; + } + + register(null, { + "proc.apigen" : { create: ApiGenerator } + }); + } +}); \ No newline at end of file diff --git a/plugins/c9.fs/proc.js b/plugins/c9.fs/proc.js new file mode 100644 index 00000000..3a738a29 --- /dev/null +++ b/plugins/c9.fs/proc.js @@ -0,0 +1,499 @@ +define(function(require, exports, module) { + main.consumes = ["vfs", "Plugin"]; + main.provides = ["proc"]; + return main; + + function main(options, imports, register) { + var vfs = imports.vfs; + var Plugin = imports.Plugin; + + /***** Initialization *****/ + + var plugin = new Plugin("Ajax.org", main.consumes); + var emit = plugin.getEmitter(); + + var tmuxName = options.tmuxName; + + /***** Register and define API *****/ + + /** + * This is a proxy for a running process in the workspace. This object exposes + * the stdin, stdout and stderr streams, which you can interact with to + * control the running process. + * + * See {@link proc#spawn} + * + * @class proc.Process + * @extends Object + */ + /** + * the process ID of the running process. + * @property {Number} pid + */ + /** + * the stdin (Standard Input) stream of this process. + * @property {proc.Stream} stdin + */ + /** + * the stdout (Standard Output) stream of this process. + * @property {proc.Stream} stdout + */ + /** + * the stderr (Standard Error) stream of this process. + * @property {proc.Stream} stderr + */ + /** + * Fires after the process ends. If the process terminated normally, + * code is the final exit code of the process; otherwise, it's null. + * If the process terminated due to receipt of a signal, signal is the string + * name of the signal; otherwise, it's null. + * + * Note that the child process stdio streams might still be open. + * + * @event exit + * @param {Number} code + * @param {String} signal + */ + /** + * Sends a signal to the child process. See [signal(7)](http://www.kernel.org/doc/man-pages/online/pages/man7/signal.7.html) + * for a list of available signals. + * + * Note that while the function is called kill, the signal delivered to the + * child process may not actually kill it. kill really just sends a signal to + * a process. + * + * @method kill + * @param {String} signal + */ + /** + * Detaches the given child process. + * + * @method unref + */ + /** + * A stream is an abstract interface implemented by various objects in + * Cloud9. Streams are readable, writable, or both. + * @class proc.Stream + * @extends Object + */ + /** + * A boolean that is true for writable streams, but turns false after an error + * event occurs, the stream comes to an 'end', or if destroy() was called. + * @property {Boolean} writable + */ + /** + * Fires when data is received on the stream. + * @event data + * @param {String} chunk + */ + /** + * Fires when the stream has received an EOF. Indicates that no more data + * events will happen. If the stream is also writable, it may be possible to + * continue writing. + * @event end + */ + /** + * Fires if there was an error receiving data. + * @event error + */ + /** + * Emitted when the underlying resource (for example, the backing file + * descriptor) has been closed. Not all streams emit this. + * @event close + */ + /** + * Writes string with to the stream. + * @method write + * @param {String} data + */ + /** + * Terminates the stream with EOF or FIN. This call send queued write data + * before closing the stream. + * @method end + * @param {String} data + */ + /** + * Closes the underlying file descriptor. + * @method destroy + */ + /** + * This is the Stream.prototype() method available on all Stream objects. + * It connects this read stream to a destination. Incoming data on this stream + * is then written to destination. The destination and source streams are kept + * in sync by Cloud9. + * @method pipe + * @param destination + * @param [options] + */ + /** + * Interface for the special stream object, passed by {@link proc#pty}. This + * object acts both like a stream and like a process at the same time. + * @class proc.PtyStream + * @extends Object + */ + /** + * Fires when data is received on the stream. + * @event data + * @param {String} chunk + */ + /** + * Fires after the process ends. If the process terminated normally, + * code is the final exit code of the process; otherwise, it's null. + * If the process terminated due to receipt of a signal, signal is the string + * name of the signal; otherwise, it's null. + * + * Note that the child process stdio streams might still be open. + * + * @event exit + */ + /** + * Writes string with to the stream. + * @method write + * @param {String} data + */ + /** + * Terminates the stream with EOF or FIN. This call send queued write data + * before closing the stream. + * @method end + * @param {String} data + */ + /** + * Terminates the PTY + * @method destroy + */ + /** + * @method pipe + * @param destination + * @param [options] + */ + /** + * Provides access to process control in the workspace + * @singleton + **/ + plugin.freezePublicAPI({ + _events: [ + /** + * @event beforeSpawn Fires right before a file is executed + * @cancellable + * @param {Object} e + * @param {String} e.path the path to the file to execute + * @param {Object} e.options the options passed to the spawn function + */ + "beforeSpawn", + /** + * @event afterSpawn Fires right after a file is executed + * @param {Object} e + * @param {String} e.path the path to the file to execute + * @param {proc.Process} e.process the process object returned by spawn + */ + "afterSpawn", + /** + * @event beforePty Fires right before a process is spawned + * @cancellable + * @param {Object} e + * @param {String} e.path the path to the file to execute + * @param {Object} e.options the options passed to the spawn function + */ + "beforePty", + /** @event afterPty Fires right after a process is spawned + * @param {Object} e + * @param {String} e.path the path to the file to execute + * @param {proc.Process} e.process the process object returned by spawn + */ + "afterPty", + /** + * @event beforeTmux Fires right before a process is spawned + * @cancellable + * @param {Object} e + * @param {String} e.path the path to the file to execute + * @param {Object} e.options the options passed to the spawn function + */ + "beforeTmux", + /** @event afterTmux Fires right after a process is spawned + * @param {Object} e + * @param {String} e.path the path to the file to execute + * @param {proc.Process} e.process the process object returned by spawn + */ + "afterTmux", + /** @event beforeExecFile Fires right before a file is executed + * @cancellable + * @param {Object} e + * @param {String} e.path the path to the file to execute + * @param {Object} e.options the options passed to the spawn function + */ + "beforeExecFile", + /** @event afterExecFile Fires right after a file is executed + * @param {Object} e + * @param {String} e.path the path to the file to execute + * @param {proc.Stream} e.stdout The stdout stream + * @param {proc.Stream} e.stderr The stderr stream + * @param {Error} e.error the error if any + */ + "afterExecFile" + ], + + /** + * Spawns a child process and returns a process object complete + * with three stdio streams. + * + * Example: + * + * proc.spawn("ls", function(err, process) { + * if (err) throw err; + * + * process.stdout.on("data", function(chunk) { + * console.log(chunk); + * }); + * }); + * + * @param {String} path the path to the file to execute + * @param {Object} [options] + * @param {Array} [options.args] An array of args to pass to the executable. + * @param {String} [options.stdoutEncoding="utf8"] The encoding to use on the stdout stream. + * @param {String} [options.stderrEncoding="utf8"] The encoding to use on the stderr stream. + * @param {String} [options.cwd] Current working directory of the child process + * @param {Object} [options.stdio] Child's stdio configuration. + * @param {Object} [options.env] Environment key-value pairs + * @param {Boolean} [options.detached] The child will be a process group leader. (See below) + * @param {Number} [options.uid] Sets the user identity of the process. (See setuid(2).) + * @param {Number} [options.gid] Sets the group identity of the process. (See setgid(2).) + * @param {Boolean} [options.resumeStdin] Start reading from stdin, so the process doesn't exit + * @param {Boolean} [options.resolve] Resolve the path to the VFS root before spawning process + * @param {Function} callback + * @param {Error} callback.err The error object if one has occured. + * @param {proc.Process} callback.process The child process + * @fires beforeSpawn + * @fires afterSpawn + */ + spawn: function(path, options, callback) { + emit("beforeSpawn", {path: path, options: options}); + + if (!callback) { // Handle optional argument + callback = options; + options = {}; + } + + !options.stdoutEncoding && (options.stdoutEncoding = "utf8"); + !options.stderrEncoding && (options.stderrEncoding = "utf8"); + !options.stdinEncoding && (options.stdinEncoding = "utf8"); + + //@todo this can be optimized to resolve locally + if (options.resolve) + vfs.resolve(path, {}, exec); + else + exec(null, {path: path}); + + function exec(err, data) { + vfs.spawn(data.path, options, function(err, meta) { + callback(err, meta && meta.process); + + emit("afterSpawn", { + path: path, + process: meta && meta.process + }); + }); + } + }, + + /** + * Spawns a child process in a PTY and returns a stream object. + * Use this method if the process you wish to start requires a + * terminal (for instance VI). + * + * Note that, unless you know what you are doing, you generally + * want to use spawn, instead of pty. If you are looking for a way + * to run a process in an output window in Cloud9, then see + * {@link run#run}. + * + * Example: + * + * proc.pty("bash", { + * args: ["-c", "vi", "helloworld"] + * }, function(err, pty) { + * if (err) throw err; + * + * pty.on("data", function(chunk) { + * console.log(chunk); + * }); + * pty.write("ihello world\x27:wq"); + * }); + * + * @param {String} path the path to the file to execute + * @param {Object} [options] + * @param {Array} [options.args] An array of args to pass to the executable. + * @param {String} [options.name="xterm-color"] The terminal emulator name. + * @param {Number} [options.cols="80"] Number of cols in characters + * @param {Number} [options.rows="24"] Number of rows in characters + * @param {String} [options.cwd] Current working directory of the child process + * @param {Object} [options.env] Environment key-value pairs + * @param {Boolean} [options.resolve] Resolve the path to the VFS root before executing file + * @param {Function} callback + * @param {Error} callback.err The error object, if any + * @param {proc.PtyStream} callback.pty The stdout stream + * @fires beforePty + * @fires afterPty + */ + pty: function(path, options, callback) { + emit("beforePty", {path: path, options: options}); + + if (!options.encoding) + options.encoding = "utf8"; + if (!options.name) + options.name = "xterm-color"; + + //@todo this can be optimized to resolve locally + if (options.resolve) + vfs.resolve(path, {}, exec); + else + exec(null, {path: path}); + + function exec(err, data) { + vfs.pty(data.path, options, function(err, meta) { + callback(err, meta && meta.pty); + + emit("afterPty", {path: path, pty: meta && meta.pty}); + }); + } + }, + + /** + * Spawns a child process in a TMUX and returns a stream object. + * Use this method if the process you wish to start requires a + * terminal (for instance VI). + * + * Note that, unless you know what you are doing, you generally + * want to use spawn, instead of tmux. If you are looking for a way + * to run a process in an output window in Cloud9, then see + * {@link run#run}. + * + * Example: + * + * proc.tmux("bash", { + * args: ["-c", "vi", "helloworld"] + * }, function(err, tmux) { + * if (err) throw err; + * + * tmux.on("data", function(chunk) { + * console.log(chunk); + * }); + * tmux.write("ihello world\x27:wq"); + * }); + * + * @param {String} command The command to execute in the tmux session. Pass empty string to start the default shell and make sure kill is not set. + * @param {Object} [options] + * @param {String} [options.session] The name of the tmux session + * @param {Boolean} [options.kill] First kill an existing session + * @param {Boolean} [options.attach] Attach if the session exists + * @param {Boolean} [options.detach] Detach immediately after starting the process + * @param {Boolean} [options.detachOthers] Detach other clients immediately after starting the process + * @param {Boolean} [options.output] Act like an output pane + * @param {Boolean} [options.base] The base path to store the watch files + * @param {String} [options.name="xterm-color"] The terminal emulator name. + * @param {Number} [options.cols="80"] Number of cols in characters + * @param {Number} [options.rows="24"] Number of rows in characters + * @param {String} [options.cwd] Current working directory of the child process + * @param {Object} [options.env] Environment key-value pairs + * @param {Function} callback + * @param {Error} callback.err The error object, if any + * @param {proc.PtyStream} callback.pty The stdout stream + * @fires beforeTmux + * @fires afterTmux + */ + tmux: function(command, options, callback) { + emit("beforeTmux", {command: command, options: options}); + + if (!options.encoding) + options.encoding = "utf8"; + if (!options.name) + options.name = "xterm-color"; + if (tmuxName) + options.tmuxName = tmuxName; + + options.command = command || ""; + + vfs.tmux("", options, function(err, meta) { + callback(err, meta && meta.pty, meta && meta.pid, meta || {}); + + emit("afterTmux", { + command: command, + pty: meta && meta.pty, + pid: meta && meta.pid + }); + }); + }, + + /** + * Executes an executable file in the workspace and buffers the + * stdout and stderr until the process is complete. + * + * Note: The buffer can grow big and slow down the general IDE + * operations. Unless you know for certain that the output will be + * minimal (10kb or less), use {@link proc#spawn}. + * + * Example: + * + * proc.execFile("find", { + * args: ["."] + * }, function(err, stdout, stderr) { + * console.log(stderr, stdout); + * }); + * + * @param {String} path the path to the file to execute + * @param {Object} [options] + * @param {Array} [options.args] An array of args to pass to the executable. + * @param {String} [options.stdoutEncoding="utf8"] The encoding to use on the stdout stream. Defaults to . + * @param {String} [options.stderrEncoding="utf8"] The encoding to use on the stderr stream. Defaults to "utf8". + * @param {String} [options.cwd] Current working directory of the child process + * @param {Array} [options.stdio] Child's stdio configuration. (See above) + * @param {Object} [options.env] Environment key-value pairs + * @param {String} [options.encoding="utf8"] + * @param {Number} [options.timeout=0] + * @param {Number} [options.maxBuffer=200*1024] + * @param {String} [options.killSignal="SIGTERM"] + * @param {Boolean} [options.resumeStdin] Start reading from stdin, so the process doesn't exit + * @param {Boolean} [options.resolve] Resolve the path to the VFS root before executing file + * @param {Function} callback + * @param {Error} callback.error The error object if an error occurred. + * @param {String} callback.stdout The stdout buffer + * @param {String} callback.stderr The stderr buffer + * @fires beforeExecFile + * @fires afterExecFile + */ + execFile: function(path, options, callback) { + if (!callback) + return this.execFile(path, {}, arguments[1]); + + emit("beforeExecFile", {path: path, options: options}); + + if (!options.encoding) + options.encoding = "utf8"; + + //@todo this can be optimized to resolve locally + if (options.resolve) + vfs.resolve(path, {}, exec); + else + exec(null, {path: path}); + + function exec(err, data) { + vfs.execFile(data.path, options, function(err, e) { + var stdout = (err || e).stdout; + var stderr = (err || e).stderr; + + callback(err, stdout, stderr); + + emit("afterExecFile", { + path: path, + stdout: stdout, + stderr: stderr, + error: err + }); + }); + } + } + }); + + register(null, { + proc: plugin + }); + } +}); \ No newline at end of file diff --git a/plugins/c9.fs/proc_test.js b/plugins/c9.fs/proc_test.js new file mode 100644 index 00000000..4b7ada4c --- /dev/null +++ b/plugins/c9.fs/proc_test.js @@ -0,0 +1,152 @@ +/*global describe it before*/ + +"use client"; + +require(["lib/architect/architect", "lib/chai/chai"], function (architect, chai) { + var expect = chai.expect; + + expect.setupArchitectTest([ + { + packagePath: "plugins/c9.core/c9", + startdate: new Date(), + debug: true, + hosted: true, + local: false + }, + "plugins/c9.core/http-xhr", + "plugins/c9.core/ext", + "plugins/c9.fs/proc", + "plugins/c9.vfs.client/vfs_client", + "plugins/c9.vfs.client/endpoint", + "plugins/c9.ide.auth/auth", + // Mock plugins + { + consumes: [], + provides: ["auth.bootstrap", "info", "dialog.error"], + setup: expect.html.mocked + }, + { + consumes: ["proc"], + provides: [], + setup: main + } + ], architect); + + function main(options, imports, register) { + var proc = imports.proc; + + describe('proc', function() { + describe('spawn()', function() { + this.timeout(10000); + + it("should spawn a child process", function(done) { + var args = ["-e", "process.stdin.pipe(process.stdout);try{process.stdin.resume()}catch(e) {};"]; + proc.spawn("node", { + args: args + }, + function(err, child) { + if (err) throw err.message; + expect(child).ok; + expect(child).property("stdout").ok; + expect(child).property("stdin").ok; + child.stderr.on("data", function(data) { + throw new Error(data); + }); + child.stdin.on("data", function(data) { + throw new Error(data); + }); + child.stdout.on("data", function(data) { + expect(data).equal("echo me"); + child.stdout.on("end", function() { + done(); + }); + child.stdin.end(); + }); + child.stdin.write("echo me"); + }); + }); + + //should test the kill() method - which is broken now + //Another test - see that cwd defaults to the root vfs dir when resolve is set to true + }); + describe('execFile()', function() { + this.timeout(10000); + + it("should have environment variables from process, fsOptions, and call", function(done) { + var args = ["-e", "console.log([process.env.SHELL, process.env.CUSTOM, process.env.LOCAL].join(','))"]; + proc.spawn("node", { + args: args, + env: { + LOCAL: 44 + } + }, + function(err, child) { + if (err) throw err.message; + var stdout = []; + child.stderr.on("data", function(data) { + throw new Error(data); + }); + child.stdin.on("data", function(data) { + throw new Error(data); + }); + child.stdout.on("data", function(data) { + stdout.push(data); + }); + child.stdout.on("end", function() { + stdout = stdout.join(""); + expect(stdout).match(/[\/\w]+,43,44\n/); + done(); + }); + + }); + }); + + //should test the kill() method - which is broken now + //Another test - see that cwd defaults to the root vfs dir when resolve is set to true + }); + describe('pty()', function() { + this.timeout(30000); + + it("Terminal Test", function(done) { + var look = /\]0;.*\-\-color=auto/; + + var args = ["-is"]; + proc.pty("bash", { + args: args, + env: {}, + cwd: "/" + }, + function(err, pty) { + if (err) throw err.message; + var stdout = []; + pty.resize(80, 80); + + var hadRows = false; + + pty.on("data", function(data) { + + if (typeof data == "object" && data.rows) { + expect(data).property("rows").is.equal(80); + expect(data).property("cols").is.equal(80); + hadRows = true; + } else { + stdout.push(data); + if (hadRows && stdout.join("").match(look) > -1) + pty.kill(); + } + }); + pty.on("exit", function() { + done(); + }); + + pty.write("ls --color=auto\n"); + }); + }); + + // Test resize(); + }); + }); + + onload && onload(); + } +}); \ No newline at end of file diff --git a/plugins/c9.ide.ace/ace.js b/plugins/c9.ide.ace/ace.js new file mode 100644 index 00000000..b6919a99 --- /dev/null +++ b/plugins/c9.ide.ace/ace.js @@ -0,0 +1,2629 @@ +define(function(require, exports, module) { + "use strict"; + main.consumes = [ + "Editor", "editors", "commands", "menus", "Menu", "MenuItem", "Divider", + "settings", "c9", "preferences", "ui", "tabManager", "layout", "util", + "threewaymerge", "error_handler" + ]; + main.provides = ["ace"]; + return main; + + function main(options, imports, register) { + var Editor = imports.Editor; + var editors = imports.editors; + var commands = imports.commands; + var menus = imports.menus; + var settings = imports.settings; + var layout = imports.layout; + var c9 = imports.c9; + var ui = imports.ui; + var util = imports.util; + var tabs = imports.tabManager; + var prefs = imports.preferences; + var Menu = imports.Menu; + var MenuItem = imports.MenuItem; + var Divider = imports.Divider; + var merge = imports.threewaymerge; + var errorHandler = imports.error_handler; + + // Markup & Modes + var cssString = require("text!./style.less"); + var themes = JSON.parse(require("text!./themes.json")); + var modes = require("./modes"); + + var extensions = Object.keys(modes.extensions); + + // bearable scrollbars on windows + require("./scrollbar"); + + // Ace + var lang = require("ace/lib/lang"); + var Range = require("ace/range").Range; + var config = require("ace/config"); + var AceEditor = require("ace/editor").Editor; + var Document = require("ace/document").Document; + var EditSession = require("ace/edit_session").EditSession; + var defaultCommands = require("ace/commands/default_commands").commands; + var VirtualRenderer = require("ace/virtual_renderer").VirtualRenderer; + var multiSelectCommands = require("ace/multi_select").commands; + var whitespaceUtil = require("ace/ext/whitespace"); + + // enable multiselect + require("ace/multi_select"); + + // and error marker + require("ace/ext/error_marker"); + + // preload html mode + require("ace/mode/html"); + + // Needed to clear ace + var dummySession = new EditSession(""); + + // We don't use ace workers + config.setDefaultValue("session", "useWorker", false); + + // experiment + config.setDefaultValue("editor", "fixedWidthGutter", true); + EditSession.prototype.diffAndReplace = function(range, text) { + var doc = this.doc; + var start = doc.positionToIndex(range.start); + var oldText = doc.getTextRange(range); + merge.patchAce(oldText, text, doc, { + offset: start, + method: "quick" + }); + var dl = text.replace(/\r\n|\r|\n/g, doc.getNewLineCharacter()).length; + return doc.indexToPosition(start + dl); + }; + + require("ace/lib/fixoldbrowsers"); + + /***** Global API *****/ + + // Set up the generic handle + var handle = editors.register("ace", "Ace", Ace, extensions); + var handleEmit = handle.getEmitter(); + handleEmit.setMaxListeners(1000); + + var mnuAce, mnuGutter; + + var isMinimal = options.minimal; + var themeLoaded = {}; + var lastTheme, grpSyntax; + + var theme; + var skin = settings.get("user/general/@skin"); + var defaultThemes = { + "light" : "ace/theme/cloud9_day", + "light-gray" : "ace/theme/cloud9_day", + "flat-light" : "ace/theme/cloud9_day", + "dark" : "ace/theme/cloud9_night_low_color", + "dark-gray" : "ace/theme/cloud9_night_low_color" + }; + + // Fix broken settings + if (!defaultThemes[skin]) { + settings.set("user/general/@skin", "dark"); + skin = "dark"; + } + + if (isMinimal) { + defaultThemes[skin] = "ace/theme/textmate"; + } else { + require([defaultThemes[skin]], function(){}); // Preload Themes + } + handle.__defineGetter__("theme", function(){ return theme; }); + + function addCorner(ace) { + if (isMinimal) + return; + var shadow = document.createElement("div"); + shadow.className = "scroll_shadow"; + var corner = document.createElement("div"); + corner.className = "ace_corner"; + shadow.appendChild(corner); + ace.renderer.scroller.appendChild(shadow); + } + + function addCornerStyles(theme) { + var sheet = document.getElementById(theme.cssClass).sheet; + sheet.insertRule( + "." + theme.cssClass + " .ace_corner" + "{" + + "background: radial-gradient(at 5px 5px, " + + (theme.isDark ? "rgba(0,0,0,0)" : "rgba(250,250,250,0)") + + "5.5px," + theme.bg + "6px)" + + "}", + sheet.cssRules.length + ); + } + + function setTheme(path, isPreview, fromServer, $err) { + // Get Theme or wait for theme to load + try{ + theme = fromServer || require(path); + + // fixes a problem with Ace architect loading /lib/ace + // creating a conflict with themes + if (theme.isDark === undefined) + throw new Error(); + } + catch (e) { + // not checking this can create infinite loop in build + $err || require([path], function(){ + setTheme(path, isPreview, fromServer, true); + }); + return; + } + + if (!isPreview) { + if (settings.get("user/ace/@theme") != path) { + settings.set("user/ace/@theme", path); + + // Emit theme change event + var style = (theme.isDark ? "dark" : "light"); + if (settings.get("user/general/@skin").indexOf(style) == -1) + layout.proposeLayoutChange(style, false, "ace"); + } + } + + if (lastTheme == theme) + return; + + if (isMinimal) { + if (!themeLoaded[path]) { + themeLoaded[path] = true; + handleEmit("themeInit", {theme: theme, path: path}); + } + return; + } + else { + if (!themeLoaded[path]) { + themeLoaded[path] = true; + + var cssClass = theme.cssClass; + + var div = document.createElement("div"); + document.body.appendChild(div); + div.innerHTML = "
      "; + div.className = cssClass; + + theme.bg = ui.getStyle(div.firstChild, "backgroundColor"); + theme.fg = ui.getStyle(div.firstChild, "color"); + theme.path = path; + + document.body.removeChild(div); + + addCornerStyles(theme); + + // Init Theme Event + handleEmit("themeInit", {theme: theme, path: path}); + } + + tabs.containers.forEach(function(container) { + if (theme.isDark) + ui.setStyleClass(container, "dark"); + else + ui.setStyleClass(container, "", ["dark"]); + }); + } + + var lTheme = lastTheme; + lastTheme = theme; + + handleEmit("themeChange", { + lastTheme: lTheme, + theme: theme, + path: path + }); + } + + // Theme passed in from the server + if (options.theme) { + ui.insertCss(options.theme.cssText, handle); + define(options.theme.path, [], options.theme); + // require([options.theme.path], function(){}); + setTheme(options.theme.path, null, options.theme); + } + + /***** Default Settings *****/ + + var BOOL = "getBool"; + var STRING = "get"; + var NUMBER = "getNumber"; + + // Name, Default Value, Type, Old Name, Store in Project Settings + var font = "Monaco, Menlo, Ubuntu Mono, Consolas, source-code-pro, monospace"; + var aceSettings = [ + // detected from document value + ["newLineMode", "unix", STRING, "newlinemode", 1], + // Per document + ["tabSize", "4", NUMBER, "tabsize", 1], + ["useSoftTabs", "true", BOOL, "softtabs", 1], + ["guessTabSize", "true", BOOL, "guesstabsize", 1], + ["useWrapMode", "false", BOOL, "wrapmode"], + ["wrapToView", "true", BOOL, "wrapmodeViewport"], + + // Ace + ["fontSize", "12", NUMBER, "fontsize"], + ["fontFamily", font, STRING, "fontfamily"], + ["antialiasedfonts", "false", BOOL], + ["overwrite", "false", BOOL, "overwrite"], + ["selectionStyle", "line", STRING, "selectstyle"], + ["cursorStyle", "ace", STRING, "cursorstyle"], + ["highlightActiveLine", "true", BOOL, "activeline"], + ["highlightGutterLine", "true", BOOL, "gutterline"], + ["showInvisibles", "false", BOOL, "showinvisibles"], + ["showPrintMargin", "true", BOOL, "showprintmargin"], + ["displayIndentGuides", "true", BOOL, "showindentguides"], + ["printMarginColumn", "80", NUMBER, "printmargincolumn"], + ["behavioursEnabled", "true", BOOL, "behaviors"], + ["wrapBehavioursEnabled", "false", BOOL, "wrapbehaviors"], + ["scrollSpeed", "2", NUMBER, "scrollspeed"], + ["showGutter", "true", BOOL, "gutter"], + ["showFoldWidgets", "true", BOOL, "folding"], + ["fadeFoldWidgets", "true", BOOL, "fadefoldwidgets"], + ["highlightSelectedWord", "true", BOOL, "highlightselectedword"], + ["animatedScroll", "true", BOOL, "animatedscroll"], + ["scrollPastEnd", "0.5", NUMBER], + ["mergeUndoDeltas", "off", STRING], + ["theme", defaultThemes[skin], STRING, "theme"] + ]; + var docSettings = aceSettings.slice(1, 6); + var editorSettings = aceSettings.slice(6); + var projectSettings = aceSettings.slice(0, 4); + var userSettings = aceSettings.slice(4); + var docLut = {}; docSettings.forEach(function(x){ docLut[x[0]] = x }); + + /***** Undo Manager *****/ + + function AceUndoManager(undoManager, session) { + this.$session = session; + this.$undo = undoManager; + var _self = this; + var Item = this.Item; + this.$undo.on("itemFind", function(e) { + return Item(_self, e.state); + }); + } + AceUndoManager.prototype = { + Item: function(_self, deltas) { + return { + undo: function(){ + _self.$session.session.undoChanges(deltas, _self.dontSelect); + }, + redo: function(){ + _self.$session.session.redoChanges(deltas, _self.dontSelect); + }, + getState: function(){ + return deltas.filter(function (d) { + return d.group != "fold"; + }); + } + }; + }, + + execute: function(options) { + if (options.merge && this.lastDeltas) { + this.lastDeltas.push.apply(this.lastDeltas, options.args[0]); + } else { + this.lastDeltas = options.args[0]; + this.$undo.add(this.Item(this, this.lastDeltas)); + } + }, + + undo: function(dontSelect) { + this.dontSelect = dontSelect; + this.$undo.undo(); + }, + redo: function(dontSelect) { + this.dontSelect = dontSelect; + this.$undo.redo(); + }, + reset: function(){ + this.$undo.reset(); + }, + hasUndo: function() { + return this.$undo.length > this.$undo.position + 1; + }, + hasRedo: function() { + return this.$undo.length <= this.$undo.position + 1; + }, + get $undoStack() { + return this.$undo.stack.slice(0, this.$undo.position + 1) + .map(function(e){ return e.getState ? e.getState() : e }); + } + }; + + function UndoManagerProxy(undoManager, session) { + this.$u = undoManager; + this.$doc = session; + } + + (function() { + this.execute = function(options) { + this.$u.execute(options); + }; + + this.undo = function() { + var selectionRange = this.$u.undo(true); + if (selectionRange) { + this.$doc.selection.setSelectionRange(selectionRange); + } + }; + + this.redo = function() { + var selectionRange = this.$u.redo(true); + if (selectionRange) { + this.$doc.selection.setSelectionRange(selectionRange); + } + }; + + this.reset = function() { + this.$u.reset(); + }; + + this.hasUndo = function() { + return this.$u.hasUndo(); + }; + + this.hasRedo = function() { + return this.$u.hasRedo(); + }; + }).call(UndoManagerProxy.prototype); + + /***** Generic Load *****/ + + handle.on("load", function(){ + if (!isMinimal) { + // Preferences + setPreferences(); + + // Menus + setMenus(); + + // State Management + c9.on("stateChange", function(e) { + if (e.state & c9.NETWORK) + menus.enableItem("View/Themes"); + else + menus.disableItem("View/Themes"); + }, handle); + } + + // Commands + setCommands(); + + // Settings + var lastSettings = {}; + function updateSettings(e, list, prefix) { + var options = {}; + (list || aceSettings).forEach(function(setting) { + options[setting[0]] + = settings[setting[2]](prefix + "/ace/@" + setting[0]); + }); + + // When loading from settings only set editor settings + docSettings.forEach(function(setting) { + var val = options[setting[0]]; + if (val !== undefined) { + setting[1] = val; + delete options[setting[0]]; + } + }); + + handleEmit("settingsUpdate", { + options: options + }); + + if (options.theme) + setTheme(options.theme); + + util.extend(lastSettings, options); + } + + settings.on("read", function(e) { + settings.setDefaults("user/ace", userSettings); + settings.setDefaults("project/ace", projectSettings); + + // pre load custom mime types + loadCustomExtensions(); + + setFontSmoothing(); + + updateSettings(null, userSettings, "user"); + updateSettings(null, projectSettings, "project"); + }, handle); + + // Listen to changes in the settings + settings.on("user/ace", function(e) { + var fstyle = settings.getBool("user/ace/@antialiasedfonts"); + ui.setStyleRule(".ace_editor", + apf.isChrome ? "WebkitFontSmoothing" : "MozOSXFontSmoothing", + fstyle && (apf.isChrome ? "antialiased" : "grayscale") || "auto"); + + updateSettings(e, userSettings, "user"); + }, handle); + settings.on("project/ace", function(e) { + updateSettings(e, projectSettings, "project"); + }, handle); + + handle.on("newListener", function(event, listener) { + if (event == "settingsUpdate") + listener({options: lastSettings}); + }); + + layout.on("themeChange", function(e) { + setFontSmoothing(); + + if (e.type !== "ace" + && settings.get("user/ace/@theme") != defaultThemes[e.oldTheme]) + return false; + }); + + layout.on("themeDefaults", function(e) { + if (e.type != "ace") + handle.setTheme(defaultThemes[e.theme]); + }, handle); + + // CSS + ui.insertCss(cssString, options.staticPrefix, handle); + }); + handle.on("unload", function(){ + drawn = false; + }); + + function setFontSmoothing(){ + var fstyle = settings.getBool("user/ace/@antialiasedfonts"); + ui.setStyleRule(".ace_editor", + apf.isChrome ? "WebkitFontSmoothing" : "MozOSXFontSmoothing", + fstyle && (apf.isChrome ? "antialiased" : "grayscale") || "auto"); + } + + var drawn; + function draw(){ + if (drawn) return; + drawn = true; + + mnuAce = new Menu({ + id: "menu", + items: [ + new MenuItem({ position: 10, command: "cut", caption: "Cut"}, handle), + new MenuItem({ position: 20, command: "copy", caption: "Copy" }, handle), + new MenuItem({ position: 30, command: "paste", caption: "Paste" }, handle), + new Divider({ position: 40 }, handle), + new MenuItem({ position: 50, command: "selectall", caption: "Select All" }, handle), + new Divider({ position: 60 }, handle) + ] + }, handle); + + mnuGutter = new Menu({ id: "menuGutter" }, handle); + mnuGutter.on("show", function(e) { + var ace = tabs.focussedTab.editor.ace; + var region = ace.renderer.$gutterLayer.getRegion(e); + var line = ace.renderer.screenToTextCoordinates(e.x, e.y).row; + var className = ace.session.getBreakpoints()[line] || ""; + + mnuGutter.meta.ace = ace; + mnuGutter.meta.line = line; + mnuGutter.meta.region = region; + mnuGutter.meta.className = className; + }); + + handleEmit("draw"); + } + + /***** Commands *****/ + + function setCommands() { + function isAce(editor, allowBlured) { + if (!editor || !editor.ace) + return false; + return allowBlured || editor.ace.isFocused(); + } + function fnWrap(command) { + command.group = "Code Editor"; + command.readOnly = command.readOnly || false; + command.focusContext = true; + + var isAvailable = command.isAvailable; + command.isAvailable = function(editor, args, event) { + // checking editor.ace instead of editor.type == "ace" to make + // commands avaliable in editors inheriting from ace + if (event instanceof KeyboardEvent && !isAce(editor)) + editor = apf.activeElement; + if (!isAce(editor, true)) + return false; + if (!editor.ace.commands.byName[command.name]) + return false; + + return isAvailable ? isAvailable(editor.ace) : true; + }; + + command.findEditor = function(editor) { + if (apf.activeElement && apf.activeElement.ace && apf.activeElement.ace.isFocused()) + return apf.activeElement.ace; + return editor && editor.ace || editor; + }; + + return command; + } + + if (!defaultCommands.wrapped) { + defaultCommands.push.apply(defaultCommands, whitespaceUtil.commands); + defaultCommands.forEach(fnWrap, defaultCommands); + Object.defineProperty(defaultCommands, "wrapped", {value: true, configurable: true}); + } + if (!multiSelectCommands.wrapped) { + multiSelectCommands.forEach(fnWrap, multiSelectCommands); + Object.defineProperty(multiSelectCommands, "wrapped", {value: true, configurable: true}); + } + + commands.addCommands(defaultCommands, handle, true); + commands.addCommands(multiSelectCommands, handle, true); + + // Override ACE key bindings (conflict with goto definition) + commands.commands.togglerecording.bindKey = { + mac: "Command-Shift-R", + win: "Alt-Shift-R" + }; + commands.commands.replaymacro.bindKey = { + mac: "Command-Ctrl-R", + win: "Alt-R" + }; + + commands.commands["findnext"].hint = + "search for the next occurrence of the search query your entered last"; + commands.commands["findnext"].msg = "Navigating to next match."; + commands.commands["findprevious"].hint = + "search for the previous occurrence of the search query your entered last"; + + commands.commands["findprevious"].msg = "Navigating to previous match."; + commands.addCommand(commands.commands.togglerecording, handle); + commands.addCommand(commands.commands.replaymacro, handle); + + commands.addCommand(fnWrap({ + name: "syntax", + exec: function(_, syntax) { + if (typeof syntax == "object") + syntax = syntax.argv && syntax.argv[1] || ""; + + syntax = modes.caption[syntax] + || modes.extensions[syntax] || syntax; + + var tab = tabs.focussedTab; + tab && tab.editor.setOption("syntax", syntax); + }, + commands: modes.caption + }), handle); + + commands.addCommand(fnWrap({ + name: "largerfont", + bindKey: { mac : "Command-+|Command-=", win : "Ctrl-+|Ctrl-=" }, + exec: function(e) { + var currSize = settings.get("user/ace/@fontSize"); + settings.set("user/ace/@fontSize", ++currSize > 72 ? 72 : currSize); + } + }), handle); + + commands.addCommand(fnWrap({ + name: "smallerfont", + bindKey: { mac : "Command--", win : "Ctrl--" }, + exec: function(e) { + var currSize = settings.get("user/ace/@fontSize"); + settings.set("user/ace/@fontSize", --currSize < 1 ? 1 : currSize); + } + }), handle); + } + + /***** Preferences *****/ + + function setPreferences(){ + prefs.add({ + "Project" : { + position: 10, + "Code Editor (Ace)" : { + position: 100, + "Soft Tabs" : { + type: "checked-spinner", + checkboxPath: "project/ace/@useSoftTabs", + path: "project/ace/@tabSize", + min: "1", + max: "64", + position: 100 + }, + "New File Line Endings" : { + type: "dropdown", + path: "project/ace/@newLineMode", + width: 130, + items: [ + { caption : "Windows (CRLF)", value : "windows" }, + { caption : "Unix (LF)", value : "unix" } + // { caption : "Mac OS 9 (CR)", value : "macos9" } + ], + position: 200 + } + } + } + }, handle); + + prefs.add({ + "Editors" : { + position: 400, + "Code Editor (Ace)" : { + position: 200, + "Auto-pair Brackets, Quotes, etc." : { + type: "checkbox", + position: 1000, + path: "user/ace/@behavioursEnabled" + }, + "Wrap Selection with Brackets, Quotes, etc." : { + type: "checkbox", + position: 1001, + path: "user/ace/@wrapBehavioursEnabled" + }, + "Code Folding" : { + type: "checkbox", + position: 2000, + path: "user/ace/@showFoldWidgets" + }, + "Fade Fold Widgets" : { + type: "checkbox", + position: 2500, + path: "user/ace/@fadeFoldWidgets" + }, + "Full Line Selection" : { + type: "checkbox", + position: 3000, + path: "user/ace/@selectionStyle", + values: "line|text" + }, + "Highlight Active Line" : { + type: "checkbox", + position: 4000, + path: "user/ace/@highlightActiveLine" + }, + "Highlight Gutter Line" : { + type: "checkbox", + position: 4000, + path: "user/ace/@highlightGutterLine" + }, + "Show Invisible Characters" : { + type: "checkbox", + position: 5000, + path: "user/ace/@showInvisibles" + }, + "Show Gutter" : { + type: "checkbox", + position: 6000, + path: "user/ace/@showGutter" + }, + "Show Indent Guides" : { + type: "checkbox", + position: 6500, + path: "user/ace/@displayIndentGuides" + }, + "Highlight Selected Word" : { + type: "checkbox", + position: 7000, + path: "user/ace/@highlightSelectedWord" + }, + "Scroll Past the End of the Document" : { + type: "dropdown", + width: 150, + path: "user/ace/@scrollPastEnd", + items: [ + { caption : "Off", value : "0" }, + { caption : "Half Editor Height", value : "0.5" }, + { caption : "Full Editor Height", value : "1" } + ], + position: 8000 + }, + "Animate Scrolling" : { + type: "checkbox", + path: "user/ace/@animatedScroll", + position: 9000 + }, + + "Font Family" : { + type: "textbox", + path: "user/ace/@fontFamily", + position: 10000 + }, + "Font Size" : { + type: "spinner", + path: "user/ace/@fontSize", + min: "1", + max: "72", + position: 10500 + }, + "Antialiased Fonts" : { + type: "checkbox", + path: "user/ace/@antialiasedfonts", + position: 10600 + }, + "Show Print Margin" : { + type: "checked-spinner", + checkboxPath: "user/ace/@showPrintMargin", + path: "user/ace/@printMarginColumn", + min: "1", + max: "200", + position: 11000 + }, + "Mouse Scroll Speed" : { + type: "spinner", + path: "user/ace/@scrollSpeed", + min: "1", + max: "8", + position: 13000, + }, + "Cursor Style" : { + type: "dropdown", + path: "user/ace/@cursorStyle", + items: [ + { caption : "Ace", value : "ace" }, + { caption : "Slim", value : "slim" }, + { caption : "Smooth", value : "smooth" }, + { caption : "Smooth And Slim", value : "smooth slim" }, + { caption : "Wide", value : "wide" }, + ], + position: 13500 + }, + "Merge Undo Deltas" : { + type: "dropdown", + path: "user/ace/@mergeUndoDeltas", + items: [ + { caption : "Always", value : "always" }, + { caption : "Never", value : "off" }, + { caption : "Timed", value : "true" } + ], + position: 14000 + } + } + } + }, handle); + } + + /***** Menus *****/ + + function setMenus() { + function addEditorMenu(path, commandName) { + return menus.addItemByPath(path, new ui.item({ + command: commandName + }), c += 100, handle); + } + + var c = 20000; + + addEditorMenu("Tools/Toggle Macro Recording", "togglerecording"); //@todo this needs some more work + addEditorMenu("Tools/Play Macro", "replaymacro"); //@todo this needs some more work + + c = 600; + + menus.addItemByPath("Edit/~", new ui.divider(), c += 100, handle); + menus.addItemByPath("Edit/Selection/", null, c += 100, handle); + menus.addItemByPath("Edit/Line/", null, c += 100, handle); + menus.addItemByPath("Edit/Text/", null, c += 100, handle); + menus.addItemByPath("Edit/Comment/", null, c += 100, handle); + menus.addItemByPath("Edit/Code Folding/", null, c += 100, handle); + + c = 0; + + addEditorMenu("Edit/Line/Indent", "indent"), + addEditorMenu("Edit/Line/Outdent", "outdent"), + addEditorMenu("Edit/Line/Move Line Up", "movelinesup"), + addEditorMenu("Edit/Line/Move Line Down", "movelinesdown"), + + menus.addItemByPath("Edit/Line/~", new ui.divider(), c += 100, handle); + addEditorMenu("Edit/Line/Copy Lines Up", "copylinesup"), + addEditorMenu("Edit/Line/Copy Lines Down", "copylinesdown"), + + menus.addItemByPath("Edit/Line/~", new ui.divider(), c += 100, handle); + addEditorMenu("Edit/Line/Remove Line", "removeline"), + addEditorMenu("Edit/Line/Remove to Line End", "removetolineend"), + addEditorMenu("Edit/Line/Remove to Line Start", "removetolinestart"), + + menus.addItemByPath("Edit/Line/~", new ui.divider(), c += 100, handle); + addEditorMenu("Edit/Line/Split Line", "splitline"); + + c = 0; + + addEditorMenu("Edit/Comment/Toggle Comment", "togglecomment"); + + c = 0; + + addEditorMenu("Edit/Text/Remove Word Right", "removewordright"), + addEditorMenu("Edit/Text/Remove Word Left", "removewordleft"), + + menus.addItemByPath("Edit/Text/~", new ui.divider(), c += 100, handle); + addEditorMenu("Edit/Text/Align", "alignCursors"); + addEditorMenu("Edit/Text/Transpose Letters", "transposeletters"); + + menus.addItemByPath("Edit/Text/~", new ui.divider(), c += 100, handle); + addEditorMenu("Edit/Text/To Upper Case", "touppercase"), + addEditorMenu("Edit/Text/To Lower Case", "tolowercase"); + + c = 0; + + addEditorMenu("Edit/Code Folding/Fold", "fold"), + addEditorMenu("Edit/Code Folding/Unfold", "unfold"), + + menus.addItemByPath("Edit/Code Folding/~", new ui.divider(), c += 100, handle); + addEditorMenu("Edit/Code Folding/Fold All", "foldall"), + addEditorMenu("Edit/Code Folding/Unfold All", "unfoldall"); + + c = 0; + + addEditorMenu("Edit/Selection/Select All", "selectall"), + addEditorMenu("Edit/Selection/Split Into Lines", "splitIntoLines"), + addEditorMenu("Edit/Selection/Single Selection", "singleSelection"), + + menus.addItemByPath("Edit/Selection/~", new ui.divider(), c += 100, handle); + menus.addItemByPath("Edit/Selection/Multiple Selections/", null, c += 100, handle); + + menus.addItemByPath("Edit/Selection/~", new ui.divider(), c += 100, handle); + addEditorMenu("Edit/Selection/Select Word Right", "selectwordright"), + addEditorMenu("Edit/Selection/Select Word Left", "selectwordleft"), + + menus.addItemByPath("Edit/Selection/~", new ui.divider(), c += 100, handle); + addEditorMenu("Edit/Selection/Select to Line End", "selecttolineend"), + addEditorMenu("Edit/Selection/Select to Line Start", "selecttolinestart"), + + menus.addItemByPath("Edit/Selection/~", new ui.divider(), c += 100, handle); + addEditorMenu("Edit/Selection/Select to Document End", "selecttoend"); + addEditorMenu("Edit/Selection/Select to Document Start", "selecttostart"); + + c = 0; + + addEditorMenu("Edit/Selection/Multiple Selections/Add Cursor Up", "addCursorAbove"), + addEditorMenu("Edit/Selection/Multiple Selections/Add Cursor Down", "addCursorBelow"), + addEditorMenu("Edit/Selection/Multiple Selections/Move Active Cursor Up", "addCursorAboveSkipCurrent"), + addEditorMenu("Edit/Selection/Multiple Selections/Move Active Cursor Down", "addCursorBelowSkipCurrent"), + + menus.addItemByPath("Edit/Selection/Multiple Selections/~", new ui.divider(), c += 100, handle); + addEditorMenu("Edit/Selection/Multiple Selections/Add Next Selection Match", "selectMoreAfter"), + addEditorMenu("Edit/Selection/Multiple Selections/Add Previous Selection Match", "selectMoreBefore"), + + menus.addItemByPath("Edit/Selection/Multiple Selections/~", new ui.divider(), c += 100, handle); + addEditorMenu("Edit/Selection/Multiple Selections/Merge Selection Range", "splitIntoLines"); + + /**** View ****/ + + menus.addItemByPath("View/~", new ui.divider(), 290000, handle); + menus.addItemByPath("View/Font Size/", null, 290001, handle); + + c = 0; + + addEditorMenu("View/Font Size/Increase Font Size", "largerfont"); + addEditorMenu("View/Font Size/Decrease Font Size", "smallerfont"); + + menus.addItemByPath("View/Gutter", new ui.item({ + type: "check", + checked: "user/ace/@showGutter" + }), 500, handle); + + var grpNewline = new ui.group(); + + + menus.addItemByPath("File/~", new ui.divider(), 1400, handle); + menus.addItemByPath("File/Line Endings/", new ui.menu({ + "onprop.visible" : function(e) { + if (e.value) { + var tab = tabs.focussedTab; + var ace = tab && tab.editor && tab.editor.ace; + if (ace && tab.editor.type == "ace") { + this.enable(); + var mode = ace.session.doc.getNewLineMode(); + grpNewline.setValue(mode); + } else { + this.disable(); + } + } + }, + "onitemclick" : function(e) { + var tab = tabs.focussedTab; + var ace = tab && tab.editor && tab.editor.ace; + if (ace && tab.editor.type == "ace") { + ace.session.doc.setNewLineMode(e.value); + tab.document.undoManager.bookmark(-2); + } + } + }), 1500, handle); + + menus.addItemByPath("File/Line Endings/Windows (CRLF)", new ui.item({ + type: "radio", + value: "windows", + group: grpNewline + }), 200, handle); + + menus.addItemByPath("File/Line Endings/Unix (LF)", new ui.item({ + type: "radio", + value: "unix", + group: grpNewline + }), 300, handle); + + menus.addItemByPath("View/Syntax/", new ui.menu({ + "onprop.visible" : function(e) { + if (e.value) { + if (!this.childNodes.length) + rebuildSyntaxMenu(); + this.$initChildren(); + var tab = tabs.focussedTab; + var c9Session = tab && tab.editor && tab.document.getSession(); + + if (!c9Session || !c9Session.session) { + this.disable(); + } else { + this.enable(); + var val = c9Session.session.syntax || c9Session.session.customSyntax || "auto"; + this.select(grpSyntax, val); + } + } + }, + "onitemclick" : function(e) { + var tab = tabs.focussedTab; + if (tab) { + var session = tab.document.getSession(); + setSyntax(session, e.value); + } + } + }), 300000, handle); + + menus.addItemByPath("View/~", new ui.divider(), 400000, handle); + + var wrapToggle = function(e) { + var tab = tabs.focussedTab; + var editor = tab && tab.editor; + + var mnuWrap = handle.getElement("mnuWrap"); + var mnuWrapPM = handle.getElement("mnuWrapPrintMargin"); + + mnuWrapPM.setAttribute("disabled", !mnuWrap.checked); + + var wrap = mnuWrap.checked; + if (mnuWrapPM.checked && (wrap || e.currentTarget == mnuWrapPM)) + wrap = "printMargin"; + + editor.setOption("wrap", wrap); + }; + + menus.addItemByPath("View/Wrap Lines", new ui.item({ + id: "mnuWrap", + type: "check", + onclick: wrapToggle, + isAvailable: function(editor) { + if (!editor || editor.type != "ace") + return false; + + var mnuWrap = handle.getElement("mnuWrap"); + var mnuWrapPrintMargin = handle.getElement("mnuWrapPrintMargin"); + + var wrap = editor.getOption("wrap"); + mnuWrap.setAttribute("checked", !ui.isFalse(wrap)); + mnuWrapPrintMargin.setAttribute("checked", wrap == "printMargin"); + + return true; + } + }), 500000, handle), + + menus.addItemByPath("View/Wrap To Print Margin", new ui.item({ + id: "mnuWrapPrintMargin", + type: "check", + onclick: wrapToggle, + isAvailable: function(editor) { + return editor && editor.type == "ace"; + } + }), 600000, handle); + + c = 0; + + /**** Goto ****/ + + menus.addItemByPath("Goto/~", new ui.divider(), c = 399, handle); + + addEditorMenu("Goto/Next Error", "goToNextError"); + addEditorMenu("Goto/Previous Error", "goToPreviousError"); + menus.addItemByPath("Goto/~", new ui.divider(), c += 200, handle); + + addEditorMenu("Goto/Word Right", "gotowordright"); + addEditorMenu("Goto/Word Left", "gotowordleft"); + menus.addItemByPath("Goto/~", new ui.divider(), c += 100, handle); + + addEditorMenu("Goto/Line End", "gotolineend"); + addEditorMenu("Goto/Line Start", "gotolinestart"); + menus.addItemByPath("Goto/~", new ui.divider(), c += 100, handle); + + addEditorMenu("Goto/Jump to Matching Brace", "jumptomatching"); + menus.addItemByPath("Goto/~", new ui.divider(), c += 100, handle); + + addEditorMenu("Goto/Scroll to Selection", "centerselection"); + + tabs.on("focus", function(e) { + var action = e.tab.editor.type != "ace" ? "disable" : "enable"; + + ["Edit/Comment", "Edit/Text", "Edit/Code Folding", + "Edit/Convert Case", "Edit/Line", "Edit/Selection", + "View/Syntax", "View/Font Size", + "View/Syntax/Other", "View/Syntax", + "File/Line Endings" + ].forEach(function(path) { + var menu = menus.get(path).menu; + if (menu) menu[action](); + }); + }); + + /**** Themes ****/ + + var grpThemes = new ui.group(); + var mnuThemes = new ui.menu({ + "onprop.visible" : function(e) { + if (e.value) + grpThemes.setValue(settings.get("user/ace/@theme")); + } + }); + menus.addItemByPath("View/Themes/", mnuThemes, 350000, handle); + + var preview; + var setMenuThemeDelayed = lang.delayedCall(function(){ + setMenuTheme(preview, true); + }, 150); + function setMenuTheme(path, isPreview) { + setTheme(path || settings.get("user/ace/@theme"), isPreview); + } + + function addThemeMenu(name, path, index) { + menus.addItemByPath("View/Themes/" + name, new ui.item({ + type: "radio", + value: path || themes[name], + group: grpThemes, + + onmouseover: function(e) { + preview = this.value; + setMenuThemeDelayed.schedule(); + }, + + onmouseout: function(e) { + preview = null; + setMenuThemeDelayed.schedule(); + }, + + onclick: function(e) { + setMenuTheme(e.currentTarget.value); + } + }), index, handle); + } + + // Create Theme Menus + var mainCounter = 100; + for (var name in themes) { + if (themes[name] instanceof Array) { + + // Add Menu Item (for submenu) + menus.addItemByPath("View/Themes/" + name + "/", null, mainCounter++, handle); + + themes[name].forEach(function (n) { + // Add Menu Item + var themeprop = Object.keys(n)[0]; + addThemeMenu(name + "/" + themeprop, n[themeprop]); + }); + } + else { + // Add Menu Item + addThemeMenu(name, null, mainCounter++); + } + } + + grpSyntax = new ui.group(); + handle.addElement(grpNewline, grpSyntax, grpThemes); + } + + + function rebuildSyntaxMenu() { + menus.remove("View/Syntax/"); + var c = 0; + + menus.addItemByPath("View/Syntax/Auto-Select", new ui.item({ + type: "radio", + value: "auto", + group: grpSyntax + }), c += 100, handle); + + menus.addItemByPath("View/Syntax/Plain Text", new ui.item({ + type: "radio", + value: "text", + group: grpSyntax + }), c += 100, handle); + + menus.addItemByPath("View/Syntax/~", new ui.divider(), c += 100, handle); + + var modeList = Object.keys(modes.byName).map(function(x) { + return modes.byName[x]; + }).sort(function(m1, m2) { + return m2.order - m1.order || m1.caption.localeCompare(m2.caption); + }); + + var groupNum = modeList[0] && modeList[0].order; + for (var i = 0; i < modeList.length; i++) { + var mode = modeList[i]; + if (mode.order < 0) + break; + if (mode.order < groupNum) { + groupNum = Math.min(mode.order, groupNum / 1000); + menus.addItemByPath("View/Syntax/~", new ui.divider(), c += 100, handle); + } + menus.addItemByPath("View/Syntax/" + mode.caption, new ui.item({ + type: "radio", + value: mode.name, + group: grpSyntax, + }), c += 100, handle); + } + } + + var updateSyntaxMenu = lang.delayedCall(rebuildSyntaxMenu, 50); + + /***** Syntax *****/ + + function defineSyntax(opts) { + if (!opts.name || !opts.caption) + throw new Error("malformed syntax definition"); + var name = opts.name; + modes.byCaption[opts.caption] = opts; + modes.byName[name] = opts; + + if (!opts.extensions) + opts.extensions = ""; + opts.extensions.split("|").forEach(function(ext) { + modes.extensions[ext] = name; + }); + updateSyntaxMenu.schedule(); + } + + function getExtOrName(path) { + var fileName = path.substr(path.lastIndexOf("/") + 1); + var extPos = fileName.lastIndexOf(".") + 1; + if (extPos) + return fileName.substr(extPos).toLowerCase(); + // special case for new files + if (/^Untitled\d+$/.test(fileName)) + fileName = fileName.replace(/\d+/, ""); + return "^" + fileName; + } + + function getSyntaxForPath(path) { + var ext = getExtOrName(path); + var modeName = modes.customExtensions[ext] || modes.extensions[ext]; + return modes.byName[modeName] ? modeName : ""; + } + + function setSyntaxForPath(path, syntax, noOverwrite) { + if (!path) + return false; + syntax = modes.byName[syntax] ? syntax : ""; + + var ext = getExtOrName(path); + var changed; + if (syntax) { + if (!modes.extensions[ext] || !noOverwrite) { + modes.customExtensions[ext] = syntax; + changed = true; + } + } else if (modes.customExtensions[ext]) { + delete modes.customExtensions[ext]; + changed = true; + } + + if (changed) + settings.setJson("user/ace/custom-types", modes.customExtensions); + return changed; + } + + function getMode(syntax) { + syntax = (syntax || "text").toLowerCase(); + if (syntax.indexOf("/") == -1) + syntax = "ace/mode/" + syntax; + + return syntax; + } + + function loadCustomExtensions() { + var custom = settings.getJson("user/ace/custom-types"); + if (!custom) return; + + Object.keys(custom).forEach(function(ext) { + var mode = custom[ext]; + if (modes.byName[mode]) + modes.customExtensions[ext] = mode; + }); + } + + function detectSyntax(c9Session, path) { + if (!c9Session.session || !c9Session.session.getLine) + return; + // todo move this into ace mode util + var firstLine = c9Session.session.getLine(0); + var syntax = ""; + if (!firstLine) { + return; + } + else if (/^#!/.test(firstLine)) { + var match = firstLine.match(/\b(node|bash|sh)\b/); + switch (match && match[1]) { + case "node": syntax = "javascript"; break; + case "sh": // fallthrough + case "bash": syntax = "sh"; break; + default: syntax = ""; break; + } + } + else if (/<\?xml/.test(firstLine)) { + syntax = "xml"; + } + else if (/^{/.test(firstLine)) { + syntax = "json"; + } + else if (/\.(bashrc|inputrc)$/.test(path)) { + syntax = "bash"; + } + else if (/\.(git(attributes|config|ignore)|npmrc)$/.test(path)) { + syntax = "ini"; + } + return syntax; + } + + function getSyntax(c9Session, path) { + var syntax = c9Session.session.customSyntax + || path && getSyntaxForPath(path) + || detectSyntax(c9Session, path); + return modes.byName[syntax] ? syntax : ""; + } + + function setSyntax(c9Session, syntax, forThisOnly) { + var c9doc = c9Session.session.c9doc; + syntax = modes.byName[syntax] ? syntax : ""; + var path = c9doc.tab.path; + if (!forThisOnly && !setSyntaxForPath(path, syntax, true)) + c9Session.session.customSyntax = syntax; + + c9doc.editor.setOption("syntax", syntax || getSyntax(c9Session, path), c9Session); + } + + function cloneSession(session, undoManager) { + var s = new EditSession(session.getDocument(), session.getMode()); + + if (!undoManager) + undoManager = session.getUndoManager(); + if (undoManager) { + var undoManagerProxy = new UndoManagerProxy(undoManager, s); + s.setUndoManager(undoManagerProxy); + } + + // Overwrite the default $informUndoManager function such that new deltas + // aren't added to the undo manager from the new and the old session. + s.$informUndoManager = lang.delayedCall(function() { s.$deltas = []; }); + + // Copy over 'settings' from the session. + s.setOptions(session.getOptions()); + s.$foldData = session.$cloneFoldData(); + + var ignore = false; + var changeAnnotation = function(){ + if (ignore) return; + ignore = true; + s.setAnnotations(session.getAnnotations()); + ignore = false; + }; + var changeMode = function(e) { + s.setMode(session.getMode()); + }; + var changeBreakpoint = function(){ + s.$breakpoints = session.$breakpoints; + s._emit("changeBreakpoint", {}); + }; + var setWrap = function(e) { + s.setOption("wrap", e.value); + }; + + session.on("changeAnnotation", changeAnnotation)(); + session.on("changeMode", changeMode); + session.on("changeBreakpoint", changeBreakpoint)(); + session.on("setWrap", setWrap); + + s.on("changeAnnotation", function(){ + if (ignore) return; + ignore = true; + session.setAnnotations(s.getAnnotations()); + ignore = false; + })(); + + s.cleanup = function(){ + session.removeListener("changeAnnotation", changeAnnotation); + session.removeListener("changeMode", changeMode); + session.removeListener("changeBreakpoint", changeBreakpoint); + session.removeListener("setWrap", setWrap); + }; + + s.c9doc = session.c9doc; + s.cloned = true; + + return s; + } + + /** + * The ace handle, responsible for events that involve all ace + * instances. This is the object you get when you request the ace + * service in your plugin. + * + * Example: + * + * define(function(require, exports, module) { + * main.consumes = ["ace"]; + * main.provides = ["myplugin"]; + * return main; + * + * function main(options, imports, register) { + * var aceHandle = imports.ace; + * + * aceHandle.on("create", function(e) { + * // This is an ace editor instance + * var ace = e.editor; + * }) + * }); + * }); + * + * + * @class ace + * @extends Plugin + * @singleton + */ + handle.freezePublicAPI({ + /** + * The context menu that is displayed when right clicked in the ace + * editing area. + * @property {Menu} contextMenu + * @readonly + */ + get contextMenu(){ draw(); return mnuAce }, + + /** + * The context menu that is displayed when right clicked in the ace + * gutter area. + * @property {Menu} gutterContextMenu + * @readonly + */ + get gutterContextMenu(){ draw(); return mnuGutter }, + + /** + * Ace Themes + * @property {Object} themese + */ + themes: themes, + + _events: [ + /** + * Fires once for each ace instance that is instantiated. + * + * Note that this event does not only fire for each ace instance + * that is created, but it also fires for all ace instances that + * have been created and are still around. + * + * @event create + * @param {Object} e + * @param {Editor} e.editor + */ + "create", + /** + * Fires when a new theme is initialized. + * @event themeInit + * @param {Object} e + * @param {Object} e.theme Describes the theme that is initialized. + * @param {String} e.theme.cssClass The css class name related to the theme. + * @param {String} e.theme.bg The background color for this theme. + * @param {String} e.theme.fg The foreground color for this theme. + * @param {String} e.theme.path The path of this theme. + * @param {Boolean} e.theme.isDark Specifies whether this is a dark theme or a light theme. + * @param {String} e.path The path of the theme. + */ + "themeInit", + /** + * Fires when the current theme changes to another theme. + * + * See also {@link ace#setTheme}. + * + * @event themeChange + * @param {Object} e + * @param {Object} e.theme Describes the theme that is initialized. + * @param {String} e.theme.cssClass The css class name related to the theme. + * @param {String} e.theme.bg The background color for this theme. + * @param {String} e.theme.fg The foreground color for this theme. + * @param {String} e.theme.path The path of this theme. + * @param {Boolean} e.theme.isDark Specifies whether this is a dark theme or a light theme. + * @param {Object} e.lastTheme Describes the theme that is initialized. + * @param {String} e.lastTheme.cssClass The css class name related to the theme. + * @param {String} e.lastTheme.bg The background color for this theme. + * @param {String} e.lastTheme.fg The foreground color for this theme. + * @param {String} e.lastTheme.path The path of this theme. + * @param {Boolean} e.lastTheme.isDark Specifies whether this is a dark theme or a light theme. + * @param {String} e.path The path of the theme. + */ + "themeChange", + /** + * Fires when an ace's EditSession is inited for the Cloud9 document + * the ace's EditSession can be get using: + * doc.getSession().session + * + * @event initAceSession + * @param {Object} e + * @param {Object} e.doc The document with the EditSession created + */ + "initAceSession", + /** + * Fires when the ace context menus are drawn + * @event draw + */ + "draw" + ], + + /** + * Set the theme for ace. + * + * Here's a list of known themes: + * + * * ace/theme/ambiance + * * ace/theme/chrome + * * ace/theme/clouds + * * ace/theme/clouds_midnight + * * ace/theme/cobalt + * * ace/theme/crimson_editor + * * ace/theme/dawn + * * ace/theme/dreamweaver + * * ace/theme/eclipse + * * ace/theme/github + * * ace/theme/idle_fingers + * * ace/theme/kr_theme + * * ace/theme/merbivore + * * ace/theme/merbivore_soft + * * ace/theme/mono_industrial + * * ace/theme/monokai + * * ace/theme/pastel_on_dark + * * ace/theme/solarized_dark + * * ace/theme/solarized_light + * * ace/theme/textmate + * * ace/theme/tomorrow + * * ace/theme/tomorrow_night + * * ace/theme/tomorrow_night_blue + * * ace/theme/tomorrow_night_bright + * * ace/theme/tomorrow_night_eighties + * * ace/theme/twilight + * * ace/theme/vibrant_ink + * * ace/theme/xcod + * + * @method setTheme + * @param {String} path The path of the theme file. + * @fires themeInit + * @fires themeChange + */ + setTheme: setTheme, + + /** + * Add new syntax to the menu + * + * See also {@link ace#setSyntax}. + * + * @param {Object} syntax + * @param {Object} syntax.caption Caption to display in the menu + * @param {Number} syntax.order order in the menu + * @param {String} syntax.id The path to corresponding ace language mode. (if doesn't contain "/" assumed to be from "ace/mode/") + * @param {String} syntax.extensions file extensions in the form "ext1|ext2|^filename". this is case-insensitive + */ + defineSyntax: defineSyntax, + + /** + * @ignore this is used by statusbar + */ + getSyntaxCaption: function(syntax) { + var mode = modes.byName[syntax]; + return mode && mode.caption || "Text"; + }, + + /** + * @ignore + */ + draw: draw, + + /** + * @ignore + */ + cloneSession: cloneSession + }); + + /***** Initialization *****/ + + function Ace(isBaseclass, exts) { + if ( !exts) exts = []; + var plugin = new Editor("Ajax.org", main.consumes, + exts && exts.concat(extensions) || extensions); + var emit = plugin.getEmitter(); + + if (isBaseclass) plugin.freezePublicAPI.baseclass(); + + var ace, currentSession, currentDocument, container, progress; + var immutableSkin; + + plugin.on("draw", function(e) { + // Create Ace + container = e.htmlNode.appendChild(document.createElement("div")); + container.className = "codeditorHolder"; + container.style.position = "absolute"; + container.style.left = "0px"; + container.style.right = "0px"; + container.style.top = ui.getStyle(e.htmlNode, "paddingTop"); + container.style.bottom = "0px"; + + // Create Ace editor instance + var theme = settings.get("user/ace/@theme"); + ace = new AceEditor(new VirtualRenderer(container, theme), null); + + + // temporary workaround for apf focus bugs + // only blur is needed sinse the rest is handled by tabManager + // todo remove this when there is proper focus manager + e.tab.$blur = function(e) { + var ace = plugin.ace; // can be null when called for destroyed tab + if (!ace || !e || !e.toElement || e.toElement.tagName == "menu") + return; + if (!ace.isFocused()) + ace.renderer.visualizeBlur(); + else + ace.textInput.blur(); + }; + ace.on("focus", function() { + var page = apf.findHost(container); + if (apf.activeElement != page) + page.focus(); + }); + + + // Create Menu + handle.draw(); + + createProgressIndicator(e.htmlNode); + + var tab = e.tab; + + tab.on("contextmenu", function(e) { + var target = e.htmlEvent.target; + var gutter = plugin.ace.container.querySelector(".ace_gutter"); + + // Set Gutter Context Menu + if (ui.isChildOf(gutter, target, true)) { + mnuGutter.show(e.x, e.y); + } + // Set main Ace Context Menu + else { + mnuAce.show(e.x, e.y); + } + return false; + }); + + addEditor(ace); + }); + + plugin.on("createAce", function(ace) { + if (c9.readonly) + ace.setReadOnly(true); + + addCorner(ace); + + ace.keyBinding.setDefaultHandler(null); + + // Route gutter events + ace.on("gutterclick", function(e){ emit("guttermousedown", e); }); + ace.on("gutterdblclick", function(e){ emit("gutterdblclick", e); }); + + // use global commandKeyBinding + // ace.commands.commandKeyBinding = {}; + + handle.on("settingsUpdate", function(e) { + setOptions(e.options); + }, plugin); + + handle.on("themeChange", function(e) { + ace.setTheme(e.path); + changeTheme(); + + emit("themeChange", e); + }, plugin); + + if (handle.theme) + ace.setTheme(handle.theme.path); + }); + + plugin.on("newListener", function(event, listener) { + if (event == "createAce" && ace) + listener(ace); + }); + + /***** Methods *****/ + + function addEditor(ace) { + emit("createAce", ace); + } + + function focus(){ + if (container) { + ui.addClass(container, "aceFocus"); + plugin.ace.focus(); + } + } + function blur(){ + if (container) { + ui.removeClass(container, "aceFocus"); + ace.blur(); + } + } + + var afterAnim; + function resize(e) { + var renderer = ace && ace.renderer; + if (!renderer || !currentDocument) return; + + if (e.type == "anim") { + var htmlNode = ace.container; + if (!htmlNode) + return; + + if (e.vertical) { + var size = e.current === 0 + ? Math.abs(e.delta) - 5 + - currentDocument.tab.pane.aml.$buttons.offsetHeight + : htmlNode.offsetHeight + e.delta; + + renderer.onResize(true, null, null, size); + } + else { + renderer.onResize(true, null, + htmlNode.offsetWidth + e.delta); + } + afterAnim = true; + } + else if (e.type == "afteranim" && afterAnim) { + afterAnim = false; + } else { + afterAnim = false; + renderer.$updateSizeAsync(); + } + } + + function getState(doc, state, filter) { + if (filter) return; + + var session = doc.getSession().session; + if (!session) return; + + // Folds + state.folds = session.getAllFolds().map(function(fold) { + return { + start: fold.start, + end: fold.end, + placeholder: fold.placeholder + }; + }); + + // Per document options + var options = {}; + docSettings.forEach(function(setting) { + var name = setting[0]; + options[name] = getOption(name, {session: session}); + }); + + if (options.guessTabSize) { + delete options.tabSize; + delete options.useSoftTabs; + } + + // Custom Type + if (session.customSyntax) + state.customSyntax = session.customSyntax; + + // Scroll state + state.scrolltop = session.getScrollTop(); + state.scrollleft = session.getScrollLeft(); + + // Selection & options + state.selection = session.selection.toJSON(); + state.options = options; + + var row = doc.editor.ace + ? doc.editor.ace.renderer.getFirstVisibleRow() + : 0; + state.firstLineState = row && session.bgTokenizer && { + row: row - 1, + state: session.bgTokenizer.states[row - 1], + mode: session.$mode.$id + }; + } + + function setState(doc, state) { + var c9Session = doc.getSession(); + var session = c9Session.session; + if (!session) return; // Happens when called after tab is closed + + if (state.cleansed) + state.firstLineState = state.folds = null; + + // Set customSyntax + if (state.customSyntax) { + session.customSyntax = state.customSyntax; + setSyntax(c9Session, session.customSyntax); + } + + // Set folds + if (state.folds) { + try { + state.folds.forEach(function(fold) { + session.addFold(fold.placeholder, + Range.fromPoints(fold.start, fold.end)); + }); + } catch (e) { + state.folds = null; + } + } + + if (state.firstLineState && session.bgTokenizer) { + var firstLineState = state.firstLineState; + var updateFirstLineState = function() { + session.bgTokenizer.states[firstLineState.row] + = firstLineState.state; + }; + if (session.$mode.$id == state.firstLineState.mode) { + updateFirstLineState(); + } else + session.once("changeMode", updateFirstLineState); + } + + function updateSession(){ + if (state.options && state.options.guessTabSize) { + delete state.options.tabSize; + delete state.options.useSoftTabs; + } + // Set per document options + setOptions(state.options, c9Session); + + // Jump to + if (state.jump) { + var row = state.jump.row; + var column = state.jump.column; + + if (typeof row === "number") { + scrollTo(row, column, state.jump.select, session); + state.scrolltop = state.scrollleft = undefined; + } + } + // Set selection + else if (state.selection) + session.selection.fromJSON(state.selection); + + // Set scroll state + if (state.scrolltop) + session.setScrollTop(state.scrolltop); + if (state.scrollleft) + session.setScrollLeft(state.scrollleft); + } + + if (ace.session == session) + updateSession(); + else { + var clean = function(){ + ace.off("changeSession", listen); + session.off("unload", clean); + }; + var listen = function(e) { + if (e.session == session) { + updateSession(); + clean(); + } + }; + + ace.on("changeSession", listen); + session.on("unload", clean); + } + } + + function scrollTo(row, column, select, session) { + if (row === undefined) + return; + + (currentSession && currentSession.session || session) + .unfold({row: row, column: column || 0}); + + ace.selection.clearSelection(); + ace.moveCursorTo(row, column || 0); + if (select) + session.getSelection().selectToPosition(select); + + var range = ace.selection.getRange(); + var initialScroll = ace.renderer.scrollTop; + ace.renderer.scrollSelectionIntoView(range.start, range.end, 0.5); + + ace.renderer.animateScrolling(initialScroll); + } + + function changeTheme(){ + if (immutableSkin || !currentSession) + return; + + var theme = handle.theme; + if (handle.theme && currentSession.cssClass != theme.cssClass) { + var tab = currentDocument.tab; + var html = plugin.aml.$int; + + if (theme.isDark) { + tab.classList.add("dark"); + html.style.boxShadow = ""; + } + else { + tab.classList.remove("dark"); + html.style.boxShadow = skin.indexOf("flat") == -1 + "0 1px 0 0 rgba(255, 255, 255, .3) inset" + ""; + } + + html.style.backgroundColor = theme.bg; + + tab.backgroundColor = theme.bg; + // tab.foregroundColor = theme.fg; + + currentSession.isDark = theme.isDark; + } + } + + function getOption(name, c9Session) { + var session = (c9Session || currentSession).session; + + if (name == "synax") + return session && session.syntax; + else if (name == "useWrapMode") + return session && session.getOption("wrap") !== "off"; + else if (name == "wrapToView") + return session && session.getOption("wrap") !== "printMargin"; + else if (name == "guessTabSize") + return session && session.$guessTabSize; + + return (session.$options[name] ? session : ace).getOption(name); + } + + function setOptions(options, c9Session) { + for (var prop in options) { + setOption(prop, options[prop], c9Session); + } + } + + function setOption(name, value, c9Session) { + if (!c9Session) + c9Session = currentSession; + var session = (c9Session || {}).session; + + if (docLut[name] && c9Session) + c9Session.options[name] = value; + + if (ui.isFalse(value)) + value = false; + + // Own Implementations + switch(name) { + case "theme": + ace.setTheme(value); + return; + case "syntax": + if (session) { + var mode = getMode(value); + session.syntax = value; + session.setMode(mode); + } + return; + case "antialiasedfonts": + return; + case "useWrapMode": + case "wrapToView": + var useWrapMode, wrapToView; + if (!session) return; + + if (name != "useWrapMode") { + wrapToView = value; + useWrapMode = session.getOption("wrap") != "off"; + } + else { + useWrapMode = value; + wrapToView = session.getOption("wrap") == "free"; + } + + value = (useWrapMode ? wrapToView || "printMargin" : false); + + /* falls through */ + case "wrap": + session._emit("setWrap", { value: value }); + session.setOption("wrap", value); + return; + case "guessTabSize": + if (session) + session.$guessTabSize = value; + return; + case "tabSize": /* fallThrough */ + case "useSoftTabs": + if (session) + session.$guessTabSize = false; + break; + } + + if (session && docLut[name]) // this can be called for session different than current ace session + session.setOption(name, value); + else // TODO when called with session this can refer to a wrong ace + ace.setOption(name, value); + } + + function createProgressIndicator(parent) { + var background = parent.appendChild(document.createElement("div")); + background.style.cssText = "background: inherit;" + + "position:absolute;top:0;bottom:0;left:0;right:0;"; + + background.style.zIndex = 20000; + background.style.transitionProperty = "opacity"; + background.style.display = "none"; + + progress = background.appendChild(document.createElement("div")); + progress.className = "ace_progress"; + progress.innerHTML = "
      "; + + progress.background = background; + } + + function hideProgress(){ + var style = progress.background.style; + function hide() { + style.display = "none"; + style.transitionDuration = 0; + progress.firstChild.style.width = "0%"; + } + if (ace.renderer.$frozen && ace.renderer.$changes) { + ace.renderer.once("afterRender", hide); + ace.renderer.$loop.schedule(ace.renderer.$changes); + } else { + hide(); + } + style.transitionDelay = 0; + style.opacity = 0; + + ace.renderer.unfreeze(); + // ace.resize(true); + } + + function showProgress(value, upload, t) { + if (!upload) + ace.renderer.freeze(); + + var growT = 200; + if (progress.t && t && progress.t - t) { + var vTotal = value / t; + var vLast = progress.value / progress.t; + var v = 0.6 * vTotal + 0.4 * vLast; + growT = Math.max((value - progress.value) / v, 0) || 200; + } + + if (upload) { + if (value === 0) { + progress.start = t; + return; + } + else if (t - progress.start < 100) + return; + } + + if (value === undefined) value = 0; + + progress.value = value; + progress.t = t; + progress.firstChild.style.width = value + "%"; + progress.firstChild.style.transition = "width " + growT + "ms"; + + progress.className = "ace_progress" + (upload ? " upload" : ""); + + // todo should we use this instead of forcing transition with clientHeight ? + // var fadeIn = function() { + // setTimeout(function () { + // if (bgStyle.display === "block") { + // bgStyle.opacity = 1; + // } + // }); + // }; + var bgStyle = progress.background.style; + if (progress.noFadeIn || upload) { + bgStyle.display = "block"; + bgStyle.opacity = 1; + } + else if (bgStyle.display !== "block") { + bgStyle.display = "block"; + bgStyle.transitionDuration = Math.max(150 - (t || 0), 0) + "ms"; + bgStyle.transitionDelay = Math.max(100 - (t || 0), 0) + "ms"; + progress.forcedTransition = progress.background.clientHeight; + bgStyle.opacity = 1; + } + + bgStyle.bottom = upload ? "" : 0; + } + + function detectSettingsOnLoad(c9Session) { + var session = c9Session.session; + whitespaceUtil.detectIndentation(session); + if (!session.syntax) { + var syntax = detectSyntax(c9Session); + if (syntax) + setSyntax(c9Session, syntax, true); + } + + var newLineMode = session.doc.getNewLineMode(); + if (newLineMode === "auto") { + var autoNewLine = session.doc.$autoNewLine; + if (autoNewLine == "\r\n") { + newLineMode = "windows"; + } else if (autoNewLine == "\n") { + newLineMode = "unix"; + } else { + newLineMode = settings.get("project/ace/@newLineMode"); + } + session.doc.setNewLineMode(newLineMode); + } + } + + /***** Lifecycle *****/ + + //@todo set selection, scroll and file in header + + plugin.on("load", function(){ + + }); + + plugin.on("documentLoad", function(e) { + var doc = e.doc; + var c9Session = doc.getSession(); + + // if load starts from another editor type + // tabmanager will show as instantly + // so we need to show progress bar instantly + progress.noFadeIn = !currentDocument; + + // Value Retrieval + doc.on("getValue", function get(e) { + var session = c9Session.session; + return session + ? session.doc.getValue(session.doc.$fsNewLine) + : e.value; + }, c9Session); + + // Value setting + doc.on("setValue", function set(e) { + var aceSession = c9Session.session; + if (!aceSession) + return; //This is probably a deconstructed document + + // The first value that is set should clear the undo stack + // additional times setting the value should keep it. + if (aceSession.c9doc.hasValue()) { + merge.patchAce(e.value || "", aceSession.doc); + // aceSession.doc.setValue(e.value || ""); + } else { + aceSession.setValue(e.value || ""); + detectSettingsOnLoad(c9Session); + hideProgress(); + } + + if (e.state) + setState(doc, e.state); + + if (currentDocument === doc) + ace.renderer.unfreeze(); + }, c9Session); + + doc.on("mergeState", function() { + return false; + }, c9Session); + + doc.on("progress", function(e) { + if (e.complete) { + c9Session.progress = 0; + } + else { + var progress = ((e.loaded / e.total) * 100) || 0; + if (progress >= (c9Session.progress || 0) || (c9Session.progress == 100 && !progress)) { + c9Session.progress = progress; + } else if (c9Session.progress && e.upload) { + // see https://github.com/c9/newclient/issues/3682 + // disabled warning for download since this happens very often with collab, + // because socket is not able to keep up with the load + // todo reenable when collab issue is fixed + errorHandler.reportError("Weird progress value", { + newValue: progress, + oldValue: c9Session.progress, + upload: e.upload + }); + } + } + + c9Session.upload = e.upload; + + if (currentSession != c9Session) + return; + + if (e.complete) + doc.hasValue() && setTimeout(hideProgress, 0); + else + showProgress(c9Session.progress, c9Session.upload, e.dt); + }, c9Session); + + doc.on("clone", function(e){ + var newsession = e.doc.getSession("ace"); + // var newundo = new AceUndoManager(doc.undoManager, c9Session); + newsession.session = cloneSession(c9Session.session); //, newundo); + newsession.undoManager = newsession.session.$undoManager; + }, c9Session); + + // Title & Tooltip + function setTitle(e) { + var path = doc.tab.path; + if (!path) return; + + // Caption is the filename + doc.title = path.substr(path.lastIndexOf("/") + 1); + + // Tooltip is the full path + doc.tooltip = path; + } + setTitle({path: doc.tab.path || ""}); + + // Update mode when the filename changes + doc.tab.on("setPath", function(e) { + setTitle(e); + // This event is triggered also when closing files, + // so session may be gone already. + if (c9Session.session) { + var syntax = getSyntax(c9Session, doc.tab.path); + setOption("syntax", syntax, c9Session); + } + }, c9Session); + + // Prevent existing session from being reset + if (c9Session.inited) + return; + + // Create an ace session + var aceSession = e.state && e.state.session || c9Session.session; + if (!aceSession) { + var acedoc = new Document(doc.value || ""); + aceSession = e.state.session || new EditSession(acedoc); + } + c9Session.session = aceSession; + c9Session.session.c9doc = doc; + c9Session.options = {}; + c9Session.setOption = function(name, value) { + setOption(name, value, this); + }; + c9Session.inited = true; + + if (!e.state || !e.state.options) + docSettings.forEach(function(setting) { + var name = setting[0]; + setOption(name, setting[1], c9Session); + }); + + if (e.state && e.state.customSyntax) + c9Session.session.customSyntax = e.state.customSyntax; + + var syntax = getSyntax(c9Session, doc.tab.path); + setOption("syntax", syntax, c9Session); + + if (e.state) + setState(doc, e.state); + + if (doc.meta.newfile) { + detectSettingsOnLoad(c9Session); + aceSession.on("change", function detectIndentation() { + if (aceSession.$guessTabSize) { + if (aceSession.getLength() <= 2) return; + whitespaceUtil.detectIndentation(aceSession); + if (doc.editor && doc.editor.ace) + doc.editor.ace._signal("changeStatus"); + } + aceSession.off("change", detectIndentation); + }); + } else if (doc.hasValue()) { + detectSettingsOnLoad(c9Session); + } + + // Create the ace like undo manager that proxies to + // the Cloud9 undo manager + if (!c9Session.undoManager) { + c9Session.undoManager + = new AceUndoManager(doc.undoManager, c9Session); + + // Attach the ace undo manager to the current session + c9Session.session.setUndoManager(c9Session.undoManager); + } + + handleEmit("initAceSession", { doc: doc }); + c9Session.getEmitter().sticky("init", { + doc: doc, + session: c9Session.session + }); + + doc.on("unload", function(){ + setTimeout(function() { //@todo is this still needed? + var session = c9Session.session; + if (!session) + return; + + if (session.cloned) { + session.cleanup(); + } + else { + var doc = session.doc; + if (doc) { + doc.$lines = []; + doc._eventRegistry = null; + doc._defaultHandlers = null; + } + session.destroy(); + session.bgTokenizer = null; + session.$rowCache = null; + session._eventRegistry = session.$mode = null; + session.$breakpoints = null; + session.$annotations = null; + session.languageAnnos = null; + session.c9doc = null; + } + + c9Session.session = null; + c9Session = null; + }); + }); + }); + plugin.on("documentActivate", function(e) { + //editor.value = e.doc.value; + currentDocument = e.doc; + currentSession = e.doc.getSession(); + + var options = currentSession.options; + docSettings.forEach(function(setting) { + if (options[setting[2]]) + setOption(setting[0], options[setting[2]]); + }); + + if (currentSession.session) + ace.setSession(currentSession.session); + + // if (!currentSession.progress && !e.doc.hasValue()) + // console.warn("broken session progress state on documentActivate see #1144", e.doc); + + if (currentSession.progress || !e.doc.hasValue()) + showProgress(currentSession.progress, currentSession.upload); + else + hideProgress(); + + // Theme support + changeTheme(); + }); + plugin.on("documentUnload", function(e) { + var session = e.doc.getSession(); + + // Clear current session + if (currentSession == session) { + currentSession = null; + currentDocument = null; + + if (ace) { + ace.setSession(dummySession); + ace.renderer.freeze(); + } + } + }); + plugin.on("resize", function(e) { + resize(e); + }); + plugin.on("getState", function(e) { + getState(e.doc, e.state, e.filter); + }); + plugin.on("setState", function(e) { + setState(e.doc, e.state); + }); + plugin.on("clear", function(){ + if (currentSession) + currentSession.session.setValue(""); + }); + plugin.on("cut", function(e) { + if (e.native) return; // Ace handles this herself + + var data = ace.getCopyText(); + ace.onCut(); + e.clipboardData.setData("text/plain", data); + }); + plugin.on("copy", function(e) { + if (e.native) return; // Ace handles this herself + + var data = ace.getCopyText(); + e.clipboardData.setData("text/plain", data); + }); + plugin.on("paste", function(e) { + if (e.native) return; // Ace handles this herself + + var data = e.clipboardData.getData("text/plain"); + if (data !== false) + ace.onPaste(data); + }); + plugin.on("blur", function(){ + blur(); + }); + plugin.on("focus", function(e) { + if (e.lost) blur(); + else focus(); + }); + plugin.on("enable", function(){ + ui.removeClass(container, "aceDisabled"); + }); + plugin.on("disable", function(){ + ui.addClass(container, "aceDisabled"); + }); + plugin.on("unload", function(){ + ace.destroy(); + container.innerHTML = ""; + + ace = null; + container = null; + }); + + /***** Register and define API *****/ + + /** + * Ace Editor for Cloud9. Ace is the high performance code + * editor for the web, build and maintained by Cloud9. + * It is the main editor for code files and offers syntax + * highlighting for over 100 languages and formats. + * For more information see [ace's website](http://ace.c9.io). + * + * The editor exposes the [ace editor object](http://ace.c9.io/#nav=api&api=editor) + * which in turn exposes many APIs that allow you to manipulate + * the editor and it's contents. + * + * Example of instantiating a new terminal: + * + * tabManager.openFile("/file.js", true, function(err, tab) { + * if (err) throw err; + * + * var ace = tab.editor; + * ace.setOption("tabSize", 8); + * }); + * + * @class ace.Ace + * @extends Editor + */ + /** + * The type of editor. Use this to create ace using + * {@link tabManager#openEditor} or {@link editors#createEditor}. + * @property {"ace"} type + * @readonly + */ + /** + * Retrieves the state of a document in relation to this editor + * @param {Document} doc The document for which to return the state + * @method getState + * @return {Object} + * @return {String} return.customSyntax The language mode for this document (if the default mode has been overridden). + * @return {Number} return.scrolltop The amount of pixels scrolled from the top. + * @return {Number} return.scrollleft The amount of pixels scrolled from the left. + * @return {Array} return.folds Describing the current state + * of the folded code in the document. + * @return {Object} return.selection Describing the current state + * of the selection. This can become a complex object when + * there are multiple selections. + * @return {Object} return.options + * @return {String} return.options.newLineMode One of three values: "windows", "unix", "auto". + * @return {Number} return.options.tabSize The number of spaces that is used to render a tab. + * @return {Boolean} return.options.useSoftTabs When set to true the tab button inserts spaces. + * @return {Boolean} return.options.useWrapMode Specifies whether the text is wrapped + * @return {Boolean} return.options.wrapToView Specifies whether the text is wrapped to the viewport, or to the print margin. + * @return {Boolean} return.options.wrapBehavioursEnabled Specifies whether selection wraps with Brackets, Quotes, etc. + */ + /** + * Sets the state of a document in relation to this editor + * @method setState + * @param {Document} doc The document for which to set the state + * @param {Object} state The state to set + * @param {String} [state.customSyntax] The language mode for this document (if the default mode has been overridden). + * @param {Number} [state.scrolltop] The amount of pixels scrolled from the top. + * @param {Number} [state.scrollleft] The amount of pixels scrolled from the left. + * @param {Array} [state.folds] Describing the current state + * of the folded code in the document. + * @param {Object} [state.selection] Describing the current state + * of the selection. This can become a complex object when + * there are multiple selections. + * @param {Object} [state.options] + * @param {String} [state.options.newLineMode] One of three values: "windows", "unix", "auto". + * @param {Number} [state.options.tabSize] The number of spaces that is used to render a tab. + * @param {Boolean} [state.options.useSoftTabs] When set to true the tab button inserts spaces. + * @param {Boolean} [state.options.useWrapMode] Specifies whether the text is wrapped + * @param {Boolean} [state.options.wrapToView] Specifies whether the text is wrapped to the viewport, or to the print margin. + * @param {Boolean} [state.options.wrapBehavioursEnabled] Specifies whether selection wraps with Brackets, Quotes, etc. + * @param {Object} [state.jump] Scrolls the document (with an animation) to the specified location (and optionally selection). + * @param {Number} [state.jump.row] The row to jump to (0 based) + * @param {Number} [state.jump.column] The column to jump to (0 based) + * @param {Object} [state.jump.select] + * @param {Number} [state.jump.select.row] The row to select to (0 based) + * @param {Number} [state.jump.select.column] The column to select to (0 based) + */ + plugin.freezePublicAPI({ + /** + * @ignore + */ + addEditor: addEditor, + /** + * Reference to the ace editor object as described + * [here](http://ace.c9.io/#nav=api&api=editor) + * @property {Ace.Editor} ace + * @readonly + */ + get ace(){ return emit("getAce") || ace; }, + + /** + * The theme object currently used in this ace instance + * @property {Object} theme Describes the theme that is initialized. + * @property {String} theme.cssClass The css class name related to the theme. + * @property {String} theme.bg The background color for this theme. + * @property {String} theme.fg The foreground color for this theme. + * @property {String} theme.path The path of this theme. + * @property {Boolean} theme.isDark Specifies whether this is a dark theme or a light theme. + * @readonly + */ + get theme(){ + if (!ace) return ""; + if (immutableSkin) { + var path = ace.getTheme(); + try { var theme = require(path); } catch (e) {} + return theme || ""; + } + else { + return handle.theme; + } + return theme; + }, + + _events: [ + /** + * Fires when a users clicks on the gutter. + * The gutter is the area that contains the line numbers. + * @event guttermousedown + * @param {Object} e information on the mouse event + */ + "guttermousedown", + /** + * Fires when a users clicks twice in fast succession on + * the gutter. The gutter is the area that contains the + * line numbers. + * @event gutterdblclick + * @param {Object} e information on the mouse event + */ + "gutterdblclick", + /** + * Fires when the current theme changes to another theme. + * + * See also {@link ace#setTheme}. + * + * @event themeChange + * @param {Object} e + * @param {Object} e.theme Describes the theme that is initialized. + * @param {String} e.theme.cssClass The css class name related to the theme. + * @param {String} e.theme.bg The background color for this theme. + * @param {String} e.theme.fg The foreground color for this theme. + * @param {String} e.theme.path The path of this theme. + * @param {Boolean} e.theme.isDark Specifies whether this is a dark theme or a light theme. + * @param {Object} e.lastTheme Describes the theme that is initialized. + * @param {String} e.lastTheme.cssClass The css class name related to the theme. + * @param {String} e.lastTheme.bg The background color for this theme. + * @param {String} e.lastTheme.fg The foreground color for this theme. + * @param {String} e.lastTheme.path The path of this theme. + * @param {Boolean} e.lastTheme.isDark Specifies whether this is a dark theme or a light theme. + * @param {String} e.path The path of the theme. + */ + "themeChange" + ], + + /** + * @ignore This is here to overwrite default behavior + */ + isClipboardAvailable: function(e) { return !e.fromKeyboard }, + + /** + * Retrieves the value of one of the ace options. + * + * See {@link #setOption} for an overview of the options that can be retrieved. + * + * @param {String} option The option to retrieve + */ + getOption: getOption, + + /** + * Sets the value of one of the ace options. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
      Option Name Possible Values
      "theme" The path to the new theme.
      "syntax" The path to the ace mode (e.g. ace/mode/javascript).
      "newLineMode" One of the following values: "windows", "unix", "auto".
      "tabSize" Number specifying the amount of spaces that represent a tab.
      "useSoftTabs" Boolean specifying whether to insert spaces when pressing the tab key.
      "useWrapMode" Specifies whether the text is wrapped
      "wrapToView" Specifies whether the text is wrapped to the viewport, or to the print margin.
      "wrapBehavioursEnabled" Specifies whether selection wraps with Brackets, Quotes, etc.
      "fontSize" Number specifying the font size in px.
      "fontFamily" String specifying the font family in css syntax.
      "overwrite" Boolean toggling overwrite mode.
      "selectionStyle" One of the following values: "line" (select the entire line), "text" (only select the text).
      "cursorStyle" One of the following values: "ace", "slim", "smooth", "wide"
      "highlightActiveLine" Boolean specifying whether to show highlighting of the line where the cursor is at.
      "highlightGutterLine" Boolean specifying whether to show highlighting in the gutter of the line where the cursor is at.
      "showInvisibles" Boolean specifying whether to show the invisible characters such as space, tab, newline.
      "printMarginColumn" Number specifying where the print margin will be in number of characters from the gutter.
      "showPrintMargin" Boolean specifying whether to show the print margin line (usually 80 chars)
      "displayIndentGuides" Boolean specifying whether to show the lines at each indentation mark
      "behavioursEnabled" Boolean specifying whether brackets are auto-paired.
      "scrollSpeed" Number specifying the number of rows that are scrolled when using the scrollwheel.
      "showGutter" Boolean specifying whether to show the gutter.
      "showFoldWidgets" Boolean specifying whether to show the fold widgets.
      "fadeFoldWidgets" Boolean specifying whether to fade the fold widgets into view on hover.
      "highlightSelectedWord" Boolean specifying whether to highlight words where the cursor is on.
      "animatedScroll" Boolean specifying whether scrolling is animated.
      "scrollPastEnd" Number specifying how far the user can scroll past the end. There are 3 possible values: 0, 0.5, 1.
      "mergeUndoDeltas" Boolean specifying whether to combine multiple operations as one on the undo stack.
      + * + * @param {String} option The option to set + * @param {String} value The value of the option + */ + setOption: setOption, + + /** + * Set multiple options by passing a multi-dimensional array + * with key/value pairs. + * + * See also {@link #setOption} + * + * @param {Array} options The options to set. + */ + setOptions: setOptions, + + /** + * Scrolls the currently active document to the specified row + * and column and places the cursor there and optionally + * select a piece of text. + * + * @param {Number} row The row to jump to (0 based) + * @param {Number} column The column to jump to (0 based) + * @param {Object} [select] + * @param {Number} [select.row] The row to select to (0 based) + * @param {Number} [select.column] The column to select to (0 based) + */ + scrollTo: scrollTo + }); + + // Emit create event on handle + setTimeout(function(){ + if (plugin.loaded) { + handleEmit.sticky("create", { editor: plugin }, plugin); + } + }); + + plugin.load(null, "ace"); + + return plugin; + } + + register(null, { + ace: handle + }); + } +}); diff --git a/plugins/c9.ide.ace/ace_test.js b/plugins/c9.ide.ace/ace_test.js new file mode 100644 index 00000000..75a3bbd1 --- /dev/null +++ b/plugins/c9.ide.ace/ace_test.js @@ -0,0 +1,545 @@ +/*global describe it before after bar*/ + +"use client"; + +require(["lib/architect/architect", "lib/chai/chai"], function (architect, chai) { + var expect = chai.expect; + + expect.setupArchitectTest([ + { + packagePath: "plugins/c9.core/c9", + workspaceId: "ubuntu/ip-10-35-77-180", + startdate: new Date(), + debug: true, + hosted: true, + local: false, + davPrefix: "/" + }, + + "plugins/c9.core/ext", + "plugins/c9.core/http-xhr", + "plugins/c9.core/util", + "plugins/c9.ide.ui/lib_apf", + "plugins/c9.ide.ui/menus", + { + packagePath: "plugins/c9.core/settings", + settings: "default", + testing: true + }, + "plugins/c9.core/api.js", + { + packagePath: "plugins/c9.ide.ui/ui", + staticPrefix: "plugins/c9.ide.ui" + }, + "plugins/c9.ide.editors/document", + "plugins/c9.ide.editors/undomanager", + { + packagePath: "plugins/c9.ide.editors/editors", + defaultEditor: "ace" + }, + "plugins/c9.ide.editors/editor", + "plugins/c9.ide.editors/tabmanager", + "plugins/c9.ide.ui/focus", + "plugins/c9.ide.editors/pane", + "plugins/c9.ide.editors/tab", + { + packagePath: "plugins/c9.ide.ace/ace", + staticPrefix: "plugins/c9.ide.layout.classic" + }, + "plugins/c9.ide.keys/commands", + "plugins/c9.fs/proc", + "plugins/c9.vfs.client/vfs_client", + "plugins/c9.vfs.client/endpoint", + "plugins/c9.ide.auth/auth", + "plugins/c9.fs/fs", + + "plugins/c9.ide.dialog/dialog", + "plugins/c9.ide.dialog.common/alert", + "plugins/c9.ide.dialog.common/alert_internal", + + // Mock plugins + { + consumes: ["apf", "ui", "Plugin"], + provides: [ + "commands", "menus", "layout", "watcher", + "save", "preferences", "anims", "clipboard", "auth.bootstrap", + "info", "dialog.error", "threewaymerge", "error_handler" + ], + setup: expect.html.mocked + }, + { + consumes: ["tabManager", "ace", "commands"], + provides: [], + setup: main + } + ], architect); + + function main(options, imports, register) { + var tabs = imports.tabManager; + var ace = imports.ace; + var commands = imports.commands; + + function getTabHtml(tab) { + return tab.pane.aml.getPage("editor::" + tab.editorType).$ext; + } + + expect.html.setConstructor(function(tab) { + if (tab && typeof tab == "object") + return getTabHtml(tab); + }); + + describe('ace', function() { + before(function(done) { + apf.config.setProperty("allow-select", false); + apf.config.setProperty("allow-blur", false); + + bar.$ext.style.background = "rgba(220, 220, 220, 0.93)"; + bar.$ext.style.position = "fixed"; + bar.$ext.style.left = "20px"; + bar.$ext.style.width = "1000px"; + bar.$ext.style.bottom = "20px"; + bar.$ext.style.height = "33%"; + + document.body.style.marginBottom = "33%"; + + tabs.once("ready", function(){ + tabs.getPanes()[0].focus(); + done(); + }); + }); + + describe("open", function(){ + this.timeout(10000); + + it('should open a pane with just an editor', function(done) { + tabs.openFile("/file.txt", function(err, tab) { + expect(tabs.getTabs()).length(1); + + expect(tab.document.title).equals("file.txt"); + done(); + }); + }); + it('should handle multiple documents in the same pane', function(done) { + tabs.openFile("/listing.json", function(err, tab) { + expect(tabs.getTabs()).length(2); + + tab.activate(); + + var doc = tab.document; + expect(doc.title).match(new RegExp("listing.json")); + done(); + }); + }); + }); + describe("clear(), getState() and setState()", function(){ + var state, info = {}; + + it('should retrieve the state', function(done) { + // @todo make sure ace has a selection and scrolltop / left + + state = tabs.getState(); + info.pages = tabs.getTabs().map(function(tab) { + return tab.path || tab.id; + }); + done(); + }); + it('should clear all tabs and pages', function(done) { + tabs.getPanes()[0]; + var pages = tabs.getTabs(); + tabs.clear(true, true); //Soft clear, not unloading the pages + expect(tabs.getTabs(), "pages").length(0); + expect(tabs.getPanes(), "tabManager").length(0); + //expect(pane.getTabs(), "aml").length(0); + done(); + }); + it('should restore the state', function(done) { + // @todo make sure the selection and scrolltop / left is preserved + + tabs.setState(state, false, function(err) { + if (err) throw err.message; + }); + var l = info.pages.length; + expect(tabs.getTabs()).length(l); + expect(tabs.getPanes()[0].getTabs()).length(l); + expect(tabs.focussedTab.pane.getTabs()).length(l); + + expect(tabs.getTabs().map(function(tab) { + return tab.path || tab.id; + })).to.deep.equal(info.pages); + done(); + }); + it('should jump to on an already loaded file', function(done) { + var tab = tabs.focussedTab; + tab.document.setState({ + ace: { + jump: { + row: 3, + column: 10 + } + } + }); + var cursor = tab.editor.ace.getCursorPosition(); + expect(cursor.row).equals(3); + expect(cursor.column).equals(10); + done(); + }); + }); + describe("split(), pane.unload()", function(){ + it('should split a pane horizontally, making the existing pane the left one', function(done) { + var pane = tabs.focussedTab.pane; + var righttab = pane.hsplit(true); + tabs.focussedTab.attachTo(righttab); + done(); + }); + it('should remove the left pane from a horizontal split', function(done) { + var pane = tabs.getPanes()[0]; + var tab = tabs.getPanes()[1].getTab(); + pane.unload(); + expect(tabs.getPanes()).length(1); + expect(tabs.getTabs()).length(2); + tabs.focusTab(tab); + done(); + }); + }); + describe("focus(), blur()", function(){ + it('should get the right className and take keyboard input when focussed', function(done) { + done(); + }); + it('should get the right className and don\'t take any keyboard input when blurred', function(done) { + done(); + }); + }); + describe("customType", function(){ + it('should remember custom types set on known extensions', function(done) { + + //@todo check if it is recorded in settings + done(); + }); + it('should remember custom types set on unknown extensions', function(done) { + + //@todo check if it is recorded in settings + done(); + }); + }); + + function render(){ + var editor = tabs.focussedTab.editor; + var changes = editor.ace.renderer.$loop.changes; + editor.ace.renderer.$loop.changes = 0; + editor.ace.renderer.$renderChanges(changes, true); + } + + describe("setOption()", function(){ + this.timeout(10000); + var lineHeight, session, editor, charWidth, doc; + + before(function(done) { + doc = tabs.focussedTab.document; + editor = doc.editor; + session = doc.getSession().session; + lineHeight = doc.editor.ace.renderer.lineHeight; + charWidth =doc.editor.ace.renderer.characterWidth; + + done(); + }); + + it('should change a theme', function(done) { + var theme = "ace/theme/textmate"; + editor.ace.renderer.on("themeLoaded", function me(e) { + if (e.theme.cssClass != "ace-tm") return; + + editor.ace.renderer.removeListener("themeLoaded", me); + expect.html(getTabHtml(tabs.focussedTab).childNodes[1]).className("ace-tm"); + + ace.once("themeChange", function(){ + done(); + }); + ace.setTheme("ace/theme/tomorrow_night_bright"); + }); + ace.setTheme(theme); + }); + it('should allow setting useWrapMode', function(done) { + doc.value = "a very long string to be wrapped a very long string to be wrapped a very long string to be wrapped a very long string to be wrapped a very long string to be wrapped a very long string to be wrapped a very long string to be wrapped a very long string to be wrapped a very long string to be wrapped a very long string to be wrapped a very long string to be wrapped a very long string to be wrapped a very long string to be wrapped a very long string to be wrapped a very long string to be wrapped a very long string to be wrapped "; + + render(); + + expect(document.querySelector(".ace_gutter-cell").offsetHeight).to.equal(lineHeight); + editor.setOption("useWrapMode", true); + + render(); + + expect(Math.ceil(document.querySelector(".ace_gutter-cell").offsetHeight)).to.equal(lineHeight * 7); + done(); + }); + it('should allow setting wrapToView', function(done) { + expect(document.querySelector(".ace_gutter-cell").offsetHeight).to.equal(lineHeight * 7); + editor.setOption("wrapToView", true); + + render(); + + expect(document.querySelector(".ace_gutter-cell").offsetHeight).to.equal(lineHeight * 4); + done(); + }); + it('should allow setting wrapBehavioursEnabled', function(done) { + done(); + }); + it('should allow setting newLineMode', function(done) { + editor.setOption("newLineMode", "windows"); + doc.value = "line1\nline2\nline3\nline4\nline5"; + + render(); + + expect(session.getValue(session.doc.$fsNewLine)).to.match(/\r/); + + editor.setOption("newLineMode", "unix"); + + expect(session.getValue()).to.not.match(/\r/); + + editor.setOption("newLineMode", "auto"); + + expect(session.getValue()).to.not.match(/\r/); + + done(); + }); + it('should allow setting tabSize', function(done) { + doc.value = "\tline1\n\t\tline2\n\t\tline3\n\tline4\nline5"; + render(); + + editor.setOption("tabSize", 4); + + render(); + expect.html(doc.tab, "tabSize: 4").text(/\s{8}/); + + editor.setOption("tabSize", 8); + render(); + + expect.html(doc.tab, "tabSize: 8").text(/\s{16}/); + + done(); + }); + it('should allow setting useSoftTabs', function(done) { + doc.value = " line1\n line2\n line3\n line4\nline5"; + render(); + + editor.setOption("tabSize", 4); + editor.setOption("useSoftTabs", true); + + editor.ace.moveCursorTo(1, 0); + // command isAvailable works only if editor is focussed + // which might break the test when debugger is focussed + editor.ace.isFocused = function() {return true}; + commands.exec("gotoright", editor, null, + document.createEvent("KeyboardEvent")); + delete editor.ace.isFocused; + + expect(editor.ace.getCursorPosition()).deep.equal({row:1, column:4}); + + done(); + }); + it('should allow setting fontSize', function(done) { + expect(document.querySelector(".ace_gutter-cell").offsetHeight).equal(lineHeight); + + editor.setOption("fontSize", 30); + + expect(document.querySelector(".ace_gutter-cell").offsetHeight).gt(lineHeight); + + editor.setOption("fontSize", 12); + + done(); + }); + it('should allow setting fontFamily', function(done) { + editor.setOption("fontFamily", "Courier New"); + render(); + + expect(editor.ace.container.style.fontFamily).to.match(/Courier New/); + + var font = "Monaco, Menlo, 'Ubuntu Mono', Consolas, source-code-pro, monospace"; + editor.setOption("fontFamily", font); + render(); + + expect(editor.ace.container.style.fontFamily).to.match(/Monaco/) + .and.to.not.match(/Courier/); + + done(); + }); + it('should allow setting selectionStyle', function(done) { + session.getSelection().setSelectionRange({ + start: { + row: 0, + column: 0 + }, + end: { + row: 4, + column: 0 + } + }, false); + + editor.setOption("selectionStyle", "text"); + render(); + + function selectionElementWidth() { + var el = document.querySelectorAll(".ace_selection")[0]; + return el.getBoundingClientRect().width; + } + + var chars = selectionElementWidth() / charWidth; + expect(chars - 10).to.lt(1/100); + + editor.setOption("selectionStyle", "line"); + render(); + + chars = selectionElementWidth() / charWidth; + expect(chars).to.gt(10); + + done(); + }); + it('should allow setting highlightActiveLine', function(done) { + session.getSelection().clearSelection(); + + editor.setOption("highlightActiveLine", false); + render(); + expect(document.querySelector(".ace_active-line")).to.not.ok; + + editor.setOption("highlightActiveLine", true); + render(); + expect(document.querySelector(".ace_active-line")).to.ok; + + done(); + }); + it('should allow setting highlightGutterLine', function(done) { + editor.setOption("highlightGutterLine", false); + render(); + expect(document.querySelector(".ace_gutter-active-line").offsetHeight).to.not.ok; + + editor.setOption("highlightGutterLine", true); + render(); + expect(document.querySelector(".ace_gutter-active-line").offsetHeight).to.ok; + + done(); + }); + it('should allow setting showInvisibles', function(done) { + editor.setOption("showInvisibles", true); + render(); + expect(document.querySelectorAll(".ace_invisible").length).ok; + editor.setOption("showInvisibles", false); + render(); + expect(document.querySelectorAll(".ace_invisible").length).not.ok; + + done(); + }); + it('should allow setting showPrintMargin', function(done) { + editor.setOption("showPrintMargin", false); + expect(document.querySelector(".ace_print-margin").style.visibility).equal("hidden"); + editor.setOption("showPrintMargin", true); + expect(document.querySelector(".ace_print-margin").style.visibility).equal("visible"); + done(); + }); + it('should allow setting printMarginColumn', function(done) { + editor.setOption("printMarginColumn", 100); + var value = Math.floor(parseInt(document.querySelector(".ace_print-margin").style.left) / charWidth); + expect(value).equal(100); + editor.setOption("printMarginColumn", 80); + var value = Math.floor(parseInt(document.querySelector(".ace_print-margin").style.left) / charWidth); + expect(value).equal(80); + done(); + }); + it('should allow setting displayIndentGuides', function(done) { + editor.setOption("displayIndentGuides", false); + render(); + expect(document.querySelector(".ace_indent-guide")).to.not.ok; + editor.setOption("displayIndentGuides", true); + render(); + expect(document.querySelector(".ace_indent-guide")).to.ok; + done(); + }); + it('should allow setting behavioursEnabled', function(done) { + editor.setOption("behavioursEnabled", false); + doc.value = "test"; + render(); + editor.ace.moveCursorTo(0, 4); + render(); + editor.ace.insert("("); + render(); + expect(doc.value).to.equal("test("); + + editor.setOption("behavioursEnabled", true); + doc.value = "test"; + render(); + editor.ace.moveCursorTo(0, 4); + render(); + editor.ace.insert("(") + render(); + expect(doc.value).to.equal("test()"); + + done(); + }); + it('should allow setting showGutter', function(done) { + editor.setOption("showGutter", false); + expect.html(document.querySelector(".ace_gutter")).not.visible; + editor.setOption("showGutter", true); + expect.html(document.querySelector(".ace_gutter")).visible; + done(); + }); + it('should allow setting showFoldWidgets', function(done) { + doc.value = "function(){\n\t\n}"; + editor.setOption("showFoldWidgets", false); + render(); + expect.html(document.querySelector(".ace_fold-widget")).not.ok; + editor.setOption("showFoldWidgets", true); + render(); + expect.html(document.querySelector(".ace_fold-widget")).ok; + done(); + }); + it('should allow setting highlightSelectedWord', function(done) { + doc.value = "test\ntest\ntest"; + session.getSelection().setSelectionRange({ + start: { + row: 0, + column: 0 + }, + end: { + row: 0, + column: 4 + } + }, false); + editor.setOption("highlightSelectedWord", false); + render(); + expect.html(document.querySelector(".ace_selected-word")).not.ok; + editor.setOption("highlightSelectedWord", true); + render(); + expect.html(document.querySelector(".ace_selected-word")).ok; + done(); + }); + it('should allow setting animatedScroll', function(done) { + var i = 0; + doc.value = Array(100).join("x").split("x").map(function(){return "Line " + i++}).join("\n"); + render(); + + editor.setOption("animatedScroll", false); + editor.scrollTo(50, 0); + render(); + expect.html(doc.tab).text("50"); + + editor.setOption("animatedScroll", true); + editor.scrollTo(0, 0); + render(); + expect.html(doc.tab).text("50"); + done(); + }); + }); + + // @todo test split api and menu + + if (!onload.remain) { + after(function(done) { + tabs.unload(); + + document.body.style.marginBottom = ""; + done(); + }); + } + }); + + onload && onload(); + } +}); \ No newline at end of file diff --git a/plugins/c9.ide.ace/modes.js b/plugins/c9.ide.ace/modes.js new file mode 100644 index 00000000..7debfe0f --- /dev/null +++ b/plugins/c9.ide.ace/modes.js @@ -0,0 +1,47 @@ +/** + * Code Editor for the Cloud9 + * + * @copyright 2010, Ajax.org B.V. + * @license GPLv3 + */ + +define(function(require, exports, module) { + +var modesByName = require("ace/ext/modelist").modesByName; + +modesByName.javascript.extensions += "|run|build"; + +var primaryModes = ["c_cpp","clojure","coffee","csharp","css","dart","golang", + "html","jade","java","javascript","json","less","lua","perl","php","python", + "ruby","scala","scss","sh","stylus","sql","text","typescript","xml","xquery", + "yaml"]; + +var hiddenModes = ["text", "snippets"]; +var fileExtensions = Object.create(null); +var modesByCaption = Object.create(null); +var customExtensions = Object.create(null); +Object.keys(modesByName).forEach(function(name) { + var mode = modesByName[name]; + modesByCaption[mode.caption] = mode; + + mode.id = name; + if (primaryModes.indexOf(mode.name) != -1) + mode.order = 100000; + else if (hiddenModes.indexOf(mode.name) != -1) + mode.order = -1; + else + mode.order = 0; + + mode.extensions.split("|").forEach(function(ext) { + fileExtensions[ext] = name; + }); +}); + + +module.exports = { + byName: modesByName, + extensions: fileExtensions, + customExtensions: customExtensions, + byCaption: modesByCaption +} +}); \ No newline at end of file diff --git a/plugins/c9.ide.ace/scrollbar.js b/plugins/c9.ide.ace/scrollbar.js new file mode 100644 index 00000000..eea7c474 --- /dev/null +++ b/plugins/c9.ide.ace/scrollbar.js @@ -0,0 +1,39 @@ +define(function(require, exports, module) { +var dom = require("ace/lib/dom"); + +if (!dom.scrollbarWidth(document)) + return; +dom.importCssString("\ +::-webkit-scrollbar {\ + background: none;\ + width: 16px;\ + height: 16px;\ +}\ +::-webkit-scrollbar-thumb {\ + border: solid 0 rgba(0, 0, 0, 0);\ + border-right-width: 4px;\ + border-left-width: 4px;\ + -webkit-border-radius: 9px 4px;\ + -webkit-box-shadow: inset 0 0 0 1px rgba(128, 128, 128, 0.2), inset 0 0 0 4px rgba(128, 128, 128, 0.2);\ +}\ +::-webkit-scrollbar-track-piece {\ + margin: 4px 0;\ +}\ +::-webkit-scrollbar-thumb:horizontal {\ + border-right-width: 0;\ + border-left-width: 0;\ + border-top-width: 4px;\ + border-bottom-width: 4px;\ + -webkit-border-radius: 4px 9px;\ +}\ +::-webkit-scrollbar-thumb:hover {\ + -webkit-box-shadow:\ + inset 0 0 0 1px rgba(128,128,128,0.9),\ + inset 0 0 0 4px rgba(128,128,128,0.9);\ +}\ +::-webkit-scrollbar-corner {\ + background: transparent;\ +}\ +.ace_scrollbar-h{margin: 0 2px}\ +"); +}); \ No newline at end of file diff --git a/plugins/c9.ide.ace/style.less b/plugins/c9.ide.ace/style.less new file mode 100644 index 00000000..38f95c62 --- /dev/null +++ b/plugins/c9.ide.ace/style.less @@ -0,0 +1,249 @@ +.ace_editor { + overflow: hidden; +} + +.ace-cloud9-night{ + background: @ace-cloud9-night-background !important; +} +.ace-cloud9-night .ace_gutter{ + background: @ace-cloud9-night-gutter !important; +} +.ace-cloud9-night .ace_marker-layer .ace_active-line { + background: @ace-cloud9-night-active-line !important; +} +.ace-cloud9-day{ + background: @ace-cloud9-day-background !important; +} +.ace-cloud9-day .ace_gutter{ + background: @ace-cloud9-day-gutter !important; +} + +.ace-cloud9-day .ace_gutter-layer{ + box-shadow: @ace-gutter-shadow; +} + +.ace_gutter-active-line{ + z-index : -1; +} + +.dark .ace_gutter .ace_gutter_active_line { + background-color: rgba(255, 255, 255, 0.07); +} + +.ace_scroller.ace_scroll-left { + box-shadow: none !important; +} + +.scroll_shadow { + top: 0; + bottom: 0; + width: 16px; + position: absolute; + border-top-left-radius: 4px; + pointer-events: none; +} + +.ace_scroller.ace_scroll-left > .scroll_shadow { + box-shadow: 17px 0 16px -16px rgba(0, 0, 0, 0.4) inset; + z-index: 100000; +} + +.ace_corner { + top: 0; + /*added by js*/ + /* background: radial-gradient(at 5px 5px, rgba(240, 240, 240, 0) 5.5px, rgb(240, 240, 240) 6px);*/ + position: absolute; + width: 6px; + height: 6px; +} + +.ace_editor .ace_printMargin { + position: absolute; + height: 100%; + width: 1px; + background-color: rgb(191, 191, 191); +} + +.ace_layer { + z-index: 0; +} + +.ace_marker-layer .ace_step, .ace_marker-layer .ace_stack { + position: absolute; + z-index: 3; +} + +.aceDisabled { + border: 1px solid #c3c3c3; + color: #bebebe; +} + +.aceError{ + border: 1px solid #ffb500; + padding : 5px; +} + +/* Gutter Icons - LIGHT */ + +.ace_gutter-layer .ace_gutter-cell { + background-repeat: no-repeat; +} + +.ace_gutter-layer .ace_gutter-cell.ace_error { + .image-2x(@ace-error, 16px, 16px, no-repeat); + background-position: 3px 0px; +} +.ace_gutter-layer .ace_gutter-cell.ace_warning { + .image-2x(@ace-warning, 16px, 16px, no-repeat); + background-position: 3px 0px; +} +.ace_gutter-layer .ace_gutter-cell.ace_breakpoint { + .image-2x(@ace-breakpoint, 16px, 16px, no-repeat); + background-position: 3px center; +} +.ace_gutter-layer .ace_breakpoint.disabled { + .image-2x(@ace-breakpoint-disabled, 16px, 16px, no-repeat); +} +.ace_gutter-layer .ace_breakpoint.condition { + .image-2x(@ace-breakpoint-condition, 16px, 16px, no-repeat); +} +.ace_gutter-layer .ace_breakpoint.invalid { + .image-2x(@ace-breakpoint-invalid, 16px, 16px, no-repeat); +} +.ace_gutter-layer .ace_breakpoint.disabled.condition { + .image-2x(@ace-breakpoint-disabled-condition, 16px, 16px, no-repeat); +} +.ace_gutter-layer .ace_gutter-cell.ace_breakpoint.step { + .image-2x(@ace-breakpoint-step, 16px, 16px, no-repeat); + background-position: 3px center; +} +.ace_gutter-layer .ace_gutter-cell.ace_breakpoint.condition.step { + .image-2x(@ace-breakpoint-condition-step, 16px, 16px, no-repeat); + background-position: 3px center; +} +.ace_gutter-layer .ace_gutter-cell.step { + .image-2x(@ace-step, 16px, 16px, no-repeat); + background-position: 3px center; +} +.ace_gutter-layer .ace_gutter-cell.stack { + .image-2x(@ace-stack, 16px, 16px, no-repeat); + background-position: 3px center; +} + +/* Gutter Icons - DARK */ + +.ace_dark .ace_gutter-layer .ace_gutter-cell.ace_error { + .image-2x(@ace-dark-error, 16px, 16px no-repeat); + background-position: 3px 0px; +} +.ace_dark .ace_gutter-layer .ace_gutter-cell.ace_warning { + .image-2x(@ace-dark-warning, 16px, 16px no-repeat); + background-position: 3px 0px; +} +.ace_dark .ace_gutter-layer .ace_gutter-cell.ace_breakpoint { + .image-2x(@ace-dark-breakpoint, 16px, 16px, no-repeat); +} +.ace_dark .ace_gutter-layer .ace_breakpoint.disabled { + .image-2x(@ace-dark-breakpoint-disabled, 16px, 16px, no-repeat); +} +.ace_dark .ace_gutter-layer .ace_breakpoint.condition { + /* @TODO */ + .image-2x(@ace-dark-breakpoint-condition, 16px, 16px, no-repeat); +} +.ace_dark .ace_gutter-layer .ace_breakpoint.invalid { + .image-2x(@ace-dark-breakpoint-invalid, 16px, 16px, no-repeat); +} +.ace_dark .ace_gutter-layer .ace_breakpoint.disabled.condition { + /* @TODO */ + .image-2x(@ace-dark-breakpoint-disabled-condition, 16px, 16px, no-repeat); +} +.ace_dark .ace_gutter-layer .ace_gutter-cell.ace_breakpoint.step { + .image-2x(@ace-dark-breakpoint-step, 16px, 16px, no-repeat); +} +.ace_dark .ace_gutter-layer .ace_gutter-cell.ace_breakpoint.disabled.step { + .image-2x(@ace-dark-breakpoint-disabled-step, 16px, 16px, no-repeat); +} +.ace_dark .ace_gutter-layer .ace_gutter-cell.ace_breakpoint.condition.step { + /* @TODO */ + .image-2x(@ace-dark-breakpoint-condition-step, 16px, 16px, no-repeat); + background-position: 4px center; +} +.ace_dark .ace_gutter-layer .ace_gutter-cell.step { + .image-2x(@ace-dark-step, 16px, 16px, no-repeat); +} +.ace_dark .ace_gutter-layer .ace_gutter-cell.stack { + /* @TODO */ + .image-2x(@ace-dark-stack, 16px, 16px, no-repeat); + background-position: 4px center; +} + +/* Themes */ + +.ace-solarized-light .fm-window .fm-content, +.fm-window .fm-header .hcontent { + background-color: rgba(220, 220, 220, 0.73); +} + +.ace_tooltip { + padding : 3px 5px 2px 5px !important; + line-height : 1.3em; + font-family : Arial, sans-serif; + box-shadow : @gutter-tooltip-shadow !important; + background : @gutter-tooltip-background !important; + border : 1px solid @gutter-tooltip-border; + color : @gutter-tooltip-color; + .font-smoothing(@gutter-tooltip-font-smoothing); +} +.ace_dark .ace_tooltip { + box-shadow : @gutter-tooltip-dark-shadow !important; + background : @gutter-tooltip-dark-background !important; + border : 1px solid @gutter-tooltip-dark-border; + color : @gutter-tooltip-dark-color; + .font-smoothing(@gutter-tooltip-dark-font-smoothing); +} + +.ace_progress { + position: absolute; + top: 50%; + left: 10%; + right: 10%; + height: 1px; + + /*.gradien("~linear-gradient(to right, rgba(0,0,0,0) 0%,rgba(0,0,0,1) 100%)");*/ + margin-top: -4px; + z-index: -1; +} +/*.dark .ace_progress{*/ +/* .gradient(~"linear-gradient(to right, rgba(0,0,0,0) 0%,rgba(0,0,0,1) 100%)");*/ +/*}*/ +.ace_progress.upload{ + top: 1px; + left: 0px; + right: 0px; + height: 1px; + margin-top: 0; + z-index: 1000; + background: none; +} + +.ace_progress div { + width: 10%; + height: 100%; + .gradient(~"linear-gradient(to right, rgba(40, 130, 190, 0) 0%,rgba(40, 130, 190, 1) 100%)"); +} +.dark .ace_progress div{ + .gradient(~"linear-gradient(to right, rgba(113,170,12,0) 0%,rgba(113,170,12,1) 100%)"); +} + + +.ace_link_marker { + position: absolute; + color: blue; + border-bottom: 1px dotted rgba(0,0,0,0.4); + z-index: 20; + cursor: pointer; + margin-top : -1px; +} +.dark .ace_link_marker { + border-bottom: 1px dotted rgba(255,255,255,0.4); +} \ No newline at end of file diff --git a/plugins/c9.ide.ace/themes.js b/plugins/c9.ide.ace/themes.js new file mode 100644 index 00000000..802bd111 --- /dev/null +++ b/plugins/c9.ide.ace/themes.js @@ -0,0 +1,211 @@ +define(function(require, exports, module) { + main.consumes = [ + "PreferencePanel", "ace", "ui", "configure", "settings" + ]; + main.provides = ["preferences.themes"]; + return main; + + function main(options, imports, register) { + var PreferencePanel = imports.PreferencePanel; + var ui = imports.ui; + var ace = imports.ace; + var configure = imports.configure; + var settings = imports.settings; + + /***** Initialization *****/ + + var plugin = new PreferencePanel("Ajax.org", main.consumes, { + caption: "Themes", + className: "keybindings", + form: true, + noscroll: true, + colwidth: 150, + index: 300 + }); + // var emit = plugin.getEmitter(); + + var intro; + + var loaded = false; + function load() { + if (loaded) return false; + loaded = true; + + } + + var drawn; + function draw(e) { + if (drawn) return; + drawn = true; + + var list = []; + var themes = ace.themes + for (var base in themes) { + if (themes[base] instanceof Array) + themes[base].forEach(function (n) { + var themeprop = Object.keys(n)[0]; + list.push({ caption: themeprop, value: n[themeprop] }); + }); + else + list.push({ caption: base, value: themes[base] }); + } + + var rb1, rb2, rb3, rb4, rb5; + plugin.form.add([ + { + type: "custom", + title: "Introduction", + position: 1, + node: intro = new ui.bar({ + height: 124, + "class" : "intro", + style: "padding:12px;position:relative;" + }) + }, + { + type: "custom", + title: "Flat Theme", + position: 1, + node: new ui.hsplitbox({ + height: 49, + edge: "10 10 10 10", + style: "white-space:nowrap", + childNodes: [ + new ui.label({ + width: 150, + caption: "Flat Theme:", + style: "padding-top:5px" + }), + new ui.bar({ + childNodes: [ + rb5 = new ui.radiobutton({ + group: "theme-color", + class: "themepicker", + style: "background:#dcdbdb;", + value: "flat-light" + }) + ] + }) + ] + }) + }, + { + type: "custom", + title: "Classic Theme", + position: 1, + node: new ui.hsplitbox({ + height: 49, + edge: "10 10 10 10", + style: "white-space:nowrap", + childNodes: [ + new ui.label({ + width: 150, + caption: "Classic Theme:", + style: "padding-top:5px" + }), + new ui.bar({ + childNodes: [ + rb1 = new ui.radiobutton({ + group: "theme-color", + class: "themepicker", + style: "background:#252525;", + value: "dark" + }), + rb2 = new ui.radiobutton({ + group: "theme-color", + class: "themepicker", + style: "background:#3f3f3f;", + value: "dark-gray" + }) + // rb3 = new ui.radiobutton({ + // group: "theme-color", + // class: "themepicker", + // style: "background:#aaa;", + // value: "light-gray" + // }), + // rb4 = new ui.radiobutton({ + // group: "theme-color", + // class: "themepicker", + // style: "background:#dcdbdb;", + // value: "light" + // }) + ] + }) + ] + }) + }, + { + title: "Syntax Theme", + type: "dropdown", + path: "user/ace/@theme", + width: 165, + onchange: function(e) { + ace.setTheme(e.value); + }, + items: list, + position: 200 + }, + ], plugin); + + var change = function(e) { + settings.set("user/general/@skin", e.value); + }; + var setTheme = function(e) { + [rb1, rb2, rb5].some(function(rb) { + if (rb.value == e.value) { + rb.select(); + return true; + } + }) + } + settings.on("user/general/@skin", setTheme); + setTheme({ value: settings.get("user/general/@skin") }); + + rb1.$group.on("afterchange", change); + + intro.$int.innerHTML = + '

      Themes

      You can also style Cloud9 by editing ' + + ' your stylesheet.

      ' + + '

      Set all the colors free!

      ' + + intro.$int.querySelector("a").onclick = function(){ + configure.editStylesCss(); + } + } + + /***** Methods *****/ + + + /***** Lifecycle *****/ + + plugin.on("load", function() { + load(); + }); + plugin.on("draw", function(e) { + draw(e); + }); + plugin.on("enable", function() { + + }); + plugin.on("disable", function() { + + }); + plugin.on("unload", function() { + loaded = false; + drawn = false; + }); + + /***** Register and define API *****/ + + /** + * + **/ + plugin.freezePublicAPI({ + + }); + + register(null, { + "preferences.themes" : plugin + }); + } +}); \ No newline at end of file diff --git a/plugins/c9.ide.ace/themes.json b/plugins/c9.ide.ace/themes.json new file mode 100644 index 00000000..10ece34c --- /dev/null +++ b/plugins/c9.ide.ace/themes.json @@ -0,0 +1,43 @@ +{ + "Ambiance" : "ace/theme/ambiance", + "Chrome" : "ace/theme/chrome", + "Cloud9" : [ + {"Cloud9 Day" : "ace/theme/cloud9_day"}, + {"Cloud9 Night" : "ace/theme/cloud9_night"}, + {"Cloud9 Night Low-Color" : "ace/theme/cloud9_night_low_color"} + ], + "Clouds" : [ + {"Clouds" : "ace/theme/clouds"}, + {"Clouds Midnight" : "ace/theme/clouds_midnight"} + ], + "Cobalt" : "ace/theme/cobalt", + "Crimson Editor" : "ace/theme/crimson_editor", + "Dawn" : "ace/theme/dawn", + "Dreamweaver" : "ace/theme/dreamweaver", + "Eclipse" : "ace/theme/eclipse", + "GitHub" : "ace/theme/github", + "Idle Fingers" : "ace/theme/idle_fingers", + "Kr Theme" : "ace/theme/kr_theme", + "Merbivore" : [ + {"Merbivore" : "ace/theme/merbivore"}, + {"Merbivore Soft" : "ace/theme/merbivore_soft"} + ], + "Mono Industrial" : "ace/theme/mono_industrial", + "Monokai" : "ace/theme/monokai", + "Pastel On Dark" : "ace/theme/pastel_on_dark", + "Solarized" : [ + {"Solarized Dark" : "ace/theme/solarized_dark"}, + {"Solarized Light" : "ace/theme/solarized_light"} + ], + "TextMate" : "ace/theme/textmate", + "Tomorrow" : [ + {"Tomorrow" : "ace/theme/tomorrow"}, + {"Tomorrow Night" : "ace/theme/tomorrow_night"}, + {"Tomorrow Night Blue" : "ace/theme/tomorrow_night_blue"}, + {"Tomorrow Night Bright" : "ace/theme/tomorrow_night_bright"}, + {"Tomorrow Night Eighties" : "ace/theme/tomorrow_night_eighties"} + ], + "Twilight" : "ace/theme/twilight", + "Vibrant Ink" : "ace/theme/vibrant_ink", + "Xcode" : "ace/theme/xcode" +} \ No newline at end of file diff --git a/plugins/c9.ide.auth/auth.js b/plugins/c9.ide.auth/auth.js new file mode 100644 index 00000000..8508ba0f --- /dev/null +++ b/plugins/c9.ide.auth/auth.js @@ -0,0 +1,203 @@ +define(function(require, exports, module) { + "use strict"; + + main.consumes = ["Plugin", "http", "auth.bootstrap"]; + main.provides = ["auth"]; + return main; + + function main(options, imports, register) { + var Plugin = imports.Plugin; + var http = imports.http; + var _login = imports["auth.bootstrap"].login; + + /***** Initialization *****/ + + var ANONYMOUS = -1; + + var plugin = new Plugin("Ajax.org", main.consumes); + var emit = plugin.getEmitter(); + var accessToken = options.accessToken || ""; + var apiUrl = options.apiUrl || ""; + var ideBaseUrl = options.ideBaseUrl; + var uid = options.userId; + var loggedIn = true; + var checkLoop = createLoopDetector(3, 20 * 1000); + + /***** Methods *****/ + + function request(url, options, callback) { + if (!callback) + return request(url, {}, options); + + if (loggingIn) { + var onLogin = function() { + plugin.off("login", onLogin); + request(url, options, callback); + }; + plugin.on("login", onLogin); + return { abort: function() { plugin.off("login", onLogin); }}; + } + + options.query = options.query || {}; + + // TODO try also using the Authorization header + if (accessToken) + options.query.access_token = accessToken; + + return http.request(url, options, function(err, data, res) { + // If we get a 'forbidden' status code login again and retry + if (res && res.status == 401 && !options.noLogin) { + if (!checkLoop(url)) { + console.trace("Login loop detected for URL " + url); + return callback(new Error("Login loop detected!")); + } + + plugin.once("login", function() { + request(url, options, callback); + }); + login(); + return; + } + + callback(err, data, res); + }); + } + + var loggingIn = false; + function login(checkLogin) { + if (loggingIn) { + if (!checkLogin) + return; + else + loggingIn(); + } + + emit("loggingin"); + + loggingIn = _login(function(err, token) { + loggingIn = false; + accessToken = token; + + request(apiUrl + "/user", function(err, user) { + if (err || !user) { + console.warn("LOGIN: API /user err", err); + return setTimeout(login, 1000); + } + + if (user.id !== ANONYMOUS) { + loggedIn = true; + if (uid != user.id) { + uid = user.id; + emit("relogin", {uid: user.id}); + } + // "login" or "logout" event is always dispatched after "loggingin" event + emit("login", {uid: user.id, oldUid: uid}); + } else { + loggedIn = false; + emit("logout", {uid: user.id, newUid: ANONYMOUS}); + } + }); + }, function() { + if (uid != ANONYMOUS) { + emit("logout", {uid: uid, newUid: ANONYMOUS}); + } + }) || true; + } + + function logout(callback) { + accessToken = "invalid"; + loggingIn = false; + + http.request("/_auth/logout", function(err1) { + http.request(ideBaseUrl + "/auth/signout", { + method: "POST" + }, function(err2) { + loggedIn = false; + emit("logout", {uid: uid, newUid: ANONYMOUS}); + callback && callback(err1 || err2); + }); + }); + } + + function createLoopDetector(count, duration) { + var log = {}; + + return function check(url) { + var now = Date.now(); + + var calls = log[url]; + if (!calls) { + log[url] = [now]; + return true; + } + + while (calls.length && calls[0] < now - duration) { + calls.shift(); + } + + calls.push(now); + return calls.length < count; + }; + } + + /***** Register and define API *****/ + + /** + * Provides login information + * @singleton + **/ + plugin.freezePublicAPI({ + + _events: [ + "loggingin", + "login", + "logout" + ], + + /** + * + */ + get loggedIn() { return loggedIn; }, + /** + * + */ + get loggingIn() { return loggingIn; }, + /** + * + */ + get accessToken() { return accessToken; }, + set accessToken(v) { accessToken = v; loggedIn = true;}, + + /** + * + */ + login: login, + + /** + * @param {Function} [callback] + */ + logout: logout, + + /** + * Wrapper for http.request which adds authorization information to + * the request + * + * @param {String} url target URL for the HTTP request + * @param {Object} options optional request options. Same format + * as {@link http#request http.request}. + * @param {Function} callback Called when the request returns. + * @param {Error} callback.err Error object if an error occured. + * @param {String} callback.data The data received. + * @param {Object} callback.res + * @param {String} callback.res.body The body of the response message. + * @param {Number} callback.res.status The status of the response message. + * @param {Object} callback.res.headers The headers of the response message. + */ + request: request + }); + + register(null, { + auth: plugin + }); + } +}); \ No newline at end of file diff --git a/plugins/c9.ide.browsersupport/browsersupport.js b/plugins/c9.ide.browsersupport/browsersupport.js new file mode 100644 index 00000000..ea9c1190 --- /dev/null +++ b/plugins/c9.ide.browsersupport/browsersupport.js @@ -0,0 +1,117 @@ +define(function(require, exports, module) { + "use strict"; + + main.consumes = ["Plugin"]; + main.provides = ["browsersupport"]; + return main; + + function main(options, imports, register) { + var Plugin = imports.Plugin; + + require("ace/lib/es5-shim"); + var useragent = require("ace/lib/useragent"); + var dom = require("ace/lib/dom"); + + if (useragent.isGecko) + dom.addCssClass(document.body, "ua_gecko"); + else if (useragent.isWebkit) + dom.addCssClass(document.body, "ua_webkit"); + else if (useragent.isIE) + dom.addCssClass(document.body, "ua_ie"); + + function getIEVersion() { + return useragent.isIE; + } + + var plugin = new Plugin("Ajax.org", main.consumes); + + /** + * Browser compatibility support. + */ + plugin.freezePublicAPI({ + /** + * Gets Internet Explorer's major version, e.g. 10, + * or returns null if a different browser is used. + * + * @return {Number} + */ + getIEVersion: getIEVersion + }); + register(null, { browsersupport: plugin }); + } +}); + +// Support __defineGetter__ et al. on IE9 +// (always triggers when packed) +try { + if (!Object.prototype.__defineGetter__ && + Object.defineProperty({},"x",{get: function(){return true}}).x) { + + // Setter + Object.defineProperty( + Object.prototype, + "__defineSetter__", + { + enumerable: false, + configurable: true, + value: function(name,func) { + Object.defineProperty(this,name,{set:func,enumerable: true,configurable: true}); + + // Adding the property to the list (for __lookupSetter__) + if (!this.setters) this.setters = {}; + this.setters[name] = func; + } + } + ); + + // Lookupsetter + Object.defineProperty( + Object.prototype, + "__lookupSetter__", + { + enumerable: false, + configurable: true, + value: function(name) { + if (!this.setters) return false; + return this.setters[name]; + } + } + ); + + // Getter + Object.defineProperty( + Object.prototype, + "__defineGetter__", + { + enumerable: false, + configurable: true, + value: function(name,func) { + Object.defineProperty(this,name,{get:func,enumerable: true,configurable: true}); + + // Adding the property to the list (for __lookupSetter__) + if (!this.getters) this.getters = {}; + this.getters[name] = func; + } + } + ); + + // Lookupgetter + Object.defineProperty( + Object.prototype, + "__lookupGetter__", + { + enumerable: false, + configurable: true, + value: function(name) { + if (!this.getters) return false; + return this.getters[name]; + } + } + ); + + } +} catch (defPropException) { + // Forget about it +} + + diff --git a/plugins/c9.ide.clipboard/clipboard.js b/plugins/c9.ide.clipboard/clipboard.js new file mode 100644 index 00000000..9d2d896c --- /dev/null +++ b/plugins/c9.ide.clipboard/clipboard.js @@ -0,0 +1,491 @@ +define(function(require, exports, module) { + main.consumes = [ + "Plugin", "c9", "menus", "commands", "clipboard.provider", "ui", + "dialog.alert", "settings" + ]; + main.provides = ["clipboard"]; + return main; + + function main(options, imports, register) { + var c9 = imports.c9; + var ui = imports.ui; + var Plugin = imports.Plugin; + var menus = imports.menus; + var settings = imports.settings; + var commands = imports.commands; + var provider = imports["clipboard.provider"]; + var alert = imports["dialog.alert"]; + + /***** Initialization *****/ + + var plugin = new Plugin("Ajax.org", main.consumes); + var emit = plugin.getEmitter(); + + var input = { "input":1, "textarea":1, "iframe":1 }; + + var loaded = false; + function load(){ + if (loaded) return false; + loaded = true; + + // return !(event instanceof KeyboardEvent) && !c9.readonly; + + function checkAvailable(editor, args, e) { + var handler = findClipboardHandler(); + var fromKeyboard = e instanceof KeyboardEvent; + + if (handler && handler.isClipboardAvailable) { + return handler.isClipboardAvailable({ + type: this.name, + fromKeyboard: fromKeyboard, + sourceEvent: e, + editor: editor, + args: args + }); + } + else if (options.local) { + var name = document.activeElement.tagName.toLowerCase(); + if (input[name] || document.activeElement.contentEditable) + return true; + } + + return !!handler; + } + + commands.addCommand({ + name: "cut", + bindKey: { mac: "Command-X", win: "Ctrl-X" }, + isAvailable: checkAvailable, + exec: function(){ cut(); }, + passEvent: true, + readOnly: true + }, plugin); + + commands.addCommand({ + name: "copy", + bindKey: { mac: "Command-C", win: "Ctrl-C" }, + isAvailable: checkAvailable, + exec: function(editor, args){ copy(null, args.data); }, + passEvent: true + }, plugin); + + commands.addCommand({ + name: "paste", + bindKey: { mac: "Command-V", win: "Ctrl-V" }, + isAvailable: checkAvailable, + exec: function(){ paste(); }, + passEvent: true, + readOnly: true + }, plugin); + + commands.addCommand({ + name: "clearcut", + bindKey: { mac: "ESC", win: "ESC" }, + isAvailable: checkAvailable, + exec: clearcut, + passEvent: true + }, plugin); + + menus.addItemByPath("Edit/~", new ui.divider(), 300, plugin); + menus.addItemByPath("Edit/Cut", + new ui.item({ command : "cut" }), 400, plugin); + menus.addItemByPath("Edit/Copy", + new ui.item({ command : "copy" }), 500, plugin); + menus.addItemByPath("Edit/Paste", + new ui.item({ command : "paste" }), 600, plugin); + } + + var clipboardData = { + items: [], + get types(){ + return clipboardData.items.map(function(item) { + return item.type; + }); + }, + + wrap: function(nativeObject){ provider.wrap(nativeObject); }, + unwrap: function(){ provider.unwrap(); }, + + setData: function(type, data) { + if (provider.set(type, data) === false) + showAlert(data); + + var found; + clipboardData.items.every(function(item) { + if (item.type == type) { + found = item; + return false; + } + return true; + }); + + if (found) found.value = data; + else clipboardData.items.push({ type: type, value: data }); + }, + getData: function(type, callback) { + var data = provider.get(type); + + // If `data` is false the provider was not able to fetch data from the clipboard. + // This is usually because the browser does not allow this for security reasons. + // The browser (chrome) does allow this when the cloud9 plugin is installed. + if (data === false) + showAlert(null, true); + + // If `data` is undefined the provider did not support the mime type. This usually + // happens when the mime type is custom, such as when copying tree nodes or other + // internal to Cloud9 data. + // In either case we try to find the data in the local (in memory) clipboard. + if (data === false || data === undefined) { + var found; + clipboardData.items.every(function(item) { + if (item.type == type) { + found = item; + return false; + } + return true; + }); + return found && found.value || false; + } + + return data; + }, + clearData: function(type) { + provider.clear(); + clipboardData.items = []; + clipboardData.types = []; + } + }; + + function findClipboardHandler() { + var el = apf.activeElement || apf.menu.lastFocussed; + + if (!el) + return; + + if (el.localName == "menu") + el = apf.menu.lastFocussed || el; + while (el) { + var handler = el.clipboardHandler || el.editor; + if (handler) + return handler; + el = el.parentNode; + } + } + + /***** Methods *****/ + + function cut(native) { + var handler = findClipboardHandler(); + var event = { + clipboardData: clipboardData, + native: native, + handler: handler + }; + + if (emit("beforeCut", event) === false) + return; + + if (!native) clipboardData.unwrap(); + emit("cut", event); + if (handler && handler.cut) + handler.cut(event); + } + + function copy(native, data) { + var handler = findClipboardHandler(); + var event = { + clipboardData: clipboardData, + native: native, + handler: handler + }; + + if (emit("beforeCopy", event) === false) + return; + + if (!native) clipboardData.unwrap(); + + if (data) + clipboardData.setData("text/plain", data); + else { + emit("copy", event); + + if (handler && handler.copy) + handler.copy(event); + } + } + + function paste(native) { + var handler = findClipboardHandler(); + var event = { + clipboardData: clipboardData, + native: native, + handler: handler + }; + + if (emit("beforePaste", event) === false) + return; + + if (!native) clipboardData.unwrap(); + emit("paste", event); + if (handler && handler.paste) + handler.paste(event); + } + + function clearcut() { + var handler = findClipboardHandler(); + if (handler && handler.clearcut) + return handler.clearcut(); + return false; + } + + function registerHandler(amlNode, clipboardHandler) { + amlNode.clipboardHandler = clipboardHandler; + } + + function showAlert(data, isPaste) { + if (settings.getBool("user/clipboard/@dontshow")) + return; + + var emitter = alert.show("Native Clipboard Unavailable", + "Important information regarding the Native Clipboard", + "By default the browser doesn't allow you to use the native " + + "clipboard via menus. This means that whatever you copy via a " + + "menu needs to be pasted by the menu as well and only works " + + "in Cloud9.

      " + + (isPaste ? "" : "You can copy the string from the " + + "textarea below.

      ") + + "To enable the native keyboard either use " + + "Command-C on Mac or Ctrl-C on Windows or for Chrome install " + + "the Cloud9 App at the Chrome store.", + function(){ + if (alert.dontShow) + settings.set("user/clipboard/@dontshow", true); + }, { isHTML: true, showDontShow: true }); + + emitter.on("show", function(){ + var textarea = alert.aml.$ext.querySelector("textarea"); + if (!textarea) return; + textarea.select(); + textarea.focus(); + function hide() { + setTimeout(function() { + alert.hide(); + }); + } + textarea.addEventListener("copy", hide); + textarea.addEventListener("cut", hide); + }); + } + + /***** Lifecycle *****/ + + plugin.on("load", function(){ + load(); + }); + plugin.on("enable", function(){ + + }); + plugin.on("disable", function(){ + + }); + plugin.on("unload", function(){ + loaded = false; + }); + + /***** Register and define API *****/ + + /** + * Object that represents the clipboard state and provides methods to + * access the clipboard. + * @class clipboard.ClipboardData + */ + /** + * @property {String[]} types The content types that currently hold + * data in the clipboard. + * @readonly + */ + /** + * Adds an item to the clipboard, replacing any item that was there + * with the same `type`. + * + * This example shows how to store a selection of tree nodes on the + * clipboard: + * + * var nodes = tree.getSelection(); + * clipboardData.setData("tree-nodes", nodes); + * + * @method setData + * @param {String} type The content type for this data. To be + * compatible with the native clipboard for all platforms use "text". + * @param {Mixed} data The actual data. This can be a string + * or a more complex object. Complex objects cannot be stored using + * the native clipboard. + */ + /** + * Retrieves the data of an item on the clipboard. + * + * This example shows how to retrieve a set of tree nodes from the + * clipboard: + * + * var nodes = clipboardData.getData("tree-nodes"); + * + * @method getData + * @param {String} type The content type for this data. To be + * compatible with the native clipboard for all platforms use "text". + */ + /** + * Clears the data from the clipboard for a certain `type`. + * @method clearData + * @param {String} type The content type for this data. To be + * compatible with the native clipboard for all platforms use "text". + */ + /** + * Providers Clipboard access for Cloud9 plugins. The Cloud9 Clipboard + * abstracts away the implementation details of the different + * environments (e.g. Browser, Node-Webkit). The Clipboard API is + * loosely based on the [HTML5 Clipboard specification](http://dev.w3.org/2006/webapi/clipops/). + * + * *N.B.: Usually these events are not listened to directly. Instead + * each editor has an {@link Editor#event-cut}, {@link Editor#event-copy} and + * {@link Editor#event-paste} event to implement. However if you are + * implementing a pane that is not an editor, use the events of this + * plugin.* + * + * Example (copy): + * + * clipboard.on("copy", function(e) { + * if (e.native) return; + * + * var data = "Example Data"; + * e.clipboardData.setData("text/plain", data); + * }); + * + * Example (paste): + * + * clipboard.on("paste", function(e) { + * if (e.native) return; + * + * var data = e.clipboardData.getData("text/plain"); + * + * }); + * + * @singleton + */ + plugin.freezePublicAPI({ + _events: [ + /** + * Fires when a cut, copy or paste command is executed. In order + * for the clipboard to work for your plugin, you will need to + * hook this event and return true when and only if your plugin + * has the focus and is capable of handling the specific action. + * + * @event available + * @param {Object} e + * @param {String} e.type The name of the command that is + * executed. This can be "cut", "copy" or "paste". + */ + "available", + /** + * Fires prior to the "cut" operation. + * @event beforeCut + * @cancellable + * @param {Object} e + * @param {clipboard.ClipboardData} e.clipboardData Gives + * access to the clipboard. See {@link #clipboardData} + */ + "beforeCut", + /** + * Fires when the cut operation is executed. + * @event cut + * @param {Object} e + * @param {clipboard.ClipboardData} e.clipboardData Gives + * access to the clipboard. See {@link #clipboardData} + */ + "cut", + /** + * Fires prior to the "paste" operation. + * @event beforePaste + * @cancellable + * @param {Object} e + * @param {clipboard.ClipboardData} e.clipboardData Gives + * access to the clipboard. See {@link #clipboardData} + */ + "beforePaste", + /** + * Fires when the paste operation is executed. + * @event paste + * @param {Object} e + * @param {clipboard.ClipboardData} e.clipboardData Gives + * access to the clipboard. See {@link #clipboardData} + */ + "paste", + /** + * Fires prior to the "copy" operation. + * @event beforeCopy + * @cancellable + * @param {Object} e + * @param {clipboard.ClipboardData} e.clipboardData Gives + * access to the clipboard. See {@link #clipboardData} + */ + "beforeCopy", + /** + * Fires when the copy operation is executed. + * @event copy + * @param {Object} e + * @param {clipboard.ClipboardData} e.clipboardData Gives + * access to the clipboard. See {@link #clipboardData} + */ + "copy", + /** + * Fires when the user has requested to clear the cut buffer. + * @event clearcut + * @param {Object} e + * @param {clipboard.ClipboardData} e.clipboardData Gives + * access to the clipboard. See {@link #clipboardData} + */ + "clearcut" + ], + + + /** + * Object that represents the clipboard state + * @param {AmlNode} target + * @param {Object} handler {cut, copy, paste, clearcut, isClipboardAvailable} + */ + registerHandler: registerHandler, + + /** + * Object that represents the clipboard state + * @property {clipboard.ClipboardData} + */ + clipboardData: clipboardData, + + /** + * Triggers a cut by the currently focused component. + * @fires beforeCut + * @fires cut + */ + cut: cut, + + /** + * Triggers a copy by the currently focused component. + * @fires beforeCopy + * @fires copy + */ + copy: copy, + + /** + * Triggers a paste by the currently focused component. + * @fires beforePaste + * @fires paste + */ + paste: paste + }); + + register(null, { + clipboard: plugin + }); + } +}); diff --git a/plugins/c9.ide.clipboard/clipboard_test.js b/plugins/c9.ide.clipboard/clipboard_test.js new file mode 100644 index 00000000..87b570fc --- /dev/null +++ b/plugins/c9.ide.clipboard/clipboard_test.js @@ -0,0 +1,84 @@ +/*global describe it before after = */ + +"use client"; + +require(["lib/architect/architect", "lib/chai/chai"], function (architect, chai) { + var expect = chai.expect; + + expect.setupArchitectTest([ + "plugins/c9.core/ext", + "plugins/c9.ide.ui/ui", + "plugins/c9.ide.ui/lib_apf", + "plugins/c9.ide.clipboard/clipboard", + "plugins/c9.ide.clipboard/html5", + + // Mock plugins + { + consumes: [], + provides: [ + "commands", "menus", "http", "layout", "c9", "dialog.error", + "dialog.alert", "settings" + ], + setup: expect.html.mocked + }, + { + consumes: ["clipboard"], + provides: [], + setup: main + } + ], architect); + + function main(options, imports, register) { + var clipboard = imports.clipboard; + + describe('clipboard', function() { + it('should provide the right events for the cut method', function(done) { + var count = 0; + clipboard.on("beforeCut", function(){ count++; }); + clipboard.on("cut", function(){ count++; }); + clipboard.cut(); + expect(count).to.equal(2); + done(); + }); + it('should provide the right events for the copy method', function(done) { + var count = 0; + clipboard.on("beforeCopy", function(){ count++; }); + clipboard.on("copy", function(){ count++; }); + clipboard.copy(); + expect(count).to.equal(2); + done(); + }); + it('should provide the right events for the paste method', function(done) { + var count = 0; + clipboard.on("beforePaste", function(){ count++; }); + clipboard.on("paste", function(){ count++; }); + clipboard.paste(); + expect(count).to.equal(2); + done(); + }); + it('should support alternative mime-types for internal data objects', function(done) { + var testData = { test: 1 }; + + clipboard.on("copy", function(){ + clipboard.clipboardData.setData("c9/tree-nodes", testData); + }); + clipboard.on("paste", function(){ + var data = clipboard.clipboardData.getData("c9/tree-nodes") + expect(data).to.equal(testData); + done(); + }); + clipboard.copy(); + clipboard.paste(); + }); + + if (!onload.remain) { + after(function(done) { + clipboard.unload(); + done(); + }); + } + }); + + onload && onload(); + } +}); \ No newline at end of file diff --git a/plugins/c9.ide.clipboard/html5.js b/plugins/c9.ide.clipboard/html5.js new file mode 100644 index 00000000..61b157b2 --- /dev/null +++ b/plugins/c9.ide.clipboard/html5.js @@ -0,0 +1,226 @@ +define(function(require, exports, module) { + main.consumes = ["Plugin", "dialog.error"]; + main.provides = ["clipboard.provider"]; + return main; + + /* + Recommended Types: + text/plain + text/uri-list + text/csv + text/css + text/html + application/xhtml+xml + image/png + image/jpg, image/jpeg + image/gif + image/svg+xml + application/xml, text/xml + application/javascript + application/json + application/octet-stream + */ + + function main(options, imports, register) { + var Plugin = imports.Plugin; + var showError = imports["dialog.error"].show; + + /***** Initialization *****/ + + var plugin = new Plugin("Ajax.org", main.consumes); + + var requested, nativeObject; + + var loaded = false; + function load(){ + if (loaded) return false; + loaded = true; + + // Chrome Specific + if (window.chrome && window.chrome.permissions) { + var chrome = window.chrome; + var permissions = { + permissions: ["clipboardRead", "clipboardWrite"], + origins: [location.origin] + }; + + chrome.permissions.contains(permissions, function(allowed) { + if (!allowed) { + chrome.permissions.request(permissions, function(result) { + if (result) { + showError("The browser has granted copy " + + "and paste permissions. Restart the " + + "browser to enable these permissions"); + } + }); + } + }); + } + } + + /***** Methods *****/ + + function clear(){ + if (nativeObject) + nativeObject.clearData(); + else { + var data = get(""); + if (data !== false) + set("", "", data.types); + } + } + + function set(type, data, list) { + if (notSupported(type)) + return; + + type = convertType(type); + + if (nativeObject) { + nativeObject.setData(type, data); + return true; + } + + var setData = function(e) { + if (list) { + list.forEach(function(type) { + e.clipboardData.setData(type, data); + }); + } + e.clipboardData.setData(type, data); + + e.preventDefault(); + e.stopPropagation(); + }; + document.addEventListener("copy", setData, true); + + // @todo test if this is sync + requested = true; + var result = execCommand("copy"); + requested = false; + + document.removeEventListener("copy", setData, true); + + return !!result; + } + + function get(type, full) { + if (notSupported(type)) + return; + + type = convertType(type); + + if (!full && nativeObject) + return nativeObject.getData(type); + + var data; + var getData = function(e) { + data = full + ? e.clipboardData + : e.clipboardData.getData(type); + e.preventDefault(); + e.stopPropagation(); + }; + document.addEventListener("paste", getData, true); + + // @todo test if this is sync + requested = true; + var result = execCommand("paste"); + requested = false; + + document.removeEventListener("paste", getData, true); + + if (!result) + return false; + + return data; + } + + function execCommand(commandName) { + try { + return document.execCommand(commandName, null, null); + } catch (e) { + return false; // firefox throws + } + } + + function notSupported(type) { + return !/text($|\/)/.test(type); + } + + function convertType(type) { + return document.all ? "Text" : type; + } + + function wrap(obj) { + nativeObject = obj; + } + + function unwrap(){ + nativeObject = window.clipboardData; // for ie and firefox addon + } + + /***** Lifecycle *****/ + + plugin.on("load", function(){ + load(); + }); + plugin.on("enable", function(){ + + }); + plugin.on("disable", function(){ + + }); + plugin.on("unload", function(){ + loaded = false; + }); + + /***** Register and define API *****/ + + /** + * Implements the clipboard for a specific system. + * + * *N.B.: Cloud9 supports two native clipboard APIs. One for HTML5 + * browsers and one for node-webkit. If you are looking to add native + * clipboard support for another system, reimplement this service.* + * + * @singleton + **/ + plugin.freezePublicAPI({ + /** + * @ignore + */ + wrap: wrap, + /** + * @ignore + */ + unwrap: unwrap, + + /** + * Clears the clipboard + */ + clear: clear, + + /** + * Sets the clipboard + * @param {String} type The content type for this data. To be + * compatible with the native clipboard for all platforms use "text". + * @param {Mixed} data The actual data. This can be a string + * or a more complex object. Complex objects cannot be stored using + * the native clipboard. + */ + set: set, + + /** + * Gets the current value of the clipboard + * @param {String} type The content type for this data. To be + * compatible with the native clipboard for all platforms use "text". + */ + get: get + }); + + register(null, { + "clipboard.provider": plugin + }); + } +}); \ No newline at end of file diff --git a/plugins/c9.ide.console/console.js b/plugins/c9.ide.console/console.js new file mode 100644 index 00000000..c3d01435 --- /dev/null +++ b/plugins/c9.ide.console/console.js @@ -0,0 +1,599 @@ +define(function(require, module, exports) { + main.consumes = [ + "Plugin", "tabManager", "menus", "settings", "layout", "ui", + "commands", "anims" + ]; + main.provides = ["console"]; + return main; + + function main(options, imports, register) { + var Plugin = imports.Plugin; + var ui = imports.ui; + var tabs = imports.tabManager; + var settings = imports.settings; + var menus = imports.menus; + var anims = imports.anims; + var commands = imports.commands; + var layout = imports.layout; + + var cssString = require("text!./style.css"); + var markup = require("text!./console.xml"); + + /***** Initialization *****/ + + var plugin = new Plugin("Ajax.org", main.consumes); + var emit = plugin.getEmitter(); + + var onFinishTimer, consoleRow, animating; + var container, changed, maximized, maxHeight, lastZIndex, height; + + var hidden = true; + var minHeight = 60; + var collapsedHeight = 0; + + var loaded = false; + function load(){ + if (loaded) return false; + loaded = true; + + // Commands + commands.addCommand({ + name: "toggleconsole", + group: "Panels", + bindKey: {mac: "Ctrl-Esc", win: "F6"}, + exec: function(editor, args) { + var el; + if (hidden || args.show) { + show(); + el = container; + } else { + hide(); + el = tabs.container; + } + var pane = tabs.findPane(container.$activePaneName); + var tab = pane && pane.activeTab || tabs.getTabs(el)[0]; + tabs.focusTab(tab); + } + }, plugin); + + // Menus + menus.addItemByPath("View/Console", new apf.item({ + type: "check", + command: "toggleconsole", + checked: "state/console/@expanded" + }), 700, plugin); + + // Settings + settings.on("read", function(e) { + // Defaults + settings.setDefaults("state/console", [ + ["expanded", "true"], + ["maximized", "false"], + ["height", "153"] + ]); + + // Height + height = Math.max(minHeight, Math.min(layout.maxConsoleHeight, + settings.getNumber("state/console/@height") || 0)); + + setTimeout(function() { + // Expanded + if (settings.getBool("state/console/@expanded")) + show(true); + + // Maximized + if (settings.getBool("state/console/@maximized")) + maximizeConsoleHeight(); + }, 0); + + changed = false; + }, plugin); + + settings.on("write", function(e) { + // if (!changed) + // return; + if (!container) return; + + if (drawn) { + var state = getState(true); + settings.setJson("state/console", state); + } + }, plugin); + + tabs.on("focus", function(e) { + if (drawn && ui.isChildOf(container, e.tab.aml)) + show(); + }); + + if (apf.isGecko) { + ui.setStyleRule(".console .btnsesssioncontainer .inside", + "padding-right", "30px"); + } + + // @todo fix Focus Handling in pane + } + + var drawn = false; + function draw(){ + if (drawn) return; + drawn = true; + + ui.insertCss(cssString, options.staticPrefix, plugin); + + consoleRow = layout.findParent(plugin); + container = consoleRow.appendChild(new ui.bar({ + zindex: 99, + height: height, + // minheight : 60, + "class" : "console codeditorHolder" + })); + + plugin.addElement(container); + tabs.containers.push(container); + + if (settings.getBool("user/tabs/@asterisk")) + ui.setStyleClass(container, "asterisk"); + + ui.insertMarkup(container, markup, plugin); + + // Track splitter and update state + var splitter = consoleRow.$handle; + splitter && splitter.on("dragdrop", function(e) { + height = Math.max(minHeight, container.height); + if (height) + settings.set("state/console/@height", height); + emit("resize"); + }); + + plugin.getElement("btnClose").onclick = function(){ + hide(); + this.blur(); + }; + plugin.getElement("btnConsoleMax").onclick = function(){ + if (this.value) + maximizeConsoleHeight(); + else + restoreConsoleHeight(); + }; + + // Create new tabs + var state = settings.getJson("state/console"); + if (!state) { + state = options.defaultState || { + type: "pane", + nodes: [ + { + type: "tab", + editorType: "terminal", + active: "true" + }, + { + type: "tab", + editorType: "immediate", + document: { + title: "Immediate" + } + } + ] + }; + } + + if (options.testing != 2) { + setState(state, true, function(){}); + emit.sticky("ready"); + } + + tabs.on("paneCreate", function(e) { + if (hidden && container && ui.isChildOf(container, e.pane.aml)) { + e.pane.visible = false; + } + }); + + emit("draw"); + } + + /***** Methods *****/ + + function getState(filter) { + var state = tabs.getState(container.lastChild, filter); + var tab = tabs.focus && tabs.findTab(state.focus); + if (!tab || !ui.isChildOf(container, tab.pane.aml)) + delete state.focus; + return state; + } + + function setState(state, init, callback) { + state.container = container; + return tabs.setState(state, init, callback); + } + + function getTabs(){ + return tabs.getTabs(container); + } + + function getPanes(){ + return tabs.getPanes(container); + } + + function clear(){ + var tabNodes = tabs.getPanes(container); + + for (var i = tabNodes.length - 1; i >= 0; i--) { + var pane = tabNodes[i], nodes = pane.getTabs(); + if (!ui.isChildOf(container, pane.aml)) + continue; + + for (var j = nodes.length - 1; j >= 0; j--) { + var tab = nodes[j]; + tab.unload(); + } + pane.unload(); + } + } + + function maximizeConsoleHeight(){ + if (maximized) + return; + maximized = true; + + apf.document.documentElement.appendChild(container); + var top = layout.getElement("root").getTop() + 1; + container.setAttribute('anchors', top + ' 0 0 0'); + lastZIndex = container.$ext.style.zIndex; + container.removeAttribute('height'); + container.$ext.style.maxHeight = "10000px"; + container.$ext.style.zIndex = 100000; + + settings.set("state/console/@maximized", true); + plugin.getElement("btnConsoleMax").setValue(true); + + setTimeout(function(){ + getPanes().forEach(function(pane) { + var tab = pane.activeTab; + if (tab) + tab.editor.resize(); + }); + }); + + emit("resize"); + } + + function restoreConsoleHeight(){ + if (!maximized) + return; + maximized = false; + + layout.findParent(plugin).appendChild(container); + container.removeAttribute('anchors'); + maxHeight = window.innerHeight - 70; + // container.$ext.style.maxHeight = maxHeight + "px"; + + container.setAttribute('height', maxHeight && height > maxHeight ? maxHeight : height); + container.$ext.style.zIndex = lastZIndex; + + settings.set("state/console/@maximized", false); + plugin.getElement("btnConsoleMax").setValue(false); + + getPanes().forEach(function(pane) { + var tab = pane.activeTab; + if (tab) + tab.editor.resize(); + }); + + emit("resize"); + } + + function hide(immediate) { show(immediate, true); } + + function show(immediate, shouldHide) { + if (!shouldHide) + draw(); + + if (hidden == shouldHide || animating) + return; + + hidden = shouldHide; + animating = true; + maxHeight = window.innerHeight - 70; + + getPanes().forEach(function(pane) { + pane.visible = !shouldHide; + }); + + if (!shouldHide && !tabs.focussedTab) { + getPanes().some(function(pane) { + if (pane.getTab()) { + tabs.focusTab(pane.getTab()); + return true; + } + }); + } + + var finish = function() { + if (onFinishTimer) + clearTimeout(onFinishTimer); + + onFinishTimer = setTimeout(function(){ + if (shouldHide) { + container.hide(); + + // If the focussed tab is in the console, make the first + // tab we can find inside the tabs the focussed tab. + if (tabs.focussedTab + && getPanes().indexOf(tabs.focussedTab.pane) > -1) { + tabs.getPanes(tabs.container).every(function(pane) { + var tab = pane.getTab(); + if (!tab) { + tabs.focusTab(); // blur + return true; + } + else { + tabs.focusTab(tab); + return false; + } + }); + } + } + else { + container.$ext.style.minHeight = minHeight + "px"; + container.minheight = minHeight; + + maxHeight = window.innerHeight - 70; + // container.$ext.style.maxHeight = maxHeight + "px"; + } + + container.height = height + 1; + container.setAttribute("height", height); + container.$ext.style[apf.CSSPREFIX + "TransitionDuration"] = ""; + + animating = false; + + settings.set("state/console/@expanded", !shouldHide); + + apf.layout.forceResize(); + emit("resize"); + }, 100); + }; + + var toHeight; + var animOn = settings.getBool("user/general/@animateui"); + if (!shouldHide) { + toHeight = Math.max(minHeight, Math.min(maxHeight, height)); + + container.$ext.style.minHeight = 0; + container.setHeight(collapsedHeight); + //container.$ext.style.height = collapsedHeight + "px"; + + container.show(); + + anims.animateSplitBoxNode(container, { + height: toHeight + "px", + immediate: immediate || !animOn, + duration: 0.2, + timingFunction: "cubic-bezier(.30, .08, 0, 1)" + }, finish); + } + else { + toHeight = collapsedHeight; + + if (container.parentNode != consoleRow) + restoreConsoleHeight(); + + container.$ext.style.minHeight = 0; + container.$ext.style.maxHeight = "10000px"; + + anims.animateSplitBoxNode(container, { + height: toHeight + "px", + immediate: immediate || !animOn, + duration: 0.2, + timingFunction: "ease-in-out" + }, finish); + } + } + + function openFile(path, active, callback) { + if (typeof active == "function") + callback = active, active = false; + + open({path: path, active: active}, callback); + } + + function openEditor(type, active, callback) { + if (typeof active == "function") + callback = active, active = false; + + open({editorType: type, active: active}, callback); + } + + function open(options, callback) { + if (!options.pane) { + draw(); + options.pane = container.getElementsByTagNameNS(apf.ns.aml, "tab")[0].cloud9pane; + } + return tabs.open(options, callback); + } + + /***** Lifecycle *****/ + + plugin.on("load", function(){ + load(); + }); + plugin.on("enable", function(){ + + }); + plugin.on("disable", function(){ + + }); + plugin.on("unload", function(){ + tabs.containers.remove(container); + clear(); + loaded = false; + }); + + /***** Register and define API *****/ + + /** + * A collapsable panel in the bottom of Cloud9's UI that contains panes, + * tabs and editors. + * + * To open new tabs in the console you can use: + * + * console.open({ + * path : "/file.txt", + * active : true + * }, function(){}); + * + * This is equivalent to using the {@link tabManager} to open new tabs: + * + * tabManager.open({ + * path : "/file.txt", + * active : true, + * pane : console.getPanes()[0] + * }, function(){}); + * + * @singleton + */ + plugin.freezePublicAPI({ + /** + * The AMLElement for the main panes area. + * @property {AMLElement} container + * @readonly + */ + get container(){ return container; }, + + _events: [ + /** + * Fires after the console is drawn. + * @event draw + */ + "draw", + /** + * Fires when the console is resized + * @event resize + **/ + "resize", + /** + * Fires when the console is ready for adding new tabs + */ + "ready" + ], + + /** + * Returns an array containing all the tabs in the console. + */ + getTabs: getTabs, + + /** + * Returns an array containing all the panes in the console. + */ + getPanes: getPanes, + + /** + * Retrieves the state of all panes, tabs and documents + * as a single serializable object. + * @returns {Object} + */ + getState: getState, + + /** + * Loads the state of all panes panes, tabs anddocuments from a + * simple object. + * @param {Object} state The state describing the pane layout. + * @param {Boolean} [init] When set to true, optimizes the state + * loading for initialization of Cloud9. + * @param {Function} callback Called when the state loading is completed. + */ + setState: setState, + + /** + * Removes all panes, except one, and destroys all tabs, documents + * and editors. + * + * @param {Boolean} [soft=false] When set to true clear + * will not unload tabs. This can be useful when loading a new + * state with exactly the same tabs. WARNING: this can lead to + * leaking tabs/documents, etc. Use with caution! getTabs() will + * continue to return all the tabs. Even though they are no longer + * attached to a pane. + */ + clear: clear, + + /** + * Expands the console. + */ + show: show, + + /** + * Collapses the console. + */ + hide: hide, + + /** + * Opens a new tab in the console. If the tab with a specified + * path already exists, that tab is activated. If state is given + * for a document, then that state is set prior to + * loading the tab. If a path is specified the file contents is + * loaded into the document. If no editorType is specified, the + * editor is determined based on the extension of the filename. + * + * See also {@link tabManager#method-open} + * + * @param options + * @param {String} [options.path] The path of the file to open + * @param {Pane} [options.pane] The pane to attach the new tab to + * @param {String} [options.editorType] The type of the editor for this tab + * @param {Boolean} [options.active=false] Whether this tab is set as active + * @param {Boolean} [options.demandExisting=false] Whether to try opening an + * existing tab even for tabs without a path. + * @param {Object} [options.document] Object describing the + * state of the document (see {@link Document#method-getState}) + * @param {String} [options.value] The contents of the file + * @param {String} [options.title] The title of the tab + * @param {String} [options.tooltip] The tooltip at the button of the tab + * @param {Function} callback + * @param {Error} callback.err An error that might + * occur during the load of the file contents. + * @param {Tab} callback.tab The created tab. + * @param {Function} callback.done Call this function + * when done retrieving the value. This is only relevant if + * -1 is passed to `value`. You are responsible for settings the + * document value yourself, like so: `tab.document.value = "value";` + * @returns {Tab} The created tab. + * @fires open + * @fires beforeOpen + */ + open: open, + + /** + * Opens a new pane tab in the console with the default editor and loads the file + * contents into the document. This is a convenience method. For + * the full method description see {@link tabManager#method-open}. + * + * @param {String} path The path of the file to open. + * @param {Boolean} [active] When set to true the new tab will become active in it's pane. + * @param {Function} callback Called when the file contents is loaded. + * @param {Error} callback.err An error that might + * occur during the load of the file contents. + * @param {Tab} callback.tab The created tab. + * @returns {Tab} The created tab. + */ + openFile: openFile, + + /** + * Opens a new tab in the console with a specific editor + * @param {String} editorType The type of the editor for this tab. + * @param {Boolean} [active] When set to true the new tab will become active in it's pane. + * @param {Function} callback Called when the editor is loaded. + * @param {Error} callback.err An error that might + * occur during the load of the editor. + * @param {Tab} callback.tab The created tab. + * @returns {Tab} The created tab. + */ + openEditor: openEditor + }); + + register(null, { + console: plugin + }); + } +}); diff --git a/plugins/c9.ide.console/console.xml b/plugins/c9.ide.console/console.xml new file mode 100644 index 00000000..2e8f7fe3 --- /dev/null +++ b/plugins/c9.ide.console/console.xml @@ -0,0 +1,11 @@ + + + + + + + \ No newline at end of file diff --git a/plugins/c9.ide.console/console_test.js b/plugins/c9.ide.console/console_test.js new file mode 100644 index 00000000..32b29183 --- /dev/null +++ b/plugins/c9.ide.console/console_test.js @@ -0,0 +1,395 @@ +/*global describe it before after = */ + +"use client"; + +require(["lib/architect/architect", "lib/chai/chai", "/vfs-root"], + function (architect, chai, baseProc) { + var expect = chai.expect; + + expect.setupArchitectTest([ + { + packagePath: "plugins/c9.core/c9", + workspaceId: "javruben/dev", + startdate: new Date(), + debug: true, + hosted: true, + local: false, + davPrefix: "/" + }, + + "plugins/c9.core/ext", + "plugins/c9.core/http-xhr", + "plugins/c9.core/util", + "plugins/c9.ide.ui/lib_apf", + "plugins/c9.ide.ui/forms", + { + packagePath: "plugins/c9.core/settings", + testing: true + }, + "plugins/c9.core/api.js", + { + packagePath: "plugins/c9.ide.ui/ui", + staticPrefix: "plugins/c9.ide.ui" + }, + "plugins/c9.ide.editors/document", + "plugins/c9.ide.editors/undomanager", + "plugins/c9.ide.editors/editors", + "plugins/c9.ide.editors/editor", + { + packagePath: "plugins/c9.ide.editors/tabmanager", + testing: 2 + }, + "plugins/c9.ide.ui/focus", + "plugins/c9.ide.editors/pane", + "plugins/c9.ide.editors/tab", + "plugins/c9.ide.run/output", + "plugins/c9.ide.console/console", + { + packagePath: "plugins/c9.ide.terminal/terminal", + testing: true + }, + "plugins/c9.ide.run/run", + "plugins/c9.fs/proc", + "plugins/c9.vfs.client/vfs_client", + "plugins/c9.vfs.client/endpoint", + "plugins/c9.ide.auth/auth", + { + packagePath: "plugins/c9.fs/fs", + baseProc: baseProc + }, + "plugins/c9.fs/fs.cache.xml", + + // Mock plugins + { + consumes: ["apf", "ui", "Plugin"], + provides: [ + "commands", "menus", "commands", "layout", "watcher", + "preferences", "anims", "clipboard", "dialog.alert", "auth.bootstrap", + "dialog.question", "debugger", "run.gui", "info", "dialog.error", + "dialog.filesave" + ], + setup: expect.html.mocked + }, + { + consumes: ["console", "tabManager", "terminal", "output"], + provides: [], + setup: main + } + ], architect); + + function main(options, imports, register) { + var tabs = imports.tabManager; + var cnsl = imports.console; + + function countEvents(count, expected, done) { + if (count == expected) + done(); + else + throw new Error("Wrong Event Count: " + + count + " of " + expected); + } + + expect.html.setConstructor(function(tab) { + if (typeof tab == "object") + return tab.pane.aml.getPage("editor::" + tab.editorType).$ext; + }); + + var startCount; + + describe('console', function() { + before(function(done) { + apf.config.setProperty("allow-select", false); + apf.config.setProperty("allow-blur", false); + + document.documentElement.style.paddingBottom = "200px"; + + cnsl.once("ready", function(){ + bar.$ext.style.background = "rgba(220, 220, 220, 0.93)"; + bar.$ext.style.position = "fixed"; + bar.$ext.style.left = "20px"; + bar.$ext.style.right = "20px"; + bar.$ext.style.bottom = "20px"; + bar.$ext.style.height = "150px"; + + cnsl.getPanes()[0].focus(); + startCount = tabs.getTabs().length; + done(); + }); + }); + + describe("open(), openFile(), openEditor() and reload()", function(){ + it('should open a pane with just an editor', function(done) { + cnsl.openEditor("terminal", true, function(err, tab) { + expect(tabs.getTabs()).length(startCount + 1); + + expect(tabs.focussedTab) + .to.exist + .to.equal(tab) + //.property("path").to.equal(vpath); + done(); + }); + }); + }); + describe("getTabs(), getPanes()", function(){ + it('should return a list containing all the pages', function(done) { + expect(tabs.getTabs()).length.gt(startCount); + done(); + }); + it('should return a list containing all the tabs', function(done) { + expect(tabs.getPanes()).length(1); + done(); + }); + it('should return an editor of a tab', function(done) { + var pages = tabs.getTabs(); + expect(pages[pages.length - 1].editor) + .property("type").to.equal("terminal"); + done(); + }); + }); + describe("clear(), getState() and setState()", function(){ + var state, info = {}; + it('should retrieve the state', function(done) { + state = cnsl.getState(); + info.pages = tabs.getTabs().map(function(tab) { + return tab.path || tab.id; + }); + done(); + }); + it('should clear all tabs and pages', function(done) { + var count = 0, expected = 0; + tabs.getTabs().forEach(function(tab) { + expected += 2; + tab.on("unload", function(){ + count++; + }); + tab.document.on("unload", function(){ + count++; + }); + }); + + cnsl.getPanes()[0]; + cnsl.clear(); + expect(tabs.getTabs(), "pages").length(0); + expect(cnsl.getPanes(), "tabManager").length(0); + + countEvents(count, expected, done); + }); + it('should restore the state', function(done) { + cnsl.setState(state, false, function(err) { + if (err) throw err.message; + }); + var l = info.pages.length; + var pages = tabs.getTabs(); + + expect(pages).length(l); + expect(tabs.getPanes()[0].getTabs()).length(l); + expect(tabs.focussedTab.pane.getTabs()).length(l); + + // Wait for the title to load + setTimeout(function(){ + expect(tabs.getTabs().map(function(tab) { + return tab.path || tab.id; + })).to.deep.equal(info.pages); + done(); + }, 1000); + }); + }); + describe("vsplit(), hsplit(), removeTab()", function(){ + this.timeout(10000); + + it('should split a pane vertically, making the existing pane the top one', function(done) { + var tab = tabs.focussedTab; + var pane = tabs.focussedTab.pane; + + tabs.focusTab(tabs.getTabs()[0]); + var name = tabs.getTabs()[0].editor.name; + tabs.focusTab(tab); + + var btmtab = pane.vsplit(true); + expect(pane.aml.getTop()).lt(btmtab.aml.getTop()); + tabs.focussedTab.attachTo(btmtab); + tabs.on("tabAfterActivate", function c1(){ + expect(tabs.focussedTab.editor.name).to.equal(name); + expect(tab.isActive()).to.ok; + tabs.off("tabAfterActivate", c1) + done(); + }); + tabs.focusTab(tabs.getTabs()[0]); + }); + it('should remove the bottom pane from a vertical split', function(done) { + var pane = tabs.getPanes()[1]; + var tab = pane.getTab(); + pane.unload(); + expect(tabs.getPanes()).length(1); + expect(tabs.getTabs()).length(startCount + 1); + tabs.focusTab(tab); + expect(tab.editor.name).to.match(/^terminal/); + expect(tab.pane.aml.getPage("editor::terminal").$ext.style.display).to.not.equal("none"); + done(); + }); + it('should split a pane vertically, making the existing pane the bottom one', function(done) { + var pane = tabs.focussedTab.pane; + var toptab = pane.vsplit(); + expect(toptab.aml.getTop()).lt(pane.aml.getTop()); + var tab = tabs.getTabs()[0]; + tab.attachTo(toptab); + tabs.focusTab(tab); + done(); + }); + it('should remove the top pane from a vertical split', function(done) { + var pane = tabs.getPanes()[0]; + var tab = pane.getTab(); + pane.unload(); + expect(tabs.getPanes()).length(1); + expect(tabs.getTabs()).length(3); + tabs.focusTab(tab); + expect(tab.editor.name).to.match(/^terminal/); + expect(tab.pane.aml.getPage("editor::terminal").$ext.style.display).to.not.equal("none"); + done(); + }); + it('should split a pane horizontally, making the existing pane the left one', function(done) { + var pane = tabs.focussedTab.pane; + var righttab = pane.hsplit(true); + expect(pane.aml.getLeft()).lt(righttab.aml.getLeft()); + tabs.focussedTab.attachTo(righttab); + tabs.focusTab(tabs.getTabs()[0]); + + setTimeout(function(){ + expect(tabs.focussedTab.title).to.match(/^bash - |^Terminal/); + done(); + }, 1000); + }); + it('should remove the left pane from a horizontal split', function(done) { + var pane = tabs.getPanes()[0]; + var tab = tabs.getPanes()[1].getTab(); + pane.unload(); + expect(tabs.getPanes()).length(1); + expect(tabs.getTabs()).length(3); + tabs.focusTab(tab); + expect(tab.editor.name).to.match(/^terminal/); + expect(tab.pane.aml.getPage("editor::terminal").$ext.style.display).to.not.equal("none"); + done(); + }); + it('should split a pane horizontally, making the existing pane the right one', function(done) { + var pane = tabs.focussedTab.pane; + var leftPane = pane.hsplit(); + expect(leftPane.aml.getLeft()).lt(pane.aml.getLeft()); + tabs.focussedTab.attachTo(leftPane); + var newTab = tabs.getTabs()[1]; + tabs.focusTab(newTab); + expect(tabs.focussedTab.title).to.equal(newTab.title); + done(); + }); + it('should remove the right pane from a horizontal split', function(done) { + var pane = tabs.getPanes()[1]; + var tab = pane.getTab(); + pane.unload(); + expect(tabs.getPanes()).length(1); + expect(tabs.getTabs()).length(3); + tabs.focusTab(tab); + expect(tab.editor.name).to.match(/^terminal/); + done(); + }); + it('should properly serialize and deserialize', function(done) { + var cstate = cnsl.getState(); + var state = cnsl.getState(); + cnsl.clear(); + expect(tabs.getPanes()).length(0); + expect(tabs.getTabs()).length(0); + + cnsl.setState(state, function(err) { + if (err) throw err.message; + }); + expect(cstate).to.deep.equal(cnsl.getState()); + + //Loop through state to check all the widths/heights + +// (function recur(parent, list) { +// list.forEach(function(state) { +// var p; +// +// if (state.type == "pane") { +// p = createPane(state).aml; +// parent.appendChild(p); +// } +// else if (state.type == "hsplitbox" || state.type == "vsplitbox") { +// p = parent.appendChild(new ui[state.type]({ +// splitter : true, +// padding : 3, +// width : state.width, +// height : state.height +// })); +// } +// else if (state.type == "tab") { +// var tab = findTab(state.id); +// if (!tab) { +// state.pane = parent.cloud9pane; +// state.init = init; +// +// open(state, function(err, tab) { +// callback(err, tab); +// }); +// } +// else { +// tab.attachTo(parent); +// } +// return; +// } +// recur(p, state.nodes); +// }); +// })(bar, [cstate]); + + done(); + }); + }); +// describe("activateTab() and focusTab()", function(){ +// it('should focus a tab', function(done) { +// tabs.activateTab(); +// done(); +// }); +// it('should activate a tab on a focussed pane', function(done) { +// done(); +// }); +// it('should activate a tab but not focus it', function(done) { +// done(); +// }); +// }); +// describe("toggleButtons() and resizePanes()", function(){ +// it('should hide and show the pane buttons', function(done) { +// done(); +// }); +// it('should force resize the pane buttons', function(done) { +// done(); +// }); +// }); +// describe("All kinds of character sets and symbols", function(){ +// it('should display characters properly', function(done) { +// done(); +// }); +// }); + describe("unload()", function(){ + it('should destroy all ui elements when it is unloaded', function(done) { + var els = tabs.getPanes(); + cnsl.unload(); + + els.forEach(function(pane) { + expect(pane.aml.$amlDestroyed).to.equal(true); + }); + done(); + }); + }); + + //@todo Idea: show in the tabs whether the editor is running atm + // @todo test fs integration + + after(function(done) { + tabs.unload(); + + document.documentElement.style.paddingBottom = ""; + done(); + }); + }); + + onload && onload(); + } +}); \ No newline at end of file diff --git a/plugins/c9.ide.console/style.css b/plugins/c9.ide.console/style.css new file mode 100644 index 00000000..67c27050 --- /dev/null +++ b/plugins/c9.ide.console/style.css @@ -0,0 +1,19 @@ +.has_apf .console .btnsesssioncontainer .inside { + padding-right : 64px; + padding-left : 2px; +} + +.console .btnsesssioncontainer .tabmenubtn { + display : none; +} + +.console .console_close_btn { + background-image: url("@{icon-path}/@{button-console-close}"); +} + +@media print, (-o-min-device-pixel-ratio: 5/4), (-webkit-min-device-pixel-ratio: 1.25), (min-resolution: 1.25dppx) { + .console .console_close_btn { + background-image: url("@{icon-path}/@{button-console-close-retina}"); + background-size: 22px 66px; + } +} \ No newline at end of file diff --git a/plugins/c9.ide.dialog.common/alert.js b/plugins/c9.ide.dialog.common/alert.js new file mode 100644 index 00000000..7db71012 --- /dev/null +++ b/plugins/c9.ide.dialog.common/alert.js @@ -0,0 +1,109 @@ +define(function(require, module, exports) { + main.consumes = ["Plugin"]; + main.provides = ["dialog.alert"]; + return main; + + function main(options, imports, register) { + var Plugin = imports.Plugin; + + var plugin = new Plugin("Ajax.org", main.consumes); + var emit = plugin.getEmitter(); + + var alertInternal; + + function show(title, header, msg, onhide, options) { + if (alertInternal) + return alertInternal.show(title, header, msg, onhide, options); + + alert(title + + (header ? "\n\n" + header : "") + + (msg ? "\n\n" + msg : "")); + onhide && onhide(); + } + + function hide() { + if (alertInternal) + alertInternal.hide.apply(alertInternal, arguments); + } + + /***** Register *****/ + + /** + * + */ + plugin.freezePublicAPI({ + /** + * @readonly + */ + get dontShow(){ + return alertInternal && alertInternal.dontShow; + }, + + get aml(){ + return alertInternal && alertInternal.aml; + }, + + /** + * Show an alert dialog. + * + * @param {String} [title] The title to display + * @param {String} header The header to display + * @param {String} [msg] The message to display + * @param {Function} [onhide] The function to call after it's closed. + */ + show: show, + + /** + * Hide an alert dialog. + */ + hide: hide, + + /** + * @internal + */ + get alertInternal() { return alertInternal; }, + + /** + * @internal + */ + set alertInternal(value) { + alertInternal = value; + alertInternal.on("show", function(e) { + emit("show", e) + }); + alertInternal.on("hide", function(e) { + emit("hide", e) + }); + alertInternal.on("draw", function(e) { + emit.sticky("draw", e) + }); + }, + + _events: [ + /** + * Fires when the form is drawn. + * @event draw + */ + "draw", + /** + * Fires when the form becomes visible. This happens when + * it's attached to an HTML element using the {@link #attachTo} + * method, or by calling the {@link #method-show} method. + * @event show + */ + "show", + /** + * Fires when the form becomes hidden. This happens when + * it's detached from an HTML element using the {@link #detach} + * method, or by calling the {@link #method-hide} method. + * @event hide + */ + "hide" + ], + }); + + register("", { + "dialog.alert": plugin + }); + } +}); \ No newline at end of file diff --git a/plugins/c9.ide.dialog.common/alert_internal.js b/plugins/c9.ide.dialog.common/alert_internal.js new file mode 100644 index 00000000..2b527375 --- /dev/null +++ b/plugins/c9.ide.dialog.common/alert_internal.js @@ -0,0 +1,81 @@ +define(function(require, module, exports) { + main.consumes = ["Dialog", "util", "dialog.alert"]; + main.provides = ["dialog.alert_internal"]; + return main; + + function main(options, imports, register) { + var Dialog = imports.Dialog; + var util = imports.util; + var alertWrapper = imports["dialog.alert"]; + + /***** Initialization *****/ + + var plugin = new Dialog("Ajax.org", main.consumes, { + name: "dialog.alert_internal", + allowClose: true, + modal: true, + elements: [ + { type: "checkbox", id: "dontshow", caption: "Don't show again", visible: false }, + { type: "filler" }, + { type: "button", id: "ok", caption: "OK", "default": true, onclick: function(){ plugin.hide() } } + ] + }); + alertWrapper.alertInternal = plugin; + + /***** Methods *****/ + + function show(title, header, msg, onhide, options) { + return plugin.queue(function(){ + if (header === undefined) { + plugin.title = "Notice"; + header = title; + msg = msg || ""; + } + else { + plugin.title = title; + } + plugin.heading = util.escapeXml(header); + plugin.body = options && options.isHTML ? msg : (util.escapeXml(msg) || "") + .replace(/\n/g, "
      ") + .replace(/(https?:\/\/[^\s]*\b)/g, "$1"); + + plugin.update([ + { id: "dontshow", visible: options && options.showDontShow } + ]); + + plugin.once("hide", function(){ + onhide && onhide(); + }); + }); + } + + /***** Register *****/ + + /** + * @internal Use dialog.alert instead + * @ignore + */ + plugin.freezePublicAPI({ + /** + * @readonly + */ + get dontShow(){ + return plugin.getElement("dontshow").value; + }, + + /** + * Show an alert dialog. + * + * @param {String} [title] The title to display + * @param {String} header The header to display + * @param {String} [msg] The message to display + * @param {Function} [onhide] The function to call after it's closed. + */ + show: show + }); + + register("", { + "dialog.alert_internal": plugin + }); + } +}); \ No newline at end of file diff --git a/plugins/c9.ide.dialog.common/confirm.js b/plugins/c9.ide.dialog.common/confirm.js new file mode 100644 index 00000000..dd841a01 --- /dev/null +++ b/plugins/c9.ide.dialog.common/confirm.js @@ -0,0 +1,47 @@ +define(function(require, module, exports) { + main.consumes = ["Dialog", "util"]; + main.provides = ["dialog.confirm"]; + return main; + + function main(options, imports, register) { + var Dialog = imports.Dialog; + var util = imports.util; + + /***** Initialization *****/ + + var plugin = new Dialog("Ajax.org", main.consumes, { + name: "dialog.confirm", + allowClose: false, + modal: true, + elements: [ + { type: "button", id: "cancel", caption: "Cancel", hotkey: "ESC", onclick: function(){ plugin.hide() } }, + { type: "button", id: "ok", caption: "OK", color: "green", "default": true, onclick: function(){ plugin.hide() } } + ] + }); + + /***** Methods *****/ + + function show(title, header, msg, onconfirm, oncancel) { + return plugin.queue(function(){ + plugin.title = title; + plugin.heading = util.escapeXml(header); + plugin.body = util.escapeXml(msg); + + plugin.update([ + { id: "ok", onclick: function(){ plugin.hide(); onconfirm(); } }, + { id: "cancel", onclick: function(){ plugin.hide(); oncancel && oncancel(); } }, + ]); + }); + } + + /***** Register *****/ + + plugin.freezePublicAPI({ + show: show + }); + + register("", { + "dialog.confirm": plugin + }); + } +}); \ No newline at end of file diff --git a/plugins/c9.ide.dialog.common/error.css b/plugins/c9.ide.dialog.common/error.css new file mode 100644 index 00000000..96f0a115 --- /dev/null +++ b/plugins/c9.ide.dialog.common/error.css @@ -0,0 +1,77 @@ +.errorlabel, .disconnectlabel{ + position: absolute; + left: 0; + right: 0; + top: 0; + z-index: 10000000; + /*text-align: center;*/ + pointer-events: none; + .font-smoothing(@error-font-smoothing); +} +.errorlabel.anim, .disconnectlabel.anim{ + transition: top 0.2s; + -moz-transition: top 0.2s; /* Gecko */ + -webkit-transition: top 0.2s; /* Safari */ +} +.errorlabel.fade-in{ + transition: opacity 0.2s; + -moz-transition: opacity 0.2s; /* Gecko */ + -webkit-transition: opacity 0.2s; /* Safari */ +} +.errorlabel div{ + background: @error-background; + padding: @error-padding; + color: @error-color; + border-radius: 0 0 3px 3px; + box-shadow: @error-box-shadow; + line-height: 1.4; + display: inline-block; + position: relative; + word-wrap: break-word; + max-width: 100%; + pointer-events: auto; +} +.errorlabel.fade-in div{ + border-radius: 3px; +} +.errorlabel u.close{ + .image-2x("@{image-path}/@{error-close-image}", 42px, 28px); + background-position: @error-close-idle-position; + width: 14px; + height: 14px; + position: absolute; + right: 8px; + top: 6px; + cursor: pointer; +} +.errorlabel u.close:hover{ + background-position: @error-close-hover-position; +} +.errorlabel u.close:active{ + background-position: @error-close-active-position; +} +.errorlabel div span{ + border-bottom: 1px dotted rgb(255, 174, 174); + cursor: help; +} + +.disconnectlabel{ + z-index: 10000001; +} +.disconnectlabel div{ + background: @disconnect-background; + padding: @disconnect-padding; + color: @disconnect-color; + border-radius: 0 0 3px 3px; + box-shadow: @disconnect-box-shadow; + line-height: 1.4; + display: inline-block; + position: relative; + word-wrap: break-word; + text-align: center; + width: 300px; + pointer-events: auto; +} +.disconnectlabel u{ + cursor: pointer; +} \ No newline at end of file diff --git a/plugins/c9.ide.dialog.common/error.js b/plugins/c9.ide.dialog.common/error.js new file mode 100644 index 00000000..3d28bb20 --- /dev/null +++ b/plugins/c9.ide.dialog.common/error.js @@ -0,0 +1,276 @@ +define(function(require, exports, module) { + "use strict"; + + main.consumes = ["Plugin", "ui"]; + main.provides = ["dialog.error"]; + return main; + + function main(options, imports, register) { + var Plugin = imports.Plugin; + var ui = imports.ui; + + /***** Initialization *****/ + + var plugin = new Plugin("Ajax.org", main.consumes); + var emit = plugin.getEmitter(); + + var topPx = 0; + var lastCookie = 0; + var offset = 0; + var error, hideTimeout, disconnect; + + var DISCONNECTDELAY = 1000; + + function load() { + ui.insertCss(require("text!./error.css"), + options.staticPrefix, plugin); + } + + function initDisconnectEvents(vfs){ + var timer; + + vfs.once("connect", function(){ + vfs.connection.on("reconnectDelay", function(e){ + clearInterval(timer); + + var delay = e.delay; + if (delay > 999) { + timer = setInterval(function(){ + if (vfs.connected) + return clearInterval(timer); + + delay -= 1000; + showDisconnect({ delay: delay }); + + if (delay <= 0) + clearInterval(timer); + }, 1000); + } + + showDisconnect(e); + }); + }); + vfs.on("connect", function(){ + hideDisconnect(); + }); + vfs.on("disconnect", function(){ + // setTimeout(function(){ + // showDisconnect(); + // }, DISCONNECTDELAY); + }); + vfs.on("connecting", function(){ + showDisconnect({ connecting: true }); + }); + plugin.on("retryConnect", function(){ + vfs.connection.reconnect(0); + }); + } + + /***** Methods *****/ + + function getCenterX(){ + var bartools = document.querySelector(".bartools"); + if (!bartools) return 0; // For testing + + var b1 = bartools.getBoundingClientRect(); + var b2 = bartools.nextSibling.getBoundingClientRect(); + + return b1.left + b1.width + ((b2.left - b1.left - b1.width)/2); + } + + function show(message, timeout) { + // Error message container + if (!error) { + error = document.body.appendChild(document.createElement("div")); + error.className = "errorlabel"; + error.addEventListener("mouseup", function(e) { + if (e.target.tagName == "U") + hide(); + }); + } + + if (!message) { + console.trace(); + return console.error("empty error message", message); + } + + console.error("Error:", + message.stack || message.html || message.message || message); + + hide(function () { + var messageString; + if (typeof message == "string") { + messageString = apf.escapeXML(message); + } + else { + if (message.message) + messageString = apf.escapeXML(message.message); + else if (message.html) + messageString = message.html; + else + messageString = "Error: " + message.toString(); + } + error.innerHTML = "
      " + + messageString + "
      "; + + error.style.opacity = 0; + error.style.display = "block"; + error.style.top = (offset - (error.offsetHeight - 10 + topPx)) + "px"; + error.firstChild.style.marginLeft = Math.max(0, (getCenterX() - (error.firstChild.offsetWidth / 2))) + "px"; + + // Start anim + setTimeout(function() { + error.className = "errorlabel anim " + (offset > 0 ? "fade-in" : ""); + error.style.top = (offset + topPx) + "px"; + error.style.opacity = 1; + }, 10); + + clearTimeout(hideTimeout); + if (!(timeout < 0)) + hideTimeout = setTimeout(hide, timeout || 15000); + }); + + return ++lastCookie; + } + + function hide(cookie, callback) { + if (typeof cookie === "function") + return hide(null, cookie); + + if (cookie && lastCookie !== cookie) + return callback && callback(); + if (!error || error.style.display === "none") + return callback && callback(); + + error.className = "errorlabel anim " + (offset > 0 ? "fade-in" : ""); + if (offset > 0) + error.style.opacity = 0; + else + error.style.top = (-1 * error.offsetHeight - 10 + topPx) + "px"; + + setTimeout(function() { + error.style.display = "none"; + callback && callback(); + }, 220); + } + + function showDisconnect(options){ + // Error message container + if (!disconnect) { + disconnect = document.body.appendChild(document.createElement("div")); + disconnect.className = "disconnectlabel"; + disconnect.addEventListener("mouseup", function(e) { + if (e.target.tagName == "U") + emit("retryConnect"); + }); + } + + var message; + if (!options || options.delay < 1000 || options.connecting) + message = "Reconnecting..."; + else if (options.delay) + message = "Reconnecting in " + Math.ceil(options.delay/1000) + + " seconds." + + (options.delay < 2001 ? "" : " Retry Now."); + else + message = "Reconnecting..."; + + disconnect.innerHTML = "
      " + message + "
      "; + disconnect.firstChild.style.marginLeft + = Math.max(0, (getCenterX() - 150)) + "px"; + + if (disconnect.style.display == "block") + return; + + disconnect.style.display = "block"; + disconnect.style.top = (-1 * disconnect.offsetHeight - 10 + topPx) + "px"; + + // Start anim + setTimeout(function() { + disconnect.className = "disconnectlabel anim"; + disconnect.style.top = (topPx) + "px"; + }, 10); + + offset = 28; + + // document.querySelector(".c9-offline").addEventListener("click", function(){ + // alert("Offline Notication", "You are currently offline.", + // "This indicator notifies you that Cloud9 is unable to reach " + // + "the server. This usually happens because you are offline. " + // + "Some features will be disabled until the " + // + "network connection becomes available again. " + // + "This notication could also show when the server is " + // + "unreachable due to other reasons. Sometimes a refresh of " + // + "the tab will fix an issue. Please e-mail " + // + "support@c9.io for further problem resolution."); + // }, false); + } + + function hideDisconnect(cookie, callback) { + if (!disconnect || disconnect.style.display === "none") + return callback && callback(); + + disconnect.className = "disconnectlabel anim"; + disconnect.style.top = (-1 * disconnect.offsetHeight - 10 + topPx) + "px"; + setTimeout(function() { + disconnect.style.display = "none"; + callback && callback(); + }, 220); + + offset = 0; + } + + /***** Lifecycle *****/ + + plugin.on("load", function() { + load(); + }); + plugin.on("unload", function() { + topPx = 0; + lastCookie = 0; + offset = 0; + error = null; + hideTimeout = null; + }); + + /***** Register and define API *****/ + + /** + * Show error messages to the user + * + * This plugin provides a way to display error messages to the user. + * + * @singleton + **/ + plugin.freezePublicAPI({ + get top(){ return topPx; }, + set top(value){ topPx = value; }, + + get vfs(){ throw new Error("Permission Denied"); }, + set vfs(v){ initDisconnectEvents(v); }, + + /** + * + */ + showDisconnect: showDisconnect, + + /** + * + */ + hideDisconnect: hideDisconnect, + + /** + * Displays an error message in the main error reporting UI. + * @param {String} message The message to display. + */ + show: show, + + /** + * Hides the main error reporting UI. + */ + hide: hide, + }); + + register(null, { "dialog.error" : plugin }); + } +}); \ No newline at end of file diff --git a/plugins/c9.ide.dialog.common/error_test.js b/plugins/c9.ide.dialog.common/error_test.js new file mode 100644 index 00000000..8c57a9a1 --- /dev/null +++ b/plugins/c9.ide.dialog.common/error_test.js @@ -0,0 +1,74 @@ +/*global describe, it, after */ + +"use client"; + +require(["lib/architect/architect", "lib/chai/chai"], function (architect, chai) { + var expect = chai.expect; + + expect.setupArchitectTest([ + "plugins/c9.ide.ui/lib_apf", + { + packagePath: "plugins/c9.ide.ui/ui", + staticPrefix: "plugins/c9.ide.ui" + }, + + "plugins/c9.core/ext", + { + packagePath: "plugins/c9.ide.dialog.common/error", + staticPrefix: "plugins/c9.ide.layout.classic" + }, + + // Mock plugins + { + consumes: [], + provides: [ + "util", "settings", "c9", "dialog.alert", "commands", "dialog.question" + ], + setup: expect.html.mocked + }, + { + consumes: ["dialog.error"], + provides: [], + setup: main + } + ], architect); + + function main(options, imports, register) { + var error = imports["dialog.error"]; + + describe('layout', function() { + it('should show an error notification', function(done) { + error.show("Test"); + setTimeout(function(){ + expect.html(document.querySelector(".errorlabel")).visible; + expect.html(document.querySelector(".errorlabel")).text(/Test/); + done(); + }, 250); + }); + it('should hide the error notification', function(done) { + error.hide(function(){ + expect.html(document.querySelector(".errorlabel")).not.visible; + done(); + }); + }); + }); + + if (!onload.remain) { + describe("unload()", function(){ + it('should destroy all ui elements when it is unloaded', function() { + error.unload(); + }); + }); + + //@todo Idea: show in the tabs whether the editor is running atm + // @todo test fs integration + + after(function(done) { + document.body.style.marginBottom = ""; + done(); + }); + } + + onload && onload(); + } +}); \ No newline at end of file diff --git a/plugins/c9.ide.dialog.common/filechange.js b/plugins/c9.ide.dialog.common/filechange.js new file mode 100644 index 00000000..1761bda0 --- /dev/null +++ b/plugins/c9.ide.dialog.common/filechange.js @@ -0,0 +1,66 @@ +define(function(require, module, exports) { + main.consumes = ["Dialog", "util"]; + main.provides = ["dialog.filechange"]; + return main; + + function main(options, imports, register) { + var Dialog = imports.Dialog; + var util = imports.util; + + /***** Initialization *****/ + + var plugin = new Dialog("Ajax.org", main.consumes, { + name: "dialog.filechange", + title: "File changed", + body: "

      You or a collaborator has changed this file.

      " + + "Which version would you like to use?", + allowClose: false, + modal: false, + width: 600, + elements: [ + { type: "checkbox", id: "applyall", caption: "Apply to all changed files" }, + { type: "filler" }, + { type: "button", id: "keepmine", caption: "Keep Mine", color: "blue" }, + { type: "button", id: "useremote", caption: "Use Remote", color: "blue" }, + { type: "button", id: "mergeboth", caption: "Merge Both", color: "green", "default": true }, + ] + }); + + /***** Methods *****/ + + function show(title, header, onlocal, onremote, onmerge, options) { + return plugin.queue(function(){ + plugin.title = title; + plugin.heading = util.escapeXml(header); + + var cb = plugin.getElement("applyall"); + cb.uncheck(); + cb.setAttribute("visible", options.all !== false); + + plugin.update([ + { id: "keepmine", onclick: function(){ plugin.hide(); onlocal(cb.value); } }, + { id: "useremote", onclick: function(){ plugin.hide(); onremote(cb.value); } }, + { id: "mergeboth", visible: options.merge, onclick: function(){ plugin.hide(); onmerge(cb.value); } } + ]); + }); + } + + /***** Register *****/ + + plugin.freezePublicAPI({ + show: show + }) + + register("", { + "dialog.filechange": plugin, + /** + * + */ + set all(value) { + plugin.update([ + { id: "applyall", visible: value} + ]); + }, + }); + } +}); \ No newline at end of file diff --git a/plugins/c9.ide.dialog.common/fileoverwrite.js b/plugins/c9.ide.dialog.common/fileoverwrite.js new file mode 100644 index 00000000..8da9bfa9 --- /dev/null +++ b/plugins/c9.ide.dialog.common/fileoverwrite.js @@ -0,0 +1,81 @@ +define(function(require, module, exports) { + main.consumes = ["Dialog", "util"]; + main.provides = ["dialog.fileoverwrite"]; + return main; + + function main(options, imports, register) { + var Dialog = imports.Dialog; + var util = imports.util; + + /***** Initialization *****/ + + // @todo think about merging this with question. + + var plugin = new Dialog("Ajax.org", main.consumes, { + name: "dialog.fileoverwrite", + allowClose: false, + modal: true, + elements: [ + { type: "button", id: "yestoall", caption: "Overwrite All", color: "green", visible: false }, + { type: "button", id: "notoall", caption: "Skip All", color: "red", "default": true, visible: false }, + { type: "filler" }, + { type: "button", id: "yes", caption: "Overwrite", color: "green", "default": true, hotkey: "Y" }, + { type: "button", id: "no", caption: "Skip", color: "red", hotkey: "N" }, + { type: "button", id: "cancel", caption: "Cancel", visible: false, hotkey: "ESC" } + ] + }); + + /***** Methods *****/ + + function show(title, header, msg, onOverwrite, onSkip, options) { + return plugin.queue(function(){ + var all = options.all; + var cancel = options.cancel; + var metadata = options.metadata; + + plugin.title = title; + plugin.heading = util.escapeXml(header); + plugin.body = util.escapeXml(msg); + + plugin.allowClose = cancel; + + var gotYes = false; + plugin.once("hide", function(){ + !gotYes && cancel && onSkip(false, true, metadata); + }); + + plugin.update([ + { id: "cancel", visible: cancel, onclick: function(){ plugin.hide(); } }, + { id: "yestoall", visible: all, onclick: function(){ + gotYes = true; + plugin.hide(); + onOverwrite(true, metadata); + }}, + { id: "notoall", visible: all, onclick: function(){ + plugin.hide(); + onSkip(true, false, metadata); + }}, + { id: "yes", onclick: function(){ + gotYes = true; + plugin.hide(); + onOverwrite(false, metadata); + }}, + { id: "no", onclick: function(){ + plugin.hide(); + onSkip(false, false, metadata); + }} + ]); + }); + } + + /***** Register *****/ + + plugin.freezePublicAPI({ + show: show + }) + + register("", { + "dialog.fileoverwrite": plugin + }); + } +}); \ No newline at end of file diff --git a/plugins/c9.ide.dialog.common/fileremove.js b/plugins/c9.ide.dialog.common/fileremove.js new file mode 100644 index 00000000..e7594b5a --- /dev/null +++ b/plugins/c9.ide.dialog.common/fileremove.js @@ -0,0 +1,58 @@ +define(function(require, module, exports) { + main.consumes = ["dialog.question"]; + main.provides = ["dialog.fileremove"]; + return main; + + function main(options, imports, register) { + var question = imports["dialog.question"].show; + + /***** Initialization *****/ + + /***** Methods *****/ + + function show(files, onremove) { + if (files.confirmed === undefined) + files.confirmed = false; + + if (files.confirmed) + return true; + + function confirm(file) { + var name = file.label; + var type = file.isFolder ? "folder" : "file"; + question( + "Confirm Remove", + "You are about to remove the " + (type || "item") + " " + name, + "Do you want continue? (This change cannot be undone)", + function(all){ // Yes + files.confirmed = true; + onremove(file); + if (all) { + files.forEach(function (file) { + onremove(file); + }); + } + files.confirmed = false; + + if (!all && files.length > 0) + confirm(files.shift()); + }, + function(all, cancel){ // No + if (!all && files.length > 0) + confirm(files.shift()); + }, + { all: files.length > 0 } + ); + } + confirm(files.shift()); + + return false; + }; + + register("", { + "dialog.fileremove": { + show: show + } + }); + } +}); \ No newline at end of file diff --git a/plugins/c9.ide.dialog.common/notification.css b/plugins/c9.ide.dialog.common/notification.css new file mode 100644 index 00000000..6a3d3c31 --- /dev/null +++ b/plugins/c9.ide.dialog.common/notification.css @@ -0,0 +1,21 @@ +.notificationlabel{ + .font-smoothing(true); + position: relative; +} +.notificationlabel u.close{ + .image-2x(@notify-close-image, @notify-close-image-width, @notify-close-image-height); + background-position: @notify-close-image-idle; + width: 14px; + height: 14px; + position: absolute; + right: 8px; + top: 8px; + cursor: pointer; + z-index: 10000; +} +.notificationlabel u.close:hover{ + background-position: @notify-close-image-hover; +} +.notificationlabel u.close:active{ + background-position: @notify-close-image-active; +} \ No newline at end of file diff --git a/plugins/c9.ide.dialog.common/notification.js b/plugins/c9.ide.dialog.common/notification.js new file mode 100644 index 00000000..753d1550 --- /dev/null +++ b/plugins/c9.ide.dialog.common/notification.js @@ -0,0 +1,158 @@ +define(function(require, exports, module) { + "use strict"; + + main.consumes = ["Plugin", "ui", "layout", "anims"]; + main.provides = ["dialog.notification"]; + return main; + + function main(options, imports, register) { + var Plugin = imports.Plugin; + var ui = imports.ui; + var layout = imports.layout; + var anims = imports.anims; + + /***** Initialization *****/ + + var plugin = new Plugin("Ajax.org", main.consumes); + + var count = 0; + var HEIGHT = 30; + var container, logo; + + var loaded = false; + function load() { + if (loaded) return false; + loaded = true; + + ui.insertCss(require("text!./notification.css"), + options.staticPrefix, plugin); + + container = layout.findParent(plugin); + logo = document.querySelector(".c9-mbar-round"); + } + + /***** Methods *****/ + + function show(html, showCloseButton, timeout) { + var hide, timer; + + count++; + + // Error message container + var div = container.$int.appendChild(document.createElement("div")); + + if (showCloseButton) { + div.appendChild(document.createElement("U")).className = "close"; + div.className = "notificationlabel"; + div.addEventListener("mouseup", function(e) { + if (e.target.tagName == "U") + hide(); + }); + } + + ui.insertHtml(div, html, plugin); + container.show(); + div.style.display = "none"; + + function show(){ + div.style.display = "block"; + var toHeight = calculateHeight(); + container.setHeight(toHeight - div.offsetHeight); + + div.style.zIndex = 10000 - count; + div.style.marginTop = (-1 * div.offsetHeight) + "px"; + + anims.animate(div, { + marginTop: 0, + duration: 0.2, + timingFunction: "linear" + }); + anims.animate(logo, { + top: toHeight + "px", + duration: 0.2, + timingFunction: "linear" + }, function(){}); + anims.animateSplitBoxNode(container, { + height: toHeight + "px", + duration: 0.22, + timingFunction: "linear" + }, function(){}); + } + + if (timeout) + timer = setTimeout(show, timeout); + else + show(); + + hide = _hide.bind(null, div, timer); + hide.hasClosed = function(){ return !div.parentNode; }; + + return hide; + } + + function _hide(div, timer, callback) { + clearTimeout(timer); + + if (!div || !div.parentNode) + return callback && callback(); + + var toHeight = calculateHeight() - div.scrollHeight; + anims.animate(div, { + marginTop: (-1 * div.offsetHeight) + "px", + duration: 0.2, + timingFunction: "linear" + }); + anims.animate(logo, { + top: toHeight + "px", + duration: 0.2, + timingFunction: "linear" + }, function(){}); + anims.animateSplitBoxNode(container, { + height: toHeight + "px", + duration: 0.2, + timingFunction: "linear" + }, function(){ + div.parentNode.removeChild(div); + callback && callback(); + + if (!count) + container.hide(); + }); + } + + function calculateHeight(){ + var nodes = container.$ext.childNodes; + var total = 0; + for (var i = 0; i < nodes.length; i++) { + if (nodes[i].nodeType == 1) + total += nodes[i].scrollHeight; + } + return total; + } + + /***** Lifecycle *****/ + + plugin.on("load", function() { + load(); + }); + + /***** Register and define API *****/ + + /** + * Show notifications to the user + * + * This plugin provides a way to display error messages to the user. + * + * @singleton + **/ + plugin.freezePublicAPI({ + /** + * Displays an error message in the main error reporting UI. + * @param {String} message The message to display. + */ + show: show + }); + + register(null, { "dialog.notification" : plugin }); + } +}); \ No newline at end of file diff --git a/plugins/c9.ide.dialog.common/question.js b/plugins/c9.ide.dialog.common/question.js new file mode 100644 index 00000000..3c9686a0 --- /dev/null +++ b/plugins/c9.ide.dialog.common/question.js @@ -0,0 +1,132 @@ +define(function(require, module, exports) { + main.consumes = ["Dialog", "util"]; + main.provides = ["dialog.question"]; + return main; + + function main(options, imports, register) { + var Dialog = imports.Dialog; + var util = imports.util; + + /***** Initialization *****/ + + var plugin = new Dialog("Ajax.org", main.consumes, { + name: "dialog.question", + allowClose: false, + modal: true, + elements: [ + { type: "checkbox", id: "dontask", caption: "Don't ask again", visible: false }, + { type: "button", id: "yestoall", caption: "Yes to All", color: "green", visible: false }, + { type: "button", id: "notoall", caption: "No to All", color: "red", "default": true, visible: false }, + { type: "filler" }, + { type: "button", id: "yes", caption: "Yes", color: "green", "default": true, hotkey: "Y" }, + { type: "button", id: "no", caption: "No", color: "red", hotkey: "N" }, + { type: "button", id: "cancel", caption: "Cancel", visible: false, hotkey: "ESC" } + ] + }); + + /***** Methods *****/ + + function show(title, header, msg, onYes, onNo, options) { + if (!options) + options = {}; + + return plugin.queue(function(){ + var all = options.all; + var cancel = options.cancel; + var showDontAsk = options.showDontAsk; + var metadata = options.metadata; + + plugin.title = title; + plugin.heading = util.escapeXml(header); + plugin.body = util.escapeXml(msg).replace(/\n/g, "
      "); + + plugin.allowClose = cancel; + + var gotYes = false; + plugin.once("hide", function(){ + !gotYes && cancel && onNo(false, true, metadata); + }); + + plugin.update([ + { id: "cancel", visible: cancel, onclick: function(){ plugin.hide(); } }, + { id: "dontask", visible: showDontAsk }, + { id: "yestoall", visible: all, onclick: function(){ + gotYes = true; + plugin.hide(); + onYes(true, metadata); + }}, + { id: "notoall", visible: all, onclick: function(){ + plugin.hide(); + onNo(true, false, metadata); + }}, + { id: "yes", onclick: function(){ + gotYes = true; + plugin.hide(); + onYes(false, metadata); + }}, + { id: "no", onclick: function(){ + plugin.hide(); + onNo(false, false, metadata); + }} + ]); + }, options.queue === false); + } + + /***** Register *****/ + + /** + * + */ + plugin.freezePublicAPI({ + /** + * + */ + get all(){ return undefined }, + set all(value) { + plugin.update([ + { id: "yestoall", visible: value}, + { id: "notoall", visible: value} + ]); + }, + + /** + * + */ + get cancel(){ return undefined }, + set cancel(value) { + plugin.allowClose = value; + plugin.update([ + { id: "cancel", visible: value } + ]); + }, + + /** + * + */ + get showDontAsk(){ + return plugin.getElement("dontask").visible; + }, + set showDontAsk(value) { + plugin.update([ + { id: "dontask", visible: value } + ]); + }, + + /** + * @readonly + */ + get dontAsk(){ + return plugin.getElement("dontask").value; + }, + + /** + * + */ + show: show + }); + + register("", { + "dialog.question": plugin + }); + } +}); \ No newline at end of file diff --git a/plugins/c9.ide.dialog.file/filesave.css b/plugins/c9.ide.dialog.file/filesave.css new file mode 100644 index 00000000..20957fac --- /dev/null +++ b/plugins/c9.ide.dialog.file/filesave.css @@ -0,0 +1,43 @@ +.tb_textbox .directory { + padding-left: 7px; + font-size: 11px; + color: #bababa; + text-shadow: rgba(255, 255, 255, 1) 0px 1px 0px; +} + +.trDgLike .item-fix:nth-child(4n-1) { + background-color: #f1f0f1; +} +.trDgLike .item-fix:nth-child(4n+1) { + background-color: #fefdfe; +} + +.trDgLike .item-fix.root { + background-color: #fefdfe; +} + +.dgLikeContaier { + background-color: rgba(255, 255, 255, 0.04); + border: @filesave-tree-border; + box-shadow: 1px 1px rgba(255,255,255,0.06), inset 1px 1px rgba(255,255,255,0.06); + color: #333333; + cursor: default; + font-family: Tahoma, Arial; + font-size: 8pt; + overflow: hidden; + position: relative; + height: 210px; + border-radius:3px; +} + +.hidefiles .file_item { + display: none; +} + +.filesave-inner-padding{ + position: absolute; + left: @filesave-inner-padding-left; + top: @filesave-inner-padding-top; + right: @filesave-inner-padding-right; + bottom: @filesave-inner-padding-bottom; +} \ No newline at end of file diff --git a/plugins/c9.ide.dialog.file/filesave.js b/plugins/c9.ide.dialog.file/filesave.js new file mode 100644 index 00000000..206f3c32 --- /dev/null +++ b/plugins/c9.ide.dialog.file/filesave.js @@ -0,0 +1,374 @@ +define(function(require, module, exports) { + main.consumes = [ + "Plugin", "ui", "fs", "dialog.alert", "fs.cache", "util", "Dialog", "tree" + ]; + main.provides = ["dialog.filesave"]; + return main; + + function main(options, imports, register) { + var Plugin = imports.Plugin; + var Dialog = imports.Dialog; + var util = imports.util; + var ui = imports.ui; + var fs = imports.fs; + var fsCache = imports["fs.cache"]; + var alert = imports["dialog.alert"].show; + var fileTree = imports.tree; + + var Tree = require("ace_tree/tree"); + var TreeData = require("ace_tree/data_provider_mirror"); + var TreeEditor = require("ace_tree/edit"); + + var join = require("path").join; + var basename = require("path").basename; + var dirname = require("path").dirname; + + /***** Initialization *****/ + + var plugin = new Plugin("Ajax.org", main.consumes); + var emit = plugin.getEmitter(); + + var dialog, container, btnChoose, btnCancel, btnCreateFolder; + var tree, cbShowFiles, txtFilename, txtDirectory, boxFilename; + var showFiles = true; + var hideFileInput = true; + + var loaded; + function load(){ + if (loaded) return; + loaded = true; + } + + var drawn = false; + function draw(htmlNode) { + if (drawn) return; + drawn = true; + + // Markup + ui.insertMarkup(null, require("text!./filesave.xml"), plugin); + + // CSS + ui.insertCss(require("text!./filesave.css"), plugin); + + dialog = plugin.getElement("window"); + container = plugin.getElement("container"); + btnChoose = plugin.getElement("btnChoose"); + btnCancel = plugin.getElement("btnCancel"); + btnCreateFolder = plugin.getElement("btnCreateFolder"); + cbShowFiles = plugin.getElement("cbShowFiles"); + txtFilename = plugin.getElement("txtFilename"); + txtDirectory = plugin.getElement("txtDirectory"); + boxFilename = plugin.getElement("boxFilename"); + + btnCreateFolder.on("click", function(){ + fileTree.createFolder(null, null, function(err, newpath) { + expandAndSelect(newpath); + }, tree); + }); + + txtFilename.on("keyup", function(e) { + if (e.keyCode == 13) { + btnChoose.dispatchEvent("click"); + } + }); + + txtDirectory.on("keyup", function(e) { + if (e.keyCode == 13) { + expandAndSelect(txtDirectory.value); + } + }); + + // Insert File Tree + // @todo abstract this from the file tree plugin + tree = new Tree(container.$int); + tree.renderer.setScrollMargin(10, 10); + tree.renderer.setTheme({cssClass: "filetree"}); + tree.edit = new TreeEditor(tree); + + // Rename + tree.on("beforeRename", function(e) { + return fileTree.tree._emit("beforeRename", e); + }); + tree.on("rename", function(e) { + return fileTree.tree._emit("rename", e); + }); + + // Remove + tree.on("delete", function(e) { + var selection = tree.selection.getSelectedNodes(); + fileTree.remove(selection); + }); + + tree.renderer.on("scrollbarVisibilityChanged", updateScrollBarSize); + tree.renderer.on("resize", updateScrollBarSize); + function updateScrollBarSize() { + var w = tree.renderer.scrollBarV.getWidth(); + tree.renderer.scroller.style.right = Math.max(w, 10) + "px"; + } + + tree.on("userSelect", function(e) { + var selected = tree.selection.getCursor(); + if (selected) { + plugin.directory = selected.isFolder + ? selected.path : dirname(selected.path); + if (!selected.isFolder) + plugin.filename = basename(selected.path); + } + }); + + tree.on("afterChoose", function(e) { + + }); + + dialog.on("prop.visible", function(e) { + updateTreeModel(e.value); + if (e.value) emit("show"); + else emit("hide"); + }); + + dialog.on("afterresize", function() { + tree.resize(); + }); + + emit.sticky("draw"); + } + + /***** Method *****/ + + function updateTreeModel(enable) { + if (enable) { + var model = new TreeData(); + + var height = parseInt(ui.getStyleRule(".filetree .tree-row", "height"), 10); + model.rowHeightInner = height; + model.rowHeight = height + 1; + model.indent = 12; + model.getIconHTML = getIconHTML; + + model.setRoot(fsCache.model.root); + model.source = fsCache.model; + Object.getOwnPropertyNames(model.source).forEach(function(n) { + if (typeof model.source[n] == "function") + model[n] = model.source[n]; + }); + model.startUpdate = function() {}; + model.endUpdate = function(node) { + if (model.isOpen(node)) { + model.close(node); + model.open(node); + } + }; + updateFilter(model); + tree.setDataProvider(model); + model.getChildren(model.root).forEach(function(node) { + if (node.isRoot) + model.expand(node); + }); + + var path = plugin.directory + (showFiles && !hideFileInput + ? "/" + plugin.filename + : ""); + expandAndSelect(path, model); + + + fsCache.model.on("startUpdate", tree.provider.startUpdate); + fsCache.model.on("endUpdate", tree.provider.endUpdate); + } else { + fsCache.model.off("startUpdate", tree.provider.startUpdate); + fsCache.model.off("endUpdate", tree.provider.endUpdate); + tree.setDataProvider(null); + } + } + function expandAndSelect(path, model) { + fsCache.loadNodes(path, function(e) { + if (model && tree.provider != model) + return; + if (e.node) { + tree.reveal(e.node); + if (e.node.isFolder) + tree.provider.expand(e.node); + } + if (e.complete) { + setTimeout(function() { + tree.renderer.scrollCaretIntoView(null, 0.5); + }, 200); + } + }); + } + function getIconHTML(node) { + var icon = node.map ? "folder" : util.getFileIcon(node.label); + if (node.status === "loading") icon = "loading"; + return ""; + } + + function updateFilter(model) { + model && model.setFilter(showFiles ? null : function(node) { + return node.isRoot || node.isFolder; + }); + } + + function init(title, path, onChoose, onCancel, options) { + var createFolderButton = (options && options.createFolderButton) !== false; + var showFilesCheckbox = (options && options.showFilesCheckbox) !== false; + var hideFileInput = options && options.hideFileInput; + + plugin.title = title || "Save As"; + plugin.filename = path ? basename(path) : ""; + plugin.directory = path ? (hideFileInput ? path : dirname(path)) : "/"; + btnChoose.setAttribute("caption", options && options.chooseCaption || "Save"); + + var choosen = false; + + btnChoose.onclick = function() { + var path = join(plugin.directory, hideFileInput ? "" : plugin.filename); + + if (!path) + return alert("Invalid Path", "Invalid Path", + "Please choose a correct path and filename"); + + fs.exists(path, function(exists, stat) { + var isDirectory = stat && ( + /(directory|folder)$/.test(stat.mime) || stat.link && /(directory|folder)$/.test(stat.linkStat.mime)); + if (isDirectory && !hideFileInput) { + // @todo + // var node = fsCache.findNode(path); + // trSaveAs.select(node); + // if (trSaveAs.selected == node) { + // txtSaveAs.setValue(""); + // expand(node); + // } + return; + } + + choosen = true; + onChoose(path, stat || false, function() { + dialog.hide(); + }); + }); + }; + + btnCancel.onclick = function() { + dialog.hide(); + }; + + btnCreateFolder.setAttribute("visible", createFolderButton); + cbShowFiles.setAttribute("visible", showFilesCheckbox); + boxFilename.setAttribute("visible", !hideFileInput); + + + cbShowFiles.setAttribute("checked", true); + showFiles = true; + cbShowFiles.on("prop.value", function() { + showFiles = cbShowFiles.checked; + updateFilter(tree.provider); + }); + // @todo options.hideTree + // @todo options.showFiles + // @todo options.showHiddenFiles + + plugin.once("hide", function() { + if (!choosen && onCancel) + onCancel(); + }); + } + + function show(title, path, onChoose, onCancel, options) { + if (!plugin.loaded) + return; + + draw(); + + init(title, path, onChoose, onCancel, options); + + dialog.show(); + } + + function hide(){ + dialog && dialog.hide(); + } + + /***** Register and define API *****/ + + /** + * + */ + plugin.freezePublicAPI({ + /** + * The APF element that is the parent to all form elements. + * @property {AMLElement} aml + * @private + * @readonly + */ + get aml(){ return dialog; }, + + /** + * + */ + get tree(){ return tree; }, + + /** + * + */ + get title(){ }, + set title(value) { + if (drawn) + dialog.setAttribute("title", value); + }, + /** + * + */ + get filename(){ return txtFilename.value; }, + set filename(value) { + if (drawn) + txtFilename.setAttribute("value", value); + }, + /** + * + */ + get directory(){ return txtDirectory.value; }, + set directory(value) { + if (drawn) + txtDirectory.setAttribute("value", value); + }, + + _events: [ + /** + * Fires when the form is drawn. + * @event draw + */ + "draw", + /** + * Fires when the form becomes visible. This happens when + * it's attached to an HTML element using the {@link #attachTo} + * method, or by calling the {@link #method-show} method. + * @event show + */ + "show", + /** + * Fires when the form becomes hidden. This happens when + * it's detached from an HTML element using the {@link #detach} + * method, or by calling the {@link #method-hide} method. + * @event hide + */ + "hide" + ], + + /** + * Show the form. This requires the form to be + * {@link #attachTo attached} to an HTML element. + * @fires show + */ + show: show, + + /** + * Hide the form. + * @fires hide + */ + hide: hide + }); + + register("", { + "dialog.filesave" : plugin + }); + } +}); \ No newline at end of file diff --git a/plugins/c9.ide.dialog.file/filesave.xml b/plugins/c9.ide.dialog.file/filesave.xml new file mode 100644 index 00000000..aca5d66f --- /dev/null +++ b/plugins/c9.ide.dialog.file/filesave.xml @@ -0,0 +1,87 @@ + + + +
      + + Filename: + + +
      + +
      + + +
      + + + Folder: + + + + + + + Create folder + + + Show files in tree + + + + + +
      +
      +
      \ No newline at end of file diff --git a/plugins/c9.ide.dialog.login/login.css b/plugins/c9.ide.dialog.login/login.css new file mode 100644 index 00000000..44bd0dd3 --- /dev/null +++ b/plugins/c9.ide.dialog.login/login.css @@ -0,0 +1,10 @@ +.bk-window.login .bg-bk-content{ + background-color : #303130; + + background-image: -webkit-linear-gradient(top,rgba(0, 0, 0, 0.29) 0%, rgba(0, 0, 0, 0.11) 8px, rgba(0, 0, 0, 0.01) 13px, transparent 15px); + background-image: -moz-linear-gradient(top,rgba(0, 0, 0, 0.29) 0%, rgba(0, 0, 0, 0.11) 8px, rgba(0, 0, 0, 0.01) 13px, transparent 15px); + background-image: linear-gradient(top,rgba(0, 0, 0, 0.29) 0%, rgba(0, 0, 0, 0.11) 8px, rgba(0, 0, 0, 0.01) 13px, transparent 15px); + + border-top : 1px solid rgba(255,255,255,0.06); + top: 34px; +} \ No newline at end of file diff --git a/plugins/c9.ide.dialog.login/login.js b/plugins/c9.ide.dialog.login/login.js new file mode 100644 index 00000000..8f2e399f --- /dev/null +++ b/plugins/c9.ide.dialog.login/login.js @@ -0,0 +1,143 @@ +define(function(require, module, exports) { + main.consumes = [ + "Plugin", "ui", "util", "Dialog" + ]; + main.provides = ["dialog.login"]; + return main; + + function main(options, imports, register) { + var Plugin = imports.Plugin; + var plugin = new Plugin("Ajax.org", main.consumes); + var ui = imports.ui; + var util = imports.util; + + var emit = plugin.getEmitter(); + + var dialog, btnChoose, btnCancel; + var txtUsername, txtPassword, lblExplanation; + + var loaded; + function load() { + if (loaded) return; + loaded = true; + } + + var drawn = false; + function draw(htmlNode) { + if (drawn) return; + drawn = true; + + // Markup + ui.insertMarkup(null, require("text!./login.xml"), plugin); + + // CSS + ui.insertCss(require("text!./login.css"), plugin); + + dialog = plugin.getElement("window"); + btnChoose = plugin.getElement("btnChoose"); + btnCancel = plugin.getElement("btnCancel"); + txtUsername = plugin.getElement("txtUsername"); + txtPassword = plugin.getElement("txtPassword"); + lblExplanation = plugin.getElement("lblExplanation"); + + dialog.on("prop.visible", function(e) { + if (e.value) emit("show"); + else emit("hide"); + }); + + emit.sticky("draw"); + } + + function show(title, description, onChoose, onCancel, options) { + draw(); + + lblExplanation.$ext.innerHTML = util.escapeXml(description); + plugin.title = title || "Please Sign In"; + + var chosen; + btnChoose.onclick = function() { + chosen = true; + + dialog.disable(); + + onChoose(txtUsername.value, txtPassword.value, function(success){ + dialog.enable(); + + if (success) + plugin.hide(); + }); + }; + btnCancel.onclick = function() { + plugin.hide(); + }; + + plugin.once("hide", function() { + if (!chosen && onCancel) + onCancel(); + }); + + // Show UI + dialog.show(); + } + + function hide() { + dialog && dialog.hide(); + } + + /***** Register and define API *****/ + + /** + * + */ + plugin.freezePublicAPI({ + + /** + * + */ + get title() { }, + set title(value) { + if (drawn) + dialog.setAttribute("title", value); + }, + + _events: [ + /** + * Fires when the form is drawn. + * @event draw + */ + "draw", + /** + * Fires when the form becomes visible. This happens when + * it's attached to an HTML element using the {@link #attachTo} + * method, or by calling the {@link #method-show} method. + * @event show + */ + "show", + /** + * Fires when the form becomes hidden. This happens when + * it's detached from an HTML element using the {@link #detach} + * method, or by calling the {@link #method-hide} method. + * @event hide + */ + "hide" + ], + + /** + * Show the form. This requires the form to be + * {@link #attachTo attached} to an HTML element. + * @fires show + */ + show: show, + + /** + * Hide the form. + * @fires hide + */ + hide: hide + }); + + register("", { + "dialog.login" : plugin + }); + } +}); \ No newline at end of file diff --git a/plugins/c9.ide.dialog.login/login.xml b/plugins/c9.ide.dialog.login/login.xml new file mode 100644 index 00000000..82b954e8 --- /dev/null +++ b/plugins/c9.ide.dialog.login/login.xml @@ -0,0 +1,64 @@ + + + \ No newline at end of file diff --git a/plugins/c9.ide.dialog/dialog.js b/plugins/c9.ide.dialog/dialog.js new file mode 100644 index 00000000..dca0cb9b --- /dev/null +++ b/plugins/c9.ide.dialog/dialog.js @@ -0,0 +1,528 @@ +define(function(require, module, exports) { + main.consumes = ["Plugin", "ui", "commands", "focusManager"]; + main.provides = ["Dialog"]; + return main; + + function main(options, imports, register) { + var Plugin = imports.Plugin; + var ui = imports.ui; + var commands = imports.commands; + var focusManager = imports.focusManager; + + var EventEmitter = require("events").EventEmitter; + + Dialog.queue = []; + Dialog.addToQueue = function(dialog, fn, force) { + var emitter = new EventEmitter(); + emitter.visible = undefined; + + function queueItem(){ + fn(function(){ + Dialog.queue.splice(Dialog.queue.indexOf(queueItem), 1); + + emitter.emit("hide"); + emitter.visible = 0; + + if (Dialog.queue.length) + Dialog.queue[0](); + else { + // Timeout to prevent the editor + // from getting the key stroke + setTimeout(function(){ + // Return last focussed element + focusManager.focus(Dialog.lastFocus); + delete Dialog.lastFocus; + }); + } + }); + + if (emitter.emit("show") === false) + dialog.hide(); + else + emitter.visible = 1; + } + + if (force) + queueItem(); + else { + Dialog.queue.push(queueItem); + + // Save last focussed element + if (!Dialog.lastFocus) + Dialog.lastFocus = focusManager.activeElement; + + // Timeout to make sure events can be set on the emitter. + if (Dialog.queue.length == 1) + setTimeout(Dialog.queue[0]); + } + + return emitter; + }; + + function Dialog(developer, deps, options) { + var plugin = new Plugin(developer, deps.concat(main.consumes)); + var emit = plugin.getEmitter(); + + var name = options.name; + var left = options.left; + var top = options.top; + var width = options.width || 512; + var title = options.title; + var heading = options.heading; + var body = options.body; + var custom = options.custom; + var modal = options.modal; + var zindex = options.zindex; + var allowClose = options.allowClose; + var elements = options.elements; + var resizable = options.resizable || false; + var widths = options.widths || {}; + var count = 0; + + var dialog, buttons, titles; + + var loaded; + function load(){ + if (loaded) return; + loaded = true; + } + + var drawn = false; + function draw(htmlNode) { + if (drawn) return; + drawn = true; + + // Create UI elements + dialog = new ui.modalwindow({ + id: "window", + title: title, + icon: "", + center: "true", + modal: modal, + buttons: allowClose ? "close" : "", + width: width, + zindex: zindex || "", + skin: "bk-window2", + class: "relative" + (options.dark ? " dark" : ""), + childNodes: [ + new ui.vbox({ + id: "titles", + padding: 10, + edge: "15 20 25 20", + }), + new ui.hbox({ + id: "buttons", + class: "dialog-buttons", + pack: "end", + padding: "8", + height: "46", + edge: "11 10 10" + }) + ] + }); + apf.document.documentElement.appendChild(dialog); + plugin.addElement(dialog); + + dialog.on("prop.visible", function(e) { + if (e.value) emit("show"); + else emit("hide"); + }); + dialog.on("keydown", function(e) { + if (allowClose && e.keyCode == 27) + dialog.hide(); + }); + + commands.addCommand({ + name: plugin.name, + bindKey: { mac: "ESC", win: "ESC" }, + group: "ignore", + isAvailable: function(){ + return dialog.visible; + }, + exec: function(){ + dialog.dispatchEvent("keydown", { keyCode : 27 }); + } + }, plugin); + + titles = plugin.getElement("titles"); + buttons = plugin.getElement("buttons"); + + // Create dynamic UI elements + elements.forEach(function(item) { + createItem(null, null, item); + }); + + emit.sticky("draw", { + aml: titles, + html: titles.$int + }); + + if (resizable) + plugin.resizable = resizable; + } + + /***** Method *****/ + + function queue(implementation, force) { + if (!plugin.loaded) + return; + + return Dialog.addToQueue(dialog, function(next) { + // Draw everything if needed + draw(); + + // Call the show implementation + implementation(); + + // Update UI + if (!custom) { + titles.$int.innerHTML = "

      " + + heading + "

      " + + body + "
      "; + } + + // allow selecting dialog message text + titles.textselect = !custom; + + // When the dialog closes the next dialog can appear + plugin.once("hide", next); + + // Show UI + dialog.show(); + + // Focus UI + focusManager.focus(dialog, true); + }, force); + } + + function hide(){ + dialog && dialog.hide(); + } + + // @todo this looks very similar to forms.js. Perhaps able to merge? + function update(items) { + items.forEach(function(item) { + if (!drawn) { + elements.every(function(el) { + if (el.id == item.id) { + for (var prop in item) { + el[prop] = item[prop]; + } + return false; + } + return true; + }); + return; + } + + var el = plugin.getElement(item.id); + switch(el.type) { + case "dropdown": + var dropdown = el.lastChild; + + var data = item.items.map(function(item) { + return ""; + }).join(""); + if (data) + dropdown.$model.load("" + data + ""); + if (item.value) + dropdown.setAttribute("value", item.value); + break; + default: + if ("value" in item) + el.setAttribute('value', item.value); + if ("onclick" in item) + el.onclick = item.onclick; + if ("visible" in item) + el.setAttribute("visible", item.visible) + if ("zindex" in item) + el.setAttribute("zindex", item.zindex) + break; + } + }) + } + + // @todo this looks very similar to forms.js. Perhaps able to merge? + function createItem(heading, name, options) { + var position = options.position || count++; + var node; + + switch(options.type) { + case "checkbox": + node = new ui.checkbox({ + label: options.caption, + value: options.defaultValue || "", + values: options.values, + skin: "checkbox_black", + }); + break; + case "dropdown": + var model = options.model || new ui.model(); + var data = options.items && options.items.map(function(item) { + return ""; + }).join(""); + if (data) model.load("" + data + ""); + + node = new ui.dropdown({ + model: model, + width: options.width || widths.dropdown, + skin: "black_dropdown", + value: options.defaultValue || "", + each: options.each || "[item]", + caption: options.caption || "[text()]", + eachvalue: options.eachvalue || "[@value]", + "empty-message" : options["empty-message"] + }); + break; + case "textbox": + node = new ui.textbox({ + skin: "searchbox", + "initial-message": options.message || "", + width: options.width || widths.textbox, + value: options.defaultValue || "", + realtime: options.realtime || 1 + }); + break; + case "button": + node = new ui.button({ + skin: "btn-default-css3", + "class" : options.color ? "btn-" + options.color : "", + margin: options.margin, + caption: options.caption || "", + submenu: options.submenu && options.submenu.aml + || options.submenu || "", + width: options.width || widths.button, + "default" : options["default"] ? "1" : "" + }); + break; + case "label": + node = new ui.label({ + caption: options.caption, + style: options.style, + width: options.width || "" + }); + break; + case "image": + node = new ui.img({ + skin: "simpleimg", + src: options.src, + margin: options.margin, + width: options.width, + height: options.height + }); + break; + case "divider": + node = new ui.divider({ + skin: "c9-divider-hor", + margin: "5 0 5 0" + }); + break; + case "filler": + node = new ui.filler(); + break; + case "custom": + node = options.node; + break; + default: + throw new Error("Unknown form element type: " + + options.type); + } + + if (options.id || options.name) + node.setAttribute("id", options.id || options.name); + if (options.visible !== undefined) + node.setAttribute("visible", options.visible); + if (options.onclick) + node.onclick = options.onclick; + if (options.hotkey) { + dialog.on("keydown", function(e) { + if (options.hotkey == "ESC" && e.keyCode == 27 + || String.fromCharCode(e.keyCode) == options.hotkey) + node.dispatchEvent("click"); + }); + } + + ui.insertByIndex(buttons, node, position, plugin); + plugin.addElement(node); + + return node; + } + + /***** Register and define API *****/ + + plugin.freezePublicAPI.baseclass(); + + /** + * Dialog Builder for Cloud9. Use this class to create dialogs. + * + * Example: + * + * var dialog = new Dialog("Developer Name", main.consumes, { + * allowClose : true, + * modal : false, + * elements : [ + * { type: "checkbox", caption: "Apply to all open files" }, + * { type: "filler" }, + * { type: "button", id: "keepmine", color: "blue", caption: "Keep Mine" }, + * { type: "button", id: "useremote", color: "blue", caption: "User Remote" }, + * { type: "button", id: "mergeboth", color: "green", caption: "Merge Both", "default": true } + * ] + * }); + */ + /** + * @constructor + * Creates a new Dialog instance based on an abstract definition of + * the dialog elements. + * + * @param {Object} [options] The definition of the dialog. + */ + plugin.freezePublicAPI({ + /** + * The APF element that is the parent to all form elements. + * @property {AMLElement} aml + * @private + * @readonly + */ + get aml(){ return dialog; }, + + /** + * @property {Number} width + */ + get width(){ return width; }, + set width(v) { + width = v; + dialog && dialog.setAttribute("width", width); + }, + /** + * @property {Number} left + */ + get left(){ return left; }, + set left(v) { + left = v; + dialog && dialog.setAttribute("left", left); + }, + /** + * @property {Number} top + */ + get top(){ return top; }, + set top(v) { + top = v; + dialog && dialog.setAttribute("top", top); + }, + /** + * @property {Number} title + */ + get title(){ return title; }, + set title(v) { + title = v; + dialog && dialog.setAttribute("title", title); + }, + /** + * @property {Boolean} resizable + */ + get resizable(){ return resizable; }, + set resizable(v) { + if (v === resizable) return; + resizable = v; + if (!dialog) return; + + dialog.setAttribute("height", v ? dialog.getHeight() : ""); + dialog.setAttribute("width", v ? dialog.getWidth() : ""); + dialog.setAttribute("class", v ? "" : "relative"); + titles.setAttribute("anchors", v ? "0 0 46 0" : ""); + buttons.setAttribute("bottom", v ? "0" : ""); + buttons.setAttribute("left", v ? "0" : ""); + buttons.setAttribute("right", v ? "0" : ""); + dialog.setAttribute("resizable", v); + }, + /** + * @property {Number} heading + */ + get heading(){ return heading; }, + set heading(v) { + heading = v; + }, + /** + * @property {Number} body + */ + get body(){ return body; }, + set body(v) { + body = v; + }, + /** + * @property {Boolean} modal + * @readonly + */ + get modal(){ return modal; }, + /** + * @property {Boolean} allowClose + */ + get allowClose(){ return allowClose; }, + set allowClose(v) { + allowClose = v; + dialog && dialog.setAttribute("buttons", v ? "close" : ""); + }, + + _events: [ + /** + * Fires when the form is drawn. + * @event draw + */ + "draw", + /** + * Fires when the form becomes visible. This happens when + * it's attached to an HTML element using the {@link #attachTo} + * method, or by calling the {@link #method-show} method. + * @event show + */ + "show", + /** + * Fires when the form becomes hidden. This happens when + * it's detached from an HTML element using the {@link #detach} + * method, or by calling the {@link #method-hide} method. + * @event hide + */ + "hide" + ], + + /** + * Updates form elements with new values. This method currently + * only supports updating the items of a dropdown element. + * + * Example: + * + * dialog.update([ + * { id: "keepmine", onclick: function(){} }, + * { id: "useremote", onclick: function(){} }, + * { id: "mergeboth", onclick: function(){} } + * ]); + * + * @param {Array} items + */ + update: update, + + /** + * Show the dialog when no other dialogs are there. + * @param {Function} callback + * @fires show + */ + queue: queue, + + /** + * Hide the dialog. + * @fires hide + */ + hide: hide + }); + + plugin.load(name, "dialog"); + + return plugin; + } + + register("", { + Dialog: Dialog + }); + } +}); \ No newline at end of file diff --git a/plugins/c9.ide.editors/document.js b/plugins/c9.ide.editors/document.js new file mode 100644 index 00000000..013a49f0 --- /dev/null +++ b/plugins/c9.ide.editors/document.js @@ -0,0 +1,590 @@ +define(function(require, module, exports) { + main.consumes = ["Plugin", "UndoManager", "util"]; + main.provides = ["Document"]; + return main; + + function main(options, imports, register) { + var Plugin = imports.Plugin; + var util = imports.util; + var UndoManager = imports.UndoManager; + + function Document(options) { + var plugin = new Plugin("Ajax.org", main.consumes); + var undoManager; + var emit = plugin.getEmitter(); + + if (options && options.undoManager instanceof Plugin) { + undoManager = options.undoManager; + delete options.undoManager; + } + else + undoManager = new UndoManager(); + + var sessions = {}; + var value = options && options.value || ""; + var changed = false; + var meta = {}; + var hasValue = options && (typeof options.value === "string"); + + var tab, lastState, title, tooltip, editor, recentValue; + + plugin.on("newListener", function(type, listener) { + if (type == "state.set" && lastState) { + listener({ + doc: plugin, + state: lastState + }); + } + }); + + // Listen to changes and detect when the value of the editor + // is different from what is on disk + undoManager.on("change", function(e) { + var c = !undoManager.isAtBookmark(); + if (changed !== c || undoManager.position == -1) { + changed = c; + emit("changed", { changed: c }); + } + }); + + /***** Methods *****/ + + function setBookmarkedValue(value, cleansed) { + if (plugin.value == value) { + undoManager.bookmark(); + return; + } + var state = getState(); + + undoManager.once("change", function(){ + // Bookmark the undo manager + undoManager.bookmark(); + + // Update state + delete state.changed; + delete state.value; + delete state.meta; + state.undoManager = undoManager.getState(); + + if (cleansed && editor && state[editor.type]) + state[editor.type].cleansed = true; + + // Set new state (preserving original state) + if (emit("mergeState") !== false) + setState(state); + }); + + // Record value (which should add an undo stack item) + plugin.value = value; + } + + function getState(filter) { + // Editor is not inited yet, so we keep the state set until + // editor is loaded + var state = !editor && lastState + ? state = util.extend({}, lastState) + : {}; + + state.changed = changed; + state.meta = {}; + state.filter = filter || false; + + for (var prop in meta) { + if (prop.charAt(0) != "$") + state.meta[prop] = meta[prop]; + } + + if (title) + state.title = title; + if (tooltip) + state.tooltip = tooltip; + + if (!filter) { + state.value = plugin.value; + state.undoManager = undoManager.getState(); + } + else { + delete state.value; + delete state.undoManager; + } + + if (editor) + state[editor.type] = editor.getState(plugin, filter); + + var event = { doc: plugin, state: state }; + emit("getState", event); + + lastState = event.state; + + return event.state; + } + + function setState(state) { + if (state.meta) { + for (var prop in meta) { + if (prop.charAt(0) == "$") + state.meta[prop] = meta[prop]; + } + meta = state.meta; + } + if (state.title) plugin.title = state.title; + if (state.tooltip) plugin.tooltip = state.tooltip; + + if (typeof state.value == "string") + plugin.value = state.value; + + if (state.undoManager && !(state.undoManager instanceof Plugin)) + undoManager.setState(state.undoManager); + + if (state.changed && state.changed !== changed) { + changed = state.changed; + emit("changed", { changed: changed }); + } + + if (editor && state[editor.type]) + editor.setState(plugin, state[editor.type]); + + var event = { doc: plugin, state: state }; + emit("setState", event); + + lastState = event.state; + } + + function getSession(type) { + var ed = editor || tab && tab.editor; + if (ed && !type) type = ed.type; + if (!type) return; + + if (sessions[type]) + return sessions[type]; + + var session = sessions[type] = new Plugin(); + session.load(null, "session"); + return session; + } + + function progress(options) { + emit("progress", options); + } + + function clone() { + var state = this.getState(); + state.undoManager = undoManager; + var newdoc = new Document(state); + emit("clone", { doc: newdoc }); + newdoc.meta.cloned = true; + return newdoc; + } + + function canUnload() { + return emit("canUnload"); + } + + /***** Lifecycle *****/ + + plugin.on("unload", function(){ + changed = false; + + // Unload the undo manager + undoManager.unload(); + + // Unload the sessions + for (var type in sessions) + sessions[type].unload(); + }); + + /** + * Session Class for Cloud9 Editors. Each document that is loaded into an + * editor has one session object per editor. A session object is retrieved by + * calling {@link Document#getSession} and is specifically tied to an editor + * type. The session is used to store state and functions on by the editor. + * + * The session relates to other objects as such: + * + * * {@link Pane} - Represent a single pane, housing multiple tabs + * * {@link Tab} - A single tab (button) in a pane + * * {@link Editor} - The editor responsible for displaying the file in the tab + * * {@link Document} - The representation of a file in the tab + * * **Session - The session information of the editor** + * * {@link UndoManager} - The object that manages the undo stack for this document + * + * Panes can live in certain areas of Cloud9. By default these areas are: + * + * * {@link panes} - The main area where editor panes are displayed + * * {@link console} - The console in the bottom of the screen + * + * Tabs are managed by the {@link tabManager}. The default way to + * open a new file in an editor uses the tabManager: + * + * tabManager.openFile("/file.js", true, function(err, tab) { + * var session = tab.document.getSession(); + * var aceSession = session.session; + * }); + * + * Generally the state and functions stored on the session object are private + * to the editor and do not concern other plugins. However one can imagine that + * plugins that work on editors make use of these properties. For instance the + * {@link ace.status.Statusbar} plugin uses the information on the state object from the + * ace editor to display state information like the line number and language + * mode. + * + * When a tab is moved from one pane to another, the document is unloaded from + * one editor and then loaded into another one. It is up to the editor to + * decide how to handle the stored state on the session object. Often the + * editor will remove only some of that state and reuse other state in the + * new editor. For instance, the {@link ace.Ace Ace} editor stores the ace session + * object on the Cloud9 session object. + * It will only do this once and will use the same ace session object in + * different ace editors, throughout the lifetime of the session object. + * + * This example shows how an editor could deal with a session. For more + * information see the source code of the {@link texteditor.TextEditor TextEditor} plugin. + * + * plugin.on("documentLoad", function(e) { + * var doc = e.doc; + * var session = doc.getSession(); + * + * if (!session.id) { + * session.id = Math.random(); + * session.iframe = document.createElement("iframe"); + * } + * + * // Container would be a div created in the {@link Editor#draw} event. + * container.appendChild(session.iframe); + * }); + * + * @class Session + * @extends Plugin + */ + /** + * Document Class for Cloud9 Editors. Each file that is opened + * in an editor has a document object that contains it's value and + * state. + * + * The document relates to other objects as such: + * + * * {@link Pane} - Represent a single pane, housing multiple tabs + * * {@link Tab} - A single tab (button) in a pane + * * {@link Editor} - The editor responsible for displaying the file in the tab + * * **Document - The representation of a file in the tab** + * * {@link Session} - The session information of the editor + * * {@link UndoManager} - The object that manages the undo stack for this document + * + * Panes can live in certain areas of Cloud9. By default these areas are: + * + * * {@link panes} - The main area where editor panes are displayed + * * {@link console} - The console in the bottom of the screen + * + * Tabs are managed by the {@link tabManager}. The default way to + * open a new file in an editor uses the tabManager: + * + * tabManager.openFile("/file.js", true, function(err, tab) { + * var doc = tab.document; + * console.log("The value is: ", doc.value); + * }); + * + * For editors that do not allow a user to edit files + * (e.g. terminal), a document object will still be created. + */ + plugin.freezePublicAPI({ + /** + * the tab this document is attached to + * @property {Tab} tab + */ + get tab(){ return tab; }, + set tab(v){ tab = v; }, + + /** + * the meta information for this document. Use this object to + * store any additional information you'd like to store. If you + * are storing state information that should not be kept between + * reloads of the IDE, prefix the items with a "$" character. + * + * Example: + * + * // This document has a black bird + * var doc = tabs.focussedTab.document; + * doc.meta.blackBird = true; + * + * Example (state is not preserved): + * + * // This document is being processed + * var doc = tabs.focussedTab.document; + * doc.meta.$processing = true; + * + * @property meta + */ + get meta(){ return meta; }, + + /** + * The last state that was set into the document. + * @property lastState + * @private + */ + get lastState(){ return lastState; }, + + /** + * the editor this document is attached to + * @property {Editor} editor + */ + get editor(){ return editor; }, + set editor(v) { + editor = v; + emit("setEditor", {editor: v}); + }, + /** + * The tooltip displayed when hovering over the tab button + * @property {String} tooltip + */ + get tooltip(){ return tooltip; }, + set tooltip(v) { + tooltip = v; + emit("setTooltip", {tooltip: v}); + }, + /** + * The title of the document (displayed as caption of the tab button) + * @property {String} title + */ + get title(){ return title; }, + set title(v) { + title = v; + emit("setTitle", {title: v}); + }, + /** + * Sets or retrieves the serialized value of this document. + * Setting this document will not change the undo stack. Set + * this property only to initialize the document or to reset + * the value of this document. Requesting the value of this + * document will cause it to serialize it's full state. + * @property {String} value + */ + get value(){ + var calculated = emit("getValue", {value: value}); + if (typeof calculated != "string") + calculated = value; + + if (undoManager.isAtBookmark()) + recentValue = calculated; + + return calculated; + }, + set value(v) { + value = recentValue = v; + emit("setValue", {value: v}); + hasValue = true; + }, + /** + * The last serialized value that was either set or retrieved. + * The `recentValue` is only updated during a get when the + * document is saved (undoManager.isAtBookmark() == true). + * @property {String} recentValue + * @readonly + */ + get recentValue(){ return recentValue; }, + /** + * Specifies whether the document on this tab is changed + * @property {Boolean} changed + */ + get changed(){ return changed; }, + /** + * The object managing all the changes to the document + * @property {UndoManager} undoManager + */ + get undoManager(){ return undoManager; }, + + _events: [ + /** + * Fires when the state is retrieved + * @event getState + * @param {Object} e + * @param {Document} e.doc the document for which the state is retrieved + * @param {Object} e.state the state object to extend with information + */ + "getState", + /** + * Fires when the state is set + * @event setState + * @param {Object} e + * @param {Document} e.doc the document for which the state is set + * @param {Object} e.state the state object + */ + "setState", + /** + * Fires when the value of this document is retrieved. + * When implementing an editor, use this event to return + * the current value of this document in the event handler. + * + * Example: + * + * doc.on("getValue", function(e) { + * return "The current value of this editor" + * }, doc.getSession()); + * + * @event getValue + * @param {Object} e + * @param {String} e.value the last cached value + */ + "getValue", + /** + * Fires when the value of this document is set + * When implementing an editor, use this event to set + * the new value of this document in the event handler. + * + * Example: + * + * doc.on("setValue", function(e) { + * myDiv.innerHTML = e.value + * }, doc.getSession()); + * + * @event setValue + * @param {Object} e + * @param {String} e.value the value that is being set + */ + "setValue", + /** + * @ignore + */ + "mergeState", + /** + * Fires when the title of this document is set + * @event setTitle + * @param {Object} e + * @param {String} e.value the title that is being set + */ + "setTitle", + /** + * Fires when the tooltip of this document is set + * @event setTooltip + * @param {Object} e + * @param {String} e.value the tooltip that is being set + */ + "setTooltip", + /** + * Fires when the editor of this document is set + * @event setEditor + * @param {Object} e + * @param {String} e.value the editor that is being set + */ + "setEditor", + /** + * Fires when the change state of the document has changed + * @event changed + * @param {Object} e + * @param {String} e.changed whether the value is changed + */ + "changed", + /** + * Fires when there is progress information related to this + * file. This can be either downloading or uploading. + * @event progress + * @param {Object} e + * @param {Number} e.loaded the number of bytes that have been downloaded/uploaded. + * @param {Number} e.total the total number of bytes for this file. + * @param {Boolean} e.complete whether the download has completed. + * @param {Boolean} e.upload whether this is an upload (instead of a download). + **/ + "progress", + /** + * Fires when this document is cloned + * @event cone + * @param {Object} e + * @param {Document} e.doc the cloned document + **/ + "clone", + /** + * @event canUnload + */ + "canUnload" + ], + + /** + * Retrieves the session object where editors can store state + */ + getSession: getSession, + + /** + * Sets the value of the document and bookmarks it in the + * undoManager. This method also preserves the complete state + * of the editor while transitioning to the new value. + * @param {String} value The new value of the document + */ + setBookmarkedValue: setBookmarkedValue, + + /** + * Retrieves the state of the document. The state object will + * have a section for each editor that it is loaded in. These + * sections have the name of the editor. For instance if the + * editor is ace, the returned object will look something like + * this: + * + * { + * ace : { + * scrollTop : 100, + * ... + * } + * } + * + * @return {Object} + * @return {Boolean} return.changed Specifying whether the document state has been saved. + * @return {Object} return.meta Any metadata set on this document (except items starting with a "$"). + * @return {String} return.title The title displayed in the tab, displaying this document. + * @return {String} return.tooltip The tooltip displayed in the tab, displaying this document + * @return {String} return.value The value of the document. + * @return {Object} return.undoManager The result of {@link UndoManager#getState}. + */ + getState: getState, + + /** + * Sets the state of the document + * @param {Object} state the state of the document. This can also include sections for editors. See {@link Document#method-getState}. + * @param {Boolean} state.changed Specifying whether the document state has been saved. + * @param {Object} state.meta Any metadata set on this document (except items starting with a "$"). + * @param {String} state.title The title displayed in the tab, displaying this document. + * @param {String} state.tooltip The tooltip displayed in the tab, displaying this document + * @param {String} state.value The value of the document. + * @param {Object} state.undoManager The result of {@link UndoManager#getState}. + */ + setState: setState, + + /** + * Set the progress indicator for this document + * @param {Object} options + * @param {Number} options.loaded the number of bytes that have been downloaded/uploaded. + * @param {Number} options.total the total number of bytes for this file. + * @param {Boolean} options.complete whether the download has completed. + * @param {Boolean} options.upload whether this is an upload (instead of a download). + */ + progress: progress, + + /** + * Clones this document + */ + clone: clone, + + /** + * Whether this document is ready to be unloaded + */ + canUnload: canUnload, + + /** + * Returns whether the document has it's value set. + * @return {Boolean} + */ + hasValue: function() { return !!hasValue; }, + }); + + if (options) + setState(options); + + plugin.load(null, "document"); + + return plugin; + } + + /***** Register and define API *****/ + + register(null, { + Document: Document + }); + } +}); diff --git a/plugins/c9.ide.editors/document_test.js b/plugins/c9.ide.editors/document_test.js new file mode 100644 index 00000000..7a101b1f --- /dev/null +++ b/plugins/c9.ide.editors/document_test.js @@ -0,0 +1,100 @@ +/*global describe:false, it:false */ + +"use client"; + +require(["lib/architect/architect", "lib/chai/chai"], function (architect, chai) { + var expect = chai.expect; + + expect.setupArchitectTest([ + "plugins/c9.core/ext", + "plugins/c9.core/util", + "plugins/c9.ide.ui/ui", + "plugins/c9.ide.ui/lib_apf", + "plugins/c9.ide.editors/document", + "plugins/c9.ide.editors/undomanager", + // Mock plugins + { + consumes: [], + provides: ["c9"], + setup: expect.html.mocked + }, + { + consumes: ["Document", "ui"], + provides: [], + setup: main + } + ], architect); + + function main(options, imports, register) { + var Document = imports.Document; + var ui = imports.ui; + + describe('document', function() { + it('should load it\'s state from the constructor', function(done) { + var doc = new Document({ + value: "test" + }) + + expect(doc.value).to.equal("test"); + + done(); + }); + it('should emit value.set when setting the value', function(done) { + var doc = new Document(); + + doc.on("setValue", function(e) { + expect(e.value).to.equal("test"); + done(); + }) + + doc.value = "test"; + }); + it('should emit state.get when calling getState', function(done) { + var doc = new Document(); + + doc.on("getState", function(e) { + expect(e.doc).to.equal(doc); + done(); + }); + + doc.getState(); + }); + it('should allow anyone to set properties on the meta object', function(done) { + var doc = new Document(); + doc.meta.test = 1; + expect(doc.meta.test).to.equal(1); + done(); + }); + it('should not serialize properties of the meta object starting with a $', function(done) { + var doc = new Document(); + doc.meta.test = 1; + doc.meta.$test = 1; + var state = doc.getState(); + + expect(state.meta.test).to.ok + expect(state.meta.$test).to.not.ok + done(); + }); + it('should emit state.set when calling setState', function(done) { + var doc = new Document(); + + doc.on("setState", function(e) { + expect(e.doc).to.equal(doc); + done(); + }); + + doc.setState({}); + }); + it('should allow anyone to get the session object', function(done) { + var doc = new Document(); + doc.editor = { type: "test" }; + var session = doc.getSession(); + session.test = 1 + expect(session.test).to.ok; + done(); + }); + }); + + onload && onload(); + } +}); \ No newline at end of file diff --git a/plugins/c9.ide.editors/editor.js b/plugins/c9.ide.editors/editor.js new file mode 100644 index 00000000..cb7f573f --- /dev/null +++ b/plugins/c9.ide.editors/editor.js @@ -0,0 +1,582 @@ +define(function(require, module, exports) { + main.consumes = ["Plugin", "ui", "clipboard"]; + main.provides = ["Editor"]; + return main; + + function main(options, imports, register) { + var Plugin = imports.Plugin; + var clipboard = imports.clipboard; + var ui = imports.ui; + + function Editor(developer, deps, extensions) { + // Editor extends ext.Plugin + var plugin = new Plugin(developer, deps); + var emit = plugin.getEmitter(); + emit.setMaxListeners(1000); + + var amlTab, type, pane, activeDocument, focussed; + var meta = {}; + + /***** Methods *****/ + + function unloadDocument(doc, options) { + if (!options) options = {}; + options.doc = doc; + emit("documentUnload", options); + doc.getSession().unload(); + } + + function loadDocument(doc) { + // Old Editor + var lastEditor = doc.editor; + if (lastEditor && lastEditor != plugin) { + lastEditor.unloadDocument(doc, { + toEditor: plugin, + fromEditor: lastEditor + }); + } + + activeDocument = doc; + + // Initialize the Document in the Editor + // When the Document unloads the editor should clear all it's state + // When the Editor unloads it should clear all it's state + if (lastEditor != plugin) { + var editor = plugin; + doc.editor = plugin; + + var session = doc.getSession(); + var state = (doc.lastState || false)[editor.type]; // Retrieve last state + bufferEvent.call(plugin, "documentLoad", { + doc: doc, + state: state || {} + }); + + // Check if session was unloaded from the previous editor + if (!session.loaded) + session.load(); + + if (!doc.meta.$unloadEditor) { + doc.meta.$unloadEditor = true; + doc.on("unload", function(){ + doc.editor.unloadDocument(doc); + }); + } + + // editor.on("unload", function(){ + // editor.unloadDocument(doc); + // }, session); + + if (state) + plugin.setState(doc, state); + } + + // Set Document Active in the Editor + bufferEvent.call(plugin, "documentActivate", { doc : doc }); + } + + function bufferEvent(name, event) { + var _self = plugin; + + emit(name, event); + + // Add new listeners + function listenForEvent(curName, listener) { + if (curName == name) + listener(event); + } + plugin.on("newListener", listenForEvent); + plugin.on("documentUnload", function callee(e) { + if (e.doc == event.doc) { + _self.off("newListener", listenForEvent); + _self.off("documentUnload", callee); + } + }); + } + + function getState(doc, filter) { + var state = {}; + + emit("getState", { + doc: doc, + state: state, + filter: filter || false + }); + + return state; + } + + function setState(doc, state) { + emit("setState", { + doc: doc, + state: state || {} + }); + } + + function clear(){ + emit("clear"); + } + + // Clipboard support + function isClipboardAvailable(e) { + return true; + } + + function cut(e) { + emit("cut", e || { clipboardData: clipboard.clipboardData }); + } + + function copy(e) { + emit("copy", e || { clipboardData: clipboard.clipboardData }); + } + + function paste(e) { + emit("paste", e || { clipboardData: clipboard.clipboardData }); + } + + function focus(regain, lost) { + if (!lost && amlTab) + amlTab.focus(); //@todo this might break selenium editor + + emit("focus", { + regain: regain || false, + lost: lost || false + }); + + focussed = lost ? 0 : true; + } + + function blur(){ + emit("blur"); + focussed = false; + } + + function resize(e) { + if (pane && pane.visible) + emit("resize", e || {}); + } + + function isValid(doc, info) { + return emit("validate", {document: doc, info: info}); + } + + function attachTo(tb) { + if (amlTab && !amlTab.$amlDestroyed) + throw new Error("Editors should only be attached once"); + + //Create Tab Element + plugin.addElement( + amlTab = new ui.page({ + id: "editor::" + plugin.type, + mimeTypes: extensions, + visible: false, + realtime: false, + focussable: true, + $focussable: true + }) + ); + + // Remember which pane we belong too + pane = tb; + + // Set the reference to us on the tab element + amlTab.editor = this; + + // Insert our tab into the pane element + pane.aml.insertBefore(amlTab, pane.aml.getPage(0)); + + // Emit draw event + var event = { tab: amlTab, htmlNode: amlTab.$int }; + emit.sticky("draw", event); + + var editor = this; + pane.on("unload", function(){ + editor.unload(); + }); + } + + function drawOn(htmlNode, pg) { + amlTab = pg; + + // Emit draw event + var event = { htmlNode: htmlNode, tab: amlTab }; + emit.sticky("draw", event); + } + + /***** Register and define API *****/ + + plugin.freezePublicAPI.baseclass(); + + /** + * Editor base class for Cloud9 Editors. Each file that is opened + * in Cloud9 has an editor to display it's content. An editor can register + * itself for a set of file extensions. There are also editors that + * don't display files but have a different purpose. For instance + * the {@link terminal.Terminal Terminal} and + * {@link preferences.Preferences Preferences} panel. + * + * The editor relates to other objects as such: + * + * * {@link Pane} - Represent a single pane, housing multiple tabs + * * {@link Tab} - A single tab (button) in a pane + * * **Editor - The editor responsible for displaying the file in the tab** + * * {@link Document} - The representation of a file in the tab + * * {@link Session} - The session information of the editor + * * {@link UndoManager} - The object that manages the undo stack for this document + * + * Panes can live in certain areas of Cloud9. By default these areas are: + * + * * {@link panes} - The main area where editor panes are displayed + * * {@link console} - The console in the bottom of the screen + * + * Tabs are managed by the {@link tabManager}. The default way to + * open a new file in an editor uses the tabManager: + * + * tabManager.openFile("/file.js", true, function(err, tab) { + * var editor = tab.editor; + * editor.focus(); + * }); + * + * The event flow of an editor plugin is as follows: + * + * * {@link #event-documentLoad} - *A document is loaded in the editor* + * * {@link #event-documentActivate} - *A becomes active in the editor* + * * {@link #event-documentUnload} - *The document is unloaded in the editor* + * + * This is in addition to the event flow of the {@link Plugin} base class. + * + * #### User Actions: + * + * * {@link #event-draw} - *The editor is drawn* + * * {@link #event-focus} - *The editor receives focus* + * * {@link #event-blur} - *The editor lost focus* + * * {@link #event-clear} - *The editor's contents is cleared* + * * {@link #event-cut} - *The editor's selection is copied and deleted* + * * {@link #event-copy} - *The editor's selection is copied* + * * {@link #event-paste} - *The editor's selection is deleted and new content is pasted in* + * * {@link #event-resize} - *The editor is resized* + * + * Implementing your own editor takes a new Editor() object rather + * than a new Plugin() object. See the {@link texteditor.TextEditor TextEditor} for a + * full implementation of an editor. Here's a short example: + * + * function TextEditor(){ + * var plugin = new Editor("(Company) Name", main.consumes, ["txt"]); + * var emit = plugin.getEmitter(); + * + * plugin.freezePublicAPI({ + * example: function(){ + * + * } + * }); + * + * plugin.load(null, "texteditor"); + * + * return plugin; + * } + * + * @class Editor + * @extends Plugin + */ + /** + * @constructor + * Creates a new Editor instance. + * @param {String} developer The name of the developer of the plugin + * @param {String[]} deps A list of dependencies for this + * plugin. In most cases it's a reference to main.consumes. + * @param {String[]} extensions A list of file extension that this + * editor can handle. + */ + plugin.freezePublicAPI({ + /** + * @ignore + */ + get aml(){ return amlTab; }, + + /** + * The pane that this editor is a part of. Each editor is + * initialized in the context of a single pane and the editor + * is destroyed when the pane is destroyed. + * @property {Pane} pane + * @readonly + */ + get pane(){ return pane; }, + + /** + * The document that is displayed in this editor. + * @property {Document} activeDocument + * @readonly + */ + get activeDocument(){ return activeDocument; }, + + /** + * @property {String} type the unique identifier for this editor + * @readonly + */ + get type(){ return type; }, + set type(val) { + if (!type) + type = val; + else + throw new Error("Plugin Type Exception"); + }, + + /** + * @property {Object} meta + */ + get meta(){ return meta; }, + + /** + * @property {String[]} fileExtensions Array of file extensions supported by this editor + * @readonly + */ + get fileExtensions(){ return extensions; }, + + _events: [ + /** + * Fires when a document is loaded into the editor. + * This event is also fired when this document is attached to another + * instance of the same editor (in a split view situation). Often you + * want to keep the session information partially in tact when this + * happens. + * @event documentLoad + * @param {Object} e + * @param {Document} e.doc the document that is loaded into the editor + * @param {Object} e.state state that was saved in the document + */ + "documentLoad", + /** + * Fires when a document becomes the active document of an editor + * This event is called every time a tab becomes the active tab of + * a pane. Use it to show / hide whatever is necessary. + * + * @event documentActivate + * @param {Object} e + * @param {Document} e.doc the document that is activate + */ + "documentActivate", + /** + * Fires when a document is unloaded from the editor. + * This event is also fired when this document is attached to another + * instance of the same editor (in a split view situation). + * @event documentUnload + * @param {Object} e + * @param {Document} e.doc the document that was loaded into the editor + */ + "documentUnload", + /** + * Fires when the state of the editor is retrieved + * @event getState + * @param {Object} e + * @param {Document} e.doc the document for which the state is retrieved + * @param {Object} e.state the state to add values to {See Editor#getState} + */ + "getState", + /** + * Fires when the state of the editor is set + * @event setState + * @param {Object} e + * @param {Document} e.doc the document for which the state is set + * @param {Object} e.state the state that is being set + */ + "setState", + /** + * Fires when the editor is cleared + * @event clear + */ + "clear", + /** + * Fires when the editor gets the focus. See also + * {@link tabManager#focusTab}, {@link tabManager#focussedTab} + * @event focus + * @param {Object} e + * @param {Boolean} e.regain whether the focus is regained. + * This means that the editor had lost the focus + * previously (the focus event with e.lost set to true + * was called.) and now the focus has been given back to + * the tabs. + * @param {Boolean} e.lost whether the focus is lost, + * while the editor remains the focussed editor. This + * happens when an element outside of the editors + * (for instance the tree or a menu) gets the focus. + */ + "focus", + /** + * Fires when the editor looses focus. + * @event blur + */ + "blur", + /** + * Fires when the cut command is dispatched to this editor, + * either using a keybinding or programmatically. + * + * plugin.on("cut", function(e) { + * var data = this.yankDataFromSomewhere(); + * e.clipboardData.setData("text/plain", data); + * }); + * + * @event cut + * @param {Object} e + * @param {clipboard.ClipboardData} e.clipboardData the api to interact with the clipboard + * @param {Boolean} e.native whether this is a native clipboard event + */ + "cut", + /** + * Fires when the copy command is dispatched to this editor, + * either using a keybinding or programmatically. + * + * plugin.on("cut", function(e) { + * var data = this.getDataFromSomewhere(); + * e.clipboardData.setData("text/plain", data); + * }); + * + * @event copy + * @param {Object} e + * @param {clipboard.ClipboardData} e.clipboardData the api to interact with the clipboard + * @param {Boolean} e.native whether this is a native clipboard event + */ + "copy", + /** + * Fires when the copy command is dispatched to this editor, + * either using a keybinding or programmatically. + * + * plugin.on("paste", function(e) { + * e.clipboardData.getData("text/plain", function(err, data) { + * // Process the data here + * }); + * }); + * + * @event paste + * @param {Object} e + * @param {clipboard.ClipboardData} e.clipboardData the api to interact with the clipboard + * @param {Boolean} e.native whether this is a native clipboard event + */ + "paste", + /** + * Fires when the editor resizes + * @event resize + * @param {Event} e the DOMEvent related to the resize event. + */ + "resize", + /** + * Fires when the editor is requested to draw itself. Cloud9 + * is optimized by lazy loading everyhing. This means that + * the editor won't be loaded until absolutely necessary. + * This is usually the case when the tab is active for the + * first time. + * @event draw + * @param {Object} e + * @param {HTMLElement} e.htmlNode + * @param {Tab} e.tab + */ + "draw", + /** + * Fires when a new document is going to be loaded in this + * editor. The purpose of this event is to allow a check + * prior to switching from one editor to the next for the + * same document. + * @event validate + * @param {Object} e + * @param {Document} e.document the document that will be loaded + * @param {Object} e.info extra information about the document + */ + "validate", + ], + + /** + * Unloads the document from this editor. + * @private + */ + unloadDocument: unloadDocument, + + /** + * Loads the document in this editor to be displayed. + * @param {Document} doc the document to display + */ + loadDocument: loadDocument, + + /** + * Retrieves the state of a document in relation to this editor + * @param {Document} doc the document for which to return the state + * @return {Object} + */ + getState: getState, + + /** + * Sets the state of this editor (related to a document) + * @param {Document} doc the document for which to set the state + * @param {Object} state the state of the document for this editor + */ + setState: setState, + + /** + * Clears the value of the document in the editor + */ + clear: clear, + + /** + * Checks if clipboard action is available + * @param {Object} clipboard action type + */ + isClipboardAvailable: isClipboardAvailable, + + /** + * Cuts the current selection from the editor into the clipboard + */ + cut: cut, + + /** + * Copies the current selection from the editor into the clipboard + */ + copy: copy, + + /** + * Pastes the current clipboard buffer into this editor + */ + paste: paste, + + /** + * Sets the focus to this editor + */ + focus: focus, + + /** + * Removes the focus from this editor + */ + blur: blur, + + /** + * Resize the editor to fit it's container + */ + resize: resize, + + /** + * Checks whether the passed document would be valid in the context + * of this editor. + * @param {Document} doc the document to check + * @param {Object} info object to put values on to display in a return alert (title, head, message) + */ + isValid: isValid, + + /** + * Attaches editor to pane element. This can be done only once + * @param pane {AmlNode.Tab} the pane element to add this editor to + */ + attachTo: attachTo, + + /** + * @private + */ + drawOn: drawOn + }); + + return plugin; + } + + /***** Register and define API *****/ + + register(null, { + Editor: Editor + }) + } +}); diff --git a/plugins/c9.ide.editors/editor_test.js b/plugins/c9.ide.editors/editor_test.js new file mode 100644 index 00000000..002cb84c --- /dev/null +++ b/plugins/c9.ide.editors/editor_test.js @@ -0,0 +1,153 @@ +/*global describe:false, it:false */ + +require(["lib/architect/architect", "lib/chai/chai"], function (architect, chai) { + "use client"; + var expect = chai.expect; + + expect.setupArchitectTest([ + "plugins/c9.core/ext", + "plugins/c9.ide.ui/ui", + "plugins/c9.core/util", + "plugins/c9.ide.ui/lib_apf", + "plugins/c9.ide.editors/editor", + "plugins/c9.ide.clipboard/clipboard", + "plugins/c9.ide.clipboard/html5", + "plugins/c9.ide.editors/document", + "plugins/c9.ide.editors/undomanager", + + // Mock plugins + { + consumes: [], + provides: ["c9"], + setup: expect.html.mocked + }, + { + consumes: ["apf", "ui", "Plugin"], + provides: [ + "commands", "menus", "layout", "settings", "dialog.alert", + "dialog.error" + ], + setup: expect.html.mocked + }, + { + consumes: ["Editor", "Document"], + provides: [], + setup: main + } + ], architect); + + function main(options, imports, register) { + var Editor = imports.Editor; + var Document = imports.Document; + + describe('editor', function() { + it('should load it\'s state from the constructor', function(done) { + var exts = ["js", "txt"]; + var editor = new Editor("Ajax.org", [], exts); + + expect(editor.fileExtensions).to.equal(exts); + + done(); + }); + it('should emit document event and connect state get/setters with those of editor', function(done) { + var exts = ["js", "txt"]; + var editor = new Editor("Ajax.org", [], exts); + var doc = new Document(); + + editor.type = "test"; + editor.name = "test1"; + + var count = 0; + editor.on("documentLoad", function(e) { + expect(e.doc).to.equal(doc); + count++; + }); + editor.on("documentActivate", function(e) { + expect(e.doc).to.equal(doc); + count++; + }); + editor.on("documentUnload", function(e) { + expect(e.doc).to.equal(doc); + count++; + }); + doc.on("setState", function(e) { + count++; + }); + doc.on("getState", function(e) { + count++; + }); + editor.on("setState", function(e) { + expect(e.state).property("x").to.equal(1); + count++; + }); + editor.on("getState", function(e) { + e.state.x = 1; + count++; + }); + + editor.loadDocument(doc); + + var state = doc.getState(); + doc.setState(state); + + editor.loadDocument(doc); + + doc.unload(); + + if (count != 8) { + throw new Error("Not all events where called: " + + count + " of 8"); + } + + expect(state).property("test").property("x").to.equal(1); + + done(); + }); + it('should emit clear when clearing the editor', function(done) { + var editor = new Editor(); + editor.on("clear", function(e){ done(); }) + editor.clear(); + }); + it('should emit focus when focussing the editor', function(done) { + var editor = new Editor(); + editor.on("focus", function(e){ done(); }) + editor.focus(); + }); + it('should emit validate when validating the editor', function(done) { + var editor = new Editor(); + editor.on("validate", function(e) { + expect(e.document).to.equal(1); + done(); + }) + editor.isValid(1); + }); + it('should attach itself to a pane element', function(done) { + var editor = new Editor(); + + var count = 0; + editor.on("draw", function(e) { + e.tab.on("DOMNodeRemovedFromDocument", function(){ + if (count != 2) + throw new Error("Not all events where called: " + + count); + + done(); + }) + count++; + }); + + var pane = { + aml: {insertBefore: function(){ count++ }, + getPage: function(){}}, + on: function(){} + } + editor.attachTo(pane); + + editor.load("test"); + editor.unload(); + }); + }); + + onload && onload(); + } +}); \ No newline at end of file diff --git a/plugins/c9.ide.editors/editors.js b/plugins/c9.ide.editors/editors.js new file mode 100644 index 00000000..cc082351 --- /dev/null +++ b/plugins/c9.ide.editors/editors.js @@ -0,0 +1,260 @@ +define(function(require, module, exports) { + main.consumes = [ + "Plugin", "menus", "ui" + ]; + main.provides = ["editors"]; + return main; + + function main(options, imports, register) { + var ui = imports.ui; + var Plugin = imports.Plugin; + var menus = imports.menus; + + /***** Initialization *****/ + + var plugin = new Plugin("Ajax.org", main.consumes); + var emit = plugin.getEmitter(); + + var fileExtensions = {}; + var editors = {}; + var defaultEditor; + var group; + + var loaded = false; + function load(){ + if (loaded) return false; + loaded = true; + + plugin.addElement(group = new ui.group()); + + menus.addItemByPath("View/Editors/", new ui.menu({ + "onprop.visible" : function(e) { + if (!e.value) + return; + + emit("menuShow", { menu: this }); + } + }), 100, plugin); + menus.addItemByPath("View/~", new ui.divider(), 200, plugin); + } + + function findEditor(type, editor) { + if (type) + editor = editors[type]; + + // if (!editor) { + // util.alert( + // "No editor is registered", + // "Could not find an editor to display content!", + // "There is something wrong with the configuration of \ + // your IDE. No editor plugin is found."); + // return; + // } + + return editor; + } + + function findEditorByFilename(fn) { + var ext = fn.substr(fn.lastIndexOf(".") + 1).toLowerCase(); + var editor = fileExtensions[fn] && fileExtensions[fn][0] + || fileExtensions[ext] && fileExtensions[ext][0] + || defaultEditor; + + return findEditor(null, editor); + } + + /***** Methods *****/ + + function registerPlugin(type, caption, editor, extensions) { + editors[type] = editor; + + var handle = new Plugin("Ajax.org", []); + handle[type] = editor; + handle[caption] = caption; + + editor.type = type; + editor.fileExtensions = extensions; + + if (extensions.length) { + //Add a menu item to the list of editors + menus.addItemByPath("View/Editors/" + caption, + new ui.item({ + type: "radio", + value: type, + group: group, + onclick: function(){ + emit("menuClick", {value: this.value}); + } + }), 40000, handle); + } + + extensions.forEach(function(ext) { + // force lower-case, to account for other LowerCase checks below + ext = ext.toLowerCase(); + (fileExtensions[ext] || (fileExtensions[ext] = [])).push(editor); + }); + + if (editor.type == options.defaultEditor) + defaultEditor = editor; + + emit("register", {editor: editor}); + + handle.on("load", function(){ + if (!editors[type]) + registerPlugin(type, caption, editor, extensions); + }); + handle.on("unload", function(){ + unregisterPlugin(type, editor, extensions); + }); + return handle; + } + + function unregisterPlugin(type, editor, extensions) { + delete editors[type]; + + extensions.forEach(function(fe) { + if (!fileExtensions[fe]) return; + + var idx = fileExtensions[fe].indexOf(editor); + fileExtensions[fe].splice(idx, 1); + if (!fileExtensions[fe].length) + delete fileExtensions[fe]; + }); + + if (defaultEditor == editor) + defaultEditor = null; + + emit("unregister", {editor: editor}); + } + + function createEditor(type, callback) { + if (!type) type = "default"; + + var cancelled = false; + + function create(){ + if (cancelled) return; + var constr = editors[type]; + var editor = constr ? new constr() : false; + editor.type = type; + callback(null, editor); + + emit("create", { editor: editor }); + } + + if (editors[type]) create(); + else { + plugin.on("register", function wait(e) { + if (e.editor.type == type) { + plugin.off("register", wait); + + // Delay creation to make sure handle is created + setTimeout(create); + } + }); + return function cancel() { cancelled = true }; + } + } + + /***** Lifecycle *****/ + + plugin.on("load", function(){ + load(); + }); + plugin.on("enable", function(){ + + }); + plugin.on("disable", function(){ + + }); + plugin.on("unload", function(){ + loaded = false; + }); + + /***** Register and define API *****/ + + /** + * Editor Manager for Cloud9. Editors are automatically registered + * here when using the {@link Editor} base class. Use this class to + * instantiate an editor instance for use outside of the normal tabs. + * If you want to open a tab with an editor to edit file content use + * {@link tabManager#method-open}. + * + * @singleton + **/ + plugin.freezePublicAPI({ + /** + * The editor that is used when no editor is registered for the + * file extension in question. + * + * See {@link editors#findEditorByFilename} + * See {@link tabManager#method-open} + * + * @property {String} defaultEditor + */ + get defaultEditor(){ return options.defaultEditor; }, + + /** + * Array of file extensions supported by the registered editors + * @property {String[]} fileExtensions + */ + get fileExtensions(){ return fileExtensions; }, + + _events: [ + /** + * @event register Fires when an editor registers + * @param {Object} e + * @param {Editor} e.editor The editor that is registered + * @readonly + */ + "register", + /** + * @event unregister Fires when an editor unregisters + * @param {Object} e + * @param {Editor} e.editor The editor that is unregistered + * @readonly + */ + "unregister" + ], + + /** + * Registers an editor constructor to be available for certain + * file types + * @param {Function} editor the editor constructor + * @param {String[]} fileExtensions the file extensions this editor supports + */ + register: registerPlugin, + + /** + * Unregisters an editor constructor for certain file types + * @param {Function} editor the editor constructor + */ + unregister: unregisterPlugin, + + /** + * Retrieves an editor constructor class based on it's type + * @param {String} type The type of the editor to retrieve + * @return {Function} + */ + findEditor: findEditor, + + /** + * Retrieves an editor constructor class based on a filename (or path) + * @param {String} filename the filename that determines the editor to find + * @return {Function} + */ + findEditorByFilename: findEditorByFilename, + + /** + * Create an editor instance based on it's type + * @param {String} type The type of the editor to create + * @return {Editor} + */ + createEditor: createEditor + }); + + register(null, { + editors: plugin + }); + } +}); \ No newline at end of file diff --git a/plugins/c9.ide.editors/editors_test.js b/plugins/c9.ide.editors/editors_test.js new file mode 100644 index 00000000..5cfde725 --- /dev/null +++ b/plugins/c9.ide.editors/editors_test.js @@ -0,0 +1,82 @@ +/*global describe:false, it:false */ + +"use client"; + +require(["lib/architect/architect", "lib/chai/chai", "events"], function (architect, chai, events) { + var expect = chai.expect; + var EventEmitter = events.EventEmitter; + + expect.setupArchitectTest([ + "plugins/c9.core/ext", + "plugins/c9.ide.ui/ui", + "plugins/c9.core/util", + "plugins/c9.ide.ui/lib_apf", + "plugins/c9.ide.editors/document", + "plugins/c9.ide.editors/undomanager", + "plugins/c9.ide.editors/editors", + "plugins/c9.ide.editors/editor", + { + consumes: ["editors", "Editor"], + provides: [], + setup: main + } + ], architect, { + mockPlugins: ["menus", "util", "clipboard", "c9"] + }); + + function main(options, imports, register) { + var editors = imports.editors; + var Editor = imports.Editor; + + var extensions = ["txt"]; + function NewEditor(){ + var plugin = new Editor("Ajax.org", [], extensions); + plugin.freezePublicAPI({ success : 1 }); + return plugin; + } + + describe('editors', function() { + it('should register an editor when the it\'s name is set', function(done) { + editors.on("register", function reg(){ + done(); + editors.off("register", reg); + }) + + var handle = editors.register("test", "Test", NewEditor, extensions); + handle.unload(); + }); + it('should call the unregister event when the plugin is unloaded', function(done) { + var handle = editors.register("test", "Test", NewEditor, extensions); + + editors.on("unregister", function reg(){ + done(); + editors.off("unregister", reg); + }); + + handle.load("test"); + handle.unload(); + }); + it('should allow for the creation and discovery of editors', function(done) { + var handle = editors.register("test", "Test", NewEditor, extensions); + + expect(editors.findEditor("test"), "findEditor") + .to.equal(NewEditor); + expect(editors.findEditorByFilename("test.txt"), "findEditorByFilename") + .to.equal(NewEditor); + editors.createEditor("test", function(err, editor) { + if (err) throw err; + + expect(editor, "createEditor") + .property("success").to.equal(1); + + handle.load("test"); + handle.unload(); + + done(); + }); + }); + }); + + onload && onload(); + } +}); \ No newline at end of file diff --git a/plugins/c9.ide.editors/htmlview.js b/plugins/c9.ide.editors/htmlview.js new file mode 100644 index 00000000..87632aad --- /dev/null +++ b/plugins/c9.ide.editors/htmlview.js @@ -0,0 +1,61 @@ +/** + * Image Viewer for the Cloud9 + * + * @copyright 2010, Ajax.org B.V. + * @license GPLv3 + */ +define(function(require, exports, module) { + main.consumes = ["Editor", "editors", "ui"]; + main.provides = ["htmlview"]; + return main; + + function main(options, imports, register) { + var Editor = imports.Editor; + var editors = imports.editors; + + /***** Initialization *****/ + + var extensions = []; + + function HtmlView(){ + var plugin = new Editor("Ajax.org", main.consumes, extensions); + var container; + + plugin.on("draw", function(e) { + // Create UI element + container = e.htmlNode; + }); + + /***** Method *****/ + + /***** Lifecycle *****/ + + plugin.on("documentLoad", function(e) { + var session = e.doc.getSession(); + session.value = e.state.value; + }); + + plugin.on("documentActivate", function(e) { + var session = e.doc.getSession(); + container.innerHTML = session.value; + }); + + /***** Register and define API *****/ + + /** + * Read Only Image Editor + **/ + plugin.freezePublicAPI({}); + + plugin.load(null, "htmlview"); + + return plugin; + } + HtmlView.autoload = false; + + register(null, { + htmlview: editors.register("htmlview", "Html View", + HtmlView, extensions) + }); + } +}); \ No newline at end of file diff --git a/plugins/c9.ide.editors/imgview.js b/plugins/c9.ide.editors/imgview.js new file mode 100644 index 00000000..c75f09ac --- /dev/null +++ b/plugins/c9.ide.editors/imgview.js @@ -0,0 +1,138 @@ +define(function(require, exports, module) { + main.consumes = ["Editor", "editors", "ui", "save", "vfs"]; + main.provides = ["imgview"]; + return main; + + function main(options, imports, register) { + var ui = imports.ui; + var vfs = imports.vfs; + var save = imports.save; + var Editor = imports.Editor; + var editors = imports.editors; + + /***** Initialization *****/ + + var extensions = ["gif", "ico"]; + + function ImageEditor(){ + var plugin = new Editor("Ajax.org", main.consumes, extensions); + var editor; + + var BGCOLOR = "#3D3D3D"; + + plugin.on("draw", function(e) { + // Create UI element + editor = e.tab.appendChild(new ui.img({ + flex: "1", + anchors: "0 0 0 0", + visible: "false", + style: "background-color:" + BGCOLOR + })); + + plugin.addElement(editor); + + save.on("beforeSave", function(e) { + var path = e.document.tab.path; + if (!path) + return; + + // don't save images for now. + if (editor.value == path) + return false; + }, plugin); + + editor.show(); + }); + + /***** Method *****/ + + function setPath(path, doc) { + if (!path) return; + + // Caption is the filename + doc.title = (doc.changed ? "*" : "") + + path.substr(path.lastIndexOf("/") + 1); + + // Tooltip is the full path + doc.tooltip = path; + + var fullpath = path.match(/^\w+:\/\//) + ? path + : vfs.url(path); + + editor.setProperty("value", apf.escapeXML(fullpath)); + } + + /***** Lifecycle *****/ + + plugin.on("documentLoad", function(e) { + var doc = e.doc; + doc.tab.on("setPath", function(e) { + setPath(e.path, doc); + }, doc.getSession()); + doc.tab.backgroundColor = BGCOLOR; + doc.tab.classList.add("dark"); + }); + + plugin.on("documentActivate", function(e) { + setPath(e.doc.tab.path || e.doc.value, e.doc); + }); + + /***** Register and define API *****/ + + /** + * The imgview handle, responsible for events that involve all + * ImageEditor instances. This is the object you get when you request + * the imgview service in your plugin. + * + * Example: + * + * define(function(require, exports, module) { + * main.consumes = ["imgview"]; + * main.provides = ["myplugin"]; + * return main; + * + * function main(options, imports, register) { + * var imgviewHandle = imports.imgview; + * }); + * }); + * + * + * @class imgview + * @extends Plugin + * @singleton + */ + /** + * Read Only Image Viewer for Cloud9 + * + * Example of instantiating a new terminal: + * + * tabManager.openFile("/test.png", true, function(err, tab) { + * if (err) throw err; + * + * var imgview = tab.editor; + * }); + * + * @class imgview.ImageEditor + * @extends Editor + **/ + /** + * The type of editor. Use this to create the terminal using + * {@link tabManager#openEditor} or {@link editors#createEditor}. + * @property {"imgview"} type + * @readonly + */ + plugin.freezePublicAPI({}); + + plugin.load(null, "imgview"); + + return plugin; + } + ImageEditor.autoload = false; + + register(null, { + imgview: editors.register("imgview", "Image Viewer", + ImageEditor, extensions) + }); + } +}); \ No newline at end of file diff --git a/plugins/c9.ide.editors/metadata.js b/plugins/c9.ide.editors/metadata.js new file mode 100644 index 00000000..050c5b46 --- /dev/null +++ b/plugins/c9.ide.editors/metadata.js @@ -0,0 +1,593 @@ +define(function(require, exports, module) { + main.consumes = [ + "c9", "Plugin", "fs", "settings", "tabManager", "dialog.error", + "dialog.question", "preferences", "save" + ]; + main.provides = ["metadata"]; + return main; + + function main(options, imports, register) { + var c9 = imports.c9; + var Plugin = imports.Plugin; + var fs = imports.fs; + var settings = imports.settings; + var save = imports.save; + var tabs = imports.tabManager; + var confirm = imports["dialog.question"].show; + var showError = imports["dialog.error"].show; + var prefs = imports.preferences; + + /***** Initialization *****/ + + var plugin = new Plugin("Ajax.org", main.consumes); + var emit = plugin.getEmitter(); + + var PATH = options.path || "/.c9/metadata"; + var WORKSPACE = "/workspace"; + + var jobs = {}; + var changed = {}; + var cached = {}; + var worker, timer; + + var CHANGE_CHECK_INTERVAL = options.changeCheckInterval || 30000; + + var loaded = false; + function load(){ + if (loaded) return false; + loaded = true; + + // Schedule for inspection when tab becomes active + tabs.on("tabAfterActivate", function(e) { + // If disabled don't do anything + if (!e.tab.loaded || !settings.getBool("user/metadata/@enabled")) + return; + + if (e.lastTab) + changed[e.lastTab.name] = e.lastTab; + + changed[e.tab.name] = e.tab; + }, plugin); + + // Closing a tab + tabs.on("tabAfterClose", function (e) { + // If disabled don't do anything + if (!settings.getBool("user/metadata/@enabled")) + return; + + var doc = e.tab.document; + if (!e.tab.path) { + fs.unlink(PATH + "/" + e.tab.name, function(){ return false }); + } + else if (doc.meta.newfile || doc.meta.$ignoreSave) { + fs.unlink(PATH + WORKSPACE + e.tab.path, function(){ return false }); + } + else if (check(e.tab) !== false) { + delete changed[e.tab.name]; + delete cached[e.tab.name]; + } + }, plugin); + + // Opening a file + tabs.on("beforeOpen", function(e) { + // If disabled don't do anything + if (!settings.getBool("user/metadata/@enabled")) + return; + + // Don't load metadata if document state is defined or value is set + if (e.tab.path && e.options.document.filter === false + || !e.tab.path && !e.options.document.filter + || e.options.value) + return; + + // todo should tabmanager check this? + e.options.loadFromDisk = e.loadFromDisk + && !e.tab.document.meta.newfile + && !e.tab.document.meta.nofs; + + // Fetch the metadata and real data + var callback = function(err) { + if (e.loadFromDisk) + e.callback(err); + }; + loadMetadata(e.tab, e.options, callback, e.options.init); + + return e.loadFromDisk ? false : true; + }, plugin); + + // Check every half a minute for changed tabs + timer = setInterval(function(){ + checkChangedTabs(); + }, CHANGE_CHECK_INTERVAL); + + // Delete metadata when file is renamed + save.on("saveAs", function(e){ + if (e.path != e.oldPath) + fs.unlink(PATH + WORKSPACE + e.oldPath, function(){ return false }); + }); + + // Settings + + settings.on("read", function(e) { + settings.setDefaults("user/metadata", [ + ["enabled", "true"], + ["undolimit", "100"], + ]); + }, plugin); + + settings.on("write", function(e) { + if (e.unload) return; + + checkChangedTabs(); + }, plugin); + + + function checkChangedTabs(unload) { + // If disabled don't do anything + if (!settings.getBool("user/metadata/@enabled")) + return; + + tabs.getPanes().forEach(function(pane) { + var tab = pane.getTab(); + if (tab) { + changed[tab.name] = tab; + } + }); + + for (var name in changed) { + if (check(changed[name], unload) === false) + return; + } + + changed = {}; + } + + // Preferences + + prefs.add({ + "File" : { + position: 150, + "Meta Data" : { + position: 200, + "Store Meta Data of Opened Files" : { + type: "checkbox", + path: "user/metadata/@enabled", + position: 100 + }, + "Maximum of Undo Stack Items in Meta Data" : { + type: "spinner", + path: "user/metadata/@undolimit", + position: 200, + min: 10, + max: 10000 + } + } + } + }, plugin); + + // Exiting Cloud9 + c9.on("beforequit", function(){ + checkChangedTabs(true); + }, plugin); + + // Initial Load + tabs.getTabs().forEach(function(tab) { + var options = tab.getState(); + options.loadFromDisk = tab.path + && !tab.document.meta.newfile + && !tab.document.meta.nofs + // autoload to false prevents loading data, used by image editor + && (!tab.editor || tab.editor.autoload !== false); + + loadMetadata(tab, options, function(err) { + if (err) { + tab.unload(); + showError("File not found '" + tab.path + "'"); + return; + } + tab.classList.remove("loading"); + }, true); + }); + } + + /***** Methods *****/ + + function check(tab, forceSync) { + var docChanged = tab.document.changed || tab.document.meta.nofs; + + // Don't save state if we're offline + if (!c9.has(c9.STORAGE)) + return false; + + if (tab.meta.$loadingMetadata) + return; + + // Ignore metadata files and preview pages and debug files and + // tabs that are not loaded + if (!tab.loaded + || tab.path && tab.path.indexOf(PATH) === 0 + || tab.document.meta.preview) + return; + + var state = tab.document.getState(); + + // Make sure timestamp is preserved + if (state.meta) + state.timestamp = state.meta.timestamp; + + // meta is recorded by the tab state + delete state.meta; + + // If we discarded the file before closing, clear that data + if (tab.document.meta.$ignoreSave) { + delete state.value; + delete state.changed; + delete state.undoManager; + docChanged = true; + } + + if (docChanged || typeof state.value == "undefined" || forceSync) { + if (forceSync && !docChanged && state.undoManager.stack.length) + delete state.value; + + write(forceSync); + } + else { + hash(state.value, function(err, hash) { + if (err) return; + + delete state.value; + delete state.changed; + state.hash = hash; + write(forceSync); + }); + } + + function write(forceSync) { + if (c9.readonly) return; + + var limit = settings.getNumber("user/metadata/@undolimit"); + var undo = state.undoManager; + if (undo) { + var start = Math.max(0, undo.position - limit); + undo.stack.splice(0, start); + undo.position -= start; + undo.mark -= start; + } + + try { + // This throws when a structure is circular + var sstate = JSON.stringify(state); + } catch (e) { + // debugger; + return; + } + + // Lets not save large metadata + if (sstate.length > 1024 * 1024) { + sstate = ""; + state = {}; + } + + if (cached[tab.name] != sstate) { + cached[tab.name] = sstate; + + if (tab.path) { + var path = (tab.path.charAt(0) == "~" ? "/" : "") + tab.path; + fs.metadata(path, state, forceSync, function(err) { + if (err) + return; + }); + } + else { + fs.metadata("/_/_/" + tab.name, state, forceSync, function(err) { + if (err) + return; + }); + } + } + } + + return true; + } + + function merge(from, to) { + for (var prop in from) { + if (to[prop] && typeof from[prop] == "object") + merge(from[prop], to[prop]); + else + to[prop] = from[prop]; + } + } + + function loadMetadata(tab, options, callback, init) { + // // When something goes wrong somewhere in cloud9, this can happen + // if (tab.path && "/~".indexOf(tab.path.charAt(0)) == -1) + // debugger; + + var path = tab.path + ? PATH + WORKSPACE + (tab.path.charAt(0) == "~" ? "/" : "") + tab.path + : PATH + "/" + tab.name; + + var storedValue, storedMetadata; + var xhr; + + // Prevent Saving of Metadata + tab.meta.$loadingMetadata = true; + + // Progress Handling + tab.classList.add("loading"); + + var loadStartT = Date.now(); + + // Handler to show loading indicator + function progress(loaded, total, complete) { + var data = { + total: total, + loaded: loaded, + complete: complete, + dt: Date.now() - loadStartT + }; + + tab.document.progress(data); + } + + if (tab.path) { + if (options.loadFromDisk === false) { + // This is for new files and other files that will store + // their value in the metadata + receive(tab.document.value); + + // Don't load metadata of newly created newfile tabs (runtime) + if (!init) { + receive(null, -1); + return; + } + } + else { + tab.classList.add("loading"); + // progress(0, 1, 0); + + var cb = function(err, data, metadata, res) { + if (err) return callback(err); + receive(data, metadata || -1); + }; + + xhr = emit("beforeReadFile", { + tab: tab, + path: tab.path, + callback: cb, + progress: progress + }); + + if (!xhr) + xhr = fs.readFileWithMetadata(tab.path, "utf8", cb, progress); + } + } + + if (!xhr) { + xhr = fs.readFile(path, "utf8", function(err, data) { + receive(null, err ? -1 : data); + }, progress); + } + + // Cancel file opening when tab is closed + var abort = function(){ xhr && xhr.abort(); }; + tab.on("close", abort); + tabs.on("open", function wait(e) { + if (e.tab == tab) { + tab.off("close", abort); + tab.off("open", wait); + } + }, tab); + + function receive(value, metadata) { + var state; + + if (value !== null) + storedValue = value; + if (metadata) { + storedMetadata = metadata; + if (metadata != -1) { + cached[tab.name] + = metadata.replace(/"timestamp":\d+\,?$/, ""); + } + } + + // Final state processing and then we're done + var compareModified = false; + function done(state, cleansed) { + // Import state from options + var doc = options.document; + if (doc instanceof Plugin) + doc = doc.getState(); + + delete doc.fullState; + delete doc.value; + delete doc.undoManager; + + if (!doc.changed) + delete doc.changed; + + if (cleansed) { + delete state.undoManager; + + if (tab.editor && state[tab.editor.type]) + state[tab.editor.type].cleansed = true; + } + + // Preserve timestamp from metadata + if (!doc.meta) doc.meta = {}; + doc.meta.timestamp = state.timestamp; + delete state.timestamp; + + // Merge the two sources + merge(doc, state); + + if (tab.document.hasValue()) + delete state.value; + + // Keep original value from disk + state.meta.$savedValue = storedValue; + + var sameValue = state.value === storedValue; + if (options.loadFromDisk && (sameValue || compareModified)) { + fs.stat(tab.path, function(err, stat) { + if (err) return; + + if (compareModified) { + // @todo this won't work well on windows, because + // there is a 20s period in which the mtime is + // the same. The solution would be to have a + // way to compare the saved document to the + // loaded document that created the state + if (!state.meta || state.meta.timestamp < stat.mtime) { + var doc = tab.document; + + function checkChange(){ + confirm("File Changed", + tab.path + " has been changed on disk.", + "Would you like to reload this file?", + function(){ // Yes + // Set new value and clear undo state + doc.setBookmarkedValue(storedValue, true); + doc.meta.timestamp = stat.mtime; + }, + function(){ // No + // Set to changed + doc.undoManager.bookmark(-2); + doc.meta.timestamp = stat.mtime; + }, + { merge: false, all: false } + ); + } + + if (state.meta.preview) { + doc.editor.on("focus", function wait(e) { + if (doc.editor.activeDocument == doc) { + doc.editor.off("focus", wait); + checkChange(); + } + }, doc); + return; + } + else + checkChange(); + } + } + else { + tab.document.meta.timestamp = stat.mtime; + } + }); + } + + // Set new state + tab.document.setState(state); + + // Declare done + delete tab.meta.$loadingMetadata; + + callback(); + } + + if ((!tab.path || storedValue !== undefined) && storedMetadata) { + try{ + state = storedMetadata == -1 + ? {} : JSON.parse(storedMetadata); + } + catch (e){ state = {} } + + // There's a hash. Lets compare it to the hash of the + // current value. If they are the same we can keep the + // undo stack, otherwise we'll clear the undo stack + if (state.hash && typeof storedValue == "string") { + state.value = storedValue; + + hash(storedValue, function(err, hash) { + done(state, state.hash != hash); + }); + return; // Wait until hash is retrieved + } + else if (state.value && tab.path) { + // If the stored value is not the same as the value + // on disk we need to find out which is newer + if (state.value != storedValue) + compareModified = true; + } + else { + state.value = storedValue; + } + + done(state); + } + } + } + + hash.counter = 0; + function hash(data, callback) { + if (!worker) { + worker = new Worker('/static/lib/rusha/rusha.min.js'); + worker.addEventListener("message", function(e) { + // @todo security? + + if (jobs[e.data.id]) { + jobs[e.data.id](null, e.data.hash); + delete jobs[e.data.id]; + } + }); + } + worker.postMessage({ id: ++hash.counter, data: data }); + jobs[hash.counter] = callback; + + if (hash.counter === 30000) + hash.counter = 0; + } + + /***** Lifecycle *****/ + + plugin.on("load", function(){ + load(); + }); + plugin.on("enable", function(){ + + }); + plugin.on("disable", function(){ + + }); + plugin.on("unload", function(){ + loaded = false; + clearInterval(timer); + }); + + /***** Register and define API *****/ + + /** + * Manages metadata for tabs in Cloud9. Each tab in Cloud9 has + * additional information that needs to be stored. + * + * When you open a file in Cloud9, it generally is opened in a tab and + * displayed using the {@link ace.Ace Ace} editor. The ace editor maintains a + * lot of state while displaying the file, such as the scroll position, + * the selection, the folds, the syntax highligher, etc. The document + * also serializes the value and the complete undo stack. Editors + * that don't open files can still hold metadata. The {@link terminal.Terminal Terminal} + * for instance has selection, scroll state and scroll history. All this + * information can be saved to disk by the metadata plugin. + * + * The metadata is saved in ~/.c9/metadata. The metadata plugin plugs + * into the tabManager and takes over the loading of the file content + * so that the loading of the content and the metadata is synchronized. + * This plugin is also responsible for saving the metadata back to the + * workspace. + * + * @singleton + **/ + plugin.freezePublicAPI({ + + }); + + register(null, { + metadata: plugin + }); + } +}); diff --git a/plugins/c9.ide.editors/metadata_test.js b/plugins/c9.ide.editors/metadata_test.js new file mode 100644 index 00000000..87387c24 --- /dev/null +++ b/plugins/c9.ide.editors/metadata_test.js @@ -0,0 +1,463 @@ +/*global describe it before after bar*/ + +"use client"; + +require(["lib/architect/architect", "lib/chai/chai", "/vfs-root"], + function (architect, chai, baseProc) { + var expect = chai.expect; + + expect.setupArchitectTest([ + { + packagePath: "plugins/c9.core/c9", + startdate: new Date(), + debug: true, + hosted: true, + local: false, + workspaceId: "javruben/dev", + davPrefix: "/" + }, + + "plugins/c9.core/ext", + "plugins/c9.core/http-xhr", + "plugins/c9.core/util", + "plugins/c9.ide.ui/lib_apf", + "plugins/c9.ide.ui/menus", + { + packagePath: "plugins/c9.core/settings", + testing: true + }, + "plugins/c9.core/api.js", + { + packagePath: "plugins/c9.ide.ui/ui", + staticPrefix: "plugins/c9.ide.ui" + }, + "plugins/c9.ide.editors/document", + "plugins/c9.ide.editors/undomanager", + { + packagePath: "plugins/c9.ide.editors/editors", + defaultEditor: "texteditor" + }, + "plugins/c9.ide.editors/editor", + "plugins/c9.ide.editors/tabmanager", + "plugins/c9.ide.ui/focus", + "plugins/c9.ide.editors/metadata", + "plugins/c9.ide.editors/pane", + "plugins/c9.ide.editors/tab", + "plugins/c9.ide.ace/ace", + { + packagePath: "plugins/c9.ide.terminal/terminal", + testing: true + }, + { + packagePath: "plugins/c9.vfs.client/vfs_client" + }, + "plugins/c9.vfs.client/endpoint", + "plugins/c9.ide.auth/auth", + "plugins/c9.fs/proc", + { + packagePath: "plugins/c9.fs/fs", + baseProc: baseProc + }, + "plugins/c9.fs/fs.cache.xml", + + "plugins/c9.ide.dialog/dialog", + "plugins/c9.ide.dialog.common/alert", + "plugins/c9.ide.dialog.common/alert_internal", + "plugins/c9.ide.dialog.common/confirm", + "plugins/c9.ide.dialog.common/filechange", + "plugins/c9.ide.dialog.common/fileoverwrite", + "plugins/c9.ide.dialog.common/fileremove", + "plugins/c9.ide.dialog.common/question", + "plugins/c9.ide.dialog.file/filesave", + + // Mock plugins + { + consumes: ["apf", "ui", "Plugin"], + provides: [ + "commands", "menus", "commands", "layout", "watcher", "save", + "preferences", "anims", "clipboard", "auth.bootstrap", "info", + "dialog.error" + ], + setup: expect.html.mocked + }, + { + consumes: ["tabManager", "fs", "settings", "metadata", "dialog.question"], + provides: [], + setup: main + } + ], architect); + + function main(options, imports, register) { + var tabs = imports.tabManager; + var fs = imports.fs; + var settings = imports.settings; + var metadata = imports.metadata; + var question = imports["dialog.question"]; + + function countEvents(count, expected, done) { + if (count == expected) + done(); + else + throw new Error("Wrong Event Count: " + + count + " of " + expected); + } + + expect.html.setConstructor(function(tab) { + if (typeof tab == "object") + return tab.pane.aml.getPage("editor::" + tab.editorType).$ext; + }); + + describe('metadata', function() { + before(function(done) { + apf.config.setProperty("allow-select", false); + apf.config.setProperty("allow-blur", false); + + bar.$ext.style.background = "rgba(220, 220, 220, 0.93)"; + bar.$ext.style.position = "fixed"; + bar.$ext.style.left = "20px"; + bar.$ext.style.right = "20px"; + bar.$ext.style.bottom = "20px"; + bar.$ext.style.height = "33%"; + + // document.body.style.marginBottom = "33%"; + + fs.rmdir("/.c9/metadata", { recursive: true }, function(err) { + if (err) throw err; + + tabs.once("ready", function(){ + tabs.getPanes()[0].focus(); + tabs.openFile("/file.js", true, function(){ + tabs.openFile("/file.txt", false, function(){ + tabs.openFile("/fileLink.txt", false, function(){ + done(); + }); + }); + }); + }); + }); + }); + + describe("Triggering save", function(){ + it('should trigger save when a tab is active and changed', function(done) { + var editor = tabs.focussedTab.editor; + fs.once("afterMetadata", function(){ + fs.exists("/.c9/metadata/workspace/file.js", function(exists) { + done(); + }); + }); + + editor.scrollTo(100, 5); + + setTimeout(function(){ + settings.save(true); + }, 100); + }); + it('should trigger save when a tab is changed and closed', function(done) { + var tab = tabs.findTab("/file.txt"); + tabs.focusTab(tab); + var editor = tabs.focussedTab.editor; + editor.scrollTo(0, 10); + + setTimeout(function(){ + fs.once("afterMetadata", function(){ + fs.exists("/.c9/metadata/workspace/file.txt", function(exists) { + expect(exists).to.ok; + done(); + }); + }); + + tab.close(); + }, 100); + }); + }); + describe("Loading metadata", function(){ + it('should load metadata properly when a file has metadata', function(done) { + fs.exists("/.c9/metadata/workspace/file.txt", function(exists) { + expect(exists).to.ok; + + tabs.openFile("/file.txt", true, function(err, tab) { + if (err) throw err; + + var state = tab.document.getState(); + if (state.ace.selection.start.column === 10 + && state.ace.selection.start.row === 0 + && state.ace.selection.end.column === 10 + && state.ace.selection.end.row === 0 + && !tab.document.changed) + done(); + else + throw new Error("Selection is not correct: ", + state.ace.selection); + + tab.close(); + }); + }); + }); + it('should load metadata properly even when the file is not active when it\'s opened', function(done) { + tabs.openFile("/file.txt", false, function(err, tab) { + if (err) throw err; + + tab.activate(); + + var state = tab.document.getState(); + if (state.ace.selection.start.column === 10 + && state.ace.selection.start.row === 0 + && state.ace.selection.end.column === 10 + && state.ace.selection.end.row === 0 + && !tab.document.changed) + done(); + else + throw new Error("Selection is not correct"); + }); + }); + it('should load metadata for a new file', function(done) { + fs.writeFile("/.c9/metadata/workspace/newfile.txt", + '{"changed":true,"filter":false,"title":"Untitled1","tooltip":"/Untitled1","value":"asdasdasdasd","undoManager":{"mark":-1,"position":11,"stack":[[{"group":"doc","deltas":[{"action":"insertText","range":{"start":{"row":0,"column":0},"end":{"row":0,"column":1}},"text":"a"}]}],[{"group":"doc","deltas":[{"action":"insertText","range":{"start":{"row":0,"column":1},"end":{"row":0,"column":2}},"text":"s"}]}],[{"group":"doc","deltas":[{"action":"insertText","range":{"start":{"row":0,"column":2},"end":{"row":0,"column":3}},"text":"d"}]}],[{"group":"doc","deltas":[{"action":"insertText","range":{"start":{"row":0,"column":3},"end":{"row":0,"column":4}},"text":"a"}]}],[{"group":"doc","deltas":[{"action":"insertText","range":{"start":{"row":0,"column":4},"end":{"row":0,"column":5}},"text":"s"}]}],[{"group":"doc","deltas":[{"action":"insertText","range":{"start":{"row":0,"column":5},"end":{"row":0,"column":6}},"text":"d"}]}],[{"group":"doc","deltas":[{"action":"insertText","range":{"start":{"row":0,"column":6},"end":{"row":0,"column":7}},"text":"a"}]}],[{"group":"doc","deltas":[{"action":"insertText","range":{"start":{"row":0,"column":7},"end":{"row":0,"column":8}},"text":"s"}]}],[{"group":"doc","deltas":[{"action":"insertText","range":{"start":{"row":0,"column":8},"end":{"row":0,"column":9}},"text":"d"}]}],[{"group":"doc","deltas":[{"action":"insertText","range":{"start":{"row":0,"column":9},"end":{"row":0,"column":10}},"text":"a"}]}],[{"group":"doc","deltas":[{"action":"insertText","range":{"start":{"row":0,"column":10},"end":{"row":0,"column":11}},"text":"s"}]}],[{"group":"doc","deltas":[{"action":"insertText","range":{"start":{"row":0,"column":11},"end":{"row":0,"column":12}},"text":"d"}]}]]},"ace":{"folds":[],"scrolltop":0,"scrollleft":0,"selection":{"start":{"row":0,"column":12},"end":{"row":0,"column":12},"isBackwards":false},"options":{"newLineMode":"auto","tabSize":4,"useSoftTabs":true,"useWrapMode":null,"wrapToView":null},"firstLineState":0}}', + function(err, data) { + expect(err).to.not.ok; + + tabs.open({ + path: "/newfile.txt", + active: true, + init: true, + document: { meta: { newfile: true } } + }, function(err, tab) { + if (err) throw err; + + expect(tab.document.value).to.equal("asdasdasdasd"); + tab.close(); + done(); + }); + }); + }); + it('should load metadata properly for loading an existing pane that is not a file', function(done) { + tabs.openEditor("terminal", true, function(err, tab) { + if (err) throw err; + + setTimeout(function(){ + var state = tab.getState(true); + var name = tab.name; + + tab.editor.write("ls -l\n"); + + setTimeout(function(){ + var docstate = tab.getState().document; + var value = docstate.terminal.scrolltop; + + fs.once("afterUnlink", function(e) { + fs.metadata("/_/_/" + name, docstate, function(err) { + if (err) throw err; + + state.name = name; + state.active = true; + + fs.exists("/.c9/metadata/" + name, function(exists) { + if (!exists) + throw new Error("File not found"); + + fs.once("afterReadFile", function(e) { + setTimeout(function(){ + var state = tab.document.getState(); + expect(state.terminal.scrolltop, + "State did not get preserved").equals(value); + done(); + }, 1000); + }); + tabs.open(state, function(err, pg) { + if (err) throw err; + tab = pg; + }); + }); + }); + }); + + tab.close(); + settings.save(true); + }, 1000); + }, 1000); + }); + }); + it('should work well together with state set when opening tab', function(done) { + var tab = tabs.findTab("/file.js"); + tabs.once("tabDestroy", function(){ + setTimeout(function(){ + fs.exists("/.c9/metadata/workspace/file.js", function(exists) { + expect(exists, "File not found").ok; + + tabs.open({ + path: "/file.js", + active: true, + document: { + ace: { + jump: { + row: 200, + column: 10, + select: { + row: 202, + column: 20 + } + } + } + } + }, function(err, tab) { + setTimeout(function(){ + var state = tab.document.getState(); + expect(state.ace.selection.start.column).equals(10); + expect(state.ace.selection.start.row).equals(200); + expect(state.ace.selection.end.column).equals(20); + expect(state.ace.selection.end.row).equals(202); + done(); + }); + }) + }); + }); + }); + tab.close(); + }); + }); + describe("Content Collision", function(){ + it('should load contents stored in metadata', function(done) { + var path = "/collision.js"; + fs.writeFile(path, String(Date.now()), function(err) { + if (err) throw err; + + tabs.openFile(path, true, function(err, tab) { + if (err) throw err; + + var state = tab.getState(true); + var value = String(Date.now()); + + // Timeout to give the change the chance to propagate + setTimeout(function(){ + expect(tab.document.meta.timestamp, "Timing issue").to.ok; + + fs.once("afterMetadata", function(e) { + tabs.open(state, function(err, tab) { + expect(tab.document.value).equals(value); + expect(tab.document.undoManager.position).equals(0); + expect(tab.document.undoManager.length).equals(1); + expect(tab.document.changed).equals(true); + done(); + }); + }); + + tab.document.value = value; + + setTimeout(function(){ + tab.close(); // Forces saving metadata + }, 10) + }, 1000); // Give time to collect timestamp + }); + }); + }); + it('should warn if file contents on disk is newer than stored in metadata', function(done) { + var path = "/collision2.js"; + fs.writeFile(path, Date.now() + "a", function(err) { + if (err) throw err; + + tabs.openFile(path, true, function(err, tab) { + if (err) throw err; + + var state = tab.getState(true); + var value = Date.now() + "b" + + // Timeout to give the change the chance to propagate + setTimeout(function(){ + expect(tab.document.meta.timestamp, "Timing issue").to.ok; + + fs.once("afterMetadata", function(e) { + setTimeout(function(){ + fs.writeFile(path, Date.now() + "c", function(err) { + if (err) throw err; + + var curTab; + + question.once("show", function(){ + expect(question.getElement("window").visible).ok; + question.getElement("yes").dispatchEvent("click"); + + setTimeout(function(){ + expect(curTab.document.value, "value").not.equals(value); + expect(curTab.document.undoManager.position, "position").equals(1); + expect(curTab.document.undoManager.length, "length").equals(2); + expect(curTab.document.changed, "changed").equals(false); + done(); + }, 10); + }); + + expect(state.value).to.not.equal(value); + tabs.open(state, function(err, tab) { + curTab = tab; + }); + }); + }, 1100); // wait at least a second because Node 10 and lower has that change granularity + }); + + tab.document.value = value; + + setTimeout(function(){ + tab.close(); // Forces saving metadata + }, 10); // Time to process setting of value + }, 1000); // Give time to collect timestamp + }); + }); + }); + it('should warn remove undo data from metadata if file on disk is different', function(done) { + var path = "/collision3.js"; + fs.writeFile(path, Date.now() + "a", function(err) { + if (err) throw err; + + tabs.openFile(path, true, function(err, tab) { + if (err) throw err; + + var state = tab.getState(true); + var value = Date.now() + "b" + + tab.document.value = value; + + // Timeout to give the change the chance to propagate + setTimeout(function(){ + tab.document.undoManager.bookmark(); + expect(tab.document.changed).not.ok; + + fs.once("afterMetadata", function(e) { + setTimeout(function(){ + fs.writeFile(path, Date.now() + "c", function(err) { + if (err) throw err; + + tabs.open(state, function(err, tab) { + setTimeout(function(){ + expect(tab.document.value).not.equals(value); + expect(tab.document.undoManager.position).equals(-1); + expect(tab.document.undoManager.length).equals(0); + expect(tab.document.changed).equals(false); + + fs.unlink(path, function(){ + done(); + }) + }, 500); + }); + }); + }, 1100); + }); + + tab.close(); // Forces saving metadata + }); + }); + }); + }); + }); + if (!onload.remain) { + after(function(done) { + // document.body.style.marginBottom = ""; + metadata.unload(); + tabs.unload(); + bar.destroy(true, true); + done(); + }); + } + }); + + onload && onload(); + } +}); \ No newline at end of file diff --git a/plugins/c9.ide.editors/pane.js b/plugins/c9.ide.editors/pane.js new file mode 100644 index 00000000..359bcc24 --- /dev/null +++ b/plugins/c9.ide.editors/pane.js @@ -0,0 +1,869 @@ +define(function(require, module, exports) { + main.consumes = [ + "Plugin", "ui", "Tab", "settings", "menus", "editors", "anims", "apf", + "layout" + ]; + main.provides = ["Pane"]; + return main; + + function main(options, imports, register) { + var Plugin = imports.Plugin; + var ui = imports.ui; + var settings = imports.settings; + var menus = imports.menus; + var layout = imports.layout; + var editors = imports.editors; + var anims = imports.anims; + var apf = imports.apf; + + function Pane(options) { + var amlPane, queue, cancelEditorCreate, isFixedHeight; + + /***** Initialization *****/ + + var plugin = new Plugin("Ajax.org", main.consumes); + var emit = plugin.getEmitter(); + + var name = options.name; + var visible = true; + var meta; + + function load(){ + var btnPlus, btnMenu, closing = 0; + + meta = {}; + + amlPane = new ui.tab({ + skin: options && options.skin || "editor_tab", + skinset: options && options.skinset || "default", + style: "height : 100%", + width: options && options.width, + height: options && options.height, + activepage: options.preventAutoActivate ? -1 : 0, // Prevent first pane from becoming active + minwidth: 60, + minheight: 60, + buttons: "close,scale,order", + anims: settings.getBool("user/general/@animateui") ? "add|remove|sync" : "", + onbeforeswitch: function(e) { + var tab = e.nextPage.cloud9tab; + var lastTab = e.previousPage && e.previousPage.cloud9tab; + + // Small hack to prevent hover transition during tab switch + if (e.previousPage) { + var html = e.previousPage.$button; + ui.setStyleClass(html, "notrans") + setTimeout(function(){ + ui.setStyleClass(html, "", ["notrans"]) + }, 200); + } + + // Emit event + emit("beforeSwitch", { + tab: tab, + lastTab: lastTab, + pane: plugin + }); + }, + onafterswitch: function(e) { + var tab = e.nextPage.cloud9tab; + var lastTab = e.previousPage && e.previousPage.cloud9tab; + + // Get editor and create it if it's not in the current pane + createEditor(tab.editorType, function(err, editor) { + editor.loadDocument(tab.document); + + // Resize editor + tab.editor && tab.editor.resize({ type: "switch" }); + + // Call switch event + emit("afterSwitch", { + tab: tab, + lastTab: lastTab, + pane: plugin + }); + }); + }, + onclose: function(e) { + var amlTab = e.page; + if (amlTab.$amlDestroyed) return; + + var tab = amlTab.cloud9tab; + var event = { tab: tab, htmlEvent: e.htmlEvent }; + + event.last = amlPane.getPages().length == ++closing; + + if (emit("beforeClose", event) === false + || tab.beforeClose(event) === false) { + closing--; + return false; + } + + tab.meta.$closing = true; + + emit("afterClose", event); + + if (tab.aml.$amlDestroyed) { + tab.unload(e); + closing--; + } + else { + tab.aml.on("afterclose", function(){ + setTimeout(function(){ + tab.unload(e); + closing--; + }); + }); + } + }, + overactivetab: true, + childNodes: [ + btnPlus = new ui.button({ + id: "btnPlus", + "class" : "plus_tab_button", + skin: "c9-simple-btn", + }), + btnMenu = new apf.button({ + skin: "c9-simple-btn", + "class" : "tabmenubtn", + onmouseover: function(){ + this.setAttribute("submenu", + menus.get('Window/Tabs').menu); + } + }) + ] + }); + + plugin.addElement(amlPane); + + settings.on("user/general/@animateui", function(value) { + amlPane.setAttribute("anims", + apf.isTrue(value) ? "add|remove|sync" : ""); + }, plugin); + + amlPane.cloud9pane = plugin; + amlPane.btnMenu = btnMenu; + amlPane.btnPlus = btnPlus; + + // Small hack to get buttons inside button area of pane + amlPane.on("DOMNodeInsertedIntoDocument", function(){ + setTimeout(function(){ + amlPane.$buttons.appendChild(btnPlus.$ext); + amlPane.$buttons.appendChild(btnMenu.$ext); + }); + }); + + amlPane.on("DOMNodeInserted",function(e) { + var amlNode = e.currentTarget; + + if (e.$isMoveWithinParent) { + if (amlNode.localName != "page" || e.relatedNode != amlPane + || amlNode.nodeType != 1) + return; + + // Record position in settings + settings.save(); + + emit("tabOrder", { + tab: amlNode.cloud9tab, + next: (amlNode.nextSibling || 1).cloud9tab + }); + } + + if (e.relatedNode == amlPane && amlNode.localName == "page") { + // See if we are put into a fixed height container + var pNode = amlNode.parentNode; + while (pNode.localName != "bar") + pNode = pNode.parentNode; + isFixedHeight = pNode.height + && parseInt(pNode.height, 10) == pNode.height; + + // Make sure the plus button is on the end + amlPane.$buttons.appendChild(btnPlus.$ext); + } + }); + } + + /***** Methods *****/ + + function createEditor(type, callback) { + var tab = amlPane.getPage("editor::" + type); + if (cancelEditorCreate) + cancelEditorCreate(); + if (!tab) { + cancelEditorCreate = editors.createEditor(type, function(err, editor) { + editor.attachTo(amlPane.cloud9pane); + callback(null, editor); + cancelEditorCreate = null; + }); + } + else + callback(null, tab.editor); + } + + function getTab(id) { + var tab = amlPane.getPage(id); + return tab && tab.cloud9tab; + } + + function getTabs(){ + return amlPane.getPages().map(function(tab) { + return tab.cloud9tab; + }) + } + + function getEditors(){ + return (amlPane.childNodes || []) + .filter(function(p){ return p.localName == "page" && p.$ext }) + .map(function(e){ return e.editor }); + } + + function focus(){ + amlPane.focus(); + } + + function hasFocus(){ + return ui.isChildOf(apf.document.activeElement, amlPane, 1); + } + + function vsplit(far, v, split) { + return hsplit(far, true, split); + } + + function hsplit(far, vertically, split, ignore) { + if (!split || !split.parentNode) split = amlPane; + + queue = []; // Used for resizing later + + var opt = { + splitter: true, + padding: 1 + }; + + var psize = split.parentNode.$vbox ? "height" : "width"; + opt[psize] = split[psize]; + + var splitbox = new ui[vertically ? "vsplitbox" : "hsplitbox"](opt); + var parent = split.parentNode; + parent.insertBefore(splitbox, split); + splitbox.appendChild(split); + parent.register && parent.register(splitbox); + split.setAttribute(psize, ""); + var ratio = balance(splitbox, vertically, 1, ignore); + + var state = {}; + var size = vertically ? "height" : "width"; + state[size] = (ratio ? (100 * ratio) : 50) + "%"; + state.skinset = split.skinset; + state.skin = split.skin; + + var newtab = options.createPane(state).aml; + if (far) + splitbox.appendChild(newtab); + else + splitbox.insertBefore(newtab, split); + split.setAttribute(vertically ? "height" : "width", ""); + + queue.push(splitbox); + + resizeAll(); + + return newtab.cloud9pane; + } + + // Resize all editors in the queue + function resizeAll(){ + queue.forEach(function(node) { + (node.localName == "tab" + ? [node] + : node.getElementsByTagNameNS(apf.ns.aml, "tab") + ).forEach(function(n) { + var pane = n.cloud9pane; + pane.getEditors().forEach(function(editor) { + editor.resize({ type: "split" }); + }); + }); + }); + } + + function balance(splitbox, vertically, diff, ignore) { + var splits = [], type = splitbox.localName, node = splitbox; + var last, ignoreIsTopLevel; + do { + splits.push(node); + if (!ignoreIsTopLevel) + ignoreIsTopLevel = node.childNodes.indexOf(ignore) > -1; + node = (last = node).parentNode; + } while (node.localName == type); + + //Resize all left elements of the before + var total = count(last, type, ignore); + var igd = (ignoreIsTopLevel ? 1 : 0); + var factor = (total + igd) / (total + diff); + + if (splits.length == 1) + return 1 / (total + 1); + + var child, prop = vertically ? "height" : "width"; + var split, children, inverse, value; + for (var i = 1, l = splits.length; i < l; i++) { + split = splits[i]; + child = splits[i - 1]; + children = split.childNodes.filter(function(x) { + return x.localName != "splitter"; + }); + + inverse = children[0] == child; + if (children[0][prop] || !children[1]) { + node = children[0]; + } + else { + inverse = !inverse; + node = children[1]; + } + + value = parseFloat(node[prop]); + node.setAttribute(prop, inverse + ? (value + (100 - value) * (1 - factor)) + "%" + : (value * factor) + "%"); + queue.push(node); + } + } + + function count(splitbox, type, ignore) { + var total = 0; + (function walk(node) { + var nodes = node.childNodes; + for (var n, i = 0, l = nodes.length; i < l; i++) { + if ((n = nodes[i]).localName == "splitter" + || n == ignore) + continue; + + if (n.localName == "tab" || n.localName != type) + total++; + else + walk(n); + } + })(splitbox); + + return total; + } + + var config = { + "left" : [hsplit, false, "hsplitbox"], + "right" : [hsplit, true, "hsplitbox"], + "up" : [vsplit, false, "vsplitbox"], + "down" : [vsplit, true, "vsplitbox"] + } + + function moveTabToSplit(tab, direction, keep) { + var isEmpty = amlPane.getPages().length == 1; + var parent = amlPane.parentNode; + + var split = config[direction][0]; + var far = config[direction][1]; + var kind = config[direction][2]; + + queue = []; // For resizing later + + if (!isEmpty) { + // Split the current pane and attach the tab + tab.attachTo(split(far), null, true); + tab.activate(); + return; + } + + var next, grandpa = parent, tabs, node = amlPane, force, test; + if (grandpa.localName != kind) { + // Find the right stack to go to + while (grandpa.parentNode.localName != kind + && grandpa.parentNode.localName != "bar") { + grandpa = (node = grandpa).parentNode; + } + next = grandpa; //grandpa.localName == "bar" ? grandpa.firstChild : grandpa; + force = true; + } + + if (!next) { + // Find pane to move to + do { + tabs = grandpa.childNodes.filter(function(x) { + return x.localName != "splitter"; + }); + if (tabs[far ? 0 : 1] == node) { + next = tabs[far ? 1 : 0]; + break; + } + node = node.parentNode; + grandpa = grandpa.parentNode; + } while (grandpa && grandpa.localName != "bar") + } + + if (next) { + // Moving from horizontal to vertical or vice verse + if (force || next.parentNode.localName != amlPane.parentNode.localName) { + var tosplit = force || next.parentNode.localName == "bar" + ? next : next.parentNode; + tab.attachTo(split(far, null, tosplit), null, true); + tab.activate(); + + var bparent = tab.pane.aml.parentNode; + balance(bparent, bparent.localName == "vsplitbox", 0, amlPane); + } + // Move to next pane + else { + // Find the most first/last pane + if (next.localName != "tab") { + while (next.localName != "tab") + next = next.childNodes[far ? 1 : 2]; + } + tab.attachTo(next.cloud9pane, + far ? (next.getPages()[0] || 1).cloud9tab : null, true); + tab.activate(); + + balance(amlPane.parentNode, split == vsplit, 0, amlPane); + } + } + else { + var type = parent.localName; + do { + parent = parent.parentNode; + } while (parent.localName == type); + + if (parent.localName == "bar") + return; + + tab.attachTo(split(far, null, parent, amlPane), null, true); + } + amlPane.cloud9pane.unload(); + + resizeAll(); + } + + /***** Resizing *****/ + + // Resize when window resizes + function windowResize(){ + var tab = getTab(); + if (tab && tab.editor) + tab.editor.resize({ type: "window" }); + } + + layout.on("resize", windowResize, plugin); + + // Resize when resizing using a splitter + function splitterResize(e) { + var parent = e.splitter.parentNode; + + // Resize only vertically in realtime (really?) + if (!parent.$vbox && !e.final) + return; + + if (ui.isChildOf(parent, amlPane) && getTab()) { + getTab().editor.resize({ + type: "splitter", + final: e.final + }); + } + } + + apf.addEventListener("splitter.resize", splitterResize); + plugin.addOther(function(){ + apf.removeEventListener("splitter.resize", splitterResize); + }); + + // Resize when an animation happens + anims.on("animate", function(e) { + var delta, result, size; + if (e.type == "editor") { + delta = e.delta; + result = { delta: delta, vertical: true }; + } + else if (e.type == "splitbox") { + if (e.options.height !== undefined) { + if (ui.isChildOf(e.other, amlPane, true)) { + size = e.which.getHeight(); + delta = isFixedHeight ? 0 : size - parseInt(e.options.height, 10); + result = { vertical: true, own: e.other == amlPane }; + } + else if (ui.isChildOf(e.which, amlPane, true)) { + size = e.which.getHeight(); + delta = parseInt(e.options.height, 10) - size; + result = { vertical: true, own: e.which == amlPane }; + } + } + else if (e.options.width !== undefined) { + if (ui.isChildOf(e.other, amlPane, true)) { + size = e.which.getWidth(); + delta = size - parseInt(e.options.width, 10); + result = { vertical: false, own: e.other == amlPane }; + } + else if (ui.isChildOf(e.which, amlPane, true)) { + size = e.which.getWidth(); + delta = parseInt(e.options.width, 10) - size; + result = { vertical: false, own: e.which == amlPane }; + } + } + + if (result) { + result.current = size; + result.delta = delta; + } + } + + if (!result) + return; //result = { type: "generic-anim" }; + else if (result) + result.type = "anim"; + + // Grow the area prior to the animation + if (delta > 0) { + var tab = getTab(); + if (tab && tab.editor) + tab.editor.resize(result); + } + + // Emit the resize event after the animation is completed to + // hide whatever the result has covered + e.on("finish", function(){ + var tab = getTab(); + if (tab && tab.editor) + tab.editor.resize({ type: "afteranim" }); + }); + }, plugin); + + /***** Lifecycle *****/ + + plugin.on("load", function(){ + load(); + }); + + plugin.on("beforeUnload", function(){ + var idx, next, last; + var parent = amlPane.parentNode; + if (!parent) return; + var nodes = parent.selectNodes("tab|hsplitbox|vsplitbox"); + + // find the next available tab + if (nodes.length > 1) { + idx = nodes.indexOf(amlPane); + next = last = nodes[idx === 0 ? 1 : 0]; + } + else { + var p = parent.parentNode; + idx = p.childNodes.indexOf(parent); + next = last = nodes[idx === 0 ? 1 : 0]; + } + + // element is a splitbox - search for a tab + var op = idx === 0 ? "shift" : "pop"; + while (next && next.tagName != "tab") { + next = next.selectNodes("tab|hsplitbox|vsplitbox")[op](); + } + + // move all pages to another pane + getTabs().forEach(function(tab) { + tab.attachTo(next.cloud9pane, null, true); + }); + + // destroy aml element + amlPane.destroy(true, true); + + // Clean up tree + if (last) { + var place = parent.nextSibling; + var grandpa = parent.parentNode; + parent.removeChild(last); + if (parent != options.container) + parent.destroy(true, true); + grandpa.insertBefore(last, place); + + queue = [grandpa] + + var size = grandpa.$vbox ? "height" : "width"; + last.setAttribute(size, parent[size]); + size = grandpa.$vbox ? "width" : "height"; + last.setAttribute(size, ""); + } + else { + queue = [parent]; + } + + if (last && last.parentNode.localName == "bar") { + last.$ext.style.width = "100%";//setAttribute("width", "100%"); + last.$ext.style.height = "100%";//.setAttribute("height", "100%"); + } + + // This is needed because other panes will need resizing + resizeAll(); + }); + + /***** Register and define API *****/ + + /** + * Represents a pane containing tabs in Cloud9. Cloud9 + * generally has a main area that contain tabs and an area in the + * console. Both areas start of as a single pane. These panes + * can then be split using menu items or drag&drop operations. The + * splits can also be made programmatically using APIs on this class. + * + * The pane relates to other objects as such: + * + * * **Pane - Represent a single pane, housing multiple tabs** + * * {@link Tab} - A single tab (button) in a pane + * * {@link Editor} - The editor responsible for displaying the file in the tab + * * {@link Document} - The representation of a file in the tab + * * {@link Session} - The session information of the editor + * * {@link UndoManager} - The object that manages the undo stack for this document + * + * Panes can live in certain areas of Cloud9. By default these areas are: + * + * * {@link panes} - The main area where editor panes are displayed + * * {@link console} - The console in the bottom of the screen + * + * Tabs are managed by the {@link tabManager}. The default way to + * open a new file in an editor uses the tabManager: + * + * var pane = tabManager.getPanes()[0]; + * var newPane = pane.splitv(); + * + * tabManager.open({ + * path: "/file.js", + * pane: newPane + * }, function(err, tab) {}); + * + **/ + plugin.freezePublicAPI({ + /** + * The APF UI element that is presenting the pane in the UI. + * This property is here for internal reasons only. *Do not + * depend on this property in your plugin.* + * @property {AMLElement} aml + * @private + * @readonly + */ + get aml(){ return amlPane; }, + + /** + * The DOM element that is presenting the pane in the UI. + * @property {DOMElement} container + * @readonly + */ + get container(){ return amlPane.$int; }, + + /** + * Retrieves the two elements (one of which is this pane) with + * which this panel forms a split. + * @return Array + * @readonly + */ + get group(){ + function getGroup(amlPane) { + var pNode = amlPane.parentNode; + + if (pNode.localName.indexOf("splitbox") == -1) + return false; + + var result = pNode.childNodes.map(function(aml) { + return aml.cloud9pane; + }); + // result.__defineGetter__("group", function(){ + // return getGroup(pNode) + // }); + return result; + } + }, + + /** + * The active {@link Tab} of this pane. Note that "active" is + * different from "focus" (See {@link tabManager#focusTab}). + * @property {Tab} activeTab + * @readonly + */ + get activeTab(){ return getTab(); }, + + /** + * The width of the pane in pixels. It only makes sense to set + * the width of the pane in a splitview situation. + * @property {Number} width + */ + get width(){ return amlPane.width; }, + set width(v){ amlPane.setProperty("width", v); }, + + /** + * The height of the pane in pixels. It only makes sense to set + * the height of the pane in a splitview situation. + * @property {Number} height + */ + get height(){ return amlPane.height; }, + set height(v){ amlPane.setProperty("height", v); }, + + /** + * Specifies whether the panel is currently being shown. + * @property {Boolean} visible + * @readonly + */ + get visible(){ return visible; }, + set visible(v){ visible = v; }, + + /** + * Retrieves the meta object for this panel + * @property {Object} meta + */ + get meta(){ return meta; }, + + _events: [ + /** + * Fires when a tab becomes the active tab of this pane. + * + * See also {@link tabManager#tabAfterActivate}. + * + * @event afterSwitch + * @param {Object} e + * @param {Tab} e.tab the tab that has become active + * @param {Tab} e.lastTab the tab that is no longer active + */ + "afterSwitch", + /** + * Fires prior to a tab becoming the active tab of this pane. + * + * See also {@link tabManager#tabBeforeActivate}. + * + * @event beforeSwitch + * @param {Object} e + * @param {Tab} e.tab the tab that will become active + * @cancellable + */ + "beforeSwitch", + /** + * Fires prior to closing a tab in this pane. + * + * See also {@link tabManager#tabBeforeClose}. + * + * @event beforeClose + * @cancellable + */ + "beforeClose", + /** + * Fires after closing a tab in this pane. + * + * See also {@link tabManager#tabAfterClose}. + * + * @event afterClose + * @cancellable + */ + "afterClose", + /** + * Fires when a tab is moved inside this pane. + * + * See also {@link tabManager#tabOrder}. + * + * @event tabOrder + * @param {Object} e + * @param {Tab} e.tab the tab that has been moved + * @param {Tab} e.next the tab on the right of e.tab. + */ + "tabOrder" + ], + + /** + * Returns an array of all the tabs in this pane. + * + * var titles = pane.getTabs().map(function(tab) { + * return tab.document.title; + * }); + * + * console.log(titles); + * + * @returns {Tab[]} + */ + getTabs: getTabs, + + /** + * Retrieves a tab by it's path or id. When no argument is + * specified, the active tab is returned. + * + * See also {@link tabManager#findTab} + * + * @param {String} id The path or id of the tab to fetch. + * @return {Tab} + */ + getTab: getTab, + + /** + * Returns an array of all the editors that have been + * initialized in this pane. + * + * Editors are initialized when the first tab that requires that + * editor becomes active. This means that you can have 20 tabs + * in one pane with 4 different editors, yet this function only + * returns one entry, because the other tabs have not yet been + * active. + * + * @return {Editor[]} + */ + getEditors: getEditors, + + /** + * Retrieves the editor instance for this pane. If the editor + * of that type has not yet been created for this pane then + * it will be instantiated. + * + * @param {String} type the {@link Editor#type} of the editor. + * @param {Function} callback + * @param {Error} callback.err an error which made have occured. + * @param {Editor} callback.editor the editor requested. + */ + createEditor: createEditor, + + /** + * Gives focus to the active tab of this pane (if any). + */ + focus: focus, + + /** + * Whether a tab in this pane has the focus. + */ + hasFocus: hasFocus, + + /** + * Splits a pane vertically into two tabs occupying the same area. + * @param {Boolean} far When set to true the new pane is + * created in the bottom of the split, otherwise it's created + * as the top pane. + * @return {Pane} + */ + vsplit: vsplit, + + /** + * Splits a pane horizontally into two tabs occupying the same area. + * @param {Boolean} far When set to true the new pane is + * created on the right of the split, otherwise it's created + * as the left pane. + * @return {Pane} + */ + hsplit: hsplit, + + /** + * Moves a tab to a "split". This is generally achieved by the + * user using keybindings. A tab can travel across the panes and + * is inserted in newly created panes at the intersection + * between panes and to existing panes when moved even further. + * @param {Tab} tab The tab to move + * @param {String} direction Any of these strings: "left", + * "right", "up", "down". + */ + moveTabToSplit: moveTabToSplit + }); + + plugin.load(name, "pane"); + + return plugin; + } + + /***** Register and define API *****/ + + register(null, { + Pane: Pane + }); + } +}); \ No newline at end of file diff --git a/plugins/c9.ide.editors/tab.js b/plugins/c9.ide.editors/tab.js new file mode 100644 index 00000000..cba64a38 --- /dev/null +++ b/plugins/c9.ide.editors/tab.js @@ -0,0 +1,607 @@ +define(function(require, module, exports) { + main.consumes = ["Plugin", "ui", "Document", "dialog.alert", "settings"]; + main.provides = ["Tab"]; + return main; + + function main(options, imports, register) { + var Plugin = imports.Plugin; + var Document = imports.Document; + var ui = imports.ui; + + var stylesheet = ui.createStylesheet(); + + function Tab(options) { + var editorType, doc, path, amlPane, init, active, fg, bg, + title, tooltip, amlTab, closed, rule, docInited; + + var meta = {}; + var name = options.name; + + var classList = { + names: [], + get length(){ return classList.names.length; }, + contains: function(name){ + return classList.names.indexOf(name) > -1; + }, + add: function(name) { + if (name) { + var idx = this.names.indexOf(name); + if (idx > -1) return; + this.names.push(name); + } + + amlTab && amlTab.setAttribute("class", this.names.join(" ")); + }, + remove: function(){ + for (var i = 0, l = arguments.length; i < l; i++) { + var idx = this.names.indexOf(arguments[i]); + if (idx > -1) + this.names.splice(idx, 1); + } + amlTab && amlTab.setAttribute("class", this.names.join(" ")); + } + } + + function initStyleSheet(fg, bg) { + var cssClass = plugin.name.replace(/[^a-zA-Z0-9\-_\u00A0-\uFFFF]/g, "-"); + classList.add(cssClass); + + rule = "." + cssClass + ".curbtn .tab_middle, ." + + cssClass + ".curbtn .tab_middle::after, ." + + cssClass + ".curbtn .tab_middle::before"; + + ui.importStylesheet([ + [rule, "background-color:" + (bg || "inherit") + ";" + + "color:" + (fg || "inherit") + ";"] + ], window, stylesheet); + } + + /***** Initialization *****/ + + var plugin = new Plugin("Ajax.org", main.consumes); + var emit = plugin.getEmitter(); + + var loaded; + function load(){ + if (loaded) return; + loaded = true; + + // Create Tab + amlTab = new ui.page({ + id: plugin.name, // path || + type: "editor::" + editorType, + autofocus: false, + tooltip: tooltip, + caption: title, + tab: plugin, + focussable: true, + $focussable: true + }); + + if (classList.names.length) + classList.add(); + + plugin.addElement(amlTab); + + // Hack to get activate event in + var activate = amlTab.$activate; + amlTab.$activate = function(){ + activate.apply(amlTab, arguments); + emit("activate"); + }; + var deactivate = amlTab.$deactivate; + amlTab.$deactivate = function(){ + deactivate.apply(amlTab, arguments); + emit("deactivate"); + }; + + // amlTab.$doc = doc; // Backwards compatibility?? + amlTab.cloud9tab = plugin; + + if (amlPane) { + if (init) + amlPane.setAttribute("buttons", "close"); + + attachTo(amlPane.cloud9pane, null, options.noanim); + + if (init) + amlPane.setAttribute("buttons", "close,scale,order"); + } + + // Activate tab if necessary + if (active) { + if (amlPane) + amlPane.set(amlTab); // path || + else { + amlTab.on("DOMNodeInsertedIntoDocument", function insert(e) { + amlTab.parentNode.set(amlTab); + amlTab.off("DOMNodeInsertedIntoDocument", insert); + }); + } + } + + init = false; + active = false; + } + + /***** Methods *****/ + + function getState(filter) { + var state = { + type: "tab", + name: plugin.name, + path: path, + className: filterClassNames(classList.names), + document: doc.getState(filter), + editorType: editorType, + active: isActive() + }; + + emit("getState", { state : state }); + + return state; + } + + function filterClassNames(classNames) { + return classNames.filter(function(n) { + return ["error", "dark", "loading"].indexOf(n) === -1; + }); + } + + function setState(state) { + if (state.pane) + amlPane = state.pane.aml; + + init = state.init; + doc = doc + ? doc.setState(state.document) + : (state.document instanceof Plugin + ? state.document + : new Document(state.document)); + // Connect to the document + doc.tab = plugin; + + active = state.active; + + if (loaded && active) + activate(); + + plugin.editorType = state.editorType; + plugin.path = state.path; + plugin.title = doc.title || ""; + plugin.tooltip = doc.tooltip; + + if (state.className) { + classList.names = filterClassNames(state.className); + if (amlTab) + classList.add(); + } + + if (!docInited) { + doc.on("setTitle", function(e) { + plugin.title = e.title; + }, plugin); + + doc.on("setTooltip", function(e) { + plugin.tooltip = e.tooltip; + }, plugin); + + // Changed marker + var setChanged = function(e) { + if (e.changed || doc.meta.newfile) + doc.tab.classList.add("changed"); + else + doc.tab.classList.remove("changed"); + }; + doc.on("changed", setChanged, plugin); + setChanged({ changed: doc.changed }); + + docInited = true; + } + } + + function isActive(){ + return amlPane ? amlPane.getPage() == amlTab : options.active; + } + + function activate(){ + amlPane.set(amlTab); + } + + function beforeClose(e) { + return emit("beforeClose", e); + } + + function attachTo(t, nextSibling, noAnim) { + if (t.aml.localName != "tab") + throw new Error("Incorrect Element: " + t.aml.localName); + + amlPane = t.aml; + var lastPane = amlTab.parentNode; + + if (emit("beforeReparent", { + lastPane: lastPane && lastPane.cloud9pane, + pane: t + }) === false) return; + + if (lastPane != amlPane) + amlPane.skipAnimOnce = noAnim; + amlPane.insertBefore(amlTab, nextSibling && nextSibling.aml); + + apf.setStyleClass(amlPane.$ext, "", ["empty"]); + if (lastPane && !lastPane.childNodes.length) + apf.setStyleClass(lastPane.$ext, "empty"); + + emit("afterReparent", { + lastPane: lastPane && lastPane.cloud9pane, + pane: t + }); + } + + function switchEditor(type, callback) { + if (editorType == type) + return; + + // var lastType = tab.editorType; + amlPane.cloud9pane.createEditor(type, function(err, editor) { + var info = {}; + if (editor.isValid(amlTab.document, info) === false) { + alert( + info.title || "Could not switch editor", + info.head || "Could not switch editor because this document is invalid.", + info.message || "Please fix the error and try again." + ); + return; + } + + editorType = type; + amlTab.setAttribute("type", "editor::" + type); + + if (amlPane.getPage() == amlTab) { + amlPane.activepage = -1; + amlPane.set(amlTab); + } + + callback(); + }); + } + + // @todo Explain difference with unload in docs + function close(noAnim) { + amlPane.remove(amlTab, null, noAnim); + } + + /***** Lifecycle *****/ + + plugin.on("load", function(){ + load(); + }); + + plugin.on("unload", function(e) { + closed = true; + + // If there are no more pages left, reset location + var last = amlPane.getPages().length === 0; + if (last) + apf.setStyleClass(amlPane.$ext, "empty"); + + loaded = false; + + emit("close", {last: last, htmlEvent: e && e.htmlEvent}); + }); + + /***** Register and define API *****/ + + /** + * Tab Class for Cloud9 Panes. Each file that is opened + * in an editor has a tab object that allows a user to activate the + * document in an editor in a pane. Tabs can be moved between + * panes using drag&drop and key bindings. + * + * The tab relates to other objects as such: + * + * * {@link Pane} - Represent a single pane, housing multiple tabs + * * **Tab - A single tab (button) in a pane** + * * {@link Editor} - The editor responsible for displaying the file in the tab + * * {@link Document} - The representation of a file in the tab + * * {@link Session} - The session information of the editor + * * {@link UndoManager} - The object that manages the undo stack for this document + * + * Panes can live in certain areas of Cloud9. By default these areas are: + * + * * {@link panes} - The main area where editor panes are displayed + * * {@link console} - The console in the bottom of the screen + * + * Tabs are managed by the {@link tabManager}. The default way to + * open a new file in an editor uses the tabManager: + * + * tabManager.openFile("/file.js", true, function(err, tab) { + * console.log("The tab title is: ", tab.title); + * }); + */ + plugin.freezePublicAPI({ + /** + * The APF UI element that is presenting the tab in the UI. + * This property is here for internal reasons only. *Do not + * depend on this property in your plugin.* + * @property {AMLElement} aml + * @private + * @readonly + */ + get aml(){ return amlTab; }, + + /** + * The pane that this tab belongs to. This property changes when + * a tab is moved to another pane. + * @property {Pane} pane + * @readonly + */ + get pane(){ return amlPane.cloud9pane; }, + /** + * The document loaded in this tab. This property is always the + * same object. + * @property {Document} document + * @readonly + */ + get document(){ return doc; }, + /** + * Retrieves the meta object for this panel + * @property {Object} meta + */ + get meta(){ return meta; }, + /** + * The path to the file loaded into this tab. This property will + * be undefined when no path is set (for instance when no file + * was loaded to create this tab). + * @property {String} path + */ + get path(){ return path || undefined; }, + set path(v) { + var oldpath = path; + path = v; + emit("setPath", {path: path, oldpath: oldpath}); + }, + get relatedPath(){ return (this.editor || 1).relatedPath; }, + /** + * The type of the editor shown in this tab. + * + * See also {@link Editor#type} + * + * @property {String} editorType + */ + get editorType(){ + return editorType; + }, + set editorType(type) { + editorType = type; + amlTab && amlTab.setProperty("type", "editor::" + type); + }, + /** + * The title (or caption) of the tab button + * @property {String} title + */ + get title(){ + return title; + }, + set title(value) { + title = value; + amlTab && amlTab.setProperty("caption", value); + }, + /** + * The value of this property is displayed when hovering the + * mouse over the tab button. + * @property {String} tooltip + **/ + get tooltip(){ + return tooltip; + }, + set tooltip(value) { + tooltip = value; + amlTab && amlTab.setProperty("tooltip", value); + }, + /** + * The background color of the tab button and it's body. It is + * recommended to use the "rgb(r,g,b)" format. To get a light + * text color use tab.classList.add("dark") to specify a dark + * backgroundColor is used. + * @property {String} backgroundColor + */ + get backgroundColor(){ return bg }, + set backgroundColor(v) { + bg = v; + if (!rule) + return initStyleSheet(fg, bg); + ui.setStyleRule(rule, "background-color", bg, stylesheet); + }, + /** + * The foreground color of the tab button and it's body. It is + * recommended to use the "rgb(r,g,b)" format. In most cases + * this property doesn't have to be set. To get a light text + * color use tab.classList.add("dark") to specify a dark + * backgroundColor is used. + * @property {String} backgroundColor + */ + get foregroundColor(){ return bg }, + set foregroundColor(v) { + fg = v; + if (!rule) + return initStyleSheet(fg, bg); + ui.setStyleRule(rule, "color", fg, stylesheet); + }, + /** + * @property {Object} classList Object that + * manages the class names of the tab button. Often used + * class names are "loading", "saving", "error". + * @property {Function} classList.add Adds a new class name to the tab button. + * @property {String} classList.add.name The name of the class to add. + * @property {Function} classList.remove Removes a class name from the tab button. + * @property {String} classList.remove.name The name of the class to remove. + * @readonly + */ + get classList(){ + return classList; + }, + /** + * Specifies whether this tab is the active tab within the panel + * @property {Boolean} active + * @readonly + */ + get active(){ + return amlPane.getPage() == amlTab; + }, + /** + * Specifies the editor that is displayed by this tab. + * + * Note that this property changes when the tab is moved to a + * different pane. An editor is connected to a pane and thus + * when this tab is moved to a pane this property will be set to + * the editor of that pane. + * + * @property {Editor} editor + * @readonly + */ + get editor(){ + if (amlPane.$amlDestroyed) + return false; + + var editorTab = amlPane.getPage("editor::" + editorType); + + // During destroy of pane, a tab that used to have an editor + // can find itself without one. There is only one way to + // detect that, which is when this getter returns false + if (!editorTab) + return false; + + return editorTab.editor; + }, + + _events: [ + /** + * Fires before the tab is closed + * @event beforeClose + * @cancellable + */ + "beforeClose", + /** + * Fires when this tab becomes the active tab of it's pane parent. + * + * Note that this event is fired early, often before the editor is initialized. + * For most cases you want to use the {@link tabManager#tabAfterActivate} or + * {@link tabManager#tabAfterActivateSync} events on the {@link tabManager} plugin. + * + * @event activate + */ + "activate", + /** + * Fires when the state of this tab is retrieved + * @event getState + * @param {Object} e + * @param {Object} e.state The state of the tab, it's document and underlying objects. + */ + "getState", + /** + * Fires when the path of this tab is updated. This happens + * when the {@link Tab#path} property is set (i.e. + * when the file that has opened this tab is renamed). + * @event setPath + * @param {Object} e + * @param {String} e.path The new path for this tab + * @param {String} e.oldpath The path that this tab had prior to setting the new path + */ + "setPath", + /** + * Fires prior to attaching this tab to a pane + * @event beforeReparent + * @cancelable + * @param {Object} e + * @param {Pane} e.lastPane The previous pane that this tab was part of + * @param {Pane} e.pane The pane this tab is moved to + */ + "beforeReparent", + /** + * Fires prior to attaching this tab to a pane + * @event afterReparent + * @param {Object} e + * @param {Pane} e.lastPane The previous pane that this tab was part of + * @param {Pane} e.pane The pane this tab is moved to + */ + "afterReparent", + /** + * @event close Fires when this tab closes + * @param {Object} e + * @param {Boolean} e.last Specifies whether this tab was + * the last tab of the pane to be closed + * (e.g. the pane has no tabs left). + */ + "close" + ], + + /** + * Sets this tab as the active tab on it's pane + */ + activate: activate, + + /** + * Checks whether this tab is actve in it's pane + * @return {Boolean} + */ + isActive: isActive, + + /** + * Retrieves the state of the tab. + * + * @return {Object} + * @return {String} [return.type="tab"] This is always the string "tab" + * @return {String} return.name The {@link Plugin#name} name of the tab plugin + * @return {String} return.path The path of this tab + * @return {Object} return.document The returned object of {@link Document#getState}. + * @return {String} return.editorType The {@link Editor#type} of the editor + * @return {Boolean} return.active Specifies whether the tab was active when the state was retrieved. + */ + getState: getState, + + /** + * Moves this tab to a pane + * @param {Pane} pane The pane to move this tab to. + * @param {Tab} [nextSibling] The tab that will be on the right of this tab after it has been inserted. + */ + attachTo: attachTo, + + /** + * Changes the editor that is used to display the content of + * the document of this tab to another editor. This can be + * useful when multiple editors can display the same content + * (i.e. displaying an image in a hex editor). + * + * @param {String} editorType Specifies the {@link Editor#type} of the editor to switch to + * @param {Function} callback + */ + switchEditor: switchEditor, + + /** + * Closes this tab. Closing a tab will destroy all it's content + * and state. + */ + close: close, + + /** + * @ignore + */ + beforeClose: beforeClose + }); + + if (options) + setState(options); + + plugin.load(name, "tab"); + + return plugin; + } + + /***** Register and define API *****/ + + register(null, { + Tab: Tab + }); + } +}); \ No newline at end of file diff --git a/plugins/c9.ide.editors/tab_test.js b/plugins/c9.ide.editors/tab_test.js new file mode 100644 index 00000000..51df933d --- /dev/null +++ b/plugins/c9.ide.editors/tab_test.js @@ -0,0 +1,136 @@ +/*global describe:false, it:false */ + +"use client"; + +require(["lib/architect/architect", "lib/chai/chai"], function (architect, chai) { + var expect = chai.expect; + + expect.setupArchitectTest([ + "plugins/c9.core/ext", + "plugins/c9.core/util", + "plugins/c9.ide.dialog/dialog", + "plugins/c9.ide.dialog.common/alert", + "plugins/c9.ide.dialog.common/alert_internal", + "plugins/c9.ide.ui/ui", + "plugins/c9.ide.ui/lib_apf", + "plugins/c9.ide.editors/tab", + "plugins/c9.ide.editors/document", + "plugins/c9.ide.ui/focus", + "plugins/c9.ide.editors/undomanager", // Mock plugins + { + consumes: ["apf", "ui", "Plugin"], + provides: [ + "commands", "settings" + ], + setup: expect.html.mocked + }, + + //Mock Plugins + { + consumes: [], + provides: ["c9"], + setup: expect.html.mocked + }, + { + consumes: ["ui", "Plugin"], + provides: ["layout"], + setup: expect.html.mocked + }, + { + consumes: ["Tab", "ui", "Document"], + provides: [], + setup: main + } + ], architect); + + function main(options, imports, register) { + var Tab = imports.Tab; + var Document = imports.Document; + var ui = imports.ui; + + var page1, page2; + var pane = {} + pane.aml = { + cloud9pane: pane, + setAttribute: function(){}, + getPages: function(){ return [page1, page2] }, + getPage: function(){ return pane.active.aml }, + set: function(tab){pane.active = tab.cloud9tab}, + localName: "tab", + insertBefore: function(){ + if (this.oninsert) this.oninsert(); + } + }; + + // @todo all these tests for tabs without a path + + describe('tab', function() { + it('should load it\'s state from the constructor', function(done) { + page1 = new Tab({ + editorType: "test", + document: { + value: "test", + title: "test", + tooltip: "test" + }, + path: "test/test/test.txt", + pane: pane, + init: true, + active: true + }); + + expect(page1.document.value, "docvalue").to.equal("test"); + expect(page1.document.changed).to.equal(false); + expect(page1.path).to.equal("test/test/test.txt"); + expect(page1.editorType).to.equal("test"); + expect(page1.title, "title").to.equal("test"); + expect(page1.tooltip, "tooltip").to.equal("test"); + + done(); + }); + it('should set changed to true when a change occurs', function(done) { + page1.document.undoManager.add({undo:function(){}, redo:function(){}}) + expect(page1.document.changed).to.equal(true); + done(); + }); + it('should be able to bind itself to a pane', function(done) { + page2 = new Tab({ + editorType: "test", + document: { value: "test" }, + path: "test/test/test.txt" + }); + + pane.aml.oninsert = function(){ + done(); + pane.aml.oninsert = null; + } + + page2.attachTo(pane); + }); + it('should be able to set itself active', function(done) { + page2.activate(); + expect(pane.active).to.equal(page2); + done(); + }); + it('should emit getState when calling getState', function(done) { + page2.on("getState", function(e) { + expect(e.state.active).to.equal(true); + done(); + }); + + page2.getState(); + }); + it('should destroy all ui elements when it is unloaded', function(done) { + page1.unload(); + page2.unload(); + + expect(page1.aml.$amlDestroyed).to.ok; + expect(page2.aml.$amlDestroyed).to.ok; + + done(); + }); + }); + + onload && onload(); + } +}); \ No newline at end of file diff --git a/plugins/c9.ide.editors/tabmanager.js b/plugins/c9.ide.editors/tabmanager.js new file mode 100644 index 00000000..5f7f8b3d --- /dev/null +++ b/plugins/c9.ide.editors/tabmanager.js @@ -0,0 +1,1947 @@ +define(function(require, module, exports) { + main.consumes = [ + "Plugin", "menus", "settings", "layout", "ui", "commands", "fs", + "Tab", "editors", "Pane", "watcher", "c9", "dialog.alert", + "focusManager", "util" + ]; + main.provides = ["tabManager"]; + return main; + + function main(options, imports, register) { + var Plugin = imports.Plugin; + var Tab = imports.Tab; + var Pane = imports.Pane; + var ui = imports.ui; + var fs = imports.fs; + var c9 = imports.c9; + var settings = imports.settings; + var util = imports.util; + var menus = imports.menus; + var editors = imports.editors; + var commands = imports.commands; + var layout = imports.layout; + var watcher = imports.watcher; + var focusManager = imports.focusManager; + var alert = imports["dialog.alert"].show; + + var basename = require("path").basename; + + /***** Initialization *****/ + + var plugin = new Plugin("Ajax.org", main.consumes); + var emit = plugin.getEmitter(); + emit.setMaxListeners(100); + + var loadFilesAtInit = options.loadFilesAtInit; + + var PREFIX = "/////"; + var XPREVIEW = /(tar\.gz|tar|tgz|zip)$/; + + var unfocussed = true; + var showTabs = true; + var panes = []; // aml pane elements + var tabs = {}; // Tab objects (non-aml) + var containers = []; + var counter = 1; + + var focussedTab, previewTab, previewTimeout; + var container, mnuEditors, collapsedMenu; + + // Ref to focusManager - this will be changed later + focusManager.tabManager = plugin; + + var loaded = false, changed = false; + function load(){ + if (loaded) return false; + loaded = true; + + draw(); + + // Commands & Menus + + commands.addCommand({ + name: "toggleButtons", + group: "Tabs", + exec: function(e) { + toggleButtons(); + } + }, plugin); + + // commands.addCommand({ + // name : "newfile", + // group : "Tabs", + // exec : function(e) { + // plusNewFile({}, true); + // } + // }, plugin); + + function getEditor(){ + var editor = focussedTab && focussedTab.editor; + var subeditor = editor && editor.focussedWidget; + return subeditor && subeditor.editor || editor; + } + commands.on("getEditor", getEditor, plugin); + menus.on("getEditor", getEditor, plugin); + + menus.addItemByPath("View/Tab Buttons", new apf.item({ + type: "check", + checked: "user/tabs/@show", + command: "toggleButtons" + }), 300, plugin); + + menus.on("focusEditor", function(){ + focussedTab && focussedTab.editor.focus(); + }, plugin); + + // Filesystem hooks + + fs.on("beforeRename", function(e) { + var oldPath = e.args[0]; + var newPath = e.args[1]; + + var changed = []; + Object.keys(tabs).forEach(function(id) { + var tab = tabs[id]; + if (tab.path && tab.path.indexOf(oldPath) === 0) { + var char = tab.path.charAt(oldPath.length); + // Make sure that a path like /Untitled1 is not matched + // by a path like /Untitled, which are clearly different + // files with no relation to each other + if (!char || char == "/") { + tab.path = tab.path.replace(oldPath, newPath); + changed.push(tab); + } + } + }); + + if (changed.length) { + e.revert = function(){ + changed.forEach(function(tab) { + // TODO store id instead of tab + // var tab = pages[id]; + tab.path = tab.path.replace(newPath, oldPath); + }); + }; + } + }); + fs.on("afterRename", function(e) { + if (e.error && e.revert) + e.revert(); + }); + function removeTab(e) { + if (!e.error) { + var tab = findTab(e.path); + tab && tab.unload(); + } + } + fs.on("afterUnlink", removeTab); + fs.on("afterRmfile", removeTab); + fs.on("afterRmdir", function(e) { + var path = e.path; + Object.keys(tabs).forEach(function(id) { + var tab = tabs[id]; + if (tab.path && tab.path.indexOf(path) === 0) { + tab.unload(); + } + }); + }); + // Close a pane when it doesn't open + // @todo this should probably be interactive (unless during init) + // @todo move this to tabbehaviours? + fs.on("error", function(e) { + if (e.name == "readFile") { + var tab = findTab(e.path); + if (tab) + tab.unload(); + } + }, plugin); + + // Disconnect handler + var disconnected; + c9.on("disconnect", function(e) { + disconnected = true; + }); + c9.on("connect", function(e) { + if (disconnected) + checkAllTabs(); + disconnected = false; + }); + + // Editors menu handling + + editors.on("menuClick", function(e) { + if (!editors.findEditor(e.value).fileExtensions.length) + openEditor(e.value, true, function(){}); + else if (focussedTab) + focussedTab.switchEditor(e.value, function(){}); + }); + editors.on("menuShow", function(e) { + var group, editor = focussedTab && focussedTab.editor; + e.menu.childNodes.forEach(function(node) { + group = node.group; + + var path = focussedTab && focussedTab.path || ""; + var ext = path.substr(path.lastIndexOf(".") + 1); + + var type = node.value; + var extensions = editors.findEditor(type).fileExtensions; + var isAvailable = editors.defaultEditor == type + || extensions.indexOf(ext.toLowerCase()) > -1 + || !extensions.length; + + node.setAttribute("disabled", !isAvailable); + }); + + if (editor && group) + group.setValue(editor.type); + }); + + // Settings + var firstTime = true; + settings.on("read", function(e) { + // Defaults + settings.setDefaults("user/tabs", [ + ["show", "true"], + ["title", "false"], + ["asterisk", "false"] + ]); + settings.setDefaults("state/tabs", []); + + // Corner Handling + collapsedMenu = settings.getBool("state/menus/@minimized"); + + if (e.reset) { + setCornerPadding(); + return; + } + + // Create new tabs + var state = settings.getJson("state/tabs"); + if (!state) { + state = { + type: "pane", + nodes: [] + }; + } + + setTimeout(function() { + // Only set the state if we're not testing something else + if (options.testing != 2 && firstTime) { + setState(state, firstTime, function(){ + emit.sticky("ready"); + }); + firstTime = false; + } + + showTabs = settings.getBool("user/tabs/@show"); + toggleButtons(showTabs); + }, 0); + + if (settings.getBool("user/tabs/@asterisk")) + ui.setStyleClass(container, "asterisk"); + + changed = false; + + }, plugin); + + settings.on("write", function(e) { + if (!changed && !e.unload) + return; + + // When testing another component, don't save state + if (options.testing != 2) { + var state = getState(null, true); + settings.setJson("state/tabs", state); + } + + changed = false; + }, plugin); + + settings.on("user/tabs/@asterisk", function(value) { + containers.forEach(function(container) { + if (value) + ui.setStyleClass(container, "asterisk"); + else + ui.setStyleClass(container, "", ["asterisk"]); + }); + }); + + // Top Right Corner Handling + var CSS1 = ".editor_tab.morepadding .btnsesssioncontainer"; + var CSS2 = ".editor_tab .btnsesssioncontainer"; + var clearAnim = function(prop){ + setTimeout(function(){ + ui.setStyleRule(prop, "transition-duration", "0"); + }, 200); + }; + + menus.on("minimize", function(){ + collapsedMenu = true; + + ui.setStyleRule(CSS1, "transition-duration", ".2s"); + clearAnim(CSS1); + + setCornerPadding(); + }); + menus.on("restore", function(){ + collapsedMenu = false; + if (lastCorner) { + ui.setStyleRule(CSS2, "transition-duration", ".2s"); + clearAnim(CSS2); + + ui.setStyleClass(lastCorner.$ext, "", ["morepadding"]); + lastCorner = null; + } + }); + + // Focus Handling + apf.addEventListener("movefocus", function(e) { + var iter = e.toElement, list = [], c = 0; + + if (iter && iter.localName == "menu") + return; + + while (iter && containers.indexOf(iter) == -1) + iter = (list[c++] = iter).parentNode; + if (!iter) { + // Editor can be unset during unload of tabs + if (!unfocussed && focussedTab && focussedTab.editor) { + focussedTab.editor.focus(false, true); + unfocussed = true; + } + return; + } + + for (var pane, i = list.length - 1; i >= 0; i--) { + if ((pane = list[i]).localName == "tab") { + if (pane.getPages().length < 1 + || !pane.cloud9pane.visible) + continue; + + var newFocus = pane.getPage().cloud9tab; + if (newFocus != focussedTab || unfocussed) { + var soft = e.toElement != newFocus.aml ? 2 : 0; + focusTab(newFocus, soft); + } + unfocussed = false; + + iter.$activePaneName = pane.cloud9pane.name; + + return; + } + } + + focusTab(); // Blur + }); + + // Title + if (!c9.local) { + plugin.on("focusSync", function(e){ updateTitle(e.tab) }); + plugin.on("tabDestroy", function(e){ if (e.last) updateTitle(); }); + settings.on("user/tabs", function(){ updateTitle(focussedTab); }); + } + } + + var drawn = false; + function draw(){ + if (drawn) return; + drawn = true; + + // Don't draw Tabs if we're testing something that just depends + // on this plugin + if (options.testing != 2) { + container = layout.findParent(plugin).appendChild(new ui.bar({ + "class" : "codeditorHolder", + "style" : "height:100%" + //style : "position:absolute;" + })); + containers.push(container); + plugin.addElement(container); + } + + mnuEditors = apf.document.documentElement.appendChild(new ui.menu({ + id: "mnuEditors", + style: "margin: 0px 0 0 4px", + "onprop.visible" : function(e) { + if (e.value) + mnuEditors.pane = this.opener.parentNode.cloud9pane; + } + })); + plugin.addElement(mnuEditors); + + menus.addItemToMenu(mnuEditors, + new ui.item({ + caption: "New File", + hotkey: "{commands.commandManager.newfile}", + onclick: function(e) { + e.pane = this.parentNode.pane; + plusNewFile(e, true); + }, + enabled: !c9.readonly + }), 100, plugin); + + emit("draw"); + } + + function plusNewFile(e, force) { + if (force || emit("plusClick", e) !== false) { + var name; + do{ name = "/Untitled" + counter++; } while (findTab(name)); + + open({ + path: name, + active: true, + pane: e.pane, + value: "", + document: { + meta: { + newfile: true + } + } + }, function(){}); + } + } + + function createPane(state) { + state.createPane = createPane; + state.container = container; + + var pane = new Pane(state); + + pane.on("beforeSwitch", onbeforeswitch); + pane.on("afterSwitch", onafterswitch); + + var btnPlus = pane.getElement("btnPlus"); + btnPlus.setAttribute("submenu", mnuEditors); + + pane.on("beforeClose", function(e) { + return emit("tabBeforeClose", e); + }); + pane.on("afterClose", function(e) { + return emit("tabAfterClose", e); + }); + + pane.on("tabOrder", function(e) { + changed = true; + settings.save(); + + return emit("tabOrder", e); + }); + + pane.on("unload", function(){ + panes.remove(pane); + + if (focussedTab && !focussedTab.isActive()) { + if (!panes.length) { + focussedTab = null; + unfocussed = true; + } + else + focusTab(panes[0].getTab(), true); + } + + emit("paneDestroy", { pane: pane }); + + setCornerPadding(); + + changed = true; + settings.save(); + }); + + panes.push(pane); + + pane.aml.once("DOMNodeInsertedIntoDocument", function(){ + emit.sticky("paneCreate", { pane: pane }, pane); + }); + + changed = true; + settings.save(); + + return pane; + } + + function updateTitle(tab) { + document.title = tab && settings.getBool("user/tabs/@title") && tab.title + ? tab.title + " - Cloud9" + : c9.projectName + " - Cloud9"; + } + + var lastCorner; + function setCornerPadding(){ + if (!collapsedMenu || c9.local) return; + + var tab = (function recur(node){ + if (!node) + return false; + else if (node.localName == "tab") + return node; + else if (node.$vbox) + return recur(node.getFirstChild()); + else + return recur(node.getSecondChild() || node.getFirstChild()); + })(container.childNodes[0]); + + if (!tab || tab == lastCorner) + return; + + if (lastCorner) + ui.setStyleClass(lastCorner.$ext, "", ["morepadding"]); + + ui.setStyleClass(tab.$ext, "morepadding"); + + lastCorner = tab; + } + + function createTab(state){ + if (!state.pane) { + if (focussedTab && ui.isChildOf(container, focussedTab.aml)) { + state.pane = focussedTab.pane; + } + if (!state.pane) { + var i = 0; + while (panes[i] && !ui.isChildOf(container, panes[i].aml)) { i++ } + state.pane = panes[i]; + } + if (!state.pane) { + throw new Error("Called open too early. Please wait until " + + "a pane is available. Use the ready event."); + } + } + + var tab = new Tab(state); + + var id = !tab.document.meta.cloned && tab.path + ? tab.path + : PREFIX + tab.name; + tabs[id] = tab; + + tab.on("close", function(e) { + var id = !tab.document.meta.cloned && tab.path + ? tab.path + : PREFIX + tab.name; + delete tabs[id]; + + if (tab.path) + watcher.unwatch(tab.path); + + if (!(function(){for (var p in tabs){return true;}})()) { + focusTab(); + focussedTab = null; + unfocussed = true; + } + else if (!tab.pane.getTabs().length) { + if (panes.every(function(pane) { + if (pane.activeTab && pane.visible) { + focusTab(pane.activeTab); + return false; + } + return true; + })) focusTab(); // blur + } + + if (tab.document.canUnload() !== false) + tab.document.unload(); + + emit("tabDestroy", { + tab: tab, + last: e.last, + htmlEvent: e.htmlEvent + }); + + changed = true; + settings.save(); + }); + + tab.on("setPath", function(e) { + var meta = tab.document.meta; + if (!meta.preview && !meta.ignoreState && !meta.cloned) { + watcher.unwatch(e.oldpath); + watcher.watch(e.path); + } + + if (!meta.cloned) { + if (tabs[PREFIX + tab.name]) + delete tabs[PREFIX + tab.name]; + delete tabs[e.oldpath]; + tabs[e.path] = tab; + } + + updateTitle(tab); + + changed = true; + settings.save(); + }); + + tab.on("beforeReparent", function(e) { + e.tab = tab; + return emit("tabBeforeReparent", e); + }); + tab.on("afterReparent", function(e) { + e.tab = tab; + emit("tabAfterReparent", e); + }); + + // Only watch pages with paths. Newfiles first need to be saved + if (tab.path) { + var meta = tab.document.meta; + if (meta.newfile) { + fs.on("afterWriteFile", function startWatch(e) { + if (e.path == tab.path) { + watcher.watch(tab.path); + fs.off("afterWriteFile", startWatch); + } + }, tab); // Only exists for the lifetime of the tab + } + else { + // Previewed files shouldn't be watched + if (!meta.preview && !meta.ignoreState && !meta.nofs && !meta.cloned) + watcher.watch(tab.path); + else + console.warn("[watchers] ignoring preview/ignoreState tab " + tab.path); + } + } + + emit.sticky("tabCreate", { tab: tab }, tab); + + changed = true; + settings.save(); + + return tab; + } + + /* Event Handlers */ + + function onbeforeswitch(e) { + var amlPane = e.pane.aml; + var tab = e.tab; + + var editorTab = amlPane.getPage(tab.aml.type); + if (!editorTab) return; + + if (emit("tabBeforeActivate", { + tab: tab + }) === false) + return false; + } + + function onafterswitch(e) { + var tab = e.tab; + + if (!loaded || tab.document.meta.preview) + return; + + var lastTab = focussedTab; + + if (!focussedTab || focussedTab.pane == tab.pane && focussedTab != tab) + focusTab(tab, true, true); + + // Undocumented + emit("tabAfterActivateSync", { + lastTab: lastTab, + tab: tab + }); + + setTimeout(function(){ + emit("tabAfterActivate", { + lastTab: lastTab, + tab: tab + }); + + changed = true; + settings.save(); + }, 500); + } + + /***** Methods *****/ + + function getState(subcontainer, filter) { + var state = (function recur(node) { + if (!node) return; + + var name = node.localName; + var isPane = name == "tab"; + if (isPane) name = "pane"; + + var state = { + type: name, + name: isPane ? node.cloud9pane.name : undefined, + nodes: node.childNodes + .filter(function(child) { + if (isPane + && (child.localName != "page" || !child.visible) + || child.localName == "splitter") + return false; + + // Exclude previewing pages; + var tab = child.cloud9tab; + return !tab || !tab.document.meta.preview + && !tab.document.meta.ignoreState; + }) + .map(function(child) { + return isPane + ? child.cloud9tab.getState(filter) + : recur(child); + }) + }; + + if (node.width) state.width = node.width; + if (node.height) state.height = node.height; + if (node.skin) state.skin = node.skin; + if (node.skinset) state.skinset = node.skinset; + + if (isPane && node.cloud9pane.meta) { + var meta = node.cloud9pane.meta; + for (var prop in meta) { + if (prop.charAt(0) != "$") { + if (!state.meta) + state.meta = {}; + state.meta[prop] = meta[prop] && meta[prop].toJson + ? meta[prop].toJson() : meta[prop]; + } + } + } + + return state; + })(subcontainer || container.firstChild); + + if (state) + state.focus = focussedTab + && (focussedTab.path || focussedTab.name); + + return state; + } + + function setState(state, init, callback) { + if (typeof init == "function") { + callback = init; + init = false; + } + + // Remove all existing tabs + if (!init && !options.testing) + clear(); + + var count = 0; + + // Load State + (function recur(parent, list) { + list.forEach(function(state) { + var p; + + if (state.type == "pane") { + state.preventAutoActivate = state.nodes.length > 0; + p = createPane(state).aml; + parent.appendChild(p); + } + else if (state.type == "hsplitbox" || state.type == "vsplitbox") { + p = parent.appendChild(new ui[state.type]({ + splitter: true, + padding: 1, + width: state.width, + height: state.height + })); + } + else if (state.type == "tab") { + var tab = findTab(state.id); + if (!tab) { + state.pane = parent.cloud9pane; + state.init = init; + + count++; + open(state, function(err, tab) { + if (!--count) + callback(); + }); + } + else { + tab.attachTo(parent); + } + return; + } + recur(p, state.nodes); + + // If somehow we didn't record an active tab, + // set the first tab as active. + if (state.type == "pane") { + var pane = p.cloud9pane; + if (!pane.activeTab) { + var next = pane.getTabs()[0]; + next && next.activate(); + } + } + }); + })(state.container || container, [state]); + + // Set Focus + if (state.focus) + focusTab(findTab(state.focus)); + + setCornerPadding(); + + if (!count) + callback(); + } + + function clear(soft, clearTabs /* For testing only */){ + var list = getPanes(container); + + for (var i = list.length - 1; i >= 0; i--) { + var pane = list[i], nodes = pane.getTabs(); + for (var j = nodes.length - 1; j >= 0; j--) { + var tab = nodes[j]; + if (!soft) tab.unload(); + else { + tab.aml.parentNode.removeChild(tab.aml); + tab.pane = null; + } + } + // if (i > 0) + pane.unload(); + } + if (!soft || clearTabs) tabs = []; + panes = []; + } + + function toggleButtons(to) { + showTabs = to !== undefined ? to : !showTabs; + + settings.set("user/tabs/@show", showTabs); + emit("visible", {value: showTabs}); + + getPanes(container).forEach(function(pane) { + ui.setStyleClass(pane.aml.$ext, showTabs ? "" : "notabs", ["notabs"]); + }); + } + + var closeTimer; + function resizePanes(cancel) { + clearTimeout(closeTimer); + + if (cancel) + return; + + closeTimer = setTimeout(function(){ + panes.forEach(function(pane) { + pane.aml.$waitForMouseOut = false; + pane.aml.$scaleinit(null, "sync"); + }); + }, 500); + } + + function activateTab(tab) { + if (typeof tab == "string") + tab = findTab(tab); + + tab.activate(); + + return tab; + } + + function focusTab(tab, soft, async) { + if (typeof tab == "string") + tab = findTab(tab); + + if (previewTab && tab != previewTab) + preview({ cancel: true }); + + // do not focus a tab during close animation + if (tab && tab.meta && tab.meta.$closing) { + // Focus + if (focussedTab && (!soft || soft !== 2 && !unfocussed) && focussedTab.editor) { + unfocussed = false; + focussedTab.editor.focus(); + } + + return tab; + } + + if (focussedTab != tab) { + // Blur + if (focussedTab) { + var blurTab = focussedTab; + var blur = function (){ + emit("blur", { tab: blurTab }); + + // During destroy of the pane the editor can + // not exist for a tab + if (blurTab.editor && focussedTab + && blurTab.editor != focussedTab.editor) + blurTab.editor.blur(); + }; + + blurTab.classList.remove("focus"); + + blur(); + } + + if (!tab) { + focussedTab = null; + unfocussed = true; + return; + } + + // Change focussedTab + focussedTab = tab; + + tab.activate(); + + // Focus + if ((!soft || soft !== 2 && !unfocussed) && focussedTab.editor) { + unfocussed = false; + focussedTab.editor.focus(); + } + + focussedTab && focussedTab.classList.add("focus"); + } + else { + if (!focussedTab) + return; + + if ((!soft || soft !== 2 && !unfocussed) && focussedTab.editor) { + unfocussed = false; + focussedTab.editor.focus(true); + } + + return tab; + } + + emit("focusSync", { tab : tab }); + + if (async) { + setTimeout(function(){ + emit("focus", { tab : tab }); + }, 500); + } + else + emit("focus", { tab : tab }); + + return tab; + } + + function findTab(path) { + return tabs[PREFIX + path] || tabs[util.normalizePath(path)]; + } + + function getTabs(container) { + var result = Object.keys(tabs).map(function(path) { + return tabs[PREFIX + path] || tabs[path]; + }); + + if (!container) + return result; + + return result.filter(function(tab) { + return ui.isChildOf(container, tab.aml); + }); + } + + function findPane(name) { + for (var i = 0; i < panes.length; i++) { + if (panes[i].name == name) + return panes[i]; + } + } + + function getPanes(container) { + return !container + ? panes.slice() + : panes.filter(function(pane) { + return ui.isChildOf(container, pane.aml); + }); + } + + /**** Main entry point for opening tabs ****/ + + // Handler to show loading indicator + function setLoading(tab) { + tab.classList.add("loading"); + + // TODO this gets called for things that have nothing to do + // with filesystem :( + if (!tab.path) + return; + + var loadStartT = Date.now(); + fs.on("downloadProgress", function progress(e) { + if (e.path == tab.path) { + e.dt = Date.now() - loadStartT; + tab.document.progress(e); + if (e.complete) + fs.off("downloadProgress", progress); + } + }); + // TODO move to fs + // tab.document.progress({dt: 0, loaded: 0, total: 1}); + } + + function openFile(path, active, callback) { + if (typeof active == "function") + callback = active, active = false; + + return open({path: path, active: active}, callback); + } + + function openEditor(type, active, callback) { + if (typeof active == "function") + callback = active, active = false; + + return open({editorType: type, active: active}, callback); + } + + function open(options, callback) { + var path = options.path = util.normalizePath(options.path); + var type = options.editorType; + var editor; + + // If a tab for this file already exist, activate it + var id = !options.forceNew && !options.init && path || options.name; + var tab = options.tab || (id + ? findTab(id) + : options.demandExisting + && getTabs().filter(function(t) { + return t.editorType === options.editorType + && (!options.title || (t.document + && t.document.title === options.title)); + })[0]); + + // Clone Tab + if (((options.document || 0).meta || 0).cloned) { + if (!tab) { + if (options.init) { + plugin.on("open", function wait(e){ + if (e.tab.path == path) { + plugin.off("open", wait); + options.tab = e.tab; + open(options, callback); + } + }, plugin); + return; + } + else { + throw new Error("Missing tab when cloning"); + } + } + + options.path = path = tab.path; + options.editorType = tab.editorType; + options.document = tab.document.clone(); + + // Tab variable will be overwritten below + tab.on("unload", function(){ tab.unload(); }, tab.document); + } + // Process Existing Tab + else if (tab) { + if (tab.document.meta.preview) + keepPreview(); + + if (options.active) + tab.activate(); + if (options.focus) + focusTab(tab, options.focus !== true); + if (options.document) + tab.document.setState(options.document); + callback && callback(null, tab, null, true); + return tab; + } + + // Find editor + if (!type) { + editor = path && editors.findEditorByFilename(path) + || editors.findEditor(editors.defaultEditor); + type = editor && editor.type || editors.defaultEditor; + } + else { + editor = editors.findEditor(type); + } + + // Set sensible defaults + if (typeof path != "string") + options.path = null; + if (!options.document) + options.document = {}; + if (path && !options.document.title) { + options.document.title = basename(path); + options.document.tooltip = path; + } + if (typeof options.value == "string") + options.document.value = options.value; + // if (options.document.filter === undefined) + // options.document.filter = true; + options.editorType = type; + + // Create the tab + tab = createTab(options); + + // Focus + if (options.focus) + focusTab(tab, options.focus !== true); + + var doc = options.document; + var loadFromDisk = path + && (!doc || doc.value === undefined) + && options.value === undefined + // autoload to false prevents loading data, used by image editor + && (!editor || editor.autoload !== false); + + // Handler to be used after content and state is loaded + function done(err, value) { + tab.classList.remove("loading"); + + if (err) { + tab.classList.add("error"); + tab.document.meta.error = true; + + alert("Error opening file", + "Could not open file: " + tab.path, + err.code == "ENOENT" + ? "The file could not be found on the file system." + : "Unknown error: " + (err.message || err.code || err), + function(){ + tab.close(); + callback && callback(err); + }); + + return; + } + + var doc = tab.document; + if (typeof value == "string") + doc.value = value; + + // Set timestamp to now() to indicate that the file has been + // loaded from disk without any changes + if (!doc.meta.timestamp) + doc.meta.timestamp = Date.now() - settings.timeOffset; + + emit("open", { tab: tab, options: options }); + callback && callback(null, tab); + } + + if (loadFilesAtInit === false && options.init + && emit.listeners("beforeOpen").length === 0) + return tab; + + // Hooks for plugins that want to override value and state loading + var event = { + options: options, + tab: tab, + loadFromDisk: loadFromDisk, + setLoading: setLoading, + callback: done + }; + if (emit("beforeOpen", event) === false) + return tab; + + // todo why metadata does this? + loadFromDisk = event.options.loadFromDisk = loadFromDisk + && !tab.document.meta.newfile + && !tab.document.meta.nofs; + + // If no value is specified, lets load it from storage + // todo metadata doesn't check for this! should we? + if (options.value === -1) { + setLoading(tab); + callback(null, tab, function(){ + tab.classList.remove("loading"); + emit("open", { tab: tab, options: options }); + }); + } + else if (loadFromDisk) { + setLoading(tab); + var xhr = fs.readFile(path, "utf8", done); + + // Cancel file opening when tab is closed + var abort = function(){ + xhr && xhr.abort(); + }; + tab.on("close", abort); + plugin.on("open", function(e) { + if (e.tab == tab) + tab.off("close", abort); + }); + } + else { + done(null, null); + } + + return tab; + } + + function clone(tab, pane, callback){ + open({ + pane: pane, + tab: tab, + focus: true, + document: { + meta: { cloned: true } + } + }, function(err, tab){ + if (tab) + tab.document.progress({ complete: true }); + callback(err, tab); + }); + } + + function reload(tab, callback) { + if (!tab) tab = focussedTab; + if (!tab || !tab.path) + return callback(); + + if (tab.editor.autoload === false) { + tab.document.setBookmarkedValue(tab.document.value); + + delete tab.document.meta.error; + tab.classList.remove("error"); + tab.classList.remove("loading"); + emit("reload", { tab: tab }); + + return callback(); + } + + setLoading(tab); + + fs.readFile(tab.path, "utf8", function(err, data) { + if (err) { + tab.classList.remove("loading"); + tab.classList.add("error"); + tab.document.meta.error = true; + callback(err); + return; + } + + // Update val + tab.document.setBookmarkedValue(data); + tab.document.meta.timestamp = Date.now() - settings.timeOffset; + + // Make sure the newfile flag is gone + delete tab.document.meta.newfile; + + // Remove the error flag + delete tab.document.meta.error; + + tab.classList.remove("error"); + tab.classList.remove("loading"); + emit("reload", { tab: tab }); + callback(); + }); + } + + function checkAllTabs() { + getTabs().forEach(function(tab) { + var meta = tab.document.meta; + if (tab.path && !meta.newfile && !meta.preview && !meta.ignoreState && !meta.nofs) + watcher.check(tab.path, meta.timestamp); + }); + } + + var lastPreviewTab; + function preview(options, callback) { + var pane; + + // Cancel previewing and show focussedTab again + if (options.cancel) + return cancelPreview(options.keep); + + // Exclude certain extensions from being previewed + if (XPREVIEW.test(options.path)) + return; + + if (previewTab && previewTab.path === options.path) { + // keepPreview(); + return previewTab; + } + // Remove existing preview pane if it's there + else if (previewTab) { + pane = previewTab.pane; + if (previewTab.document.meta.existing) { + delete previewTab.document.meta.preview; + delete previewTab.document.meta.existing; + + previewTab.classList.remove("preview"); + } + + // Or keep tab until the new one is loaded + else { + previewTab.unload(); + } + } + + if (!options.path) + throw new Error("No path specified for preview"); + + return createPreview(options, pane, callback); + } + + function createPreview(options, pane, callback) { + var path = options.path; + // Check if pane is already loaded + var tab = findTab(path); + if (tab) { + // tab.document.meta.preview = true; + // tab.document.meta.existing = true; + tab.activate(); + clearTimeout(previewTimeout); + callback(null, null); + } + // Else create preview pane + else if (!previewTimeout || options.immediate) { + previewTab = open({ + path: path, + active: true, + pane: pane, + noanim: true, + document: { + meta: { + readonly: true, + preview: true + } + } + }, function(err, tab) { + // Previewing has already been cancelled + if (err || !tab.loaded) + return callback(new Error("Preview was cancelled")); + + // Activate previewTab showing content + tab.activate(); + + // Open actual tab when the user starts editing + // @TODO cleanup + tab.document.undoManager.on("change", function(){ + if (tab.document.undoManager.position > -1) + keepPreview(); + }); + + callback(null, tab); + }); + previewTab.classList.add("preview"); + } else { + clearTimeout(previewTimeout); + previewTimeout = setTimeout(function() { + previewTimeout = null; + createPreview({ + path: options.path, + immediate: true + }, pane, callback); + }, 200); + } + + return previewTab; + } + + function cancelPreview(keep) { + // Unload last preview tab + if (lastPreviewTab) { + lastPreviewTab.unload(); + lastPreviewTab = null; + } + + if (!previewTab) + return false; + + previewTab.classList.remove("preview"); + + if (keep) + return keepPreview(); + + if (previewTab.document.meta.existing) { + delete previewTab.document.meta.preview; + delete previewTab.document.meta.existing; + } + else { + previewTab.unload(); + } + + previewTab = null; + focussedTab && focussedTab.activate(); + return false; + } + + // Open actual tab + function keepPreview(){ + if (!previewTab) return; + + if (previewTimeout) { + previewTimeout = null; + clearTimeout(previewTimeout); + } + + if (!previewTab.loaded) { + previewTab.unload(); + previewTab = null; + return false; + } + + previewTab.classList.remove("preview"); + + if (previewTab.document.meta.existing) { + delete previewTab.document.meta.existing; + delete previewTab.document.meta.preview; + } + else { + delete previewTab.document.meta.readonly; + delete previewTab.document.meta.preview; + previewTab.document.undoManager.off("change", keepPreview); + emit("open", { tab: previewTab }); + } + + previewTab = null; + return true; + } + + /**** Support for state preservation ****/ + + function pauseTabResize(){ + panes.forEach(function(pane) { + pane.setAttribute("buttons", "close,order"); + }); + } + + function continueTabResize(){ + setTimeout(function(){ + panes.forEach(function(pane) { + pane.setAttribute("buttons", "close,scale,order"); + pane.$waitForMouseOut = false; + pane.$scaleinit(null, "sync"); + }); + }, 300); + } + + /***** Lifecycle *****/ + + plugin.on("load", function(){ + load(); + }); + plugin.on("enable", function(){ + + }); + plugin.on("disable", function(){ + + }); + plugin.on("unload", function(){ + panes = []; + tabs = []; + loaded = false; + drawn = false; + lastPreviewTab = null; + }); + + /***** Register and define API *****/ + + /** + * Manages all tabs in all panes of Cloud9. This includes the panes + * in the console. Use this plugin to open files and editors, to change + * the focus of a tab, or to fetch panes and tabs. + * + * The tabManager manages the whole of panes and tabs that are organized + * as follows: + * + * * {@link Pane} - Represent a single pane, housing multiple tabs + * * {@link Tab} - A single tab (button) in a pane + * * {@link Editor} - The editor responsible for displaying the file in the tab + * * {@link Document} - The representation of a file in the tab + * * {@link Session} - The session information of the editor + * * {@link UndoManager} - The object that manages the undo stack for this document + * + * Panes can live in certain areas of Cloud9. By default these areas are: + * + * * {@link panes} - The main area where editor panes are displayed + * * {@link console} - The console in the bottom of the screen + * + * This is the default way to open a new file in an editor: + * + * tabManager.openFile("/file.js", true, function(err, tab) { + * var doc = tab.document; + * console.log("The value is: ", doc.value); + * }); + * + * @class tabManager + * @alternateClassName panes + * @singleton + **/ + plugin.freezePublicAPI({ + /** + * The tab that currently has the focus. Multiple tabs can be + * active at the same time. However there can only be one tab + * that has the focus at one time. If there are no tabs this + * property is null. + * + * See also {@link tabManager#focusTab} + * @property {Tab} focussedTab + * @readonly + */ + get focussedTab(){ return focussedTab || null; }, + /** + * Specifies whether the tabManager has focus. When a component + * outside of the editors has focus (such as the tree or a menu + * item), then this property is set to false. Otherwise it is set + * to true. + * @property {Boolean} focussed + * @readonly + */ + get focussed(){ return !unfocussed; }, + /** + * The tab that is shown as a preview. This property is set to null + * if there is currently no preview being shown. + * @property {Tab} previewTab + * @readonly + */ + get previewTab(){ return previewTab; }, + /** + * An Array of all the HTML Elements that act as containers for + * panes. Generally this is one for the main panes area and one for + * the console. + * @property {HTMLElement[]} containers + * @readonly + */ + get containers(){ return containers; }, + /** + * The AMLElement for the main panes area. + * @property {AMLElement} container + * @readonly + */ + get container(){ return container; }, + + _events: [ + /** + * Fires after a tab received focus. This event is fired + * when the focussedTab property is set. There is about 500ms + * delay between the user action and the firing of this event. + * This delay prevents the UI from getting stuck while plugins + * update their UIs. If you MUST have a sync event, check out + * {@link tabManager#focusSync}. + * + * @event focus + * @param {Object} e + * @param {Tab} e.tab the tab that received focus + */ + "focus", + /** + * Fires after a tab received focus. This event is fired + * when the focussedTab property is set. Do not use this event + * unless you ABSOLUTELY have to. Use {@link tabManager#focus} + * instead. + * + * @event focusSync + * @param {Object} e + * @param {Tab} e.tab the tab that received focus + */ + "focusSync", + /** + * Fires after a tab lost focus. This event is fired + * when the focussedTab property is changed to another tab. + * + * @event blur + * @param {Object} e + * @param {Tab} e.tab the tab that lost focus + * @private + */ + "blur", + /** + * Fires before a tab is activated. A tab becomes active when + * it is the selected tab (button) of the pane it belongs to. + * This is different from receiving the focus. A tab that has + * focus is always the active tab of it's parent pane. If a pane + * has at least one tab, it always has an active tab. You can + * cancel the activation of a tab by returning false in the + * event listener. This will prevent the tab from becoming + * active. + * + * See also {@link Pane#activeTab}. + * + * @event tabBeforeActivate + * @cancellable + * @param {Object} e + * @param {Tab} e.tab the tab that will become active + */ + "tabBeforeActivate", + /** + * Fires after a tab is activated asynchronously. See + * {@link #tabAfterActivateSync} for the synchronous event. + * A tab becomes active when + * it is the selected tab (button) of the pane it belongs to. + * This is different from receiving the focus. A tab that has + * focus is always the active tab of it's parent pane. If a pane + * has at least one tab, it always has an active tab. You can + * cancel the activation of a tab by returning false in the + * event listener. This will prevent the tab from becoming + * active. + * + * See also {@link Pane#activeTab}. + * + * @event tabAfterActivate + * @param {Object} e + * @param {Tab} e.tab the tab that has become active + * @param {Tab} e.lastTab the tab that is no longer active + */ + "tabAfterActivate", + /** + * Fires after a tab is activated synchronously. See + * {@link #tabAfterActivate} for the asynchronous event. + * A tab becomes active when + * it is the selected tab (button) of the pane it belongs to. + * This is different from receiving the focus. A tab that has + * focus is always the active tab of it's parent pane. If a pane + * has at least one tab, it always has an active tab. You can + * cancel the activation of a tab by returning false in the + * event listener. This will prevent the tab from becoming + * active. + * + * See also {@link Pane#activeTab}. + * + * @event tabAfterActivateSync + * @param {Object} e + * @param {Tab} e.tab the tab that has become active + * @param {Tab} e.lastTab the tab that is no longer active + */ + "tabAfterActivateSync", + /** + * Fires prior to closing a tab. The default action of closing + * the tab can be cancelled by returning false. + * + * @event tabBeforeClose + * @cancellable + * @param {Object} e + * @param {Object} e.tab the tab that is to be closed + */ + "tabBeforeClose", + /** + * Fires after a tab is closed, but not yet destroyed. Generally + * you want to use {@link tabManager#tabDestroy}. + * + * @event tabAfterClose + * @param {Object} e + * @param {Tab} e.tab the tab that is to be closed + */ + "tabAfterClose", + /** + * Fires after a tab is newly created. + * @event tabCreate + * @param {Object} e + * @param {Tab} e.tab the tab that is created + */ + "tabCreate", + /** + * Fires after a tab is destroyed + * @event tabDestroy + * @param {Object} e + * @param {Tab} e.tab the tab that has been destroyed + * @param {Tab} e.last whether this was the last tab of a pane that was destroyed + */ + "tabDestroy", + /** + * Fires when a tab is moved within a pane. + * @event tabOrder + * @param {Object} e + * @param {Tab} e.tab the tab that has been moved + * @param {Tab} e.next the tab on the right of e.tab. + */ + "tabOrder", + /** + * Fires before a tab is moved to a different pane. This usually + * happens when a pane is split, or when a tab is dragged to a + * different pane. + * + * @event tabBeforeReparent + * @cancelable + * @param {Object} e + * @param {Tab} e.tab the tab that is moved. + * @param {Tab} e.lastPane the previous pane that this tab was part of. + * @param {Pane} e.pane the pane that the tab is moved to. + */ + "tabBeforeReparent", + /** + * Fires after a tab is moved to a different pane. This usually + * happens when a pane is split, or when a tab is dragged to a + * different pane. + * + * @event tabAfterReparent + * @param {Object} e + * @param {Tab} e.tab the tab that is moved. + * @param {Tab} e.lastPane the previous pane that this tab was part of. + * @param {Pane} e.pane the pane that the tab is moved to. + */ + "tabAfterReparent", + /** + * Fires after a pane is newly created + * @event paneCreate + * @param {Object} e + * @param {Pane} e.pane the pane that is created + */ + "paneCreate", + /** + * Fires after a pane is destroyed + * @event paneDestroy + * @param {Object} e + * @param {Pane} e.pane the pane that is destroyed + */ + "paneDestroy", + /** + * Fires after a tab is opened and before it's contents is + * loaded. This event can be cancelled by returning false. + * Cancelling this event will prevent the data from being + * loaded. It then becomes your reponsibility to load the + * contents and call e.callback(err, value) when done. + * + * This event is primarily used by the {@link metadata} plugin. + * + * @event beforeOpen + * @cancellable + * @param {Object} e + * @param {Object} e.options The options object that was passed to the {@link tabManager#method-open} method. + * @param {Tab} e.tab The created tab that will present the file contents to the user. + * @param {Boolean} e.loadFromDisk Specifies whether the file contents will be loaded from disk if the event is not cancelled. + * @param {Function} e.setLoading Call this function to set the tab into a loading state. + * @param {Tab} e.setLoading.tab Specify the tab to set in a loading state. + * @param {Function} e.callback Call this function when the content is loaded. + * @param {Error} e.callback.err Specify an error if loading the contents has failed. + * @param {String} e.callback.value Specify the value of the content that is loaded. + */ + "beforeOpen", + /** + * Fires after a tab is opened and it's contents loaded + * @event open + * @param {Object} e + * @param {Tab} e.tab The tab that has been opened + * @param {Object} e.options The options object that was passed to the {@link tabManager#method-open} method. + */ + "open", + /** + * Fires after the contents of a tab is reloaded + * @event reload + * @param {Object} e + * @param {Tab} e.tab The tab for which the contents is reloaded + */ + "reload", + /** + * Fires when the tab manager is ready to open tabs + * @event ready + */ + "ready", + /** + * Fires when the user clicked on the + button in pane. + * @event plusClick + * @cancellable + * @param {Object} e + * @param {Tab} e.pane The pane to which the + button belongs to + */ + "plusClick", + /** + * Fires after the panels container is drawn + * @event draw + */ + "draw" + ], + + /** + * Prevent all pane buttons from resizing for all panes. + */ + pauseTabResize: pauseTabResize, + + /** + * Re-enable pane button resizing for all panes. + */ + continueTabResize: continueTabResize, + + /** + * Sets the tab as the active tab of it's pane element + * @param {Tab} tab The tab to activate + */ + activateTab: activateTab, + + /** + * Gives the focus to the tab and it's editor and sets the tab as + * the the active tab of it's pane. + * @param {Tab} tab The tab to activate + * @fires focus + * @fires focusSync + * @fires blur + */ + focusTab: focusTab, + + /** + * Retrieves the state of all panes, tabs and documents + * as a single serializable object. + * @param {HTMLElement} container One of the items from the + * {@link tabManager#containers} set, specifying which area it + * should serialize. Defaults to the container from the panels. + * @returns {Object} + */ + getState: getState, + + /** + * Loads the state of all panes panes, tabs anddocuments from a + * simple object. + * @param {Object} state The state describing the pane layout. + * @param {Boolean} [init] When set to true, optimizes the state + * loading for initialization of Cloud9. + * @param {Function} callback Called when the state loading is completed. + */ + setState: setState, + + /** + * Removes all panes, except one, and destroys all tabs, documents + * and editors. + * + * @param {Boolean} [soft=false] When set to true clear + * will not unload tabs. This can be useful when loading a new + * state with exactly the same tabs. WARNING: this can lead to + * leaking tabs/documents, etc. Use with caution! getTabs() will + * continue to return all the tabs. Even though they are no longer + * attached to a pane. + */ + clear: clear, + + /** + * Toggle the tab buttons between visible and hidden state. + * @param {Number} [force] When set to 1 the buttons become visible, + * when set to 2 they become hidden. + */ + toggleButtons: toggleButtons, + + /** + * Force a resize of all the tab buttons in all the panes. + */ + resizePanes: resizePanes, + + /** + * Retrieves a tab based on a path or it's unique identifier. + * @param {String} path The path or id of the tab to retrieve. + */ + findTab: findTab, + + /** + * Returns an array containing all the tabs. + */ + getTabs: getTabs, + + /** + * @ignore + */ + checkAllTabs: checkAllTabs, + + /** + * Retrieves a pane based on it's unique identifier. + * @param {String} name The name of the pane to retrieve. + */ + findPane: findPane, + + /** + * Returns an array containing all the panes (in a container). + * @param {AMLElement} [container] The container in which the panes + * reside. If no container is specified all panes in all + * containers are returned. + */ + getPanes: getPanes, + + /** + * Opens a new tab with an editor. If the tab with a specified + * path already exists, that tab is activated. + * (If no path was specified and option demandExisting is used, + * we look for a tab with the same editor type and title.) + * If state is given for a document, then that state is set prior + * to loading the tab. If a path is specified the file contents is + * loaded into the document. If no editorType is specified, the + * editor is determined based on the extension of the filename. + * + * @param options + * @param {String} [options.path] The path of the file to open + * @param {Pane} [options.pane] The pane to attach the new tab to + * @param {String} [options.editorType] The type of the editor for this tab + * @param {Boolean} [options.active=false] Whether this tab is set as active + * @param {Boolean} [options.forceNew=false] Always create a tab + * @param {Boolean} [options.demandExisting=false] Whether to try opening an + * existing tab even for tabs without a path. + * @param {Object} [options.document] Object describing the + * state of the document (see {@link Document#method-getState}) + * @param {String} [options.value] The contents of the file + * @param {String} [options.title] The title of the tab + * @param {String} [options.tooltip] The tooltip at the button of the tab + * @param {Function} callback + * @param {Error} callback.err An error that might + * occur during the load of the file contents. + * @param {Tab} callback.tab The created tab. + * @param {Function} callback.done Call this function + * when done retrieving the value. This is only relevant if + * -1 is passed to `value`. You are responsible for settings the + * document value yourself, like so: `tab.document.value = "value";` + * @returns {Tab} The created tab. + * @fires open + * @fires beforeOpen + */ + open: open, + + /** + * Opens a new pane tab with the default editor and loads the file + * contents into the document. This is a convenience method. For + * the full method see {@link tabManager#method-open}. + * + * @param {String} path The path of the file to open. + * @param {Boolean} [active] When set to true the new tab will become active in it's pane. + * @param {Function} callback Called when the file contents is loaded. + * @param {Error} callback.err An error that might + * occur during the load of the file contents. + * @param {Tab} callback.tab The created tab. + * @returns {Tab} The created tab. + */ + openFile: openFile, + + /** + * Opens a new tab with a specific editor + * @param {String} editorType The type of the editor for this tab. + * @param {Boolean} [active] When set to true the new tab will become active in it's pane. + * @param {Function} callback Called when the editor is loaded. + * @param {Error} callback.err An error that might + * occur during the load of the editor. + * @param {Tab} callback.tab The created tab. + * @returns {Tab} The created tab. + */ + openEditor: openEditor, + + /** + * Reloads the file contents of a tab. The tab needs to have a + * path property set. + * @param {Tab} tab The tab to reload. + */ + reload: reload, + + /** + * Opens a tab in preview mode, displaying the contents of a file with + * it's editor. The options passed can be the same as for the + * {@link tabManager#method-open} + * + * @param options + * @param {String} [options.path] The path of the file to open + * @param {Pane} [options.pane] The pane to attach the new tab to + * @param {String} [options.editorType] The type of the editor for this tab + * @param {Boolean} [options.active=false] Whether this tab is set as active + * @param {Object} [options.document] Object describing the + * state of the document (see {@link Document#method-getState}) + * @param {String} [options.value] The contents of the file + * @param {String} [options.title] The title of the tab + * @param {String} [options.tooltip] The tooltip at the button of the tab + * @param {Function} callback + * @param {Error} callback.err An error that might + * occur during the load of the file contents. + * @param {Tab} callback.tab The created tab. + * @param {Function} callback.done Call this function + * when done retrieving the value. This is only relevant if + * -1 is passed to `value`. You are responsible for settings the + * document value yourself, like so: `tab.document.value = "value";` + * @returns {Tab} The created tab. + * @fires open + * @fires beforeOpen + */ + preview: preview, + + /** + * + */ + clone: clone + }); + + register(null, { + tabManager: plugin + // panes : plugin + }); + } +}); diff --git a/plugins/c9.ide.editors/tabmanager_test.js b/plugins/c9.ide.editors/tabmanager_test.js new file mode 100644 index 00000000..bd7c47fa --- /dev/null +++ b/plugins/c9.ide.editors/tabmanager_test.js @@ -0,0 +1,592 @@ +/*global describe it before after bar = */ + +"use client"; + +require(["lib/architect/architect", "lib/chai/chai"], + function (architect, chai, baseProc) { + var expect = chai.expect; + + expect.setupArchitectTest([ + { + packagePath: "plugins/c9.core/c9", + startdate: new Date(), + debug: true, + hosted: true, + local: false, + davPrefix: "/" + }, + + "plugins/c9.core/ext", + "plugins/c9.core/http-xhr", + "plugins/c9.core/util", + "plugins/c9.ide.ui/lib_apf", + { + packagePath: "plugins/c9.core/settings", + testing: true + }, + "plugins/c9.core/api.js", + { + packagePath: "plugins/c9.ide.ui/ui", + staticPrefix: "plugins/c9.ide.ui" + }, + "plugins/c9.ide.editors/document", + "plugins/c9.ide.editors/undomanager", + { + packagePath: "plugins/c9.ide.editors/editors", + defaultEditor: "texteditor" + }, + "plugins/c9.ide.editors/editor", + "plugins/c9.ide.editors/tabmanager", + "plugins/c9.ide.ui/focus", + "plugins/c9.ide.editors/pane", + "plugins/c9.ide.editors/tab", + "plugins/c9.ide.editors/texteditor", + "plugins/c9.ide.editors/timeview", + "plugins/c9.ide.editors/imgview", + { + packagePath: "plugins/c9.vfs.client/vfs_client" + }, + "plugins/c9.vfs.client/endpoint", + "plugins/c9.ide.auth/auth", + { + packagePath: "plugins/c9.fs/fs", + baseProc: baseProc + }, + "plugins/c9.fs/fs.cache.xml", + + // Mock plugins + { + consumes: ["apf", "ui", "Plugin"], + provides: [ + "commands", "menus", "commands", "layout", "watcher", "proc", + "save", "anims", "clipboard", "dialog.alert", "auth.bootstrap", + "info", "dialog.error" + ], + setup: expect.html.mocked + }, + { + consumes: ["tabManager", "ui", "fs.cache", "fs"], + provides: [], + setup: main + } + ], architect); + + function main(options, imports, register) { + var tabs = imports.tabManager; + var fs = imports.fs; + + function countEvents(count, expected, done) { + if (count == expected) + done(); + else + throw new Error("Wrong Event Count: " + + count + " of " + expected); + } + + expect.html.setConstructor(function(tab) { + if (typeof tab == "object") + return tab.pane.aml.getPage("editor::" + tab.editorType).$ext; + }); + + describe('tabs', function() { + before(function(done) { + apf.config.setProperty("allow-select", false); + apf.config.setProperty("allow-blur", false); + + bar.$ext.style.background = "rgba(220, 220, 220, 0.93)"; + bar.$ext.style.position = "fixed"; + bar.$ext.style.left = "20px"; + bar.$ext.style.right = "20px"; + bar.$ext.style.bottom = "20px"; + bar.$ext.style.height = "33%"; + + document.body.style.marginBottom = "33%"; + + tabs.once("ready", function(){ + tabs.getPanes()[0].focus(); + done(); + }); + }); + + var text; + describe("open(), openFile(), openEditor() and reload()", function(){ + it('should open a pane from a path', function(done) { + var vpath = "/file.txt"; + tabs.openFile(vpath, function(err, tab) { + expect(tabs.getTabs()).length(1); + + expect(tabs.focussedTab) + .to.exist + .property("path").to.equal(vpath); + expect(tab.title).to.equal(vpath.substr(1)); + + fs.readFile(vpath, "utf8", function(err, data) { + text = data; + expect(tab.document.value).to.equal(data); + done(); + }); + }); + }); + it('should open a pane with just an editor', function(done) { + tabs.openEditor("timeview", function(err, tab) { + expect(tabs.getTabs()).length(2); + + expect(tabs.focussedTab) + .to.exist + .to.not.equal(tab); + //.property("path").to.equal(vpath); + done(); + }); + }); + it('should handle multiple docs on the same editor well', function(done) { + var vpath = "/listing.json"; + tabs.open({ + path: vpath, + active: true + }, function(err, tab) { + expect(tabs.getTabs()).length(3); + expect(tab.title).to.equal(vpath.substr(1)); + + expect(tabs.focussedTab) + .to.exist + .property("path").to.equal(vpath); + + fs.readFile(vpath, "utf8", function(err, data) { + expect(tab.document.value).to.equal(data); + + tabs.activateTab("/file.txt"); + expect(tabs.focussedTab.document.value) + .to.equal(text); + + tabs.openEditor("timeview", function(err, tab) { + expect(tabs.getTabs()).length(4); + + tabs.activateTab(tab); + expect(tabs.focussedTab) + .to.exist + .to.equal(tab); + + tabs.activateTab(tabs.getTabs()[1]); + expect.html(tabs.focussedTab).is.visible; + done(); + }); + }); + }); + }); + it('should reload the contents of an editor on a tab', function(done) { + var tab = tabs.findTab("/file.txt"); + tabs.activateTab(tab); + tab.document.value = "Testing"; + tabs.reload(tab, function(err) { + if (err) throw err.message; + expect(tab.document.value).to.equal(text); + done(); + }); + }); + it('should open a non-existing file with empty content passed as value', function(done) { + var vpath = "/Untitled1"; + tabs.open({ + path: vpath, + value: "", + active: true, + }, function(err, tab) { + expect(tabs.getTabs()).length(5); + expect(tab.title).to.equal(vpath.substr(1)); + expect(tabs.focussedTab) + .to.exist + .property("path").to.equal(vpath); + + expect(tabs.focussedTab.document.value).to.equal(""); + + done(); + }); + }); + it('should open a non-existing file with set content passed as value', function(done) { + var vpath = "/Untitled2"; + var text = "This is a test"; + tabs.open({ + path: vpath, + value: text, + active: true, + }, function(err, tab) { + expect(tabs.getTabs()).length(6); + expect(tab.title).to.equal(vpath.substr(1)); + expect(tabs.focussedTab) + .to.exist + .property("path").to.equal(vpath); + + expect(tabs.focussedTab.document.value) + .to.equal(text); + + done(); + }); + }); + }); + + describe("File system rename hooks - change open tab paths", function(){ + it('should rename a file - change page path', function(done) { + var vpath = "/dir/stuff.json"; + var newVpath = "/dir/stuff2.json"; + tabs.openFile(vpath, function(err, tab) { + expect(tab.path).to.equal(vpath); + expect(tab.title).to.equal("stuff.json"); + + fs.rename(vpath, newVpath, function(err) { + if (err) + throw err; + expect(tab.path).to.equal(newVpath); + tab.unload(); + fs.rename(newVpath, vpath, function (err) { + if (err) + throw err; + done(); + }); + }); + }); + }); + + it('should rename a directory - change tab path', function(done) { + var vpath = "/dir/stuff.json"; + tabs.openFile(vpath, function(err, tab) { + expect(tab.path).to.equal(vpath); + expect(tab.title).to.equal("stuff.json"); + + fs.rename("/dir", "/dir2", function(err) { + if (err) + throw err; + expect(tab.path).to.equal("/dir2/stuff.json"); + expect(tab.title).to.equal("stuff.json"); + tab.unload(); + fs.rename("/dir2", "/dir", function (err) { + if (err) + throw err; + done(); + }); + }); + }); + }); + }); + + describe("getTabs(), getPanes()", function(){ + it('should return a list containing all the pages', function(done) { + expect(tabs.getTabs()).length.gt(4); + done(); + }); + it('should return a list containing all the tabs', function(done) { + expect(tabs.getPanes()).length(1); + done(); + }); + it('should return an editor of a tab', function(done) { + expect(tabs.findTab("/file.txt").editor) + .property("type").to.equal("texteditor"); + done(); + }); + }); + describe("switchEditor()", function(){ + it('should switch to another editor for the selected tab', function(done) { + var tab = tabs.focusTab("/file.txt"); + tab.switchEditor("imgview", function(){ + expect(tabs.focussedTab.editor) + .property("type").to.equal("imgview"); + tab.switchEditor("texteditor", function(){ + expect(tabs.focussedTab.document.value).to.equal(text); + done(); + }); + }); + }); + it('should switch to another editor for a given tab (not selected)', function(done) { + var tab = tabs.findTab("/listing.json"); + tab.switchEditor("imgview", function(){ + expect(tab.editor) + .property("type").to.equal("imgview"); + tab.switchEditor("texteditor", function(){ + expect(tabs.focussedTab.document.value).to.equal(text); + done(); + }); + }); + }); + }); + + describe("clear(), getState() and setState()", function(){ + var state, info = {}; + it('should retrieve the state', function(done) { + state = tabs.getState(); + info.pages = tabs.getTabs().map(function(tab) { + return tab.path || tab.id; + }); + done(); + }); + it('should clear all tabs and pages', function(done) { + var count = 0, expected = 0; + tabs.getTabs().forEach(function(tab) { + expected += 2; + tab.on("unload", function(){ + count++; + }); + tab.document.on("unload", function(){ + count++; + }); + }); + + tabs.getPanes()[0]; + tabs.clear(); + expect(tabs.getTabs(), "pages").length(0); + expect(tabs.getPanes(), "tabManager").length(0); + + countEvents(count, expected, done); + }); + it('should restore the state', function(done) { + tabs.setState(state, false, function(err) { + if (err) throw err.message; + }); + var l = info.pages.length; + expect(tabs.getTabs()).length(l); + expect(tabs.getPanes()[0].getTabs()).length(l); + expect(tabs.focussedTab.pane.getTabs()).length(l); + expect(tabs.getTabs()[2].title).to.equal("listing.json"); + expect(tabs.getTabs().map(function(tab) { + return tab.path || tab.id; + })).to.deep.equal(info.pages); + done(); + }); + }); +// describe("pauseTabResize() and continueTabResize()", function(){ +// it('should stop resizing of tabs', function(done) { +// var pane = tabs.focussedTab.pane; +// var w = pane.aml.getWidth(); +// var pw = pane.getTab().aml.getWidth(); +// tabs.pauseTabResize(); +// pane.$ext.style.width = (200) + "px"; +// expect(pane.getTab().aml.getWidth()).to.equal(pw); +// done(); +// }); +// it('should restore resizing of tabs', function(done) { +// done(); +// }); +// }); + + describe("vsplit(), hsplit(), removeTab()", function(){ + it('should split a pane vertically, making the existing pane the top one', function(done) { + var pane = tabs.focussedTab.pane; + var btmtab = pane.vsplit(true); + expect(pane.aml.getTop()).lt(btmtab.aml.getTop()); + tabs.focussedTab.attachTo(btmtab); + tabs.on("tabAfterActivate", function c1(){ + expect(tabs.focussedTab.title).to.equal("file.txt"); + expect(tabs.focussedTab.document.value).to.equal(text); + expect(tabs.focussedTab.editor).to.equal(tabs.focussedTab.pane.aml.getPage("editor::texteditor").editor); + tabs.off("tabAfterActivate", c1); + done(); + }); + tabs.focusTab("/file.txt"); + }); + it('should remove the bottom pane from a vertical split', function(done) { + var pane = tabs.getPanes()[1]; + var tab = pane.getTab(); + pane.unload(); + expect(tabs.getPanes()).length(1); + expect(tabs.getTabs()).length(6); + tabs.focusTab(tab); + expect(tab.editor.name).to.equal("texteditor1"); + expect.html(tab.pane.aml.getPage("editor::texteditor").$ext).visible; + done(); + }); + it('should split a pane vertically, making the existing pane the bottom one', function(done) { + var pane = tabs.focussedTab.pane; + var toptab = pane.vsplit(); + expect(toptab.aml.getTop()).lt(pane.aml.getTop()); + tabs.focussedTab.attachTo(toptab); + tabs.on("tabAfterActivate", function c1(){ + expect(tabs.focussedTab.title).to.equal("file.txt"); + expect(tabs.focussedTab.document.value).to.equal(text); + expect(tabs.focussedTab.editor).to.equal(tabs.focussedTab.pane.aml.getPage("editor::texteditor").editor); + tabs.off("tabAfterActivate", c1); + done(); + }); + tabs.focusTab("/file.txt"); + }); + it('should remove the top pane from a vertical split', function(done) { + var pane = tabs.getPanes()[0]; + var tab = pane.getTab(); + pane.unload(); + expect(tabs.getPanes()).length(1); + expect(tabs.getTabs()).length(6); + tabs.focusTab(tab); + expect(tab.editor.name).to.equal("texteditor3"); + expect(tab.pane.aml.getPage("editor::texteditor").$ext.style.display).to.not.equal("none"); + done(); + }); + it('should split a pane horizontally, making the existing pane the left one', function(done) { + var pane = tabs.focussedTab.pane; + var righttab = pane.hsplit(true); + expect(pane.aml.getLeft()).lt(righttab.aml.getLeft()); + tabs.focussedTab.attachTo(righttab); + tabs.focusTab("/file.txt"); + expect(tabs.focussedTab.title).to.equal("file.txt"); + expect(tabs.focussedTab.document.value).to.equal(text); + expect(tabs.focussedTab.editor).to.equal(tabs.focussedTab.pane.aml.getPage("editor::texteditor").editor); + done(); + }); + it('should remove the left pane from a horizontal split', function(done) { + var pane = tabs.getPanes()[0]; + var tab = tabs.getPanes()[1].getTab(); + pane.unload(); + expect(tabs.getPanes()).length(1); + expect(tabs.getTabs()).length(6); + tabs.focusTab(tab); + expect(tab.editor.name).to.equal("texteditor4"); + expect(tab.pane.aml.getPage("editor::texteditor").$ext.style.display).to.not.equal("none"); + done(); + }); + it('should split a pane horizontally, making the existing pane the right one', function(done) { + var pane = tabs.focussedTab.pane; + var lefttab = pane.hsplit(); + expect(lefttab.aml.getLeft()).lt(pane.aml.getLeft()); + tabs.focussedTab.attachTo(lefttab); + tabs.focusTab("/file.txt"); + expect(tabs.focussedTab.title).to.equal("file.txt"); + expect(tabs.focussedTab.document.value).to.equal(text); + expect(tabs.focussedTab.editor).to.equal(tabs.focussedTab.pane.aml.getPage("editor::texteditor").editor); + done(); + }); + it('should remove the right pane from a horizontal split', function(done) { + var pane = tabs.getPanes()[1]; + var tab = pane.getTab(); + pane.unload(); + expect(tabs.getPanes()).length(1); + expect(tabs.getTabs()).length(6); + tabs.focusTab(tab); + expect(tab.editor.name).to.equal("texteditor4"); + expect(tab.pane.aml.getPage("editor::texteditor").$ext.style.display).to.not.equal("none"); + done(); + }); + it('should be able to create a complex 5 pane layout', function(done) { + var first = tabs.getPanes()[0]; + var right = first.hsplit(true); + right.width = "20%"; + + var other = first.vsplit(); + other.hsplit(); + first.hsplit(); + + var pages = tabs.getTabs(); + expect(pages).length(6); + tabs.getPanes().forEach(function(pane) { + pages.pop().attachTo(pane); + }); + + expect(tabs.getPanes()).length(5); + expect(tabs.getTabs()).length(6); + + done(); + }); + it('should propertly serialize and deserialize', function(done) { + var cstate = tabs.getState(); + var state = tabs.getState(); + tabs.clear(); + expect(tabs.getPanes()).length(0); + expect(tabs.getTabs()).length(0); + apf.z = 1; + tabs.setState(state, function(err) { + if (err) throw err.message; + }); + console.log(cstate, tabs.getState()); + expect(cstate).to.deep.equal(tabs.getState()); + + expect(tabs.getPanes()).length(5); + expect(tabs.getTabs()).length(6); + + //Loop through state to check all the widths/heights + +// (function recur(parent, list) { +// list.forEach(function(state) { +// var p; +// +// if (state.type == "pane") { +// p = createPane(state).aml; +// parent.appendChild(p); +// } +// else if (state.type == "hsplitbox" || state.type == "vsplitbox") { +// p = parent.appendChild(new ui[state.type]({ +// splitter : true, +// padding : 3, +// width : state.width, +// height : state.height +// })); +// } +// else if (state.type == "tab") { +// var tab = findTab(state.id); +// if (!tab) { +// state.pane = parent.cloud9pane; +// state.init = init; +// +// open(state, function(err, tab) { +// callback(err, tab); +// }); +// } +// else { +// tab.attachTo(parent); +// } +// return; +// } +// recur(p, state.nodes); +// }); +// })(bar, [cstate]); + done(); + }); + }); +// describe("activateTab() and focusTab()", function(){ +// it('should focus a tab', function(done) { +// tabs.activateTab(); +// done(); +// }); +// it('should activate a tab on a focussed pane', function(done) { +// done(); +// }); +// it('should activate a tab but not focus it', function(done) { +// done(); +// }); +// }); +// describe("toggleButtons() and resizePanes()", function(){ +// it('should hide and show the pane buttons', function(done) { +// done(); +// }); +// it('should force resize the pane buttons', function(done) { +// done(); +// }); +// }); +// describe("All kinds of character sets and symbols", function(){ +// it('should display characters properly', function(done) { +// done(); +// }); +// }); + + if (!onload.remain) { + describe("unload()", function(){ + it('should destroy all ui elements when it is unloaded', function(done) { + expect(tabs.getPanes()).length(5); + var els = tabs.getPanes(); + tabs.unload(); + + expect(tabs.getPanes()).length(0); + + els.forEach(function(pane) { + expect(pane.aml.$amlDestroyed).to.equal(true); + }); + done(); + }); + }); + + //@todo Idea: show in the tabs whether the editor is running atm + // @todo test fs integration + + after(function(done) { + document.body.style.marginBottom = ""; + done(); + }); + } + }); + + onload && onload(); + } +}); \ No newline at end of file diff --git a/plugins/c9.ide.editors/texteditor.js b/plugins/c9.ide.editors/texteditor.js new file mode 100644 index 00000000..7f5dbd9b --- /dev/null +++ b/plugins/c9.ide.editors/texteditor.js @@ -0,0 +1,206 @@ +define(function(require, exports, module) { + main.consumes = ["Editor", "editors"]; + main.provides = ["texteditor"]; + return main; + + function main(options, imports, register) { + var Editor = imports.Editor; + var editors = imports.editors; + + /***** Initialization *****/ + + var extensions = ["txt"]; + var handle = editors.register( + "texteditor", "Text Editor", TextEditor, extensions); + + function TextEditor(){ + var plugin = new Editor("Ajax.org", main.consumes, extensions); + var emit = plugin.getEmitter(); + + var editor; + + plugin.on("draw", function(e) { + // Create UI elements + editor = document.createElement("textarea"); + e.htmlNode.appendChild(editor); + + editor.style.display = "block"; + editor.style.position = "absolute"; + editor.style.borderRadius = "6px 0 0 0"; + editor.style.left = + editor.style.top = + editor.style.bottom = + editor.style.right = "3px"; + + // @todo UndoManager integration + }); + + /***** Method *****/ + + /***** Lifecycle *****/ + + plugin.on("load", function(){ + }); + + var currentDocument; + plugin.on("documentLoad", function(e) { + var doc = e.doc; + var session = doc.getSession(); + + // Value + doc.on("getValue", function get(e) { + return currentDocument == doc + ? editor.value + : e.value; + }, session); + + doc.on("setValue", function set(e) { + if (currentDocument == doc) + editor.value = e.value || ""; + }, session); + + // Title & Tooltip + function setTitle(e) { + var path = doc.tab.path; + if (!path) return; + + // Caption is the filename + doc.title = path.substr(path.lastIndexOf("/") + 1); + + // Tooltip is the full path + doc.tooltip = path; + } + doc.tab.on("setPath", setTitle, session); + + setTitle({path: doc.tab.path || ""}); + + var tab = doc.tab; + tab.backgroundColor = "rgb(255,255,255)"; + }); + plugin.on("documentActivate", function(e) { + editor.value = e.doc.value; + currentDocument = e.doc; + }); + plugin.on("documentUnload", function(e) { + + }); + plugin.on("getState", function(e) { + if (editor) + e.state.scrollTop = editor.scrollTop; + }); + plugin.on("setState", function(e) { + if (e.state.scrollTop) + editor.scrollTop = e.state.scrollTop; + }); + plugin.on("clear", function(){ + editor.value = ""; + }); + plugin.on("focus", function(){ + editor.focus(); + }); + plugin.on("blur", function(){ + }); + plugin.on("resize", function(){ + }); + plugin.on("cut", function(e) { + if (e.native) return; // Handled by the textarea + + var sel = window.getSelection(); + var range = sel.getRangeAt(0); + var data = range.toString(); + + // Remove contents + range.deleteContents(); + + // Add data to clipboard + e.clipboardData.setData("text/plain", data); + }); + plugin.on("copy", function(e) { + if (e.native) return; // Handled by the textarea + + var sel = window.getSelection(); + var range = sel.getRangeAt(0); + var data = range.toString(); + + // Add data to clipboard + e.clipboardData.setData("text/plain", data); + }); + plugin.on("paste", function(e) { + if (e.native) return; // Handled by the textarea + + var data = e.clipboardData.getData("text/plain"); + if (data === false) return; + + var sel = window.getSelection(); + var range = sel.getRangeAt(0); + + // Delete contents + range.deleteContents(); + + // Add pasted data + range.insertNode(document.createTextNode(data)); + }); + plugin.on("enable", function(){ + editor.disabled = false; + }); + plugin.on("disable", function(){ + editor.disabled = true; + }); + plugin.on("unload", function(){ + editor.parentNode.removeChild(editor); + editor = null; + }); + + /***** Register and define API *****/ + + /** + * The texteditor handle, responsible for events that involve all + * TextEditor instances. This is the object you get when you request + * the texteditor service in your plugin. + * + * Example: + * + * define(function(require, exports, module) { + * main.consumes = ["texteditor"]; + * main.provides = ["myplugin"]; + * return main; + * + * function main(options, imports, register) { + * var texteditorHandle = imports.texteditor; + * }); + * }); + * + * + * @class texteditor + * @extends Plugin + * @singleton + */ + /** + * Simple Text Editor for Cloud9. This editor is not actually + * used by Cloud9, but rather serves as an example of how to create + * a simple editor for Cloud9. Check out the source code and + * use it as a template for creating your own editor. + * + * @class texteditor.TextEditor + * @extends Editor + **/ + /** + * The type of editor. Use this to create the terminal using + * {@link tabManager#openEditor} or {@link editors#createEditor}. + * @property {"texteditor"} type + * @readonly + */ + plugin.freezePublicAPI({ + + }); + + plugin.load(null, "texteditor"); + + return plugin; + } + + register(null, { + texteditor: handle + }); + } +}); \ No newline at end of file diff --git a/plugins/c9.ide.editors/timeview.js b/plugins/c9.ide.editors/timeview.js new file mode 100644 index 00000000..83f49a3e --- /dev/null +++ b/plugins/c9.ide.editors/timeview.js @@ -0,0 +1,104 @@ +/** + * Text Editor for the Cloud9 + * + * @copyright 2010, Ajax.org B.V. + * @license GPLv3 + */ +define(function(require, exports, module) { + main.consumes = ["Editor", "editors", "ui", "tabManager"]; + main.provides = ["timeview"]; + return main; + + function main(options, imports, register) { + var Editor = imports.Editor; + var editors = imports.editors; + var tabs = imports.tabManager; + var ui = imports.ui; + + /***** Initialization *****/ + + var extensions = []; + + var handle = editors.register("timeview", "Time Viewer", + TimeViewer, extensions); + + handle.addElement( + tabs.getElement("mnuEditors").appendChild( + new ui.item({ + caption: "New Clock", + onclick: function(e) { + e.pane = tabs.focussedTab.pane; + tabs.openEditor("timeview", true, function(){}); + } + }) + ) + ); + + function TimeViewer(){ + var deps = main.consumes.splice(0, main.consumes.length - 1); + var plugin = new Editor("Ajax.org", deps, extensions); + var editor; + + plugin.on("draw", function(e) { + // Create UI elements + editor = document.createElement("div"); + e.htmlNode.appendChild(editor); + + editor.style.display = "block"; + editor.style.position = "absolute"; + editor.style.backgroundColor = "rgba(255,255,255,0.8)"; + editor.style.left = + editor.style.right = + editor.style.top = + editor.style.bottom = 0; + editor.style.fontSize = "50px"; + editor.style.fontFamily = "Tahoma"; + editor.style.textAlign = "center"; + }) + + /***** Method *****/ + + /***** Lifecycle *****/ + + plugin.on("documentLoad", function(e) { + var doc = e.doc; + var session = doc.getSession(); + + session.timer = setInterval(function(){ + var dt = new Date(); + var time = dt.getHours() + ":" + + dt.getMinutes() + ":" + + dt.getSeconds(); + + if (doc.tab.isActive()) + editor.innerHTML = time; + doc.title = time; + }, 1); + }); + + plugin.on("documentUnload", function(e) { + clearTimeout(e.doc.getSession().timer); + }); + + plugin.on("unload", function(){ + editor.parentNode.removeChild(editor); + editor = null; + }); + + /***** Register and define API *****/ + + /** + * Read Only Image Editor + **/ + plugin.freezePublicAPI({}); + + plugin.load(null, "timeview"); + + return plugin; + } + + register(null, { + timeview: handle + }); + } +}); \ No newline at end of file diff --git a/plugins/c9.ide.editors/undomanager.js b/plugins/c9.ide.editors/undomanager.js new file mode 100644 index 00000000..e5c6f5d9 --- /dev/null +++ b/plugins/c9.ide.editors/undomanager.js @@ -0,0 +1,400 @@ +define(function(require, module, exports) { + main.consumes = ["Plugin"]; + main.provides = ["UndoManager"]; + return main; + + function main(options, imports, register) { + var Plugin = imports.Plugin; + + function UndoManager(options) { + var plugin = new Plugin("Ajax.org", main.consumes); + var emit = plugin.getEmitter(); + + var position = -1, mark = null, stack = []; + + if (options) + setState(options); + + + function canUndo() { + return position >= 0; + } + + function undo(){ + if (!canUndo()) + return false; + + var item = stack[position]; + if (!item.undo) + item = stack[position] = findItem(item); + position--; + item.undo(); + + emit("change"); + } + + function canRedo() { + return position !== stack.length - 1; + } + + function redo(){ + if (!canRedo()) + return false; + + position++; + var item = stack[position]; + if (!item.redo) + item = stack[position] = findItem(item); + item.redo(); + + emit("change"); + } + + function clearUndo(){ + stack = stack.slice(position - 1); + position = 0; + + if (mark < position) + mark = -1; + + emit("change"); + } + + function clearRedo(noEvent) { + stack = stack.slice(0, position + 1); + + if (mark > position) + mark = -1; + + if (!noEvent) + emit("change"); + } + + function add(item) { + if (!item.undo || !item.redo) + throw new Error("Missing undo and/or redo method implementation"); + + clearRedo(true); + stack.push(item); + position = stack.length - 1; + + emit("change"); + } + + function remove(idx) { + var item = stack.splice(idx, 1)[0]; + if (!item.undo) + item = findItem(item); + item.undo(); + + if (idx <= position) + position--; + + if (mark == idx) + mark = -1; + else if (mark > idx) + mark--; + + emit("change"); + } + + function bookmark(index) { + mark = index !== undefined ? index : this.position; + + emit("change"); + } + + function isAtBookmark(){ + return mark !== null && mark == this.position + || mark === null && position == -1; + } + + function item(idx) { + return stack[idx] || null; + } + + function getState(){ + return { + mark: mark, + position: position, + stack: stack.map(function(item) { + return item.getState ? item.getState() : item; + }) + }; + } + + function setState(state) { + if (!state || !state.stack.length) + return reset(); + + mark = state.mark; + position = state.position; + if (state.stack.length && state.stack[0] == undefined) + return; // guard against broken stack + stack = state.stack; + + emit("change"); //If you remove this again, change the test + } + + function findItem(compressedItem) { + return emit("itemFind", {state: compressedItem}); + } + + function reset(){ + if (position == -1) + return; + + position = -1; + stack = []; + mark = null; + + emit("change"); + } + + /** + * The Undo Manager class of Cloud9. Each {@link Document} + * has a single instance of the undo manager that + * is used by each editor that works on the document. The undo + * manager manages the undo stack which tracks the changes to the + * document. + * + * The undoManager relates to other objects as such: + * + * * {@link Pane} - Represent a single pane, housing multiple tabs + * * {@link Tab} - A single tab (button) in a pane + * * {@link Editor} - The editor responsible for displaying the file in the tab + * * {@link Document} - The representation of a file in the tab + * * {@link Session} - The session information of the editor + * * **UndoManager - The object that manages the undo stack for this document** + * + * Panes can live in certain areas of Cloud9. By default these areas are: + * + * * {@link panes} - The main area where editor panes are displayed + * * {@link console} - The console in the bottom of the screen + * + * Tabs are managed by the {@link tabManager}. The default way to + * open a new file in an editor uses the tabManager: + * + * tabManager.openFile("/file.js", true, function(err, tab) { + * tab.document.value = "new value"; // adds item to the undo manager. + * + * var undoManager = tab.document.undoManager; + * undoManager.undo(); + * }); + * + * The undo manager doesn't apply any changes itself. The changes + * are managed by objects that are pushed onto the stack and have + * an undo(), redo() and getState() method. This allows each + * editor to implement it's own way to change the document while + * keeping a consistent undo stack for the document. + * + * Example: + * + * The item class in the following example simply manages an + * array, adding and removing items. + * + * var data = []; + * + * function Item(info, idx) { + * this.getState = function(){ return [ info, idx ] } + * this.undo = function(){ data.splice(idx, 1) } + * this.redo = function(){ + * data[idx || (idx = data.length)] = info; + * return this; + * } + * } + * + * var undoManager = new UndoManager(); + * undoManager.add(new Item("a", 0)); // data = ["a"] + * undoManager.add(new Item("b", 1)); // data = ["a", "b"] + * + * undoManager.undo(); // data = ["a"]; + * undoManager.undo(); // data = []; + * + **/ + plugin.freezePublicAPI({ + /** + * @ignore + */ + get stack() { return stack; }, + /** + * The number of items on the stack. This number will stay the + * same when using {@link UndoManager#undo} and + * {@link UndoManager#redo}. See the {@link UndoManager#position} + * property if you want to find out which items are applied + * to the document and which are not. + * + * @property {Number} length + * @readonly + */ + get length(){ return stack.length; }, + /** + * Set to the index of the item in the stack up to which the + * items have been applied to the document. This property + * changes when using the {@link UndoManager#undo} and + * {@link UndoManager#redo} methods. + * + * When {@link UndoManager#length} is 10, and 6 items have been + * executed, this property is set to 5. It is then + * possible to execute redo() 4 times. At that point, the + * position property is set to 9. Calling redo() further will + * not result in any changes. Similarly undo() can be called + * until position is -1. + * + * @property {Number} position + * @readonly + */ + get position(){ return position; }, + + events: [ + /** + * Fires when the undo manager is loading state from a state + * object (object returned by {@link #getState}() call). This + * event allows you to switch the state object (which was a + * result of the getState() call to your item object) with + * the actual implementation of your item object. + * + * Return an instance of the item to push on to the stack. + * + * Example: + * + * undoManager.on("itemFind", function(e) { + * return new Item(e.state[0], e.state[1]); + * }); + * + * @event itemFind + * @param {Object} e + * @param {Object} e.state The state of the object to + * be unserialized. + */ + "itemFind", + /** + * Fires whenever the {@link #position} or {@link #length} + * properties changes. + * @event change + */ + "change" + ], + + /** + * Checks if there are items to be undone. This is equivalent + * to: + * + * undoManager.position >= 0 + */ + canUndo: canUndo, + + /** + * Checks if there are items to be redone. This is equivalent + * to: + * + * undoManager.position != undoManager.length - 1 + */ + canRedo: canRedo, + + /** + * Reverts the last change that was applied to the document. + * This method calls undo() on the item that is on the stack + * at the index specified by the {@link UndoManager#position} + * property. + */ + undo: undo, + + /** + * Executes the change that was undone last. + * This method calls redo() on the item that is on the stack + * at the index specified by the {@link UndoManager#position} + * property + 1. + */ + redo: redo, + + /** + * Clears the complete stack + */ + reset: reset, + + /** + * Retrieves an object from the stack by it's index. + * @param {Number} index The index of the item to retrieve. + * This needs to be a number between 0 and the value of the + * {@link UndoManager#length} property, including 0. + */ + item: item, + + /** + * Sets the bookmark pointer to the `index` specfied or the + * current value of the `position` property. + * The bookmark is used by Cloud9 to specify at which point the + * file was saved. + * @param {Number} [index] The index of the item to bookmark + */ + bookmark: bookmark, + + /** + * Retrieves whether the current position of the stack is bookmarked. + */ + isAtBookmark: isAtBookmark, + + /** + * Removes all items on the stack that have an index less than + * or equal to the value of {@link UndoManager#position}. These + * are all the items that have been applied to the document. + */ + clearUndo: clearUndo, + + /** + * Removes all items on the stack that have an index greater than + * the value of {@link UndoManager#position}. These are all the + * items that have not been applied to the document. + */ + clearRedo: clearRedo, + + /** + * Retrieves the state of the undo stack. The state of the + * stack is retrieved by calling getState() on each item in the + * stack. + * + * @return {Object} + * @return {Number} return.mark The value of the {@link #bookmark} property. + * @return {Number} return.position The value of the {@link #position} property. + * @return {Array} return.stack An array containing the + * results of calling getState() on each stack item. + */ + getState: getState, + + /** + * Sets the state of the undo stack + * @param {Object} state The state object. See {@link #getState}. + * @fires itemFind + */ + setState: setState, + + /** + * Adds an item to the undo stack. The redo() method is called + * on the `item` that is added and the item is added to the + * stack. + * @param {Object} item the object to put on the undo stack. + * This item should have getState(), undo() and redo() + * methods. + */ + add: add, + + /** + * Removes an item from the undo stack + * @param {Number} index The index of the item to remove + */ + remove: remove + }); + + plugin.load(null, "undoManager"); + + return plugin; + } + + /***** Register and define API *****/ + + register(null, { + UndoManager: UndoManager + }); + } +}); diff --git a/plugins/c9.ide.editors/undomanager_test.js b/plugins/c9.ide.editors/undomanager_test.js new file mode 100644 index 00000000..b7624924 --- /dev/null +++ b/plugins/c9.ide.editors/undomanager_test.js @@ -0,0 +1,146 @@ +/*global describe:false, it:false */ + +"use client"; + +require(["lib/architect/architect", "lib/chai/chai"], function (architect, chai) { + var expect = chai.expect; + + expect.setupArchitectTest([ + "plugins/c9.core/ext", + "plugins/c9.ide.editors/undomanager", + { + consumes: ["UndoManager"], + provides: [], + setup: main + } + ], architect); + + function main(options, imports, register) { + var UndoManager = imports.UndoManager; + + var data = ["a", "b"]; + var stack = [ ["a", 0],["b", 1],["c", 2],["d", 3],["e", 4] ]; + var count = 0, check = 0; + var undo; + + function Item(info, idx) { + this.getState = function(){ return [ info, idx ] }; + this.undo = function(){ data.splice(idx, 1) }; + this.redo = function(){ + data[idx || (idx = data.length)] = info; + return this; + }; + } + + function checkCount(){ + if (count != check) + throw new Error("invalid amount of change events called: got " + + count + ", expected " + check); + } + + describe('undomanager', function() { + it('should load it\'s state from the constructor', function(done) { + undo = new UndoManager({ + position: 1, + stack: stack + }); + + undo.on("change", function(){ count++ }); + + undo.on("itemFind", function(e) { + return new Item(e.state[0], e.state[1]); + }); + + expect(undo.position).to.equal(1); + expect(undo.length).to.equal(5); + + checkCount(); + done(); + }); + it('should return a representation of the stack using getState()', function(done) { + var state = undo.getState(); + expect(state.stack).to.not.equal(stack); + expect(state.stack).to.deep.equal(stack); + checkCount(); + done(); + }); + it('should re-execute items when redo() is called', function(done) { + undo.redo(); check++; + expect(undo.position).to.equal(2); + expect(data).to.deep.equal(["a", "b", "c"]); + undo.redo(); check++; + expect(undo.position).to.equal(3); + expect(data).to.deep.equal(["a", "b", "c", "d"]); + undo.redo(); check++; + expect(undo.position).to.equal(4); + expect(data).to.deep.equal(["a", "b", "c", "d", "e"]); + checkCount(); + done(); + }); + it('should undo items when undo() is called', function(done) { + undo.undo(); check++; + expect(undo.position).to.equal(3); + expect(data).to.deep.equal(["a", "b", "c", "d"]); + undo.undo(); check++; + expect(undo.position).to.equal(2); + expect(data).to.deep.equal(["a", "b", "c"]); + undo.undo(); check++; + expect(undo.position).to.equal(1); + expect(data).to.deep.equal(["a", "b"]); + checkCount(); + done(); + }); + it('should clear redo positions when adding a new item', function(done) { + undo.add(new Item("q").redo()); check++; + expect(undo.position).to.equal(2); + expect(undo.length).to.equal(3); + expect(data).to.deep.equal(["a", "b", "q"]); + checkCount(); + done(); + }); + it('should remove an item while keeping the stack in tact', function(done) { + undo.remove(1); check++; + expect(undo.position).to.equal(1); + expect(undo.length).to.equal(2); + expect(data).to.deep.equal(["a", "q"]); + checkCount(); + done(); + }); + it('should clear the undo stack when calling clearUndo()', function(done) { + undo.setState({ position : 3, stack : stack }); check++; + expect(undo.position).to.equal(3); + expect(undo.length).to.equal(5); + undo.clearUndo(); check++; + expect(undo.position).to.equal(0); + expect(undo.length).to.equal(3); + expect(data).to.deep.equal(["a", "q"]); + checkCount(); + done(); + }); + it('should remember bookmarked state', function(done) { + undo.setState({ position : 3, stack : stack, mark : 4 }); check++; + expect(undo.position).to.equal(3); + expect(undo.length).to.equal(5); + expect(undo.isAtBookmark()).to.equal(false); + undo.redo(); check++; + checkCount(); + expect(undo.isAtBookmark()).to.equal(true); + expect(undo.position).to.equal(4); + undo.undo(); check++; + expect(undo.isAtBookmark()).to.equal(false); + undo.add(new Item("q").redo()); check++; + expect(undo.isAtBookmark()).to.equal(false); + expect(undo.position).to.equal(4); + undo.undo(); check++; + + undo.setState({ position : -1, stack : stack, mark : null }); check++; + expect(undo.isAtBookmark()).to.equal(true); + expect(data).to.deep.equal(["a", "q"]); + checkCount(); + done(); + }); + }); + + onload && onload(); + } +}); \ No newline at end of file diff --git a/plugins/c9.ide.editors/urlview.js b/plugins/c9.ide.editors/urlview.js new file mode 100644 index 00000000..fa8824b4 --- /dev/null +++ b/plugins/c9.ide.editors/urlview.js @@ -0,0 +1,196 @@ +define(function(require, exports, module) { + main.consumes = ["Editor", "editors"]; + main.provides = ["urlview"]; + return main; + + function main(options, imports, register) { + var Editor = imports.Editor; + var editors = imports.editors; + + /***** Initialization *****/ + + var extensions = []; + + function UrlView(){ + var plugin = new Editor("Ajax.org", main.consumes, extensions); + //var emit = plugin.getEmitter(); + var container; + + plugin.on("draw", function(e) { + // Create UI elements + container = e.htmlNode; + }); + + /***** Method *****/ + + /***** Lifecycle *****/ + + plugin.on("load", function(){ + }); + + var currentDocument; + plugin.on("documentLoad", function(e) { + var doc = e.doc; + var session = doc.getSession(); + + // Value + doc.on("getValue", function get(e) { + return currentDocument == doc + ? session.iframe.src + : e.value; + }, session); + + doc.on("setValue", function set(e) { + if (currentDocument == doc) + session.iframe.src = e.value || "about:blank"; + }, session); + + session.state = e.state || {}; + + if (!session.iframe) { + var div = document.createElement("div"); + var iframe = document.createElement("iframe"); + + iframe.setAttribute("nwfaketop", true); + iframe.setAttribute("nwdisable", true); + + iframe.style.width = "100%"; + iframe.style.height = "100%"; + iframe.style.border = 0; + iframe.src = doc.value || "about:blank"; + + div.style.position = "absolute"; + div.style.left = 0; + div.style.top = 0; + div.style.right = 0; + div.style.bottom = 0; + div.appendChild(iframe); + + session.iframe = iframe; + session.div = div; + } + + container.appendChild(session.div); + + session.iframe.style.backgroundColor = + doc.tab.backgroundColor = + session.state.backgroundColor || "#222222"; + + if (session.state.dark === false) + doc.tab.classList.remove("dark"); + else + doc.tab.classList.add("dark"); + }); + plugin.on("documentActivate", function(e) { + if (currentDocument) + currentDocument.getSession().div.style.display = "none"; + + currentDocument = e.doc; + + e.doc.getSession().div.style.display = "block"; + }); + plugin.on("documentUnload", function(e) { + container.removeChild(e.doc.getSession().div); + }); + plugin.on("getState", function(e) { + var doc = e.doc; + e.state.backgroundColor = doc.tab.backgroundColor; + e.state.dark = doc.tab.classList.names.indexOf("dark") > -1; + }); + plugin.on("setState", function(e) { + e.doc.tab.backgroundColor = e.state.backgroundColor; + if (e.state.dark) + e.doc.tab.classList.add("dark"); + }); + plugin.on("clear", function(){ + }); + plugin.on("focus", function(){ + }); + plugin.on("enable", function(){ + }); + plugin.on("disable", function(){ + }); + plugin.on("unload", function(){ + }); + + /***** Register and define API *****/ + + /** + * The urlview handle, responsible for events that involve all + * UrlView instances. This is the object you get when you request + * the urlview service in your plugin. + * + * Example: + * + * define(function(require, exports, module) { + * main.consumes = ["urlview"]; + * main.provides = ["myplugin"]; + * return main; + * + * function main(options, imports, register) { + * var urlviewHandle = imports.urlview; + * }); + * }); + * + * + * @class urlview + * @extends Plugin + * @singleton + */ + /** + * Simple URL Viewer for Cloud9. This is not an actual editor + * but instead loads an iframe in an editor tab. This editor can + * only be instantiated programmatically and should be used when + * you need to show a website in Cloud9. + * + * Note that this plugin is not intended for previewing content, + * use the {@link Preview} plugin for that purpose. + * + * This example shows how to create a tab that shows c9.io. + * + * tabManager.open({ + * value : "http://www.c9.io", + * editorType : "urlview", + * active : true, + * document : { + * urlview : { + * backgroundColor : "#FF0000", + * dark : true + * } + * } + * }, function(err, tab) { + * console.log("Done"); + * }) + * + * @class urlview.UrlView + * @extends Editor + **/ + /** + * The type of editor. Use this to create the urlview using + * {@link tabManager#openEditor} or {@link editors#createEditor}. + * @property {"urlview"} type + * @readonly + */ + /** + * Retrieves the state of a document in relation to this editor + * @param {Document} doc The document for which to return the state + * @method getState + * @return {Object} + * @return {String} return.backgroundColor The background color of the tab. + * @return {String} return.dark Whether the "dark" class is set to the tab. + */ + plugin.freezePublicAPI({ + + }); + + plugin.load("urlview" + counter++); + + return plugin; + } + + register(null, { + urlview: editors.register("urlview", "URL Viewer", + UrlView, extensions) + }); + } +}); \ No newline at end of file diff --git a/plugins/c9.ide.errorhandler/raygun.js b/plugins/c9.ide.errorhandler/raygun.js new file mode 100644 index 00000000..f586c42d --- /dev/null +++ b/plugins/c9.ide.errorhandler/raygun.js @@ -0,0 +1,1611 @@ +/*! Raygun4js - v1.8.4 - 2014-05-22 +* https://github.com/MindscapeHQ/raygun4js +* Copyright (c) 2014 MindscapeHQ; Licensed MIT */ + +define(function(require, exports, module) { + +;(function(window, undefined) { + + +var TraceKit = {}; +var _oldTraceKit = window.TraceKit; + +// global reference to slice +var _slice = [].slice; +var UNKNOWN_FUNCTION = '?'; + + +/** + * _has, a better form of hasOwnProperty + * Example: _has(MainHostObject, property) === true/false + * + * @param {Object} host object to check property + * @param {string} key to check + */ +function _has(object, key) { + return Object.prototype.hasOwnProperty.call(object, key); +} + +function _isUndefined(what) { + return typeof what === 'undefined'; +} + +/** + * TraceKit.noConflict: Export TraceKit out to another variable + * Example: var TK = TraceKit.noConflict() + */ +TraceKit.noConflict = function noConflict() { + window.TraceKit = _oldTraceKit; + return TraceKit; +}; + +/** + * TraceKit.wrap: Wrap any function in a TraceKit reporter + * Example: func = TraceKit.wrap(func); + * + * @param {Function} func Function to be wrapped + * @return {Function} The wrapped func + */ +TraceKit.wrap = function traceKitWrapper(func) { + function wrapped() { + try { + return func.apply(this, arguments); + } catch (e) { + TraceKit.report(e); + throw e; + } + } + return wrapped; +}; + +/** + * TraceKit.report: cross-browser processing of unhandled exceptions + * + * Syntax: + * TraceKit.report.subscribe(function(stackInfo) { ... }) + * TraceKit.report.unsubscribe(function(stackInfo) { ... }) + * TraceKit.report(exception) + * try { ...code... } catch(ex) { TraceKit.report(ex); } + * + * Supports: + * - Firefox: full stack trace with line numbers, plus column number + * on top frame; column number is not guaranteed + * - Opera: full stack trace with line and column numbers + * - Chrome: full stack trace with line and column numbers + * - Safari: line and column number for the top frame only; some frames + * may be missing, and column number is not guaranteed + * - IE: line and column number for the top frame only; some frames + * may be missing, and column number is not guaranteed + * + * In theory, TraceKit should work on all of the following versions: + * - IE5.5+ (only 8.0 tested) + * - Firefox 0.9+ (only 3.5+ tested) + * - Opera 7+ (only 10.50 tested; versions 9 and earlier may require + * Exceptions Have Stacktrace to be enabled in opera:config) + * - Safari 3+ (only 4+ tested) + * - Chrome 1+ (only 5+ tested) + * - Konqueror 3.5+ (untested) + * + * Requires TraceKit.computeStackTrace. + * + * Tries to catch all unhandled exceptions and report them to the + * subscribed handlers. Please note that TraceKit.report will rethrow the + * exception. This is REQUIRED in order to get a useful stack trace in IE. + * If the exception does not reach the top of the browser, you will only + * get a stack trace from the point where TraceKit.report was called. + * + * Handlers receive a stackInfo object as described in the + * TraceKit.computeStackTrace docs. + */ +TraceKit.report = (function reportModuleWrapper() { + var handlers = [], + lastException = null, + lastExceptionStack = null; + + /** + * Add a crash handler. + * @param {Function} handler + */ + function subscribe(handler) { + handlers.push(handler); + } + + /** + * Remove a crash handler. + * @param {Function} handler + */ + function unsubscribe(handler) { + for (var i = handlers.length - 1; i >= 0; --i) { + if (handlers[i] === handler) { + handlers.splice(i, 1); + } + } + } + + /** + * Dispatch stack information to all handlers. + * @param {Object.} stack + */ + function notifyHandlers(stack, windowError) { + var exception = null; + if (windowError && !TraceKit.collectWindowErrors) { + return; + } + for (var i in handlers) { + if (_has(handlers, i)) { + try { + handlers[i].apply(null, [stack].concat(_slice.call(arguments, 2))); + } catch (inner) { + exception = inner; + } + } + } + + if (exception) { + throw exception; + } + } + + var _oldOnerrorHandler = window.onerror; + + /** + * Ensures all global unhandled exceptions are recorded. + * Supported by Gecko and IE. + * @param {string} message Error message. + * @param {string} url URL of script that generated the exception. + * @param {(number|string)} lineNo The line number at which the error + * occurred. + */ + window.onerror = function traceKitWindowOnError(message, url, lineNo, columnNo, errorObj) { + var stack = null; + + if (errorObj) { + stack = TraceKit.computeStackTrace(errorObj); + } + else + { + if (lastExceptionStack) { + TraceKit.computeStackTrace.augmentStackTraceWithInitialElement(lastExceptionStack, url, lineNo, message); + stack = lastExceptionStack; + lastExceptionStack = null; + lastException = null; + } else { + var location = { + 'url': url, + 'line': lineNo, + 'column': columnNo + }; + location.func = TraceKit.computeStackTrace.guessFunctionName(location.url, location.line); + location.context = TraceKit.computeStackTrace.gatherContext(location.url, location.line); + stack = { + 'mode': 'onerror', + 'message': message, + 'url': document.location.href, + 'stack': [location], + 'useragent': navigator.userAgent + }; + } + } + + notifyHandlers(stack, 'from window.onerror'); + + if (_oldOnerrorHandler) { + return _oldOnerrorHandler.apply(this, arguments); + } + + return false; + }; + + /** + * Reports an unhandled Error to TraceKit. + * @param {Error} ex + */ + function report(ex) { + var args = _slice.call(arguments, 1); + if (lastExceptionStack) { + if (lastException === ex) { + return; // already caught by an inner catch block, ignore + } else { + var s = lastExceptionStack; + lastExceptionStack = null; + lastException = null; + notifyHandlers.apply(null, [s, null].concat(args)); + } + } + + var stack = TraceKit.computeStackTrace(ex); + lastExceptionStack = stack; + lastException = ex; + + // If the stack trace is incomplete, wait for 2 seconds for + // slow slow IE to see if onerror occurs or not before reporting + // this exception; otherwise, we will end up with an incomplete + // stack trace + window.setTimeout(function () { + if (lastException === ex) { + lastExceptionStack = null; + lastException = null; + notifyHandlers.apply(null, [stack, null].concat(args)); + } + }, (stack.incomplete ? 2000 : 0)); + + throw ex; // re-throw to propagate to the top level (and cause window.onerror) + } + + report.subscribe = subscribe; + report.unsubscribe = unsubscribe; + return report; +}()); + +/** + * TraceKit.computeStackTrace: cross-browser stack traces in JavaScript + * + * Syntax: + * s = TraceKit.computeStackTrace.ofCaller([depth]) + * s = TraceKit.computeStackTrace(exception) // consider using TraceKit.report instead (see below) + * Returns: + * s.name - exception name + * s.message - exception message + * s.stack[i].url - JavaScript or HTML file URL + * s.stack[i].func - function name, or empty for anonymous functions (if guessing did not work) + * s.stack[i].args - arguments passed to the function, if known + * s.stack[i].line - line number, if known + * s.stack[i].column - column number, if known + * s.stack[i].context - an array of source code lines; the middle element corresponds to the correct line# + * s.mode - 'stack', 'stacktrace', 'multiline', 'callers', 'onerror', or 'failed' -- method used to collect the stack trace + * + * Supports: + * - Firefox: full stack trace with line numbers and unreliable column + * number on top frame + * - Opera 10: full stack trace with line and column numbers + * - Opera 9-: full stack trace with line numbers + * - Chrome: full stack trace with line and column numbers + * - Safari: line and column number for the topmost stacktrace element + * only + * - IE: no line numbers whatsoever + * + * Tries to guess names of anonymous functions by looking for assignments + * in the source code. In IE and Safari, we have to guess source file names + * by searching for function bodies inside all page scripts. This will not + * work for scripts that are loaded cross-domain. + * Here be dragons: some function names may be guessed incorrectly, and + * duplicate functions may be mismatched. + * + * TraceKit.computeStackTrace should only be used for tracing purposes. + * Logging of unhandled exceptions should be done with TraceKit.report, + * which builds on top of TraceKit.computeStackTrace and provides better + * IE support by utilizing the window.onerror event to retrieve information + * about the top of the stack. + * + * Note: In IE and Safari, no stack trace is recorded on the Error object, + * so computeStackTrace instead walks its *own* chain of callers. + * This means that: + * * in Safari, some methods may be missing from the stack trace; + * * in IE, the topmost function in the stack trace will always be the + * caller of computeStackTrace. + * + * This is okay for tracing (because you are likely to be calling + * computeStackTrace from the function you want to be the topmost element + * of the stack trace anyway), but not okay for logging unhandled + * exceptions (because your catch block will likely be far away from the + * inner function that actually caused the exception). + * + * Tracing example: + * function trace(message) { + * var stackInfo = TraceKit.computeStackTrace.ofCaller(); + * var data = message + "\n"; + * for(var i in stackInfo.stack) { + * var item = stackInfo.stack[i]; + * data += (item.func || '[anonymous]') + "() in " + item.url + ":" + (item.line || '0') + "\n"; + * } + * if (window.console) + * console.info(data); + * else + * alert(data); + * } + */ +TraceKit.computeStackTrace = (function computeStackTraceWrapper() { + var debug = false, + sourceCache = {}; + + /** + * Attempts to retrieve source code via XMLHttpRequest, which is used + * to look up anonymous function names. + * @param {string} url URL of source code. + * @return {string} Source contents. + */ + function loadSource(url) { + if (!TraceKit.remoteFetching) { //Only attempt request if remoteFetching is on. + return ''; + } + try { + function getXHR() { + try { + return new window.XMLHttpRequest(); + } catch (e) { + // explicitly bubble up the exception if not found + return new window.ActiveXObject('Microsoft.XMLHTTP'); + } + } + + var request = getXHR(); + request.open('GET', url, false); + request.send(''); + return request.responseText; + } catch (e) { + return ''; + } + } + + /** + * Retrieves source code from the source code cache. + * @param {string} url URL of source code. + * @return {Array.} Source contents. + */ + function getSource(url) { + if (!_has(sourceCache, url)) { + // URL needs to be able to fetched within the acceptable domain. Otherwise, + // cross-domain errors will be triggered. + var source = ''; + + url = url || ""; + + if (url.indexOf(document.domain) !== -1) { + source = loadSource(url); + } + sourceCache[url] = source ? source.split('\n') : []; + } + + return sourceCache[url]; + } + + /** + * Tries to use an externally loaded copy of source code to determine + * the name of a function by looking at the name of the variable it was + * assigned to, if any. + * @param {string} url URL of source code. + * @param {(string|number)} lineNo Line number in source code. + * @return {string} The function name, if discoverable. + */ + function guessFunctionName(url, lineNo) { + var reFunctionArgNames = /function ([^(]*)\(([^)]*)\)/, + reGuessFunction = /['"]?([0-9A-Za-z$_]+)['"]?\s*[:=]\s*(function|eval|new Function)/, + line = '', + maxLines = 10, + source = getSource(url), + m; + + if (!source.length) { + return UNKNOWN_FUNCTION; + } + + // Walk backwards from the first line in the function until we find the line which + // matches the pattern above, which is the function definition + for (var i = 0; i < maxLines; ++i) { + line = source[lineNo - i] + line; + + if (!_isUndefined(line)) { + if ((m = reGuessFunction.exec(line))) { + return m[1]; + } else if ((m = reFunctionArgNames.exec(line))) { + return m[1]; + } + } + } + + return UNKNOWN_FUNCTION; + } + + /** + * Retrieves the surrounding lines from where an exception occurred. + * @param {string} url URL of source code. + * @param {(string|number)} line Line number in source code to centre + * around for context. + * @return {?Array.} Lines of source code. + */ + function gatherContext(url, line) { + var source = getSource(url); + + if (!source.length) { + return null; + } + + var context = [], + // linesBefore & linesAfter are inclusive with the offending line. + // if linesOfContext is even, there will be one extra line + // *before* the offending line. + linesBefore = Math.floor(TraceKit.linesOfContext / 2), + // Add one extra line if linesOfContext is odd + linesAfter = linesBefore + (TraceKit.linesOfContext % 2), + start = Math.max(0, line - linesBefore - 1), + end = Math.min(source.length, line + linesAfter - 1); + + line -= 1; // convert to 0-based index + + for (var i = start; i < end; ++i) { + if (!_isUndefined(source[i])) { + context.push(source[i]); + } + } + + return context.length > 0 ? context : null; + } + + /** + * Escapes special characters, except for whitespace, in a string to be + * used inside a regular expression as a string literal. + * @param {string} text The string. + * @return {string} The escaped string literal. + */ + function escapeRegExp(text) { + return text.replace(/[\-\[\]{}()*+?.,\\\^$|#]/g, '\\$&'); + } + + /** + * Escapes special characters in a string to be used inside a regular + * expression as a string literal. Also ensures that HTML entities will + * be matched the same as their literal friends. + * @param {string} body The string. + * @return {string} The escaped string. + */ + function escapeCodeAsRegExpForMatchingInsideHTML(body) { + return escapeRegExp(body).replace('<', '(?:<|<)').replace('>', '(?:>|>)').replace('&', '(?:&|&)').replace('"', '(?:"|")').replace(/\s+/g, '\\s+'); + } + + /** + * Determines where a code fragment occurs in the source code. + * @param {RegExp} re The function definition. + * @param {Array.} urls A list of URLs to search. + * @return {?Object.} An object containing + * the url, line, and column number of the defined function. + */ + function findSourceInUrls(re, urls) { + var source, m; + for (var i = 0, j = urls.length; i < j; ++i) { + // console.log('searching', urls[i]); + if ((source = getSource(urls[i])).length) { + source = source.join('\n'); + if ((m = re.exec(source))) { + // console.log('Found function in ' + urls[i]); + + return { + 'url': urls[i], + 'line': source.substring(0, m.index).split('\n').length, + 'column': m.index - source.lastIndexOf('\n', m.index) - 1 + }; + } + } + } + + // console.log('no match'); + + return null; + } + + /** + * Determines at which column a code fragment occurs on a line of the + * source code. + * @param {string} fragment The code fragment. + * @param {string} url The URL to search. + * @param {(string|number)} line The line number to examine. + * @return {?number} The column number. + */ + function findSourceInLine(fragment, url, line) { + var source = getSource(url), + re = new RegExp('\\b' + escapeRegExp(fragment) + '\\b'), + m; + + line -= 1; + + if (source && source.length > line && (m = re.exec(source[line]))) { + return m.index; + } + + return null; + } + + /** + * Determines where a function was defined within the source code. + * @param {(Function|string)} func A function reference or serialized + * function definition. + * @return {?Object.} An object containing + * the url, line, and column number of the defined function. + */ + function findSourceByFunctionBody(func) { + var urls = [window.location.href], + scripts = document.getElementsByTagName('script'), + body, + code = '' + func, + codeRE = /^function(?:\s+([\w$]+))?\s*\(([\w\s,]*)\)\s*\{\s*(\S[\s\S]*\S)\s*\}\s*$/, + eventRE = /^function on([\w$]+)\s*\(event\)\s*\{\s*(\S[\s\S]*\S)\s*\}\s*$/, + re, + parts, + result; + + for (var i = 0; i < scripts.length; ++i) { + var script = scripts[i]; + if (script.src) { + urls.push(script.src); + } + } + + if (!(parts = codeRE.exec(code))) { + re = new RegExp(escapeRegExp(code).replace(/\s+/g, '\\s+')); + } + + // not sure if this is really necessary, but I don’t have a test + // corpus large enough to confirm that and it was in the original. + else { + var name = parts[1] ? '\\s+' + parts[1] : '', + args = parts[2].split(',').join('\\s*,\\s*'); + + body = escapeRegExp(parts[3]).replace(/;$/, ';?'); // semicolon is inserted if the function ends with a comment.replace(/\s+/g, '\\s+'); + re = new RegExp('function' + name + '\\s*\\(\\s*' + args + '\\s*\\)\\s*{\\s*' + body + '\\s*}'); + } + + // look for a normal function definition + if ((result = findSourceInUrls(re, urls))) { + return result; + } + + // look for an old-school event handler function + if ((parts = eventRE.exec(code))) { + var event = parts[1]; + body = escapeCodeAsRegExpForMatchingInsideHTML(parts[2]); + + // look for a function defined in HTML as an onXXX handler + re = new RegExp('on' + event + '=[\\\'"]\\s*' + body + '\\s*[\\\'"]', 'i'); + + if ((result = findSourceInUrls(re, urls[0]))) { + return result; + } + + // look for ??? + re = new RegExp(body); + + if ((result = findSourceInUrls(re, urls))) { + return result; + } + } + + return null; + } + + // Contents of Exception in various browsers. + // + // SAFARI: + // ex.message = Can't find variable: qq + // ex.line = 59 + // ex.sourceId = 580238192 + // ex.sourceURL = http://... + // ex.expressionBeginOffset = 96 + // ex.expressionCaretOffset = 98 + // ex.expressionEndOffset = 98 + // ex.name = ReferenceError + // + // FIREFOX: + // ex.message = qq is not defined + // ex.fileName = http://... + // ex.lineNumber = 59 + // ex.stack = ...stack trace... (see the example below) + // ex.name = ReferenceError + // + // CHROME: + // ex.message = qq is not defined + // ex.name = ReferenceError + // ex.type = not_defined + // ex.arguments = ['aa'] + // ex.stack = ...stack trace... + // + // INTERNET EXPLORER: + // ex.message = ... + // ex.name = ReferenceError + // + // OPERA: + // ex.message = ...message... (see the example below) + // ex.name = ReferenceError + // ex.opera#sourceloc = 11 (pretty much useless, duplicates the info in ex.message) + // ex.stacktrace = n/a; see 'opera:config#UserPrefs|Exceptions Have Stacktrace' + + /** + * Computes stack trace information from the stack property. + * Chrome and Gecko use this property. + * Added WinJS regex for Raygun4JS's offline caching support + * @param {Error} ex + * @return {?Object.} Stack trace information. + */ + function computeStackTraceFromStackProp(ex) { + if (!ex.stack) { + return null; + } + + var chrome = /^\s*at (?:((?:\[object object\])?\S+) )?\(?((?:file|http|https):.*?):(\d+)(?::(\d+))?\)?\s*$/i, + gecko = /^\s*(\S*)(?:\((.*?)\))?@((?:file|http|https).*?):(\d+)(?::(\d+))?\s*$/i, + winjs = /^\s*at (?:((?:\[object object\])?.+) )?\(?((?:ms-appx|http|https):.*?):(\d+)(?::(\d+))?\)?\s*$/i, + lines = ex.stack.split('\n'), + stack = [], + parts, + element, + reference = /^(.*) is undefined$/.exec(ex.message); + + for (var i = 0, j = lines.length; i < j; ++i) { + if ((parts = gecko.exec(lines[i]))) { + element = { + 'url': parts[3], + 'func': parts[1] || UNKNOWN_FUNCTION, + 'args': parts[2] ? parts[2].split(',') : '', + 'line': +parts[4], + 'column': parts[5] ? +parts[5] : null + }; + } else if ((parts = chrome.exec(lines[i]))) { + element = { + 'url': parts[2], + 'func': parts[1] || UNKNOWN_FUNCTION, + 'line': +parts[3], + 'column': parts[4] ? +parts[4] : null + }; + } else if ((parts = winjs.exec(lines[i]))) { + element = { + 'url': parts[2], + 'func': parts[1] || UNKNOWN_FUNCTION, + 'line': +parts[3], + 'column': parts[4] ? +parts[4] : null + }; + } else { + continue; + } + + if (!element.func && element.line) { + element.func = guessFunctionName(element.url, element.line); + } + + if (element.line) { + element.context = gatherContext(element.url, element.line); + } + + stack.push(element); + } + + if (stack[0] && stack[0].line && !stack[0].column && reference) { + stack[0].column = findSourceInLine(reference[1], stack[0].url, stack[0].line); + } + + if (!stack.length) { + return null; + } + + return { + 'mode': 'stack', + 'name': ex.name, + 'message': ex.message, + 'url': document.location.href, + 'stack': stack, + 'useragent': navigator.userAgent + }; + } + + /** + * Computes stack trace information from the stacktrace property. + * Opera 10 uses this property. + * @param {Error} ex + * @return {?Object.} Stack trace information. + */ + function computeStackTraceFromStacktraceProp(ex) { + // Access and store the stacktrace property before doing ANYTHING + // else to it because Opera is not very good at providing it + // reliably in other circumstances. + var stacktrace = ex.stacktrace; + + var testRE = / line (\d+), column (\d+) in (?:]+)>|([^\)]+))\((.*)\) in (.*):\s*$/i, + lines = stacktrace.split('\n'), + stack = [], + parts; + + for (var i = 0, j = lines.length; i < j; i += 2) { + if ((parts = testRE.exec(lines[i]))) { + var element = { + 'line': +parts[1], + 'column': +parts[2], + 'func': parts[3] || parts[4], + 'args': parts[5] ? parts[5].split(',') : [], + 'url': parts[6] + }; + + if (!element.func && element.line) { + element.func = guessFunctionName(element.url, element.line); + } + if (element.line) { + try { + element.context = gatherContext(element.url, element.line); + } catch (exc) {} + } + + if (!element.context) { + element.context = [lines[i + 1]]; + } + + stack.push(element); + } + } + + if (!stack.length) { + return null; + } + + return { + 'mode': 'stacktrace', + 'name': ex.name, + 'message': ex.message, + 'url': document.location.href, + 'stack': stack, + 'useragent': navigator.userAgent + }; + } + + /** + * NOT TESTED. + * Computes stack trace information from an error message that includes + * the stack trace. + * Opera 9 and earlier use this method if the option to show stack + * traces is turned on in opera:config. + * @param {Error} ex + * @return {?Object.} Stack information. + */ + function computeStackTraceFromOperaMultiLineMessage(ex) { + // Opera includes a stack trace into the exception message. An example is: + // + // Statement on line 3: Undefined variable: undefinedFunc + // Backtrace: + // Line 3 of linked script file://localhost/Users/andreyvit/Projects/TraceKit/javascript-client/sample.js: In function zzz + // undefinedFunc(a); + // Line 7 of inline#1 script in file://localhost/Users/andreyvit/Projects/TraceKit/javascript-client/sample.html: In function yyy + // zzz(x, y, z); + // Line 3 of inline#1 script in file://localhost/Users/andreyvit/Projects/TraceKit/javascript-client/sample.html: In function xxx + // yyy(a, a, a); + // Line 1 of function script + // try { xxx('hi'); return false; } catch(ex) { TraceKit.report(ex); } + // ... + + var lines = ex.message.split('\n'); + if (lines.length < 4) { + return null; + } + + var lineRE1 = /^\s*Line (\d+) of linked script ((?:file|http|https)\S+)(?:: in function (\S+))?\s*$/i, + lineRE2 = /^\s*Line (\d+) of inline#(\d+) script in ((?:file|http|https)\S+)(?:: in function (\S+))?\s*$/i, + lineRE3 = /^\s*Line (\d+) of function script\s*$/i, + stack = [], + scripts = document.getElementsByTagName('script'), + inlineScriptBlocks = [], + parts, + i, + len, + source; + + for (i in scripts) { + if (_has(scripts, i) && !scripts[i].src) { + inlineScriptBlocks.push(scripts[i]); + } + } + + for (i = 2, len = lines.length; i < len; i += 2) { + var item = null; + if ((parts = lineRE1.exec(lines[i]))) { + item = { + 'url': parts[2], + 'func': parts[3], + 'line': +parts[1] + }; + } else if ((parts = lineRE2.exec(lines[i]))) { + item = { + 'url': parts[3], + 'func': parts[4] + }; + var relativeLine = (+parts[1]); // relative to the start of the ' + : ''; + var generateInstrumentedHTML = require("../c9.ide.language.html.diff/HTMLSimpleDOM").generateInstrumentedHTML; + + var buffer = ""; + request.on("data", function(data) { + buffer += data; + }); + request.on("end", function(data) { + if (data) + buffer += data; + + if (shouldInject) + buffer = generateInstrumentedHTML(buffer) || ""; + data = new Buffer(buffer); + res.writeHead(200, { + "content-length": data.length + inject.length, + "content-type": request.headers["content-type"], + "etag": request.headers.etag, + "date": request.headers.data, + "access-control-allow-origin": "https://ide." + ideHost + }); + res.write(data); + + res.end(inject); + }); + } + + function serveFile(request) { + debug("forward file %s", request.url); + res.writeHead(request.statusCode, request.headers); + request.pipe(res); + } + + }; + } + + register(null, { + "preview.handler": { + getProjectSession: getProjectSession, + getRole: getRole, + proxyCall: proxyCall + } + }); + } +}); \ No newline at end of file diff --git a/plugins/c9.preview/preview.js b/plugins/c9.preview/preview.js new file mode 100644 index 00000000..8969bdc4 --- /dev/null +++ b/plugins/c9.preview/preview.js @@ -0,0 +1,127 @@ +define(function(require, exports, module) { + "use strict"; + + main.consumes = [ + "session", + "db", + "c9.login", + "preview.handler" + ]; + main.provides = []; + return main; + + function main(options, imports, register) { + var maxVfsAge = options.maxVfsAge || 20 * 1000; + var region = options.region; + + var session = imports.session; + var db = imports.db; + var ensureLoggedIn = imports["c9.login"].ensureLoggedIn(); + var handler = imports["preview.handler"]; + + var frontdoor = require("frontdoor"); + var error = require("http-error"); + var requestTimeout = require("c9/request_timeout"); + + var api = frontdoor(); + var vfsServers; + + api.registerType("username", /^[0-9a-z_\-]*$/i); + api.registerType("projectname", /^[0-9a-z\-_]*$/i); + + api.use(function(req, res, next) { + res.setHeader("X-Content-Type-Options", "nosniff"); + next(); + }); + + session.use(api); + + api.get("/:username/:projectname/:path*", { + params: { + username: { + type: "username" + }, + projectname: { + type: "projectname" + } + } + }, [ + requestTimeout(15*60*1000), + handler.getProjectSession(), + handler.getRole(db), + handler.proxyCall(function() { + return vfsServers ? vfsServers[0] : null; + }) + ]); + + api.error(function(err, req, res, next) { + if (err instanceof error.Unauthorized) { + req.logout(); + delete req.session.token; + return ensureLoggedIn(req, res, next); + } + return next(err); + }); + + api.get("/:username/:projectname", { + params: { + username: { + type: "username" + }, + projectname: { + type: "projectname" + } + } + }, function(req, res, next) { + res.redirect(req.url + "/"); + }); + + function updateVfsServerList(callback) { + db.Vfs.findAllAndPurge(maxVfsAge, function(err, servers) { + if (err) + return callback(err); + if (!servers.length) + return callback(new Error("No VFS server available")); + + vfsServers = shuffleServers(servers); + callback(); + }); + } + + function shuffleServers(servers) { + servers = servers.slice(); + var isBeta = region == "beta"; + servers = servers.filter(function(s) { + return isBeta ? s.region == "beta" : s.region !== "beta"; + }); + return servers.sort(function(a, b) { + if (a.region == b.region) { + if (a.load < b.load) + return -1; + else + return 1; + } + else if (a.region == region) + return -1; + else if (b.region == region) + return 1; + else + return 0; + }); + } + + load(); + function load() { + updateVfsServerList(function(err) { + if (err) + return setTimeout(load, 20000); + + setInterval(updateVfsServerList.bind(null, function(err) { + if (err) console.error("Retrieving VFS server list failed", err); + }), 20 * 1000); + + register(); + }); + } + } +}); \ No newline at end of file diff --git a/plugins/c9.preview/static/livecss.js b/plugins/c9.preview/static/livecss.js new file mode 100644 index 00000000..bab98140 --- /dev/null +++ b/plugins/c9.preview/static/livecss.js @@ -0,0 +1,1027 @@ +(function() { + +var parent = window.opener || window.parent; +if (!parent) return; + +var host = (location.search.match(/_c9_host=(.*?)(?:$|&)/) || false)[1]; +var id = (location.search.match(/[?&]_c9_id=([a-zA-Z0-9]+)(?:$|&)/) || false)[1]; + +if (!host || !id) { + var cookies = document.cookie.split(";"); + cookies.forEach(function(c) { + var parts = c.split("="); + var key = parts.shift().replace(/^\s+/, ""); + + if (key == "_c9_host") host = parts.join(";"); + else if (key == "_c9_id") id = parts.join(";"); + }); + + if (!host || !id) + return; +} +else { + document.cookie = "_c9_host=" + host; + document.cookie = "_c9_id=" + id; +} + +var mainPath = location.href.split("?")[0]; +var isHosted = mainPath.indexOf("/preview") == -1; +var importedStyles = {}; +var session, reloader; + +function init(id) { + if (session) + return console.error("connection alreay established"); + + reloader = new Reloader(window, console); + + window.addEventListener("message", function(e) { + var data = e.data; + + // TODO check origin + if (data.id != id || host != "local" && e.origin !== host) + return; + + if (data.type == "updatecss") { + reloader.reloadStyleSheet(data.path, data.data); + resize(); + } + else if (data.type == "domedits") + editHandler.apply(data.edits); + else if (data.type == "initdom") + editHandler.initDom(data.dom); + else if (data.type == "simpledom") { + var dom = getSimpleDOM(); + send({ message: "callback", data: dom, cb: data.cb }); + } + else if (data.type == "keys") + setKeys(data.keys); + else if (data.type == "stylerule") { + updateStyleRule(data.url, data.rule); + resize(); + } + else if (data.type == "highlight") + highlightByCssQuery(data.query); + else if (data.type == "reload") + window.location.reload(); + else if (data.type == "reveal") { + highlightByCssQuery(data.query); + var el = document.querySelector(data.query); + if (el) + (el.scrollIntoViewIfNeeded || el.scrollIntoView).call(el); + } + }); + + var styles = reloader.getAllStylesheets(); + var scripts = reloader.getAllScripts(); + + session = { + id: id, + styles: styles, + scripts: scripts //@todo + }; + + setTimeout(function(){ + send({ + message: "html.ready", + data: { + styles: session.styles.map(function(n){ return n.path }), + scripts: session.scripts.map(function(n){ return n.path }), + href: document.location.pathname.replace(/^\/preview\//, "/") + } + }); + }, 1000); +} + +function urlToPath(url, base) { + // Absolute Path + if (url.charAt(0) == "/") { + // return url; + } + // Absolute URL + else if (url.match(/^https?:\/\//)) { + var origin = location.origin; + if (url.substr(0, origin.length) == origin) { + url = url.substr(origin.length); + } + // return url; + } + else { + if (!base) base = dirname(location.pathname); + url = join(base, url); + } + + if (!isHosted) + url = url.replace(/^\/preview/, ""); + + return url; +} + +function getDataUrl(data){ return "data:text/css," + data.replace(/\n/g, ""); } +function dirname(path){ return path.substr(0, path.lastIndexOf("/")); } +function join(base, path) { + if (path.charAt(0) != "/") { + var parts = path.split("/"); + var sparts = base.split("/"); + for (var i = 0; i < parts.length; i++) { + if (parts[i] == "..") + sparts.pop(); + else + sparts.push(parts[i]); + } + return sparts.join("/"); + } + + return path; +} + +/**** RELOADER ****/ + +/*global CSSRule*/ +function Reloader(win, console) { + + function getAllStylesheets(){ + var results = []; + var nodes, node, i, path; + + // Link tags + nodes = win.document.querySelectorAll("link"); + for (i = 0; i < nodes.length; i++) { + node = nodes[i]; + path = urlToPath(node.href); + results.push({ path: path, href: node.href, node: node }); + findImportedSheets(node, node.sheet, results, dirname(path)); + } + + // Style tags + nodes = win.document.querySelectorAll("style"); + for (i = 0; i < nodes.length; i++) { + node = nodes[i]; + if (node.c9__path) + results.push({ path: node.c9__path, href: node.c9__href, node: node }); + if (node.sheet) + findImportedSheets(node, node.sheet, results, + dirname(node.c9__path || mainPath)); + } + + if (win.StyleFix) { + nodes = win.document.querySelectorAll('style[data-href]'); + for (i = 0; i < nodes.length; i++) { + var href = urlToPath(nodes[i].getAttribute('data-href')); + results.push({ path: urlToPath(href), href: href, node: nodes[i] }); + } + } + + return results; + } + + function getAllScripts(){ + var results = []; + var nodes, node, i, path; + + // Link tags + nodes = win.document.querySelectorAll("script[src]"); + for (i = 0; i < nodes.length; i++) { + node = nodes[i]; + if (node.src.indexOf("/livecss.js") > -1) continue; + + path = urlToPath(node.src); + results.push({ path: path, src: node.src, node: node }); + } + + return results; + } + + function findStylesheet(path) { + var results = session.styles; //getAllStylesheets(); + + return pickBestMatch(path, results, function(item) { + return item.path; + }); + } + + function findImportedSheets(node, styleSheet, results, base) { + try { + var rules = styleSheet !== null ? styleSheet.cssRules : void 0; + } catch (_error) { + return; + } + + if (rules && rules.length) { + var rule; + for (var i = rules.length - 1; i >= 0; i--) { + rule = rules[i]; + switch (rule.type) { + case CSSRule.CHARSET_RULE: + continue; + case CSSRule.IMPORT_RULE: + var path = urlToPath(rule.href, base); + if (importedStyles[path]) { + styleSheet.deleteRule(i); + break; + } + + results.push({ + node: node, + rule: rule, + index: i, + path: path, + href: rule.href + }); + findImportedSheets(node, rule.styleSheet, results, dirname(path)); + break; + default: + break; + } + } + } + } + + function pickBestMatch(path, objects, pathFunc) { + var bestMatch, object, score, _i, _len; + bestMatch = { + score: 0 + }; + for (_i = 0, _len = objects.length; _i < _len; _i++) { + object = objects[_i]; + score = numberOfMatchingSegments(path, pathFunc(object)); + if (score > bestMatch.score) { + bestMatch = { + object: object, + score: score + }; + } + } + if (bestMatch.score > 0) { + return bestMatch; + } else { + return null; + } + } + + function numberOfMatchingSegments(path1, path2) { + var comps1, comps2, eqCount, len; + path1 = path1.replace(/^\/+/, '').toLowerCase(); + path2 = path2.replace(/^\/+/, '').toLowerCase(); + if (path1 === path2) { + return 10000; + } + comps1 = path1.split('/').reverse(); + comps2 = path2.split('/').reverse(); + len = Math.min(comps1.length, comps2.length); + eqCount = 0; + while (eqCount < len && comps1[eqCount] === comps2[eqCount]) { + ++eqCount; + } + return eqCount; + } + + // Normalize Image Paths + function normalizeImagePaths(cssPath, data) { + cssPath = cssPath.match(/^https?:\/\//) // If an absolute url + ? dirname(cssPath) // Retrieve the absolute path + : join(mainPath, dirname(cssPath)); // Normalize path, based on main path + + var expando = generateUniqueString(); + + return data.replace(/\burl\s*\("?([^)]*?)"?\)/g, function(match, src) { + if (!src.match(/^https?:\/\//)) { // Ignore absolute paths + var path = join(cssPath, src); + return "url(" + (generateCacheBustUrl(path, expando)) + ")"; + } else { + return match; + } + }); + } + + function generateUniqueString() { + return 'livereload=' + Date.now(); + } + + function generateCacheBustUrl(url, expando) { + if (!expando) + expando = this.generateUniqueString(); + + var parts = url.split("#"); + var base = parts[0]; + var hash = parts[1] || ""; + + var newBase = base.replace(/(\?|&)livereload=(\d+)/, function(match, sep) { + return "" + sep + expando; + }); + if (newBase === base) + newBase += (~base.indexOf("?") ? "&" : "?") + expando; + return newBase + hash; + } + + function reloadStyleSheet(path, content) { + // Find Stylesheet + var match = findStylesheet(path); + if (!match) return; + + match = match.object; + var replaced, node; + + // If Imported Rule + if (match.rule) { + node = document.createElement("style"); + node.c9__path = match.path; + node.c9__href = match.href; + + // Delete Rule + match.rule.parentStyleSheet.deleteRule(match.index); + delete match.rule; + + // Insert style rule + match.node.parentNode.insertBefore(node, match.node); + match.node = node; + + // Add to list of replaces import rules + importedStyles[match.path] = match; + + replaced = true; + } + // If Link, replace link with style node + else if (match.node.tagName == "LINK") { + node = document.createElement("style"); + node.c9__path = match.path; + node.c9__href = match.href; + + match.node.parentNode.insertBefore(node, match.node); + match.node.parentNode.removeChild(match.node); + match.node = node; + + for (var i = session.styles.length - 1; i >= 0; i--) { + if (session.styles[i].rule && session.styles[i].node == node) + session.styles.splice(i); + } + + replaced = true; + } + + // Set content + match.node.textContent = normalizeImagePaths(match.href, content); + + if (replaced) + findImportedSheets(node, node.sheet, session.styles, dirname(match.path)); + } + + function reloadImage(path) { + + } + + return { + reloadStyleSheet: reloadStyleSheet, + + reloadImage: reloadImage, + + findStylesheet: findStylesheet, + + getAllStylesheets: getAllStylesheets, + + getAllScripts: getAllScripts + }; +} + +// Keys +var ckb; +function setKeys(list) { + ckb = {}; + + list.forEach(function(item) { + var binding = item.binding; + var command = item.command; + var hashId = binding.hashId; + var hash = (ckb[hashId] || (ckb[hashId] = {})); + + if (!hash[binding.key]) { + hash[binding.key] = command; + } else { + if (!Array.isArray(hash[binding.key])) + hash[binding.key] = [hash[binding.key]]; + + hash[binding.key].push(command); + } + }, this); +} + +document.addEventListener("keydown", function(e) { + var hashId = 0 | (e.ctrlKey ? 1 : 0) | (e.altKey ? 2 : 0) + | (e.shiftKey ? 4 : 0) | (e.metaKey ? 8 : 0); + + var keys = ckb[hashId]; + var cmd = keys && keys[e.keyCode]; + + if (cmd) { + send({ message: "exec", command: cmd }); + + e.preventDefault(); + e.stopPropagation(); + } +}); + +window.addEventListener("focus", function(){ + send({ message: "focus" }); + removeHighlight(); +}); + +// Highlight + +var HIGHLIGHT_CLASSNAME = "c9___highlighter"; + +var last = [], lastHighlight; +function removeHighlight(){ + last.forEach(function(item) { + item.destroy(); + }); +} + +function Highlight(div, text, setDisplayName) { + var cover = document.documentElement.appendChild(document.createElement("c9__div")); + cover.style.position = "fixed"; + cover.style.zIndex = 10000000000; + cover.style.border = "1px solid rgba(238, 238, 48, 0.5)"; //rgba(128, 128, 128, 0.85)" + cover.style.boxSizing = "border-box"; + cover.style.boxShadow = "0 0 20px rgba(0,0,0,0.5)"; + cover.style.pointerEvents = "none"; + cover.style.color = "black"; + cover.className = HIGHLIGHT_CLASSNAME; + cover.innerHTML = ""; + cover.style.background = "transparent"; //"rgba(53, 239, 255, 0.5)"; + + var child = cover.firstChild; + child.style.whiteSpace = "nowrap"; + + var arrow = child.firstChild; + var label = child.lastChild; + + arrow.style.border = "7px inset blue"; + arrow.style.borderColor = "transparent transparent rgb(228, 214, 140) transparent"; + arrow.style.position = "absolute"; + arrow.style.left = "3px"; + arrow.style.top = "-13px"; + + child.style.position = "absolute"; + child.style.bottom = "-20px"; + child.style.left = "0"; + child.style.fontFamily = "Arial"; + child.style.fontSize = "11px"; + child.style.background = "rgb(228, 214, 140)"; //"rgb(238, 238, 48)"; + child.style.color = "rgb(0, 0, 0)"; + child.style.padding = "2px 4px 3px 4px"; + child.style.borderRadius = "3px"; + child.style.boxShadow = "rgba(0, 0, 0, 0.7) 0px 1px 3px"; + label.style.color = child.style.color; + + + if (setDisplayName) { + text = div.tagName.toLowerCase() + + (div.id ? "#" + div.id + "" : "") + + (div.className ? "." + div.className.replace(/ /g, "") + "" : ""); + } + + this.resize = function(){ + var pos = div.getBoundingClientRect(); + cover.style.left = (pos.left - 1) + "px"; + cover.style.top = (pos.top - 1) + "px"; + cover.style.width = (pos.width + 2) + "px"; + cover.style.height = (pos.height + 2) + "px"; + + label.innerHTML = "" + text + " " + + pos.width + "px" + + " x " + + pos.height + "px"; + }; + + this.destroy = function(){ + if (cover.parentNode) + cover.parentNode.removeChild(cover); + }; + + this.resize(); +} + +function highlightByCssQuery(query) { + removeHighlight(); + last = []; + if (!query) { + lastHighlight = null; + return; + } + + var setDisplayName = query.match(/\[data\-\w+\-id='\d+'\]/) ? true : false; + + var nodes = document.querySelectorAll(query); + var len = Math.min(10, nodes.length); + for (var i = len - 1; i >= 0; i--) { + last.push(new Highlight(nodes[i], query, setDisplayName)); + } + + lastHighlight = { fn: highlightByCssQuery, query: query }; +} + +function redrawHighlights(){ + if (lastHighlight) { + lastHighlight.fn(lastHighlight.query); + } +} + +function resize(){ + last.forEach(function(item) { + item.resize(); + }); + + showSize(); + clearTimeout(timer); + timer = setTimeout(hideSize, 1000); +} + +var timer, sizeDiv; +function showSize(){ + if (!sizeDiv) { + sizeDiv = document.createElement("div"); + sizeDiv.style.position = "absolute"; + sizeDiv.style.zIndex = 100000000000; + sizeDiv.style.right = 0; + sizeDiv.style.top = 0; + sizeDiv.style.background = "rgba(255,255,255,0.7)"; + sizeDiv.style.color = "#333"; + sizeDiv.style.fontFamily = "Arial"; + sizeDiv.style.fontSize = "20px"; + sizeDiv.style.padding = "2px 6px"; + sizeDiv.style.borderRadius = "0 0 0 3px"; + } + + document.documentElement.appendChild(sizeDiv); + sizeDiv.innerHTML = window.innerWidth + "px \u00D7 " + window.innerHeight + "px"; +} +function hideSize(){ + if (sizeDiv.parentNode) + document.documentElement.removeChild(sizeDiv); +} + +window.addEventListener("resize", resize); +window.document.addEventListener("scroll", resize); + + +// Editing + +/** + * Constructor + * @param {Document} htmlDocument + */ +function DOMEditHandler(htmlDocument) { + this.htmlDocument = htmlDocument; + this.rememberedNodes = null; + this.entityParseParent = htmlDocument.createElement("div"); +} + +/** + * @private + * Find the first matching element with the specified data-cloud9-id + * @param {string} id + * @return {Element} + */ +DOMEditHandler.prototype._queryBracketsID = function (id) { + if (!id) { + return null; + } + + if (this.rememberedNodes && this.rememberedNodes[id]) { + return this.rememberedNodes[id]; + } + + var results = this.htmlDocument.querySelectorAll("[data-cloud9-id='" + id + "']"); + return results && results[0]; +}; + +/** + * @private + * Insert a new child element + * @param {Element} targetElement Parent element already in the document + * @param {Element} childElement New child element + * @param {Object} edit + */ +DOMEditHandler.prototype._insertChildNode = function (targetElement, childElement, edit) { + var before = this._queryBracketsID(edit.beforeID), + after = this._queryBracketsID(edit.afterID); + + if (edit.firstChild) { + before = targetElement.firstChild; + } else if (edit.lastChild) { + after = targetElement.lastChild; + } + + if (!childElement || !targetElement) { + return console.error("missing tagID"); + } + + if (before) { + targetElement.insertBefore(childElement, before); + } else if (after && (after !== targetElement.lastChild)) { + targetElement.insertBefore(childElement, after.nextSibling); + } else { + targetElement.appendChild(childElement); + } +}; + +/** + * @private + * Given a string containing encoded entity references, returns the string with the entities decoded. + * @param {string} text The text to parse. + * @return {string} The decoded text. + */ +DOMEditHandler.prototype._parseEntities = function (text, forTextarea) { + // Kind of a hack: just set the innerHTML of a div to the text, which will parse the entities, then + // read the content out. + if (forTextarea) text = ""; + this.entityParseParent.innerHTML = text; + var result = forTextarea + ? this.entityParseParent.firstChild.value + : this.entityParseParent.textContent; + this.entityParseParent.textContent = ""; + return result; +}; + +/** + * @private + * @param {Node} node + * @return {boolean} true if node expects its content to be raw text (not parsed for entities) according to the HTML5 spec. + */ +function _isRawTextNode(node) { + return (node.nodeType === Node.ELEMENT_NODE && /script|style|noscript|noframes|noembed|iframe|xmp/i.test(node.tagName)); +} + +/** + * @private + * Replace a range of text and comment nodes with an optional new text node + * @param {Element} targetElement + * @param {Object} edit + */ +DOMEditHandler.prototype._textReplace = function (targetElement, edit) { + function prevIgnoringHighlights(node) { + do { + node = node.previousSibling; + } while (node && node.className === HIGHLIGHT_CLASSNAME); + return node; + } + function nextIgnoringHighlights(node) { + do { + node = node.nextSibling; + } while (node && node.className === HIGHLIGHT_CLASSNAME); + return node; + } + function lastChildIgnoringHighlights(node) { + node = (node.childNodes.length ? node.childNodes.item(node.childNodes.length - 1) : null); + if (node && node.className === HIGHLIGHT_CLASSNAME) { + node = prevIgnoringHighlights(node); + } + return node; + } + + if (targetElement.tagName === "TEXTAREA") + return targetElement.value = this._parseEntities(edit.content, true); + + var start = (edit.afterID) ? this._queryBracketsID(edit.afterID) : null, + startMissing = edit.afterID && !start, + end = (edit.beforeID) ? this._queryBracketsID(edit.beforeID) : null, + endMissing = edit.beforeID && !end, + moveNext = start && nextIgnoringHighlights(start), + current = moveNext || (end && prevIgnoringHighlights(end)) || lastChildIgnoringHighlights(targetElement), + next, + lastRemovedWasText, + isText, + textNode; + if (edit.content !== undefined) + textNode = this.htmlDocument.createTextNode(_isRawTextNode(targetElement) + ? edit.content : this._parseEntities(edit.content)); + + // remove all nodes inside the range + while (current && (current !== end)) { + isText = current.nodeType === Node.TEXT_NODE; + + // if start is defined, delete following text nodes + // if start is not defined, delete preceding text nodes + next = (moveNext) ? nextIgnoringHighlights(current) : prevIgnoringHighlights(current); + + // only delete up to the nearest element. + // if the start/end tag was deleted in a prior edit, stop removing + // nodes when we hit adjacent text nodes + if ((current.nodeType === Node.ELEMENT_NODE) || + ((startMissing || endMissing) && (isText && lastRemovedWasText))) { + break; + } else { + lastRemovedWasText = isText; + + current.remove(); + current = next; + } + } + + if (textNode) { + // OK to use nextSibling here (not nextIgnoringHighlights) because we do literally + // want to insert immediately after the start tag. + if (start && start.nextSibling) { + targetElement.insertBefore(textNode, start.nextSibling); + } else if (end) { + if (end.parentNode !== targetElement) + return console.error("missing tagID"); + targetElement.insertBefore(textNode, end); + } else { + targetElement.appendChild(textNode); + } + } +}; + +/** + * @private + * Apply an array of DOM edits to the document + * @param {Array.} edits + */ +DOMEditHandler.prototype.apply = function (edits) { + var targetID, + targetElement, + childElement, + self = this; + + this.rememberedNodes = {}; + + edits.forEach(function (edit) { + var editIsSpecialTag = edit.type === "elementInsert" && (edit.tag === "html" || edit.tag === "head" || edit.tag === "body"); + + if (edit.type === "rememberNodes") { + edit.tagIDs.forEach(function (tagID) { + var node = self._queryBracketsID(tagID); + if (node) { + self.rememberedNodes[tagID] = node; + node.remove(); + } + }); + return; + } + + targetID = edit.type.match(/textReplace|textDelete|textInsert|elementInsert|elementMove/) ? edit.parentID : edit.tagID; + targetElement = self._queryBracketsID(targetID); + + if (!targetElement && !editIsSpecialTag) { + console.error("data-cloud9-id=" + targetID + " not found"); + return; + } + + switch (edit.type) { + case "attrChange": + case "attrAdd": + targetElement.setAttribute(edit.attribute, self._parseEntities(edit.value)); + break; + case "attrDelete": + targetElement.removeAttribute(edit.attribute); + break; + case "elementDelete": + targetElement.remove(); + break; + case "elementInsert": + childElement = null; + if (editIsSpecialTag) { + // If we already have one of these elements (which we should), then + // just copy the attributes and set the ID. + childElement = self.htmlDocument[edit.tag === "html" ? "documentElement" : edit.tag]; + if (!childElement) { + // Treat this as a normal insertion. + editIsSpecialTag = false; + } + } + if (!editIsSpecialTag) { + childElement = self.htmlDocument.createElement(edit.tag); + } + + Object.keys(edit.attributes).forEach(function (attr) { + childElement.setAttribute(attr, self._parseEntities(edit.attributes[attr])); + }); + childElement.setAttribute("data-cloud9-id", edit.tagID); + + if (!editIsSpecialTag) { + self._insertChildNode(targetElement, childElement, edit); + } + break; + case "elementMove": + childElement = self._queryBracketsID(edit.tagID); + self._insertChildNode(targetElement, childElement, edit); + break; + case "textInsert": + var textElement = self.htmlDocument.createTextNode(_isRawTextNode(targetElement) ? edit.content : self._parseEntities(edit.content)); + self._insertChildNode(targetElement, textElement, edit); + break; + case "textReplace": + case "textDelete": + self._textReplace(targetElement, edit); + break; + } + }); + + this.rememberedNodes = {}; + + // update highlight after applying diffs + redrawHighlights(); +}; + +DOMEditHandler.prototype.initDom = function (docState) { + if (docState.idMap && !this.initialized) { + this.initialized = true; + var idMap = docState.idMap; + var walk = function (el) { + var id = el.getAttribute("data-cloud9-id"); + if (idMap[id]) + el.setAttribute("data-cloud9-id", idMap[id]); + var ch = el.children; + for (var i = 0; i < ch.length; i++) walk(ch[i]); + }; + walk(document.documentElement); + } + else if (docState.dom) { + var dom = docState.dom; + if (!dom.children || document.documentElement.hasAttribute("data-cloud9-id")) + return; + var filter = function(dom) { + return dom.children = dom.children && dom.children.filter(function(x) { + if (x.children) + return filter(x); + }); + }; + filter(dom); + + var init = function(htmlNode, dom) { + htmlNode.setAttribute("data-cloud9-id", dom.tagID); + var children = htmlNode.children; + var domChildren = dom.children; + var match = false; + for (var i = 0, j = 0; i < children.length; i++) { + var htmlCh = children[i]; + var domCh = domChildren[j]; + j++; + if (!domCh || domCh.tag !== htmlCh.tagName.toLowerCase()) + continue; + match = true; + init(children[i], domChildren[i]); + } + if (domChildren.length != children.length) { + if (!match && children.length == 1) + init(children[0], dom); + } + }; + + document.documentElement.setAttribute("data-cloud9-id", 1); + var head = document.head; + var body = document.body; + head.setAttribute("data-cloud9-id", 2); + body.setAttribute("data-cloud9-id", 3); + var root = { + children: [], + setAttribute: function() {} + }; + for (var ch = head.children, i = 0; i < ch.length; i++) { + root.children.push(ch[i]); + } + for (var ch = body.children, i = 0; i < ch.length; i++) { + root.children.push(ch[i]); + } + + var flatten = function(node, i) { + var args = [i, 1].concat(node.children[i].children); + node.children.splice.apply(node.children, args); + }; + + if (dom.tag == "html") { + for (var ch = dom.children, i = ch.length; i--; ) { + if (ch[i].tag == "head" || ch[i].tag == "body") + flatten(dom, i); + } + } + + init(root, dom); + } + if (docState.edits) + this.apply(docState.edits); +}; + +/** + * + * @param {Element} elem + */ +function _domElementToJSON(elem) { + var json = { tag: elem.tagName.toLowerCase(), attributes: {}, children: [] }, + i, + len, + node, + value; + + len = elem.attributes.length; + for (i = 0; i < len; i++) { + node = elem.attributes.item(i); + value = (node.name === "data-cloud9-id") ? parseInt(node.value, 10) : node.value; + json.attributes[node.name] = value; + } + + len = elem.childNodes.length; + for (i = 0; i < len; i++) { + node = elem.childNodes.item(i); + + // ignores comment nodes and visuals generated by live preview + if (node.nodeType === Node.ELEMENT_NODE && node.className !== HIGHLIGHT_CLASSNAME) { + json.children.push(_domElementToJSON(node)); + } else if (node.nodeType === Node.TEXT_NODE) { + json.children.push({ content: node.nodeValue }); + } + } + + return json; +} + +function getSimpleDOM() { + return JSON.stringify(_domElementToJSON(document.documentElement)); +} + +// init +var editHandler = new DOMEditHandler(window.document); + +// Update Style Rule +function findCssRule(name, stylesheet) { + // chrome normalizes pseudo-elements to :: and firefox to : + name = name.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1') + .replace(/::?(after|before)/g, "::?$1"); + var nameRe = new RegExp("^" + name + "$", "i"); + var rules, i; + + if (!stylesheet) { + var sheets = window.document.styleSheets; + for (var j = sheets.length - 1; j >= 0; j--) { + try { + rules = sheets[j].cssRules; + for (i = 0; i < rules.length; i++) { + if (nameRe.test(rules.item(i).selectorText)) { + return rules.item(i); + } + } + } + catch (e) {} + } + } + else { + if (typeof stylesheet == "number") + stylesheet = window.document.styleSheets[stylesheet || 0]; + rules = stylesheet.cssRules; + if (!rules) return false; + for (i = 0; i < rules.length; i++) { + if (nameRe.test(rules.item(i).selectorText)) { + return rules.item(i); + } + } + } +} + +/** + * This method sets a single CSS rule. + * @param {String} name The CSS name of the rule (i.e. `.cls` or `#id`). + * @param {String} type The CSS property to change. + * @param {String} value The CSS value of the property. + * @param {String} [stylesheet] The name of the stylesheet to change. + * @param {Object} [win] A reference to a window + */ +function setStyleRule(name, type, value, stylesheet, win) { + var rule = findCssRule(name, stylesheet, win); + if (rule) { + if (value.indexOf("!important") > -1) { + rule.style.cssText = type + ":" + value; + } else { + type = type.replace(/-(\w)/g, function(_, a) {return a.toUpperCase()}); + rule.style[type] = value; + } + } + return !!rule; +} + +function updateStyleRule(url, rule) { + var link = reloader.findStylesheet(url); + if (!link) return; + + setStyleRule(rule.selector, rule.key, rule.value, + link.object.rule ? link.object.rule.styleSheet : link.object.node.sheet); +} + +function send(message) { + if (!session) return; + + message.id = session.id; + parent.postMessage(message, + host == "local" ? "*" : host); +} + +window.start = function(win) { + parent = win; + init(id); +}; + +// Make sure everything is loaded +if (parent != window) + init(id); + +})(); \ No newline at end of file diff --git a/plugins/c9.preview/statics.js b/plugins/c9.preview/statics.js new file mode 100644 index 00000000..13ad8656 --- /dev/null +++ b/plugins/c9.preview/statics.js @@ -0,0 +1,14 @@ +main.consumes = ["connect.static"]; + +module.exports = main; + +function main(options, imports, register) { + var statics = imports["connect.static"]; + + statics.addStatics([{ + path: __dirname + "/static", + mount: "/preview" + }]); + + register(); +} \ No newline at end of file diff --git a/plugins/c9.preview/views/listing.html.ejs b/plugins/c9.preview/views/listing.html.ejs new file mode 100644 index 00000000..d344db98 --- /dev/null +++ b/plugins/c9.preview/views/listing.html.ejs @@ -0,0 +1,36 @@ + + + + Cloud9 Preview + + + + + + + + + + + + <% if (!isRoot) { %> + + + + + + <% } %> + <% entries.forEach(function(entry) { %> + + + + + + <% }) %> +
      NameContent-TypeSize
      ..
      + + <%= entry.name %> + <%= entry.mime %><%= entry.size %>
      + + + \ No newline at end of file diff --git a/plugins/c9.preview/views/progress.html.ejs b/plugins/c9.preview/views/progress.html.ejs new file mode 100644 index 00000000..0e0396e9 --- /dev/null +++ b/plugins/c9.preview/views/progress.html.ejs @@ -0,0 +1,26 @@ + + + + <%=title%> + + + +
      +

      <%=title%>

      +

      + <%=message%> +

      + + Status Page | + Support | + Dashboard | + Home +
      + + + + diff --git a/plugins/c9.static/build.js b/plugins/c9.static/build.js new file mode 100644 index 00000000..82632f9e --- /dev/null +++ b/plugins/c9.static/build.js @@ -0,0 +1,405 @@ +"use strict"; + +main.consumes = ["Plugin", "connect.static"]; +main.provides = ["cdn.build"]; +module.exports = main; + +function main(options, imports, register) { + var Plugin = imports.Plugin; + var connectStatic = imports["connect.static"]; + + var os = require("os"); + var fs = require("fs"); + var path = require("path"); + var error = require("http-error"); + + var build = function() { + // delay loading of architect build for faster startup + // todo should we disable this plugin on local instead? + build = require("architect-build/build"); + build.apply(null, arguments); + }; + var cache; + + /***** Initialization *****/ + + var compress = options.compress || false; + var obfuscate = options.obfuscate || false; + var keepLess = options.keepLess || false; + var config = options.config || "ide"; + var settings = options.settings || "devel"; + var cacheDir = path.resolve(options.cache || os.tmpdir() + "/cdn"); + var staticsConfig; + + var plugin = new Plugin("Ajax.org", main.consumes); + + /***** Register and define API *****/ + + function init(callback) { + if (!options.link) + return callback(); + + var dir = path.join(cacheDir, options.version); + var rjsConfigPath = path.join(dir, "/static/requirejs-config.json"); + fs.exists(rjsConfigPath, function(exists) { + if (!exists) + getStaticsConfig(callback); + else + callback(); + }); + } + + function readConfig(config) { + if (config == "full") { + var plugins = []; + ["default-local", "ssh", "default"].forEach(function(n) { + plugins.push.apply(plugins, readConfig(n).config); + }); + return {config: plugins}; + } + + if (config[0] != "/") + config = path.join(__dirname, "/../../configs/client-" + config); + + if (config.slice(-3) !== ".js") + config += ".js"; + + var settings; + try { + settings = require("../../settings/standalone"); + config = require(config); + } catch (e) { + if (e.code == "MODULE_NOT_FOUND") + e = new error.NotFound(); + return {error: e}; + } + settings = settings(); + settings.packaging = true; + return {config: config(settings)}; + } + + function buildConfig(config, pathConfig, callback, onReadConfig) { + var data = readConfig(config); + if (data.error) + return callback(data.error); + + if (onReadConfig && onReadConfig(config, data.config)) + return; + + var plugins = data.config.concat(sharedModules()); + + var moduleLoadUrl = (options.virtual + ? pathConfig.baseUrl + "/" + pathConfig.hash + : options.baseUrl) + "/modules"; + + build(plugins, { + cache: cache, + pathConfig: pathConfig, + enableBrowser: true, + includeConfig: false, + noArchitect: true, + compress: compress, + filter: [], + ignore: ["amdefine", "plugins/c9.ide.ui/lib_less1.5"], + withRequire: true, + stripLess: !keepLess, + moduleLoadUrl: moduleLoadUrl, + basepath: pathConfig.root + }, callback); + } + + function buildSkin(config, color, pathConfig, callback) { + var data = readConfig(config); + if (data.error) + return callback(data.error); + + var plugins = data.config.concat(sharedModules()); + var lessLibs = []; + + fs.readFile(path.join(pathConfig.root, "plugins/c9.ide.layout.classic/less/lesshat.less"), "utf8", function(err, lesshat) { + if (err) return callback(err); + + lessLibs.push(lesshat); + + fs.readFile(path.join(pathConfig.root, "plugins/c9.ide.layout.classic/themes/default-" + color + ".less"), "utf8", function(err, theme) { + if (err) return callback(err); + + lessLibs.push(theme); + + lessLibs.staticPrefix = "plugins/c9.ide.layout.classic"; + + var themeCss = [{ + id: "text!" + "plugins/c9.ide.layout.classic/themes/" + color + ".less", + parent: {} + }]; + + build(plugins, { + cache: cache, + pathConfig: pathConfig, + enableBrowser: true, + includeConfig: false, + noArchitect: true, + compress: compress, + filter: [], + ignore: [], + withRequire: false, + compileLess: true, + lessLibs: lessLibs, + lessLibCacheKey: color, + basepath: pathConfig.root, + additional: themeCss + }, callback); + }); + }); + } + + function buildAce(module, pathConfig, callback, aceModuleIgnores) { + if (!aceModuleIgnores && cache && cache.aceModuleIgnores) + aceModuleIgnores = cache.aceModuleIgnores; + + if (aceModuleIgnores) { + if (aceModuleIgnores.indexOf(module) != -1) + aceModuleIgnores = []; // allow building default themes + + return build([module], { + cache: cache, + pathConfig: pathConfig, + enableBrowser: true, + includeConfig: false, + noArchitect: true, + compress: compress, + quiet: true, + filter: [], + ignore: aceModuleIgnores, + withRequire: false, + basepath: pathConfig.root + }, callback); + } + + var ignoreRoots = sharedModules().concat([ + "ace/editor", + "ace/multi_select" + ]); + + build(ignoreRoots, { + cache: cache, + pathConfig: pathConfig, + enableBrowser: true, + includeConfig: false, + noArchitect: true, + compress: false, + quiet: true, + }, function(err, result) { + var deps = Object.create(null); + result.sources.forEach(function(pkg) { + pkg.deps && pkg.deps.forEach(function(p) { + if (!deps[p]) deps[p] = 1; + }); + deps[pkg.id] = 1; + }); + aceModuleIgnores = Object.keys(deps); + if (cache) + cache.aceModuleIgnores = aceModuleIgnores; + buildAce(module, pathConfig, callback, aceModuleIgnores); + }); + } + + function sharedModules() { + return [ + "lib/architect/architect", + "ace/mode/html", + "ace/mode/javascript", + "ace/mode/css", + "ace/mode/c9search", + "ace/multi_select" + ]; + } + + function buildModule(module, pathConfig, callback) { + if (/^(ace\/|plugins\/c9.ide.ace)/.test(module)) + return buildAce(module, pathConfig, callback); + + build([], { + cache: cache, + pathConfig: pathConfig, + enableBrowser: true, + includeConfig: false, + noArchitect: true, + compress: compress, + filter: [], + ignore: [], + additional: [{ + id: module, + noDeps: true + }], + withRequire: false, + basepath: pathConfig.root + }, callback); + } + + function buildWorker(module, pathConfig, callback) { + var modules = [module]; + if (module == "plugins/c9.ide.language/worker") { + // jsonalyzer is missing in built version of local + var jsonalyzer = require("../c9.ide.language.jsonalyzer/default_plugins"); + modules = [ + "plugins/c9.ide.language/worker", + "plugins/c9.ide.language.generic/local_completer", + "plugins/c9.ide.language.generic/snippet_completer", + "plugins/c9.ide.language.generic/mode_completer", + "plugins/c9.ide.language.generic/open_files_local_completer", + "plugins/c9.ide.language.generic/simple/make", + "plugins/c9.ide.language.generic/simple/shell", + "plugins/c9.ide.language.javascript/parse", + "plugins/c9.ide.language.javascript/scope_analyzer", + "plugins/c9.ide.language.javascript/debugger", + "plugins/c9.ide.language.javascript/outline", + "plugins/c9.ide.language.javascript/jumptodef", + "plugins/c9.ide.language.javascript.immediate/immediate_complete", + "plugins/c9.ide.language.javascript.immediate/immediate_complete_static", + "plugins/c9.ide.language.javascript.infer/infer_jumptodef", + "plugins/c9.ide.language.javascript.infer/infer_tooltip", + "plugins/c9.ide.language.javascript.infer/infer_completer", + "plugins/c9.ide.language.html/html_completer", + "plugins/c9.ide.language.css/css_handler", + "plugins/c9.ide.language.javascript.tern/worker/tern_worker", + "plugins/c9.ide.language.javascript.tern/worker/architect_resolver_worker", + "plugins/c9.ide.language.javascript.eslint/worker/eslint_worker", + ].concat(jsonalyzer.handlersWorker).concat(jsonalyzer.helpersWorker); + } + + build(modules, { + cache: cache, + pathConfig: pathConfig, + enableBrowser: true, + includeConfig: false, + noArchitect: true, + compress: compress, + obfuscate: obfuscate, + filter: [], + ignore: [], + additional: [{ + id: "ace/worker/worker", + order: -1000, + noRequire: true + }], + withRequire: false, + basepath: pathConfig.root + }, callback); + } + + function getStaticsConfig(callback) { + if (staticsConfig) + return callback(null, staticsConfig); + + tryGetConfig(null, connectStatic); + + if (staticsConfig) + return callback(null, staticsConfig); + + var dir = path.join(cacheDir, options.version); + console.log("Linking static files to ", dir, settings); + require("../../scripts/makestatic.js")(config, settings, { + dest: dir + "/static", + symlink: false, + compress: options.compress, + getMounts: !options.link, + saveRjsConfig: false, + }, function(err, connectStatic) { + tryGetConfig(err, connectStatic); + return callback(err, staticsConfig); + }); + + function tryGetConfig(err, connectStatic) { + if (!connectStatic || options.link) + return; + + var mounts = connectStatic.getMounts(); + var rjsConfig = connectStatic.getRequireJsConfig(); + + if (!mounts || !mounts[0] || !mounts[0].mount) + return; + + var pathMap = Object.create(null); + mounts.forEach(function(mount) { + pathMap[mount.mount] = mount.path; + }); + + staticsConfig = { + pathMap: pathMap, + rjsConfig: JSON.parse(JSON.stringify(rjsConfig)) + }; + } + } + + function getPathConfig(hash, callback) { + if (!options.link) { + getStaticsConfig(function(err, config) { + if (err) return callback(err); + + var pathMap = config.pathMap; + var pathConfig = config.rjsConfig; + + pathConfig.hash = hash; + pathConfig.root = path.resolve(path.join(__dirname, "../../")); + var baseUrl = pathConfig.baseUrl || ""; + for (var p in pathConfig.paths) { + var url = pathConfig.paths[p]; + if (typeof url === "string" && url.substring(0, baseUrl.length) == baseUrl) + pathConfig.paths[p] = url.substring(baseUrl.length); + } + pathConfig.pathMap = pathMap; + callback(null, pathConfig); + }); + } else { + var root = path.resolve(path.join(cacheDir, hash)); + var rjsConfigPath = path.join(root, "/static/requirejs-config.json"); + fs.readFile(rjsConfigPath, "utf8", function(err, pathConfig) { + if (err) { + if (err.code == "ENOENT") + return callback(new error.NotFound()); + else + return callback(err); + } + + try { + pathConfig = JSON.parse(pathConfig); + } catch (e) { + return callback(e); + } + + pathConfig.root = path.join(root, pathConfig.baseUrl); + for (var p in pathConfig.paths) { + pathConfig.paths[p] = path.join(root, pathConfig.paths[p]); + } + callback(null, pathConfig); + }); + } + } + + function setCache(cacheObj) { + cache = cacheObj; + } + + /** + * + **/ + plugin.freezePublicAPI({ + buildAce: buildAce, + setCache: setCache, + buildSkin: buildSkin, + buildConfig: buildConfig, + buildModule: buildModule, + buildWorker: buildWorker, + getPathConfig: getPathConfig, + get cacheDir() { return cacheDir; }, + get version() { return options.version; } + }); + + init(function(err) { + if (err) return register(err); + + console.log("CDN: version " + options.version + " initialized", cacheDir); + register(null, { "cdn.build" : plugin }); + }); +} diff --git a/plugins/c9.static/build_test.js b/plugins/c9.static/build_test.js new file mode 100755 index 00000000..c4a96d33 --- /dev/null +++ b/plugins/c9.static/build_test.js @@ -0,0 +1,76 @@ +#!/usr/bin/env node +/*global describe it before after beforeEach afterEach */ +"use strict"; + +"use server"; +"use mocha"; + +require("c9/inline-mocha")(module); + +var expect = require("chai").expect; +var assert = require("assert"); +var sinon = require("sinon"); + +var buildPlugin = require("./build"); + +require("amd-loader"); + +var build, options, pathConfig; + +describe("The Module", function(){ + this.timeout(60000); + + beforeEach(function(next) { + + options = { + version: "testing", + compress: false, + baseUrl: "https://cdn.c9.io/static/abcd1234" + }; + + buildPlugin(options, { + "Plugin": function() { + this.freezePublicAPI = function(api) { + for (var key in api) this[key] = api[key]; + }; + } + }, function(err, services) { + if (err) return next(err); + + build = services["cdn.build"]; + + build.getPathConfig("testing", function(err, _pathConfig) { + if (err) return next(err); + + pathConfig = _pathConfig; + next(); + }); + }); + }); + + afterEach(function () { + }); + + it("should compile the default config", function(done) { + build.buildConfig("default", pathConfig, function(err, result) { + if (err) return done(err); + + var code = result.code; + assert(code.indexOf("" >= 0), "should have at least one stripped style"); + assert(!code.match(/= servers.length) + return callback(new Error("Disconnected: Could not reach your workspace. Please try again later.")); + + var server = servers[i]; + + auth.request(server.url + "/" + options.pid, { + method: "POST", + timeout: 120000, + body: { + version: version + }, + headers: { + Accept: "application/json" + } + }, function(err, res) { + // the workspace is not configured correctly + if (err && res && res.error) { + if (err.code == 429) { + // rate limited + setTimeout(function() { + tryNext(i); + }, res.error.retryIn || 10000); + return; + } + else if (err.code == 412 && res.error && res.error.subtype == "protocol_mismatch") { + return onProtocolChange(callback); + } + else if (err.code == 412) { + callback(fatalError(res.error.message, "dashboard")); + return; + } + else if (err.code === 428 && res.error) { + emit("restore", { + projectState: res.error.projectState, + premium: res.error.premium, + progress: res.error.progress || { + progress: 0, + nextProgress: 0, + message: "" + } + }); + setTimeout(function() { + tryNext(i); + }, res.error.retryIn || 10000); + return; + } + else if (err.code == 403) { + // forbidden. User doesn't have access + // wait a while before trying again + setTimeout(function() { + tryNext(i); + }, 10000); + return; + } + } + + if (err) { + setTimeout(function() { + tryNext(i+1); + }, 2000); + return; + } + + var vfs = rememberVfs(server, res.vfsid); + callback(null, vfs.vfsid, server.url, server.region); + }); + })(0); + } + + function onProtocolChange(callback) { + // I'm keeping this vague because we don't want users to blame + // a "cloud9 update" for losing work + deleteOldVfs(); + return callback(fatalError("Protocol change detected", "reload")); + } + + function shuffleServers(servers) { + servers = servers.slice(); + var isBeta = region == "beta"; + servers = servers.filter(function(s) { + return isBeta || s.region !== "beta"; + }); + return servers.sort(function(a, b) { + if (a.region == b.region) { + if (a.load < b.load) + return -1; + else + return 1; + } + else if (a.region == region) + return -1; + else if (b.region == region) + return 1; + else + return 0; + }); + } + + function rememberVfs(server, vfsid) { + var vfs = { + url: server.url, + region: server.region, + pid: options.pid, + vfsid: server.url + "/" + options.pid + "/" + vfsid, + readonly: options.readonly + }; + + var data = JSON.stringify(vfs); + var oldData = window.sessionStorage.getItem("vfsid"); + if (oldData && oldData !== data) + deleteOldVfs(); + + try { + window.sessionStorage.setItem("vfsid", data); + } catch(e) { + // could throw a quota exception + } + return vfs; + } + + function recallVfs() { + var vfs; + try { + vfs = JSON.parse(window.sessionStorage.getItem("vfsid")); + } catch (e) {} + + if (!vfs) + return null; + + if (vfs.pid !== options.pid || vfs.readonly != options.readonly) { + deleteOldVfs(); + return null; + } + + return vfs; + } + + function deleteOldVfs() { + var vfs; + try { + vfs = JSON.parse(window.sessionStorage.getItem("vfsid")); + } catch (e) {} + + window.sessionStorage.removeItem("vfsid"); + if (!vfs) return; + + auth.request(vfs.vfsid, { + method: "DELETE", + headers: { + Accept: "application/json" + } + }, function(err) { + if (err) console.error(vfs.vfsid, "deleted", err); + }); + } + + function fatalError(msg, action) { + var err = new Error(msg); + err.fatal = true; + err.action = action || "reload"; + return err; + } + + /***** Register and define API *****/ + + /** + **/ + plugin.freezePublicAPI({ + /** + * Returns the URLs for the home and project REST API and the socket + */ + get: getVfsEndpoint, + + /** + * Checks if the client has a network connection + */ + isOnline: isOnline, + + /** + * + */ + clearCache: deleteOldVfs, + + /** + * Checks if the current VFS server is still alive + */ + isServerAlive: isServerAlive + }); + + register(null, { + "vfs.endpoint": plugin + }); + } +}); \ No newline at end of file diff --git a/plugins/c9.vfs.client/ping-service.js b/plugins/c9.vfs.client/ping-service.js new file mode 100644 index 00000000..52fb886a --- /dev/null +++ b/plugins/c9.vfs.client/ping-service.js @@ -0,0 +1,7 @@ +module.exports = function(vfs, options, register) { + register(null, { + ping: function (payload, callback) { + callback(null, payload); + } + }); +}; diff --git a/plugins/c9.vfs.client/vfs.cli.js b/plugins/c9.vfs.client/vfs.cli.js new file mode 100644 index 00000000..915200fe --- /dev/null +++ b/plugins/c9.vfs.client/vfs.cli.js @@ -0,0 +1,20 @@ +define(function(require, module, exports) { + main.consumes = ["c9", "ext"]; + main.provides = ["vfs"]; + return main; + + function main(options, imports, register) { + var c9 = imports.c9; + var localFs = require("vfs-local"); + + var vfs = new localFs({ + root: "/", + nopty: true, + defaultEnv: { CUSTOM: 43 } + }); + + c9.setStatus(c9.status | c9.STORAGE | c9.PROCESS); + + register(null, {vfs: vfs}); + } +}); \ No newline at end of file diff --git a/plugins/c9.vfs.client/vfs.ping.js b/plugins/c9.vfs.client/vfs.ping.js new file mode 100644 index 00000000..e458d929 --- /dev/null +++ b/plugins/c9.vfs.client/vfs.ping.js @@ -0,0 +1,83 @@ +define(function(require, exports, module) { + "use strict"; + + main.consumes = ["Plugin", "ext", "c9"]; + main.provides = ["vfs.ping"]; + return main; + + function main(options, imports, register) { + var Plugin = imports.Plugin; + var c9 = imports.c9; + var ext = imports.ext; + + /***** Initialization *****/ + + var plugin = new Plugin("Ajax.org", main.consumes); + var api; + + var loaded = false; + function load(){ + if (loaded) return; + loaded = true; + + ext.loadRemotePlugin("ping", { + code: require("text!./ping-service.js"), + redefine: true + }, function(err, remote) { + if (err) + return console.error(err); + + api = remote; + }); + + c9.on("stateChange", function(e) { + if (e.state & c9.NETWORK) { + load(); + } + else { + loaded = false; + api = null; + } + }, plugin); + } + + /***** Lifecycle *****/ + + plugin.on("load", function(){ + load(); + }); + + /***** Register and define API *****/ + function ping(callback) { + if (!callback) { + callback = function(err, result) { + if (err) + return console.error(err); + console.log("ping took", result, "ms"); + }; + } + + if (!api) return callback(new Error("Client is offline")); + + var start = Date.now(); + api.ping("ping", function(err) { + var took = Date.now() - start; + if (err) return callback(err); + + callback(null, took); + }); + } + + window.ping = ping; + + /** + * + **/ + plugin.freezePublicAPI({ + ping: ping + }); + + register(null, { "vfs.ping" : plugin }); + } + +}); \ No newline at end of file diff --git a/plugins/c9.vfs.client/vfs_client.js b/plugins/c9.vfs.client/vfs_client.js new file mode 100644 index 00000000..266974e7 --- /dev/null +++ b/plugins/c9.vfs.client/vfs_client.js @@ -0,0 +1,430 @@ +/** + * Smith.io client + * + * @copyright 2010, Ajax.org B.V. + * @license GPLv3 + */ + +define(function(require, exports, module) { + "use strict"; + + main.consumes = ["Plugin", "auth", "vfs.endpoint", "dialog.error", "dialog.alert"]; + main.provides = ["vfs"]; + return main; + + /** + * login flow + * + * init: + * - receive list of VFS servers + * - choose one of the servers (based on some metric) + * - create VFS connection to that VFS server and remember the ID in sessionStorage + * + * offline: + * - ping a stable URL to detect if it is a network error + * - if it is a network error try to reconnect to the same VFS server with the same ID + * - if it is not a network error pick another server + */ + + function main(options, imports, register) { + var Plugin = imports.Plugin; + var auth = imports.auth; + var vfsEndpoint = imports["vfs.endpoint"]; + var errorDialog = imports["dialog.error"]; + var showError = errorDialog.show; + var hideError = errorDialog.hide; + var showAlert = imports["dialog.alert"].show; + + var eio = require("engine.io"); + var Consumer = require("vfs-socket/consumer").Consumer; + var connectClient = require("kaefer"); + var protocolVersion = require("kaefer/version").protocol; + var smith = require("smith"); + var URL = require("url"); + + // The connected vfs unique id + var id; + + /***** Initialization *****/ + + var plugin = new Plugin("Ajax.org", main.consumes); + var emit = plugin.getEmitter(); + + // Give reference to vfs to plugin + errorDialog.vfs = plugin; + + var buffer = []; + var installChecked = false; + var withInstall = options.withInstall; + var dashboardUrl = options.dashboardUrl; + var region, vfsBaseUrl, homeUrl, projectUrl, pingUrl, serviceUrl; + var eioOptions, connection, consumer, vfs; + var showErrorTimer, showErrorTimerMessage; + var lastError; + + function emptyBuffer(){ + var b = buffer; + buffer = []; + b.forEach(function(item) { + if (!item) return; + + var xhr = rest.apply(null, item); + if (item.length > 3) + item[3].abort = xhr.abort.bind(xhr); + }); + } + + var loaded = false; + function load(){ + if (loaded) return false; + loaded = true; + + smith.debug = options.debug; + + connection = connectClient(connectEngine, { + preConnectCheck: preConnectCheck, + debug: options.debug + }); + + connection.on("away", emit.bind(null, "away")); + connection.on("back", function(e) { + emit("back"); + emptyBuffer(); + }); + + connection.on("disconnect", onDisconnect); + connection.on("connect", onConnect); + + reconnect(function(err) { + connection.connect(); + }); + + function connectEngine() { + if (auth.accessToken) { + eioOptions.query = { + access_token: auth.accessToken + }; + } + return eio(eioOptions); + } + + function preConnectCheck(callback) { + + vfsEndpoint.isOnline(function(err, isOnline) { + if (err || !isOnline) return callback(null, false); + + if (!eioOptions) return disconnect(); + if (!pingUrl) return disconnect(); + + vfsEndpoint.isServerAlive(pingUrl, function(err, isAlive) { + if (!err && isAlive) return callback(null, true); + + disconnect(); + }); + }); + + function disconnect() { + reconnect(function(err) { + if (err && err.fatal) + return; + callback(err, !err); + }); + } + } + } + + /***** Methods *****/ + + function join(a, b) { + return (a || "").replace(/\/?$/, "/") + (b || "").replace(/^\//, ""); + } + + function vfsUrl(path) { + // resolve home and project url + return path.charAt(0) == "~" + ? join(homeUrl, escape(path.slice(1))) + : join(projectUrl, escape(path)); + } + + function rest(path, options, callback) { + if (!vfs || !connection || connection.readyState != "open") { + var stub = { abort: function(){ buffer[this.id]= null; } }; + stub.id = buffer.push([path, options, callback, stub]) - 1; + return stub; + } + + // resolve home and project url + var url = vfsUrl(path); + + options.overrideMimeType = options.contentType || "text/plain"; + options.contentType = options.contentType || "text/plain"; + + return auth.request(url, options, function(err, data, res) { + var reErrorCode = /(ENOENT|EISDIR|ENOTDIR|EEXIST|EACCES|ENOTCONNECTED)/; + + if (err) { + var isConnected = !connection || connection.readyState == "open"; + if (err.code === 499 || (err.code === 0) && !isConnected) { + if (isConnected) + buffer.push([path, options, callback]); + else + rest(path, options, callback); + return; + } + + if (!res) return callback(err); + + var message = (res.body || "").replace(/^Error:\s+/, ""); + var code = res.status === 0 + ? "ENOTCONNECTED" + : message.match(reErrorCode) && RegExp.$1; + + err = new Error(res.body); + err.code = code || undefined; + err.status = res.status; + return callback(err); + } + callback(null, data, res); + }); + } + + function download(path, filename, isfile) { + window.open(vfsUrl(path) + "?download" + + (filename ? "=" + encodeURIComponent(filename) : "") + + (isfile ? "&isfile=1" : "")); + } + + function reconnect(callback) { + connection.socket.setSocket(null); + + vfsEndpoint.get(protocolVersion, function(err, urls) { + if (err) { + if (!showErrorTimer) { + showErrorTimer = setTimeout(function() { + showVfsError(showErrorTimerMessage); + }, err.fatal ? 0 : 20000); + } + showErrorTimerMessage = err; + return callback(err); + } + + if (lastError) + hideError(lastError); + + region = urls.region; + vfsBaseUrl = urls.url; + homeUrl = urls.home; + projectUrl = urls.project; + pingUrl = urls.ping; + serviceUrl = urls.serviceUrl; + id = pingUrl.split("/").pop(); + + var parsedSocket = URL.parse(urls.socket); + eioOptions = { + path: parsedSocket.path, + host: parsedSocket.host, + port: parsedSocket.port || "443", + secure: parsedSocket.protocol + ? parsedSocket.protocol == "https:" : true + }; + callback(); + }); + } + + function showVfsError(err) { + switch (err.action) { + case "dashboard": + return showAlert("Workspace Error", "Unable to access your workspace", err.message, function() { + window.location = dashboardUrl; + }); + case "reload": + lastError = showError(err.message + ". Please reload this window.", -1); + break; + default: + lastError = showError(err, -1); + } + if (err.fatal) + console.error("Fatal connection error:", err); + } + + function onDisconnect() { + vfs = null; + emit("disconnect"); + } + + function onConnect() { + var transport = new smith.EngineIoTransport(connection); + + if (consumer) + consumer.disconnect(); + + clearTimeout(showErrorTimer); + showErrorTimer = null; + + consumer = new Consumer(); + consumer.connectionTimeout = 5000; + consumer.connect(transport, function(err, _vfs) { + // TODO + if (err) { + console.error("error connecting to VFS", err); + return; + } + + if (!installChecked) { + checkInstall(_vfs, callback); + installChecked = true; + } + else { + callback(); + } + + function callback(shouldReconnect) { + if (shouldReconnect) { + vfsEndpoint.clearCache(); + reconnect(function(err) { + if (err) return console.log(err); + connection.connect(); + }); + return; + } + + vfs = _vfs; + + bufferedVfsCalls.forEach(vfsCall); + bufferedVfsCalls = []; + emit("connect"); + + emptyBuffer(); + } + }); + + consumer.on("error", function(err) { + connection.disconnect(); + }); + } + + function checkInstall(vfs, callback) { + if (!withInstall) + return callback(false); + + vfs.stat(options.installPath + "/installed", {}, function(err, stat) { + if (err && err.code == "ENOENT") { + emit.sticky("install", { callback: callback, vfs: vfs }); + } + else + callback(); + }); + } + + var bufferedVfsCalls = []; + function vfsCall(method, path, options, callback) { + if (Array.isArray(method)) + return vfsCall.apply(null, method); + + if (vfs) + return vfs[method](path, options, callback); + else + bufferedVfsCalls.push([method, path, options, callback]); + } + + /***** Lifecycle *****/ + + plugin.on("load", function(){ + load(); + }); + plugin.on("unload", function(){ + loaded = false; + + id = null; + buffer = []; + installChecked = false; + region = null; + vfsBaseUrl = null; + homeUrl = null; + projectUrl = null; + pingUrl = null; + serviceUrl = null; + eioOptions = null; + consumer = null; + vfs = null; + showErrorTimer = null; + showErrorTimerMessage = null; + lastError = null; + }); + + /***** Register and define API *****/ + + /** + * @event connect Fires ... + * @event disconnect Fires ... + * @event message Fires ... + * @event away Fires ... + * @event back Fires ... + * @event error Fires ... + */ + plugin.freezePublicAPI({ + + get connection(){ return connection; }, + get connecting(){ return connection ? connection.readyState == "reconnecting" : true; }, + get connected(){ return vfs ? connection.readyState == "open" : false; }, + + get previewUrl(){ throw new Error("gone") }, + get serviceUrl(){ return serviceUrl; }, + get id() { return id; }, + get baseUrl() { return vfsBaseUrl; }, + get region() { return region; }, + + /** + * Performs a VFS REST API call + * @param path {String} Path of the resource. Can be prefixed + * with '~' to resolve the path relative + * to the user's home dir + * @param options {Object} Same format as 'http.request' + * @param callback(err, data) {Function} + */ + rest: rest, + download: download, + url: vfsUrl, + + // File management + resolve: vfsCall.bind(null, "resolve"), + stat: vfsCall.bind(null, "stat"), + readfile: vfsCall.bind(null, "readfile"), + readdir: vfsCall.bind(null, "readdir"), + mkfile: vfsCall.bind(null, "mkfile"), + mkdir: vfsCall.bind(null, "mkdir"), + mkdirP: vfsCall.bind(null, "mkdirP"), + appendfile: vfsCall.bind(null, "appendfile"), + rmfile: vfsCall.bind(null, "rmfile"), + rmdir: vfsCall.bind(null, "rmdir"), + rename: vfsCall.bind(null, "rename"), + copy: vfsCall.bind(null, "copy"), + chmod: vfsCall.bind(null, "chmod"), + symlink: vfsCall.bind(null, "symlink"), + + // Retrieve Metadata + metadata: vfsCall.bind(null, "metadata"), + + // Wrapper around fs.watch or fs.watchFile + watch: vfsCall.bind(null, "watch"), + + // Network connection + connect: vfsCall.bind(null, "connect"), + + // Process Management + spawn: vfsCall.bind(null, "spawn"), + pty: vfsCall.bind(null, "pty"), + tmux: vfsCall.bind(null, "tmux"), + execFile: vfsCall.bind(null, "execFile"), + + // Extending the API + use: vfsCall.bind(null, "use"), + extend: vfsCall.bind(null, "extend"), + unextend: vfsCall.bind(null, "unextend") + }); + + register(null, { + "vfs": plugin + }); + } +}); \ No newline at end of file diff --git a/plugins/c9.vfs.client/vfs_test.js b/plugins/c9.vfs.client/vfs_test.js new file mode 100644 index 00000000..aedcbbe7 --- /dev/null +++ b/plugins/c9.vfs.client/vfs_test.js @@ -0,0 +1,106 @@ +/*global describe it before beforeEach*/ + +"use client"; + +require(["lib/architect/architect", "lib/chai/chai"], function (architect, chai) { + var expect = chai.expect; + + expect.setupArchitectTest([ + { + packagePath: "plugins/c9.core/c9", + startdate: new Date(), + debug: 2, + hosted: true, + local: false + }, + "plugins/c9.core/http-xhr", + "plugins/c9.core/ext", + { + packagePath: "plugins/c9.vfs.client/vfs_client", + debug: true + }, + "plugins/c9.vfs.client/endpoint", + "plugins/c9.ide.auth/auth", + + //Mock Plugins + { + consumes: ["Plugin"], + provides: ["auth.bootstrap", "info", "dialog.error", "api", "dialog.alert"], + setup: expect.html.mocked + }, + { + consumes: ["vfs", "c9"], + provides: [], + setup: main + } + ], architect); + + function main(options, imports, register) { + var vfs = imports.vfs; + var c9 = imports.c9; + + describe('vfs', function() { + this.timeout(20000); + + beforeEach(function(done) { + if (vfs.connected) + return done(); + + vfs.once("connect", done); + }); + + it("should handle calls across away/back boundary", function(done) { + vfs.readdir("/", {}, function(err, meta) { + if (err) throw err; + meta.stream.destroy(); + done(); + }); + + // Disconnect to force away state + vfs.connection.socket.close(); + }); + it("should handle calls during away", function(done) { + vfs.connection.socket.close(); + vfs.readdir("/", {}, function(err, meta) { + if (err) throw err; + meta.stream.destroy(); + done(); + }); + }); + it("should keep state over away/back boundary", function(done) { + var path = "/testwatch.txt"; + + vfs.copy("/file.txt", {to: path, overwrite: true}, function(err) { + if (err) throw err; + vfs.watch(path, {}, function(err, meta) { + if (err) throw err; + + meta.watcher.on("change", function (event, filename) { + if (event == "delete" && filename == path.substr(1)) { + done(); + vfs.off("back", onBack); + } + }); + meta.watcher.on("error", function(err) { + throw err; + }); + + c9.once("back", onBack); + + function onBack() { + vfs.rmfile(path, {}, function(err) { + if (err) throw err; + }); + } + + setTimeout(function() { + vfs.connection.socket.close(); + }, 200); + }); + }); + }); + }); + + onload && onload(); + } +}); \ No newline at end of file diff --git a/plugins/c9.vfs.server/cache.js b/plugins/c9.vfs.server/cache.js new file mode 100644 index 00000000..bc174ae4 --- /dev/null +++ b/plugins/c9.vfs.server/cache.js @@ -0,0 +1,255 @@ +define(function(require, exports, module) { + "use strict"; + + main.consumes = ["Plugin", "vfs.connect"]; + main.provides = ["vfs.cache"]; + return main; + + + function main(options, imports, register) { + var Plugin = imports.Plugin; + var connectVfs = imports["vfs.connect"].connect; + + var async = require("async"); + var uid = require("c9/uid"); + var error = require("http-error"); + var EventEmitter = require("events").EventEmitter; + + /***** Initialization *****/ + + var plugin = new Plugin("Ajax.org", main.consumes); + var emit = plugin.getEmitter(); + + var cache = {}; + var maxAge = options.maxAge || 15 * 1000; + + var vfsExtensions = []; + + /***** Methods *****/ + + function registerExtension(handler) { + vfsExtensions.push(handler); + } + + function create(pid, user, callback) { + var vfsid; + do { + vfsid = uid(16); + } while (has(vfsid)); + + var entry = createEntry(pid, user, vfsid); + cache[vfsid] = entry; + + return connectVfs(user, pid, function(err, vfs) { + if (err) return done(err); + + vfs.id = vfsid; + vfs.uid = user.id; + vfs.pid = pid; + entry.vfs = vfs; + + async.forEach(vfsExtensions, function(factory, next) { + factory(vfs, next); + }, function(err) { + if (err) return done(err); + + entry.connectTime = Date.now() - entry.startTime; + + entry.emit("loaded"); + + cache[vfsid] = entry; + + vfs.on("destroy", function() { + remove(vfsid); + }); + vfs.on("keepalive", function() { + entry.keepalive(); + emit("keepalive", entry); + }); + + done(); + }); + }); + + function done(err) { + if (err) { + entry.emit("fail", err); + remove(vfsid); + return callback(err); + } + callback(null, entry); + } + } + + function has(vfsid) { + return !!cache[vfsid]; + } + + function get(vfsid) { + var entry = cache[vfsid]; + if (entry) + entry.keepalive(); + + return entry || null; + } + + function getAll() { + return cache; + } + + function remove(vfsid) { + var entry = cache[vfsid]; + if (entry) { + delete cache[vfsid]; + entry.destroy(); + } + } + + function createEntry(pid, user, vfsid) { + var entry = new EventEmitter(); + entry.setMaxListeners(100); + + entry.pid = pid; + entry.user = user; + entry.vfsid = vfsid; + entry.startTime = Date.now(); + + var expiresAt = 0; + Object.defineProperty(entry, "ttl", { + get: function() { + return expiresAt - Date.now(); + } + }); + + entry.destroy = function() { + entry.vfs && entry.vfs.destroy(); + }; + + entry.keepalive = function() { + clearTimeout(timer); + startTimer(); + }; + + var timer; + function startTimer() { + clearTimeout(timer); + expiresAt = Date.now() + maxAge; + timer = setTimeout(function() { + remove(vfsid); + }, maxAge); + } + + startTimer(); + return entry; + } + + + function readonlyRest(pid, user, path, scope, req, res, next) { + for (var key in cache) { + var entry = cache[key]; + var isPublic = entry.vfs && entry.vfs.public; + if (entry.pid == pid && (entry.user.id == user.id || isPublic)) { + if (entry.vfs) + handle(entry.vfs); + else { + var called = false; + entry.on("loaded", function() { + if (called) return; + called = true; + handle(entry.vfs); + }); + entry.on("fail", function(err) { + if (called) return; + called = true; + return next(err); + }); + } + return; + } + } + + create(pid, user, function(err, entry) { + if (err) return next(err); + + handle(entry.vfs); + }); + + function handle(vfs) { + if (req.method !== "GET" && req.method !== "HEAD") + return next(new error.Forbidden("Only GET and HEAD requests are allowed in read only mode")); + + vfs.handleRest(scope, path, req, res, next); + } + } + + /***** Register and define API *****/ + + /** + * Keeps a Cache of VFS instances + * + * @singleton + */ + plugin.freezePublicAPI({ + /** + * Create a new VFS connection + * + * @param {Number} pid Project ID of the workspace to connect to + * @param {Object} user User trying to connect to the worksapce + * @param {Function} callback Called after the VFs connection has been established + * @param {Error} callback.err Error object if an error occured. + * @param {Object} callback.entry Cached VFS entry + * @param {Vfs} callback.entry.vfs VFS instance + * @param {String} callback.entry.vfsid Unique ID of the cache entry + */ + create: create, + + /** + * Get an entry by it's unique ID + * + * @param {String} vfsid Unique ID of the cache entry + * @return {Object} callback.entry Cached VFS entry + * @return {Vfs} callback.entry.vfs VFS instance + * @return {String} callback.entry.vfsid Unique ID of the cache entry + */ + get: get, + + /** + * Get all cached entries + * + * @return {Object} Object keys are the VFS IDs and the values are the cache entries + */ + getAll: getAll, + + /** + * Check if the cache has an entry with the given VFS ID + * + * @param {String} vfsid Unique ID of the cache entry + * @return {Boolean} Whether the cache has an entry with the given ID + */ + has: has, + + /** + * Remove an entry by vfs ID + * + * @param {String} vfsid Unique ID of the cache entry + */ + remove: remove, + + readonlyRest: readonlyRest, + + /** + * Register a callback which is called with each created VFS connection. + * This can e.g. be used to extend the remote agent using 'vfs.extend'. + * + * @param {Function} factory Function to be called on new VFS connections + * @param {Object} vfs The VFS Object + * @param {Function} callback Needs to be called after the factory is done + */ + registerExtension: registerExtension + }); + + register(null, { + "vfs.cache": plugin + }); + } +}); \ No newline at end of file diff --git a/plugins/c9.vfs.server/download.js b/plugins/c9.vfs.server/download.js new file mode 100644 index 00000000..4044d847 --- /dev/null +++ b/plugins/c9.vfs.server/download.js @@ -0,0 +1,141 @@ +define(function(require, exports, module) { + "use strict"; + + main.consumes = ["Plugin", "vfs.cache"]; + main.provides = ["vfs.download"]; + return main; + + function main(options, imports, register) { + var Plugin = imports.Plugin; + var cache = imports["vfs.cache"]; + + var error = require("http-error"); + var Path = require("path"); + + /***** Initialization *****/ + + var plugin = new Plugin("Ajax.org", main.consumes); + + cache.registerExtension(function(vfs, callback) { + + var restful = vfs.restful.workspace; + + vfs.restful.workspace = function(req, res, next) { + if (req.method == "GET" && "download" in req.uri.query) + download(vfs.vfs, vfs.workspaceDir, req, res, next); + else + restful(req, res, next); + }; + + callback(); + }); + + function download(vfs, root, req, res, next) { + var path = Path.join(root, Path.normalize(decodeURI(req.uri.pathname).replace(/^(\/?\.\.)?\/?/, ""))); + var dir = Path.dirname(path); + var name = Path.basename(path).replace(/\/*$/, ""); + + var filename; + if (req.uri.query.download) + filename = req.uri.query.download; + else + filename = name + ".tar.gz"; + + var process; + + req.on("close", function() { + if (process) process.kill(); + }); + + if (req.uri.query.isfile) { + vfs.readfile(path, {}, function(err, meta){ + if (err) { + if (err.code == "ENOENT") + return next(new error.NotFound("File '" + path + "' could not be found!")); + else + return next(err); + } + + // once we receive data on stdout pipe it to the response + meta.stream.once("data", function (data) { + if (res.headerSent) + return; + + res.writeHead(200, { + "Content-Type": "octet/stream", + "Content-Disposition": "attachment; filename=" + name + }); + res.write(data); + meta.stream.pipe(res); + }); + + meta.stream.on("error", function(err){ + res.writeHead(500); + res.end(err.message); + }); + }); + } + else { + vfs.spawn("tar", { + args: ["-zcf", "-", name], + cwd: dir + }, function (err, meta) { + if (err) + return next(err); + + process = meta.process; + + // once we receive data on stdout pipe it to the response + process.stdout.once("data", function (data) { + if (res.headerSent) + return; + + res.writeHead(200, { + "Content-Type": "application/x-gzip", + "Content-Disposition": "attachment; filename=" + filename + }); + res.write(data); + process.stdout.pipe(res); + }); + + var stderr = ""; + process.stderr.on("data", function (data) { + stderr += data; + }); + + process.on("exit", function(code, signal) { + if (res.headerSent) + return; + + var err; + if (code == 127) { + err = new error.PreconditionFailed( + "Your instance seems to be missing the 'tar' utility\n" + + "If you are using an SSH workspace, please do:\n" + + " 'sudo apt-get install tar'"); + } else if (code) { + err = new error.InternalServerError( + "'tar' utility failed with exit code " + code + + " and stderr:/n'" + stderr + "'"); + } else if (signal) { + err = new error.InternalServerError( + "'tar' utility was terminated by signal " + signal + ); + } + + if (err) { + next(err); + } + }); + }); + } + } + + plugin.freezePublicAPI({ + // for testing only + download: download + }); + + register(null, { "vfs.download" : plugin }); + } +}); \ No newline at end of file diff --git a/plugins/c9.vfs.server/download_test.js b/plugins/c9.vfs.server/download_test.js new file mode 100755 index 00000000..07c815f8 --- /dev/null +++ b/plugins/c9.vfs.server/download_test.js @@ -0,0 +1,120 @@ +#!/usr/bin/env node +"use strict"; +"use server"; + +require("amd-loader"); +var assert = require("assert"); +var fs = require("fs"); +var tmp = require("tmp"); +var http = require("http"); +var localfs = require("vfs-local"); +var download = require("./download"); +var urlParse = require('url').parse; +var execFile = require('child_process').execFile; + +module.exports = { + + timeout: 4000, + + setUp: function(next) { + var that = this; + var vfs = localfs({root: "/"}); + download({}, { + "Plugin": function() { + var that = this; + this.freezePublicAPI = function(api) { + for (var key in api) + that[key] = api[key]; + }; + }, + "vfs.cache": { + registerExtension: function() { } + } + }, function(err, api) { + var download = api["vfs.download"].download; + that.server = http.createServer(function(req, res, next) { + req.uri = urlParse(req.url, true); + download(vfs, __dirname, req, res, function(err) { + console.log("download failed", err); + assert.fail(err); + }); + }); + that.server.listen(8787, "0.0.0.0", next); + }); + }, + + tearDown: function(next) { + this.server.close(next); + }, + + "test download": function(next) { + tmp.dir({unsafeCleanup: true}, function(err, path) { + var filename = path + "/download.tar.gz"; + var file = fs.createWriteStream(filename); + http.get("http://localhost:8787/?download=download.tar.gz", function(res) { + assert.equal(res.headers["content-type"], "application/x-gzip"); + assert.equal(res.headers["content-disposition"], "attachment; filename=download.tar.gz"); + + res.pipe(file); + + res.on("end", function() { + execFile("tar", ["-zxvf", filename, "c9.vfs.server/download.js"], {cwd: path}, function(err, stdout, stderr) { + assert.equal(err, null); + assert.equal( + fs.readFileSync(__dirname + "/download.js", "utf8"), + fs.readFileSync(path + "/c9.vfs.server/download.js", "utf8") + ); + next(); + }); + }); + }); + }); + }, + + "test download sub directory": function(next) { + tmp.dir({unsafeCleanup: true}, function(err, path) { + var filename = path + "/download.tar.gz"; + var file = fs.createWriteStream(filename); + http.get("http://localhost:8787/views?download=download.tar.gz", function(res) { + res.pipe(file); + + res.on("end", function() { + execFile("tar", ["-zxvf", filename, "views/status.html.ejs"], {cwd: path}, function(err) { + assert.equal(err, null); + assert.equal( + fs.readFileSync(__dirname + "/views/status.html.ejs", "utf8"), + fs.readFileSync(path + "/views/status.html.ejs", "utf8") + ); + next(); + }); + }); + }); + }); + }, + + "test download without specifying a name": function(next) { + tmp.dir({unsafeCleanup: true}, function(err, path) { + var filename = path + "/download.tar.gz"; + var file = fs.createWriteStream(filename); + http.get("http://localhost:8787/views?download", function(res) { + assert.equal(res.headers["content-type"], "application/x-gzip"); + assert.equal(res.headers["content-disposition"], "attachment; filename=views.tar.gz"); + + res.pipe(file); + + res.on("end", function() { + execFile("tar", ["-zxvf", filename, "views/status.html.ejs"], {cwd: path}, function(err) { + assert.equal(err, null); + assert.equal( + fs.readFileSync(__dirname + "/views/status.html.ejs", "utf8"), + fs.readFileSync(path + "/views/status.html.ejs", "utf8") + ); + next(); + }); + }); + }); + }); + } +}; + +!module.parent && require("asyncjs").test.testcase(module.exports).exec(); \ No newline at end of file diff --git a/plugins/c9.vfs.server/filelist.js b/plugins/c9.vfs.server/filelist.js new file mode 100644 index 00000000..c652f0a9 --- /dev/null +++ b/plugins/c9.vfs.server/filelist.js @@ -0,0 +1,123 @@ +define(function(require, exports, module) { + "use strict"; + + main.consumes = ["Plugin", "vfs.cache", "connect"]; + main.provides = ["vfs.filelist"]; + return main; + + function main(options, imports, register) { + var Plugin = imports.Plugin; + var cache = imports["vfs.cache"]; + + var error = require("http-error"); + var Path = require("path"); + + /***** Initialization *****/ + + var plugin = new Plugin("Ajax.org", main.consumes); + + var compress = imports.connect.getModule().compress(); + + cache.registerExtension(function(vfs, callback) { + var restful = vfs.restful.home; + + vfs.restful.home = function(req, res, next) { + var path = unescape(req.uri.pathname); + + if (req.method == "GET" && path == "/.c9/file.listing") { + compress(req, res, function(err) { + if (err) return next(err); + + filelist(vfs.vfs, vfs.workspaceDir, vfs.vfsOptions, req, res, next); + }); + } + else + restful(req, res, next); + }; + + callback(); + }); + + function filelist(vfs, root, vfsOptions, req, res, next) { + var query = req.uri.query; + var path = query && query.path + ""; + var nakBin = vfsOptions.nakBin; + var nodeBin = vfsOptions.nodeBin && vfsOptions.nodeBin[0]; + + if (!path) + return next(new error.BadRequest("path query must be set")); + + if (!nakBin) + return next(new error.InternalServerError("nak binary not configured")); + + // sandbox path to workspaceDir + path = Path.normalize(path); + // if (path.indexOf(root) !== 0) + // return next(new error.Forbidden("Can't list files outside of the workspace")); + + query.list = true; + query.follow = true; + query.path = path; + + vfs.spawn(nodeBin, { + stdoutEncoding: "utf8", + stderrEncoding: "utf8", + args: [nakBin, "--json", JSON.stringify(query)] + }, function(err, meta) { + if (err) return next(err); + + var process = meta.process; + // once we receive data on stdout pipe it to the response + process.stdout.once("data", function (data) { + if (res.headerSent) + return; + + res.writeHead(200, { "Content-Type": "text/plain" }); + res.write(data); + process.stdout.pipe(res); + }); + + req.on("close", function () { + process && process.kill(); + }); + + var stderr = ""; + process.stderr.on("data", function (data) { + stderr += data; + }); + + process.on("exit", function(code, signal) { + if (res.headerSent) + return; + + var err; + if (code == 127) { + err = new error.PreconditionFailed( + "Your instance seems to be missing the 'nak' utility\n" + + "If you are using an SSH workspace, please do:\n" + + " 'curl https://raw.github.com/c9/install/master/install.sh | bash'"); + } else if (code) { + err = new error.InternalServerError( + "'nak' utility failed with exit code " + code + + " and stderr: '" + stderr + "'"); + } else if (signal) { + err = new error.InternalServerError( + "'nak' utility was terminated by signal " + signal + ); + } + + if (err) { + next(err); + } + }); + }); + } + + plugin.freezePublicAPI({ + // for testing only + filelist: filelist + }); + + register(null, { "vfs.filelist" : plugin }); + } +}); \ No newline at end of file diff --git a/plugins/c9.vfs.server/statics.js b/plugins/c9.vfs.server/statics.js new file mode 100644 index 00000000..a3ddd1dc --- /dev/null +++ b/plugins/c9.vfs.server/statics.js @@ -0,0 +1,101 @@ +/** + * Additional static files for the the smith.io client plugin + * + * @copyright 2010, Ajax.org B.V. + * @license GPLv3 + */ + +main.consumes = ["Plugin", "connect.static"]; +main.provides = ["smithio.server"]; + +module.exports = main; + +function main(options, imports, register) { + var Plugin = imports.Plugin; + var statics = imports["connect.static"]; + + var fs = require("fs"); + var dirname = require("path").dirname; + + /***** Initialization *****/ + + var plugin = new Plugin("Ajax.org", main.consumes); + + var loaded = false; + function load(){ + if (loaded || options.disableUnpackagedClient) return false; + loaded = true; + + // TODO: big hack. Patch engine.io client to disable 'withCredentials" + var eioClient = require.resolve("engine.io-client/engine.io.js"); + try { + fs.writeFileSync(eioClient, fs.readFileSync(eioClient, "utf8").replace("xhr.withCredentials = true;", "xhr.__withCredentials = true;")); + } catch (e) { + console.warn("unable to patch engine.io"); + } + + statics.addStatics([{ + path: dirname(eioClient), + mount: "/engine.io", + rjs: [{ + "name": "engine.io", + "location": "engine.io", + "main": "engine.io.js" + }] + }]); + + statics.addStatics([{ + path: dirname(require.resolve("kaefer/lib/client")), + mount: "/kaefer", + rjs: [{ + "name": "kaefer", + "location": "kaefer", + "main": "client.js" + }] + }]); + + statics.addStatics([{ + path: dirname(require.resolve("smith")), + mount: "/smith", + rjs: [{ + "name": "smith", + "location": "smith", + "main": "smith.js" + }] + }]); + + statics.addStatics([{ + path: dirname(require.resolve("vfs-socket/consumer")), + mount: "/vfs-socket", + rjs: [{ + "name": "vfs-socket", + "location": "vfs-socket" + }] + }]); + + statics.addStatics([{ + path: dirname(require.resolve("msgpack-js-browser")), + mount: "/msgpack-js", + rjs: [{ + "name": "msgpack-js", + "location": "msgpack-js", + "main": "msgpack.js" + }] + }]); + + } + + /***** Lifecycle *****/ + + plugin.on("load", function(){ + load(); + }); + + /***** Register and define API *****/ + + plugin.freezePublicAPI({}); + + register(null, { + "smithio.server": plugin + }); +} \ No newline at end of file diff --git a/plugins/c9.vfs.server/vfs.connect.local.js b/plugins/c9.vfs.server/vfs.connect.local.js new file mode 100644 index 00000000..5189ccd0 --- /dev/null +++ b/plugins/c9.vfs.server/vfs.connect.local.js @@ -0,0 +1,69 @@ +define(function(require, exports, module) { + "use strict"; + + main.consumes = ["Plugin"]; + main.provides = ["vfs.connect"]; + return main; + + function main(options, imports, register) { + var Plugin = imports.Plugin; + + var Vfs = require("./vfs"); + var localFs = require("vfs-local"); + + var join = require("path").join; + + /***** Initialization *****/ + + var plugin = new Plugin("Ajax.org", main.consumes); + + /***** Methods *****/ + + function connect(user, pid, callback) { + var vfsOptions = { + root: "/", + metapath: join(options.settingDir, "/metadata"), + wsmetapath: join(options.settingDir, "/metadata/workspace"), + local: false, + readOnly: false, + debug: options.debug, + homeDir: process.env.HOME, + projectDir: options.workspaceDir, + nakBin: options.nakBin || join(options.installPath, "/node_modules/.bin/nak"), + nodeBin: options.nodeBin, + tmuxBin: options.tmuxBin + }; + for (var key in options.vfs) + vfsOptions[key] = options.vfs[key]; + + var master = { + destroy: function() {}, + disconnect: function() {}, + on: function() {}, + removeListener: function() {} + }; + + callback(null, new Vfs(localFs(vfsOptions), master, { + debug: options.debug || false, + homeDir: vfsOptions.homeDir, + projectDir: vfsOptions.projectDir, + extendDirectory: options.extendDirectory, + extendOptions: options.extendOptions, + vfsOptions: vfsOptions, + public: true + })); + + return function cancel() {}; + } + + /***** Register and define API *****/ + + plugin.freezePublicAPI({ + connect: connect + }); + + register(null, { + "vfs.connect": plugin + }); + } +}); \ No newline at end of file diff --git a/plugins/c9.vfs.server/vfs.connect.standalone.js b/plugins/c9.vfs.server/vfs.connect.standalone.js new file mode 100644 index 00000000..9aa89953 --- /dev/null +++ b/plugins/c9.vfs.server/vfs.connect.standalone.js @@ -0,0 +1,80 @@ +/** + * Keeps a Cache of VFS instances + * + * @copyright 2010, Ajax.org B.V. + * @license GPLv3 + */ +define(function(require, exports, module) { + main.consumes = ["Plugin", "api"]; + main.provides = ["vfs.connect"]; + return main; + + + function main(options, imports, register) { + var Plugin = imports.Plugin; + var api = imports.api; + + var Vfs = require("./vfs"); + var Parent = require('vfs-child').Parent; + + /***** Initialization *****/ + + var plugin = new Plugin("Ajax.org", main.consumes); + + /***** Methods *****/ + + function connect(user, pid, callback) { + var projectOptions = api.getVfsOptions + ? api.getVfsOptions(user, pid) + : { + workspaceDir: options.workspaceDir, + extendOptions: options.extendOptions + }; + + var vfsOptions = { + root: "/", + metapath: "/.c9/metadata", + wsmetapath: "/.c9/metadata/workspace", + local: false, + readOnly: false, + debug: options.debug, + homeDir: process.env.HOME, + projectDir: projectOptions.workspaceDir, + nakBin: options.nakBin || (process.env.HOME + "/.c9/node_modules/.bin/nak"), + nodeBin: options.nodeBin, + tmuxBin: options.tmuxBin + }; + for (var key in options.vfs) + vfsOptions[key] = options.vfs[key]; + + var master = new Parent(vfsOptions); + master.connect(function(err, vfs) { + if (err) return callback(err); + + callback(null, new Vfs(vfs, master, { + debug: options.debug || false, + homeDir: vfsOptions.homeDir, + projectDir: vfsOptions.projectDir, + extendDirectory: options.extendDirectory, + extendOptions: projectOptions.extendOptions, + extendToken: "not_needed", + collab: options.collab, + vfsOptions: vfsOptions, + public: true + })); + }); + + return function cancel() {}; + } + + /***** Register and define API *****/ + + plugin.freezePublicAPI({ + connect: connect + }); + + register(null, { + "vfs.connect": plugin + }); + } +}); \ No newline at end of file diff --git a/plugins/c9.vfs.server/vfs.js b/plugins/c9.vfs.server/vfs.js new file mode 100644 index 00000000..d75a8adc --- /dev/null +++ b/plugins/c9.vfs.server/vfs.js @@ -0,0 +1,232 @@ +"use strict"; + +var EventEmitter = require("events").EventEmitter; +var util = require("util"); +var kaefer = require("kaefer"); +var smith = require("smith"); +var eio = require("engine.io"); +var restful = require("vfs-http-adapter"); +var VfsWorker = require('vfs-socket/worker').Worker; +var wrapVfs = require("./vfs_wrapper"); +var proxyVfs = require("./vfs_proxy"); +var urlParse = require('url').parse; + +module.exports = Vfs; + +function Vfs(vfs, master, options) { + EventEmitter.call(this); + + this.vfs = vfs; + this.master = master; + this.debug = options.debug || false; + this.logger = options.logger || {log: function(){}}; + this.readonly = options.readonly || false; + this.public = options.public || false; + this.vfsOptions = options.vfsOptions || {}; + this.pid = this.vfsOptions.pid; + var extendToken = options.extendToken; + + this.homeDir = options.homeDir; + this.workspaceDir = options.projectDir; + + this.vfsHome = wrapVfs(vfs, { + root: this.homeDir, + // we don't want to expose files from the home dir in read only mode + // we need to protect e.g. .ssh + blocked: this.readonly, + extendDirectory: options.extendDirectory, + extendOptions: options.extendOptions, + extendToken: extendToken + }); + this.vfsWorkspace = wrapVfs(vfs, { + root: this.workspaceDir, + readonly: this.readonly, + extendDirectory: options.extendDirectory, + extendOptions: options.extendOptions, + extendToken: extendToken + }); + + var vfsProxy = proxyVfs(Object.keys(this.vfsHome), this.vfsHome, this.vfsWorkspace); + this.engine = this._createEngine(vfsProxy, options); + + this.restful = { + home: restful("/", this.vfsHome, { + autoIndex: false, + noMime: true, + readOnly: this.readonly + }), + workspace: restful("/", this.vfsWorkspace, { + autoIndex: false, + noMime: false, + readOnly: this.readonly + }) + }; + + this._watchConnection(options.vfsOptions.pid); +} + +util.inherits(Vfs, EventEmitter); + +Vfs.prototype.handleRest = function(scope, path, req, res, next) { + this.emit("keepalive"); + + if (!req.uri) { req.uri = urlParse(req.url, true); } + var proto = req.proto; + req.restBase = proto + "://" + req.headers.host + req.uri.pathname; + req.uri.pathname = path; + + this.restful[scope](req, res, next); +}; + +Vfs.prototype.handleEngine = function(req, res, next) { + if (req.ws) { + req.method = "GET"; + this.engine.handleUpgrade(req, req.ws.socket, req.ws.head); + + // default node behavior is to disconnect when no handlers + // but by adding a handler, we prevent that + // and if no eio thing handles the upgrade + // then the socket needs to die! + setTimeout(function() { + var socket = req.ws.socket; + if (socket.writable && socket.bytesWritten <= 0) { + return socket.end(); + } + }, 1000); + } + else { + this.engine.handleRequest(req, res); + } +}; + +Vfs.prototype.destroy = function(err) { + if (err) { + console.error("VFS error", err); + console.trace(); + } + + if (this.master) + this.master.destroy(); + + if (this.socket) + this.socket.disconnect(); + + clearInterval(this.keepAliveTimer); + + this.master = null; + this.emit("destroy", err); +}; + +Vfs.prototype._watchConnection = function(pid) { + var master = this.master; + var that = this; + + function onError(err) { + console.log("destroying because of error", err && err.stack || err) + that.destroy(err); + } + function onStderr(data) { + // @todo collab stderr logs + console.log("VFS stderr [" + pid + "]: " + data); + } + + master.on("disconnect", onError); + master.on("error", onError); + master.on("stderr", onStderr); + + master.destroy = function() { + master.removeListener("disconnect", onError); + master.removeListener("error", onError); + master.removeListener("stderr", onStderr); + master.disconnect(); + }; +}; + +Vfs.prototype._createEngine = function(vfs, options) { + var that = this; + + var engine = new eio.Server({ + pingTimeout: 3000, + pingInterval: 15000, + transports: ["polling", "websocket"], + allowUpgrades: true, + cookie: false + }); + + this.keepAliveTimer = null; + + this.workers = 0; + + var server = new kaefer.Server(engine, { debug: false }); + server.on("connection", function (socket) { + clearInterval(that.keepAliveTimer); + that.keepAliveTimer = setInterval(function() { + that.emit("keepalive"); + }, 2000); + that.workers++; + + if (that.socket) + that.socket.disconnect(); + + that.socket = socket; + socket.on('close', function (reason, description) { + var logMetadata = {collab: options.collab, reason: reason, description: description, id: that.id, sid: socket.id, pid: that.pid}; + console.log("Socket closed", logMetadata); + logMetadata.message = "Socket closed"; + that.logger.log(logMetadata); + }); + + var transport = new smith.EngineIoTransport(socket, true); + var worker = new VfsWorker(vfs); + worker.connectionTimeout = 30000; + worker.connect(transport); + + worker.on("error", function (err) { + console.error("Unhandled worker error:", err.stack); + }); + + var collabApi; + + function disposeCollabClient() { + console.log("VFS Collab Disposing:", that.id); + collabApi.dispose(that.id); + } + + worker.on("disconnect", function() { + var logMetadata = {collab: options.collab, id: that.id, sid: socket.id, pid: that.pid}; + console.log("VFS socket disconnect:", logMetadata); + logMetadata.message = "VFS socket disconnect"; + that.logger.log(logMetadata); + if (options.collab) { + if (collabApi) + return disposeCollabClient(); + vfs.use("collab", {}, function(err, meta) { + if (err || !meta || !meta.api) + return console.error("Collab not found on disconnect"); + collabApi = meta.api; + disposeCollabClient(); + }); + } + + that.workers--; + if (!that.workers) + clearInterval(that.keepAliveTimer); + that.socket = null; + }); + }); + + return engine; +}; + +Vfs.prototype.handlePublish = function(message) { + console.log("PUBSUB: PUBLISH", message); + var that = this; + if (this.pubSubApi) + return this.pubSubApi.publish(message); + this.vfs.use("pubsub", {}, function(err, meta) { + if (err || !meta || !meta.api) + return console.error("PubSub not found", err, !!meta, !! (meta && meta.api)); + that.pubSubApi = meta.api; + that.pubSubApi.publish(message); + }); +}; diff --git a/plugins/c9.vfs.server/vfs.server.js b/plugins/c9.vfs.server/vfs.server.js new file mode 100644 index 00000000..274c3a09 --- /dev/null +++ b/plugins/c9.vfs.server/vfs.server.js @@ -0,0 +1,319 @@ +"use strict"; + +plugin.consumes = [ + "api", + "passport", + "connect", + "connect.render", + "connect.render.ejs", + "connect.remote-address", + "vfs.cache" +]; +plugin.provides = [ + "vfs.server" +]; + +module.exports = plugin; + +/** + * VFS session: + * - unique vfsid + * - bound to the client sessionId + * - either readonly or read/write + * - auto disposes after N seconds of idle time + * - keeps: + * - vfs-ssh instance + * - engine.io instance (only one socket connected at a time) + * - vfs rest API instance + * + * - authentication using tokens or auth headers (no cookies) + */ +function plugin(options, imports, register) { + var api = imports.api; + var cache = imports["vfs.cache"]; + var passport = imports.passport; + var connect = imports.connect; + var render = imports["connect.render"]; + + var Types = require("frontdoor").Types; + var error = require("http-error"); + var kaefer = require("kaefer"); + var ratelimit = require("c9/ratelimit"); + var requestTimeout = require("c9/request_timeout"); + + var section = api.section("vfs"); + + + section.registerType("vfsid", new Types.RegExp(/[a-zA-Z0-9]{16}/)); + section.registerType("pid", new Types.Number(0)); + + // admin interface + api.use(render.setTemplatePath(__dirname + "/views")); + api.get("/:status", { + params: { + status: { + type: /^vfs(?:\.(?:json|html))?$/, + source: "url" + } + } + }, [ + api.ensureAdmin(), + function(req, res, next) { + + var type = req.params.status.split(".")[1] || "html"; + + var entries = cache.getAll(); + var data = { + entries: [] + }; + for (var key in entries) { + var entry = entries[key]; + + data.entries.push({ + vfsid: entry.vfsid, + pid: entry.pid, + uid: entry.user.id, + ttl: entry.ttl, + readonly: entry.vfs ? entry.vfs.readonly : "", + state: entry.vfs ? "connected" : "connecting", + startTime: entry.startTime, + connectTime: entry.connectTime || -1 + }); + } + + if (type == "json") + res.json(data); + else + res.render("status.html.ejs", data, next); + } + ]); + + // creates a new connection for the specified project + section.post("/:pid", { + params: { + "pid": { + type: "pid" + }, + "version": { + type: "string", + source: "body", + optional: false + } + } + }, [ + api.authenticate(), + ratelimit("pid", 60 * 1000, 30), + function(req, res, next) { + var pid = req.params.pid; + var version = req.params.version; + var user = req.user; + + if (version != kaefer.version.protocol) { + var err = new error.PreconditionFailed("Wrong VFS protocol version. Expected version '" + kaefer.version.protocol + "' but found '" + version + "'"); + err.subtype = "protocol_mismatch"; + err.clientVersion = version; + err.serverVersion = kaefer.version.protocol; + return next(err); + } + + var done = false; + var cancel = cache.create(pid, user, function(err, entry) { + if (done) return; + if (err) return next(err); + + res.json({ + pid: pid, + uid: user.id, + readonly: entry.vfs.readonly, + vfsid: entry.vfsid + }, null, 201); + }); + + // if the clients aborts the request we have to kill the ssh process + req.on("close", function() { + done = true; + cancel(); + res.json({}, 0, 500); + }); + } + ]); + + // checks if the connection exists and returns connection meta data + section.get("/:pid/:vfsid", { + params: { + "pid": { + type: "pid" + }, + "vfsid": { + type: "vfsid" + } + } + }, function(req, res, next) { + var pid = req.params.pid; + var vfsid = req.params.vfsid; + + var entry = cache.get(vfsid); + if (!entry) { + var err = new error.PreconditionFailed("VFS connection does not exist"); + err.code = 499; + return next(err); + } + + res.json({ + pid: pid, + vfsid: vfsid, + uid: entry.user.id + }); + }); + + // read only rest interface + section.get("/:pid/plugins/:access_token/:path*", { + "access_token": { + type: "string" + }, + "pid": { + type: "pid" + }, + "path": { + type: "string" + } + }, [ + requestTimeout(15*60*1000), + connect.getModule().compress(), + function(req, res, next) { + req.query = { + access_token: req.params["access_token"] + }; + passport.authenticate("bearer", { session: false }, function(err, user) { + if (err) return next(err); + + req.user = user || { id: -1}; + next(); + })(req, res, next); + }, + function(req, res, next) { + var pid = req.params.pid; + var path = req.params.path; + var user = req.user; + + if (path.indexOf("../") !== -1) + return next(new error.BadRequest("invalid path")); + + cache.readonlyRest(pid, user, "/.c9/plugins/" + path, "home", req, res, next); + } + ]); + + section.get("/:pid/preview/:path*", { + "pid": { + type: "pid" + }, + "path": { + type: "string" + } + }, [ + requestTimeout(15*60*1000), + connect.getModule().compress(), + function(req, res, next) { + passport.authenticate("bearer", { session: false }, function(err, user) { + if (err) return next(err); + + req.user = user || { id: -1}; + next(); + })(req, res, next); + }, + function(req, res, next) { + var pid = req.params.pid; + var path = req.params.path; + var user = req.user; + + cache.readonlyRest(pid, user, path, "workspace", req, res, next); + } + ]); + + // disconnects VFS connection + section.delete("/:pid/:vfsid", { + params: { + "pid": { + type: "pid" + }, + "vfsid": { + type: "vfsid" + } + } + }, function(req, res, next) { + var vfsid = req.params.vfsid; + + cache.remove(vfsid); + res.json({}, null, 201); + }); + + // REST API + // serves all files with mime type "text/plain" + // real mime type will be in "X-C9-ContentType" + section.all("/:pid/:vfsid/:scope/:path*", { + params: { + "pid": { + type: "pid" + }, + "vfsid": { + type: "vfsid" + }, + "scope": { + type: /^(home|workspace)$/ + }, + "path": { + type: "string" + } + } + }, [ + function(req, res, next) { + var vfsid = req.params.vfsid; + var scope = req.params.scope; + var path = req.params.path; + + var entry = cache.get(vfsid); + if (!entry) { + var err = new error.PreconditionFailed("VFS connection does not exist"); + err.code = 499; + return next(err); + } + + entry.vfs.handleRest(scope, path, req, res, next); + } + ]); + + // engine.io endpoint of the VFS server + section.all("/:pid/:vfsid/socket/:path*", { + params: { + "pid": { + type: "pid" + }, + "vfsid": { + type: "vfsid" + }, + "path": { + type: "string" + } + } + }, [ + requestTimeout(15*60*1000), + function handleEngine(req, res, next) { + var vfsid = req.params.vfsid; + + var entry = cache.get(vfsid); + if (!entry) { + var err = new error.PreconditionFailed("VFS connection does not exist"); + err.code = 499; + return next(err); + } + + entry.vfs.handleEngine(req, res, next); + } + ]); + + register(null, { + "vfs.server": { + get section() { return section; } + } + }); +} diff --git a/plugins/c9.vfs.server/vfs_proxy.js b/plugins/c9.vfs.server/vfs_proxy.js new file mode 100644 index 00000000..c73732fb --- /dev/null +++ b/plugins/c9.vfs.server/vfs_proxy.js @@ -0,0 +1,70 @@ +"use strict"; + +module.exports = function(methods, vfsHome, vfsWorkspace) { + var proxy = {}; + var homeDir = vfsHome.root.replace(/\/?$/, "/"); + + /** VFS command options that contain paths. */ + var PATH_OPTIONS = ["from", "to", "target"]; + + var absoluteWrap = { + spawn: true, + pty: true, + execFile: true, + }; + + var noWrap = { + connect: true, + on: true, + off: true, + emit: true, + extend: true, + unextend: true, + use: true, + killtree: true + }; + + methods.forEach(function(name) { + var vfsMethod = vfsWorkspace[name]; + if (typeof vfsMethod !== "function") + return; + + proxy[name] = wrap(name, noWrap[name]); + }); + + function wrap(name, excluded) { + if (excluded) { + return function(){ + vfsWorkspace[name].apply(vfsWorkspace, arguments); + }; + } + + return function(path, options) { + var args = Array.prototype.slice.call(arguments); + + PATH_OPTIONS.forEach(function(o) { + options[o] = options[o] && substituteTilde(options[o]); + }); + args[1] = options; + + if (path.charAt(0) == "~") { + args[0] = substituteTilde(path); + + vfsHome[name].apply(vfsHome, args); + } + else + vfsWorkspace[name].apply(vfsWorkspace, args); + }; + + function substituteTilde(path) { + return (absoluteWrap[name]) + ? path.replace(/^~/, homeDir.substr(0, homeDir.length - 1)) + : path.replace(/^~/, ""); + } + } + + proxy.readonly = vfsWorkspace.readonly; + proxy.root = vfsWorkspace.root; + + return proxy; +}; \ No newline at end of file diff --git a/plugins/c9.vfs.server/vfs_wrapper.js b/plugins/c9.vfs.server/vfs_wrapper.js new file mode 100644 index 00000000..c4bf5a37 --- /dev/null +++ b/plugins/c9.vfs.server/vfs_wrapper.js @@ -0,0 +1,99 @@ +"use strict"; + +var path = require("path"); +var error = require("http-error"); + +module.exports = function(vfs, options) { + var root = options.root || ""; + var methods = options.methods || Object.keys(vfs); + var readonly = "readonly" in options ? options.readonly : false; + var blocked = !!options.blocked; + var extendToken = options.extendToken; + + var roMethods = { + resolve: 1, + stat: 1, + readfile: 1, + readdir: 1, + watch: 1, + on: 1, + off: 1, + extend: 1, + unextend: 1, + use: 1 + }; + + var noWrap = { + connect: true, + spawn: true, + pty: true, + execFile: true, + on: true, + off: true, + emit: true, + extend: true, + unextend: true, + use: true, + killtree: true + }; + + var wrapper = methods.reduce(function(wrapper, method) { + var vfsMethod = vfs[method]; + if (typeof vfsMethod !== "function") return wrapper; + + if (blocked) + wrapper[method] = wrapReadOnly(method); + else if (readonly && !roMethods[method]) + wrapper[method] = wrapReadOnly(method); + else if (noWrap[method] || !root) + wrapper[method] = vfsMethod.bind(vfs); + else + wrapper[method] = wrapSandbox(vfsMethod); + + return wrapper; + }, {}); + + function wrapSandbox(vfsMethod) { + return function(path, options, callback) { + options.sandbox = root; + vfsMethod.call(vfs, path, options, callback); + }; + } + + function wrapReadOnly(vfsMethod) { + return function(path, options, callback) { + return callback(new error.Forbidden("VFS method " + vfsMethod + " is blocked in read only mode")); + }; + } + + var extendDirectory = path.normalize(options.extendDirectory || ""); + var extendOptions = options.extendOptions || {}; + + wrapper.extend = function(name, options, callback) { + for (var key in extendOptions) { + options[key] = extendOptions[key]; + } + + if (options.code || options.stream) { + if (readonly && (!extendToken || extendToken !== options.extendToken)) + return callback(new error.Forbidden("VFS extend: " + name + " with options 'stream' or 'code' not authorized in read only mode")); + else + return vfs.extend(name, options, callback); + } + + if (extendDirectory) { + var file = options.file = path.normalize(path.join(extendDirectory, options.file)); + + var dir = path.dirname(file); + if (dir.indexOf(extendDirectory) !== 0) + return callback(new error.Forbidden("Option 'file' in VFS extend must be in the white listed directory")); + } + + return vfs.extend(name, options, callback); + }; + + wrapper.readonly = readonly; + wrapper.root = root; + + return wrapper; +}; \ No newline at end of file diff --git a/plugins/c9.vfs.standalone/standalone.js b/plugins/c9.vfs.standalone/standalone.js new file mode 100644 index 00000000..9448b065 --- /dev/null +++ b/plugins/c9.vfs.standalone/standalone.js @@ -0,0 +1,325 @@ +"use strict"; + +plugin.consumes = [ + "connect.static", + "connect", + "preview.handler", + "connect.render", + "connect.render.ejs" +]; +plugin.provides = ["api", "passport"]; + +module.exports = plugin; + +var fs = require("fs"); +var assert = require("assert"); +var async = require("async"); +var join = require("path").join; +var extend = require("util")._extend; +var resolve = require("path").resolve; +var basename = require("path").basename; +var frontdoor = require("frontdoor"); + +function plugin(options, imports, register) { + var previewHandler = imports["preview.handler"]; + var statics = imports["connect.static"]; + + assert(options.workspaceDir, "Option 'workspaceDir' is required"); + assert(options.options, "Option 'options' is required"); + + + // serve index.html + statics.addStatics([{ + path: __dirname + "/www", + mount: "/" + }]); + + statics.addStatics([{ + path: __dirname + "/../../configs", + mount: "/configs" + }]); + + statics.addStatics([{ + path: __dirname + "/../../test/resources", + mount: "/test" + }]); + + var api = frontdoor(); + imports.connect.use(api); + + api.get("/", function(req, res, next) { + res.writeHead(302, { "Location": "/ide.html" }); + res.end(); + }); + + api.get("/ide.html", { + params: { + workspacetype: { + source: "query", + optional: true + }, + devel: { + source: "query", + optional: true + }, + collab: { + type: "number", + optional: true, + source: "query" + }, + nocollab: { + type: "number", + optional: true, + source: "query" + }, + debug: { + optional: true, + source: "query" + }, + packed: { + source: "query", + type: "number", + optional: true + }, + token: { + source: "query", + optional: true + }, + w: { + source: "query", + optional: true + }, + } + }, function(req, res, next) { + var configType = null; + if (req.params.workspacetype) + configType = "workspace-" + req.params.workspacetype; + else if (req.params.devel) + configType = "devel"; + + var configName = getConfigName(configType, options); + var cdn = options.options.cdn; + options.options.themePrefix = "/static/" + cdn.version + "/skin/" + configName; + options.options.workerPrefix = "/static/" + cdn.version + "/worker"; + if (req.params.packed == 1) + options.options.CORSWorkerPrefix = "/static/" + cdn.version + "/worker"; + + var collab = options.collab && req.params.collab !== 0 && req.params.nocollab != 1; + var opts = extend({}, options); + opts.options.collab = collab; + if (req.params.packed == 1) + opts.packed = opts.options.packed = true; + + api.updatConfig(opts.options, { + w: req.params.w, + token: req.params.token + }); + + opts.options.debug = req.params.debug; + res.setHeader("Cache-Control", "no-cache, no-store"); + res.render(__dirname + "/views/standalone.html.ejs", { + architectConfig: getConfig(configType, opts), + configName: configName, + packed: opts.packed, + version: opts.version + }, next); + }); + + api.get("/_ping", function(params, callback) { + return callback(null, {"ping": "pong"}); + }); + + api.get("/preview/:path*", [ + function(req, res, next) { + req.projectSession = { + pid: 1 + }; + req.session = {}; + next(); + }, + previewHandler.proxyCall(function() { + return { + url: "http://localhost:" + options.options.port + "/vfs" + }; + }) + ]); + + api.get("/preview", function(req, res, next) { + res.redirect(req.url + "/"); + }); + + api.get("/vfs-root", function(req, res, next) { + if (!options.options.testing) + return next(); + + res.writeHead(200, {"Content-Type": "application/javascript"}); + res.end("define(function(require, exports, module) { return '" + + options.workspaceDir + "'; });"); + }); + + api.get("/update", function(req, res, next) { + res.writeHead(200, { + "Content-Type": "application/javascript", + "Access-Control-Allow-Origin": "*" + }); + var path = resolve(__dirname + "/../../build/output/latest.tar.gz"); + fs.readlink(path, function(err, target) { + res.end((target || "").split(".")[0]); + }); + }); + + api.get("/update/:path*", function(req, res, next) { + var filename = req.params.path; + var path = resolve(__dirname + "/../../build/output/" + filename); + + res.writeHead(200, {"Content-Type": "application/octet-stream"}); + var stream = fs.createReadStream(path); + stream.pipe(res); + }); + + api.get("/configs/require_config.js", function(req, res, next) { + var config = res.getOptions().requirejsConfig || {}; + config.waitSeconds = 240; + + res.writeHead(200, {"Content-Type": "application/javascript"}); + res.end("requirejs.config(" + JSON.stringify(config) + ");"); + }); + + api.get("/test/all.json", function(req, res, next) { + var base = __dirname + "/../../"; + var blacklistfile = base + "/test/blacklist.txt"; + var filefinder = require(base + "/test/filefinder.js"); + filefinder.find(base, "plugins", ".*_test.js", blacklistfile, function(err, result) { + result.all = result.list.concat(result.blacklist); + async.filterSeries(result.list, function(file, next) { + fs.readFile(file, "utf8", function(err, file) { + if (err) return next(false); + if (file.match(/^"use server"/m) && !file.match(/^"use client"/m)) + return next(false); + next(file.match(/^define\(|^require\(\[/m)); + }); + }, function(files) { + result.list = files; + res.writeHead(200, {"Content-Type": "application/json"}); + res.end(JSON.stringify(result, null, 2)); + }); + }); + }); + + api.get("/api.json", {name: "api"}, frontdoor.middleware.describeApi(api)); + + // fake authentication + api.authenticate = api.authenticate || function() { + return function(req, res, next) { + req.user = extend({}, options.options.extendOptions.user); + next(); + }; + }; + api.ensureAdmin = api.ensureAdmin || function() { + return function(req, res, next) { + next(); + }; + }; + api.getVfsOptions = api.getVfsOptions || function(user, pid) { + if (!options._projects) { + options._projects = [options.workspaceDir]; + } + var wd = options._projects[pid] || options._projects[0]; + console.log(user) + return { + workspaceDir: wd, + extendOptions: { + user: user, + project: { + id: pid, + name: pid + "-" + options._projects[pid] + }, + readonly: user.id > 100 + } + }; + }; + api.updatConfig = api.updatConfig || function(opts, params) { + var id = params.token; + opts.accessToken = opts.extendToken = id || "token"; + var user = opts.extendOptions.user; + user.id = id || -1; + user.name = id ? "user" + id : "johndoe"; + user.email = id ? "user" + id + "@c9.io" : "johndoe@example.org"; + user.fullname = id ? "User " + id : "John Doe"; + opts.workspaceDir = params.w ? params.w : options.workspaceDir; + opts.projectName = basename(opts.workspaceDir); + if (!options._projects) { + options._projects = [options.workspaceDir]; + } + var project = opts.extendOptions.project; + var pid = options._projects.indexOf(opts.workspaceDir); + if (pid == -1) + pid = options._projects.push(opts.workspaceDir) - 1; + project.id = pid; + }; + + imports.connect.setGlobalOption("apiBaseUrl", ""); + + register(null, { + "api": api, + "passport": { + authenticate: function() { + return function(req, res, next) { + req.user = extend({}, options.options.extendOptions.user); + next(); + }; + } + } + }); +} + +function getConfigName(requested, options) { + var name; + if (requested) { + name = requested; + } + else if (options.workspaceType) { + name = "workspace-" + options.workspaceType; + } + else if (options.options.client_config) { + // pick up client config from settings, if present + name = options.options.client_config; + } + else if (options.readonly) { + name = "default-ro"; + } + else { + name = "default"; + } + + if (options.local) + name += "-local"; + + return name; +} + +function getConfig(requested, options) { + var filename = __dirname + "/../../configs/client-" + getConfigName(requested, options) + ".js"; + + var installPath = options.settingDir || options.installPath || ""; + var workspaceDir = options.options.workspaceDir; + var settings = { + "user": join(installPath, "user.settings"), + "project": join(options.local ? installPath : join(workspaceDir, ".c9"), "project.settings"), + "state": join(options.local ? installPath : join(workspaceDir, ".c9"), "state.settings") + }; + + var fs = require("fs"); + for (var type in settings) { + var data = ""; + try { + data = fs.readFileSync(settings[type], "utf8"); + } catch (e) { + console.log(e); + } + settings[type] = data; + } + options.options.settings = settings; + + return require(filename)(options.options); +} diff --git a/plugins/c9.vfs.standalone/views/standalone.html.ejs b/plugins/c9.vfs.standalone/views/standalone.html.ejs new file mode 100644 index 00000000..47426afe --- /dev/null +++ b/plugins/c9.vfs.standalone/views/standalone.html.ejs @@ -0,0 +1,143 @@ + + + + + Cloud9 + + + + + + +
      +
      +
      + Loading your workspace +
      +
      +
      It will be just as you left it
      + +
      +
      + +
      +
      +
      + +
      + + + + <% if (packed) { %> + + <% } else { %> + + + <% } %> + + + \ No newline at end of file diff --git a/plugins/c9.vfs.standalone/www/html2canvas.js b/plugins/c9.vfs.standalone/www/html2canvas.js new file mode 100644 index 00000000..4689971c --- /dev/null +++ b/plugins/c9.vfs.standalone/www/html2canvas.js @@ -0,0 +1,2841 @@ +/* + html2canvas 0.4.0 + Copyright (c) 2013 Niklas von Hertzen (@niklasvh) + + Released under MIT License +*/ +(function(window, document, undefined){ + +"use strict"; + +var _html2canvas = {}, +previousElement, +computedCSS, +html2canvas; + +function h2clog(a) { + if (_html2canvas.logging && window.console && window.console.log) { + window.console.log(a); + } +} + +_html2canvas.Util = {}; + +_html2canvas.Util.trimText = (function(isNative){ + return function(input){ + if(isNative) { return isNative.apply( input ); } + else { return ((input || '') + '').replace( /^\s+|\s+$/g , '' ); } + }; +})( String.prototype.trim ); + +_html2canvas.Util.parseBackgroundImage = function (value) { + var whitespace = ' \r\n\t', + method, definition, prefix, prefix_i, block, results = [], + c, mode = 0, numParen = 0, quote, args; + + var appendResult = function(){ + if(method) { + if(definition.substr( 0, 1 ) === '"') { + definition = definition.substr( 1, definition.length - 2 ); + } + if(definition) { + args.push(definition); + } + if(method.substr( 0, 1 ) === '-' && + (prefix_i = method.indexOf( '-', 1 ) + 1) > 0) { + prefix = method.substr( 0, prefix_i); + method = method.substr( prefix_i ); + } + results.push({ + prefix: prefix, + method: method.toLowerCase(), + value: block, + args: args + }); + } + args = []; //for some odd reason, setting .length = 0 didn't work in safari + method = + prefix = + definition = + block = ''; + }; + + appendResult(); + for(var i = 0, ii = value.length; i -1){ + continue; + } + switch(c) { + case '"': + if(!quote) { + quote = c; + } + else if(quote === c) { + quote = null; + } + break; + + case '(': + if(quote) { break; } + else if(mode === 0) { + mode = 1; + block += c; + continue; + } else { + numParen++; + } + break; + + case ')': + if(quote) { break; } + else if(mode === 1) { + if(numParen === 0) { + mode = 0; + block += c; + appendResult(); + continue; + } else { + numParen--; + } + } + break; + + case ',': + if(quote) { break; } + else if(mode === 0) { + appendResult(); + continue; + } + else if (mode === 1) { + if(numParen === 0 && !method.match(/^url$/i)) { + args.push(definition); + definition = ''; + block += c; + continue; + } + } + break; + } + + block += c; + if(mode === 0) { method += c; } + else { definition += c; } + } + appendResult(); + + return results; +}; + +_html2canvas.Util.Bounds = function getBounds (el) { + var clientRect, + bounds = {}; + + if (el.getBoundingClientRect){ + clientRect = el.getBoundingClientRect(); + + + // TODO add scroll position to bounds, so no scrolling of window necessary + bounds.top = clientRect.top; + bounds.bottom = clientRect.bottom || (clientRect.top + clientRect.height); + bounds.left = clientRect.left; + + // older IE doesn't have width/height, but top/bottom instead + bounds.width = clientRect.width || (clientRect.right - clientRect.left); + bounds.height = clientRect.height || (clientRect.bottom - clientRect.top); + + return bounds; + + } +}; + +_html2canvas.Util.getCSS = function (el, attribute, index) { + // return $(el).css(attribute); + + var val, + isBackgroundSizePosition = attribute.match( /^background(Size|Position)$/ ); + + function toPX( attribute, val ) { + var rsLeft = el.runtimeStyle && el.runtimeStyle[ attribute ], + left, + style = el.style; + + // Check if we are not dealing with pixels, (Opera has issues with this) + // Ported from jQuery css.js + // From the awesome hack by Dean Edwards + // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 + + // If we're not dealing with a regular pixel number + // but a number that has a weird ending, we need to convert it to pixels + + if ( !/^-?[0-9]+\.?[0-9]*(?:px)?$/i.test( val ) && /^-?\d/.test( val ) ) { + + // Remember the original values + left = style.left; + + // Put in the new values to get a computed value out + if ( rsLeft ) { + el.runtimeStyle.left = el.currentStyle.left; + } + style.left = attribute === "fontSize" ? "1em" : (val || 0); + val = style.pixelLeft + "px"; + + // Revert the changed values + style.left = left; + if ( rsLeft ) { + el.runtimeStyle.left = rsLeft; + } + + } + + if (!/^(thin|medium|thick)$/i.test( val )) { + return Math.round(parseFloat( val )) + "px"; + } + + return val; + } + + if (previousElement !== el) { + computedCSS = document.defaultView.getComputedStyle(el, null); + } + val = computedCSS[attribute]; + + if (isBackgroundSizePosition) { + val = (val || '').split( ',' ); + val = val[index || 0] || val[0] || 'auto'; + val = _html2canvas.Util.trimText(val).split(' '); + + if(attribute === 'backgroundSize' && (!val[ 0 ] || val[ 0 ].match( /cover|contain|auto/ ))) { + //these values will be handled in the parent function + + } else { + val[ 0 ] = ( val[ 0 ].indexOf( "%" ) === -1 ) ? toPX( attribute + "X", val[ 0 ] ) : val[ 0 ]; + if(val[ 1 ] === undefined) { + if(attribute === 'backgroundSize') { + val[ 1 ] = 'auto'; + return val; + } + else { + // IE 9 doesn't return double digit always + val[ 1 ] = val[ 0 ]; + } + } + val[ 1 ] = ( val[ 1 ].indexOf( "%" ) === -1 ) ? toPX( attribute + "Y", val[ 1 ] ) : val[ 1 ]; + } + } else if ( /border(Top|Bottom)(Left|Right)Radius/.test( attribute) ) { + var arr = val.split(" "); + if ( arr.length <= 1 ) { + arr[ 1 ] = arr[ 0 ]; + } + arr[ 0 ] = parseInt( arr[ 0 ], 10 ); + arr[ 1 ] = parseInt( arr[ 1 ], 10 ); + val = arr; + } + + return val; +}; + +_html2canvas.Util.resizeBounds = function( current_width, current_height, target_width, target_height, stretch_mode ){ + var target_ratio = target_width / target_height, + current_ratio = current_width / current_height, + output_width, output_height; + + if(!stretch_mode || stretch_mode === 'auto') { + output_width = target_width; + output_height = target_height; + + } else { + if(target_ratio < current_ratio ^ stretch_mode === 'contain') { + output_height = target_height; + output_width = target_height * current_ratio; + } else { + output_width = target_width; + output_height = target_width / current_ratio; + } + } + + return { width: output_width, height: output_height }; +}; + +function backgroundBoundsFactory( prop, el, bounds, image, imageIndex, backgroundSize ) { + var bgposition = _html2canvas.Util.getCSS( el, prop, imageIndex ) , + topPos, + left, + percentage, + val; + + if (bgposition.length === 1){ + val = bgposition[0]; + + bgposition = []; + + bgposition[0] = val; + bgposition[1] = val; + } + + if (bgposition[0].toString().indexOf("%") !== -1){ + percentage = (parseFloat(bgposition[0])/100); + left = bounds.width * percentage; + if(prop !== 'backgroundSize') { + left -= (backgroundSize || image).width*percentage; + } + + } else { + if(prop === 'backgroundSize') { + if(bgposition[0] === 'auto') { + left = image.width; + + } else { + if(bgposition[0].match(/contain|cover/)) { + var resized = _html2canvas.Util.resizeBounds( image.width, image.height, bounds.width, bounds.height, bgposition[0] ); + left = resized.width; + topPos = resized.height; + } else { + left = parseInt (bgposition[0], 10 ); + } + } + + } else { + left = parseInt( bgposition[0], 10 ); + } + } + + + if(bgposition[1] === 'auto') { + topPos = left / image.width * image.height; + } else if (bgposition[1].toString().indexOf("%") !== -1){ + percentage = (parseFloat(bgposition[1])/100); + topPos = bounds.height * percentage; + if(prop !== 'backgroundSize') { + topPos -= (backgroundSize || image).height * percentage; + } + + } else { + topPos = parseInt(bgposition[1],10); + } + + return [left, topPos]; +} + +_html2canvas.Util.BackgroundPosition = function( el, bounds, image, imageIndex, backgroundSize ) { + var result = backgroundBoundsFactory( 'backgroundPosition', el, bounds, image, imageIndex, backgroundSize ); + return { left: result[0], top: result[1] }; +}; +_html2canvas.Util.BackgroundSize = function( el, bounds, image, imageIndex ) { + var result = backgroundBoundsFactory( 'backgroundSize', el, bounds, image, imageIndex ); + return { width: result[0], height: result[1] }; +}; + +_html2canvas.Util.Extend = function (options, defaults) { + for (var key in options) { + if (options.hasOwnProperty(key)) { + defaults[key] = options[key]; + } + } + return defaults; +}; + + +/* + * Derived from jQuery.contents() + * Copyright 2010, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + */ +_html2canvas.Util.Children = function( elem ) { + + + var children; + try { + + children = (elem.nodeName && elem.nodeName.toUpperCase() === "IFRAME") ? + elem.contentDocument || elem.contentWindow.document : (function( array ){ + var ret = []; + + if ( array !== null ) { + + (function( first, second ) { + var i = first.length, + j = 0; + + if ( typeof second.length === "number" ) { + for ( var l = second.length; j < l; j++ ) { + first[ i++ ] = second[ j ]; + } + + } else { + while ( second[j] !== undefined ) { + first[ i++ ] = second[ j++ ]; + } + } + + first.length = i; + + return first; + })( ret, array ); + + } + + return ret; + })( elem.childNodes ); + + } catch (ex) { + h2clog("html2canvas.Util.Children failed with exception: " + ex.message); + children = []; + } + return children; +}; + +_html2canvas.Util.Font = (function () { + + var fontData = {}; + + return function(font, fontSize, doc) { + if (fontData[font + "-" + fontSize] !== undefined) { + return fontData[font + "-" + fontSize]; + } + + var container = doc.createElement('div'), + img = doc.createElement('img'), + span = doc.createElement('span'), + sampleText = 'Hidden Text', + baseline, + middle, + metricsObj; + + container.style.visibility = "hidden"; + container.style.fontFamily = font; + container.style.fontSize = fontSize; + container.style.margin = 0; + container.style.padding = 0; + + doc.body.appendChild(container); + + // http://probablyprogramming.com/2009/03/15/the-tiniest-gif-ever (handtinywhite.gif) + img.src = "data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACwAAAAAAQABAAACAkQBADs="; + img.width = 1; + img.height = 1; + + img.style.margin = 0; + img.style.padding = 0; + img.style.verticalAlign = "baseline"; + + span.style.fontFamily = font; + span.style.fontSize = fontSize; + span.style.margin = 0; + span.style.padding = 0; + + span.appendChild(doc.createTextNode(sampleText)); + container.appendChild(span); + container.appendChild(img); + baseline = (img.offsetTop - span.offsetTop) + 1; + + container.removeChild(span); + container.appendChild(doc.createTextNode(sampleText)); + + container.style.lineHeight = "normal"; + img.style.verticalAlign = "super"; + + middle = (img.offsetTop-container.offsetTop) + 1; + metricsObj = { + baseline: baseline, + lineWidth: 1, + middle: middle + }; + + fontData[font + "-" + fontSize] = metricsObj; + + doc.body.removeChild(container); + + return metricsObj; + }; +})(); + +(function(){ + + _html2canvas.Generate = {}; + + var reGradients = [ + /^(-webkit-linear-gradient)\(([a-z\s]+)([\w\d\.\s,%\(\)]+)\)$/, + /^(-o-linear-gradient)\(([a-z\s]+)([\w\d\.\s,%\(\)]+)\)$/, + /^(-webkit-gradient)\((linear|radial),\s((?:\d{1,3}%?)\s(?:\d{1,3}%?),\s(?:\d{1,3}%?)\s(?:\d{1,3}%?))([\w\d\.\s,%\(\)\-]+)\)$/, + /^(-moz-linear-gradient)\(((?:\d{1,3}%?)\s(?:\d{1,3}%?))([\w\d\.\s,%\(\)]+)\)$/, + /^(-webkit-radial-gradient)\(((?:\d{1,3}%?)\s(?:\d{1,3}%?)),\s(\w+)\s([a-z\-]+)([\w\d\.\s,%\(\)]+)\)$/, + /^(-moz-radial-gradient)\(((?:\d{1,3}%?)\s(?:\d{1,3}%?)),\s(\w+)\s?([a-z\-]*)([\w\d\.\s,%\(\)]+)\)$/, + /^(-o-radial-gradient)\(((?:\d{1,3}%?)\s(?:\d{1,3}%?)),\s(\w+)\s([a-z\-]+)([\w\d\.\s,%\(\)]+)\)$/ + ]; + + /* + * TODO: Add IE10 vendor prefix (-ms) support + * TODO: Add W3C gradient (linear-gradient) support + * TODO: Add old Webkit -webkit-gradient(radial, ...) support + * TODO: Maybe some RegExp optimizations are possible ;o) + */ + _html2canvas.Generate.parseGradient = function(css, bounds) { + var gradient, i, len = reGradients.length, m1, stop, m2, m2Len, step, m3, tl,tr,br,bl; + + for(i = 0; i < len; i+=1){ + m1 = css.match(reGradients[i]); + if(m1) { + break; + } + } + + if(m1) { + switch(m1[1]) { + case '-webkit-linear-gradient': + case '-o-linear-gradient': + + gradient = { + type: 'linear', + x0: null, + y0: null, + x1: null, + y1: null, + colorStops: [] + }; + + // get coordinates + m2 = m1[2].match(/\w+/g); + if(m2){ + m2Len = m2.length; + for(i = 0; i < m2Len; i+=1){ + switch(m2[i]) { + case 'top': + gradient.y0 = 0; + gradient.y1 = bounds.height; + break; + + case 'right': + gradient.x0 = bounds.width; + gradient.x1 = 0; + break; + + case 'bottom': + gradient.y0 = bounds.height; + gradient.y1 = 0; + break; + + case 'left': + gradient.x0 = 0; + gradient.x1 = bounds.width; + break; + } + } + } + if(gradient.x0 === null && gradient.x1 === null){ // center + gradient.x0 = gradient.x1 = bounds.width / 2; + } + if(gradient.y0 === null && gradient.y1 === null){ // center + gradient.y0 = gradient.y1 = bounds.height / 2; + } + + // get colors and stops + m2 = m1[3].match(/((?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\)(?:\s\d{1,3}(?:%|px))?)+/g); + if(m2){ + m2Len = m2.length; + step = 1 / Math.max(m2Len - 1, 1); + for(i = 0; i < m2Len; i+=1){ + m3 = m2[i].match(/((?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\))\s*(\d{1,3})?(%|px)?/); + if(m3[2]){ + stop = parseFloat(m3[2]); + if(m3[3] === '%'){ + stop /= 100; + } else { // px - stupid opera + stop /= bounds.width; + } + } else { + stop = i * step; + } + gradient.colorStops.push({ + color: m3[1], + stop: stop + }); + } + } + break; + + case '-webkit-gradient': + + gradient = { + type: m1[2] === 'radial' ? 'circle' : m1[2], // TODO: Add radial gradient support for older mozilla definitions + x0: 0, + y0: 0, + x1: 0, + y1: 0, + colorStops: [] + }; + + // get coordinates + m2 = m1[3].match(/(\d{1,3})%?\s(\d{1,3})%?,\s(\d{1,3})%?\s(\d{1,3})%?/); + if(m2){ + gradient.x0 = (m2[1] * bounds.width) / 100; + gradient.y0 = (m2[2] * bounds.height) / 100; + gradient.x1 = (m2[3] * bounds.width) / 100; + gradient.y1 = (m2[4] * bounds.height) / 100; + } + + // get colors and stops + m2 = m1[4].match(/((?:from|to|color-stop)\((?:[0-9\.]+,\s)?(?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\)\))+/g); + if(m2){ + m2Len = m2.length; + for(i = 0; i < m2Len; i+=1){ + m3 = m2[i].match(/(from|to|color-stop)\(([0-9\.]+)?(?:,\s)?((?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\))\)/); + stop = parseFloat(m3[2]); + if(m3[1] === 'from') { + stop = 0.0; + } + if(m3[1] === 'to') { + stop = 1.0; + } + gradient.colorStops.push({ + color: m3[3], + stop: stop + }); + } + } + break; + + case '-moz-linear-gradient': + + gradient = { + type: 'linear', + x0: 0, + y0: 0, + x1: 0, + y1: 0, + colorStops: [] + }; + + // get coordinates + m2 = m1[2].match(/(\d{1,3})%?\s(\d{1,3})%?/); + + // m2[1] == 0% -> left + // m2[1] == 50% -> center + // m2[1] == 100% -> right + + // m2[2] == 0% -> top + // m2[2] == 50% -> center + // m2[2] == 100% -> bottom + + if(m2){ + gradient.x0 = (m2[1] * bounds.width) / 100; + gradient.y0 = (m2[2] * bounds.height) / 100; + gradient.x1 = bounds.width - gradient.x0; + gradient.y1 = bounds.height - gradient.y0; + } + + // get colors and stops + m2 = m1[3].match(/((?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\)(?:\s\d{1,3}%)?)+/g); + if(m2){ + m2Len = m2.length; + step = 1 / Math.max(m2Len - 1, 1); + for(i = 0; i < m2Len; i+=1){ + m3 = m2[i].match(/((?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\))\s*(\d{1,3})?(%)?/); + if(m3[2]){ + stop = parseFloat(m3[2]); + if(m3[3]){ // percentage + stop /= 100; + } + } else { + stop = i * step; + } + gradient.colorStops.push({ + color: m3[1], + stop: stop + }); + } + } + break; + + case '-webkit-radial-gradient': + case '-moz-radial-gradient': + case '-o-radial-gradient': + + gradient = { + type: 'circle', + x0: 0, + y0: 0, + x1: bounds.width, + y1: bounds.height, + cx: 0, + cy: 0, + rx: 0, + ry: 0, + colorStops: [] + }; + + // center + m2 = m1[2].match(/(\d{1,3})%?\s(\d{1,3})%?/); + if(m2){ + gradient.cx = (m2[1] * bounds.width) / 100; + gradient.cy = (m2[2] * bounds.height) / 100; + } + + // size + m2 = m1[3].match(/\w+/); + m3 = m1[4].match(/[a-z\-]*/); + if(m2 && m3){ + switch(m3[0]){ + case 'farthest-corner': + case 'cover': // is equivalent to farthest-corner + case '': // mozilla removes "cover" from definition :( + tl = Math.sqrt(Math.pow(gradient.cx, 2) + Math.pow(gradient.cy, 2)); + tr = Math.sqrt(Math.pow(gradient.cx, 2) + Math.pow(gradient.y1 - gradient.cy, 2)); + br = Math.sqrt(Math.pow(gradient.x1 - gradient.cx, 2) + Math.pow(gradient.y1 - gradient.cy, 2)); + bl = Math.sqrt(Math.pow(gradient.x1 - gradient.cx, 2) + Math.pow(gradient.cy, 2)); + gradient.rx = gradient.ry = Math.max(tl, tr, br, bl); + break; + case 'closest-corner': + tl = Math.sqrt(Math.pow(gradient.cx, 2) + Math.pow(gradient.cy, 2)); + tr = Math.sqrt(Math.pow(gradient.cx, 2) + Math.pow(gradient.y1 - gradient.cy, 2)); + br = Math.sqrt(Math.pow(gradient.x1 - gradient.cx, 2) + Math.pow(gradient.y1 - gradient.cy, 2)); + bl = Math.sqrt(Math.pow(gradient.x1 - gradient.cx, 2) + Math.pow(gradient.cy, 2)); + gradient.rx = gradient.ry = Math.min(tl, tr, br, bl); + break; + case 'farthest-side': + if(m2[0] === 'circle'){ + gradient.rx = gradient.ry = Math.max( + gradient.cx, + gradient.cy, + gradient.x1 - gradient.cx, + gradient.y1 - gradient.cy + ); + } else { // ellipse + + gradient.type = m2[0]; + + gradient.rx = Math.max( + gradient.cx, + gradient.x1 - gradient.cx + ); + gradient.ry = Math.max( + gradient.cy, + gradient.y1 - gradient.cy + ); + } + break; + case 'closest-side': + case 'contain': // is equivalent to closest-side + if(m2[0] === 'circle'){ + gradient.rx = gradient.ry = Math.min( + gradient.cx, + gradient.cy, + gradient.x1 - gradient.cx, + gradient.y1 - gradient.cy + ); + } else { // ellipse + + gradient.type = m2[0]; + + gradient.rx = Math.min( + gradient.cx, + gradient.x1 - gradient.cx + ); + gradient.ry = Math.min( + gradient.cy, + gradient.y1 - gradient.cy + ); + } + break; + + // TODO: add support for "30px 40px" sizes (webkit only) + } + } + + // color stops + m2 = m1[5].match(/((?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\)(?:\s\d{1,3}(?:%|px))?)+/g); + if(m2){ + m2Len = m2.length; + step = 1 / Math.max(m2Len - 1, 1); + for(i = 0; i < m2Len; i+=1){ + m3 = m2[i].match(/((?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\))\s*(\d{1,3})?(%|px)?/); + if(m3[2]){ + stop = parseFloat(m3[2]); + if(m3[3] === '%'){ + stop /= 100; + } else { // px - stupid opera + stop /= bounds.width; + } + } else { + stop = i * step; + } + gradient.colorStops.push({ + color: m3[1], + stop: stop + }); + } + } + break; + } + } + + return gradient; + }; + + _html2canvas.Generate.Gradient = function(src, bounds) { + if(bounds.width === 0 || bounds.height === 0) { + return; + } + + var canvas = document.createElement('canvas'), + ctx = canvas.getContext('2d'), + gradient, grad, i, len; + + canvas.width = bounds.width; + canvas.height = bounds.height; + + // TODO: add support for multi defined background gradients + gradient = _html2canvas.Generate.parseGradient(src, bounds); + + if(gradient) { + if(gradient.type === 'linear') { + grad = ctx.createLinearGradient(gradient.x0, gradient.y0, gradient.x1, gradient.y1); + + for (i = 0, len = gradient.colorStops.length; i < len; i+=1) { + try { + grad.addColorStop(gradient.colorStops[i].stop, gradient.colorStops[i].color); + } + catch(e) { + h2clog(['failed to add color stop: ', e, '; tried to add: ', gradient.colorStops[i], '; stop: ', i, '; in: ', src]); + } + } + + ctx.fillStyle = grad; + ctx.fillRect(0, 0, bounds.width, bounds.height); + + } else if(gradient.type === 'circle') { + + grad = ctx.createRadialGradient(gradient.cx, gradient.cy, 0, gradient.cx, gradient.cy, gradient.rx); + + for (i = 0, len = gradient.colorStops.length; i < len; i+=1) { + try { + grad.addColorStop(gradient.colorStops[i].stop, gradient.colorStops[i].color); + } + catch(e) { + h2clog(['failed to add color stop: ', e, '; tried to add: ', gradient.colorStops[i], '; stop: ', i, '; in: ', src]); + } + } + + ctx.fillStyle = grad; + ctx.fillRect(0, 0, bounds.width, bounds.height); + + } else if(gradient.type === 'ellipse') { + + // draw circle + var canvasRadial = document.createElement('canvas'), + ctxRadial = canvasRadial.getContext('2d'), + ri = Math.max(gradient.rx, gradient.ry), + di = ri * 2, imgRadial; + + canvasRadial.width = canvasRadial.height = di; + + grad = ctxRadial.createRadialGradient(gradient.rx, gradient.ry, 0, gradient.rx, gradient.ry, ri); + + for (i = 0, len = gradient.colorStops.length; i < len; i+=1) { + try { + grad.addColorStop(gradient.colorStops[i].stop, gradient.colorStops[i].color); + } + catch(e) { + h2clog(['failed to add color stop: ', e, '; tried to add: ', gradient.colorStops[i], '; stop: ', i, '; in: ', src]); + } + } + + ctxRadial.fillStyle = grad; + ctxRadial.fillRect(0, 0, di, di); + + ctx.fillStyle = gradient.colorStops[i - 1].color; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.drawImage(canvasRadial, gradient.cx - gradient.rx, gradient.cy - gradient.ry, 2 * gradient.rx, 2 * gradient.ry); + + } + } + + return canvas; + }; + + _html2canvas.Generate.ListAlpha = function(number) { + var tmp = "", + modulus; + + do { + modulus = number % 26; + tmp = String.fromCharCode((modulus) + 64) + tmp; + number = number / 26; + }while((number*26) > 26); + + return tmp; + }; + + _html2canvas.Generate.ListRoman = function(number) { + var romanArray = ["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"], + decimal = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1], + roman = "", + v, + len = romanArray.length; + + if (number <= 0 || number >= 4000) { + return number; + } + + for (v=0; v < len; v+=1) { + while (number >= decimal[v]) { + number -= decimal[v]; + roman += romanArray[v]; + } + } + + return roman; + + }; + +})(); +function h2cRenderContext(width, height) { + var storage = []; + return { + storage: storage, + width: width, + height: height, + clip: function() { + storage.push({ + type: "function", + name: "clip", + 'arguments': arguments + }); + }, + translate: function() { + storage.push({ + type: "function", + name: "translate", + 'arguments': arguments + }); + }, + fill: function() { + storage.push({ + type: "function", + name: "fill", + 'arguments': arguments + }); + }, + save: function() { + storage.push({ + type: "function", + name: "save", + 'arguments': arguments + }); + }, + restore: function() { + storage.push({ + type: "function", + name: "restore", + 'arguments': arguments + }); + }, + fillRect: function () { + storage.push({ + type: "function", + name: "fillRect", + 'arguments': arguments + }); + }, + createPattern: function() { + storage.push({ + type: "function", + name: "createPattern", + 'arguments': arguments + }); + }, + drawShape: function() { + + var shape = []; + + storage.push({ + type: "function", + name: "drawShape", + 'arguments': shape + }); + + return { + moveTo: function() { + shape.push({ + name: "moveTo", + 'arguments': arguments + }); + }, + lineTo: function() { + shape.push({ + name: "lineTo", + 'arguments': arguments + }); + }, + arcTo: function() { + shape.push({ + name: "arcTo", + 'arguments': arguments + }); + }, + bezierCurveTo: function() { + shape.push({ + name: "bezierCurveTo", + 'arguments': arguments + }); + }, + quadraticCurveTo: function() { + shape.push({ + name: "quadraticCurveTo", + 'arguments': arguments + }); + } + }; + + }, + drawImage: function () { + storage.push({ + type: "function", + name: "drawImage", + 'arguments': arguments + }); + }, + fillText: function () { + storage.push({ + type: "function", + name: "fillText", + 'arguments': arguments + }); + }, + setVariable: function (variable, value) { + storage.push({ + type: "variable", + name: variable, + 'arguments': value + }); + } + }; +} +_html2canvas.Parse = function (images, options) { + window.scroll(0,0); + + var element = (( options.elements === undefined ) ? document.body : options.elements[0]), // select body by default + numDraws = 0, + doc = element.ownerDocument, + support = _html2canvas.Util.Support(options, doc), + ignoreElementsRegExp = new RegExp("(" + options.ignoreElements + ")"), + body = doc.body, + getCSS = _html2canvas.Util.getCSS, + pseudoHide = "___html2canvas___pseudoelement", + hidePseudoElements = doc.createElement('style'); + + hidePseudoElements.innerHTML = '.' + pseudoHide + '-before:before { content: "" !important; display: none !important; }' + + '.' + pseudoHide + '-after:after { content: "" !important; display: none !important; }'; + + body.appendChild(hidePseudoElements); + + images = images || {}; + + function documentWidth () { + return Math.max( + Math.max(doc.body.scrollWidth, doc.documentElement.scrollWidth), + Math.max(doc.body.offsetWidth, doc.documentElement.offsetWidth), + Math.max(doc.body.clientWidth, doc.documentElement.clientWidth) + ); + } + + function documentHeight () { + return Math.max( + Math.max(doc.body.scrollHeight, doc.documentElement.scrollHeight), + Math.max(doc.body.offsetHeight, doc.documentElement.offsetHeight), + Math.max(doc.body.clientHeight, doc.documentElement.clientHeight) + ); + } + + function getCSSInt(element, attribute) { + var val = parseInt(getCSS(element, attribute), 10); + return (isNaN(val)) ? 0 : val; // borders in old IE are throwing 'medium' for demo.html + } + + function renderRect (ctx, x, y, w, h, bgcolor) { + if (bgcolor !== "transparent"){ + ctx.setVariable("fillStyle", bgcolor); + ctx.fillRect(x, y, w, h); + numDraws+=1; + } + } + + function textTransform (text, transform) { + switch(transform){ + case "lowercase": + return text.toLowerCase(); + case "capitalize": + return text.replace( /(^|\s|:|-|\(|\))([a-z])/g , function (m, p1, p2) { + if (m.length > 0) { + return p1 + p2.toUpperCase(); + } + } ); + case "uppercase": + return text.toUpperCase(); + default: + return text; + } + } + + function noLetterSpacing(letter_spacing) { + return (/^(normal|none|0px)$/.test(letter_spacing)); + } + + function drawText(currentText, x, y, ctx){ + if (currentText !== null && _html2canvas.Util.trimText(currentText).length > 0) { + ctx.fillText(currentText, x, y); + numDraws+=1; + } + } + + function setTextVariables(ctx, el, text_decoration, color) { + var align = false, + bold = getCSS(el, "fontWeight"), + family = getCSS(el, "fontFamily"), + size = getCSS(el, "fontSize"); + + switch(parseInt(bold, 10)){ + case 401: + bold = "bold"; + break; + case 400: + bold = "normal"; + break; + } + + ctx.setVariable("fillStyle", color); + ctx.setVariable("font", [getCSS(el, "fontStyle"), getCSS(el, "fontVariant"), bold, size, family].join(" ")); + ctx.setVariable("textAlign", (align) ? "right" : "left"); + + if (text_decoration !== "none"){ + return _html2canvas.Util.Font(family, size, doc); + } + } + + function renderTextDecoration(ctx, text_decoration, bounds, metrics, color) { + switch(text_decoration) { + case "underline": + // Draws a line at the baseline of the font + // TODO As some browsers display the line as more than 1px if the font-size is big, need to take that into account both in position and size + renderRect(ctx, bounds.left, Math.round(bounds.top + metrics.baseline + metrics.lineWidth), bounds.width, 1, color); + break; + case "overline": + renderRect(ctx, bounds.left, Math.round(bounds.top), bounds.width, 1, color); + break; + case "line-through": + // TODO try and find exact position for line-through + renderRect(ctx, bounds.left, Math.ceil(bounds.top + metrics.middle + metrics.lineWidth), bounds.width, 1, color); + break; + } + } + + function getTextBounds(state, text, textDecoration, isLast) { + var bounds; + if (support.rangeBounds) { + if (textDecoration !== "none" || _html2canvas.Util.trimText(text).length !== 0) { + bounds = textRangeBounds(text, state.node, state.textOffset); + } + state.textOffset += text.length; + } else if (state.node && typeof state.node.nodeValue === "string" ){ + var newTextNode = (isLast) ? state.node.splitText(text.length) : null; + bounds = textWrapperBounds(state.node); + state.node = newTextNode; + } + return bounds; + } + + function textRangeBounds(text, textNode, textOffset) { + var range = doc.createRange(); + range.setStart(textNode, textOffset); + range.setEnd(textNode, textOffset + text.length); + return range.getBoundingClientRect(); + } + + function textWrapperBounds(oldTextNode) { + var parent = oldTextNode.parentNode, + wrapElement = doc.createElement('wrapper'), + backupText = oldTextNode.cloneNode(true); + + wrapElement.appendChild(oldTextNode.cloneNode(true)); + parent.replaceChild(wrapElement, oldTextNode); + + var bounds = _html2canvas.Util.Bounds(wrapElement); + parent.replaceChild(backupText, wrapElement); + return bounds; + } + + function renderText(el, textNode, stack) { + var ctx = stack.ctx, + color = getCSS(el, "color"), + textDecoration = getCSS(el, "textDecoration"), + textAlign = getCSS(el, "textAlign"), + metrics, + textList, + state = { + node: textNode, + textOffset: 0 + }; + + if (_html2canvas.Util.trimText(textNode.nodeValue).length > 0) { + textNode.nodeValue = textTransform(textNode.nodeValue, getCSS(el, "textTransform")); + textAlign = textAlign.replace(["-webkit-auto"],["auto"]); + + textList = (!options.letterRendering && /^(left|right|justify|auto)$/.test(textAlign) && noLetterSpacing(getCSS(el, "letterSpacing"))) ? + textNode.nodeValue.split(/(\b| )/) + : textNode.nodeValue.split(""); + + metrics = setTextVariables(ctx, el, textDecoration, color); + + if (options.chinese) { + textList.forEach(function(word, index) { + if (/.*[\u4E00-\u9FA5].*$/.test(word)) { + word = word.split(""); + word.unshift(index, 1); + textList.splice.apply(textList, word); + } + }); + } + + textList.forEach(function(text, index) { + var bounds = getTextBounds(state, text, textDecoration, (index < textList.length - 1)); + if (bounds) { + drawText(text, bounds.left, bounds.bottom, ctx); + renderTextDecoration(ctx, textDecoration, bounds, metrics, color); + } + }); + } + } + + function listPosition (element, val) { + var boundElement = doc.createElement( "boundelement" ), + originalType, + bounds; + + boundElement.style.display = "inline"; + + originalType = element.style.listStyleType; + element.style.listStyleType = "none"; + + boundElement.appendChild(doc.createTextNode(val)); + + element.insertBefore(boundElement, element.firstChild); + + bounds = _html2canvas.Util.Bounds(boundElement); + element.removeChild(boundElement); + element.style.listStyleType = originalType; + return bounds; + } + + function elementIndex( el ) { + var i = -1, + count = 1, + childs = el.parentNode.childNodes; + + if (el.parentNode) { + while( childs[ ++i ] !== el ) { + if ( childs[ i ].nodeType === 1 ) { + count++; + } + } + return count; + } else { + return -1; + } + } + + function listItemText(element, type) { + var currentIndex = elementIndex(element), + text; + switch(type){ + case "decimal": + text = currentIndex; + break; + case "decimal-leading-zero": + text = (currentIndex.toString().length === 1) ? currentIndex = "0" + currentIndex.toString() : currentIndex.toString(); + break; + case "upper-roman": + text = _html2canvas.Generate.ListRoman( currentIndex ); + break; + case "lower-roman": + text = _html2canvas.Generate.ListRoman( currentIndex ).toLowerCase(); + break; + case "lower-alpha": + text = _html2canvas.Generate.ListAlpha( currentIndex ).toLowerCase(); + break; + case "upper-alpha": + text = _html2canvas.Generate.ListAlpha( currentIndex ); + break; + } + + text += ". "; + return text; + } + + function renderListItem(element, stack, elBounds) { + var x, + text, + ctx = stack.ctx, + type = getCSS(element, "listStyleType"), + listBounds; + + if (/^(decimal|decimal-leading-zero|upper-alpha|upper-latin|upper-roman|lower-alpha|lower-greek|lower-latin|lower-roman)$/i.test(type)) { + text = listItemText(element, type); + listBounds = listPosition(element, text); + setTextVariables(ctx, element, "none", getCSS(element, "color")); + + if (getCSS(element, "listStylePosition") === "inside") { + ctx.setVariable("textAlign", "left"); + x = elBounds.left; + } else { + return; + } + + drawText(text, x, listBounds.bottom, ctx); + } + } + + function loadImage (src){ + var img = images[src]; + if (img && img.succeeded === true) { + return img.img; + } else { + return false; + } + } + + function clipBounds(src, dst){ + var x = Math.max(src.left, dst.left), + y = Math.max(src.top, dst.top), + x2 = Math.min((src.left + src.width), (dst.left + dst.width)), + y2 = Math.min((src.top + src.height), (dst.top + dst.height)); + + return { + left:x, + top:y, + width:x2-x, + height:y2-y + }; + } + + function setZ(zIndex, parentZ){ + // TODO fix static elements overlapping relative/absolute elements under same stack, if they are defined after them + var newContext; + if (!parentZ){ + newContext = h2czContext(0); + return newContext; + } + + if (zIndex !== "auto"){ + newContext = h2czContext(zIndex); + parentZ.children.push(newContext); + return newContext; + + } + + return parentZ; + } + + function renderImage(ctx, element, image, bounds, borders) { + + var paddingLeft = getCSSInt(element, 'paddingLeft'), + paddingTop = getCSSInt(element, 'paddingTop'), + paddingRight = getCSSInt(element, 'paddingRight'), + paddingBottom = getCSSInt(element, 'paddingBottom'); + + drawImage( + ctx, + image, + 0, //sx + 0, //sy + image.width, //sw + image.height, //sh + bounds.left + paddingLeft + borders[3].width, //dx + bounds.top + paddingTop + borders[0].width, // dy + bounds.width - (borders[1].width + borders[3].width + paddingLeft + paddingRight), //dw + bounds.height - (borders[0].width + borders[2].width + paddingTop + paddingBottom) //dh + ); + } + + function getBorderData(element) { + return ["Top", "Right", "Bottom", "Left"].map(function(side) { + return { + width: getCSSInt(element, 'border' + side + 'Width'), + color: getCSS(element, 'border' + side + 'Color') + }; + }); + } + + function getBorderRadiusData(element) { + return ["TopLeft", "TopRight", "BottomRight", "BottomLeft"].map(function(side) { + return getCSS(element, 'border' + side + 'Radius'); + }); + } + + var getCurvePoints = (function(kappa) { + + return function(x, y, r1, r2) { + var ox = (r1) * kappa, // control point offset horizontal + oy = (r2) * kappa, // control point offset vertical + xm = x + r1, // x-middle + ym = y + r2; // y-middle + return { + topLeft: bezierCurve({ + x:x, + y:ym + }, { + x:x, + y:ym - oy + }, { + x:xm - ox, + y:y + }, { + x:xm, + y:y + }), + topRight: bezierCurve({ + x:x, + y:y + }, { + x:x + ox, + y:y + }, { + x:xm, + y:ym - oy + }, { + x:xm, + y:ym + }), + bottomRight: bezierCurve({ + x:xm, + y:y + }, { + x:xm, + y:y + oy + }, { + x:x + ox, + y:ym + }, { + x:x, + y:ym + }), + bottomLeft: bezierCurve({ + x:xm, + y:ym + }, { + x:xm - ox, + y:ym + }, { + x:x, + y:y + oy + }, { + x:x, + y:y + }) + }; + }; + })(4 * ((Math.sqrt(2) - 1) / 3)); + + function bezierCurve(start, startControl, endControl, end) { + + var lerp = function (a, b, t) { + return { + x:a.x + (b.x - a.x) * t, + y:a.y + (b.y - a.y) * t + }; + }; + + return { + start: start, + startControl: startControl, + endControl: endControl, + end: end, + subdivide: function(t) { + var ab = lerp(start, startControl, t), + bc = lerp(startControl, endControl, t), + cd = lerp(endControl, end, t), + abbc = lerp(ab, bc, t), + bccd = lerp(bc, cd, t), + dest = lerp(abbc, bccd, t); + return [bezierCurve(start, ab, abbc, dest), bezierCurve(dest, bccd, cd, end)]; + }, + curveTo: function(borderArgs) { + borderArgs.push(["bezierCurve", startControl.x, startControl.y, endControl.x, endControl.y, end.x, end.y]); + }, + curveToReversed: function(borderArgs) { + borderArgs.push(["bezierCurve", endControl.x, endControl.y, startControl.x, startControl.y, start.x, start.y]); + } + }; + } + + function parseCorner(borderArgs, radius1, radius2, corner1, corner2, x, y) { + if (radius1[0] > 0 || radius1[1] > 0) { + borderArgs.push(["line", corner1[0].start.x, corner1[0].start.y]); + corner1[0].curveTo(borderArgs); + corner1[1].curveTo(borderArgs); + } else { + borderArgs.push(["line", x, y]); + } + + if (radius2[0] > 0 || radius2[1] > 0) { + borderArgs.push(["line", corner2[0].start.x, corner2[0].start.y]); + } + } + + function drawSide(borderData, radius1, radius2, outer1, inner1, outer2, inner2) { + var borderArgs = []; + + if (radius1[0] > 0 || radius1[1] > 0) { + borderArgs.push(["line", outer1[1].start.x, outer1[1].start.y]); + outer1[1].curveTo(borderArgs); + } else { + borderArgs.push([ "line", borderData.c1[0], borderData.c1[1]]); + } + + if (radius2[0] > 0 || radius2[1] > 0) { + borderArgs.push(["line", outer2[0].start.x, outer2[0].start.y]); + outer2[0].curveTo(borderArgs); + borderArgs.push(["line", inner2[0].end.x, inner2[0].end.y]); + inner2[0].curveToReversed(borderArgs); + } else { + borderArgs.push([ "line", borderData.c2[0], borderData.c2[1]]); + borderArgs.push([ "line", borderData.c3[0], borderData.c3[1]]); + } + + if (radius1[0] > 0 || radius1[1] > 0) { + borderArgs.push(["line", inner1[1].end.x, inner1[1].end.y]); + inner1[1].curveToReversed(borderArgs); + } else { + borderArgs.push([ "line", borderData.c4[0], borderData.c4[1]]); + } + + return borderArgs; + } + + function calculateCurvePoints(bounds, borderRadius, borders) { + + var x = bounds.left, + y = bounds.top, + width = bounds.width, + height = bounds.height, + + tlh = borderRadius[0][0], + tlv = borderRadius[0][1], + trh = borderRadius[1][0], + trv = borderRadius[1][1], + brv = borderRadius[2][0], + brh = borderRadius[2][1], + blh = borderRadius[3][0], + blv = borderRadius[3][1], + + topWidth = width - trh, + rightHeight = height - brv, + bottomWidth = width - brh, + leftHeight = height - blv; + + return { + topLeftOuter: getCurvePoints( + x, + y, + tlh, + tlv + ).topLeft.subdivide(0.5), + + topLeftInner: getCurvePoints( + x + borders[3].width, + y + borders[0].width, + Math.max(0, tlh - borders[3].width), + Math.max(0, tlv - borders[0].width) + ).topLeft.subdivide(0.5), + + topRightOuter: getCurvePoints( + x + topWidth, + y, + trh, + trv + ).topRight.subdivide(0.5), + + topRightInner: getCurvePoints( + x + Math.min(topWidth, width + borders[3].width), + y + borders[0].width, + (topWidth > width + borders[3].width) ? 0 :trh - borders[3].width, + trv - borders[0].width + ).topRight.subdivide(0.5), + + bottomRightOuter: getCurvePoints( + x + bottomWidth, + y + rightHeight, + brh, + brv + ).bottomRight.subdivide(0.5), + + bottomRightInner: getCurvePoints( + x + Math.min(bottomWidth, width + borders[3].width), + y + Math.min(rightHeight, height + borders[0].width), + Math.max(0, brh - borders[1].width), + Math.max(0, brv - borders[2].width) + ).bottomRight.subdivide(0.5), + + bottomLeftOuter: getCurvePoints( + x, + y + leftHeight, + blh, + blv + ).bottomLeft.subdivide(0.5), + + bottomLeftInner: getCurvePoints( + x + borders[3].width, + y + leftHeight, + Math.max(0, blh - borders[3].width), + Math.max(0, blv - borders[2].width) + ).bottomLeft.subdivide(0.5) + }; + } + + function getBorderClip(element, borderPoints, borders, radius, bounds) { + var backgroundClip = getCSS(element, 'backgroundClip'), + borderArgs = []; + + switch(backgroundClip) { + case "content-box": + case "padding-box": + parseCorner(borderArgs, radius[0], radius[1], borderPoints.topLeftInner, borderPoints.topRightInner, bounds.left + borders[3].width, bounds.top + borders[0].width); + parseCorner(borderArgs, radius[1], radius[2], borderPoints.topRightInner, borderPoints.bottomRightInner, bounds.left + bounds.width - borders[1].width, bounds.top + borders[0].width); + parseCorner(borderArgs, radius[2], radius[3], borderPoints.bottomRightInner, borderPoints.bottomLeftInner, bounds.left + bounds.width - borders[1].width, bounds.top + bounds.height - borders[2].width); + parseCorner(borderArgs, radius[3], radius[0], borderPoints.bottomLeftInner, borderPoints.topLeftInner, bounds.left + borders[3].width, bounds.top + bounds.height - borders[2].width); + break; + + default: + parseCorner(borderArgs, radius[0], radius[1], borderPoints.topLeftOuter, borderPoints.topRightOuter, bounds.left, bounds.top); + parseCorner(borderArgs, radius[1], radius[2], borderPoints.topRightOuter, borderPoints.bottomRightOuter, bounds.left + bounds.width, bounds.top); + parseCorner(borderArgs, radius[2], radius[3], borderPoints.bottomRightOuter, borderPoints.bottomLeftOuter, bounds.left + bounds.width, bounds.top + bounds.height); + parseCorner(borderArgs, radius[3], radius[0], borderPoints.bottomLeftOuter, borderPoints.topLeftOuter, bounds.left, bounds.top + bounds.height); + break; + } + + return borderArgs; + } + + function parseBorders(element, bounds, borders){ + var x = bounds.left, + y = bounds.top, + width = bounds.width, + height = bounds.height, + borderSide, + bx, + by, + bw, + bh, + borderArgs, + // http://www.w3.org/TR/css3-background/#the-border-radius + borderRadius = getBorderRadiusData(element), + borderPoints = calculateCurvePoints(bounds, borderRadius, borders), + borderData = { + clip: getBorderClip(element, borderPoints, borders, borderRadius, bounds), + borders: [] + }; + + for (borderSide = 0; borderSide < 4; borderSide++) { + + if (borders[borderSide].width > 0) { + bx = x; + by = y; + bw = width; + bh = height - (borders[2].width); + + switch(borderSide) { + case 0: + // top border + bh = borders[0].width; + + borderArgs = drawSide({ + c1: [bx, by], + c2: [bx + bw, by], + c3: [bx + bw - borders[1].width, by + bh], + c4: [bx + borders[3].width, by + bh] + }, borderRadius[0], borderRadius[1], + borderPoints.topLeftOuter, borderPoints.topLeftInner, borderPoints.topRightOuter, borderPoints.topRightInner); + break; + case 1: + // right border + bx = x + width - (borders[1].width); + bw = borders[1].width; + + borderArgs = drawSide({ + c1: [bx + bw, by], + c2: [bx + bw, by + bh + borders[2].width], + c3: [bx, by + bh], + c4: [bx, by + borders[0].width] + }, borderRadius[1], borderRadius[2], + borderPoints.topRightOuter, borderPoints.topRightInner, borderPoints.bottomRightOuter, borderPoints.bottomRightInner); + break; + case 2: + // bottom border + by = (by + height) - (borders[2].width); + bh = borders[2].width; + + borderArgs = drawSide({ + c1: [bx + bw, by + bh], + c2: [bx, by + bh], + c3: [bx + borders[3].width, by], + c4: [bx + bw - borders[2].width, by] + }, borderRadius[2], borderRadius[3], + borderPoints.bottomRightOuter, borderPoints.bottomRightInner, borderPoints.bottomLeftOuter, borderPoints.bottomLeftInner); + break; + case 3: + // left border + bw = borders[3].width; + + borderArgs = drawSide({ + c1: [bx, by + bh + borders[2].width], + c2: [bx, by], + c3: [bx + bw, by + borders[0].width], + c4: [bx + bw, by + bh] + }, borderRadius[3], borderRadius[0], + borderPoints.bottomLeftOuter, borderPoints.bottomLeftInner, borderPoints.topLeftOuter, borderPoints.topLeftInner); + break; + } + + borderData.borders.push({ + args: borderArgs, + color: borders[borderSide].color + }); + + } + } + + return borderData; + } + + function createShape(ctx, args) { + var shape = ctx.drawShape(); + args.forEach(function(border, index) { + shape[(index === 0) ? "moveTo" : border[0] + "To" ].apply(null, border.slice(1)); + }); + return shape; + } + + function renderBorders(ctx, borderArgs, color) { + if (color !== "transparent") { + ctx.setVariable( "fillStyle", color); + createShape(ctx, borderArgs); + ctx.fill(); + numDraws+=1; + } + } + + function renderFormValue (el, bounds, stack){ + + var valueWrap = doc.createElement('valuewrap'), + cssPropertyArray = ['lineHeight','textAlign','fontFamily','color','fontSize','paddingLeft','paddingTop','width','height','border','borderLeftWidth','borderTopWidth'], + textValue, + textNode; + + cssPropertyArray.forEach(function(property) { + try { + valueWrap.style[property] = getCSS(el, property); + } catch(e) { + // Older IE has issues with "border" + h2clog("html2canvas: Parse: Exception caught in renderFormValue: " + e.message); + } + }); + + valueWrap.style.borderColor = "black"; + valueWrap.style.borderStyle = "solid"; + valueWrap.style.display = "block"; + valueWrap.style.position = "absolute"; + + if (/^(submit|reset|button|text|password)$/.test(el.type) || el.nodeName === "SELECT"){ + valueWrap.style.lineHeight = getCSS(el, "height"); + } + + valueWrap.style.top = bounds.top + "px"; + valueWrap.style.left = bounds.left + "px"; + + textValue = (el.nodeName === "SELECT") ? (el.options[el.selectedIndex] || 0).text : el.value; + if(!textValue) { + textValue = el.placeholder; + } + + textNode = doc.createTextNode(textValue); + + valueWrap.appendChild(textNode); + body.appendChild(valueWrap); + + renderText(el, textNode, stack); + body.removeChild(valueWrap); + } + + function drawImage (ctx) { + ctx.drawImage.apply(ctx, Array.prototype.slice.call(arguments, 1)); + numDraws+=1; + } + + function getPseudoElement(el, which) { + var elStyle = window.getComputedStyle(el, which); + if(!elStyle || !elStyle.content || elStyle.content === "none" || elStyle.content === "-moz-alt-content") { + return; + } + var content = elStyle.content + '', + first = content.substr( 0, 1 ); + //strips quotes + if(first === content.substr( content.length - 1 ) && first.match(/'|"/)) { + content = content.substr( 1, content.length - 2 ); + } + + var isImage = content.substr( 0, 3 ) === 'url', + elps = document.createElement( isImage ? 'img' : 'span' ); + + elps.className = pseudoHide + "-before " + pseudoHide + "-after"; + + Object.keys(elStyle).filter(indexedProperty).forEach(function(prop) { + // Prevent assigning of read only CSS Rules, ex. length, parentRule + try { + elps.style[prop] = elStyle[prop]; + } catch (e) { + h2clog(['Tried to assign readonly property ', prop, 'Error:', e]); + } + }); + + if(isImage) { + elps.src = _html2canvas.Util.parseBackgroundImage(content)[0].args[0]; + } else { + elps.innerHTML = content; + } + return elps; + } + + function indexedProperty(property) { + return (isNaN(window.parseInt(property, 10))); + } + + function injectPseudoElements(el, stack) { + var before = getPseudoElement(el, ':before'), + after = getPseudoElement(el, ':after'); + if(!before && !after) { + return; + } + + if(before) { + el.className += " " + pseudoHide + "-before"; + el.parentNode.insertBefore(before, el); + parseElement(before, stack, true); + el.parentNode.removeChild(before); + el.className = el.className.replace(pseudoHide + "-before", "").trim(); + } + + if (after) { + el.className += " " + pseudoHide + "-after"; + el.appendChild(after); + parseElement(after, stack, true); + el.removeChild(after); + el.className = el.className.replace(pseudoHide + "-after", "").trim(); + } + + } + + function renderBackgroundRepeat(ctx, image, backgroundPosition, bounds) { + var offsetX = Math.round(bounds.left + backgroundPosition.left), + offsetY = Math.round(bounds.top + backgroundPosition.top); + + ctx.createPattern(image); + ctx.translate(offsetX, offsetY); + ctx.fill(); + ctx.translate(-offsetX, -offsetY); + } + + function backgroundRepeatShape(ctx, image, backgroundPosition, bounds, left, top, width, height) { + var args = []; + args.push(["line", Math.round(left), Math.round(top)]); + args.push(["line", Math.round(left + width), Math.round(top)]); + args.push(["line", Math.round(left + width), Math.round(height + top)]); + args.push(["line", Math.round(left), Math.round(height + top)]); + createShape(ctx, args); + ctx.save(); + ctx.clip(); + renderBackgroundRepeat(ctx, image, backgroundPosition, bounds); + ctx.restore(); + } + + function renderBackgroundColor(ctx, backgroundBounds, bgcolor) { + renderRect( + ctx, + backgroundBounds.left, + backgroundBounds.top, + backgroundBounds.width, + backgroundBounds.height, + bgcolor + ); + } + + function renderBackgroundRepeating(el, bounds, ctx, image, imageIndex) { + var backgroundSize = _html2canvas.Util.BackgroundSize(el, bounds, image, imageIndex), + backgroundPosition = _html2canvas.Util.BackgroundPosition(el, bounds, image, imageIndex, backgroundSize), + backgroundRepeat = getCSS(el, "backgroundRepeat").split(",").map(function(value) { + return value.trim(); + }); + + image = resizeImage(image, backgroundSize); + + backgroundRepeat = backgroundRepeat[imageIndex] || backgroundRepeat[0]; + + switch (backgroundRepeat) { + case "repeat-x": + backgroundRepeatShape(ctx, image, backgroundPosition, bounds, + bounds.left, bounds.top + backgroundPosition.top, 99999, image.height); + break; + + case "repeat-y": + backgroundRepeatShape(ctx, image, backgroundPosition, bounds, + bounds.left + backgroundPosition.left, bounds.top, image.width, 99999); + break; + + case "no-repeat": + backgroundRepeatShape(ctx, image, backgroundPosition, bounds, + bounds.left + backgroundPosition.left, bounds.top + backgroundPosition.top, image.width, image.height); + break; + + default: + renderBackgroundRepeat(ctx, image, backgroundPosition, { + top: bounds.top, + left: bounds.left, + width: image.width, + height: image.height + }); + break; + } + } + + function renderBackgroundImage(element, bounds, ctx) { + var backgroundImage = getCSS(element, "backgroundImage"), + backgroundImages = _html2canvas.Util.parseBackgroundImage(backgroundImage), + image, + imageIndex = backgroundImages.length; + + while(imageIndex--) { + backgroundImage = backgroundImages[imageIndex]; + + if (!backgroundImage.args || backgroundImage.args.length === 0) { + continue; + } + + var key = backgroundImage.method === 'url' ? + backgroundImage.args[0] : + backgroundImage.value; + + image = loadImage(key); + + // TODO add support for background-origin + if (image) { + renderBackgroundRepeating(element, bounds, ctx, image, imageIndex); + } else { + h2clog("html2canvas: Error loading background:", backgroundImage); + } + } + } + + function resizeImage(image, bounds) { + if(image.width === bounds.width && image.height === bounds.height) { + return image; + } + + var ctx, canvas = doc.createElement('canvas'); + canvas.width = bounds.width; + canvas.height = bounds.height; + ctx = canvas.getContext("2d"); + drawImage(ctx, image, 0, 0, image.width, image.height, 0, 0, bounds.width, bounds.height ); + return canvas; + } + + function setOpacity(ctx, element, parentStack) { + var opacity = getCSS(element, "opacity") * ((parentStack) ? parentStack.opacity : 1); + ctx.setVariable("globalAlpha", opacity); + return opacity; + } + + function createStack(element, parentStack, bounds) { + + var ctx = h2cRenderContext((!parentStack) ? documentWidth() : bounds.width , (!parentStack) ? documentHeight() : bounds.height), + stack = { + ctx: ctx, + zIndex: setZ(getCSS(element, "zIndex"), (parentStack) ? parentStack.zIndex : null), + opacity: setOpacity(ctx, element, parentStack), + cssPosition: getCSS(element, "position"), + borders: getBorderData(element), + clip: (parentStack && parentStack.clip) ? _html2canvas.Util.Extend( {}, parentStack.clip ) : null + }; + + // TODO correct overflow for absolute content residing under a static position + if (options.useOverflow === true && /(hidden|scroll|auto)/.test(getCSS(element, "overflow")) === true && /(BODY)/i.test(element.nodeName) === false){ + stack.clip = (stack.clip) ? clipBounds(stack.clip, bounds) : bounds; + } + + stack.zIndex.children.push(stack); + + return stack; + } + + function getBackgroundBounds(borders, bounds, clip) { + var backgroundBounds = { + left: bounds.left + borders[3].width, + top: bounds.top + borders[0].width, + width: bounds.width - (borders[1].width + borders[3].width), + height: bounds.height - (borders[0].width + borders[2].width) + }; + + if (clip) { + backgroundBounds = clipBounds(backgroundBounds, clip); + } + + return backgroundBounds; + } + + function renderElement(element, parentStack, pseudoElement){ + var bounds = _html2canvas.Util.Bounds(element), + image, + bgcolor = (ignoreElementsRegExp.test(element.nodeName)) ? "#efefef" : getCSS(element, "backgroundColor"), + stack = createStack(element, parentStack, bounds), + borders = stack.borders, + ctx = stack.ctx, + backgroundBounds = getBackgroundBounds(borders, bounds, stack.clip), + borderData = parseBorders(element, bounds, borders); + + createShape(ctx, borderData.clip); + + ctx.save(); + ctx.clip(); + + if (backgroundBounds.height > 0 && backgroundBounds.width > 0){ + renderBackgroundColor(ctx, bounds, bgcolor); + renderBackgroundImage(element, backgroundBounds, ctx); + } + + ctx.restore(); + + borderData.borders.forEach(function(border) { + renderBorders(ctx, border.args, border.color); + }); + + if (!pseudoElement) { + injectPseudoElements(element, stack); + } + + switch(element.nodeName){ + case "IMG": + if ((image = loadImage(element.getAttribute('src')))) { + renderImage(ctx, element, image, bounds, borders); + } else { + h2clog("html2canvas: Error loading :" + element.getAttribute('src')); + } + break; + case "INPUT": + // TODO add all relevant type's, i.e. HTML5 new stuff + // todo add support for placeholder attribute for browsers which support it + if (/^(text|url|email|submit|button|reset)$/.test(element.type) && (element.value || element.placeholder).length > 0){ + renderFormValue(element, bounds, stack); + } + break; + case "TEXTAREA": + if ((element.value || element.placeholder || "").length > 0){ + renderFormValue(element, bounds, stack); + } + break; + case "SELECT": + if ((element.options||element.placeholder || "").length > 0){ + renderFormValue(element, bounds, stack); + } + break; + case "LI": + renderListItem(element, stack, backgroundBounds); + break; + case "CANVAS": + renderImage(ctx, element, element, bounds, borders); + break; + } + + return stack; + } + + function isElementVisible(element) { + return (getCSS(element, 'display') !== "none" && getCSS(element, 'visibility') !== "hidden" && !element.hasAttribute("data-html2canvas-ignore")); + } + + function parseElement (el, stack, pseudoElement) { + + if (isElementVisible(el)) { + stack = renderElement(el, stack, pseudoElement) || stack; + if (!ignoreElementsRegExp.test(el.nodeName)) { + _html2canvas.Util.Children(el).forEach(function(node) { + if (node.nodeType === 1) { + parseElement(node, stack, pseudoElement); + } else if (node.nodeType === 3) { + renderText(el, node, stack); + } + }); + } + } + } + + function svgDOMRender(body, stack) { + var img = new Image(), + docWidth = documentWidth(), + docHeight = documentHeight(), + html = ""; + + function parseDOM(el) { + var children = _html2canvas.Util.Children( el ), + len = children.length, + attr, + a, + alen, + elm, + i; + for ( i = 0; i < len; i+=1 ) { + elm = children[ i ]; + if ( elm.nodeType === 3 ) { + // Text node + html += elm.nodeValue.replace(//g,">"); + } else if ( elm.nodeType === 1 ) { + // Element + if ( !/^(script|meta|title)$/.test(elm.nodeName.toLowerCase()) ) { + + html += "<" + elm.nodeName.toLowerCase(); + + // add attributes + if ( elm.hasAttributes() ) { + attr = elm.attributes; + alen = attr.length; + for ( a = 0; a < alen; a+=1 ) { + html += " " + attr[ a ].name + '="' + attr[ a ].value + '"'; + } + } + + + html += '>'; + + parseDOM( elm ); + + + html += ""; + } + } + + } + + } + + parseDOM(body); + img.src = [ + "data:image/svg+xml,", + "", + "", + "", + html.replace(/\#/g,"%23"), + "", + "", + "" + ].join(""); + + img.onload = function() { + stack.svgRender = img; + }; + + } + + function init() { + var stack = renderElement(element, null); + + if (support.svgRendering) { + svgDOMRender(document.documentElement, stack); + } + + Array.prototype.slice.call(element.children, 0).forEach(function(childElement) { + parseElement(childElement, stack); + }); + + stack.backgroundColor = getCSS(document.documentElement, "backgroundColor"); + body.removeChild(hidePseudoElements); + return stack; + } + + return init(); +}; + +function h2czContext(zindex) { + return { + zindex: zindex, + children: [] + }; +} +_html2canvas.Preload = function( options ) { + + var images = { + numLoaded: 0, // also failed are counted here + numFailed: 0, + numTotal: 0, + cleanupDone: false + }, + pageOrigin, + methods, + i, + count = 0, + element = options.elements[0] || document.body, + doc = element.ownerDocument, + domImages = doc.images, // TODO probably should limit it to images present in the element only + imgLen = domImages.length, + link = doc.createElement("a"), + supportCORS = (function( img ){ + return (img.crossOrigin !== undefined); + })(new Image()), + timeoutTimer; + + link.href = window.location.href; + pageOrigin = link.protocol + link.host; + + function isSameOrigin(url){ + link.href = url; + link.href = link.href; // YES, BELIEVE IT OR NOT, that is required for IE9 - http://jsfiddle.net/niklasvh/2e48b/ + var origin = link.protocol + link.host; + return (origin === pageOrigin); + } + + function start(){ + h2clog("html2canvas: start: images: " + images.numLoaded + " / " + images.numTotal + " (failed: " + images.numFailed + ")"); + if (!images.firstRun && images.numLoaded >= images.numTotal){ + h2clog("Finished loading images: # " + images.numTotal + " (failed: " + images.numFailed + ")"); + + if (typeof options.complete === "function"){ + options.complete(images); + } + + } + } + + // TODO modify proxy to serve images with CORS enabled, where available + function proxyGetImage(url, img, imageObj){ + var callback_name, + scriptUrl = options.proxy, + script; + + link.href = url; + url = link.href; // work around for pages with base href="" set - WARNING: this may change the url + + callback_name = 'html2canvas_' + (count++); + imageObj.callbackname = callback_name; + + if (scriptUrl.indexOf("?") > -1) { + scriptUrl += "&"; + } else { + scriptUrl += "?"; + } + scriptUrl += 'url=' + encodeURIComponent(url) + '&callback=' + callback_name; + script = doc.createElement("script"); + + window[callback_name] = function(a){ + if (a.substring(0,6) === "error:"){ + imageObj.succeeded = false; + images.numLoaded++; + images.numFailed++; + start(); + } else { + setImageLoadHandlers(img, imageObj); + img.src = a; + } + window[callback_name] = undefined; // to work with IE<9 // NOTE: that the undefined callback property-name still exists on the window object (for IE<9) + try { + delete window[callback_name]; // for all browser that support this + } catch(ex) {} + script.parentNode.removeChild(script); + script = null; + delete imageObj.script; + delete imageObj.callbackname; + }; + + script.setAttribute("type", "text/javascript"); + script.setAttribute("src", scriptUrl); + imageObj.script = script; + window.document.body.appendChild(script); + + } + + function loadPseudoElement(element, type) { + var style = window.getComputedStyle(element, type), + content = style.content; + if (content.substr(0, 3) === 'url') { + methods.loadImage(_html2canvas.Util.parseBackgroundImage(content)[0].args[0]); + } + loadBackgroundImages(style.backgroundImage, element); + } + + function loadPseudoElementImages(element) { + loadPseudoElement(element, ":before"); + loadPseudoElement(element, ":after"); + } + + function loadGradientImage(backgroundImage, bounds) { + var img = _html2canvas.Generate.Gradient(backgroundImage, bounds); + + if (img !== undefined){ + images[backgroundImage] = { + img: img, + succeeded: true + }; + images.numTotal++; + images.numLoaded++; + start(); + } + } + + function invalidBackgrounds(background_image) { + return (background_image && background_image.method && background_image.args && background_image.args.length > 0 ); + } + + function loadBackgroundImages(background_image, el) { + var bounds; + + _html2canvas.Util.parseBackgroundImage(background_image).filter(invalidBackgrounds).forEach(function(background_image) { + if (background_image.method === 'url') { + methods.loadImage(background_image.args[0]); + } else if(background_image.method.match(/\-?gradient$/)) { + if(bounds === undefined) { + bounds = _html2canvas.Util.Bounds(el); + } + loadGradientImage(background_image.value, bounds); + } + }); + } + + function getImages (el) { + var elNodeType = false; + + // Firefox fails with permission denied on pages with iframes + try { + _html2canvas.Util.Children(el).forEach(function(img) { + getImages(img); + }); + } + catch( e ) {} + + try { + elNodeType = el.nodeType; + } catch (ex) { + elNodeType = false; + h2clog("html2canvas: failed to access some element's nodeType - Exception: " + ex.message); + } + + if (elNodeType === 1 || elNodeType === undefined) { + loadPseudoElementImages(el); + try { + loadBackgroundImages(_html2canvas.Util.getCSS(el, 'backgroundImage'), el); + } catch(e) { + h2clog("html2canvas: failed to get background-image - Exception: " + e.message); + } + loadBackgroundImages(el); + } + } + + function setImageLoadHandlers(img, imageObj) { + img.onload = function() { + if ( imageObj.timer !== undefined ) { + // CORS succeeded + window.clearTimeout( imageObj.timer ); + } + + images.numLoaded++; + imageObj.succeeded = true; + img.onerror = img.onload = null; + start(); + }; + img.onerror = function() { + if (img.crossOrigin === "anonymous") { + // CORS failed + window.clearTimeout( imageObj.timer ); + + // let's try with proxy instead + if ( options.proxy ) { + var src = img.src; + img = new Image(); + imageObj.img = img; + img.src = src; + + proxyGetImage( img.src, img, imageObj ); + return; + } + } + + images.numLoaded++; + images.numFailed++; + imageObj.succeeded = false; + img.onerror = img.onload = null; + start(); + }; + } + + methods = { + loadImage: function( src ) { + var img, imageObj; + if ( src && images[src] === undefined ) { + img = new Image(); + if ( src.match(/data:image\/.*;base64,/i) ) { + img.src = src.replace(/url\(['"]{0,}|['"]{0,}\)$/ig, ''); + imageObj = images[src] = { + img: img + }; + images.numTotal++; + setImageLoadHandlers(img, imageObj); + } else if ( isSameOrigin( src ) || options.allowTaint === true ) { + imageObj = images[src] = { + img: img + }; + images.numTotal++; + setImageLoadHandlers(img, imageObj); + img.src = src; + } else if ( supportCORS && !options.allowTaint && options.useCORS ) { + // attempt to load with CORS + + img.crossOrigin = "anonymous"; + imageObj = images[src] = { + img: img + }; + images.numTotal++; + setImageLoadHandlers(img, imageObj); + img.src = src; + + // work around for https://bugs.webkit.org/show_bug.cgi?id=80028 + img.customComplete = function () { + if (!this.img.complete) { + this.timer = window.setTimeout(this.img.customComplete, 100); + } else { + this.img.onerror(); + } + }.bind(imageObj); + img.customComplete(); + + } else if ( options.proxy ) { + imageObj = images[src] = { + img: img + }; + images.numTotal++; + proxyGetImage( src, img, imageObj ); + } + } + + }, + cleanupDOM: function(cause) { + var img, src; + if (!images.cleanupDone) { + if (cause && typeof cause === "string") { + h2clog("html2canvas: Cleanup because: " + cause); + } else { + h2clog("html2canvas: Cleanup after timeout: " + options.timeout + " ms."); + } + + for (src in images) { + if (images.hasOwnProperty(src)) { + img = images[src]; + if (typeof img === "object" && img.callbackname && img.succeeded === undefined) { + // cancel proxy image request + window[img.callbackname] = undefined; // to work with IE<9 // NOTE: that the undefined callback property-name still exists on the window object (for IE<9) + try { + delete window[img.callbackname]; // for all browser that support this + } catch(ex) {} + if (img.script && img.script.parentNode) { + img.script.setAttribute("src", "about:blank"); // try to cancel running request + img.script.parentNode.removeChild(img.script); + } + images.numLoaded++; + images.numFailed++; + h2clog("html2canvas: Cleaned up failed img: '" + src + "' Steps: " + images.numLoaded + " / " + images.numTotal); + } + } + } + + // cancel any pending requests + if(window.stop !== undefined) { + window.stop(); + } else if(document.execCommand !== undefined) { + document.execCommand("Stop", false); + } + if (document.close !== undefined) { + document.close(); + } + images.cleanupDone = true; + if (!(cause && typeof cause === "string")) { + start(); + } + } + }, + + renderingDone: function() { + if (timeoutTimer) { + window.clearTimeout(timeoutTimer); + } + } + }; + + if (options.timeout > 0) { + timeoutTimer = window.setTimeout(methods.cleanupDOM, options.timeout); + } + + h2clog('html2canvas: Preload starts: finding background-images'); + images.firstRun = true; + + getImages(element); + + h2clog('html2canvas: Preload: Finding images'); + // load images + for (i = 0; i < imgLen; i+=1){ + methods.loadImage( domImages[i].getAttribute( "src" ) ); + } + + images.firstRun = false; + h2clog('html2canvas: Preload: Done.'); + if ( images.numTotal === images.numLoaded ) { + start(); + } + + return methods; + +}; +_html2canvas.Renderer = function(parseQueue, options){ + + function createRenderQueue(parseQueue) { + var queue = []; + + var sortZ = function(zStack){ + var subStacks = [], + stackValues = []; + + zStack.children.forEach(function(stackChild) { + if (stackChild.children && stackChild.children.length > 0){ + subStacks.push(stackChild); + stackValues.push(stackChild.zindex); + } else { + queue.push(stackChild); + } + }); + + stackValues.sort(function(a, b) { + return a - b; + }); + + stackValues.forEach(function(zValue) { + var index; + + subStacks.some(function(stack, i){ + index = i; + return (stack.zindex === zValue); + }); + sortZ(subStacks.splice(index, 1)[0]); + + }); + }; + + sortZ(parseQueue.zIndex); + + return queue; + } + + function getRenderer(rendererName) { + var renderer; + + if (typeof options.renderer === "string" && _html2canvas.Renderer[rendererName] !== undefined) { + renderer = _html2canvas.Renderer[rendererName](options); + } else if (typeof rendererName === "function") { + renderer = rendererName(options); + } else { + throw new Error("Unknown renderer"); + } + + if ( typeof renderer !== "function" ) { + throw new Error("Invalid renderer defined"); + } + return renderer; + } + + return getRenderer(options.renderer)(parseQueue, options, document, createRenderQueue(parseQueue), _html2canvas); +}; + +_html2canvas.Util.Support = function (options, doc) { + + function supportSVGRendering() { + var img = new Image(), + canvas = doc.createElement("canvas"), + ctx = (canvas.getContext === undefined) ? false : canvas.getContext("2d"); + if (ctx === false) { + return false; + } + canvas.width = canvas.height = 10; + img.src = [ + "data:image/svg+xml,", + "", + "", + "
      ", + "sup", + "
      ", + "
      ", + "
      " + ].join(""); + try { + ctx.drawImage(img, 0, 0); + canvas.toDataURL(); + } catch(e) { + return false; + } + h2clog('html2canvas: Parse: SVG powered rendering available'); + return true; + } + + // Test whether we can use ranges to measure bounding boxes + // Opera doesn't provide valid bounds.height/bottom even though it supports the method. + + function supportRangeBounds() { + var r, testElement, rangeBounds, rangeHeight, support = false; + + if (doc.createRange) { + r = doc.createRange(); + if (r.getBoundingClientRect) { + testElement = doc.createElement('boundtest'); + testElement.style.height = "123px"; + testElement.style.display = "block"; + doc.body.appendChild(testElement); + + r.selectNode(testElement); + rangeBounds = r.getBoundingClientRect(); + rangeHeight = rangeBounds.height; + + if (rangeHeight === 123) { + support = true; + } + doc.body.removeChild(testElement); + } + } + + return support; + } + + return { + rangeBounds: supportRangeBounds(), + svgRendering: options.svgRendering && supportSVGRendering() + }; +}; +window.html2canvas = function(elements, opts) { + elements = (elements.length) ? elements : [elements]; + var queue, + canvas, + options = { + // general + logging: false, + elements: elements, + background: "#fff", + + // preload options + proxy: null, + timeout: 0, // no timeout + useCORS: false, // try to load images as CORS (where available), before falling back to proxy + allowTaint: false, // whether to allow images to taint the canvas, won't need proxy if set to true + + // parse options + svgRendering: false, // use svg powered rendering where available (FF11+) + ignoreElements: "IFRAME|OBJECT|PARAM", + useOverflow: true, + letterRendering: false, + chinese: false, + + // render options + + width: null, + height: null, + taintTest: true, // do a taint test with all images before applying to canvas + renderer: "Canvas" + }; + + options = _html2canvas.Util.Extend(opts, options); + + _html2canvas.logging = options.logging; + options.complete = function( images ) { + + if (typeof options.onpreloaded === "function") { + if ( options.onpreloaded( images ) === false ) { + return; + } + } + queue = _html2canvas.Parse( images, options ); + + if (typeof options.onparsed === "function") { + if ( options.onparsed( queue ) === false ) { + return; + } + } + + canvas = _html2canvas.Renderer( queue, options ); + + if (typeof options.onrendered === "function") { + options.onrendered( canvas ); + } + + + }; + + // for pages without images, we still want this to be async, i.e. return methods before executing + window.setTimeout( function(){ + _html2canvas.Preload( options ); + }, 0 ); + + return { + render: function( queue, opts ) { + return _html2canvas.Renderer( queue, _html2canvas.Util.Extend(opts, options) ); + }, + parse: function( images, opts ) { + return _html2canvas.Parse( images, _html2canvas.Util.Extend(opts, options) ); + }, + preload: function( opts ) { + return _html2canvas.Preload( _html2canvas.Util.Extend(opts, options) ); + }, + log: h2clog + }; +}; + +window.html2canvas.log = h2clog; // for renderers +window.html2canvas.Renderer = { + Canvas: undefined // We are assuming this will be used +}; +_html2canvas.Renderer.Canvas = function(options) { + + options = options || {}; + + var doc = document, + safeImages = [], + testCanvas = document.createElement("canvas"), + testctx = testCanvas.getContext("2d"), + canvas = options.canvas || doc.createElement('canvas'); + + + function createShape(ctx, args) { + ctx.beginPath(); + args.forEach(function(arg) { + ctx[arg.name].apply(ctx, arg['arguments']); + }); + ctx.closePath(); + } + + function safeImage(item) { + if (safeImages.indexOf(item['arguments'][0].src ) === -1) { + testctx.drawImage(item['arguments'][0], 0, 0); + try { + testctx.getImageData(0, 0, 1, 1); + } catch(e) { + testCanvas = doc.createElement("canvas"); + testctx = testCanvas.getContext("2d"); + return false; + } + safeImages.push(item['arguments'][0].src); + } + return true; + } + + function isTransparent(backgroundColor) { + return (backgroundColor === "transparent" || backgroundColor === "rgba(0, 0, 0, 0)"); + } + + function renderItem(ctx, item) { + switch(item.type){ + case "variable": + ctx[item.name] = item['arguments']; + break; + case "function": + if (item.name === "createPattern") { + if (item['arguments'][0].width > 0 && item['arguments'][0].height > 0) { + try { + ctx.fillStyle = ctx.createPattern(item['arguments'][0], "repeat"); + } + catch(e) { + h2clog("html2canvas: Renderer: Error creating pattern", e.message); + } + } + } else if (item.name === "drawShape") { + createShape(ctx, item['arguments']); + } else if (item.name === "drawImage") { + if (item['arguments'][8] > 0 && item['arguments'][7] > 0) { + if (!options.taintTest || (options.taintTest && safeImage(item))) { + ctx.drawImage.apply( ctx, item['arguments'] ); + } + } + } else { + ctx[item.name].apply(ctx, item['arguments']); + } + break; + } + } + + return function(zStack, options, doc, queue, _html2canvas) { + + var ctx = canvas.getContext("2d"), + storageContext, + i, + queueLen, + newCanvas, + bounds, + fstyle; + + canvas.width = canvas.style.width = options.width || zStack.ctx.width; + canvas.height = canvas.style.height = options.height || zStack.ctx.height; + + fstyle = ctx.fillStyle; + ctx.fillStyle = (isTransparent(zStack.backgroundColor) && options.background !== undefined) ? options.background : zStack.backgroundColor; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.fillStyle = fstyle; + + + if ( options.svgRendering && zStack.svgRender !== undefined ) { + // TODO: enable async rendering to support this + ctx.drawImage( zStack.svgRender, 0, 0 ); + } else { + for ( i = 0, queueLen = queue.length; i < queueLen; i+=1 ) { + storageContext = queue.splice(0, 1)[0]; + storageContext.canvasPosition = storageContext.canvasPosition || {}; + + // set common settings for canvas + ctx.textBaseline = "bottom"; + + if (storageContext.clip){ + ctx.save(); + ctx.beginPath(); + // console.log(storageContext); + ctx.rect(storageContext.clip.left, storageContext.clip.top, storageContext.clip.width, storageContext.clip.height); + ctx.clip(); + } + + if (storageContext.ctx.storage) { + storageContext.ctx.storage.forEach(renderItem.bind(null, ctx)); + } + + if (storageContext.clip){ + ctx.restore(); + } + } + } + + h2clog("html2canvas: Renderer: Canvas renderer done - returning canvas obj"); + + queueLen = options.elements.length; + + if (queueLen === 1) { + if (typeof options.elements[0] === "object" && options.elements[0].nodeName !== "BODY") { + // crop image to the bounds of selected (single) element + bounds = _html2canvas.Util.Bounds(options.elements[0]); + newCanvas = doc.createElement('canvas'); + newCanvas.width = bounds.width; + newCanvas.height = bounds.height; + ctx = newCanvas.getContext("2d"); + + ctx.drawImage(canvas, bounds.left, bounds.top, bounds.width, bounds.height, 0, 0, bounds.width, bounds.height); + canvas = null; + return newCanvas; + } + } + + return canvas; + }; +}; +})(window,document); \ No newline at end of file diff --git a/plugins/c9.vfs.standalone/www/install.html b/plugins/c9.vfs.standalone/www/install.html new file mode 100644 index 00000000..d7e3dce9 --- /dev/null +++ b/plugins/c9.vfs.standalone/www/install.html @@ -0,0 +1,43 @@ + + + + + Cloud9 Installer + + + + + + + diff --git a/plugins/c9.vfs.standalone/www/packed.html b/plugins/c9.vfs.standalone/www/packed.html new file mode 100644 index 00000000..e5aa5fc4 --- /dev/null +++ b/plugins/c9.vfs.standalone/www/packed.html @@ -0,0 +1,37 @@ + + + + + Cloud9 + + + + + + + \ No newline at end of file diff --git a/plugins/c9.vfs.standalone/www/places.html b/plugins/c9.vfs.standalone/www/places.html new file mode 100644 index 00000000..21f72b4e --- /dev/null +++ b/plugins/c9.vfs.standalone/www/places.html @@ -0,0 +1,71 @@ + + + + + Cloud9 hub + + + + + + \ No newline at end of file diff --git a/plugins/c9.vfs.standalone/www/require.js b/plugins/c9.vfs.standalone/www/require.js new file mode 100644 index 00000000..46aac2dd --- /dev/null +++ b/plugins/c9.vfs.standalone/www/require.js @@ -0,0 +1,1999 @@ +/** vim: et:ts=4:sw=4:sts=4 + * @license RequireJS 2.1.4 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ +//Not using strict: uneven strict support in browsers, #392, and causes +//problems with requirejs.exec()/transpiler plugins that may not be strict. +/*jslint regexp: true, nomen: true, sloppy: true */ +/*global window, navigator, document, importScripts, setTimeout, opera */ + +var requirejs, require, define; +(function (global) { + var req, s, head, baseElement, dataMain, src, + interactiveScript, currentlyAddingScript, mainScript, subPath, + version = '2.1.4', + commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, + cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, + jsSuffixRegExp = /\.js$/, + currDirRegExp = /^\.\//, + op = Object.prototype, + ostring = op.toString, + hasOwn = op.hasOwnProperty, + ap = Array.prototype, + apsp = ap.splice, + isBrowser = !!(typeof window !== 'undefined' && navigator && document), + isWebWorker = !isBrowser && typeof importScripts !== 'undefined', + //PS3 indicates loaded and complete, but need to wait for complete + //specifically. Sequence is 'loading', 'loaded', execution, + // then 'complete'. The UA check is unfortunate, but not sure how + //to feature test w/o causing perf issues. + readyRegExp = isBrowser && navigator.platform === 'PLAYSTATION 3' ? + /^complete$/ : /^(complete|loaded)$/, + defContextName = '_', + //Oh the tragedy, detecting opera. See the usage of isOpera for reason. + isOpera = typeof opera !== 'undefined' && opera.toString() === '[object Opera]', + contexts = {}, + cfg = {}, + globalDefQueue = [], + useInteractive = false; + + function isFunction(it) { + return ostring.call(it) === '[object Function]'; + } + + function isArray(it) { + return ostring.call(it) === '[object Array]'; + } + + /** + * Helper function for iterating over an array. If the func returns + * a true value, it will break out of the loop. + */ + function each(ary, func) { + if (ary) { + var i; + for (i = 0; i < ary.length; i += 1) { + if (ary[i] && func(ary[i], i, ary)) { + break; + } + } + } + } + + /** + * Helper function for iterating over an array backwards. If the func + * returns a true value, it will break out of the loop. + */ + function eachReverse(ary, func) { + if (ary) { + var i; + for (i = ary.length - 1; i > -1; i -= 1) { + if (ary[i] && func(ary[i], i, ary)) { + break; + } + } + } + } + + function hasProp(obj, prop) { + return hasOwn.call(obj, prop); + } + + function getOwn(obj, prop) { + return hasProp(obj, prop) && obj[prop]; + } + + /** + * Cycles over properties in an object and calls a function for each + * property value. If the function returns a truthy value, then the + * iteration is stopped. + */ + function eachProp(obj, func) { + var prop; + for (prop in obj) { + if (hasProp(obj, prop)) { + if (func(obj[prop], prop)) { + break; + } + } + } + } + + /** + * Simple function to mix in properties from source into target, + * but only if target does not already have a property of the same name. + */ + function mixin(target, source, force, deepStringMixin) { + if (source) { + eachProp(source, function (value, prop) { + if (force || !hasProp(target, prop)) { + if (deepStringMixin && typeof value !== 'string') { + if (!target[prop]) { + target[prop] = {}; + } + mixin(target[prop], value, force, deepStringMixin); + } else { + target[prop] = value; + } + } + }); + } + return target; + } + + //Similar to Function.prototype.bind, but the 'this' object is specified + //first, since it is easier to read/figure out what 'this' will be. + function bind(obj, fn) { + return function () { + return fn.apply(obj, arguments); + }; + } + + function scripts() { + return document.getElementsByTagName('script'); + } + + //Allow getting a global that expressed in + //dot notation, like 'a.b.c'. + function getGlobal(value) { + if (!value) { + return value; + } + var g = global; + each(value.split('.'), function (part) { + g = g[part]; + }); + return g; + } + + /** + * Constructs an error with a pointer to an URL with more information. + * @param {String} id the error ID that maps to an ID on a web page. + * @param {String} message human readable error. + * @param {Error} [err] the original error, if there is one. + * + * @returns {Error} + */ + function makeError(id, msg, err, requireModules) { + var e = new Error(msg + '\nhttp://requirejs.org/docs/errors.html#' + id); + e.requireType = id; + e.requireModules = requireModules; + if (err) { + e.originalError = err; + } + return e; + } + + if (typeof define !== 'undefined') { + //If a define is already in play via another AMD loader, + //do not overwrite. + return; + } + + if (typeof requirejs !== 'undefined') { + if (isFunction(requirejs)) { + //Do not overwrite and existing requirejs instance. + return; + } + cfg = requirejs; + requirejs = undefined; + } + + //Allow for a require config object + if (typeof require !== 'undefined' && !isFunction(require)) { + //assume it is a config object. + cfg = require; + require = undefined; + } + + function newContext(contextName) { + var inCheckLoaded, Module, context, handlers, + checkLoadedTimeoutId, + config = { + waitSeconds: 7, + baseUrl: './', + paths: {}, + pkgs: {}, + shim: {}, + map: {}, + config: {} + }, + registry = {}, + undefEvents = {}, + defQueue = [], + defined = {}, + urlFetched = {}, + requireCounter = 1, + unnormalizedCounter = 1; + + /** + * Trims the . and .. from an array of path segments. + * It will keep a leading path segment if a .. will become + * the first path segment, to help with module name lookups, + * which act like paths, but can be remapped. But the end result, + * all paths that use this function should look normalized. + * NOTE: this method MODIFIES the input array. + * @param {Array} ary the array of path segments. + */ + function trimDots(ary) { + var i, part; + for (i = 0; ary[i]; i += 1) { + part = ary[i]; + if (part === '.') { + ary.splice(i, 1); + i -= 1; + } else if (part === '..') { + if (i === 1 && (ary[2] === '..' || ary[0] === '..')) { + //End of the line. Keep at least one non-dot + //path segment at the front so it can be mapped + //correctly to disk. Otherwise, there is likely + //no path mapping for a path starting with '..'. + //This can still fail, but catches the most reasonable + //uses of .. + break; + } else if (i > 0) { + ary.splice(i - 1, 2); + i -= 2; + } + } + } + } + + /** + * Given a relative module name, like ./something, normalize it to + * a real name that can be mapped to a path. + * @param {String} name the relative name + * @param {String} baseName a real name that the name arg is relative + * to. + * @param {Boolean} applyMap apply the map config to the value. Should + * only be done if this normalization is for a dependency ID. + * @returns {String} normalized name + */ + function normalize(name, baseName, applyMap) { + var pkgName, pkgConfig, mapValue, nameParts, i, j, nameSegment, + foundMap, foundI, foundStarMap, starI, + baseParts = baseName && baseName.split('/'), + normalizedBaseParts = baseParts, + map = config.map, + starMap = map && map['*']; + + //Adjust any relative paths. + if (name && name.charAt(0) === '.') { + //If have a base name, try to normalize against it, + //otherwise, assume it is a top-level require that will + //be relative to baseUrl in the end. + if (baseName) { + if (getOwn(config.pkgs, baseName)) { + //If the baseName is a package name, then just treat it as one + //name to concat the name with. + normalizedBaseParts = baseParts = [baseName]; + } else { + //Convert baseName to array, and lop off the last part, + //so that . matches that 'directory' and not name of the baseName's + //module. For instance, baseName of 'one/two/three', maps to + //'one/two/three.js', but we want the directory, 'one/two' for + //this normalization. + normalizedBaseParts = baseParts.slice(0, baseParts.length - 1); + } + + name = normalizedBaseParts.concat(name.split('/')); + trimDots(name); + + //Some use of packages may use a . path to reference the + //'main' module name, so normalize for that. + pkgConfig = getOwn(config.pkgs, (pkgName = name[0])); + name = name.join('/'); + if (pkgConfig && name === pkgName + '/' + pkgConfig.main) { + name = pkgName; + } + } else if (name.indexOf('./') === 0) { + // No baseName, so this is ID is resolved relative + // to baseUrl, pull off the leading dot. + name = name.substring(2); + } + } + + //Apply map config if available. + if (applyMap && (baseParts || starMap) && map) { + nameParts = name.split('/'); + + for (i = nameParts.length; i > 0; i -= 1) { + nameSegment = nameParts.slice(0, i).join('/'); + + if (baseParts) { + //Find the longest baseName segment match in the config. + //So, do joins on the biggest to smallest lengths of baseParts. + for (j = baseParts.length; j > 0; j -= 1) { + mapValue = getOwn(map, baseParts.slice(0, j).join('/')); + + //baseName segment has config, find if it has one for + //this name. + if (mapValue) { + mapValue = getOwn(mapValue, nameSegment); + if (mapValue) { + //Match, update name to the new value. + foundMap = mapValue; + foundI = i; + break; + } + } + } + } + + if (foundMap) { + break; + } + + //Check for a star map match, but just hold on to it, + //if there is a shorter segment match later in a matching + //config, then favor over this star map. + if (!foundStarMap && starMap && getOwn(starMap, nameSegment)) { + foundStarMap = getOwn(starMap, nameSegment); + starI = i; + } + } + + if (!foundMap && foundStarMap) { + foundMap = foundStarMap; + foundI = starI; + } + + if (foundMap) { + nameParts.splice(0, foundI, foundMap); + name = nameParts.join('/'); + } + } + + return name; + } + + function removeScript(name) { + if (isBrowser) { + each(scripts(), function (scriptNode) { + if (scriptNode.getAttribute('data-requiremodule') === name && + scriptNode.getAttribute('data-requirecontext') === context.contextName) { + scriptNode.parentNode.removeChild(scriptNode); + return true; + } + }); + } + } + + function hasPathFallback(id) { + var pathConfig = getOwn(config.paths, id); + if (pathConfig && isArray(pathConfig) && pathConfig.length > 1) { + removeScript(id); + //Pop off the first array value, since it failed, and + //retry + pathConfig.shift(); + context.require.undef(id); + context.require([id]); + return true; + } + } + + //Turns a plugin!resource to [plugin, resource] + //with the plugin being undefined if the name + //did not have a plugin prefix. + function splitPrefix(name) { + var prefix, + index = name ? name.indexOf('!') : -1; + if (index > -1) { + prefix = name.substring(0, index); + name = name.substring(index + 1, name.length); + } + return [prefix, name]; + } + + /** + * Creates a module mapping that includes plugin prefix, module + * name, and path. If parentModuleMap is provided it will + * also normalize the name via require.normalize() + * + * @param {String} name the module name + * @param {String} [parentModuleMap] parent module map + * for the module name, used to resolve relative names. + * @param {Boolean} isNormalized: is the ID already normalized. + * This is true if this call is done for a define() module ID. + * @param {Boolean} applyMap: apply the map config to the ID. + * Should only be true if this map is for a dependency. + * + * @returns {Object} + */ + function makeModuleMap(name, parentModuleMap, isNormalized, applyMap) { + var url, pluginModule, suffix, nameParts, + prefix = null, + parentName = parentModuleMap ? parentModuleMap.name : null, + originalName = name, + isDefine = true, + normalizedName = ''; + + //If no name, then it means it is a require call, generate an + //internal name. + if (!name) { + isDefine = false; + name = '_@r' + (requireCounter += 1); + } + + nameParts = splitPrefix(name); + prefix = nameParts[0]; + name = nameParts[1]; + + if (prefix) { + prefix = normalize(prefix, parentName, applyMap); + pluginModule = getOwn(defined, prefix); + } + + //Account for relative paths if there is a base name. + if (name) { + if (prefix) { + if (pluginModule && pluginModule.normalize) { + //Plugin is loaded, use its normalize method. + normalizedName = pluginModule.normalize(name, function (name) { + return normalize(name, parentName, applyMap); + }); + } else { + normalizedName = normalize(name, parentName, applyMap); + } + } else { + //A regular module. + normalizedName = normalize(name, parentName, applyMap); + + //Normalized name may be a plugin ID due to map config + //application in normalize. The map config values must + //already be normalized, so do not need to redo that part. + nameParts = splitPrefix(normalizedName); + prefix = nameParts[0]; + normalizedName = nameParts[1]; + isNormalized = true; + + url = context.nameToUrl(normalizedName); + } + } + + //If the id is a plugin id that cannot be determined if it needs + //normalization, stamp it with a unique ID so two matching relative + //ids that may conflict can be separate. + suffix = prefix && !pluginModule && !isNormalized ? + '_unnormalized' + (unnormalizedCounter += 1) : + ''; + + return { + prefix: prefix, + name: normalizedName, + parentMap: parentModuleMap, + unnormalized: !!suffix, + url: url, + originalName: originalName, + isDefine: isDefine, + id: (prefix ? + prefix + '!' + normalizedName : + normalizedName) + suffix + }; + } + + function getModule(depMap) { + var id = depMap.id, + mod = getOwn(registry, id); + + if (!mod) { + mod = registry[id] = new context.Module(depMap); + } + + return mod; + } + + function on(depMap, name, fn) { + var id = depMap.id, + mod = getOwn(registry, id); + + if (hasProp(defined, id) && + (!mod || mod.defineEmitComplete)) { + if (name === 'defined') { + fn(defined[id]); + } + } else { + getModule(depMap).on(name, fn); + } + } + + function onError(err, errback) { + var ids = err.requireModules, + notified = false; + + if (errback) { + errback(err); + } else { + each(ids, function (id) { + var mod = getOwn(registry, id); + if (mod) { + //Set error on module, so it skips timeout checks. + mod.error = err; + if (mod.events.error) { + notified = true; + mod.emit('error', err); + } + } + }); + + if (!notified) { + req.onError(err); + } + } + } + + /** + * Internal method to transfer globalQueue items to this context's + * defQueue. + */ + function takeGlobalQueue() { + //Push all the globalDefQueue items into the context's defQueue + if (globalDefQueue.length) { + //Array splice in the values since the context code has a + //local var ref to defQueue, so cannot just reassign the one + //on context. + apsp.apply(defQueue, + [defQueue.length - 1, 0].concat(globalDefQueue)); + globalDefQueue = []; + } + } + + handlers = { + 'require': function (mod) { + if (mod.require) { + return mod.require; + } else { + return (mod.require = context.makeRequire(mod.map)); + } + }, + 'exports': function (mod) { + mod.usingExports = true; + if (mod.map.isDefine) { + if (mod.exports) { + return mod.exports; + } else { + return (mod.exports = defined[mod.map.id] = {}); + } + } + }, + 'module': function (mod) { + if (mod.module) { + return mod.module; + } else { + return (mod.module = { + id: mod.map.id, + uri: mod.map.url, + config: function () { + return (config.config && getOwn(config.config, mod.map.id)) || {}; + }, + exports: defined[mod.map.id] + }); + } + } + }; + + function cleanRegistry(id) { + //Clean up machinery used for waiting modules. + delete registry[id]; + } + + function breakCycle(mod, traced, processed) { + var id = mod.map.id; + + if (mod.error) { + mod.emit('error', mod.error); + } else { + traced[id] = true; + each(mod.depMaps, function (depMap, i) { + var depId = depMap.id, + dep = getOwn(registry, depId); + + //Only force things that have not completed + //being defined, so still in the registry, + //and only if it has not been matched up + //in the module already. + if (dep && !mod.depMatched[i] && !processed[depId]) { + if (getOwn(traced, depId)) { + mod.defineDep(i, defined[depId]); + mod.check(); //pass false? + } else { + breakCycle(dep, traced, processed); + } + } + }); + processed[id] = true; + } + } + + function checkLoaded() { + var map, modId, err, usingPathFallback, + waitInterval = config.waitSeconds * 1000, + //It is possible to disable the wait interval by using waitSeconds of 0. + expired = waitInterval && (context.startTime + waitInterval) < new Date().getTime(), + noLoads = [], + reqCalls = [], + stillLoading = false, + needCycleCheck = true; + + //Do not bother if this call was a result of a cycle break. + if (inCheckLoaded) { + return; + } + + inCheckLoaded = true; + + //Figure out the state of all the modules. + eachProp(registry, function (mod) { + map = mod.map; + modId = map.id; + + //Skip things that are not enabled or in error state. + if (!mod.enabled) { + return; + } + + if (!map.isDefine) { + reqCalls.push(mod); + } + + if (!mod.error) { + //If the module should be executed, and it has not + //been inited and time is up, remember it. + if (!mod.inited && expired) { + if (hasPathFallback(modId)) { + usingPathFallback = true; + stillLoading = true; + } else { + noLoads.push(modId); + removeScript(modId); + } + } else if (!mod.inited && mod.fetched && map.isDefine) { + stillLoading = true; + if (!map.prefix) { + //No reason to keep looking for unfinished + //loading. If the only stillLoading is a + //plugin resource though, keep going, + //because it may be that a plugin resource + //is waiting on a non-plugin cycle. + return (needCycleCheck = false); + } + } + } + }); + + if (expired && noLoads.length) { + //If wait time expired, throw error of unloaded modules. + err = makeError('timeout', 'Load timeout for modules: ' + noLoads, null, noLoads); + err.contextName = context.contextName; + return onError(err); + } + + //Not expired, check for a cycle. + if (needCycleCheck) { + each(reqCalls, function (mod) { + breakCycle(mod, {}, {}); + }); + } + + //If still waiting on loads, and the waiting load is something + //other than a plugin resource, or there are still outstanding + //scripts, then just try back later. + if ((!expired || usingPathFallback) && stillLoading) { + //Something is still waiting to load. Wait for it, but only + //if a timeout is not already in effect. + if ((isBrowser || isWebWorker) && !checkLoadedTimeoutId) { + checkLoadedTimeoutId = setTimeout(function () { + checkLoadedTimeoutId = 0; + checkLoaded(); + }, 50); + } + } + + inCheckLoaded = false; + } + + Module = function (map) { + this.events = getOwn(undefEvents, map.id) || {}; + this.map = map; + this.shim = getOwn(config.shim, map.id); + this.depExports = []; + this.depMaps = []; + this.depMatched = []; + this.pluginMaps = {}; + this.depCount = 0; + + /* this.exports this.factory + this.depMaps = [], + this.enabled, this.fetched + */ + }; + + Module.prototype = { + init: function (depMaps, factory, errback, options) { + options = options || {}; + + //Do not do more inits if already done. Can happen if there + //are multiple define calls for the same module. That is not + //a normal, common case, but it is also not unexpected. + if (this.inited) { + return; + } + + this.factory = factory; + + if (errback) { + //Register for errors on this module. + this.on('error', errback); + } else if (this.events.error) { + //If no errback already, but there are error listeners + //on this module, set up an errback to pass to the deps. + errback = bind(this, function (err) { + this.emit('error', err); + }); + } + + //Do a copy of the dependency array, so that + //source inputs are not modified. For example + //"shim" deps are passed in here directly, and + //doing a direct modification of the depMaps array + //would affect that config. + this.depMaps = depMaps && depMaps.slice(0); + + this.errback = errback; + + //Indicate this module has be initialized + this.inited = true; + + this.ignore = options.ignore; + + //Could have option to init this module in enabled mode, + //or could have been previously marked as enabled. However, + //the dependencies are not known until init is called. So + //if enabled previously, now trigger dependencies as enabled. + if (options.enabled || this.enabled) { + //Enable this module and dependencies. + //Will call this.check() + this.enable(); + } else { + this.check(); + } + }, + + defineDep: function (i, depExports) { + //Because of cycles, defined callback for a given + //export can be called more than once. + if (!this.depMatched[i]) { + this.depMatched[i] = true; + this.depCount -= 1; + this.depExports[i] = depExports; + } + }, + + fetch: function () { + if (this.fetched) { + return; + } + this.fetched = true; + + context.startTime = (new Date()).getTime(); + + var map = this.map; + + //If the manager is for a plugin managed resource, + //ask the plugin to load it now. + if (this.shim) { + context.makeRequire(this.map, { + enableBuildCallback: true + })(this.shim.deps || [], bind(this, function () { + return map.prefix ? this.callPlugin() : this.load(); + })); + } else { + //Regular dependency. + return map.prefix ? this.callPlugin() : this.load(); + } + }, + + load: function () { + var url = this.map.url; + + //Regular dependency. + if (!urlFetched[url]) { + urlFetched[url] = true; + context.load(this.map.id, url); + } + }, + + /** + * Checks is the module is ready to define itself, and if so, + * define it. + */ + check: function () { + if (!this.enabled || this.enabling) { + return; + } + + var err, cjsModule, + id = this.map.id, + depExports = this.depExports, + exports = this.exports, + factory = this.factory; + + if (!this.inited) { + this.fetch(); + } else if (this.error) { + this.emit('error', this.error); + } else if (!this.defining) { + //The factory could trigger another require call + //that would result in checking this module to + //define itself again. If already in the process + //of doing that, skip this work. + this.defining = true; + + if (this.depCount < 1 && !this.defined) { + if (isFunction(factory)) { + //If there is an error listener, favor passing + //to that instead of throwing an error. + if (this.events.error) { + try { + exports = context.execCb(id, factory, depExports, exports); + } catch (e) { + err = e; + } + } else { + exports = context.execCb(id, factory, depExports, exports); + } + + if (this.map.isDefine) { + //If setting exports via 'module' is in play, + //favor that over return value and exports. After that, + //favor a non-undefined return value over exports use. + cjsModule = this.module; + if (cjsModule && + cjsModule.exports !== undefined && + //Make sure it is not already the exports value + cjsModule.exports !== this.exports) { + exports = cjsModule.exports; + } else if (exports === undefined && this.usingExports) { + //exports already set the defined value. + exports = this.exports; + } + } + + if (err) { + err.requireMap = this.map; + err.requireModules = [this.map.id]; + err.requireType = 'define'; + return onError((this.error = err)); + } + + } else { + //Just a literal value + exports = factory; + } + + this.exports = exports; + + if (this.map.isDefine && !this.ignore) { + defined[id] = exports; + + if (req.onResourceLoad) { + req.onResourceLoad(context, this.map, this.depMaps); + } + } + + //Clean up + delete registry[id]; + + this.defined = true; + } + + //Finished the define stage. Allow calling check again + //to allow define notifications below in the case of a + //cycle. + this.defining = false; + + if (this.defined && !this.defineEmitted) { + this.defineEmitted = true; + this.emit('defined', this.exports); + this.defineEmitComplete = true; + } + + } + }, + + callPlugin: function () { + var map = this.map, + id = map.id, + //Map already normalized the prefix. + pluginMap = makeModuleMap(map.prefix); + + //Mark this as a dependency for this plugin, so it + //can be traced for cycles. + this.depMaps.push(pluginMap); + + on(pluginMap, 'defined', bind(this, function (plugin) { + var load, normalizedMap, normalizedMod, + name = this.map.name, + parentName = this.map.parentMap ? this.map.parentMap.name : null, + localRequire = context.makeRequire(map.parentMap, { + enableBuildCallback: true + }); + + //If current map is not normalized, wait for that + //normalized name to load instead of continuing. + if (this.map.unnormalized) { + //Normalize the ID if the plugin allows it. + if (plugin.normalize) { + name = plugin.normalize(name, function (name) { + return normalize(name, parentName, true); + }) || ''; + } + + //prefix and name should already be normalized, no need + //for applying map config again either. + normalizedMap = makeModuleMap(map.prefix + '!' + name, + this.map.parentMap); + on(normalizedMap, + 'defined', bind(this, function (value) { + this.init([], function () { return value; }, null, { + enabled: true, + ignore: true + }); + })); + + normalizedMod = getOwn(registry, normalizedMap.id); + if (normalizedMod) { + //Mark this as a dependency for this plugin, so it + //can be traced for cycles. + this.depMaps.push(normalizedMap); + + if (this.events.error) { + normalizedMod.on('error', bind(this, function (err) { + this.emit('error', err); + })); + } + normalizedMod.enable(); + } + + return; + } + + load = bind(this, function (value) { + this.init([], function () { return value; }, null, { + enabled: true + }); + }); + + load.error = bind(this, function (err) { + this.inited = true; + this.error = err; + err.requireModules = [id]; + + //Remove temp unnormalized modules for this module, + //since they will never be resolved otherwise now. + eachProp(registry, function (mod) { + if (mod.map.id.indexOf(id + '_unnormalized') === 0) { + cleanRegistry(mod.map.id); + } + }); + + onError(err); + }); + + //Allow plugins to load other code without having to know the + //context or how to 'complete' the load. + load.fromText = bind(this, function (text, textAlt) { + /*jslint evil: true */ + var moduleName = map.name, + moduleMap = makeModuleMap(moduleName), + hasInteractive = useInteractive; + + //As of 2.1.0, support just passing the text, to reinforce + //fromText only being called once per resource. Still + //support old style of passing moduleName but discard + //that moduleName in favor of the internal ref. + if (textAlt) { + text = textAlt; + } + + //Turn off interactive script matching for IE for any define + //calls in the text, then turn it back on at the end. + if (hasInteractive) { + useInteractive = false; + } + + //Prime the system by creating a module instance for + //it. + getModule(moduleMap); + + //Transfer any config to this other module. + if (hasProp(config.config, id)) { + config.config[moduleName] = config.config[id]; + } + + try { + req.exec(text); + } catch (e) { + return onError(makeError('fromtexteval', + 'fromText eval for ' + id + + ' failed: ' + e, + e, + [id])); + } + + if (hasInteractive) { + useInteractive = true; + } + + //Mark this as a dependency for the plugin + //resource + this.depMaps.push(moduleMap); + + //Support anonymous modules. + context.completeLoad(moduleName); + + //Bind the value of that module to the value for this + //resource ID. + localRequire([moduleName], load); + }); + + //Use parentName here since the plugin's name is not reliable, + //could be some weird string with no path that actually wants to + //reference the parentName's path. + plugin.load(map.name, localRequire, load, config); + })); + + context.enable(pluginMap, this); + this.pluginMaps[pluginMap.id] = pluginMap; + }, + + enable: function () { + this.enabled = true; + + //Set flag mentioning that the module is enabling, + //so that immediate calls to the defined callbacks + //for dependencies do not trigger inadvertent load + //with the depCount still being zero. + this.enabling = true; + + //Enable each dependency + each(this.depMaps, bind(this, function (depMap, i) { + var id, mod, handler; + + if (typeof depMap === 'string') { + //Dependency needs to be converted to a depMap + //and wired up to this module. + depMap = makeModuleMap(depMap, + (this.map.isDefine ? this.map : this.map.parentMap), + false, + !this.skipMap); + this.depMaps[i] = depMap; + + handler = getOwn(handlers, depMap.id); + + if (handler) { + this.depExports[i] = handler(this); + return; + } + + this.depCount += 1; + + on(depMap, 'defined', bind(this, function (depExports) { + this.defineDep(i, depExports); + this.check(); + })); + + if (this.errback) { + on(depMap, 'error', this.errback); + } + } + + id = depMap.id; + mod = registry[id]; + + //Skip special modules like 'require', 'exports', 'module' + //Also, don't call enable if it is already enabled, + //important in circular dependency cases. + if (!hasProp(handlers, id) && mod && !mod.enabled) { + context.enable(depMap, this); + } + })); + + //Enable each plugin that is used in + //a dependency + eachProp(this.pluginMaps, bind(this, function (pluginMap) { + var mod = getOwn(registry, pluginMap.id); + if (mod && !mod.enabled) { + context.enable(pluginMap, this); + } + })); + + this.enabling = false; + + this.check(); + }, + + on: function (name, cb) { + var cbs = this.events[name]; + if (!cbs) { + cbs = this.events[name] = []; + } + cbs.push(cb); + }, + + emit: function (name, evt) { + each(this.events[name], function (cb) { + cb(evt); + }); + if (name === 'error') { + //Now that the error handler was triggered, remove + //the listeners, since this broken Module instance + //can stay around for a while in the registry. + delete this.events[name]; + } + } + }; + + function callGetModule(args) { + //Skip modules already defined. + if (!hasProp(defined, args[0])) { + getModule(makeModuleMap(args[0], null, true)).init(args[1], args[2]); + } + } + + function removeListener(node, func, name, ieName) { + //Favor detachEvent because of IE9 + //issue, see attachEvent/addEventListener comment elsewhere + //in this file. + if (node.detachEvent && !isOpera) { + //Probably IE. If not it will throw an error, which will be + //useful to know. + if (ieName) { + node.detachEvent(ieName, func); + } + } else { + node.removeEventListener(name, func, false); + } + } + + /** + * Given an event from a script node, get the requirejs info from it, + * and then removes the event listeners on the node. + * @param {Event} evt + * @returns {Object} + */ + function getScriptData(evt) { + //Using currentTarget instead of target for Firefox 2.0's sake. Not + //all old browsers will be supported, but this one was easy enough + //to support and still makes sense. + var node = evt.currentTarget || evt.srcElement; + + //Remove the listeners once here. + removeListener(node, context.onScriptLoad, 'load', 'onreadystatechange'); + removeListener(node, context.onScriptError, 'error'); + + return { + node: node, + id: node && node.getAttribute('data-requiremodule') + }; + } + + function intakeDefines() { + var args; + + //Any defined modules in the global queue, intake them now. + takeGlobalQueue(); + + //Make sure any remaining defQueue items get properly processed. + while (defQueue.length) { + args = defQueue.shift(); + if (args[0] === null) { + return onError(makeError('mismatch', 'Mismatched anonymous define() module: ' + args[args.length - 1])); + } else { + //args are id, deps, factory. Should be normalized by the + //define() function. + callGetModule(args); + } + } + } + + context = { + config: config, + contextName: contextName, + registry: registry, + defined: defined, + urlFetched: urlFetched, + defQueue: defQueue, + Module: Module, + makeModuleMap: makeModuleMap, + nextTick: req.nextTick, + + /** + * Set a configuration for the context. + * @param {Object} cfg config object to integrate. + */ + configure: function (cfg) { + //Make sure the baseUrl ends in a slash. + if (cfg.baseUrl) { + if (cfg.baseUrl.charAt(cfg.baseUrl.length - 1) !== '/') { + cfg.baseUrl += '/'; + } + } + + //Save off the paths and packages since they require special processing, + //they are additive. + var pkgs = config.pkgs, + shim = config.shim, + objs = { + paths: true, + config: true, + map: true + }; + + eachProp(cfg, function (value, prop) { + if (objs[prop]) { + if (prop === 'map') { + mixin(config[prop], value, true, true); + } else { + mixin(config[prop], value, true); + } + } else { + config[prop] = value; + } + }); + + //Merge shim + if (cfg.shim) { + eachProp(cfg.shim, function (value, id) { + //Normalize the structure + if (isArray(value)) { + value = { + deps: value + }; + } + if ((value.exports || value.init) && !value.exportsFn) { + value.exportsFn = context.makeShimExports(value); + } + shim[id] = value; + }); + config.shim = shim; + } + + //Adjust packages if necessary. + if (cfg.packages) { + each(cfg.packages, function (pkgObj) { + var location; + + pkgObj = typeof pkgObj === 'string' ? { name: pkgObj } : pkgObj; + location = pkgObj.location; + + //Create a brand new object on pkgs, since currentPackages can + //be passed in again, and config.pkgs is the internal transformed + //state for all package configs. + pkgs[pkgObj.name] = { + name: pkgObj.name, + location: location || pkgObj.name, + //Remove leading dot in main, so main paths are normalized, + //and remove any trailing .js, since different package + //envs have different conventions: some use a module name, + //some use a file name. + main: (pkgObj.main || 'main') + .replace(currDirRegExp, '') + .replace(jsSuffixRegExp, '') + }; + }); + + //Done with modifications, assing packages back to context config + config.pkgs = pkgs; + } + + //If there are any "waiting to execute" modules in the registry, + //update the maps for them, since their info, like URLs to load, + //may have changed. + eachProp(registry, function (mod, id) { + //If module already has init called, since it is too + //late to modify them, and ignore unnormalized ones + //since they are transient. + if (!mod.inited && !mod.map.unnormalized) { + mod.map = makeModuleMap(id); + } + }); + + //If a deps array or a config callback is specified, then call + //require with those args. This is useful when require is defined as a + //config object before require.js is loaded. + if (cfg.deps || cfg.callback) { + context.require(cfg.deps || [], cfg.callback); + } + }, + + makeShimExports: function (value) { + function fn() { + var ret; + if (value.init) { + ret = value.init.apply(global, arguments); + } + return ret || (value.exports && getGlobal(value.exports)); + } + return fn; + }, + + makeRequire: function (relMap, options) { + options = options || {}; + + function localRequire(deps, callback, errback) { + var id, map, requireMod; + + if (options.enableBuildCallback && callback && isFunction(callback)) { + callback.__requireJsBuild = true; + } + + if (typeof deps === 'string') { + if (isFunction(callback)) { + //Invalid call + return onError(makeError('requireargs', 'Invalid require call'), errback); + } + + //If require|exports|module are requested, get the + //value for them from the special handlers. Caveat: + //this only works while module is being defined. + if (relMap && hasProp(handlers, deps)) { + return handlers[deps](registry[relMap.id]); + } + + //Synchronous access to one module. If require.get is + //available (as in the Node adapter), prefer that. + if (req.get) { + return req.get(context, deps, relMap); + } + + //Normalize module name, if it contains . or .. + map = makeModuleMap(deps, relMap, false, true); + id = map.id; + + if (!hasProp(defined, id)) { + return onError(makeError('notloaded', 'Module name "' + + id + + '" has not been loaded yet for context: ' + + contextName + + (relMap ? '' : '. Use require([])'))); + } + return defined[id]; + } + + //Grab defines waiting in the global queue. + intakeDefines(); + + //Mark all the dependencies as needing to be loaded. + context.nextTick(function () { + //Some defines could have been added since the + //require call, collect them. + intakeDefines(); + + requireMod = getModule(makeModuleMap(null, relMap)); + + //Store if map config should be applied to this require + //call for dependencies. + requireMod.skipMap = options.skipMap; + + requireMod.init(deps, callback, errback, { + enabled: true + }); + + checkLoaded(); + }); + + return localRequire; + } + + mixin(localRequire, { + isBrowser: isBrowser, + + /** + * Converts a module name + .extension into an URL path. + * *Requires* the use of a module name. It does not support using + * plain URLs like nameToUrl. + */ + toUrl: function (moduleNamePlusExt) { + var ext, url, + index = moduleNamePlusExt.lastIndexOf('.'), + segment = moduleNamePlusExt.split('/')[0], + isRelative = segment === '.' || segment === '..'; + + //Have a file extension alias, and it is not the + //dots from a relative path. + if (index !== -1 && (!isRelative || index > 1)) { + ext = moduleNamePlusExt.substring(index, moduleNamePlusExt.length); + moduleNamePlusExt = moduleNamePlusExt.substring(0, index); + } + + url = context.nameToUrl(normalize(moduleNamePlusExt, + relMap && relMap.id, true), ext || '.fake'); + return ext ? url : url.substring(0, url.length - 5); + }, + + defined: function (id) { + return hasProp(defined, makeModuleMap(id, relMap, false, true).id); + }, + + specified: function (id) { + id = makeModuleMap(id, relMap, false, true).id; + return hasProp(defined, id) || hasProp(registry, id); + } + }); + + //Only allow undef on top level require calls + if (!relMap) { + localRequire.undef = function (id) { + //Bind any waiting define() calls to this context, + //fix for #408 + takeGlobalQueue(); + + var map = makeModuleMap(id, relMap, true), + mod = getOwn(registry, id); + + delete defined[id]; + delete urlFetched[map.url]; + delete undefEvents[id]; + + if (mod) { + //Hold on to listeners in case the + //module will be attempted to be reloaded + //using a different config. + if (mod.events.defined) { + undefEvents[id] = mod.events; + } + + cleanRegistry(id); + } + }; + } + + return localRequire; + }, + + /** + * Called to enable a module if it is still in the registry + * awaiting enablement. A second arg, parent, the parent module, + * is passed in for context, when this method is overriden by + * the optimizer. Not shown here to keep code compact. + */ + enable: function (depMap) { + var mod = getOwn(registry, depMap.id); + if (mod) { + getModule(depMap).enable(); + } + }, + + /** + * Internal method used by environment adapters to complete a load event. + * A load event could be a script load or just a load pass from a synchronous + * load call. + * @param {String} moduleName the name of the module to potentially complete. + */ + completeLoad: function (moduleName) { + var found, args, mod, + shim = getOwn(config.shim, moduleName) || {}, + shExports = shim.exports; + + takeGlobalQueue(); + + while (defQueue.length) { + args = defQueue.shift(); + if (args[0] === null) { + args[0] = moduleName; + //If already found an anonymous module and bound it + //to this name, then this is some other anon module + //waiting for its completeLoad to fire. + if (found) { + break; + } + found = true; + } else if (args[0] === moduleName) { + //Found matching define call for this script! + found = true; + } + + callGetModule(args); + } + + //Do this after the cycle of callGetModule in case the result + //of those calls/init calls changes the registry. + mod = getOwn(registry, moduleName); + + if (!found && !hasProp(defined, moduleName) && mod && !mod.inited) { + if (config.enforceDefine && (!shExports || !getGlobal(shExports))) { + if (hasPathFallback(moduleName)) { + return; + } else { + return onError(makeError('nodefine', + 'No define call for ' + moduleName, + null, + [moduleName])); + } + } else { + //A script that does not call define(), so just simulate + //the call for it. + callGetModule([moduleName, (shim.deps || []), shim.exportsFn]); + } + } + + checkLoaded(); + }, + + /** + * Converts a module name to a file path. Supports cases where + * moduleName may actually be just an URL. + * Note that it **does not** call normalize on the moduleName, + * it is assumed to have already been normalized. This is an + * internal API, not a public one. Use toUrl for the public API. + */ + nameToUrl: function (moduleName, ext) { + var paths, pkgs, pkg, pkgPath, syms, i, parentModule, url, + parentPath; + + //If a colon is in the URL, it indicates a protocol is used and it is just + //an URL to a file, or if it starts with a slash, contains a query arg (i.e. ?) + //or ends with .js, then assume the user meant to use an url and not a module id. + //The slash is important for protocol-less URLs as well as full paths. + if (req.jsExtRegExp.test(moduleName)) { + //Just a plain path, not module name lookup, so just return it. + //Add extension if it is included. This is a bit wonky, only non-.js things pass + //an extension, this method probably needs to be reworked. + url = moduleName + (ext || ''); + } else { + //A module that needs to be converted to a path. + paths = config.paths; + pkgs = config.pkgs; + + syms = moduleName.split('/'); + //For each module name segment, see if there is a path + //registered for it. Start with most specific name + //and work up from it. + for (i = syms.length; i > 0; i -= 1) { + parentModule = syms.slice(0, i).join('/'); + pkg = getOwn(pkgs, parentModule); + parentPath = getOwn(paths, parentModule); + if (parentPath) { + //If an array, it means there are a few choices, + //Choose the one that is desired + if (isArray(parentPath)) { + parentPath = parentPath[0]; + } + syms.splice(0, i, parentPath); + break; + } else if (pkg) { + //If module name is just the package name, then looking + //for the main module. + if (moduleName === pkg.name) { + pkgPath = pkg.location + '/' + pkg.main; + } else { + pkgPath = pkg.location; + } + syms.splice(0, i, pkgPath); + break; + } + } + + //Join the path parts together, then figure out if baseUrl is needed. + url = syms.join('/'); + url += (ext || (/\?/.test(url) ? '' : '.js')); + url = (url.charAt(0) === '/' || url.match(/^[\w\+\.\-]+:/) ? '' : config.baseUrl) + url; + } + + return config.urlArgs ? url + + ((url.indexOf('?') === -1 ? '?' : '&') + + config.urlArgs) : url; + }, + + //Delegates to req.load. Broken out as a separate function to + //allow overriding in the optimizer. + load: function (id, url) { + req.load(context, id, url); + }, + + /** + * Executes a module callack function. Broken out as a separate function + * solely to allow the build system to sequence the files in the built + * layer in the right sequence. + * + * @private + */ + execCb: function (name, callback, args, exports) { + return callback.apply(exports, args); + }, + + /** + * callback for script loads, used to check status of loading. + * + * @param {Event} evt the event from the browser for the script + * that was loaded. + */ + onScriptLoad: function (evt) { + //Using currentTarget instead of target for Firefox 2.0's sake. Not + //all old browsers will be supported, but this one was easy enough + //to support and still makes sense. + if (evt.type === 'load' || + (readyRegExp.test((evt.currentTarget || evt.srcElement).readyState))) { + //Reset interactive script so a script node is not held onto for + //to long. + interactiveScript = null; + + //Pull out the name of the module and the context. + var data = getScriptData(evt); + context.completeLoad(data.id); + } + }, + + /** + * Callback for script errors. + */ + onScriptError: function (evt) { + var data = getScriptData(evt); + if (!hasPathFallback(data.id)) { + return onError(makeError('scripterror', 'Script error', evt, [data.id])); + } + } + }; + + context.require = context.makeRequire(); + return context; + } + + /** + * Main entry point. + * + * If the only argument to require is a string, then the module that + * is represented by that string is fetched for the appropriate context. + * + * If the first argument is an array, then it will be treated as an array + * of dependency string names to fetch. An optional function callback can + * be specified to execute when all of those dependencies are available. + * + * Make a local req variable to help Caja compliance (it assumes things + * on a require that are not standardized), and to give a short + * name for minification/local scope use. + */ + req = requirejs = function (deps, callback, errback, optional) { + //Find the right context, use default + var context, config, + contextName = defContextName; + + // Determine if have config object in the call. + if (!isArray(deps) && typeof deps !== 'string') { + // deps is a config object + config = deps; + if (isArray(callback)) { + // Adjust args if there are dependencies + deps = callback; + callback = errback; + errback = optional; + } else { + deps = []; + } + } + + if (config && config.context) { + contextName = config.context; + } + + context = getOwn(contexts, contextName); + if (!context) { + context = contexts[contextName] = req.s.newContext(contextName); + } + + if (config) { + context.configure(config); + } + + return context.require(deps, callback, errback); + }; + + /** + * Support require.config() to make it easier to cooperate with other + * AMD loaders on globally agreed names. + */ + req.config = function (config) { + return req(config); + }; + + /** + * Execute something after the current tick + * of the event loop. Override for other envs + * that have a better solution than setTimeout. + * @param {Function} fn function to execute later. + */ + req.nextTick = typeof setTimeout !== 'undefined' ? function (fn) { + setTimeout(fn, 4); + } : function (fn) { fn(); }; + + /** + * Export require as a global, but only if it does not already exist. + */ + if (!require) { + require = req; + } + + req.version = version; + + //Used to filter out dependencies that are already paths. + req.jsExtRegExp = /^\/|:|\?|\.js$/; + req.isBrowser = isBrowser; + s = req.s = { + contexts: contexts, + newContext: newContext + }; + + //Create default context. + req({}); + + //Exports some context-sensitive methods on global require. + each([ + 'toUrl', + 'undef', + 'defined', + 'specified' + ], function (prop) { + //Reference from contexts instead of early binding to default context, + //so that during builds, the latest instance of the default context + //with its config gets used. + req[prop] = function () { + var ctx = contexts[defContextName]; + return ctx.require[prop].apply(ctx, arguments); + }; + }); + + if (isBrowser) { + head = s.head = document.getElementsByTagName('head')[0]; + //If BASE tag is in play, using appendChild is a problem for IE6. + //When that browser dies, this can be removed. Details in this jQuery bug: + //http://dev.jquery.com/ticket/2709 + baseElement = document.getElementsByTagName('base')[0]; + if (baseElement) { + head = s.head = baseElement.parentNode; + } + } + + /** + * Any errors that require explicitly generates will be passed to this + * function. Intercept/override it if you want custom error handling. + * @param {Error} err the error object. + */ + req.onError = function (err) { + throw err; + }; + + /** + * Does the request to load a module for the browser case. + * Make this a separate function to allow other environments + * to override it. + * + * @param {Object} context the require context to find state. + * @param {String} moduleName the name of the module. + * @param {Object} url the URL to the module. + */ + req.load = function (context, moduleName, url) { + var config = (context && context.config) || {}, + node; + if (isBrowser) { + //In the browser so use a script tag + node = config.xhtml ? + document.createElementNS('http://www.w3.org/1999/xhtml', 'html:script') : + document.createElement('script'); + node.type = config.scriptType || 'text/javascript'; + node.charset = 'utf-8'; + node.async = true; + + node.setAttribute('data-requirecontext', context.contextName); + node.setAttribute('data-requiremodule', moduleName); + + //Set up load listener. Test attachEvent first because IE9 has + //a subtle issue in its addEventListener and script onload firings + //that do not match the behavior of all other browsers with + //addEventListener support, which fire the onload event for a + //script right after the script execution. See: + //https://connect.microsoft.com/IE/feedback/details/648057/script-onload-event-is-not-fired-immediately-after-script-execution + //UNFORTUNATELY Opera implements attachEvent but does not follow the script + //script execution mode. + if (node.attachEvent && + //Check if node.attachEvent is artificially added by custom script or + //natively supported by browser + //read https://github.com/jrburke/requirejs/issues/187 + //if we can NOT find [native code] then it must NOT natively supported. + //in IE8, node.attachEvent does not have toString() + //Note the test for "[native code" with no closing brace, see: + //https://github.com/jrburke/requirejs/issues/273 + !(node.attachEvent.toString && node.attachEvent.toString().indexOf('[native code') < 0) && + !isOpera) { + //Probably IE. IE (at least 6-8) do not fire + //script onload right after executing the script, so + //we cannot tie the anonymous define call to a name. + //However, IE reports the script as being in 'interactive' + //readyState at the time of the define call. + useInteractive = true; + + node.attachEvent('onreadystatechange', context.onScriptLoad); + //It would be great to add an error handler here to catch + //404s in IE9+. However, onreadystatechange will fire before + //the error handler, so that does not help. If addEvenListener + //is used, then IE will fire error before load, but we cannot + //use that pathway given the connect.microsoft.com issue + //mentioned above about not doing the 'script execute, + //then fire the script load event listener before execute + //next script' that other browsers do. + //Best hope: IE10 fixes the issues, + //and then destroys all installs of IE 6-9. + //node.attachEvent('onerror', context.onScriptError); + } else { + node.addEventListener('load', context.onScriptLoad, false); + node.addEventListener('error', context.onScriptError, false); + } + node.src = url; + + //For some cache cases in IE 6-8, the script executes before the end + //of the appendChild execution, so to tie an anonymous define + //call to the module name (which is stored on the node), hold on + //to a reference to this node, but clear after the DOM insertion. + currentlyAddingScript = node; + if (baseElement) { + head.insertBefore(node, baseElement); + } else { + head.appendChild(node); + } + currentlyAddingScript = null; + + return node; + } else if (isWebWorker) { + //In a web worker, use importScripts. This is not a very + //efficient use of importScripts, importScripts will block until + //its script is downloaded and evaluated. However, if web workers + //are in play, the expectation that a build has been done so that + //only one script needs to be loaded anyway. This may need to be + //reevaluated if other use cases become common. + importScripts(url); + + //Account for anonymous modules + context.completeLoad(moduleName); + } + }; + + function getInteractiveScript() { + if (interactiveScript && interactiveScript.readyState === 'interactive') { + return interactiveScript; + } + + eachReverse(scripts(), function (script) { + if (script.readyState === 'interactive') { + return (interactiveScript = script); + } + }); + return interactiveScript; + } + + //Look for a data-main script attribute, which could also adjust the baseUrl. + if (isBrowser) { + //Figure out baseUrl. Get it from the script tag with require.js in it. + eachReverse(scripts(), function (script) { + //Set the 'head' where we can append children by + //using the script's parent. + if (!head) { + head = script.parentNode; + } + + //Look for a data-main attribute to set main script for the page + //to load. If it is there, the path to data main becomes the + //baseUrl, if it is not already set. + dataMain = script.getAttribute('data-main'); + if (dataMain) { + //Set final baseUrl if there is not already an explicit one. + if (!cfg.baseUrl) { + //Pull off the directory of data-main for use as the + //baseUrl. + src = dataMain.split('/'); + mainScript = src.pop(); + subPath = src.length ? src.join('/') + '/' : './'; + + cfg.baseUrl = subPath; + dataMain = mainScript; + } + + //Strip off any trailing .js since dataMain is now + //like a module name. + dataMain = dataMain.replace(jsSuffixRegExp, ''); + + //Put the data-main script in the files to load. + cfg.deps = cfg.deps ? cfg.deps.concat(dataMain) : [dataMain]; + + return true; + } + }); + } + + /** + * The function that handles definitions of modules. Differs from + * require() in that a string for the module should be the first argument, + * and the function to execute after dependencies are loaded should + * return a value to define the module corresponding to the first argument's + * name. + */ + define = function (name, deps, callback) { + var node, context; + + //Allow for anonymous modules + if (typeof name !== 'string') { + //Adjust args appropriately + callback = deps; + deps = name; + name = null; + } + + //This module may not have dependencies + if (!isArray(deps)) { + callback = deps; + deps = []; + } + + //If no name, and callback is a function, then figure out if it a + //CommonJS thing with dependencies. + if (!deps.length && isFunction(callback)) { + //Remove comments from the callback string, + //look for require calls, and pull them into the dependencies, + //but only if there are function args. + if (callback.length) { + callback + .toString() + .replace(commentRegExp, '') + .replace(cjsRequireRegExp, function (match, dep) { + deps.push(dep); + }); + + //May be a CommonJS thing even without require calls, but still + //could use exports, and module. Avoid doing exports and module + //work though if it just needs require. + //REQUIRES the function to expect the CommonJS variables in the + //order listed below. + deps = (callback.length === 1 ? ['require'] : ['require', 'exports', 'module']).concat(deps); + } + } + + //If in IE 6-8 and hit an anonymous define() call, do the interactive + //work. + if (useInteractive) { + node = currentlyAddingScript || getInteractiveScript(); + if (node) { + if (!name) { + name = node.getAttribute('data-requiremodule'); + } + context = contexts[node.getAttribute('data-requirecontext')]; + } + } + + //Always save off evaluating the def call until the script onload handler. + //This allows multiple modules to be in a file without prematurely + //tracing dependencies, and allows for anonymous module support, + //where the module name is not known until the script onload event + //occurs. If no context, use the global queue, and get it processed + //in the onscript load callback. + (context ? context.defQueue : globalDefQueue).push([name, deps, callback]); + }; + + define.amd = { + jQuery: true + }; + + + /** + * Executes the text. Normally just uses eval, but can be modified + * to use a better, environment-specific call. Only used for transpiling + * loader plugins, not for plain JS modules. + * @param {String} text the text to execute/evaluate. + */ + req.exec = function (text) { + /*jslint evil: true */ + return eval(text); + }; + + //Set up with config info. + req(cfg); +}(this)); diff --git a/plugins/c9.vfs.standalone/www/test.html b/plugins/c9.vfs.standalone/www/test.html new file mode 100644 index 00000000..777fa68c --- /dev/null +++ b/plugins/c9.vfs.standalone/www/test.html @@ -0,0 +1,380 @@ + + + + + Test Runner + + + + +
      + + + + + + + + + diff --git a/plugins/c9.vfs.standalone/www/test.js b/plugins/c9.vfs.standalone/www/test.js new file mode 100644 index 00000000..cfb4dbb8 --- /dev/null +++ b/plugins/c9.vfs.standalone/www/test.js @@ -0,0 +1,469 @@ +var bar; // Intended global + +require([ + "lib/chai/chai", + "text!plugins/c9.ide.layout.classic/skins.xml", + "events", + "text!/static/standalone/skin/default/dark.css" +], function (chai, skin, events, theme) { + "use strict"; + var expect = chai.expect; + var EventEmitter = events.EventEmitter; + + function html(path, message) { + var htmlNode; + if (typeof path != "object" || !(path instanceof HTMLElement)) + htmlNode = html.constr(path); + else + htmlNode = path; + var not = false; + + function testOk(value) { + if (not) + expect(value, message || path).not.ok; + else + expect(value, message || path).ok; + not = false; + } + + var obj = { + get is(){ return obj; }, + get has(){ return obj; }, + get have(){ return obj; }, + get and(){ return obj; }, + get to(){ return obj; }, + get not(){ not = true; return obj; }, + + get ok(){ testOk(htmlNode); return obj; }, + get exists(){ testOk(htmlNode); return obj; }, + get exist(){ testOk(htmlNode); return obj; }, + get node(){ return htmlNode }, + + get visible() { + testOk(htmlNode && (htmlNode.offsetWidth || htmlNode.offsetHeight)); + return obj; + }, + + text: function(text) { + testOk(htmlNode.textContent.match(text)); + return obj; + }, + + icon: function(icon) { + testOk(htmlNode.innerHTML.indexOf(icon) > -1); + return obj; + }, + + className: function(name) { + testOk(htmlNode.className.indexOf(name) > -1); + return obj; + }, + child: function(query) { + if (typeof query == "number") { + if (query < 0) + query = htmlNode.children.length + query; + htmlNode = htmlNode.children[query]; + } else { + htmlNode = htmlNode.querySelector(query); + } + return obj; + } + }; + return obj; + } + expect.html = html; + expect.html.setConstructor = function(fn) { + html.constr = fn; + }; + + expect.html.mocked = function(options, imports, register) { + register(null, { + c9 : (function(){ + var x = new EventEmitter(); + x.location = ""; + x.has = function(){ return false; }; + x.toInternalPath = x.toExternalPath = function(p) { + return p; + }; + x.connected = true; + return x; + })(), + vfs: (function(){ + var x = new EventEmitter(); + return x; + })(), + anims: (function(){ + var x = new EventEmitter(); + x.animateSplitBoxNode = function(node, opt) { + node.setAttribute("height", parseInt(opt.height, 10)); + }; + return x; + })(), + watcher: (function(){ + var x = new EventEmitter(); + x.watch = function(){}; + x.unwatch = function(){}; + x.check = function(){}; + return x; + })(), + save: (function(){ + var x = new EventEmitter(); + x.saveAll = function(c){ c(); }; + x.getSavingState = function(tab) { return "saved"; }; + return x; + })(), + findreplace: { + + }, + ace: { + getElement: function(){} + }, + css: { + get packed() { return true; }, + get packedThemes() { return true; }, + defineLessLibrary: function(){}, + insert: function() {}, + insertLess: function() {} + }, + settings: (function(){ + var obj = new EventEmitter(); + obj.save = function(){}; + obj.set = function(){}; + obj.get = function(){}; + obj.getNumber = function() {}; + obj.emit("read", {}); + return obj; + })(), + fs: (function(){ + var obj = new EventEmitter(); + obj.writeFile = function(){}; + obj.watch = function(){}; + return obj; + })(), + tooltip: { + add: function(){} + }, + clipboard: (function(){ + var cb = new EventEmitter(); + cb.registerHandler = function(){}; + return cb; + })(), + preferences: (function(){ + var prefs = new EventEmitter(); + prefs.add = function(){}; + return prefs; + })(), + commands: (function(){ + var commands = {}; + + if (typeof apf != "undefined") { + apf.button.prototype.$propHandlers["command"] = + apf.item.prototype.$propHandlers["command"] = function(value) { + this.onclick = function(){ + commands[value].exec( + apf.getPlugin("tabManager").focussedPage.editor + ); + }; + }; + } + + var c = new EventEmitter(); + + c.commands = commands; + c.addCommands = function(a, b, c) { + a.forEach(function(o) { + commands[o.name] = o; + }); + }; + c.addCommand = function(o) { + commands[o.name] = o; + }; + c.removeCommand = function(o) { + delete commands[o.name]; + }; + c.exec = function(name) { + commands[name].exec(); + }; + c.getExceptionList = function(){ return []; }; + + return c; + })(), + log: {}, + http: {}, + api: { + stats: { + post: function(type, message, cb) { + cb && cb(); + } + } + }, + layout: (function(){ + // Load the skin + if (imports.ui) { + var plugin = new imports.Plugin(); + + imports.ui.insertCss(theme, false, plugin); + + imports.ui.insertSkin({ + "data" : skin, + "media-path" : "plugins/c9.ide.layout.classic/images/", + "icon-path" : "plugins/c9.ide.layout.classic/icons/" + }, {addElement: function(){}}); + + document.documentElement.style.background = "white"; + } + + var layout = plugin || new EventEmitter(); + + layout.initMenus = function() {}; + layout.findParent = function(){ + if (!bar || bar.$amlDestroyed) { + bar = apf.document.documentElement.appendChild( + new imports.ui.bar()); + bar.$ext.style.position = "fixed"; + bar.$ext.style.left = "20px"; + bar.$ext.style.right = "320px"; + bar.$ext.style.bottom = "20px"; + bar.$ext.style.height = "200px"; + bar.$ext.style.minHeight = "200px"; + plugin.addElement(bar); + } + bar.setAttribute("resizable", true); + + return bar; + }; + layout.getElement = function(){ + return new apf.bar(); + }; + layout.setFindArea = function(active, callback, isDefault) { + // callback(); + }; + layout.proposeLayoutChange = function(){}; + return layout; + })(), + panels: (function(){ + var panel, column; + + var api = { + register: function(p, o) { + if (!column) { + column = apf.document.documentElement.appendChild( + new imports.ui.bar({style:"background : #303130;"})); + column.$ext.style.position = "fixed"; + column.$ext.style.top = "75px"; + column.$ext.style.right = "20px"; + column.$ext.style.left = ""; + column.$ext.style.bottom = "20px"; + column.$ext.style.width = "300px"; + column.$ext.style.height = ""; + } + + panel = p; + p.draw({container: column.$ext, aml: column}); + }, + isActive: function() { return false; }, + unregister: function(){}, + activate: function(){ + // panel.panel.show() + }, + deactivate: function(){ + // panel.panel.hide() + }, + on: function(){ + + } + }; + if (imports.Plugin) { + var plugin = new imports.Plugin(); + plugin.freezePublicAPI(api); + return plugin; + } else { + return api; + } + })(), + Panel: function(developer, deps, options) { + var plugin = new imports.Plugin(developer, deps); + var emit = plugin.getEmitter(); + var drawn = false; + var where; + plugin.on("load", function(){ + where = options.where || "left"; + var panels = apf.getPlugin("panels"); + panels.register(plugin); + }); + plugin.freezePublicAPI.baseclass(); + plugin.freezePublicAPI({ + get autohide(){ return false; }, + get width(){ return options.width; }, + get minWidth(){ return options.minWidth; }, + get aml(){ return plugin.getElement(options.elementName); }, + get area(){ return ""; }, + get where(){ return where; }, + setCommand: function(){}, + attachTo: function(){}, + detach: function(){}, + show: function(){ emit("show"); }, + hide: function(){ emit("hide"); }, + draw: function draw(area) { + if (drawn) return false; + drawn = true; + + emit.sticky("draw", { + html: area.container, + aml: area.aml + }); + + return true; + } + }); + + return plugin; + }, + tree: (function(){ + var tree = new EventEmitter(); + tree.createFolder = function(){}; + tree.getElement = function(){}; + tree.getAllExpanded = function(){ return []; }; + return tree; + })(), + "tree.favorites" : (function(){ + var tree = new EventEmitter(); + tree.addFavorites = function(){}; + tree.getFavoritePaths = function(){ return [] }; + return tree; + })(), + tabManager: (function(){ + var tabManager = new EventEmitter(); + tabManager.open = function(){ tabManager.emit("open") }; + tabManager.openFile = function(){ tabManager.emit("open") }; + tabManager.findPage = function(){}; + tabManager.getPanes = function(){ return [] }; + tabManager.checkAllTabs = function(){}; + return tabManager; + })(), + tabbehavior: (function(){ + var x = new EventEmitter(); + x.getElement = function(){}; + return x; + })(), + menus: (function(){ + var menus = new EventEmitter(); + menus.addItemByPath = function(x, aml, y, plugin) { + aml && (plugin || y).addElement(aml); + return aml; + }; + menus.addItemToMenu = menus.addItemByPath; + menus.get = function(){return {}}; + menus.remove = function(){}; + menus.enableItem = function(){}; + menus.disableItem = function(){}; + return menus; + })(), + util: { + alert: function() {}, + escapeXml: function(s) { return s; } + }, + gotoline: { + toggle: function(){ } + }, + "auth.bootstrap": { + login: function(callback) { callback(); } + }, + "auth": {}, + "info": { + getUser: function(callback) { + var user = { id: 1 }; + return callback ? callback(null, user) : user; + }, + getWorkspace: function(callback) { + var ws = { id: 2 }; + return callback ? callback(null, ws) : ws; + } + }, + "ace.gotoline": {}, + "ace.stripws": { + disable: function(){}, + enable: function(){} + }, + "dialog.alert": {show: function() { console.log(console, Array.prototype.slice.apply(arguments)); }}, + "dialog.confirm": {show: function() {}}, + "dialog.question": {show: function() {}}, + "dialog.filesave": {show: function() {}}, + "dialog.fileremove": {show: function() {}}, + "dialog.fileoverwrite": {show: function() {}}, + "dialog.error": { + showError: function(msg) { + console.warn(msg); + } + }, + "run.gui": { getElement : function(){} }, + "debugger": {debug: function() {}, stop: function(){}}, + "focusManager": { + focus: function() { + + } + }, + error_handler: {reportError: function(){}}, + installer: { + show: function(){} + }, + proc: { + execFile: function() {}, + spawn: function() {} + }, + threewaymerge: { + patchAce: function(oldVal, newVal, doc) { + if (doc == undefined) { + doc = newVal; + newVal = oldVal; + } + doc.setValue(newVal); + } + } + }); + }; + + expect.setupArchitectTest = function(config, architect, options) { + if (options && options.mockPlugins) { + config.push({ + consumes: [], + provides: options.mockPlugins, + setup: expect.html.mocked + }); + } + architect.resolveConfig(config, function(err, config) { + /*global describe it before after = */ + if (err) throw err; + var app = window.app = architect.createApp(config, function(err, app) { + if (err && err.unresolved && !config.unresolved) { + console.warn("Adding mock services for " + err.unresolved); + config.unresolved = err.unresolved; + expect.setupArchitectTest(config, architect, { + mockPlugins: config.unresolved + }); + return; + } + + describe('app', function() { + it('should load test app', function(done) { + expect(err).not.ok; + done(); + }); + }); + + onload && onload(); + + }); + if (app) { + app.on("service", function(name, plugin) { + if (!plugin.name && typeof plugin != "function") + plugin.name = name; + }); + app.rerun = function() { + expect.setupArchitectTest(config, architect); + }; + } + }); + }; + +}); \ No newline at end of file diff --git a/plugins/c9.vfs.standalone/www/testsuite.html b/plugins/c9.vfs.standalone/www/testsuite.html new file mode 100644 index 00000000..30b577d1 --- /dev/null +++ b/plugins/c9.vfs.standalone/www/testsuite.html @@ -0,0 +1,142 @@ + + + + + + Test Runner + + + + + +
      + +
        +
        + + + + + + + + \ No newline at end of file diff --git a/plugins/c9.vfs.standalone/www/text.js b/plugins/c9.vfs.standalone/www/text.js new file mode 100644 index 00000000..a234cb1f --- /dev/null +++ b/plugins/c9.vfs.standalone/www/text.js @@ -0,0 +1,308 @@ +/** + * @license RequireJS text 2.0.3 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/requirejs/text for details + */ +/*jslint regexp: true */ +/*global require: false, XMLHttpRequest: false, ActiveXObject: false, + define: false, window: false, process: false, Packages: false, + java: false, location: false */ + +define(['module'], function (module) { + 'use strict'; + + var text, fs, + progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'], + xmlRegExp = /^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im, + bodyRegExp = /]*>\s*([\s\S]+)\s*<\/body>/im, + hasLocation = typeof location !== 'undefined' && location.href, + defaultProtocol = hasLocation && location.protocol && location.protocol.replace(/\:/, ''), + defaultHostName = hasLocation && location.hostname, + defaultPort = hasLocation && (location.port || undefined), + buildMap = [], + masterConfig = (module.config && module.config()) || {}; + + text = { + version: '2.0.3', + + strip: function (content) { + //Strips declarations so that external SVG and XML + //documents can be added to a document without worry. Also, if the string + //is an HTML document, only the part inside the body tag is returned. + if (content) { + content = content.replace(xmlRegExp, ""); + var matches = content.match(bodyRegExp); + if (matches) { + content = matches[1]; + } + } else { + content = ""; + } + return content; + }, + + jsEscape: function (content) { + return content.replace(/(['\\])/g, '\\$1') + .replace(/[\f]/g, "\\f") + .replace(/[\b]/g, "\\b") + .replace(/[\n]/g, "\\n") + .replace(/[\t]/g, "\\t") + .replace(/[\r]/g, "\\r") + .replace(/[\u2028]/g, "\\u2028") + .replace(/[\u2029]/g, "\\u2029"); + }, + + createXhr: masterConfig.createXhr || function () { + //Would love to dump the ActiveX crap in here. Need IE 6 to die first. + var xhr, i, progId; + if (typeof XMLHttpRequest !== "undefined") { + return new XMLHttpRequest(); + } else if (typeof ActiveXObject !== "undefined") { + for (i = 0; i < 3; i += 1) { + progId = progIds[i]; + try { + xhr = new ActiveXObject(progId); + } catch (e) {} + + if (xhr) { + progIds = [progId]; // so faster next time + break; + } + } + } + + return xhr; + }, + + /** + * Parses a resource name into its component parts. Resource names + * look like: module/name.ext!strip, where the !strip part is + * optional. + * @param {String} name the resource name + * @returns {Object} with properties "moduleName", "ext" and "strip" + * where strip is a boolean. + */ + parseName: function (name) { + var strip = false, index = name.indexOf("."), + modName = name.substring(0, index), + ext = name.substring(index + 1, name.length); + + index = ext.indexOf("!"); + if (index !== -1) { + //Pull off the strip arg. + strip = ext.substring(index + 1, ext.length); + strip = strip === "strip"; + ext = ext.substring(0, index); + } + + return { + moduleName: modName, + ext: ext, + strip: strip + }; + }, + + xdRegExp: /^((\w+)\:)?\/\/([^\/\\]+)/, + + /** + * Is an URL on another domain. Only works for browser use, returns + * false in non-browser environments. Only used to know if an + * optimized .js version of a text resource should be loaded + * instead. + * @param {String} url + * @returns Boolean + */ + useXhr: function (url, protocol, hostname, port) { + var uProtocol, uHostName, uPort, + match = text.xdRegExp.exec(url); + if (!match) { + return true; + } + uProtocol = match[2]; + uHostName = match[3]; + + uHostName = uHostName.split(':'); + uPort = uHostName[1]; + uHostName = uHostName[0]; + + return (!uProtocol || uProtocol === protocol) && + (!uHostName || uHostName.toLowerCase() === hostname.toLowerCase()) && + ((!uPort && !uHostName) || uPort === port); + }, + + finishLoad: function (name, strip, content, onLoad) { + content = strip ? text.strip(content) : content; + if (masterConfig.isBuild) { + buildMap[name] = content; + } + onLoad(content); + }, + + load: function (name, req, onLoad, config) { + //Name has format: some.module.filext!strip + //The strip part is optional. + //if strip is present, then that means only get the string contents + //inside a body tag in an HTML string. For XML/SVG content it means + //removing the declarations so the content can be inserted + //into the current doc without problems. + + // Do not bother with the work if a build and text will + // not be inlined. + if (config.isBuild && !config.inlineText) { + onLoad(); + return; + } + + masterConfig.isBuild = config.isBuild; + + var parsed = text.parseName(name), + nonStripName = parsed.moduleName + '.' + parsed.ext, + url = req.toUrl(nonStripName), + useXhr = (masterConfig.useXhr) || + text.useXhr; + + //Load the text. Use XHR if possible and in a browser. + if (!hasLocation || useXhr(url, defaultProtocol, defaultHostName, defaultPort)) { + text.get(url, function (content) { + text.finishLoad(name, parsed.strip, content, onLoad); + }, function (err) { + if (onLoad.error) { + onLoad.error(err); + } + }); + } else { + //Need to fetch the resource across domains. Assume + //the resource has been optimized into a JS module. Fetch + //by the module name + extension, but do not include the + //!strip part to avoid file system issues. + req([nonStripName], function (content) { + text.finishLoad(parsed.moduleName + '.' + parsed.ext, + parsed.strip, content, onLoad); + }); + } + }, + + write: function (pluginName, moduleName, write, config) { + if (buildMap.hasOwnProperty(moduleName)) { + var content = text.jsEscape(buildMap[moduleName]); + write.asModule(pluginName + "!" + moduleName, + "define(function () { return '" + + content + + "';});\n"); + } + }, + + writeFile: function (pluginName, moduleName, req, write, config) { + var parsed = text.parseName(moduleName), + nonStripName = parsed.moduleName + '.' + parsed.ext, + //Use a '.js' file name so that it indicates it is a + //script that can be loaded across domains. + fileName = req.toUrl(parsed.moduleName + '.' + + parsed.ext) + '.js'; + + //Leverage own load() method to load plugin value, but only + //write out values that do not have the strip argument, + //to avoid any potential issues with ! in file names. + text.load(nonStripName, req, function (value) { + //Use own write() method to construct full module value. + //But need to create shell that translates writeFile's + //write() to the right interface. + var textWrite = function (contents) { + return write(fileName, contents); + }; + textWrite.asModule = function (moduleName, contents) { + return write.asModule(moduleName, fileName, contents); + }; + + text.write(pluginName, nonStripName, textWrite, config); + }, config); + } + }; + + if (masterConfig.env === 'node' || (!masterConfig.env && + typeof process !== "undefined" && + process.versions && + !!process.versions.node) && require.nodeRequire) { + //Using special require.nodeRequire, something added by r.js. + fs = require.nodeRequire('fs'); + + text.get = function (url, callback) { + var file = fs.readFileSync(url, 'utf8'); + //Remove BOM (Byte Mark Order) from utf8 files if it is there. + if (file.indexOf('\uFEFF') === 0) { + file = file.substring(1); + } + callback(file); + }; + } else if (masterConfig.env === 'xhr' || (!masterConfig.env && + text.createXhr())) { + text.get = function (url, callback, errback) { + var xhr = text.createXhr(); + xhr.open('GET', url, true); + + //Allow overrides specified in config + if (masterConfig.onXhr) { + masterConfig.onXhr(xhr, url); + } + + xhr.onreadystatechange = function (evt) { + var status, err; + //Do not explicitly handle errors, those should be + //visible via console output in the browser. + if (xhr.readyState === 4) { + status = xhr.status; + if (status > 399 && status < 600) { + //An http 4xx or 5xx error. Signal an error. + err = new Error(url + ' HTTP status: ' + status); + err.xhr = xhr; + errback(err); + } else { + callback(xhr.responseText); + } + } + }; + xhr.send(null); + }; + } else if (masterConfig.env === 'rhino' || (!masterConfig.env && + typeof Packages !== 'undefined' && typeof java !== 'undefined')) { + //Why Java, why is this so awkward? + text.get = function (url, callback) { + var stringBuffer, line, + encoding = "utf-8", + file = new java.io.File(url), + lineSeparator = java.lang.System.getProperty("line.separator"), + input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)), + content = ''; + try { + stringBuffer = new java.lang.StringBuffer(); + line = input.readLine(); + + // Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324 + // http://www.unicode.org/faq/utf_bom.html + + // Note that when we use utf-8, the BOM should appear as "EF BB BF", but it doesn't due to this bug in the JDK: + // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058 + if (line && line.length() && line.charAt(0) === 0xfeff) { + // Eat the BOM, since we've already found the encoding on this file, + // and we plan to concatenating this buffer with others; the BOM should + // only appear at the top of a file. + line = line.substring(1); + } + + stringBuffer.append(line); + + while ((line = input.readLine()) !== null) { + stringBuffer.append(lineSeparator); + stringBuffer.append(line); + } + //Make sure we return a JavaScript string and not a Java string. + content = String(stringBuffer.toString()); //String + } finally { + input.close(); + } + callback(content); + }; + } + + return text; +}); diff --git a/scripts/initlocal.sh b/scripts/initlocal.sh new file mode 100755 index 00000000..edf9e11d --- /dev/null +++ b/scripts/initlocal.sh @@ -0,0 +1,71 @@ +#!/bin/bash -e + +NODE_VERSION=v0.10.21 + +cd $HOME +mkdir -p .c9/bin +mkdir -p .c9/node_modules +cd .c9 + +rm -rf node +rm -rf node-$NODE_VERSION* + +echo :Installing Node $NODE_VERSION +echo Downloading Node $NODE_VERSION... +curl -sSOL http://nodejs.org/dist/$NODE_VERSION/node-$NODE_VERSION-darwin-x64.tar.gz +tar xvfz node-$NODE_VERSION-darwin-x64.tar.gz +mv node-$NODE_VERSION-darwin-x64 node +rm node-$NODE_VERSION-darwin-x64.tar.gz + +NPM=$HOME/.c9/node/bin/npm +NODE=$HOME/.c9/node/bin/node + +echo :Installing pty.js +$NPM install pty.js +echo :Installing Nak +$NPM install https://github.com/c9/nak/tarball/ea1299a3688f307d2269c93bd9692101eb4f262e +echo :Installing Coffee Script +$NPM install coffee +echo :Installing Less +$NPM install less +echo :Installing Sass +$NPM install sass +echo :Installing TypeScript +$NPM install typescript + +echo :Correcting Paths +for FILE in $HOME/.c9/node_modules/.bin/* +do + perl -i -p -e 's/#!\/usr\/bin\/env node/#!'${NODE//\//\\\/}'/' $(readlink $FILE) +done + +echo :Installing TMUX +echo Downloading TMUX 1.6... +curl -sSOL http://downloads.sourceforge.net/tmux/tmux-1.6.tar.gz +echo Downloading Libevent 2.0... +curl -sSOL http://downloads.sourceforge.net/project/levent/libevent/libevent-2.0/libevent-2.0.16-stable.tar.gz + +# Unpack the sources + +tar xzf tmux-1.6.tar.gz +tar xzf libevent-2.0.16-stable.tar.gz + +# Compiling libevent + +cd libevent-2.0.16-stable +./configure --prefix=/opt +make +#sudo make install + +# Compiling tmux + +cd ../tmux-1.6 +LDFLAGS="-L/opt/lib" CPPFLAGS="-I/opt/include" LIBS="-lresolv" ./configure --prefix=/opt +make +#sudo make install + +mkdir -p ~/.c9/bin +cp ./tmux ~/.c9/bin/tmux + +echo 1 > $HOME/.c9/installed +echo :Done. \ No newline at end of file diff --git a/scripts/install-sdk.sh b/scripts/install-sdk.sh new file mode 100755 index 00000000..18bf05d4 --- /dev/null +++ b/scripts/install-sdk.sh @@ -0,0 +1,80 @@ +#!/bin/bash -ex + +cd `dirname $0`/.. +SOURCE=`pwd` + +uname="$(uname -a)" +os= +arch="$(uname -m)" +case "$uname" in + Linux\ *) os=linux ;; + Darwin\ *) os=darwin ;; + SunOS\ *) os=sunos ;; + FreeBSD\ *) os=freebsd ;; + CYGWIN*) os=windows ;; + MINGW*) os=windows ;; +esac +case "$uname" in + *x86_64*) arch=x64 ;; + *i*86*) arch=x86 ;; + *armv6l*) arch=arm-pi ;; +esac + +if ! [[ -f ~/.c9/installed ]] && ! [[ $os == "windows" ]]; then + curl https://raw.githubusercontent.com/c9/install/master/install.sh | bash +fi + + +installC9Package() { + name=$1 + + REPO=https://github.com/c9/$name + + echo "checking out $REPO" + + if ! [[ -d ./plugins/$name ]]; then + mkdir -p ./plugins/$name + fi + + pushd ./plugins/$name + if ! [[ -d .git ]]; then + git init + # git remote rm origin || true + git remote add origin $REPO + fi + + version=`node -e 'console.log((require("../../package.json").c9plugins["'$name'"].substr(1) || "origin/master"))'`; + rev=`git rev-parse --revs-only $version` + + if [ "$rev" == "" ]; then + git fetch origin + fi + + status=`git status --porcelain --untracked-files=no` + if [ "$status" == "" ]; then + git reset $version --hard + else + echo "$name contains uncommited changes. Skipping..." + fi + popd +} + +c9packages=(`node -e 'console.log(Object.keys(require("./package.json").c9plugins).join(" "))'`); +count=${#c9packages[@]} +i=0 +for m in ${c9packages[@]}; do echo $m; + i=$(($i + 1)) + echo "updating plugin $i of $count" + installC9Package $m || true +done + + +# deps=`node -e 'console.log(Object.keys(require("./package.json").dependencies).join(" "))'`; +# for m in $deps; do echo $m; +# npm install $m || true +# done +npm install || true + + +echo "Success!" +echo "run 'node server.js -p 8181 -l 0.0.0.0' to launch Cloud9" \ No newline at end of file diff --git a/scripts/makelocal.sh b/scripts/makelocal.sh new file mode 100755 index 00000000..0d585e44 --- /dev/null +++ b/scripts/makelocal.sh @@ -0,0 +1,54 @@ +#!/bin/bash -e + +while [ "$1" ]; do + case "$1" in + --compress) + COMPRESS_OPTION="--compress" + ;; + --obfuscate) + OBFUSCATE_OPTION="--obfuscate" + ;; + --quick) + QUICK="1" + ;; + *) + echo "Unknown option: $1" >&2 + exit 1 + ;; + esac + shift +done + + +cd `dirname $0` +CURDIR=`pwd` +CACHE=../build + +#CDN="echo server.js cdn-cli" +CDN_SETTINGS="cdn-cli --server-settings standalone --server-config standalone" +CDN="../server.js $CDN_SETTINGS --settings local --version=standalone --cache $CACHE $COMPRESS_OPTION $OBFUSCATE_OPTION" + +mkdir -p "$CACHE/standalone/modules/lib/emmet" +cp "$CURDIR/../node_modules/emmet/emmet.js" "$CACHE/standalone/modules/lib/emmet/" + +WORKER=plugins/c9.ide.language/worker +echo building worker $WORKER +$CDN --worker $WORKER +echo $CDN --worker $WORKER + +if [ "$QUICK" = "1" ]; then + # build ace modules only if they are missing + if [ ! -f ../build/standalone/modules/ace/mode/abap.js ]; then + $CDN --module ace + fi + $CDN --config full --with-skins dark + cp ../build/standalone/config/full.js ../build/standalone/config/default-local.js + mkdir -p ../build/standalone/skin/default-local + cp ../build/standalone/skin/full/* ../build/standalone/skin/default-local/ +else + # build async loaded ace modules + $CDN --module ace + + # todo instead of creating file with full source create diff between default-local and full + $CDN --config "default-local,full" --with-skins +fi \ No newline at end of file diff --git a/scripts/makestandalone.sh b/scripts/makestandalone.sh new file mode 100755 index 00000000..9fe3aefa --- /dev/null +++ b/scripts/makestandalone.sh @@ -0,0 +1,42 @@ +#!/bin/bash -e + +while [ "$1" ]; do + case "$1" in + --compress) + COMPRESS_OPTION="--compress" + ;; + --obfuscate) + OBFUSCATE_OPTION="--obfuscate" + ;; + *) + echo Unknown option: $1 + exit 1 + ;; + esac + shift +done + +cd `dirname $0` +CURDIR=`pwd` + +case `uname` in + *CYGWIN*) CURDIR=`cygpath -w "$CURDIR"`;; +esac + +CACHE=$CURDIR/../build + +#CDN="echo server.js cdn-cli" +CDN="$CURDIR/../server.js cdn-cli -s standalone --server-config standalone --server-settings standalone --version=standalone --cache $CACHE $COMPRESS_OPTION $OBFUSCATE_OPTION" + +# build async loaded ace modules +$CDN --module ace + +WORKER=plugins/c9.ide.language/worker +echo building worker $WORKER +$CDN --worker $WORKER +echo $CDN --worker $WORKER +for CONFIG in "default"; do \ +echo cdn + echo building config $CONFIG + $CDN --config $CONFIG --with-skins +done diff --git a/scripts/makestatic.js b/scripts/makestatic.js new file mode 100755 index 00000000..c3d5344d --- /dev/null +++ b/scripts/makestatic.js @@ -0,0 +1,107 @@ +#!/usr/bin/env node +"use strict"; + +require("amd-loader"); +var path = require("path"); +var architect = require("architect"); +var optimist = require("optimist"); + +module.exports = main; + +if (!module.parent) { + var options = optimist(process.argv) + .usage("Usage: $0 [--help]") + .alias("s", "settings") + .default("settings", "local") + .describe("settings", "Settings file to use") + .alias("d", "dest") + .default("dest", __dirname + "/../build/static") + .describe("symlink", "Whether to symlink files instead of copying") + .boolean("symlink") + .describe("compress", "Compress output files") + .boolean("compress") + .describe("dest", "destination folder for the static files") + .boolean("help") + .describe("help", "Show command line options."); + + var argv = options.argv; + + if (argv.help) { + options.showHelp(); + process.exit(); + } + + var config = argv._[2] || "ide"; + var settings = argv.settings; + + main(config, settings, argv, function(err) { + if (err) { + console.error(err); + process.exit(1); + } + process.exit(0); + }); +} + + +function main(config, settings, options, callback) { + + if (config[0] !== "/") + config = path.join(__dirname, "/../configs/", config); + + settings = require(path.join(__dirname, "/../settings", settings))(); + settings.pricing = {}; + + var plugins = require(config)(settings, optimist(process.argv)) + .map(function(plugin) { + if (plugin.packagePath == "connect-architect/connect") { + plugin.packagePath = "./c9.static/connect"; + } + else if (plugin.packagePath == "connect-architect/connect.static") { + plugin.packagePath = "./c9.static/connect-static"; + } + return plugin; + }) + .concat({ + packagePath: "./c9.static/makestatic", + compress: options.compress, + virtual: options.virtual + }) + .concat({ + consumes: [], + provides: ["cdn.build", "db"], + setup: function(options, imports, register) { + register(null, { "cdn.build": {}, "db": {} }); + } + }) + .filter(function(p) { + var path = p.packagePath; + return !path || path.indexOf("c9.db.redis/redis") == -1 + && path.indexOf("c9.static/build") == -1 + && path.indexOf("c9.api/health") == -1; + }); + + + architect.resolveConfig(plugins, __dirname + "/../plugins", function(err, config) { + if (err) return callback(err); + + var app = architect.createApp(config, function (err, app) { + if (err) { + return callback(err); + } + if (options.getMounts) + app.services.makestatic.getMounts(options.dest, callback); + else if (options.symlink) + app.services.makestatic.symlink(options.dest, callback); + else + app.services.makestatic.copy(options.dest, callback); + }); + + app.on("service", function(name, plugin) { + if (typeof plugin !== "function") + plugin.name = name; + }); + }); + +} + diff --git a/scripts/setup-local-dev.sh b/scripts/setup-local-dev.sh new file mode 100755 index 00000000..d1a8c71d --- /dev/null +++ b/scripts/setup-local-dev.sh @@ -0,0 +1,67 @@ +#!/bin/bash -e + +while [ "$1" ]; do + case "$1" in + --compress) COMPRESS=1 ;; + --obfuscate) OBFUSCATE=1 ;; + *) echo "Unknown option: $1" >&2; exit 1 ;; + esac + shift +done + +uname="$(uname -a)" +os= +arch="$(uname -m)" +case "$uname" in + Linux\ *) os=linux ;; + Darwin\ *) os=darwin ;; + SunOS\ *) os=sunos ;; + FreeBSD\ *) os=freebsd ;; + CYGWIN*) os=windows ;; + MINGW*) os=windows ;; +esac +case "$uname" in + *x86_64*) arch=x64 ;; + *i*86*) arch=x86 ;; + *armv6l*) arch=arm-pi ;; +esac + + +cd `dirname $0`/.. +SOURCE=`pwd` + +LOCAL=$SOURCE/local +APPDIR=$SOURCE/build/webkitbuilds/app.nw +LOCALCFG=configs/client-default-local.js + + +if [ ! -d $SOURCE/build/webkitbuilds/cache/mac/0.9.3 ]; then + mkdir -p $SOURCE/build/webkitbuilds/cache/mac/0.9.3/node-webkit.app + pushd $SOURCE/build/webkitbuilds/cache/mac/0.9.3 + curl -O http://dl.node-webkit.org/v0.9.3/node-webkit-v0.9.3-pre8-osx-ia32.zip + unzip node-webkit-v0.9.3-pre8-osx-ia32.zip + popd +fi + +DEST="$SOURCE/build/Cloud9-dev.app" +RES="$DEST/Contents/Resources" + +rm -rf "$DEST" +mkdir -p "$RES/app.nw" + +cp -R $SOURCE/build/webkitbuilds/cache/mac/0.9.3/node-webkit.app/* $DEST +cat $SOURCE/local/Info.plist | sed "s/Cloud9/Cloud9-dev/" > $DEST/Contents/Info.plist +# TODO add blue icon for dev mode +# rm $DEST/Contents/Resources/nw.icns +cp $SOURCE/build/osx/c9.icns $DEST/Contents/Resources/nw.icns + +node --eval " + var path = require('path') + var p = require('./local/package.json'); + p.main = path.relative('$RES/app.nw', '$SOURCE/local/projectManager.html'); + delete p.dependencies; + // p.window.icon = 'icon.png'; + console.log(JSON.stringify(p, null, 2)); +" > $RES/app.nw/package.json + +echo dev app created in build/Cloud9-dev.app/Contents/MacOS/node-webkit \ No newline at end of file diff --git a/scripts/uninstall-c9.sh b/scripts/uninstall-c9.sh new file mode 100755 index 00000000..9fffbce9 --- /dev/null +++ b/scripts/uninstall-c9.sh @@ -0,0 +1,9 @@ +rm ~/.c9/installed 2> /dev/null +rm ~/.c9/version 2> /dev/null +rm -Rf ~/.c9/bin 2> /dev/null +rm -Rf ~/.c9/lib 2> /dev/null +rm -Rf ~/.c9/node_modules 2> /dev/null + +if [ -d /Applications/Cloud9.app ]; then + rm -Rf /Applications/Cloud9.app 2> /dev/null +fi \ No newline at end of file diff --git a/scripts/update-npm.sh b/scripts/update-npm.sh new file mode 100755 index 00000000..74855fc9 --- /dev/null +++ b/scripts/update-npm.sh @@ -0,0 +1,6 @@ +#!/bin/bash -e + +cd `dirname $0`/.. + +npm dedupe +npm shrinkwrap \ No newline at end of file diff --git a/server.js b/server.js new file mode 100755 index 00000000..9853e568 --- /dev/null +++ b/server.js @@ -0,0 +1,132 @@ +#!/usr/bin/env node +"use strict"; + +require("amd-loader"); +try { + require("heapdump"); +} catch(e) {} + +var path = require("path"); +var architect = require("architect"); +var optimist = require("optimist"); + +if (process.version.match(/^v0/) && parseFloat(process.version.substr(3)) < 10) { + console.warn("You're using Node.js version " + process.version + + ". Version 0.10 or higher is recommended. Some features will not work."); +} + +var DEFAULT_CONFIG = "s"; +var DEFAULT_SETTINGS = getDefaultSettings(); + +var shortcuts = { + "dev" : ["ide", "preview", "vfs", "api", "sapi", "proxy", "redis", "account", "oldclient", "homepage", "apps-proxy", "-s", "devel"], + "odev" : ["ide", "preview", "vfs", "api", "proxy", "oldclient", "homepage", "apps-proxy", "worker", "-s", "onlinedev"], + "bill" : ["ide", "preview", "vfs", "api", "proxy", "oldclient", "homepage", "apps-proxy", "account", "-s", "billing"], + "beta" : ["ide", "preview", "vfs", "proxy", "-s", "beta"], + "ci" : ["ide", "preview", "vfs", "proxy", "-s", "ci"], + "s" : ["standalone", "-s", "standalone"] +}; + +module.exports = main; + +if (!module.parent) + main(process.argv.slice(2)); + +function getDefaultSettings() { + var hostname = require("os").hostname(); + + var suffix = hostname.trim().split("-").pop() || ""; + var modes = { + "prod": "deploy", + "beta": "beta", + "dev": "devel", + "onlinedev": "onlinedev" + }; + return modes[suffix] || "devel"; +} + +module.exports.getDefaultSettings = getDefaultSettings; + +function main(argv, config, callback) { + var options = optimist(argv) + .usage("Usage: $0 [CONFIG_NAME] [--help]") + .alias("s", "settings") + .default("settings", DEFAULT_SETTINGS) + .describe("settings", "Settings file to use") + .describe("dump", "dump config file as JSON") + .boolean("help") + .describe("help", "Show command line options."); + + var configs = options.argv._; + if (!configs.length) + configs = [config || DEFAULT_CONFIG]; + + configs.forEach(function(config) { + if (shortcuts[config]) { + return main(shortcuts[config].concat(argv.filter(function(arg) { + return arg != config; + })), null, callback); + } + else { + start(config, options, callback); + } + }); +} + +function start(configName, options, callback) { + var argv = options.argv; + var settingsName = argv.settings; + + if (typeof settingsName != "string") + settingsName = settingsName.pop(); + + var configPath = configName; + if (configPath[0] !== "/") + configPath = path.join(__dirname, "/configs/", configName); + + var settings = require(path.join(__dirname, "./settings", settingsName))(); + + var plugins = require(configPath)(settings, options); + + if (argv.help) { + options.usage("Usage: $0 " + configName); + options.showHelp(); + } + + if (!plugins) + return; + + if (module.exports.onResolvePlugins) + module.exports.onResolvePlugins(plugins, __dirname + "/plugins"); + + architect.resolveConfig(plugins, __dirname + "/plugins", function(err, config) { + if (err) { + console.error(err); + process.exit(1); + } + + if (argv.dump) { + console.log(JSON.stringify(config, null, 2)); + return callback && callback(null, config); + } + + if (argv._getConfig) + return callback && callback(null, config); + + var app = architect.createApp(config, function (err, app) { + if (err) { + console.trace("Error while starting '%s':", configPath); + console.log(err, err.stack); + process.exit(1); + } + console.log("Started '%s' with config '%s'!", configPath, settingsName); + + callback && callback(null, app); + }); + + app.on("service", function(name, plugin) { + if (typeof plugin !== "function") + plugin.name = name; + }); + }); +} diff --git a/settings/local.js b/settings/local.js new file mode 100644 index 00000000..e10b625d --- /dev/null +++ b/settings/local.js @@ -0,0 +1,62 @@ +module.exports = function(manifest, installPath, settingDir) { + var path = require("path"); + var fs = require("fs"); + + if (typeof installPath != "string") { + installPath = process.platform == "darwin" + ? "/Library/Application Support/Cloud9" + : path.join(process.env.HOME, ".c9"); + } + + var config = require("./standalone")(manifest, installPath); + + // Support legacy installations + if (!config.settingDir) { + if (settingDir) + config.settingDir = settingDir; + else { + config.settingDir = installPath; + if (installPath === "/Library/Application Support/Cloud9") + config.settingDir = path.join(process.env.HOME, installPath); + } + } + + config.local = true; + config.standalone = false; + config.host = "localhost"; + config.startBridge = true; + config.collab = false; + config.apiUrl = "https://api.c9.io", + config.ideBaseUrl = "https://c9.io", + config.authorizationUrl = "https://c9.io/api/nc/auth"; + config.projectName = process.env.HOSTNAME || "/"; + if (process.platform == "win32" && config.projectName == "/") + config.projectName = "Computer"; + + config.saucelabs.serverURL = null; + config.saucelabs.account = null; + + config.update = { + path: require("path").join(__dirname, ".."), + host: "update.c9.io", + port: "443", + protocol: "https" + }; + // for development + // config.update.host = "localhost" + // config.update.port = "8888" + // config.update.host = "http" + + config.nodeBin = [process.platform == "win32" + ? path.join(process.execPath, "..\\node.exe") + : path.join(installPath, "node/bin/node")]; + config.bashBin = process.platform == "win32" + ? process.env.C9_BASH_BIN || "C:\\cygwin\\bin\\bash.exe" + : "/bin/bash"; + + config.raygun.client.apiKey = "sraXwWUvvI6TQT6d45u4bw=="; + config.raygun.server.apiKey = "sraXwWUvvI6TQT6d45u4bw=="; + + config.packed = false; + return config; +}; diff --git a/settings/standalone.js b/settings/standalone.js new file mode 100644 index 00000000..92a162c9 --- /dev/null +++ b/settings/standalone.js @@ -0,0 +1,142 @@ +module.exports = function(manifest, installPath) { + if (!manifest) { + manifest = require(__dirname + "/../package.json"); + manifest.revision = + manifest.revision || + require("c9/git").getHeadRevisionSync(__dirname + "/.."); + } + + var path = require("path"); + var runners = require("../plugins/c9.ide.run/runners_list").local; + var builders = require("../plugins/c9.ide.run.build/builders_list"); + + var workspaceDir = path.resolve(__dirname + "/../"); + + if (process.platform == "win32" && process.env.HOME === undefined) { + process.env.HOME = process.env.HOMEDRIVE + process.env.HOMEPATH; + } + + var home = process.env.HOME; + + if (!installPath) + installPath = path.join(home, ".c9"); + + var correctedInstallPath = installPath.substr(0, home.length) == home + ? "~" + installPath.substr(home.length) + : installPath; + + var config = { + standalone: true, + manifest: manifest, + workspaceDir: workspaceDir, + projectName: path.basename(workspaceDir), + homeDir: home, + workspaceId: "devel", + workspaceName: "devel", + tmpdir: "/tmp", + home: home, + uid: "-1", + dev: true, + pid: process.pid, + port: process.env.PORT || 8181, + host: process.env.IP || "0.0.0.0", + testing: false, + platform: process.platform, + tmux: path.join(installPath, "bin/tmux"), + nakBin: path.join(__dirname, "../node_modules/nak/bin/nak"), + bashBin: "bash", + nodeBin: [process.execPath], + installPath: installPath, + correctedInstallPath: correctedInstallPath, + staticPrefix: "/static", + projectUrl: "/workspace", + ideBaseUrl: "http://c9.io", + previewUrl: "/preview", + dashboardUrl: "https://c9.io/dashboard.html", + apiUrl: "https://api.c9.dev", + homeUrl: "/home", + collab: false, + installed: true, + packed: false, + packedThemes: true, + readonly: false, + role: "a", + isAdmin: true, + runners: runners, + builders: builders, + themePrefix: "/static/standalone/skin", + cdn: { + version: "standalone", + cacheDir: __dirname + "/../build", + compress: false, + baseUrl: "" + }, + mount: { + fusermountBin: "fusermount", + curlftpfsBin: "curlftpfs", + sshfsBin: "sshfs" + }, + saucelabs: { + serverURL: null, // testing: "https://jlipps.dev.saucelabs.net" + account: { + username: "saucefree000093", + apikey: "3227f6a3-3861-4a56-8b27-e756ce0bba20" + }, + assumeConnected: true + }, + feedback: { + userSnapApiKey: "a83fc136-1bc4-4ab8-8158-e750c30873b5" + }, + support: { + userSnapApiKey: "e3d3b232-1c21-4961-b73d-fbc8dc7be1c3" + }, + user: { + id: -1, + name: "johndoe", + fullname: "John Doe", + email: "johndoe@example.org", + pubkey: null + }, + project: { + id: 2, + name: "projectname", + contents: null, + descr: "descr" + }, + analytics: { + segmentio: { + secret: "12346", + flushAt: 1, // The number of messages to enqueue before flushing. + integrations: { + "All": true + } + }, + treasureData: { + tdWriteKey: "12346", + tdDb: "test_db", + tdAgentHost: "localhost", + tdAgentPort: 24224 + } + }, + raygun: { + server: { + apiKey: "1234" + }, + client: { + apiKey: "1234" + } + }, + pricing: { containers: [] }, + zuora: {}, + localExtend: true, + extendDirectory: __dirname + "/../plugins/c9.vfs.extend" + }; + + config.extendOptions = { + user: config.user, + project: config.project, + readonly: config.readonly + }; + + return config; +}; diff --git a/test/filefinder.js b/test/filefinder.js new file mode 100644 index 00000000..451ec0a4 --- /dev/null +++ b/test/filefinder.js @@ -0,0 +1,164 @@ +/* +filefinder - find files matching a specific file name pattern that are not found on a specified blacklist + +=example= + ff.find("/tmp", "files", ".*_test.js", "/tmp/blacklist", function(err, res) { + console.log(util.inspect(res)); + }); + +--dirlist-- +one_test.js +two_test.js +three.js +four_test.js + +--blacklist-- +one_test.js +files/two_test.js +four + +--result-- +{ countOk: 2, + countPatternMis: 1, + countBl: 1, + list: [ 'files/four_test.js', 'files/one_test.js' ] } + +*/ + +var fs = require("fs"); +var util = require("util"); +var path = require("path"); + + +var DEBUGMODE = false; + + + +function filefinder(basedir, subdir, fnpattern, blacklistfile, cb) { + if (DEBUGMODE) console.log("\n\n\n\nfilefinder()"); + if (cb) cb(); +} + +filefinder.prototype.find = function(basedir, subdir, fnpattern, blacklistfile, cb) { + if (DEBUGMODE) console.log("\n\n\n\nfind(%s, %s, %s)", path.join(basedir, subdir), fnpattern, blacklistfile); + this.basedir = basedir; + this.subdir = subdir; + this.pattern = fnpattern; + this.blacklistfile = blacklistfile; + + this.flist = []; + this.countBlacklisted = 0; + this.countPatternMis = 0; + var _self = this; + + _self.getBlacklist(this.blacklistfile, function(err, blacklist) { + _self.treewalk(basedir, subdir, fnpattern, blacklist, _self.flist, function(err, res) { + // compose results object + var result = { + countOk: _self.flist.length, + countPatternMis: _self.countPatternMis, + countBl: _self.countBlacklisted, + list: _self.flist, + blacklist: blacklist + }; + cb(null, result); + }); + }); +}; + +filefinder.prototype.getBlacklist = function(filename, cb) { + if (DEBUGMODE) console.log("getBlacklist()"); + var _self = this; + _self.getFileInArray(filename, function(err, blacklist) { + if (err) return cb(new Error("error reading blacklist file")); + _self.arrayRemoveCrap(blacklist, function(err, blacklist) { + if (DEBUGMODE) console.log("--blacklist--\nlength: %s\n%s\n-------------", blacklist.length, util.inspect(blacklist)); + cb(null, blacklist); + }); + }); +}; + +// read a text file and make each line a member of an array +filefinder.prototype.getFileInArray = function(filename, cb) { + if (DEBUGMODE) console.log("getFileInArray()"); + var array = []; + fs.exists(filename, function (exists) { + if (!exists) return cb(null, array); + fs.readFile(filename, function(err, data) { + if(err) return cb(err); + array = data.toString().split("\n"); + cb(null, array); + }); + }); +}; + +filefinder.prototype.arrayRemoveCrap = function(array, cb) { + if (DEBUGMODE) console.log("arrayRemoveCrap()"); + + function removeComments(element, index, array) { + // clean-up whitespace, comments etc. + array[index] = array[index].replace(/\s*#.*|^\s*|\s*$/g, ''); + } + array.forEach(removeComments); + + array = array.filter(function(e) { + return e !== ""; + }); + + cb(null, array); +}; + + +filefinder.prototype.treewalk = function(basedir, subdir, fnpattern, blacklist, foundfilesarray, cb) { + var _self = this; + var fulldir = path.join(basedir, subdir); + if (DEBUGMODE) console.log(">treewalk (dir: %s, fnpattern: %s)", fulldir, fnpattern); + var results = []; + + fs.readdir(fulldir, function(err, list) { + if (err) return cb(err); + var i = 0; + + function next() { + var file = list[i++]; + if (!file) return cb(null, foundfilesarray.length); + var filepath = path.join(fulldir, file); + + // get file info + fs.stat(filepath, function(err, stat) { + if (stat && stat.isDirectory()) { + // directory, so recurse + _self.treewalk(basedir, path.join(subdir, file), fnpattern, blacklist, foundfilesarray, function(err, res) { + results = results.concat(res); + next(); + }); + } + else { + // file found, matches pattern? + if (file.match(fnpattern) === null) { + _self.countPatternMis++; + return next(); + } + + // check if blacklisted + var partName = path.join(subdir, file); + if (!blacklist || blacklist.indexOf(partName) == -1) { + if (DEBUGMODE) console.log("file found: %s", partName); + foundfilesarray.push(partName); + } + else { + _self.countBlacklisted++; + if (DEBUGMODE) console.log("File blacklisted: ", partName); + } + next(); + } + }); + } + next(); + }); +}; + +// export the class +module.exports = new filefinder(); + +

      C+U-;RWd&sWGV{Ott_dLlyBKs{1ktj;JxN^%*2 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 literal 0 HcmV?d00001 diff --git a/node_modules/ace/api/resources/images/cloud9-logo.png b/node_modules/ace/api/resources/images/cloud9-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..912524a9ee1d12e58f34ec5622fd4d0b99cfd9ea GIT binary patch literal 14564 zcmW-ocQ{-B`^Jw|qcvjJC_>GaqV^_6QA*8NHA?LfdsnGYw2E3WitsUFN2$H3RV!9e zGq&2BU%tOTPR=FQl{h(hzwhUMUeBGFS32tCWK3iL0Fb}Xfav4Sd$>c0`t>^nuT$I(DgSoX5s1>R_I)y_v7bNt)8C0 zfN&b49|0-pQx6Vr8vTtwt5+;;gA8u$gevvs^^zP*F*M4a?C;GrS)91ypJx<0X?>fV zn-DG9X~taLRGplG`tj) zOH5S*d?5(;1Qe+PlpzVEimh+}9u5F-^Dz!r|KX!0&Bn3Y8Zn<@nQP3CyUnJ%*6nhc z5asK)T!Hc+U(T-nm53Dz++*dd#C_A*g;q>F3WMt5ph2K~4b&J@CwHP}4 z@=tIe*UfRaNh+(~BFuC9r6qq>v!DiYDofsH*(`~MQzmT&q*s7;n{H>`Yd*`~ZoNHm zcfs$n`op147^ffyKLPf7hkD6&iszVsHdicxVHH5Fsn-DO0ZA^@z}f1bz=71D@Rj7pdC)fM1&|Z;OE! z;@|^-@Vmlo?g-0!03o1Drbq+<<1tbt;(??_JuHTq2$rA_^RX`K!nrqh^l3*A@VfB3 z92{ccJJi@mCO>X3{~dzdI!sMAt-u`@nx$SUV^FO3RFi7Op={W}>-}#{-!KWr&yM_h z)pXt5s4DbJxWN#OidO7i<0T4actPX=gAghsbRq6Mh0G*;%F5B<{T_A=G-vu)F4{y( z&_fzeG0#I)r7|wxkoQ#kY8{zWj-+5o0Ps|fI6vTh(0WuhvYReiB@SuIq%vk-_Tm~0 z2P8dRP>sw8=2r8X7}Af~oe(zmLKcn&?o`_j(I^D$7xae;WRG*%n4^PPQoQ@mpGUTN zPJbR85f$L&F6<$`!1i*oV0UI;12_PxQLxP|Ec-M&9O3u-Ac>HQNU=@IFA3&B3)kR(^0WA)OOcEQL)LUpKZu zovxXd4AlH40l_aM(l;f(3cnOjSfsX-!wL256cT_RG~L;a%4Tb@D$@?T#nGBRW>W$ zkEIDoNZ^1pHo4~XaUxo%7IUjG+<+nh?$Zlq`CU$UdJTVz;q90S=_%KxqID!Oqa~z; z(Bi#6N3^+{%Xhq_*J3`>Vh@isWCfvM6cOw-&r*JsHPhCg*(LzG4mUV zfdb?~axSV{BZUSw-TOwG^Mxjprk>NQ3mHDiF>UxBTwq?EzG_1~J9i_pTg+L6)u+7Q zRr)^bX&WFt1dQ;FssO7+T*C?5i`hE#NTapQbuE==N;+7ZD;t)82h<+u!(T2t)HyY> zfTV%SpQ4V+ZISvwxOi+~*(d&_mHf|>+mpfo zu+4Qf=<=tb=L&HL0-uL^luDZM6p{d4&{8sF9YZ_O+TS<|FUx%MV&$r7-}&i{{v2y+ zPgQLWXc_a$ya~$aQHn!9hV{`#vx?)12+AkLG%DuP{gl%~r2f^tl?zwQtP>h4FDdTj zH7#Yv0S4hi7~JbI#dEXL>u5FwUlJv*SjvlIJOX9x7mw9Er5r8th@su9;2ZIoTGp)j zE2x=Fxs2~|8#mSko&NoC9N)sxLz!2cV*~IFG{htWX+)Mw!vXp+E_G2Sc{Z|#Zwta> z#9d3+$*hL<2hP1o@(zyU4ax(y@Z)<}mIvg=@;~k8dz|ALu3x@&@+t$-(q^I( z;ttyVZ=LbjSFVa1;~1_Fi)o@IK#6bF)FZ`bWK`nV%BHs5S$7t_G=xWTT0J(WekHA> zJ$n`tGhcNO5y4gv$_$)#W804bML#OL1+VK3rRq9a>)L}H>7`-(mtUyffY^uC0l9po zHb(p%o^>y~&Nw5duW$sKK2Z`I5PEh&B0`qmZ_#+Kl^m#axhP5X&z|yn#7H@o{%5jC z=h1xff7aAOEYUq1W=`m>d=ihD$+hpdPl;Ry=W30_kOo=sCqS-Gf*Dj=8hsENGUc&I zX;fypn5BcY+`KA2!`)|(#`rv8Nb*Os0sjTDmYmDZfFt_b-6fT)x@;*kB|tXh(Z49* zzzMSBSUrFGq3;o>xUT`IJa+&9Ip7uk7X-;I0O@$xPl^YevMV!?tP2OK$%FJb zm*c}t6d^OhwXWC_v8i&2o;!Us^rQV#yVHFVNPT3C!mq)nwCWQnG|I$Z{K+Aa2%k@= znpRs>Gf`Qi6@po=^x})gTP({C%fe|w-D&y$)V3l0do}Mza1!b5wDd)ViB{w?f&dc9 z`oWAc1v;zqN%Ec|!}yPI_$x*X<^Nt4w&J|GU5YWkDy+^4RY8gSFeaKmc_~Z?{5RD} zq*1GbV67a+1A+&n{D?suV9hei`%>FIcz;V{*fltpPc+VJQc5dsyqtrkD0_R=q+f5k z+$@v&WzbNwFULoon{z?aU0!v_=`meO;gbl*i|C0}$#qNh&X_wsYq9oG;CM6E2#8DU64|9&YdiQ$xHVcBptLDQNWx^#)&~t>Evt{W~TO z5>a*GQ7~NcSo?QL{MpB)_62#|0zGw?hiK$Lo84BXw4SowdGGYS7ZFvD=Kxi;I;$@h z(v@Nszt>)fI^=^OwXn($Rhy)PJ6a#9th69MIKMAe#uwtz@X%rZEXsI>@lZH@rD6az zCs4U7c0CSc{xC5D~ z3#mpq*nx<-#-M+>7^k>&B|?vK(nP>S3N>+OXa6}R!zqnS^t|o3=esS3uXtSEyT^%F zVV%#eT|M`9g81=u2oW%L9UVy?{se6M!+pv`^{%U|zURM$4)!IB1_&d)Hp&RLp8%56 z!nM1fj)Lg#ph%JaLE%J+G!fBgXr@&T0>MZHdR12Usn0^R z*I+Youcfm+EZgt-KR^e7GDUYI@{t3M9o5y?NEkMHgmsddOst;9mc}2zOFS! z3sn%#V;H8pY{PW2C4Uki0BU@i)=zYc-DO*lWJJ6_1<7;qw9c)h(5*IW01#$@mL*rx0cZrLe!Ov1T!fSjl zGui2y3XD(_5Uy$AdUVL-Ecq4ix8?qor$c>%_4*Itqe)Fq!zw0S14aoRj@&AFQMd_p zIj`^!74V@Te2`kTX9Esr0Tdf#tAw)p1*O^AMPWbJ&GQbvv**3-_IbKR11V6A^vI|H zVkD_~R&)xi5LfB&2MQL|xMF13b0ll){kG>(ywp3|sMlbMjGF*zcPgCt-};}-k}C*j zhXvuD-}J6CxTWY|_pfn}B(o*idhH@9Z!H&L2%iUp2Rh8>$aN0)_5{(lVCKitI^k?93 zNn!`hYf&*t5Z(%r0&QZZt#Ys9>u@*%CO-d{R_0?}Jdsi^UV-@Tv643$N_4uj6~;(d z2yZatGxQrS)~>5$0urnwf&8VU&S*gvu@FM(nU_komih>%Vowi;>I5F^6x#F?eZFo{D|~f0c@`V_{->Uq5CI#jLFgRC{iRP)Gy-@@>p)+uI(RY9PR#-87I6&?W zT56PLnrAm;s~}&xmPV3!#46%B{MaqizU--Q03uT`?^8^gzUHnn*JFINRDCKSnNCXf z)l||-MWmOB#tGo1(nE2Or08d1>3m^uaU}XO7sKxm$LH)?m~3>?l>lSVs)ZT6pN%5r z7*F}Hsco>_vNXYbBO4+u#)jX^Lj0D|mLHlKD_m$3mp-PZ`_T4RPuh!>0GjOm_@JIz zN2L73;*U+Fu8+=B6zhzm#KO)8-eENgka2G=U$!;uT4Z0i^p;lYx4f8|U*sZwL90Km2Xw0RC5d zNdeh41QlYbkk%Vq3G<&brg|r0)Q|}Vn5DV#pOs=c!i{1(?O{rg+Jozno!QYd1>gNY zw`#81&wk`==Eswir6i2diSIu(D*W}{hoTIv2*2YO8H!`BtD=H==vl|W9Xh>M&D-vC zTk_TaAo8#iF{@bz!6gVaJIHY&cPS8%||G!dRzgkU8g019e_0i0s*C;p_gc zUs8@PVX`fZbNJOG`WAH}KwRe@s2;R*VZM#nYklDQ8%N_|<9s0IWe=gIwi8L8OY(ef&dv_jD8NS^Tg~-Fpy?4X8nA;% zOwUoU0&@K)9!Sp#{Yw^NLLUCASbJCD{u@Hg&4I7xhqOozV>(=v73gHus!(zDV{i!K+e3^&AROjy$z`JMA_#T_=<{FEaFq&)Y{jWtg7n zbi=%731Kk|5rTBoT$*IsWTdXtGRC|-s~MQ(s#o1yi~q08K8}NI`^bjSFkFM28!|(Z zn?&fz{qEe@=FPp45RbT5mwdz!5F=30?cbir8|y8dwSD|y!VL(&ZFw1(>pt#!6O#FJ_)C3^#nrObi(2w4 zcQ3Dq=}Z={y-SXWYtJ`E>om6 z%;>b2_dX5EtU6Ti2WS~~Qj1ZP&bk@!=9bXq;$AS(QtXZ8L{2-p8ufn9Wf9}-fZL62 z?zEDaOLiF|M1_ws^U+ewS@F65mMK8&?C)GH#|90UoR<*!>{&CD;XEJM$3;@xR0;EW zy@6N607=Agsp03rH@8m)XE*rr{Sn+0Eja}(jJEqQb8T|EW zD$i+7m=qzTII> z&vw8q!KSubXiaUJ&&Km;Xz8K>RBli+#GLOoSAPoz-L80u+Mj?M)^jhaAI9I;!U2V9b9A%N&+lLUDckJM<*jvS;)&!7vE2Xzh@ z9vfyd=1-X?#vd>7?xdquwI+n`k~7ymGIE42x{F+8!89Rn{438!^|i1sP|ZfzC%sNS z4I7`o(by96Xfzp{(3U9-=NGmB~3$P0qYXjXXh=SUo9 z_gO@rsfT`X)Iy3-zF01tR1=b6wwU4ddU<>}@6CM%vOl>8gySqfk>-)W$^)6hkM{z7 z#?b{-b|E`+joy&VaEmnpM4nhZs*b~r*tWRNA}UUJ8(`Odv#I5@!vnDvNGZ-=S+SLY&0Lo_WGqF%p9za!N{TiV z)D9sT9bQ)}pGV*{!>Tdx=4A5zeD9#U(|+1rzO6b11nfr5?pyKP#RB5Z1rZf@c&#MM zQ-Va>+W1%cQG><@uLTt=VW)~zqc7t=H_-!r%qusp#po3jXHf#VSOb;?WCrTzL*6Mk zWWA2Mr{j;v{|Z_rA4FJ!#A}P znE1s2069Lx!1EPj$?qr=?U99%4m^zM4Ws(F#4F$VoWVK2xW9k&!(ec6@7CA8te@B` z3CkxM$mEtr*g}Vo(w9xoVJ}1ru_QrcRlH%d$vlA~nf}aPLV0$4kN-YB-tXBz@56;+ z4a-eEo2a#jOv{o3uM*l(>NPVRShDU@G)9_^jTQh`liFBn;d69JEwT3r?rdx|%rfpz z-MjjM@Qu;p&l>B%mfOjkVfGgdbd=)z^xF83@R=hrQMI2hkOrCG`6 z$=p)`aV+Zk*ukP&A2MyoJri)edGcVv|CS#dc7B(PTMnYjJxeXP(|TQolNNI}Dodh`tMFQ>|l*+(M6Z-Q3y;^KkTMV6(k zeuDgF%rC`M3vi9fZ|IXc!MR2U#*f573h2Pyo?xniPzRe}Z$G4nC!}kV`4hZPS_3(E zbTOvs+Qf#}wvGFuc3i*ds1P(0lulU&y^7CBncSL43`9xaW8VlU)-Qkclb>WP2uFW3 zIg36UQguIEc?(a;Ir)&lo|0aH4w(D?LAULZ`qRsa>Arrswc?mg^5@c- z0>c8d&{R`qxq#Jww<2HR`$c4fEbn&dA`I-`W7gX_qba%sc>zUdJW@P761|Wm=f=nxuFiBE{qD-2YUk{gDaU+^MsT4kSO< zpEfxiAIF5~xXd%Q(os2B8-npMYI@B^PdVAoL-{MvF9cjgl)mg?dan3@Ke9M#mS_SD z7?-_xsT1cLeKJcLi=Gwz^PN57Mfv`7SX`dRui5{W%RH)(AyLA&Wxv%QgYm#dg2YSW z06#MMM7G@tE#Bg+ez%B2Zsksnj#l}#!~Do`Ym>}pJp%;c@@#lCc?elgmqvY0BPz>f zu1OO)u)uJgLKHy5INfqVMKj+VIN!64KCnz5NVOyf=B-WGIJvqtk$8Xg0Dk~zk(T`( zG%H0cXpJ4b?#6XrWI#O#Fv3@aO=!zCoY}@J=HPJ3)l}Ksd6vF&ZxEieTb20OaDz05 zqmkyLBW3`a`2+|i04xVI(NE2r4vT;{ zc)6570)AU7UYqf~D+$Wyy>Y#3w!c;KuJGQ_QDdl&39=;TF$>K`d^dURw?jqQl+yEpNuzuwwQR&V znmABG?9}jU^U2NM`h8*rP3`cav5b*+b>MGXS@tDSkIb)Pk3 z$vI6G>>Gp-{rCsG9;Ufp>~(R#bGm;Er6LqVp_>iF_gwtt56gVI9}gI{ zp4jZow47jv)|@jGDZ&k%#mk7p`*CdbOf#=gbG#^qqk9kBRhTT3_E7@q$w+PE7)sC4 zQG#ZsCr~5>dVC+a%`+?Tkp7d*l$OHYrqh1+j~hySIn+J5KKz|@8b9OVKp?=#$h3j} z?fnv_;83PQ{Rs}wMTZKA&fC@&SL>f}Js7L48w%3-@~a8E{0#|u}-n1`^MI|7<~C|Car=U9nl zEzoEz{I#aFi>OJ-*!1)QzKYYGr$l4zlRYHpk3diQ8l&F!n@%IyYLAYjI z%H=eW4A}xbI)ojZ(K**K7-<{(paz3WHPId|1*FuFUd=PlYFXz`m$W@ouj23Wzg04A z%o#kKZrKcl?2PsV2?I}VDwJzey@pcQ3Mf8*&dTGG+cVA5=oG@0V4tH4mpNN?%A0Am zB@L?c(Y55d7sW3{dXBQGIhA*m@)niDw~5}ELqaJb2|!yT(O(Dl!*Pek%hj?@YS94+ z>g6zk@MO5`YF7x;A0c~ftgsedqCWimJ8riMg3fe2ZSKZt-Zhb;NGcxzEq;8%_(=Ut zcaY~LAF+)>=Q^U3H@1Fa>>_yNTuxY%q(&Z2_rBwVt+yhZmaKFM`cJ5UbKTbq)h}u|pqh|n4%ZZguQ_@*cL`+0<Zw;uwh#3 zVmCULG7vA^7MpJ%eUr)1_$}4x33itULk3T`?2pY4Zb{p+td#63`i*_e(c~~@9B1Q@ zyxeNDZd{~4W96F0+hFe5><|pCvvJ)N0w>}0< z37H@Y6E;!`)<1W0pobDYk)&UPXC_aBTi&9D7Zl9Dydw@o>t73w995Y(T@B<%=bW>E zH3Y2&nO8z|yM}nUja?k4a0bL^*pXo5vSm|+M8lhgS`L8AXQwpgbk}7c`LR3~sQ*RfZgETH1v~Q^ed7Qfc{Pd>Wo{h{wANgPIvgE2Ob42%iMe zMPjAP2JIaIl*`$5)T76lzemNwt~$Dn*W^a-esJmUJ|wmD8h$@^X?vkOC-$P}o~3<< zDwf63byjs)pB`Ag{+l??Qy2F+Yhfi|edbl-%9I|7|4i@!Bf#?W_X(@T5xJ-U$awK= z+QW)Asue#xxqmh6bb7D7Zx#+H#vMG0E!F!gZGWq7e~S-Vj1esk-M3%Q5kB%6Y)XNL z3Q^c#CHU5fKOr&9-zrQ7YMjcoVSX*|(_04y6?pPw`1baV>~A?lZ-hDKBSj~IR`#;y z7U@-&>>+@WChQvF_v}bFeZ!jT7kF5HFmhtJD=aVmg23q7$o4vwXQUxICUj6+D}5s# za%~D0q}HPp4T(;d5FG`Bf9AlY;eD?)LrjHRq0C43M$YFUwFzkzoO!Jrd3!iNuMAFh zsry2?jsDEhF$eNg>5vo|JjM?G8Gx{X!R+g1bVpVWq79kfo>)BW8l-p+ceh*L7d<*7 z-TZi@r!klYPrr~yoj8~jPce>Md5H9`X&;l@2XczeYd~^1m$%^>qN5IJ4XNpFkMqu` zM#;4ynx!%(p0ovHTmRZ`$Vf>+se3GY1Mvv?gI~Dvq5^LE3=jPPPo*S34)uPQ>$isM z#tw0!F+zUg-oOgH`7cZ>6xVkPeI)*INO+;?uSk6`xi>g!yL0!Rio`Zl(MHPi)Y(V=c^|#%nW(a^ItUIh7tp6 zLf*RkDN2i!x0ND>*}!{dnymp2(Z zi5)NYw(PRzPjakElpEB}(MFCxM0pp%PIZ85YOtj`BxlIZixnbEjd6Zj%q|B-83uy` zo#m|tqpY7Y6pYG))`#}w{*GSe>9kjJ{+{UH!8j2Z{{glgPR?{5Xwl9Q2> z8EsUBYL{`rSUT?7$drFd|NFp#-$X!~S~!-D!IeS(NIHept9GW5qY#KW)XDK~`AN+E z7kqS(%MX~k@(V}_ZIP43qy9|7#rxoiQ@NHa8RBgJ9kY`_|A@5rY1ZDW$EO5WXQ7Kn z*FS~11M3Xz7IlSwt;J??klNM5jdYPUI2HHrwi!7KQT$>c4fEeGe{b!apW5U0*lK@f zvUQ5_$PGNUn>9~l#BbBBr|xiO82TmfX$_g#T%$;0{JLn(5Ce3qD|xKP7KNs&(!%jy z>X+MjijZ8neNIhbw9g<;^tXTf@cSUVKulNqUrlK*C{a&SWvYp&=V&m@IQDzKb323< za|Ez!W)f%?OB9VgRE6*a3;n&gPyd?pSIjbR;TesdnS-$|F(_(qM`Y$tA#RU*Aq@)T zXoOczG>d;TuB;20bf~4L46=a6DRI&)u>Q=Lw_K&*5qI^bwxD6@x7Loqr#(lAgX@b} z!?Yo~Zv-|B;8-+AU=QJ-3r>!AHA_>U9sDw{`^#zbI92Fv8az(ebyhTwRy})vu}k}J zz`|7uhPq&^C~dl~w(hD1{A2yUUTyFDqOJc;j9F?R$3UPt1ODd4`w@m+h}W7?7`3d~ z@ea)>pjDo@(wG%H*$hb*>G?2R zp3R3E65>Ouc$Uu}MIgq0CPa>iWvA+EMqSuwY4Z8Vhzbp@lQ97$7s{J)#$R4>7Pwtu za;9P~=vcGvTSCg9LJSAuWE~G}!HZ{GxW=mSV{~1}TkOBn);|sTci(Y3aZ50ARFcg= zvx}r~mSrAgqIvSpbsriIXA6zB2o4!3zb!49)TG0E>vBB7$93&(QZY{yz8rAN3tk5f zF1l8O6;808ljM}3c06T0KHp96Jtgc86T~}RdoMb6GUOtdFRP!vCXyGaFGD>>t$b~c zpp1Pa`9s-JMT!5YWsm5S!0XpZVU&N@1C(;*M#7TxGse=(B&59#>4A5;MKwKYqcWY9 zn37}+MlG5Ol*fy}j|}u1`Fj06Bq$hit^5^M0$O^k$%iE_R)}?3y=KoEn+;|o6@ONB za+B=ly1&P6lRCg4%A@;eCN{Ebu+FmLW%aU=(XX|`?hrI|O&+M+^!6>YtT>@c9Kveh z1_t=T4eT1bFmZkW@b(dMB2I>xJ!;4MDg?he!38iX^N_XW?nK7!ERHIUo zRXBlZh&N?dsfn0yi=KviUPf7@P_Z_oe$o}gv;5XDN zdTj_ueq_hF_}r~4%m0$ANAO2W*i)KInrni{L5t)sFA^B$W@j6Odl@Tb+uoK(fdCA4K{oaASw11H*?x#l=JpjEJA&HWK!v|Nyddg zLP`JpFqV?lzv<=jhi4b(3rm!f&XeMb$?PeDpW_kNr1&IBv#--Lt|dhYz?#iQrlzQ5 zEt0~jMZ7JPloX6oQ7Xgnx?(Un~m-*Ew1)kJ0OLNoW}>KxuFJBOU% zV9a0+eRy+bs4VIqPYHo}$S!#n_%I$f?|z2^FgfhX&589P#h~@b@Irxe9z1$4sThou z`mmHCZ=IY_rT_+Xum(K4c-|<0BQLvYX^e6pLfm&`Y!FSkC-WuwJ0EeeHur<=;!4X* zYS6^&ioVtrwW0@40_!XR@HapS3C+^%Hl%KtZGPjpUByWpin6Q-2FIxN;<^=_nqEX4$;Z=Iv+se~V_4+~z z@^E_C*xisxA%Agh%q&ISV4lc7DWYy|qWcS@FK+c{w?*LJ*8SaHV#(Djc@VjC#-gbvmtGA+eqyMnL}Do69wy zocuW3vc_#CT4d(htStWaZpym7 zk&%N7{tWRWUrJ{UIIi5JV~N}=47hpF;{T(o(eN-5AR0Q?*ospGo?wL(Er)8W|M4^- zqcUhKsNhNt$4(0 zw5lqRO}K33=@WV@bCk|oSc7sSTYd$%8V&`JTM+wt^2 zq>yVmKr&k>S$g~A(m>GootA@Fm{qBvmAJ6HO?rwBvgTNTT#JHcc{KzV<1CEA z)NB)HT!(E-PAo#BRQOg2{3}{7jVwaD+{Eb<@E6;)6{Sb}u|N1TczK9CFYBpiW^SEY zzY#d1bjqrg33vqWxPA1OCR#_LtYg z-(A&>%Nyzlfw23Yf>>NktCPz3G|0o>V|#TA&5RG6Q+I6!Qc_U5g>dOSB4$@MsoDF< zjQ4lp4RzaY@`c4vO(0DnR}V;Ace`UT4?Drj_j{00f6lCA93@i8QEM z8-$r4U^C_il)BlHmqK6wm-P%10Iq#S>WK0FhAAQTFWYe)<`n=Kq2~X6E7;%1&7<(! zxPf{F(=AHHYx{OKf;JW0T+oLw($HBVm>w{~{oUw$ELUqYdAXg0md69E=7sA|96TeL z71SM1(zWZRF$==`7+l7-5dd%?a9#xPrvZZHO+R%5|BCH|0mG8CFJw5dFvV0V9U@qd9-%&cj2S-SGu zpEiz1_gC%R54B$?rdx>CD%m*%F`OgzUS(uYUZ-vD9}M0yN1rLT|Enp<0F#LDqAGka zn{}rFk5NN!J}eE&-XHEKv9EYBu9TyyC~6yTb?D>}qOhBr)xx{yJY(n#1^!+E|FTyn zGi#=nB96N5Rg&TM=Qqu_Uq2yF6L2v%xTM6*J%x5r{oRr39}XgsS}OH05=qN~^U7n_ zn+q;*C@ZK{2VQxafn7}z9{_R*d(5uy)7Pg!=m>ymvHFmsg6D?3?+gU|3oE8&qqBm- z1g(DF2SNcL#|xvQ^`pkkT$Cuw;b!Eb;^;Kso5IM&4N=pr>A<}Ki=No=kxpB_jP~1-|uzZ*Y*A5m*(tfCkKLn004lTgFV4j zxb79ca48Ytck4S=k8n}r+In%_n1S3VGMfglqA~+$PzMG%h~`QoQ=`M%X{G>xD2(pz z#q}cX##5LK1bH2U;4xT2HUMC1!DEprp)@WufEGj#GlPAo{SyYIQ_Wy|j7TUF%Z3(A zw~t}d++rNvDKViG92I6^4mIWBg#rv3mki}G4uo;=JTusLUA%C=evE`czeBj8X0X4D z@*+7yZJ2Bt)Chsnr=W~cP-8R#ZD43(VxkAdpwK8J3WG#r^wB1G0}LL8g8q15!fb46 zAl{Wg{EVBM>>wl>hr_LFU@-bZggz%aj7#R}hjFxiDiCNK z3Y*U2(wSk|$32=wL%Py9%m_9`IJiKq^;9gp4Vy;hGTH7-=7FDGbPi^6nVeuI3u@zL z1SOFv^sx2#JDxEFqhk@`=jV)W$hK7d&AAS3F$nUMmL`q6ZT}(_&$639$rMbEE z_P9!OL!1;|%`*Fow}K-kd!!B&p4)yyFa9o{&mWv4pKGUidyNEz?^0$C z(}8BlDj%|^74bU~1bJW7s>GY8yyq;hXhN=0j1DC0FF)QrY;86~1vufLn?fVL(K1aDbce9;Y1Bw z{;;2kj#XHEyjW^nz0420(oD`%cmwv$szs-TQoZ9IP{9GoGH-B9dA>Uf1X+1@nhjcg zciDB`O3GUDY~ECHp2efP!!P@9>?!hE?OV)n%12M0)UO@oi|38o#k;`A64gvXHtQ;c ziqtjje2`XTqe%%o$486l^X`;OBzeFrOAbQq1;)%)AVg#77&ucKH6(ebYFnQ_SiUP# z;45fQi`}U)T)-pr79r!)e6LnyyVY%`R($hN{+fy{^{Kg84&pz2i&D83X)R%X;nAol zrHLxBl>&Js5@IZN-61n{sq2hFm!D_A!b6{k)os`kTsId%8u3mjb)fb?pLMd3P)GJhf9SPj5QJu1} zzHr>q(pM`RyOkZzub{|J@4p9#)l7w-Qg*FJRk^MXOphL!z>3_I}0dz1IybD#E$OkKM&6sDmm48!fmB*a;MitwegC)YtkDF zL>9=9cL3LmPDM36lK$|T!1yj1&`Uwve0PTnqJfc;;8^+etA1djFSbArpoSiqA4nOK zX>*L7yuN#!usKWBQX%Oscq85~5xg_$2{yLM^7Az7)&fzLc<_lSkRap3ko&hmDK~4! zzgv&q&t#TOGFtytJ%vJ?46pkd5-6>ntA1*mD7<-3Z?vB#q+hi>Zz_2}Wd2oaMKV{q z>n*WXGGm~LeX-~Tx<~b%S{chmLhGvK1r<>1f^2hnsS`6ta5`T->q+^?SB2G?bJLf} zLt((KR$#rXrlsY^E*v{GvHl!-c-a1gce2kJvQ9u`zxu4)OuX56_u0#$>Zoq|?G9+a zF4zm>!O0UttH>NTTRS4XVWYCSwXFJy(uI`lMsAB(!lK8?5mt+hnPcyZ>wc+Gb$ z$d|#dUHQ{X1xXRSO^(yIvuj6lT=)9E!GC(%R1M#10!_+l_<*6DP7-}Fdg+pU9MJEq z5mh3G<>4lA59SW6@1*R%j61(!3@If}R_pTxcxL4TcJo)I0E=Bl{?H}$YZ|tI&M_-E z5Y_FQXVRehS3$S=F075_w0F_gYX>GkvOf1IO*e!2w_i$u5~@!rnZ3gpBXjSfUKFBW zhn!1?%eZZS5bo1)xUq2EI6n5*Thm0aSfx!+$Jk)hIz442I*PpA-jA;YoVdl3-{)9 zPp^0T#R2W-bN%b~;j3s(#V$QOJHr^dC>^}^DezKmrM51TIo+c=xktUxKs)rf7@_Vf zy#bcXJyQWs+!ocZWig(>R-6=r$QDF9PK6cAG{T@Fkb3!=&fj<5#Wa>W}}`GiLYxsF>J?@=;F}p7!ulNC(V~*B3}mYEB1BCG;OW{qP&%+{Cl! zUc2C_`1_HK_w)U0FavJEQ5s{U&cB*Xm7l-OtUXaScC=oy)iWHx3)bohi2W-J)0111HIJm<-k-8zZ@f~zK9IOiddeULDq}xoF z4yio5{g!Tg1M`q%Gx?1E#nhU8ecrQs%OmD`)o&)Em=N%0=#xi+b0LUC^+@~41;*2f z9>b>Nt1ZJ!G{+*e)N|2DVMr?2|Y#PKnkW}McHOS#$=?E#X4$_l9x zgz~J#ov^vbsmjiuRx*-Agk-Ub;<$y00009a7bBm000XU z000XU0RWnu7ytkPHfcjcP*7-ZbZ>KLZ*U+R`sCEkzKl)gj5&q@hY_5?)@_euSf22N!q0z{yc?Q2YY_Kym8e z5Fvwu2%hQO!{u_psMvL#(bD64NQRTZj^-}DnS22ry9f-;mW=gZvQj}U-ZdMsK&I8^7~DvX`q=iSi{g7JZ z_pQcB63i4tlp8ecKb(gX8#6Eyhy+A{nS+@6R_8N47Ac;Kd~b0sVgC5~p}WHYh;T;_ zQA8SZ9JHxjt}t}BJngupIQ3XWh1lKc&Vvz= z4B1$mo54)s`M$UW$|&L7YCS0q#4|eUX6r&~t>)JIIA-1_-I*In3If3p3t;9-{O5z~ zM9mCfLi{rT=X(>?tO{!4lYb=_X6HMd%ywa}zRy7@PSA7pNE8_fAohv&~Cw~?nWV3s_1%0+YL&MYKCl2#g^UA3Wh!xVr zfzI>nm3w)^`SPwJW){x?KrA3)sNVR20W1XO1J#@R-~=(2uARh`xoKTX3$+_5DRPNv zZYsX@-o)pAV0pS#Yxn6_BsDmy^#RA`s%mKd3@aL@I*15B1b2h#C-T^1AD;IlS@Tsj zkiR#B$&X#v3LJoV2=!@ukO=0e(~btQKY#v!6O1}N7J}xTbq@IhoD;?o!bMOpXk1{F zQBVo_^K$?W(m{y7SKW$3t{Z^I>CcVLZHSzwgcM3UY7+@^L|x@0uHNMtJH0clrVnLROn{-eyHPo|Wt;9)6%%c8+rgon5lVNh7)2xk59x@8_3Q(A( z7gDzxhZuj$qLo$B^0c4&U9T(f3y_Lvs?eYGpsxSL9W2p53r-)@De`~@Db6>YLA!fF zK!oY4gTu}kg)ci_CmOuNaRcLo`0!_M+UT81v1x%l5thsh`?c}>dv89=`(WZgJcvio zH-egVk*?gWo1kJ&^cMPJIy+xSG}yzwOcjpECE@|SO=v27MFKF3epXqTNb_HHHx8bj z1Fy6QUXXRT-V`5hzYtXx0A1Cmj8(1$C6)Kq2yabgj*{hoUHuge&7SfS3Zdc1+no(n z+H5eZ!`L`cBBUw;*X{87WrW2Crcvvv#1y*L1HMmiRFSt3308Fb*19B#Bwd^^4t{>{ zb52!Q+|Q?J>nFb-_T`Ng3yd2B@Z@+3mdJ%bVXPcsjyG6_+(|lE`Dh6ubrY>`&A=iM z5$L^n%9z_qU~^a8YkdeKO{WB^YVAAdxBfUv`BpWJjcSQas3>%3lfu?R`BWm4@-U$8MwHp8|)QbBPT6NoXkiCJ$@V0o6Op%h1 z19b6>`aVMZ2Jj`g_U9p}C!d3YBwYQO^mh%JIi2aB6X29a_3%BRx0I zB2R>UJ1ymJRVh;qCZ)-!%ESm3m??%iynHSf&=A~wQq z?O7_P7ikusMOEAJd~STss`2JXHaWjf60|QTE`u7i8$(1UwDYsMax=KI4p!7c9undq z&%TMmDkX(}!L2=Y=m6jj=gq99+{~e~P#P!UUO4>G%AZe0 z8Wv#j5S3P6WgfJ^U=Ybr%v?)>@pd!aTP@8d_Gyl+8hh1!$Uu8bS#r>?r_TTFQ8hba zhP3x>578ke2ya$qj~p%ehZT(u>jOjt#S%XJ-z-S`m*aPhmD3;kSg_gG0X^kq z%f%rvW8YK{OC&oJOoP{S3_;pQ7Z0B zO*2Q}^OAehbJ}ULHT3Q%RA<6XgiC=y;7bWBLq-ztV+EywvL+@=r%a_|xH`YcQg{z@zk2Y;ml7?{^ zZM!}fW83fP1rzuA711DK@Ck2P)s`N%ww$AEaSDh8{;gOl7b%k;0Pg)f3&H9qZ5|x@ zb+q)`ZlxymlT-5CE)j5Vq(q@>^}aZ**A0rqlt4;@7nVe2*|-J7L=-mdoCLL6Dc2&j zWLhp%5jl0++Pt^+l{>WjO9R7K8`N7fmr*ylNRLRVjcXclO?)~Hq#-`-RDq)rY zCQWvD6K*1c9Kk#Oz!4(dEm&yTq~Vj(0G{24QBH3;lDDC~YU}i{Xf*`5$%UqQ*rsDn z3(RZj=|;q@N_Rk7K@Ga*4e5lKq&`(Glh1y&Nw=iqCLMUV_qRvA=SIe5^kwQ5JDLW- z&(COKO~+iBGi51 z8l2hb5kKd=z5C2^yduQf9^O5$Qf6e<`)YASi%gVZh7Cgg-Ri6^V$|Yu!g^_~ngro( zV$m}>@KRO+x-E;|_@=ueQ6=i8rgbV$535}5okp9|ni&ojC@>KqJPfOFlzEhL~{dYDXKo@RE1_dKt|MTh#nsOHuKO5Y|GDzz#VPly;+qvTAuTu+t#dD zQvoH)ZM9ap8eX*8D%B2I0|rb9RLc|Fc5JO9#hE1H!l#1j)V6+)UL7H0cpD@Z&k|wsu2I8iSPW^%#K*?h z(=^Ag8LvnoYGnpcyQ`b#HjtsBie6wNYW}UNfzs9^2GlLnZRn}qIApG&%{Ay^j)dVJ zABw4*H;-sVNtLj`gc_glc0-?Gx1Jo}XMBm79)uPacpngT%f?g_JG0%od%Q6O;_W?I z+qOw3K~3sAFH1?K=VcZTs1e3NbLaESf!Jf^o`UN#&Py2hmV?;CqqI5;gVf$(MgVEk&z_S`hlHO9aWF~agle`? zw;|VJg}+)cB_riwfivgj``5*|z~O zWPhBJJ)p9=EpdqVP5m}ms6JP9Knj?cdBzkSYZ&#N7^F4W0;(D6eBBO#?jqKMv%c=h zfC`oRQ~jIWl0lB|2T*Yj%FL!_D0J|G*0epnw$Mtg>Nsw*qEywM+1j(#X7d^zb79X? z`RGf$a}@iwBIn*=@Ml&8{z$gn1JazC?y-hIZDxdJbQAPa z-PNF|(`&m}*THuRb_T$5fSakqeoMm28P(f4*aK#!AtY9N^?NL$fu~YOKLZ*U+R`sCEkzKl)gj5&q@hY_5?)@_euSf22N!q0z{yc?Q2YY_Kym8e z5Fvwu2%hQO!{u_psMvL#(bD64NQRTZj^-}DnS22ry9f-;mW=gZvQj}U-ZdMsK&I8^7~DvX`q=ii|OLO+rIyV)MLgDrDUTUJRV>T za@p!w2C%B;w|Pc-HA0XeX?d5L-1&rybtMUozAiex>Jcp_Wt$3vPIRE7?W}XLd`Xl~ zbWb^Bv3FNL-6_SW=2CrT6cUb(rMs`)*jL(gI(-P<)}wibeWEu@BmV;clj%B0q6v+& P00000NkvXXu0mjfThRhE literal 0 HcmV?d00001 diff --git a/node_modules/ace/api/resources/images/dashed_back.png b/node_modules/ace/api/resources/images/dashed_back.png new file mode 100644 index 0000000000000000000000000000000000000000..c6ee9313f2d636546a778425ff998e839f05624f GIT binary patch literal 3445 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 XM~`vmQcs7_00000NkvXXu0mjfem-^= literal 0 HcmV?d00001 diff --git a/node_modules/ace/api/resources/images/footer-bg.png b/node_modules/ace/api/resources/images/footer-bg.png new file mode 100644 index 0000000000000000000000000000000000000000..0d572c2809916d5279032187efd1863651024884 GIT binary patch literal 1090 zcmaJ=TSyd97@jWLwjphyK|Y-w!3y1-%eK4j;HJAfySm}Xwk~J|(KvI|VVybC%+Xz? z2NMm2C_xAVDJY{Ls;5Hmq0C-{dgv+WAt<7!KmjMD460vS8Y3=P&HI3J};rh23dNFWP> zpr7?AY={LR&d&vohr{7Uz_T37usp-@J}xW-c!6cX#z&KAmf9y|#neVDGKc<=Kf^^L5l4gPeFWjNM+__%eTH3ERuG}BSel77WB^A|?nOg5N)xB06m)Y_ z*048@i5wVHlud^7vrbB7pd|ets_UC*8)xBPzgr61xe*gGS!kmnOCcB6SLcK>g@grV zjI10&gXL4q3?Pi`0c3(iR}e_Dq8ZM79WO~j+OV-~C@?KXX`72r75|+ml9Xq!b>TSrqs4vhL~ZTi~Z-K%S)tsoZ)8KlF4S_LxWViMasHj z?D9SGB%Y?lSg!c)%iHCu72v6O(>T`<&z$^$s^%*%eoKvZy}0^WX6txV@afk38T;4$hTRjMopINt$BmO? zp4p1YRNr$=+jDfnGuK#JXHS#Oi80SLp|nX5*W;~ItK)Ik^3v>+ q@52?yb#p3mr0&MV70#7@>3dG)&xIEj=RPhtuR5LV6d%RUkN*LJOIQW~ literal 0 HcmV?d00001 diff --git a/node_modules/ace/api/resources/images/main_bg.png b/node_modules/ace/api/resources/images/main_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..f26aefc2af41d6a77b1c5caa18f50cbe26e5990a GIT binary patch literal 9630 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 U(??5`rT_o{07*qoM6N<$f-EzwH~;_u literal 0 HcmV?d00001 diff --git a/node_modules/ace/api/resources/images/member-sprites.png b/node_modules/ace/api/resources/images/member-sprites.png new file mode 100644 index 0000000000000000000000000000000000000000..96b0520fd70a6299d27e188d1090606c78b3c72a GIT binary patch literal 3505 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 literal 0 HcmV?d00001 diff --git a/node_modules/ace/api/resources/images/menu_disc.png b/node_modules/ace/api/resources/images/menu_disc.png new file mode 100644 index 0000000000000000000000000000000000000000..1d3925b3f103cb7d1d2ccb34251cb2543f936f2e GIT binary patch literal 556 zcmV+{0@MA8P)KLZ*U+R`sCEkzKl)gj5&q@hY_5?)@_euSf22N!q0z{yc?Q2YY_Kym8e z5Fvwu2%hQO!{u_psMvL#(bD64NQRTZj^-}DnS22ry9f-;mW=gZvQj}U-ZdMsK&I8^7~DvX`q=inIVXE>RF&gA_=FG; u5mXfsK}5K&3+cUYfYusjMvM_v&>- literal 0 HcmV?d00001 diff --git a/node_modules/ace/api/resources/images/method_bg.png b/node_modules/ace/api/resources/images/method_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..b018955737a730de52f23bc8fd39786ffe7cd9d0 GIT binary patch literal 8001 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 N002ovPDHLkV1g96i!uNJ literal 0 HcmV?d00001 diff --git a/node_modules/ace/api/resources/images/sidebar-top-bg.png b/node_modules/ace/api/resources/images/sidebar-top-bg.png new file mode 100644 index 0000000000000000000000000000000000000000..c0a800e1f8ac0b7cba486dba48441f5cfaaca8be GIT binary patch literal 2693 zcmaJ@c{r47AD)mURCE%9&KQL(vogjsgjpXhEv2IGNHi%+mV_*sV>#)JPIbONzP|Um-uHQa&voDTZ+))o&G7Yh(_RBz z1A#!aJ>1FuiuG5;yG~t6@wGp&z)&m(AcY3*=0<=bIv;?zgmc3HmK!4gu{0@!H6*gg#a4>>981fG)F*)afE-;B`EeQ$4EHr z69kNMg#R5B&C3@?;_?BQ9Rg*;K;cj@92$Yf+S=ROTf;CYGzy8rAki2bv^@cfA)rvO z&ktPTjUOIC@F!D0`%+kr@JJBk5s*lcNQ4k!5nTR3B-+8jVMPOju~8sw1hE{D9%I81 zn0`?p0|Ex0$pe{O4s1n{9>x`dj&Mb!f2Y9aeU;@1K9@;RFk}p!heRV#D=B>edU^eS zD4YEiEdc$2f8zb0!h(QU9)R=*1Y9AXp=ex$>53~Jfy4*sAeSG&^vH=eGg&Y147xPW-$|$gT3eRMK&pZT#Q~6vr>{H4F<~L)p zqkdEGGdKL(v7o-mMJj?pt~B<)8vW%+F+D5WuVbq)z79UXQA|5uG1fCf3)&Ef>VgN^ zB_QT`=jk4nk;i&U@V@AeACYTRT-WKU8wAN7?)iRUUN@*$eV92`()##;SUg81%MS^K z)ofW!+{;(5u(LBWGar^j5kG{4UO1I8>z2nHAp$~QNdNZwY z`D|~#3bD$+lX5d$_Xd!2?AGc+l4Vxoolu{N(e->oR#C%sJyaX-1(C#fG_lmLfi-az zZ(FVzy8n~jIfLYbc4}t#jL{c0@wU>LE@ixJmJoT^nDT~Y%q5pr=GrH76&K&aeI%7Y zZq}V!TQ1Hm1T4NIq7wV0l^6E>Zc?=Bg%~EkpJB3@F({b0i)qKFxq22y+0+?tCN5+5 zE~}qU<&$6X$^;{zH$BiI{TjaBTNxPEX-d}}3)P?qA)pbdxY*QM7IgA4?7q47y~Vm? zTa!E;?Qh*|$XKtuOlpzI_IDYmJh$6t3Kn=8o*}04DQ5FO3yG@8loL)#eu9B1PAoem zI*oL5xpTI{#xlJoC0cN*l+<*8T3^`}yhv=Pu*$0mR*2;711$Y)m$alKi6%!Ymm(9C zux8Ma?HE5zm+O~1J@3qkE3=rZBu;$a@Wy?*nYDNIpD0akg|6lA+A{8ovUOwGekj|m z%eu%eZ8De6Og62$6zQIyJe!`V(XTD9&}+yZzoF#QE~;{9A$lck@DP-q@bmNW@iEo7 zy55SV8(nH7uIo3^e7=iTo1a)z{w&i!V#NFGc{8{50V(zilh?T6o$?lQUlsG*yzWFj z6cN@kJ$1Pe`oMi=cBK9G+><0%m7{_3v3Kju-QK3nkG$U#Jsk(xa-|b#S zvUp6%Cse&`EXdWXSz1~;-nL2hXl05xu1TV(;x-?*TE|uHcfUxGh9d{d*36 zODY?)*_u8s+3jxnA!w@cHGZfYdmv?kWYVW*R!M|RNS2Y z`y)S7tG9DI+OKcP>6dV%QmJ7^=~>c={UivA@Xtq4hd6P@VnrUXe%=w~ZEOYaW$K)P{|X)@I)m)yMVWrJXt{vTGr?>jYTZ#y#`K z+9k!cnNE8<-p@fFGROTaB2hgRCPt4Q6MCo<&f|tRIJTbb)9$QDncpG$v*FyD zW|T$LmUF>ZplOrK*r$%kD25qMqk#5ou*);6Ry**}&OoLLx+@uv_pGk!YBj&3pE`J4 zR-Bf#{f2G_Ce(kmd`OR4`J!?QbQ7+~y&8px#u58$k4#F`&8Gw}{ND{6lpNOCVK-I> zT?`2}l(S`lSGAi@ZFqKcBKG1n?ckn-uAPeH8?8~;_v@j^FWM>ROt% zM`#8ii=Cmhmz{dAWYQBk>1EDJKWkF${Wq5wS%AbG1Ew+U<4-YH?ikHq+YnW!uM!;E q{jpaa61jM9fI=A43m{H~Fe-X!2h!YK=+& literal 0 HcmV?d00001 diff --git a/node_modules/ace/api/resources/images/sidebar_border.png b/node_modules/ace/api/resources/images/sidebar_border.png new file mode 100644 index 0000000000000000000000000000000000000000..ea6cd700be849c020b74c06ca2c4ed521b744cd6 GIT binary patch literal 2967 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 LQ|<2BoVog6l3=FD literal 0 HcmV?d00001 diff --git a/node_modules/ace/api/resources/images/swirl_divider.png b/node_modules/ace/api/resources/images/swirl_divider.png new file mode 100644 index 0000000000000000000000000000000000000000..f3e9f6c6af3c18fc84c25594f3434d1a1031d209 GIT binary patch literal 1043 zcmV+u1nm2XP)R?59o%`Dv8?v^mBYql_}fD5H#NI5wfv&DMR<8C9Dp z{b^e^v-L~bZ0nk)O`A)u`Tjk3d*_zexpnOpD_QReFPGfsbI(Jc>&NrlJ%{E(Q9;-b z9q7jm45JSYQ`~`G3_->K4qMvj#%0L3g428Sc?1%?7=+vCM~sE=8@jGH&GvshVPEvm zuSH*c-P)d9kEdq7Y^sZ#)A0eP(1UxQBkI!)H9fhqwH=%fMT?wM(2p*R2i9YcR+Yqy zZ_&iU!kUt)xA76(mi`I!|$Xw#$v$P9b~8475=|Z&~7<%s`id#Onq0IY);j=j?VSUp1~rWIO$` z*6tqvAf2&P?h}RfjNQjb__xKg9WE0$qyxqa*~Z4;Z$bjPjm6<_f)BEdc_AGzZn#X^ zjoAQPCT>Uvj2E(vjlti91pfF_TT(MC{F788@5l4asGiOje~ITyWjzp%89BT((sRYK zLDPQbD5v*FmAX^+HF5=7yccVKFx2r7#*fEcGAMZ(64*XE2`5HQG=)9{XK?JWIX9BLR=y z$4C&*JcZW05!;wiE;E~4F})49I*D1{jz1*dXL^HPfV4vaO|a#tk>i8Yl5=rgO_>X5 z&klXM>2H$UHoK3JAd08Zx;LYT<@*K&Z;RhS$nZkODlcsUxnk)(dHwbL>&aX}XU3|T z_HkZ=gyF?-Y=-uV>=|to&=9Ub!Vo5yeNNSu{_OFr@H>kUNOeB8PL0yffZfMN5XDny z{TtHFp39J$&Tp>8k{@cD*4ZrohCP=NVt({k3oef`!?hwxp2DX2cOfPDh&SX9iA~}x zX1QLECbKGq^fhfhF-K@?BnKU%_L z05>3G2*-EHcff<2kTHlpOU_ALhK#H5z-eit4').hide().insertAfter("body")[0].contentWindow;q=function(){return a(n.document[c][l])};o=function(u,s){if(u!==s){var t=n.document;t.open().close();t[c].hash="#"+u}};o(a())}}m.start=function(){if(r){return}var t=a();o||p();(function s(){var v=a(),u=q(t);if(v!==t){o(t=v,u);$(i).trigger(d)}else{if(u!==t){i[c][l]=i[c][l].replace(/#.*/,"")+"#"+u}}r=setTimeout(s,$[d+"Delay"])})()};m.stop=function(){if(!n){r&&clearTimeout(r);r=0}};return m})()})(jQuery,this); \ No newline at end of file diff --git a/node_modules/ace/api/resources/javascripts/bootstrap.js b/node_modules/ace/api/resources/javascripts/bootstrap.js new file mode 100644 index 00000000..79241e74 --- /dev/null +++ b/node_modules/ace/api/resources/javascripts/bootstrap.js @@ -0,0 +1,389 @@ +/* ============================================================ + * bootstrap-dropdown.js v2.1.1 + * http://twitter.github.com/bootstrap/javascript.html#dropdowns + * ============================================================ + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* DROPDOWN CLASS DEFINITION + * ========================= */ + + var toggle = '[data-toggle=dropdown]' + , Dropdown = function (element) { + var $el = $(element).on('click.dropdown.data-api', this.toggle) + $('html').on('click.dropdown.data-api', function () { + $el.parent().removeClass('open') + }) + } + + Dropdown.prototype = { + + constructor: Dropdown + + , toggle: function (e) { + var $this = $(this) + , $parent + , isActive + + if ($this.is('.disabled, :disabled')) return + + $parent = getParent($this) + + isActive = $parent.hasClass('open') + + clearMenus() + + if (!isActive) { + $parent.toggleClass('open') + $this.focus() + } + + return false + } + + , keydown: function (e) { + var $this + , $items + , $active + , $parent + , isActive + , index + + if (!/(38|40|27)/.test(e.keyCode)) return + + $this = $(this) + + e.preventDefault() + e.stopPropagation() + + if ($this.is('.disabled, :disabled')) return + + $parent = getParent($this) + + isActive = $parent.hasClass('open') + + if (!isActive || (isActive && e.keyCode == 27)) return $this.click() + + $items = $('[role=menu] li:not(.divider) a', $parent) + + if (!$items.length) return + + index = $items.index($items.filter(':focus')) + + if (e.keyCode == 38 && index > 0) index-- // up + if (e.keyCode == 40 && index < $items.length - 1) index++ // down + if (!~index) index = 0 + + $items + .eq(index) + .focus() + } + + } + + function clearMenus() { + getParent($(toggle)) + .removeClass('open') + } + + function getParent($this) { + var selector = $this.attr('data-target') + , $parent + + if (!selector) { + selector = $this.attr('href') + selector = selector && /#/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + $parent.length || ($parent = $this.parent()) + + return $parent + } + + + /* DROPDOWN PLUGIN DEFINITION + * ========================== */ + + $.fn.dropdown = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('dropdown') + if (!data) $this.data('dropdown', (data = new Dropdown(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.dropdown.Constructor = Dropdown + + + /* APPLY TO STANDARD DROPDOWN ELEMENTS + * =================================== */ + + $(function () { + $('html') + .on('click.dropdown.data-api touchstart.dropdown.data-api', clearMenus) + $('body') + .on('click.dropdown touchstart.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() }) + .on('click.dropdown.data-api touchstart.dropdown.data-api' , toggle, Dropdown.prototype.toggle) + .on('keydown.dropdown.data-api touchstart.dropdown.data-api', toggle + ', [role=menu]' , Dropdown.prototype.keydown) + }) + +}(window.jQuery); +/* ======================================================== + * bootstrap-tab.js v2.1.1 + * http://twitter.github.com/bootstrap/javascript.html#tabs + * ======================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================== */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* TAB CLASS DEFINITION + * ==================== */ + + var Tab = function (element) { + this.element = $(element) + } + + Tab.prototype = { + + constructor: Tab + + , show: function () { + var $this = this.element + , $ul = $this.closest('ul:not(.dropdown-menu)') + , selector = $this.attr('data-target') + , previous + , $target + , e + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + if ( $this.parent('li').hasClass('active') ) return + + previous = $ul.find('.active a').last()[0] + + e = $.Event('show', { + relatedTarget: previous + }) + + $this.trigger(e) + + if (e.isDefaultPrevented()) return + + $target = $(selector) + + this.activate($this.parent('li'), $ul) + this.activate($target, $target.parent(), function () { + $this.trigger({ + type: 'shown' + , relatedTarget: previous + }) + }) + } + + , activate: function ( element, container, callback) { + var $active = container.find('> .active') + , transition = callback + && $.support.transition + && $active.hasClass('fade') + + function next() { + $active + .removeClass('active') + .find('> .dropdown-menu > .active') + .removeClass('active') + + element.addClass('active') + + if (transition) { + element[0].offsetWidth // reflow for transition + element.addClass('in') + } else { + element.removeClass('fade') + } + + if ( element.parent('.dropdown-menu') ) { + element.closest('li.dropdown').addClass('active') + } + + callback && callback() + } + + transition ? + $active.one($.support.transition.end, next) : + next() + + $active.removeClass('in') + } + } + + + /* TAB PLUGIN DEFINITION + * ===================== */ + + $.fn.tab = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('tab') + if (!data) $this.data('tab', (data = new Tab(this))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.tab.Constructor = Tab + + + /* TAB DATA-API + * ============ */ + + $(function () { + $('body').on('click.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) { + e.preventDefault() + $(this).tab('show') + }) + }) + +}(window.jQuery); +/* ========================================================== + * bootstrap-affix.js v2.1.1 + * http://twitter.github.com/bootstrap/javascript.html#affix + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* AFFIX CLASS DEFINITION + * ====================== */ + + var Affix = function (element, options) { + this.options = $.extend({}, $.fn.affix.defaults, options) + this.$window = $(window).on('scroll.affix.data-api', $.proxy(this.checkPosition, this)) + this.$element = $(element) + this.checkPosition() + } + + Affix.prototype.checkPosition = function () { + if (!this.$element.is(':visible')) return + + var scrollHeight = $(document).height() + , scrollTop = this.$window.scrollTop() + , position = this.$element.offset() + , offset = this.options.offset + , offsetBottom = offset.bottom + , offsetTop = offset.top + , reset = 'affix affix-top affix-bottom' + , affix + + if (typeof offset != 'object') offsetBottom = offsetTop = offset + if (typeof offsetTop == 'function') offsetTop = offset.top() + if (typeof offsetBottom == 'function') offsetBottom = offset.bottom() + + affix = this.unpin != null && (scrollTop + this.unpin <= position.top) ? + false : offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ? + 'bottom' : offsetTop != null && scrollTop <= offsetTop ? + 'top' : false + + if (this.affixed === affix) return + + this.affixed = affix + this.unpin = affix == 'bottom' ? position.top - scrollTop : null + + this.$element.removeClass(reset).addClass('affix' + (affix ? '-' + affix : '')) + } + + + /* AFFIX PLUGIN DEFINITION + * ======================= */ + + $.fn.affix = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('affix') + , options = typeof option == 'object' && option + if (!data) $this.data('affix', (data = new Affix(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.affix.Constructor = Affix + + $.fn.affix.defaults = { + offset: 0 + } + + + /* AFFIX DATA-API + * ============== */ + + $(window).on('load', function () { + $('[data-spy="affix"]').each(function () { + var $spy = $(this) + , data = $spy.data() + + data.offset = data.offset || {} + + data.offsetBottom && (data.offset.bottom = data.offsetBottom) + data.offsetTop && (data.offset.top = data.offsetTop) + + $spy.affix(data) + }) + }) + + +}(window.jQuery); \ No newline at end of file diff --git a/node_modules/ace/api/resources/javascripts/clicker.js b/node_modules/ace/api/resources/javascripts/clicker.js new file mode 100644 index 00000000..90e7e12c --- /dev/null +++ b/node_modules/ace/api/resources/javascripts/clicker.js @@ -0,0 +1,69 @@ +function setupClicker() { + // when hovering over arrow, add highlight (only if inactive) + $("i.methodToggle").hover(function () { + if (!$("i.methodToggle").hasClass('active')) + $(this).addClass("methodToggleHover"); + }, + function () { + $(this).removeClass("methodToggleHover"); + } + ); + + function handleClick(e, linkHref) { + //if (linkHref.indexOf("nav=api&api=") >= 0) + // return; + if (linkHref == "api") + return; + + e.preventDefault(); + + var dstElem; + if (linkHref) { + dstElem = $("article[id='" + linkHref + "']"); + } + + var $article = (dstElem || $(this)).closest('.article'), + $arrow = $('i.methodClicker', $article); + + if (!$article.hasClass('methodToggleOpen') || this.force) { + $article.addClass('methodToggleOpen'); + $arrow.removeClass('inactive').addClass('active'); + + if (!$arrow[0]) + return; + + var data = $arrow[0].id.replace(/^js_/, ""); + //var state = {}; + //state.section = data; + //$.bbq.pushState(state); + + scrollTo(null, data); + } + else { + $article.removeClass('methodToggleOpen'); + $arrow.removeClass('active').addClass('inactive'); + } + } + + function transformHash(e) { + // some bs to figure out link hash + var hashId = (e.srcElement ? e.srcElement.href : (e.hash || e.target.href)) || e.currentTarget.hash; + + handleClick(e, hashId.substring(hashId.indexOf("#") + 1)); + } + + // for the arrow + $("i.methodToggle").click(handleClick); + + // for the signature + $('.member-name').click(handleClick); + + // for the top dropdown + $('li.memberLink a').click(transformHash); + + //$('a[href^="#"]').click(transformHash); + + $('.related-to', '.metaInfo').click(function(){ + location.hash = $(this).find('a').attr('href').split('#')[1]; + }); +} \ No newline at end of file diff --git a/node_modules/ace/api/resources/javascripts/disqus-ext.js b/node_modules/ace/api/resources/javascripts/disqus-ext.js new file mode 100644 index 00000000..6bb7ff4e --- /dev/null +++ b/node_modules/ace/api/resources/javascripts/disqus-ext.js @@ -0,0 +1,17 @@ +function setupDisqus(href) { + var disqus_shortname = 'aceapi'; + + //var paths = window.location.pathname.split("/"); + //var fileName = paths[paths.length - 2] + "/" + paths[paths.length - 1]; + + //var disqus_identifier = fileName; + var disqus_identifier = href.substring(2); + + (function() { + if (document.getElementById("disqusScript") === null) { + var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; + dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; + (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); + } + })(); +} \ No newline at end of file diff --git a/node_modules/ace/api/resources/javascripts/jquery-scrollspy.js b/node_modules/ace/api/resources/javascripts/jquery-scrollspy.js new file mode 100644 index 00000000..71b4a363 --- /dev/null +++ b/node_modules/ace/api/resources/javascripts/jquery-scrollspy.js @@ -0,0 +1,98 @@ +/*! + * jQuery Scrollspy Plugin + * Author: @sxalexander + * Licensed under the MIT license + */ + + +;(function ( $, window, document, undefined ) { + + $.fn.extend({ + scrollspy: function ( options ) { + + var defaults = { + min: 0, + max: 0, + mode: 'vertical', + buffer: 0, + container: window, + onEnter: options.onEnter ? options.onEnter : [], + onLeave: options.onLeave ? options.onLeave : [], + onTick: options.onTick ? options.onTick : [] + } + + var options = $.extend( {}, defaults, options ); + + return this.each(function (i) { + + var element = this; + var o = options; + var $container = $(o.container); + var mode = o.mode; + var buffer = o.buffer; + var enters = leaves = 0; + var inside = false; + + /* add listener to container */ + $container.bind('scroll', function(e){ + var position = {top: $(this).scrollTop(), left: $(this).scrollLeft()}; + var xy = (mode == 'vertical') ? position.top + buffer : position.left + buffer; + var max = o.max; + var min = o.min; + + /* fix max */ + if($.isFunction(o.max)){ + max = o.max(); + } + + /* fix max */ + if($.isFunction(o.min)){ + min = o.min(); + } + + if(max == 0){ + max = (mode == 'vertical') ? $container.height() : $container.outerWidth() + $(element).outerWidth(); + } + + /* if we have reached the minimum bound but are below the max ... */ + if(xy >= o.min && xy <= max){ + /* trigger enter event */ + if(!inside){ + inside = true; + enters++; + + /* fire enter event */ + $(element).trigger('scrollEnter', {position: position}) + if($.isFunction(o.onEnter)){ + o.onEnter(element, position); + } + + } + + /* triger tick event */ + $(element).trigger('scrollTick', {position: position, inside: inside, enters: enters, leaves: leaves}) + if($.isFunction(o.onTick)){ + o.onTick(element, position, inside, enters, leaves); + } + }else{ + + if(inside){ + inside = false; + leaves++; + /* trigger leave event */ + $(element).trigger('scrollLeave', {position: position, leaves:leaves}) + + if($.isFunction(o.onLeave)){ + o.onLeave(element, position); + } + } + } + }); + + }); + } + + }) + + +})( jQuery, window ); diff --git a/node_modules/ace/api/resources/javascripts/jquery.collapse.js b/node_modules/ace/api/resources/javascripts/jquery.collapse.js new file mode 100644 index 00000000..427ee5fa --- /dev/null +++ b/node_modules/ace/api/resources/javascripts/jquery.collapse.js @@ -0,0 +1,151 @@ +/*! + * Collapse plugin for jQuery + * http://github.com/danielstocks/jQuery-Collapse/ + * + * @author Daniel Stocks (http://webcloud.se) + * @version 0.9.1 + * @updated 17-AUG-2010 + * + * Copyright 2010, Daniel Stocks + * Released under the MIT, BSD, and GPL Licenses. + */ + +(function($) { + + // Use a cookie counter to allow multiple instances of the plugin + var cookieCounter = 0; + + $.fn.extend({ + collapse: function(options) { + + var defaults = { + head : "h3", + group : "div, ul", + cookieName : "collapse", + // Default function for showing content + show: function() { + this.show(); + }, + // Default function for hiding content + hide: function() { + this.hide(); + } + }; + var op = $.extend(defaults, options); + + // Default CSS classes + var active = "active", + inactive = "inactive"; + + return this.each(function() { + + // Increment coookie counter to ensure cookie name integrity + cookieCounter++; + var obj = $(this), + // Find all headers and wrap them in for accessibility. + sections = obj.find(op.head).wrapInner(''), + l = sections.length, + cookie = op.cookieName + "_" + cookieCounter; + // Locate all panels directly following a header + var panel = obj.find(op.head).map(function() { + var head = $(this) + if(!head.hasClass(active)) { + return head.next(op.group).hide()[0]; + } + return head.next(op.group)[0]; + }); + + // Bind event for showing content + obj.bind("show", function(e, bypass) { + var obj = $(e.target); + // ARIA attribute + obj.attr('aria-hidden', false) + .prev() + .removeClass(inactive) + .addClass(active); + // Bypass method for instant display + if(bypass) { + obj.show(); + } else { + op.show.call(obj); + } + }); + + // Bind event for hiding content + obj.bind("hide", function(e, bypass) { + var obj = $(e.target); + obj.attr('aria-hidden', true) + .prev() + .removeClass(active) + .addClass(inactive); + if(bypass) { + obj.hide(); + } else { + op.hide.call(obj); + } + }); + + // Look for existing cookies + if(cookieSupport) { + for (var c=0;c<=l;c++) { + var val = $.cookie(cookie + c); + // Show content if associating cookie is found + if ( val == c + "open" ) { + panel.eq(c).trigger('show', [true]); + // Hide content + } else if ( val == c + "closed") { + panel.eq(c).trigger('hide', [true]); + } + } + } + + // Delegate click event to show/hide content. + obj.bind("click", function(e) { + var t = $(e.target); + // Check if header was clicked + if(!t.is(op.head)) { + // What about link inside header. + if ( t.parent().is(op.head) ) { + t = t.parent(); + } else { + return; + } + e.preventDefault(); + } + // Figure out what position the clicked header has. + var num = sections.index(t), + cookieName = cookie + num, + cookieVal = num, + content = t.next(op.group); + // If content is already active, hide it. + if(t.hasClass(active)) { + content.trigger('hide'); + cookieVal += 'closed'; + if(cookieSupport) { + $.cookie(cookieName, cookieVal, { path: '/', expires: 10 }); + } + return; + } + // Otherwise show it. + content.trigger('show'); + cookieVal += 'open'; + if(cookieSupport) { + $.cookie(cookieName, cookieVal, { path: '/', expires: 10 }); + } + }); + }); + } + }); + + // Make sure can we eat cookies without getting into trouble. + var cookieSupport = (function() { + try { + $.cookie('x', 'x', { path: '/', expires: 10 }); + $.cookie('x', null); + } + catch(e) { + return false; + } + return true; + })(); +})(jQuery); \ No newline at end of file diff --git a/node_modules/ace/api/resources/javascripts/jquery.cookie.js b/node_modules/ace/api/resources/javascripts/jquery.cookie.js new file mode 100644 index 00000000..6df1faca --- /dev/null +++ b/node_modules/ace/api/resources/javascripts/jquery.cookie.js @@ -0,0 +1,96 @@ +/** + * Cookie plugin + * + * Copyright (c) 2006 Klaus Hartl (stilbuero.de) + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + * + */ + +/** + * Create a cookie with the given name and value and other optional parameters. + * + * @example $.cookie('the_cookie', 'the_value'); + * @desc Set the value of a cookie. + * @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true }); + * @desc Create a cookie with all available options. + * @example $.cookie('the_cookie', 'the_value'); + * @desc Create a session cookie. + * @example $.cookie('the_cookie', null); + * @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain + * used when the cookie was set. + * + * @param String name The name of the cookie. + * @param String value The value of the cookie. + * @param Object options An object literal containing key/value pairs to provide optional cookie attributes. + * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object. + * If a negative value is specified (e.g. a date in the past), the cookie will be deleted. + * If set to null or omitted, the cookie will be a session cookie and will not be retained + * when the the browser exits. + * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie). + * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie). + * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will + * require a secure protocol (like HTTPS). + * @type undefined + * + * @name $.cookie + * @cat Plugins/Cookie + * @author Klaus Hartl/klaus.hartl@stilbuero.de + */ + +/** + * Get the value of a cookie with the given name. + * + * @example $.cookie('the_cookie'); + * @desc Get the value of a cookie. + * + * @param String name The name of the cookie. + * @return The value of the cookie. + * @type String + * + * @name $.cookie + * @cat Plugins/Cookie + * @author Klaus Hartl/klaus.hartl@stilbuero.de + */ +jQuery.cookie = function(name, value, options) { + if (typeof value != 'undefined') { // name and value given, set cookie + options = options || {}; + if (value === null) { + value = ''; + options.expires = -1; + } + var expires = ''; + if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) { + var date; + if (typeof options.expires == 'number') { + date = new Date(); + date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000)); + } else { + date = options.expires; + } + expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE + } + // CAUTION: Needed to parenthesize options.path and options.domain + // in the following expressions, otherwise they evaluate to undefined + // in the packed version for some reason... + var path = options.path ? '; path=' + (options.path) : ''; + var domain = options.domain ? '; domain=' + (options.domain) : ''; + var secure = options.secure ? '; secure' : ''; + document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join(''); + } else { // only name given, get cookie + var cookieValue = null; + if (document.cookie && document.cookie != '') { + var cookies = document.cookie.split(';'); + for (var i = 0; i < cookies.length; i++) { + var cookie = jQuery.trim(cookies[i]); + // Does this cookie string begin with the name we want? + if (cookie.substring(0, name.length + 1) == (name + '=')) { + cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); + break; + } + } + } + return cookieValue; + } +}; \ No newline at end of file diff --git a/node_modules/ace/api/resources/javascripts/plugins.js b/node_modules/ace/api/resources/javascripts/plugins.js new file mode 100644 index 00000000..efda459c --- /dev/null +++ b/node_modules/ace/api/resources/javascripts/plugins.js @@ -0,0 +1,13 @@ +window.log=function(){log.history=log.history||[];log.history.push(arguments);if(this.console){arguments.callee=arguments.callee.caller;var a=[].slice.call(arguments);(typeof console.log==="object"?log.apply.call(console.log,console,a):console.log.apply(console,a))}}; +(function(b){function c(){}for(var d="assert,count,debug,dir,dirxml,error,exception,group,groupCollapsed,groupEnd,info,log,timeStamp,profile,profileEnd,time,timeEnd,trace,warn".split(","),a;a=d.pop();){b[a]=b[a]||c}})((function(){try +{console.log();return window.console;}catch(err){return window.console={};}})()); + +/* + * jQuery throttle / debounce - v1.1 - 3/7/2010 + * http://benalman.com/projects/jquery-throttle-debounce-plugin/ + * + * Copyright (c) 2010 "Cowboy" Ben Alman + * Dual licensed under the MIT and GPL licenses. + * http://benalman.com/about/license/ + */ +(function(b,c){var $=b.jQuery||b.Cowboy||(b.Cowboy={}),a;$.throttle=a=function(e,f,j,i){var h,d=0;if(typeof f!=="boolean"){i=j;j=f;f=c}function g(){var o=this,m=+new Date()-d,n=arguments;function l(){d=+new Date();j.apply(o,n)}function k(){h=c}if(i&&!h){l()}h&&clearTimeout(h);if(i===c&&m>e){l()}else{if(f!==true){h=setTimeout(i?k:l,i===c?e-m:e)}}}if($.guid){g.guid=j.guid=j.guid||$.guid++}return g};$.debounce=function(d,e,f){return f===c?a(d,e,false):a(d,f,e!==false)}})(this); diff --git a/node_modules/ace/api/resources/javascripts/prettify-extension.js b/node_modules/ace/api/resources/javascripts/prettify-extension.js new file mode 100644 index 00000000..ca8458dc --- /dev/null +++ b/node_modules/ace/api/resources/javascripts/prettify-extension.js @@ -0,0 +1,24 @@ +// Stolen from StackOverflow. Find all