Compare commits

..

3 Commits

Author SHA1 Message Date
rick 46cf9107e2 Release v1.2.1 2011-04-25 21:02:34 -04:00
Tom Ward 87aec65d37 ruby1.8 compatibility isn't required to run gollum using ruby 1.8.7
The sanitize gem requires 1.8.7 or later, so compatibility with earlier versions is moot
2011-04-25 21:01:22 -04:00
rick be72bcf353 fix xss vulnerability in mathjax parsing 2011-04-25 21:00:39 -04:00
1114 changed files with 48678 additions and 153610 deletions
-1
View File
@@ -3,4 +3,3 @@ pkg
.DS_Store
.bundle
Gemfile.lock
*.gem
-8
View File
@@ -1,8 +0,0 @@
rvm:
- 1.8.7
- 1.9.3
notifications:
disabled: true
before_install:
- gem uninstall ffi -a
- sudo apt-get install -y asciidoc
-1
View File
@@ -1,4 +1,3 @@
source "http://rubygems.org"
gemspec
gem "rake", "~> 0.9.2"
+2 -50
View File
@@ -1,52 +1,4 @@
# 1.4.0 / 2012-04-10
* Minor
* Add a way to configure the `#id_prefix` property of Sanitization
objects.
* Add web sequence diagrams support
* Support for updating wysiwyg components when markup language changes
* Support RedCarpet 2.0
* Allow ftp and irc links in wiki markup
* Minor ui fixups
* Bug Fixes
* Include the language of the code snippet when making a uniquely
identifiable sha of a code snippet while rendering a page.
* Pygments lexer forces utf8 encoding
* Remove MathJax, this created problems in production for us.
We'll look at bringing it back in future releases
# 1.3.1 / 2011-07-21
* Major Enhancements
* Allow prefixed ID attributes in headers to support internal linking
(#146).
* Markdown pages are rendered through Redcarpet by default (#176).
* Minor Enhancements
* Remove Edit button on Preview pages (#164).
* Simplify Wiki#inspect and Page#inspect.
* Bug Fixes
* Fixed broken preview functionality (#157).
* Fixed sidebar/footer rendering problems related to whitespace (#145).
# 1.3.0 / 2011-04-25
* Major Enhancements
* Listing of all Pages
* Support for running Gollum under a separate branch.
* Minor Enhancements
* Fix a security issue with rendering Mathjax.
# 1.2.0 / 2011-03-11
* Major Enhancements
* Major HTML/CSS/JS overhaul.
* Add Sidebars (similar to Footers).
* Add commit reverts.
* Minor Enhancements
* Optimization in source code highlighting, resulting in a huge
decrease in rendering time.
* Security fixes related to source code highlighting.
# HEAD
* Major Enhancements
* Add Page sidebars, similar to Page footers.
@@ -99,4 +51,4 @@
# 1.0.0 / 2010-08-12
* Open Source Birthday!
* Open Source Birthday!
+14 -97
View File
@@ -1,8 +1,6 @@
gollum -- A wiki built on top of Git
====================================
[![Build Status](https://secure.travis-ci.org/github/gollum.png?branch=master)](http://travis-ci.org/github/gollum)
## DESCRIPTION
Gollum is a simple wiki system built on top of Git that powers GitHub Wikis.
@@ -28,16 +26,15 @@ The best way to install Gollum is with RubyGems:
If you're installing from source, you can use [Bundler][bundler] to pick up all the
gems:
$ bundle install
$ bundle install # ([more info](http://gembundler.com/bundle_install.html))
In order to use the various formats that Gollum supports, you will need to
separately install the necessary dependencies for each format. You only need
to install the dependencies for the formats that you plan to use.
* [ASCIIDoc](http://www.methods.co.nz/asciidoc/) -- `brew install asciidoc` on mac or `apt-get install -y asciidoc` on Ubuntu
* [ASCIIDoc](http://www.methods.co.nz/asciidoc/) -- `brew install asciidoc`
* [Creole](http://wikicreole.org/) -- `gem install creole`
* [Markdown](http://daringfireball.net/projects/markdown/) -- `gem install redcarpet`
* [GitHub Flavored Markdown](http://github.github.com/github-flavored-markdown/) -- `gem install github-markdown`
* [Markdown](http://daringfireball.net/projects/markdown/) -- `gem install rdiscount`
* [Org](http://orgmode.org/) -- `gem install org-ruby`
* [Pod](http://search.cpan.org/dist/perl/pod/perlpod.pod) -- `Pod::Simple::HTML` comes with Perl >= 5.10. Lower versions should install Pod::Simple from CPAN.
* [RDoc](http://rdoc.sourceforge.net/)
@@ -61,7 +58,6 @@ utility, you can run it like so:
$ gollum --help
Note that the gollum server will not run on Windows because of [an issue](https://github.com/rtomayko/posix-spawn/issues/9) with posix-spawn (which is used by Grit).
## REPO STRUCTURE
@@ -109,13 +105,6 @@ are named `_Sidebar.ext` where the extension is one of the supported formats.
Sidebars affect all pages in their directory and any subdirectories that do not
have a sidebar file of their own.
## HEADER FILES
Header files allow you to add a simple header to your wiki. Header files must
be named `_Header.ext` where the extension is one of the supported formats.
Like sidebars, headers affect all pages in their directory and any
subdirectories that do not have a header file of their own.
## FOOTER FILES
Footer files allow you to add a simple footer to your wiki. Footer files must
@@ -123,6 +112,7 @@ be named `_Footer.ext` where the extension is one of the supported formats.
Like sidebars, footers affect all pages in their directory and any
subdirectories that do not have a footer file of their own.
## HTML SANITIZATION
For security and compatibility reasons Gollum wikis may not contain custom CSS
@@ -291,22 +281,6 @@ wiki page, simply preface the link with a single quote (like in LISP):
This is useful for writing about the link syntax in your wiki pages.
## TABLE OF CONTENTS
Gollum has a special tag to insert a table of contents (new in v2.1)
'[[_TOC_]]
This tag is case sensitive, use all upper case. The TOC tag can be inserted
into the `_Header`, `_Footer` or `_Sidebar` files too.
There is also a wiki option `:universal_toc` which will display a
table of contents at the top of all your wiki pages if it is enabled.
The `:universal_toc` is not enabled by default. To set the option,
add the option to the `:wiki_options` hash before starting the
frontend app:
Precious::App.set(:wiki_options, {:universal_toc => true})
## SYNTAX HIGHLIGHTING
@@ -320,23 +294,21 @@ separately) by using the following syntax:
end
```
The block must start with three backticks, at the beginning of a line or
indented with any number of spaces or tabs.
After that comes the name of the language that is contained by the
The block must start with three backticks (as the first characters on the
line). After that comes the name of the language that is contained by the
block. The language must be one of the `short name` lexer strings supported by
Pygments. See the [list of lexers](http://pygments.org/docs/lexers/) for valid
options.
The block contents should be indented at the same level than the opening backticks.
If the block contents are indented with an additional two spaces or one tab,
then that whitespace will be ignored (this makes the blocks easier to read in plaintext).
If the block contents are indented two spaces or one tab, then that whitespace
will be ignored (this makes the blocks easier to read in plaintext).
The block must end with three backticks as the first characters on a
line.
The block must end with three backticks indented at the same level than the opening
backticks.
## MATHEMATICAL EQUATIONS
Page files may contain mathematic equations in TeX syntax that will be nicely
typeset into the expected output. A block-style equation is delimited by `\[`
and `\]`. For example:
@@ -346,28 +318,11 @@ and `\]`. For example:
Inline equations are delimited by `\(` and `\)`. These equations will appear
inline with regular text. For example:
The Pythagorean theorem is \( a^2 + b^2 = c^2 \).
The Pythagorean theorum is \( a^2 + b^2 = c^2 \).
### INSTALLATION REQUIREMENTS
Gollum uses [MathJax](http://www.mathjax.org/) to convert the TeX syntax into
output suitable for display in web browsers.
In order to get the mathematical equations rendering to work, you need the following binaries:
* LaTex, TeTex or MacTex/BasicTeX (pdflatex)
* Netpbm (pnmcrop, pnmpad, pnmscale, ppmtopgm, pnmgamma, pnmtopng)
* Ghostscript (gs)
## SEQUENCE DIAGRAMS
You may imbed sequence diagrams into your wiki page (rendered by
[WebSequenceDiagrams](http://www.websequencediagrams.com) by using the
following syntax:
{{{ blue-modern
alice->bob: Test
bob->alice: Test response
}}}
You can replace the string "blue-modern" with any supported style.
## API DOCUMENTATION
@@ -416,11 +371,6 @@ Get the footer (if any) for a given page:
page.footer
# => <Gollum::Page>
Get the header (if any) for a given page:
page.header
# => <Gollum::Page>
Get a list of versions for a given page:
@@ -481,24 +431,6 @@ To delete a page and commit the change:
wiki.delete_page(page, commit)
### RACK
You can also run gollum with any rack-compatible server by placing this config.ru
file inside your wiki repository. This allows you to utilize any Rack middleware
like Rack::Auth, OmniAuth, etc.
#!/usr/bin/env ruby
require 'rubygems'
require 'gollum/frontend/app'
gollum_path = File.expand_path(File.dirname(__FILE__)) # CHANGE THIS TO POINT TO YOUR OWN WIKI REPO
Precious::App.set(:gollum_path, gollum_path)
Precious::App.set(:default_markup, :markdown) # set your favorite markup language
Precious::App.set(:wiki_options, {:universal_toc => false})
run Precious::App
## Windows Filename Validation
Note that filenames on windows must not contain any of the following characters `\ / : * ? " < > |`. See [this support article](http://support.microsoft.com/kb/177506) for details.
## CONTRIBUTE
@@ -518,18 +450,3 @@ your changes merged back into core is as follows:
1. If necessary, rebase your commits into logical chunks, without errors
1. Push the branch up to GitHub
1. Send a pull request to the github/gollum project.
## RELEASING
Update VERSION in lib/gollum.rb
$ rake gemspec
$ git tag vX.Y.Z
$ git push origin vX.Y.Z
$ gem build gollum.gemspec
$ gem push gollum-X.Y.Z.gem
## BUILDING THE GEM FROM MASTER
$ gem uninstall -aix gollum
$ git clone https://github.com/github/gollum.git
$ cd gollum
gollum$ rake build
gollum$ gem install pkg/gollum*.gem
+9 -5
View File
@@ -60,6 +60,14 @@ task :coverage do
sh "open coverage/index.html"
end
require 'rake/rdoctask'
Rake::RDocTask.new do |rdoc|
rdoc.rdoc_dir = 'rdoc'
rdoc.title = "#{name} #{version}"
rdoc.rdoc_files.include('README*')
rdoc.rdoc_files.include('lib/**/*.rb')
end
desc "Open an irb session preloaded with this library"
task :console do
sh "irb -rubygems -r ./lib/#{name}.rb"
@@ -79,7 +87,6 @@ end
#
#############################################################################
desc 'Create a release build'
task :release => :build do
unless `git branch` =~ /^\* master$/
puts "You must be on the master branch to release!"
@@ -92,14 +99,12 @@ task :release => :build do
sh "gem push pkg/#{name}-#{version}.gem"
end
desc 'Build gem'
task :build => :gemspec do
sh "mkdir -p pkg"
sh "gem build #{gemspec_file}"
sh "mv #{gem_file} pkg"
end
desc 'Update gemspec'
task :gemspec => :validate do
# read spec file and split out manifest section
spec = File.read(gemspec_file)
@@ -128,7 +133,6 @@ task :gemspec => :validate do
puts "Updated #{gemspec_file}"
end
desc 'Validate lib files and version file'
task :validate do
libfiles = Dir['lib/*'] - ["lib/#{name}.rb", "lib/#{name}"]
unless libfiles.empty?
@@ -139,4 +143,4 @@ task :validate do
puts "A `VERSION` file at root level violates Gem best practices."
exit!
end
end
end
+1 -24
View File
@@ -48,26 +48,6 @@ opts = OptionParser.new do |opts|
opts.on("--page-file-dir [PATH]", "Specify the sub directory for all page files (default: repository root).") do |path|
wiki_options[:page_file_dir] = path
end
opts.on("--base-path [PATH]", "Specify the base path.") do |path|
wiki_options[:base_path] = path
end
opts.on("--gollum-path [PATH]", "Specify the gollum path.") do |path|
wiki_options[:gollum_path] = path
end
opts.on("--ref [REF]", "Specify the repository ref to use (default: master).") do |ref|
wiki_options[:ref] = ref
end
opts.on("--no-live-preview", "Disables livepreview.") do
wiki_options[:live_preview] = false
end
opts.on("--mathjax", "Enables mathjax.") do
options['mathjax'] = true
end
end
# Read command line options into `options` hash
@@ -79,10 +59,7 @@ rescue OptionParser::InvalidOption
exit
end
# --gollum-path wins over ARGV[0]
gollum_path = wiki_options[:gollum_path] ?
wiki_options[:gollum_path] :
ARGV[0] || Dir.pwd
gollum_path = ARGV[0] || Dir.pwd
if options['irb']
require 'irb'
+643 -452
View File
File diff suppressed because it is too large Load Diff
+11 -17
View File
@@ -8,25 +8,19 @@ require 'github/markup'
require 'sanitize'
# internal
require File.expand_path('../gollum/git_access', __FILE__)
require File.expand_path('../gollum/committer', __FILE__)
require File.expand_path('../gollum/pagination', __FILE__)
require File.expand_path('../gollum/blob_entry', __FILE__)
require File.expand_path('../gollum/wiki', __FILE__)
require File.expand_path('../gollum/page', __FILE__)
require File.expand_path('../gollum/file', __FILE__)
require File.expand_path('../gollum/file_view', __FILE__)
require File.expand_path('../gollum/markup', __FILE__)
require File.expand_path('../gollum/sanitization', __FILE__)
require File.expand_path('../gollum/tex', __FILE__)
require File.expand_path('../gollum/web_sequence_diagram', __FILE__)
require 'gollum/git_access'
require 'gollum/committer'
require 'gollum/pagination'
require 'gollum/blob_entry'
require 'gollum/wiki'
require 'gollum/page'
require 'gollum/file'
require 'gollum/markup'
require 'gollum/albino'
require 'gollum/sanitization'
module Gollum
VERSION = '2.1.5'
def self.assets_path
::File.expand_path('gollum/frontend/public', ::File.dirname(__FILE__))
end
VERSION = '1.2.1'
class Error < StandardError; end
+5
View File
@@ -0,0 +1,5 @@
require 'albino/multi'
class Gollum::Albino < Albino::Multi
self.bin = ::Albino::Multi.bin
end
+1 -13
View File
@@ -48,18 +48,6 @@ module Gollum
page
end
# Gets a File instance for this blob.
#
# wiki - Gollum::Wiki instance for the Gollum::File
#
# Returns a Gollum::File instance.
def file(wiki, commit)
blob = self.blob(wiki.repo)
file = wiki.file_class.new(wiki).populate(blob, self.dir)
file.version = commit
file
end
def inspect
%(#<Gollum::BlobEntry #{@sha} #{@path}>)
end
@@ -87,4 +75,4 @@ module Gollum
dir
end
end
end
end
+11 -21
View File
@@ -1,7 +1,7 @@
module Gollum
# Responsible for handling the commit process for a Wiki. It sets up the
# Responsible for handling the commit process for a Wiki. It sets up the
# Git index, provides methods for modifying the tree, and stores callbacks
# to be fired after the commit has been made. This is specifically
# to be fired after the commit has been made. This is specifically
# designed to handle multiple updated pages in a single commit.
class Committer
# Gets the instance of the Gollum::Wiki that is being updated.
@@ -21,7 +21,7 @@ module Gollum
# :tree - Optional String SHA of the tree to create the
# index from.
# :committer - Optional Gollum::Committer instance. If provided,
# assume that this operation is part of batch of
# assume that this operation is part of batch of
# updates and the commit happens later.
#
# Returns the Committer instance.
@@ -62,7 +62,7 @@ module Gollum
# Returns an array of Grit::Commit instances.
def parents
@parents ||= begin
arr = [@options[:parent] || @wiki.repo.commit(@wiki.ref)]
arr = [@options[:parent] || @wiki.repo.commit('master')]
arr.flatten!
arr.compact!
arr
@@ -73,7 +73,7 @@ module Gollum
#
# dir - The String subdirectory of the Gollum::Page without any
# prefix or suffix slashes (e.g. "foo/bar").
# name - The String Gollum::Page filename_stripped.
# name - The String Gollum::Page name.
# format - The Symbol Gollum::Page format.
# data - The String wiki data to store in the tree map.
# allow_same_ext - A Boolean determining if the tree map allows the same
@@ -91,11 +91,7 @@ module Gollum
fullpath = ::File.join(*[@wiki.page_file_dir, dir, path].compact)
fullpath = fullpath[1..-1] if fullpath =~ /^\//
if index.current_tree && tree = index.current_tree / (@wiki.page_file_dir || '/')
tree = tree / dir unless tree.nil?
end
if tree
if index.current_tree && tree = index.current_tree / dir
downpath = path.downcase.sub(/\.\w+$/, '')
tree.blobs.each do |blob|
@@ -108,8 +104,6 @@ module Gollum
end
end
fullpath = fullpath.force_encoding('ascii-8bit') if fullpath.respond_to?(:force_encoding)
index.add(fullpath, @wiki.normalize(data))
end
@@ -117,15 +111,14 @@ module Gollum
# is a working directory present.
#
# dir - The String directory in which the file lives.
# name - The String name of the page or the stripped filename
# (should be pre-canonicalized if required).
# name - The String name of the page (may be in human format).
# format - The Symbol format of the page.
#
# Returns nothing.
def update_working_dir(dir, name, format)
unless @wiki.repo.bare
if @wiki.page_file_dir
dir = dir.size.zero? ? @wiki.page_file_dir : ::File.join(dir, @wiki.page_file_dir)
dir = dir.size.zero? ? @wiki.page_file_dir : File.join(dir, @wiki.page_file_dir)
end
path =
@@ -135,8 +128,6 @@ module Gollum
::File.join(dir, @wiki.page_file_name(name, format))
end
path = path.force_encoding('ascii-8bit') if path.respond_to?(:force_encoding)
Dir.chdir(::File.join(@wiki.repo.path, '..')) do
if file_path_scheduled_for_deletion?(index.tree, path)
@wiki.repo.git.rm({'f' => true}, '--', path)
@@ -151,7 +142,7 @@ module Gollum
#
# Returns the String SHA1 of the new commit.
def commit
sha1 = index.commit(@options[:message], parents, actor, nil, @wiki.ref)
sha1 = index.commit(@options[:message], parents, actor)
@callbacks.each do |cb|
cb.call(self, sha1)
end
@@ -160,7 +151,7 @@ module Gollum
# Adds a callback to be fired after a commit.
#
# block - A block that expects this Committer instance and the created
# block - A block that expects this Committer instance and the created
# commit's SHA1 as the arguments.
#
# Returns nothing.
@@ -220,8 +211,7 @@ module Gollum
# Proxies methods t
def method_missing(name, *args)
args.map! { |item| item.respond_to?(:force_encoding) ? item.force_encoding('ascii-8bit') : item }
index.send(name, *args)
end
end
end
end
+2 -15
View File
@@ -19,7 +19,6 @@ module Gollum
def name
@blob && @blob.name
end
alias filename name
# Public: The raw contents of the page.
#
@@ -29,7 +28,7 @@ module Gollum
end
# Public: The Grit::Commit version of the file.
attr_accessor :version
attr_reader :version
# Public: The String path of the file.
attr_reader :path
@@ -39,18 +38,6 @@ module Gollum
@blob.mime_type
end
# Populate the File with information from the Blob.
#
# blob - The Grit::Blob that contains the info.
# path - The String directory path of the file.
#
# Returns the populated Gollum::File.
def populate(blob, path=nil)
@blob = blob
@path = "#{path}/#{blob.name}"[1..-1]
self
end
#########################################################################
#
# Internal Methods
@@ -74,4 +61,4 @@ module Gollum
end
end
end
end
end
-145
View File
@@ -1,145 +0,0 @@
module Gollum
=begin
FileView requires that:
- All files in root dir are processed first
- Then all the folders are sorted and processed
=end
class FileView
def initialize pages
@pages = pages
end
def enclose_tree string
%Q(<ol class="tree">\n) + string + %Q(</ol>)
end
def new_page page
name = page.name
url = url_for_page page
%Q( <li class="file"><a href="#{url}">#{name}</a></li>\n)
end
def new_folder folder_path
new_sub_folder folder_path
end
def new_sub_folder path
<<-HTML
<li>
<label>#{path}</label> <input type="checkbox" checked />
<ol>
HTML
end
def end_folder
<<-HTML
</ol>
</li>
HTML
end
def url_for_page page
url = ::File.join(::File.dirname(page.path), page.filename_stripped)
url = url[2..-1] if url[0,2] == './'
url
end
def render_files
html = ''
count = @pages.size
folder_start = -1
# Process all pages until folders start
count.times do | index |
page = @pages[ index ]
path = page.path
unless path.include? '/'
# Page processed (not contained in a folder)
html += new_page page
else
# Folders start at the next index
folder_start = index
break # Pages finished, move on to folders
end
end
# If there are no folders, then we're done.
return enclose_tree(html) if folder_start <= -1
# Handle special case of only one folder.
if (count - folder_start == 1)
page = @pages[ folder_start ]
name = page.name
url = url_for_page page
html += <<-HTML
<li>
<label>#{::File.dirname(page.path)}</label> <input type="checkbox" checked />
<ol>
<li class="file"><a href="#{url}">#{name}</a></li>
</ol>
</li>
HTML
return enclose_tree html
end
sorted_folders = []
(folder_start).upto count - 1 do | index |
sorted_folders += [[ @pages[ index ].path, index ]]
end
# http://stackoverflow.com/questions/3482814/sorting-list-of-string-paths-in-vb-net
sorted_folders.sort! do |first,second|
a = first[0]
b = second[0]
# use :: operator because gollum defines its own conflicting File class
dir_compare = ::File.dirname(a) <=> ::File.dirname(b)
# Sort based on directory name unless they're equal (0) in
# which case sort based on file name.
if dir_compare == 0
::File.basename(a) <=> ::File.basename(b)
else
dir_compare
end
end
# keep track of folder depth, 0 = at root.
cwd_array = []
changed = false
# process rest of folders
(0...sorted_folders.size).each do | index |
page = @pages[ sorted_folders[ index ][ 1 ] ]
path = page.path
folder = ::File.dirname path
tmp_array = folder.split '/'
(0...tmp_array.size).each do | index |
if cwd_array[ index ].nil? || changed
html += new_sub_folder tmp_array[ index ]
next
end
if cwd_array[ index ] != tmp_array[ index ]
changed = true
(cwd_array.size - index).times do
html += end_folder
end
html += new_sub_folder tmp_array[ index ]
end
end
html += new_page page
cwd_array = tmp_array
changed = false
end
# return the completed html
enclose_tree html
end # end render_files
end # end FileView class
end # end Gollum module
+74 -243
View File
@@ -2,63 +2,20 @@ require 'cgi'
require 'sinatra'
require 'gollum'
require 'mustache/sinatra'
require 'useragent'
require 'stringex'
require 'gollum/frontend/views/layout'
require 'gollum/frontend/views/editable'
require 'gollum/frontend/views/has_page'
require File.expand_path '../uri_encode_component', __FILE__
require File.expand_path '../helpers', __FILE__
# Fix to_url
class String
alias :upstream_to_url :to_url
# _Header => header which causes errors
def to_url
return nil if self.nil?
return self if ['_Header', '_Footer', '_Sidebar'].include? self
upstream_to_url
end
end
# Run the frontend, based on Sinatra
#
# There are a number of wiki options that can be set for the frontend
#
# Example
# require 'gollum/frontend/app'
# Precious::App.set(:wiki_options, {
# :universal_toc => false,
# }
#
# See the wiki.rb file for more details on wiki options
module Precious
class App < Sinatra::Base
register Mustache::Sinatra
include Precious::Helpers
dir = File.dirname(File.expand_path(__FILE__))
# Detect unsupported browsers.
Browser = Struct.new(:browser, :version)
@@min_ua = [
Browser.new('Internet Explorer', '10.0'),
Browser.new('Chrome', '7.0'),
Browser.new('Firefox', '4.0'),
]
def supported_useragent?(user_agent)
ua = UserAgent.parse(user_agent)
@@min_ua.detect {|min| ua >= min }
end
# We want to serve public assets for now
set :public_folder, "#{dir}/public/gollum"
set :static, true
set :default_markup, :markdown
set :public, "#{dir}/public"
set :static, true
set :mustache, {
# Tell mustache where the Views constant lives
@@ -81,122 +38,47 @@ module Precious
enable :logging, :raise_errors, :dump_errors
end
before do
@base_url = url('/', false).chomp('/')
settings.wiki_options.merge!({ :base_path => @base_url }) unless settings.wiki_options.has_key? :base_path
end
get '/' do
redirect File.join(settings.wiki_options[:base_path].to_s, 'Home')
end
# path is set to name if path is nil.
# if path is 'a/b' and a and b are dirs, then
# path must have a trailing slash 'a/b/' or
# extract_path will trim path to 'a'
# name, path, version
def wiki_page( name, path = nil, version = nil)
path = name if path.nil?
name = extract_name(name)
path = extract_path(path)
wiki = wiki_new
OpenStruct.new(:wiki => wiki, :page => wiki.paged(name, path, version),
:name => name, :path => path)
end
def wiki_new
Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
end
get '/data/*' do
if page = wiki_page(params[:splat].first).page
page.raw_data
end
show_page_or_file('Home')
end
get '/edit/*' do
wikip = wiki_page(params[:splat].first)
@name = wikip.name
@path = wikip.path
wiki = wikip.wiki
if page = wikip.page
if wiki.live_preview && page.format.to_s.include?('markdown') && supported_useragent?(request.user_agent)
live_preview_url = '/livepreview/index.html?page=' + encodeURIComponent(@name)
if @path
live_preview_url << '&path=' + encodeURIComponent(@path)
end
redirect to(live_preview_url)
else
@page = page
@page.version = wiki.repo.log(wiki.ref, @page.path).first
raw_data = page.raw_data
@content = raw_data.respond_to?(:force_encoding) ? raw_data.force_encoding('UTF-8') : raw_data
mustache :edit
end
else
redirect to("/create/#{encodeURIComponent(@name)}")
end
end
post '/edit/*' do
wikip = wiki_page(CGI.unescape(params[:page]), sanitize_empty_params(params[:path]))
path = wikip.path
wiki = wikip.wiki
page = wikip.page
rename = params[:rename].to_url if params[:rename]
name = rename || page.name
committer = Gollum::Committer.new(wiki, commit_message)
commit = {:committer => committer}
update_wiki_page(wiki, page, params[:content], commit, name, params[:format])
update_wiki_page(wiki, page.header, params[:header], commit) if params[:header]
update_wiki_page(wiki, page.footer, params[:footer], commit) if params[:footer]
update_wiki_page(wiki, page.sidebar, params[:sidebar], commit) if params[:sidebar]
committer.commit
page = wiki.page(rename) if rename
redirect to("/#{page.escaped_url_path}") unless page.nil?
end
get '/delete/*' do
wikip = wiki_page(params[:splat].first)
name = wikip.name
wiki = wikip.wiki
page = wikip.page
wiki.delete_page(page, { :message => "Destroyed #{name} (#{page.format})" })
redirect to('/')
end
get '/create/*' do
wikip = wiki_page(params[:splat].first.gsub('+', '-'))
@name = wikip.name.to_url
@path = wikip.path
page = wikip.page
if page
redirect to("/#{page.escaped_url_path}")
@name = params[:splat].first
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
if page = wiki.page(@name)
@page = page
@content = page.raw_data
mustache :edit
else
mustache :create
end
end
post '/create' do
name = params[:page].to_url
path = sanitize_empty_params(params[:path])
format = params[:format].intern
post '/edit/*' do
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
page = wiki.page(params[:splat].first)
name = params[:rename] || page.name
committer = Gollum::Committer.new(wiki, commit_message)
commit = {:committer => committer}
# write_page is not directory aware so use wiki_options to emulate dir support.
wiki_options = settings.wiki_options.merge({ :page_file_dir => path })
wiki = Gollum::Wiki.new(settings.gollum_path, wiki_options)
update_wiki_page(wiki, page, params[:content], commit, name,
params[:format])
update_wiki_page(wiki, page.footer, params[:footer], commit) if params[:footer]
update_wiki_page(wiki, page.sidebar, params[:sidebar], commit) if params[:sidebar]
committer.commit
redirect "/#{CGI.escape(Gollum::Page.cname(name))}"
end
post '/create' do
name = params[:page]
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
format = params[:format].intern
begin
wiki.write_page(name, format, params[:content], commit_message)
page = wiki.page(name)
redirect to("/#{page.escaped_url_path}") unless page.nil?
redirect "/#{CGI.escape(name)}"
rescue Gollum::DuplicatePageError => e
@message = "Duplicate page: #{e.message}"
mustache :error
@@ -204,99 +86,75 @@ module Precious
end
post '/revert/:page/*' do
wikip = wiki_page(params[:page])
@path = wikip.path
@name = wikip.name
wiki = wikip.wiki
@page = wiki.paged(@name,@path)
shas = params[:splat].first.split("/")
sha1 = shas.shift
sha2 = shas.shift
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
@name = params[:page]
@page = wiki.page(@name)
shas = params[:splat].first.split("/")
sha1 = shas.shift
sha2 = shas.shift
if wiki.revert_page(@page, sha1, sha2, commit_message)
redirect to("/#{@page.escaped_url_path}")
redirect "/#{CGI.escape(@name)}"
else
sha2, sha1 = sha1, "#{sha1}^" if !sha2
@versions = [sha1, sha2]
diffs = wiki.repo.diff(@versions.first, @versions.last, @page.path)
@diff = diffs.first
@message = "The patch does not apply."
@versions = [sha1, sha2]
diffs = wiki.repo.diff(@versions.first, @versions.last, @page.path)
@diff = diffs.first
@message = "The patch does not apply."
mustache :compare
end
end
post '/preview' do
wiki = wiki_new
@name = params[:page] || "Preview"
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
@name = "Preview"
@page = wiki.preview_page(@name, params[:content], params[:format])
@content = @page.formatted_data
@toc_content = wiki.universal_toc ? @page.toc_data : nil
@mathjax = wiki.mathjax
@editable = false
mustache :page
end
get '/history/*' do
@page = wiki_page(params[:splat].first).page
@page_num = [params[:page].to_i, 1].max
@versions = @page.versions :page => @page_num
get '/history/:name' do
@name = params[:name]
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
@page = wiki.page(@name)
@page_num = [params[:page].to_i, 1].max
@versions = @page.versions :page => @page_num
mustache :history
end
post '/compare/*' do
@file = params[:splat].first
post '/compare/:name' do
@versions = params[:versions] || []
if @versions.size < 2
redirect to("/history/#{@file}")
redirect "/history/#{CGI.escape(params[:name])}"
else
redirect to("/compare/%s/%s...%s" % [
@file,
redirect "/compare/%s/%s...%s" % [
CGI.escape(params[:name]),
@versions.last,
@versions.first]
)
end
end
get %r{
/compare/ # match any URL beginning with /compare/
(.+) # extract the full path (including any directories)
/ # match the final slash
([^.]+) # match the first SHA1
\.{2,3} # match .. or ...
(.+) # match the second SHA1
}x do |path, start_version, end_version|
wikip = wiki_page(path)
@path = wikip.path
@name = wikip.name
@versions = [start_version, end_version]
wiki = wikip.wiki
@page = wikip.page
diffs = wiki.repo.diff(@versions.first, @versions.last, @page.path)
@diff = diffs.first
get '/compare/:name/:version_list' do
@name = params[:name]
@versions = params[:version_list].split(/\.{2,3}/)
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
@page = wiki.page(@name)
diffs = wiki.repo.diff(@versions.first, @versions.last, @page.path)
@diff = diffs.first
mustache :compare
end
get '/_tex.png' do
content_type 'image/png'
formula = Base64.decode64(params[:data])
Gollum::Tex.render_formula(formula)
end
get %r{^/(javascript|css|images)} do
halt 404
end
get %r{/(.+?)/([0-9a-f]{40})} do
file_path = params[:captures][0]
version = params[:captures][1]
wikip = wiki_page(file_path, file_path, version)
name = wikip.name
path = wikip.path
if page = wikip.page
name = params[:captures][0]
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
if page = wiki.page(name, params[:captures][1])
@page = page
@name = name
@content = page.formatted_data
@editable = true
mustache :page
else
halt 404
@@ -305,66 +163,39 @@ module Precious
get '/search' do
@query = params[:q]
wiki = wiki_new
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
@results = wiki.search @query
@name = @query
mustache :search
end
get %r{
/pages # match any URL beginning with /pages
(?: # begin an optional non-capturing group
/(.+) # capture any path after the "/pages" excluding the leading slash
)? # end the optional non-capturing group
}x do |path|
@path = extract_path(path) if path
wiki_options = settings.wiki_options.merge({ :page_file_dir => @path })
wiki = Gollum::Wiki.new(settings.gollum_path, wiki_options)
@results = wiki.pages
@ref = wiki.ref
mustache :pages
end
get '/fileview' do
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
@results = Gollum::FileView.new(wiki.pages).render_files
@ref = wiki.ref
mustache :file_view, { :layout => false }
end
get '/*' do
show_page_or_file(params[:splat].first)
end
def show_page_or_file(fullpath)
name = extract_name(fullpath)
path = extract_path(fullpath)
wiki = wiki_new
if page = wiki.paged(name, path)
def show_page_or_file(name)
wiki = Gollum::Wiki.new(settings.gollum_path, settings.wiki_options)
if page = wiki.page(name)
@page = page
@name = name
@editable = true
@content = page.formatted_data
@toc_content = wiki.universal_toc ? @page.toc_data : nil
@mathjax = wiki.mathjax
mustache :page
elsif file = wiki.file(fullpath)
elsif file = wiki.file(name)
content_type file.mime_type
file.raw_data
else
page_path = [path, name].compact.join('/')
redirect to("/create/#{encodeURIComponent(page_path).gsub('%2F','/')}")
@name = name
mustache :create
end
end
def update_wiki_page(wiki, page, content, commit, name = nil, format = nil)
return if !page ||
def update_wiki_page(wiki, page, content, commit_message, name = nil, format = nil)
return if !page ||
((!content || page.raw_data == content) && page.format == format)
name ||= page.name
format = (format || page.format).to_sym
content ||= page.raw_data
wiki.update_page(page, name, format, content.to_s, commit)
wiki.update_page(page, name, format, content.to_s, commit_message)
end
def commit_message
-21
View File
@@ -1,21 +0,0 @@
module Precious
module Helpers
# Extract the path string that Gollum::Wiki expects
def extract_path(file_path)
return nil if file_path.nil?
last_slash = file_path.rindex("/")
if last_slash
file_path[0, last_slash]
end
end
# Extract the 'page' name from the file_path
def extract_name(file_path)
::File.basename(file_path)
end
def sanitize_empty_params(param)
[nil,''].include?(param) ? nil : CGI.unescape(param)
end
end
end
@@ -18,7 +18,7 @@
width: 450px;
border: 7px solid #999;
border: 7px solid rgba(0, 0, 0, 0.3);
border: 7px solid rgba(0, 0, 0, 0.3);
border-radius: 5px;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
@@ -28,7 +28,7 @@
background-color: #fff;
overflow: hidden;
padding: 1em;
background: -webkit-gradient(linear, left top, left bottom, from(#f7f7f7), to(#ffffff));
background: -moz-linear-gradient(top, #f7f7f7, #ffffff);
}
@@ -71,7 +71,7 @@
padding: 0;
min-width: 80px;
}
#gollum-dialog-dialog-body fieldset .field input[type="text"] {
border: 1px solid #ddd;
display: block;
@@ -82,11 +82,11 @@
padding: 0.3em 0.5em;
width: 96.5%;
}
#gollum-dialog-dialog-body fieldset .field input.code {
font-family: 'Monaco', 'Courier New', Courier, monospace;
}
#gollum-dialog-dialog-body fieldset .field:last-child {
margin: 0 0 1em 0;
}
@@ -30,9 +30,8 @@ a {
-webkit-border-radius: 1em;
}
.ff #gollum-editor,
.ie #gollum-editor {
padding-bottom: 1em;
padding-bottom: 1em;
}
#gollum-editor form fieldset {
@@ -52,9 +51,9 @@ a {
background: #fff;
border: 1px solid #ddd;
color: #000;
font-size: 1.1em;
font-size: 1.3em;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
line-height: 1.5em;
line-height: 1.8em;
margin: 1em 0 0.4em;
padding: 0.5em;
width: 98%;
@@ -64,12 +63,6 @@ a {
color: #999;
}
#gollum-editor .path_note {
text-align: right;
font-size: small;
padding-right: 5px;
}
#gollum-editor-title-field input#gollum-editor-page-title {
font-weight: bold;
margin-top: 0;
@@ -126,11 +119,11 @@ a {
/* text-indent: -5000px; */
text-shadow: 0 1px 0 #fff;
width: 25px;
border-radius: 0.3em;
-moz-border-radius: 0.3em;
-webkit-border-radius: 0.3em;
filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#f4f4f4', endColorstr='#ececec');
background: -webkit-gradient(linear, left top, left bottom, from(#f4f4f4), to(#ececec));
background: -moz-linear-gradient(top, #f4f4f4, #ececec);
@@ -140,7 +133,7 @@ a {
color: #fff;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.3);
text-decoration: none;
filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#599bdc', endColorstr='#3072b3');
background: -webkit-gradient(linear, left top, left bottom, from(#599bdc), to(#3072b3));
background: -moz-linear-gradient(top, #599bdc, #3072b3);
@@ -169,7 +162,7 @@ a#function-h2 span { background-position: -244px 0; }
a#function-h3 span { background-position: -271px 0; }
a#function-link span { background-position: -298px 0; }
a#function-image span { background-position: -324px 0; }
a#function-help span { background-position: -405px 0; }
a#function-help span { background-position: -405px 0; }
a#function-bold:hover span { background-position: 0 -28px; }
a#function-italic:hover span { background-position: -27px -28px; }
@@ -184,7 +177,7 @@ a#function-h2:hover span { background-position: -244px -28px; }
a#function-h3:hover span { background-position: -271px -28px; }
a#function-link:hover span { background-position: -298px -28px; }
a#function-image:hover span { background-position: -324px -28px; }
a#function-help:hover span { background-position: -405px -28px; }
a#function-help:hover span { background-position: -405px -28px; }
#gollum-editor #gollum-editor-function-bar a.disabled {
@@ -199,54 +192,62 @@ a#function-help:hover span { background-position: -405px -28px; }
#gollum-editor #gollum-editor-function-bar #gollum-editor-format-selector {
overflow: hidden;
padding: .2em 0 .5em 0;
padding: 0 0 1.1em 0;
}
#gollum-editor #gollum-editor-function-bar
#gollum-editor-format-selector select {
#gollum-editor #gollum-editor-function-bar
#gollum-editor-format-selector select {
background-color: #f9f9f9;
border: 1px solid #ddd;
color: #333;
border: 1px solid transparent;
float: right;
font-size: 1em;
font-size: 1.1em;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-weight: bold;
line-height: 1.6em;
padding: 0.3em 0.4em;
padding: 0.5em 0.7em;
margin-bottom: 0;
border-radius: 0.5em;
-moz-border-radius: 0.5em;
-webkit-border-radius: 0.5em;
-webkit-border-radius: 0.5em;
-moz-outline: none;
}
#gollum-editor #gollum-editor-function-bar
#gollum-editor-format-selector select:hover {
background-color: #fff;
border: 1px solid #ddd;
-moz-outline: none;
}
#gollum-editor #gollum-editor-function-bar
#gollum-editor-format-selector label {
color: #999;
float: right;
font-size: 1em;
font-size: 1.1em;
font-weight: bold;
line-height: 1.6em;
padding: .3em 0.5em 0 0;
padding: 0.6em 0.5em 0 0;
}
#gollum-editor #gollum-editor-function-bar
#gollum-editor-format-selector label:after {
#gollum-editor-format-selector label:after {
content: ':';
}
/* @section form-fields */
#gollum-editor textarea {
#gollum-editor textarea#gollum-editor-body {
background: #fff;
border: 1px solid #ddd;
font-size: 1em;
font-size: 1.3em;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
line-height: 1.4em;
line-height: 1.8em;
margin: 1em 0 0.4em;
padding: 0.5em;
padding: 0.5em; /* I don't really like mixing pct & em here… */
width: 98%;
height: 20em;
}
@@ -258,7 +259,7 @@ a#function-help:hover span { background-position: -405px -28px; }
cursor: pointer;
display: block;
float: left;
font-size: 1em;
font-size: 1.2em;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-weight: bold;
margin: 0;
@@ -300,7 +301,7 @@ a#function-help:hover span { background-position: -405px -28px; }
border-bottom: 1px solid #ddd;
display: block;
overflow: hidden;
padding: 0.5em 0 0;
padding: 1em 0 0.5em;
}
#gollum-editor #gollum-editor-body + .collapsed,
@@ -321,11 +322,11 @@ a#function-help:hover span { background-position: -405px -28px; }
margin: 0.2em 0.5em 0.75em 0;
text-shadow: 0 1px 0 #fff;
width: 25px;
border-radius: 0.3em;
-moz-border-radius: 0.3em;
-webkit-border-radius: 0.3em;
filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#f4f4f4', endColorstr='#ececec');
background: -webkit-gradient(linear, left top, left bottom, from(#f4f4f4), to(#ececec));
background: -moz-linear-gradient(top, #f4f4f4, #ececec);
@@ -336,19 +337,16 @@ a#function-help:hover span { background-position: -405px -28px; }
font-size: 1.6em;
float: left;
margin: 0;
padding: 0.15em 0 0 0.3em;
padding: 0.4em 0 0 0.3em;
text-shadow: 0 -1px 0 #fff;
}
#gollum-editor .collapsed h4 {
color: #bbb;
}
#gollum-editor .collapsed a.button:hover,
#gollum-editor .expanded a.button:hover {
#gollum-editor .expanded h4 a.button:hover {
color: #fff;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.3);
text-decoration: none;
filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#599bdc', endColorstr='#3072b3');
background: -webkit-gradient(linear, left top, left bottom, from(#599bdc), to(#3072b3));
background: -moz-linear-gradient(top, #599bdc, #3072b3);
@@ -387,10 +385,10 @@ a#function-help:hover span { background-position: -405px -28px; }
border: 1px solid #ddd;
clear: both;
display: block;
font-size: 1em;
font-size: 1.3em;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
height: 7em;
line-height: 1.4em;
line-height: 1.8em;
margin: 0.7em 0;
padding: 0.5em;
width: 98%;
@@ -405,7 +403,7 @@ a#function-help:hover span { background-position: -405px -28px; }
color: #333;
cursor: pointer;
display: block;
font-size: 1em;
font-size: 1.2em;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-weight: bold;
line-height: 1.2em;
@@ -463,16 +461,16 @@ a#function-help:hover span { background-position: -405px -28px; }
padding: 1em 0;
width: 18%;
}
#gollum-editor-help-parent {
border-right: 1px solid #eee;
}
#gollum-editor-help-list {
background: #fafafa;
border-right: 1px solid #eee;
}
#gollum-editor-help-parent li,
#gollum-editor-help-list li {
font-size: 1.2em;
@@ -480,7 +478,7 @@ a#function-help:hover span { background-position: -405px -28px; }
margin: 0;
padding: 0;
}
#gollum-editor-help-parent li a,
#gollum-editor-help-list li a {
border: 1px solid transparent;
@@ -492,16 +490,16 @@ a#function-help:hover span { background-position: -405px -28px; }
padding: 0.2em 1em;
text-shadow: 0 -1px 0 #fff;
}
#gollum-editor-help-parent li a:hover,
#gollum-editor-help-list li a:hover {
background: #fff;
border-color: #f0f0f0;
text-decoration: none;
box-shadow: none;
}
#gollum-editor-help-parent li a.selected,
#gollum-editor-help-list li a.selected {
border: 1px solid #eee;
@@ -509,29 +507,29 @@ a#function-help:hover span { background-position: -405px -28px; }
border-width: 1px 0;
background: #fff;
color: #000;
box-shadow: 0 1px 2px #f0f0f0;
}
#gollum-editor-help-wrapper {
background: #fff;
overflow: auto;
height: 17em;
padding: 1em;
}
#gollum-editor-help-content {
font-size: 1.2em;
margin: 0 1em 0 0.5em;
padding: 0;
line-height: 1.8em;
}
#gollum-editor-help-content p {
margin: 0 0 1em 0;
padding: 0;
}
/* IE */
.ie #gollum-editor .singleline input {
padding-top: 0.25em;
+665
View File
@@ -0,0 +1,665 @@
/*
gollum.css
A basic stylesheet for Gollum
*/
/* @section core */
body, html {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 10px; /* -> 1em */
margin: 0;
padding: 0;
}
#wiki-wrapper {
margin: 0 auto;
overflow: visible;
width: 80%;
}
a:link {
color: #4183c4;
text-decoration: none;
}
a:hover, a:visited {
color: #4183c4;
text-decoration: underline;
}
/* @section head */
#head {
border-bottom: 1px solid #ccc;
margin: 4.5em 0 0.5em;
padding: 0.5em 0;
overflow: hidden;
}
#head h1 {
font-size: 3.3em;
float: left;
line-height: normal;
margin: 0;
padding: 0.08em 0 0 0;
width: 50%;
}
#head ul.actions {
float: right;
}
/* @section content */
#wiki-content {
height: 1%;
overflow: visible;
}
#wiki-content .wrap {
height: 1%;
overflow: auto;
}
/* @section comments */
#wiki-body #inline-comment {
display: none; /* todo */
}
/* @section body */
#wiki-body {
display: block;
float: left;
margin-right: 3%;
width: 100%;
}
.has-rightbar #wiki-body {
width: 68%;
}
/* @section rightbar */
#wiki-rightbar {
background-color: #f7f7f7;
border: 1px solid #ddd;
font-size: 13px;
float: right;
padding: 7px;
width: 25%;
border-radius: 0.5em;
-moz-border-radius: 0.5em;
-webkit-border-radius: 0.5em;
}
#wiki-rightbar p {
margin: 13px 0 0;
}
#wiki-rightbar > p:first-child {
margin-top: 0;
}
#wiki-rightbar p.parent {
border-bottom: 1px solid #bbb;
font-weight: bold;
margin: 0 0 0.5em 0;
padding: 0 0 0.5em 0;
text-shadow: 0 1px 0 #fff;
}
/* Back arrow */
#wiki-rightbar p.parent:before {
color: #666;
content: "← ";
}
#wiki-rightbar h3 {
font-size: 1.2em;
color: #333;
margin: 1.2em 0 0;
padding: 0;
text-shadow: 0 1px 0 #fff;
}
#wiki-rightbar ul {
margin: 0.5em 0 1em;
padding: 0;
}
#wiki-rightbar ul li {
color: #bbb;
margin: 0 0 0 1em;
padding: 0;
line-height: 1.75em;
list-style-position: inside;
list-style-type: round;
}
#wiki-rightbar #nav ul li a {
font-weight: bold;
text-shadow: 0 1px 0 #fff;
}
/* @section footer */
#wiki-footer {
clear: both;
margin: 2em 0 5em;
}
.has-rightbar #wiki-footer {
width: 70%;
}
#wiki-footer #footer-content {
background-color: #f7f7f7;
border: 1px solid #ddd;
font-size: 1.2em;
line-height: 1.5em;
margin-top: 1.5em;
padding: 1em;
border-radius: 0.5em;
-moz-border-radius: 0.5em;
-webkit-border-radius: 0.5em;
}
#wiki-footer #footer-content h3 {
font-size: 1.2em;
color: #333;
margin: 0;
padding: 0 0 0.2em;
text-shadow: 0 1px 0 #fff;
}
#wiki-footer #footer-content p {
margin: 0.5em 0 0;
padding: 0;
}
#wiki-footer #footer-content ul.links {
margin: 0.5em 0 0;
overflow: hidden;
padding: 0;
}
#wiki-footer #footer-content ul.links li {
color: #999;
float: left;
list-style-position: inside;
list-style-type: square;
padding: 0;
margin-left: 0.75em;
}
#wiki-footer #footer-content ul.links li a {
font-weight: bold;
text-shadow: 0 1px 0 #fff;
}
#wiki-footer #footer-content ul.links li:first-child {
list-style-type: none;
margin: 0;
}
.ff #wiki-footer #footer-content ul.links li:first-child {
margin: 0 -0.75em 0 0;
}
/* @section page-footer */
.page #footer {
border-top: 1px solid #ccc;
margin: 1em 0 7em;
}
#footer p#last-edit {
font-size: 1.2em;
line-height: 1.6em;
color: #999;
margin: 0.9em 0;
}
#footer p#last-edit span.username {
font-weight: bold;
}
/* @section history */
.history h1 {
color: #999;
font-weight: normal;
}
.history h1 strong {
color: #000;
font-weight: bold;
}
#wiki-history {
margin-top: 3em;
}
#wiki-history fieldset {
border: 0;
margin: 2em 0;
padding: 0;
}
#wiki-history table, #wiki-history tbody {
border-collapse: collapse;
padding: 0;
margin: 0;
width: 100%;
}
#wiki-history table tr {
padding: 0;
margin: 0;
}
#wiki-history table tr {
background-color: #ebf2f6;
}
#wiki-history table tr td {
border: 1px solid #c0dce9;
font-size: 1.2em;
line-height: 1.6em;
margin: 0;
padding: 0.3em 0.7em;
}
#wiki-history table tr td.checkbox {
min-width: 2em;
padding: 0.3em;
}
#wiki-history table tr td.checkbox input {
cursor: pointer;
display: block;
padding-right: 0;
padding-top: 0.4em;
margin-right: -0.2em;
}
#wiki-history table tr:nth-child(2n),
#wiki-history table tr.alt-row {
background-color: #f3f7fa;
}
#wiki-history table tr.selected {
background-color: #ffffea !important;
z-index: 100;
}
#wiki-history table tr td.commit-name {
border-left: 0;
}
#wiki-history table tr td.commit-name span.time-elapsed {
color: #999;
}
#wiki-history table tr td.author {
width: 20%;
}
#wiki-history table tr td.author a {
color: #000;
font-weight: bold;
}
#wiki-history table tr td.author a span.username {
display: block;
padding-top: 3px;
}
#wiki-history table tr td img {
background-color: #fff;
border: 1px solid #999;
display: block;
float: left;
height: 18px;
overflow: hidden;
margin: 0 0.5em 0 0;
width: 18px;
padding: 2px;
}
#wiki-history table tr td.commit-name a {
font-size: 0.9em;
font-family: 'Monaco', 'Andale Mono', Consolas, 'Courier New', monospace;
padding: 0 0.2em;
}
.history #wiki-history ul.actions li,
.history #footer ul.actions li {
margin: 0 0.6em 0 0;
}
/* @section edit */
.edit h1 {
color: #999;
font-weight: normal;
}
.edit h1 strong {
color: #000;
font-weight: bold;
}
/* @section search */
.results h1 {
color: #999;
font-weight: normal;
}
.results h1 strong {
color: #000;
font-weight: bold;
}
.results #results {
border-bottom: 1px solid #ccc;
margin-bottom: 2em;
padding-bottom: 2em;
}
.results #results ul {
margin: 2em 0 0 0;
padding: 0;
}
.results #results ul li {
font-size: 1.2em;
line-height: 1.6em;
list-style-position: outside;
padding: 0.2em 0;
}
.results #results ul li span.count {
color: #999;
}
.results p#no-results {
font-size: 1.2em;
line-height: 1.6em;
margin-top: 2em;
}
.results #footer ul.actions li {
margin: 0 1em 0 0;
}
/* @section compare */
.compare h1 {
color: #999;
font-weight: normal;
}
.compare h1 strong {
color: #000;
font-weight: bold;
}
.compare #compare-content {
margin-top: 3em;
}
.compare .data {
border: 1px solid #ddd;
margin-top: 1em;
overflow: auto;
}
.compare .data pre {
margin: 0;
padding: 0;
}
.compare .data pre div {
padding: 0 0 0 1em;
}
.compare .data tr td {
font-family: "Consolas", "Monaco", "Andale Mono", "Courier New", monospace;
font-size: 1.2em;
line-height: 1.8em;
margin: 0;
padding: 0;
}
.compare .data td.line_numbers {
background: #f7f7f7;
border-right: 1px solid #999;
color: #999;
padding: 0 0 0 0.5em;
}
.compare #compare-content ul.actions li,
.compare #footer ul.actions li {
margin-left: 0;
margin-right: 0.6em;
}
/* @control syntax */
.highlight { background: #ffffff; }
.highlight .c { color: #999988; font-style: italic }
.highlight .err { color: #a61717; background-color: #e3d2d2 }
.highlight .k { font-weight: bold }
.highlight .o { font-weight: bold }
.highlight .cm { color: #999988; font-style: italic }
.highlight .cp { color: #999999; font-weight: bold }
.highlight .c1 { color: #999988; font-style: italic }
.highlight .cs { color: #999999; font-weight: bold; font-style: italic }
.highlight .gd { color: #000000; background-color: #ffdddd }
.highlight .gd .x { color: #000000; background-color: #ffaaaa }
.highlight .ge { font-style: italic }
.highlight .gr { color: #aa0000 }
.highlight .gh { color: #999999 }
.highlight .gi { color: #000000; background-color: #ddffdd }
.highlight .gi .x { color: #000000; background-color: #aaffaa }
.highlight .gc { color: #999; background-color: #EAF2F5 }
.highlight .go { color: #888888 }
.highlight .gp { color: #555555 }
.highlight .gs { font-weight: bold }
.highlight .gu { color: #aaaaaa }
.highlight .gt { color: #aa0000 }
/* @control minibutton */
ul.actions {
display: block;
list-style-type: none;
overflow: hidden;
padding: 0;
}
ul.actions li {
float: left;
font-size: 1.2em;
margin-left: 0.6em;
}
.minibutton a {
background-color: #f7f7f7;
border: 1px solid #d4d4d4;
color: #333;
display: block;
font-weight: bold;
margin: 0;
padding: 0.4em 1em;
height: 1.4em;
text-shadow: 0 1px 0 #fff;
filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#f4f4f4', endColorstr='#ececec');
background: -webkit-gradient(linear, left top, left bottom, from(#f4f4f4), to(#ececec));
background: -moz-linear-gradient(top, #f4f4f4, #ececec);
border-radius: 3px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
}
#search-submit {
background-color: #f7f7f7;
border: 1px solid #d4d4d4;
color: #333;
display: block;
font-weight: bold;
margin: 0;
padding: 0.4em 1em;
text-shadow: 0 1px 0 #fff;
filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#f4f4f4', endColorstr='#ececec');
background: -webkit-gradient(linear, left top, left bottom, from(#f4f4f4), to(#ececec));
background: -moz-linear-gradient(top, #f4f4f4, #ececec);
border-radius: 3px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
}
.minibutton a:hover,
#search-submit:hover {
background: #3072b3;
border-color: #518cc6 #518cc6 #2a65a0;
color: #fff;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.3);
text-decoration: none;
filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#599bdc', endColorstr='#3072b3');
background: -webkit-gradient(linear, left top, left bottom, from(#599bdc), to(#3072b3));
background: -moz-linear-gradient(top, #599bdc, #3072b3);
}
.minibutton a:visited {
text-decoration: none;
}
/* @special error */
#wiki-wrapper.error {
height: 1px;
position: absolute;
overflow: visible;
top: 50%;
width: 100%;
}
#error {
background-color: #f9f9f9;
border: 1px solid #e4e4e4;
left: 50%;
overflow: hidden;
padding: 2%;
margin: -10% 0 0 -35%;
position: absolute;
width: 70%;
border-radius: 0.5em;
-moz-border-radius: 0.5em;
-webkit-border-radius: 0.5em;
}
#error h1 {
font-size: 3em;
line-height: normal;
margin: 0;
padding: 0;
}
#error p {
font-size: 1.2em;
line-height: 1.6em;
margin: 1em 0 0.5em;
padding: 0;
}
/* @control searchbar */
#head #searchbar {
float: right;
margin: 1em 0 0 0;
padding: 0;
overflow: hidden;
}
#head #searchbar #searchbar-fauxtext {
background: #fff;
border: 1px solid #d4d4d4;
overflow: hidden;
border-radius: 0.3em;
-moz-border-radius: 0.3em;
-webkit-border-radius: 0.3em;
}
#head #searchbar #searchbar-fauxtext input#search-query {
border: none;
color: #000;
float: left;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: 1.2em;
height: 1.8em;
-webkit-focus-ring: none;
}
.ff #head #searchbar #searchbar-fauxtext input#search-query {
padding: 0.2em 0 0.2em 0.5em;
}
.ie #head #searchbar #searchbar-fauxtext input#search-query {
padding: 0.4em 0 0 0.5em;
}
#head #searchbar #searchbar-fauxtext input#search-query.ph {
color: #999;
}
#head #searchbar #searchbar-fauxtext #search-submit {
border: 0;
border-left: 1px solid #d4d4d4;
cursor: pointer;
margin: 0 !important;
padding: 0;
float: right;
font-size: 1.2em;
border-radius: 0 3px 3px 0;
-moz-border-radius: 0 3px 3px 0;
-webkit-border-radius: 0 3px 3px 0;
}
#head #searchbar #searchbar-fauxtext #search-submit span {
background-image: url(/images/icon-sprite.png);
background-position: -431px -1px;
background-repeat: no-repeat;
display: block;
height: 2em;
overflow: hidden;
text-indent: -5000px;
width: 28px;
}
.ff #head #searchbar #searchbar-fauxtext #search-submit span,
.ie #head #searchbar #searchbar-fauxtext #search-submit span {
height: 2.2em;
}
#head #searchbar #searchbar-fauxtext #search-submit:hover span {
background-position: -431px -28px;
padding: 0;
}
#MathJax_Message {
display: none;
}
+316
View File
@@ -0,0 +1,316 @@
/*
Gollum v3 Template
*/
#template {
font-size: 13px;
line-height: 23px;
margin-bottom: 40px;
}
/* Link Colors */
a.absent {
color: #c00;
}
/* Primary Body Copy */
#template p {
margin: 16px 0 0;
padding: 0;
}
/* ReST first graf in nested list */
#template * li p.first {
display: inline-block;
}
/* Headings */
#template h1, #template h2, #template h3,
#template h4, #template h5, #template h6 {
margin: 0;
padding: 0;
}
#template h1 {
border-top: 4px solid #ccc;
font-size: 32px;
line-height: normal;
padding: 10px 0 0;
margin: 30px 0 0;
}
#template h2 {
border-top: 4px solid #ccc;
font-size: 22px;
line-height: normal;
margin: 22px 0 0;
padding: 7px 0 0;
}
#template h3 {
font-size: 16px;
line-height: 26px;
padding: 26px 0 0;
}
#template h4 {
font-size: 14px;
line-height: 26px;
padding: 18px 0 4px;
font-weight: bold;
text-transform: uppercase;
}
#template h5 {
font-size: 13px;
line-height: 26px;
margin-bottom: -19px;
padding: 14px 0 0;
font-weight: bold;
text-transform: uppercase;
}
#template h6 {
color: #666;
font-size: 14px;
line-height: 26px;
margin-bottom: -19px;
padding: 18px 0 0;
font-weight: normal;
font-variant: italic;
}
#template hr {
background-color: #ccc;
color: #ccc;
border: 2px solid #ccc;
margin: 20px 0;
padding: 0;
}
/* Border Reset for headers with horizontal rules */
#template > h2:first-child,
#template > h1:first-child {
border: 0;
margin: 12px 0 0;
padding: 10px 0 0;
}
/* Lists, Blockquotes & Such */
#template ul,
#template ol {
margin: 0;
padding: 20px 0 0;
list-style-position: inside;
}
/* Nested Lists */
#template ul li ul,
#template ol li ol,
#template ul li ol,
#template ol li ul,
#template ul ul,
#template ol ol {
padding: 0 0 0 14px;
}
#template dl {
margin: 0;
padding: 20px 0 0;
}
#template dl dt {
font-size: 14px;
font-weight: bold;
line-height: normal;
margin: 0;
padding: 20px 0 0;
}
#template dl dt:first-child {
padding: 0;
}
#template dl dd {
font-size: 13px;
margin: 0;
padding: 3px 0 0;
}
/* Tables */
#template table {
border-collapse: collapse;
margin: 20px 0 0;
padding: 0;
}
#template table * tr {
border-top: 1px solid #ccc;
background-color: #fff;
margin: 0;
padding: 0;
}
#template table * tr:nth-child(2n) {
background-color: #f8f8f8;
}
#template table * tr th,
#template table * tr td {
border: 1px solid #ccc;
text-align: left;
margin: 0;
padding: 6px 13px;
}
/* Images & Stuff */
#template img {
max-width: 100%;
}
/* Gollum Image Tags */
/* Framed */
#template span.frame {
display: block;
overflow: hidden;
}
#template span.frame > span {
border: 1px solid #ddd;
display: block;
float: left;
overflow: hidden;
margin: 13px 0 0;
padding: 7px;
width: auto;
}
#template span.frame span img {
display: block;
float: left;
}
#template span.frame span span {
clear: both;
color: #333;
display: block;
padding: 5px 0 0;
}
#template span.align-center {
display: block;
overflow: hidden;
clear: both;
}
#template span.align-center > span {
display: block;
overflow: hidden;
margin: 13px auto 0;
text-align: center;
}
#template span.align-center span img {
margin: 0 auto;
text-align: center;
}
#template span.align-right {
display: block;
overflow: hidden;
clear: both;
}
#template span.align-right > span {
display: block;
overflow: hidden;
margin: 13px 0 0;
text-align: right;
}
#template span.align-right span img {
margin: 0;
text-align: right;
}
#template span.float-left {
display: block;
margin-right: 13px;
overflow: hidden;
float: left;
}
#template span.float-left span {
margin: 13px 0 0;
}
#template span.float-right {
display: block;
margin-left: 13px;
overflow: hidden;
float: right;
}
#template span.float-right > span {
display: block;
overflow: hidden;
margin: 13px auto 0;
text-align: right;
}
/* Code */
#template code, #template tt {
background-color: #f8f8f8;
border: 1px solid #dedede;
font-size: 13px;
padding: 1px 5px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
}
#template .highlight pre, #template pre {
background-color: #f8f8f8;
border: 1px solid #ccc;
font-size: 13px;
line-height: 19px;
overflow: auto;
padding: 6px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
}
#template pre code, #template pre tt {
background-color: transparent;
border: none;
}
#template .highlight { background: #ffffff; }
#template .highlight .c { color: #999988; font-style: italic }
#template .highlight .err { color: #a61717; background-color: #e3d2d2 }
#template .highlight .k { font-weight: bold }
#template .highlight .o { font-weight: bold }
#template .highlight .cm { color: #999988; font-style: italic }
#template .highlight .cp { color: #999999; font-weight: bold }
#template .highlight .c1 { color: #999988; font-style: italic }
#template .highlight .cs { color: #999999; font-weight: bold; font-style: italic }
#template .highlight .gd { color: #000000; background-color: #ffdddd }
#template .highlight .gd .x { color: #000000; background-color: #ffaaaa }
#template .highlight .ge { font-style: italic }
#template .highlight .gr { color: #aa0000 }
#template .highlight .gh { color: #999999 }
#template .highlight .gi { color: #000000; background-color: #ddffdd }
#template .highlight .gi .x { color: #000000; background-color: #aaffaa }
#template .highlight .gc { color: #999; background-color: #EAF2F5 }
#template .highlight .go { color: #888888 }
#template .highlight .gp { color: #555555 }
#template .highlight .gs { font-weight: bold }
#template .highlight .gu { color: #aaaaaa }
#template .highlight .gt { color: #aa0000 }
@@ -1,121 +0,0 @@
*, html {
font-family: Verdana, Arial, Helvetica, sans-serif;
}
#results a:hover {
background-color: #4c4c4c;
}
#home_button {
position: absolute;
top: 10px;
left: 50%;
}
#home_button .minibutton {
font-size: 1em;
text-align: center;
}
#results {
position: absolute;
top: 60px;
left: 10px;
}
body, form, ul, li, p, h1, h2, h3, h4, h5 {
margin: 0;
padding: 0;
}
body {
background-color: #606061;
color: #ffffff;
margin: 0;
}
img {
border: none;
}
p {
font-size: 1em;
margin: 0 0 1em 0;
}
html { font-size: 100%; /* IE hack */ }
body { font-size: 1em; /* Sets base font size to 16px */ }
table { font-size: 100%; /* IE hack */ }
input, select, textarea, th, td { font-size: 1em; }
/* Prevent wrapping on large file names. */
li.file {
white-space: nowrap;
}
/* CSS Tree menu styles */
ol.tree
{
padding: 0 0 0 30px;
width: 300px;
}
li
{
position: relative;
margin-left: -15px;
list-style: none;
}
li.file
{
margin-left: -1px !important;
height: 1.5em;
}
li.file a
{
background: url(../images/fileview/document.png) 0 0 no-repeat;
color: #fff;
padding-left: 21px;
text-decoration: none;
display: block;
}
li.file a[href *= '.pdf'] { background: url(../images/fileview/document.png) 0 0 no-repeat; }
li.file a[href *= '.html'] { background: url(../images/fileview/document.png) 0 0 no-repeat; }
li.file a[href $= '.css'] { background: url(../images/fileview/document.png) 0 0 no-repeat; }
li.file a[href $= '.js'] { background: url(../images/fileview/document.png) 0 0 no-repeat; }
li input
{
position: absolute;
left: 0;
margin-left: 0;
opacity: 0;
z-index: 2;
cursor: pointer;
height: 1em;
width: 1em;
top: 0;
}
li input + ol
{
background: url(../images/fileview/toggle-small-expand.png) 40px 0 no-repeat;
margin: -1.188em 0 0 -44px; /* 15px */
height: 1.5em;
}
li input + ol > li { display: none; margin-left: -14px !important; padding-left: 1px; }
li label
{
background: url(../images/fileview/folder-horizontal.png) 15px 1px no-repeat;
cursor: pointer;
display: block;
padding-left: 37px;
}
li input:checked + ol
{
background: url(../images/fileview/toggle-small.png) 40px 5px no-repeat;
margin: -1.5em 0 0 -44px; /* 20px */
padding: 1.563em 0 0 80px;
height: auto;
}
li input:checked + ol > li { display: block; margin: 0 0 0.125em; /* 2px */}
li input:checked + ol > li:last-child { margin: 0 0 0.063em; /* 1px */ }
@@ -1,716 +0,0 @@
#wiki-wrapper #template blockquote {
margin: 1em 0;
border-left: 4px solid #ddd;
padding-left: .8em;
color: #555;
}
/*
gollum.css
A basic stylesheet for Gollum
*/
/* @section core */
body, html {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 10px;
margin: 0;
padding: 0;
}
#wiki-wrapper {
margin: 0 auto;
overflow: visible;
width: 80%;
}
a:link {
color: #4183c4;
text-decoration: none;
}
a:hover, a:visited {
color: #4183c4;
text-decoration: underline;
}
/* @section head */
#head {
border-bottom: 1px solid #ddd;
margin: 4em 0 1.5em;
padding-bottom: 0.3em;
overflow: hidden;
}
#head h1 {
font-size: 33px;
float: left;
line-height: normal;
margin: 0;
padding: 2px 0 0 0;
}
#head ul.actions {
float: right;
}
/* @section content */
#wiki-content {
height: 1%;
overflow: visible;
}
#wiki-content .wrap {
height: 1%;
overflow: auto;
}
/* @section comments */
#wiki-body #inline-comment {
display: none; /* todo */
}
/* @section body */
#wiki-body {
display: block;
float: left;
clear: left;
margin-right: 3%;
margin-bottom: 40px;
width: 100%;
}
.has-rightbar #wiki-body {
width: 68%;
}
/* @section toc */
#wiki-toc-main {
background-color: #F7F7F7;
border: 1px solid #DDD;
font-size: 13px;
padding: 0px 5px;
float:left;
margin-bottom: 20px;
min-width: 33%;
border-radius: 0.5em;
-moz-border-radius: 0.5em;
-webkit-border-radius: 0.5em;
}
#wiki-toc-main > div {
border: none;
}
/* @section rightbar */
#wiki-rightbar {
background-color: #f7f7f7;
border: 1px solid #ddd;
font-size: 13px;
float: right;
padding: 7px;
width: 25%;
color: #555;
border-radius: 0.5em;
-moz-border-radius: 0.5em;
-webkit-border-radius: 0.5em;
}
#wiki-rightbar p {
margin: 13px 0 0;
}
#wiki-rightbar > p:first-child {
margin-top: 10px;
}
#wiki-rightbar p.parent {
border-bottom: 1px solid #bbb;
font-weight: bold;
margin: 0 0 0.5em 0;
padding: 0 0 0.5em 0;
text-shadow: 0 1px 0 #fff;
}
/* Back arrow */
#wiki-rightbar p.parent:before {
color: #666;
content: "← ";
}
/* @section footer */
#wiki-footer {
clear: both;
margin: 2em 0 5em;
}
.has-rightbar #wiki-footer {
width: 70%;
}
#wiki-header #header-content,
#wiki-footer #footer-content {
background-color: #f7f7f7;
border: 1px solid #ddd;
padding: 1em;
border-radius: 0.5em;
-moz-border-radius: 0.5em;
-webkit-border-radius: 0.5em;
}
#wiki-header #header-content {
margin-bottom: 1.5em;
}
#wiki-footer #footer-content {
margin-top: 1.5em;
}
#wiki-footer #footer-content h3 {
font-size: 1.2em;
color: #333;
margin: 0;
padding: 0 0 0.2em;
text-shadow: 0 1px 0 #fff;
}
#wiki-footer #footer-content p {
margin: 0.5em 0 0;
padding: 0;
}
#wiki-footer #footer-content ul.links {
margin: 0.5em 0 0;
overflow: hidden;
padding: 0;
}
#wiki-footer #footer-content ul.links li {
color: #999;
float: left;
list-style-position: inside;
list-style-type: square;
padding: 0;
margin-left: 0.75em;
}
#wiki-footer #footer-content ul.links li a {
font-weight: bold;
text-shadow: 0 1px 0 #fff;
}
#wiki-footer #footer-content ul.links li:first-child {
list-style-type: none;
margin: 0;
}
.ff #wiki-footer #footer-content ul.links li:first-child {
margin: 0 -0.75em 0 0;
}
/* @section page-footer */
.page #footer {
clear: both;
border-top: 1px solid #ddd;
margin: 1em 0 7em;
}
#footer p#last-edit {
font-size: .9em;
line-height: 1.6em;
color: #999;
margin: 0.9em 0;
}
#footer p#last-edit span.username {
font-weight: bold;
}
/* @section history */
.history h1 {
color: #999;
font-weight: normal;
}
.history h1 strong {
color: #000;
font-weight: bold;
}
#wiki-history {
margin-top: 2em;
}
#wiki-history fieldset {
border: 0;
margin: 1em 0;
padding: 0;
}
#wiki-history table, #wiki-history tbody {
border-collapse: collapse;
padding: 0;
margin: 0;
width: 100%;
}
#wiki-history table tr {
padding: 0;
margin: 0;
}
#wiki-history table tr {
background-color: #ebf2f6;
}
#wiki-history table tr td {
border: 1px solid #c0dce9;
font-size: 1em;
line-height: 1.6em;
margin: 0;
padding: 0.3em 0.7em;
}
#wiki-history table tr td.checkbox {
width: 4em;
padding: 0.3em;
}
#wiki-history table tr td.checkbox input {
cursor: pointer;
display: block;
padding-right: 0;
padding-top: 0.4em;
margin: 0 auto;
width: 1.2em;
height: 1.2em;
}
#wiki-history table tr:nth-child(2n),
#wiki-history table tr.alt-row {
background-color: #f3f7fa;
}
#wiki-history table tr.selected {
background-color: #ffffea !important;
z-index: 100;
}
#wiki-history table tr td.commit-name {
border-left: 0;
}
#wiki-history table tr td.commit-name span.time-elapsed {
color: #999;
}
#wiki-history table tr td.author {
width: 20%;
}
#wiki-history table tr td.author a {
color: #000;
font-weight: bold;
}
#wiki-history table tr td.author a span.username {
display: block;
padding-top: 3px;
}
#wiki-history table tr td img {
background-color: #fff;
border: 1px solid #999;
display: block;
float: left;
height: 18px;
overflow: hidden;
margin: 0 0.5em 0 0;
width: 18px;
padding: 2px;
}
#wiki-history table tr td.commit-name a {
font-size: 0.9em;
font-family: 'Monaco', 'Andale Mono', Consolas, 'Courier New', monospace;
padding: 0 0.2em;
}
.history #footer {
margin-bottom: 7em;
}
.history #wiki-history ul.actions li,
.history #footer ul.actions li {
margin: 0 0.6em 0 0;
}
/* @section edit */
.edit h1 {
color: #999;
font-weight: normal;
}
.edit h1 strong {
color: #000;
font-weight: bold;
}
/* @section search */
.results h1 {
color: #999;
font-weight: normal;
}
.results h1 strong {
color: #000;
font-weight: bold;
}
.results #results {
border-bottom: 1px solid #ccc;
margin-bottom: 2em;
padding-bottom: 2em;
}
.results #results ul {
margin: 2em 0 0 0;
padding: 0;
}
.results #results ul li {
font-size: 1.2em;
line-height: 1.6em;
list-style-position: outside;
padding: 0.2em 0;
}
.results #results ul li span.count {
color: #999;
}
.results p#no-results {
font-size: 1.2em;
line-height: 1.6em;
margin-top: 2em;
}
.results #footer ul.actions li {
margin: 0 1em 0 0;
}
/* @section compare */
.compare h1 {
color: #999;
font-weight: normal;
}
.compare h1 strong {
color: #000;
font-weight: bold;
}
.compare #compare-content {
margin-top: 3em;
}
.compare .data {
border: 1px solid #ddd;
margin: 1em 0 2em;
overflow: auto;
}
.compare .data table {
width: 100%;
}
.compare .data pre {
margin: 0;
padding: 0;
}
.compare .data pre div {
padding: 0 0 0 1em;
}
.compare .data tr td {
font-family: "Consolas", "Monaco", "Andale Mono", "Courier New", monospace;
font-size: 1.2em;
line-height: 1.2em;
margin: 0;
padding: 0;
}
.compare .data tr td + td + td {
width: 100%;
}
.compare .data td.line_numbers {
background: #f7f7f7;
border-right: 1px solid #999;
color: #999;
padding: 0 0 0 0.5em;
}
.compare #compare-content ul.actions li,
.compare #footer ul.actions li {
margin-left: 0;
margin-right: 0.6em;
}
.compare #footer {
margin-bottom: 7em;
}
/* @control syntax */
.highlight { background: #ffffff; }
.highlight .c { color: #999988; font-style: italic }
.highlight .err { color: #a61717; background-color: #e3d2d2 }
.highlight .k { font-weight: bold }
.highlight .o { font-weight: bold }
.highlight .cm { color: #999988; font-style: italic }
.highlight .cp { color: #999999; font-weight: bold }
.highlight .c1 { color: #999988; font-style: italic }
.highlight .cs { color: #999999; font-weight: bold; font-style: italic }
.highlight .gd { color: #000000; background-color: #ffdddd }
.highlight .gd .x { color: #000000; background-color: #ffaaaa }
.highlight .ge { font-style: italic }
.highlight .gr { color: #aa0000 }
.highlight .gh { color: #999999 }
.highlight .gi { color: #000000; background-color: #ddffdd }
.highlight .gi .x { color: #000000; background-color: #aaffaa }
.highlight .gc { color: #999; background-color: #EAF2F5 }
.highlight .go { color: #888888 }
.highlight .gp { color: #555555 }
.highlight .gs { font-weight: bold }
.highlight .gu { color: #aaaaaa }
.highlight .gt { color: #aa0000 }
/* @control minibutton */
ul.actions {
display: block;
list-style-type: none;
overflow: hidden;
padding: 0;
}
ul.actions li {
float: left;
font-size: 0.9em;
margin-left: 0.6em;
margin-bottom: 0.6em;
}
.minibutton a {
background-color: #f7f7f7;
border: 1px solid #d4d4d4;
color: #333;
display: block;
font-weight: bold;
margin: 0;
padding: 0.4em 1em;
height: 1.4em;
text-shadow: 0 1px 0 #fff;
filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#f4f4f4', endColorstr='#ececec');
background: -webkit-gradient(linear, left top, left bottom, from(#f4f4f4), to(#ececec));
background: -moz-linear-gradient(top, #f4f4f4, #ececec);
border-radius: 3px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
}
#search-submit {
background-color: #f7f7f7;
border: 1px solid #d4d4d4;
color: #333;
display: block;
font-weight: bold;
margin: 0;
padding: 0.4em 1em;
text-shadow: 0 1px 0 #fff;
filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#f4f4f4', endColorstr='#ececec');
background: -webkit-gradient(linear, left top, left bottom, from(#f4f4f4), to(#ececec));
background: -moz-linear-gradient(top, #f4f4f4, #ececec);
border-radius: 3px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
}
.minibutton a:hover,
#search-submit:hover {
background: #3072b3;
border-color: #518cc6 #518cc6 #2a65a0;
color: #fff;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.3);
text-decoration: none;
filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#599bdc', endColorstr='#3072b3');
background: -webkit-gradient(linear, left top, left bottom, from(#599bdc), to(#3072b3));
background: -moz-linear-gradient(top, #599bdc, #3072b3);
}
.minibutton a:visited {
text-decoration: none;
}
/* @special error */
#wiki-wrapper.error {
height: 1px;
position: absolute;
overflow: visible;
top: 50%;
width: 100%;
}
#error {
background-color: #f9f9f9;
border: 1px solid #e4e4e4;
left: 50%;
overflow: hidden;
padding: 2%;
margin: -10% 0 0 -35%;
position: absolute;
width: 70%;
border-radius: 0.5em;
-moz-border-radius: 0.5em;
-webkit-border-radius: 0.5em;
}
#error h1 {
font-size: 3em;
line-height: normal;
margin: 0;
padding: 0;
}
#error p {
font-size: 1.2em;
line-height: 1.6em;
margin: 1em 0 0.5em;
padding: 0;
}
/* @control searchbar */
#head #searchbar {
float: right;
padding: 0;
overflow: hidden;
}
#head #searchbar #searchbar-fauxtext {
background: #fff;
border: 1px solid #d4d4d4;
overflow: hidden;
height: 2.2em;
border-radius: 0.3em;
-moz-border-radius: 0.3em;
-webkit-border-radius: 0.3em;
}
#head #searchbar #searchbar-fauxtext input#search-query {
border: none;
color: #000;
float: left;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: 1em;
height: inherit;
padding: 0 .5em;
-webkit-focus-ring: none;
}
.ie8 #head #searchbar #searchbar-fauxtext input#search-query {
padding: 0.5em 0 0 0.5em;
}
#head #searchbar #searchbar-fauxtext input#search-query.ph {
color: #999;
}
#head #searchbar #searchbar-fauxtext #search-submit {
border: 0;
border-left: 1px solid #d4d4d4;
cursor: pointer;
margin: 0 !important;
padding: 0;
float: right;
height: inherit;
border-radius: 0 3px 3px 0;
-moz-border-radius: 0 3px 3px 0;
-webkit-border-radius: 0 3px 3px 0;
}
#head #searchbar #searchbar-fauxtext #search-submit span {
background-image: url(../images/icon-sprite.png);
background-position: -431px -1px;
background-repeat: no-repeat;
display: block;
height: inherit;
overflow: hidden;
text-indent: -5000px;
width: 28px;
}
.ff #head #searchbar #searchbar-fauxtext #search-submit span,
.ie #head #searchbar #searchbar-fauxtext #search-submit span {
height: 2.2em;
}
#head #searchbar #searchbar-fauxtext #search-submit:hover span {
background-position: -431px -28px;
padding: 0;
}
/* @section pages */
#pages {
font-size: 1.2em;
margin-bottom: 20px;
}
#pages ul {
list-style: none;
margin: 0;
padding: 0;
}
#pages li a.file,
#pages li a.folder {
background-image: url(/images/fileview/document.png);
background-position: 0 1px;
background-repeat: no-repeat;
padding-left: 20px;
}
#pages li a.folder {
background-image: url(/images/fileview/folder-horizontal.png);
}
#pages .breadcrumb {
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
margin: 1em 0;
padding: 0.25em;
}
@@ -1,633 +0,0 @@
/*
Gollum v3 Template
*/
/* margin & padding reset*/
* {
margin: 0;
padding: 0;
}
html, body {
color: #333;
}
body {
font: 13.34px helvetica,arial,freesans,clean,sans-serif;
line-height: 1.4;
}
img {
border: 0;
}
a {
color: #4183C4;
text-decoration: none;
}
a.absent {
color: #c00;
}
.markdown-body a[id].wiki-toc-anchor {
color: inherit;
text-decoration: none;
}
.markdown-body {
font-size: 14px;
line-height: 1.6;
}
.markdown-body>*:first-child {
margin-top: 0!important;
}
.markdown-body>*:last-child {
margin-bottom: 0!important;
}
.markdown-body a.absent {
color: #c00;
}
.markdown-body a.anchor {
display: block;
padding-left: 30px;
margin-left: -30px;
cursor: pointer;
position: absolute;
top: 0;
left: 0;
bottom: 0;
}
.markdown-body h1,
.markdown-body h2,
.markdown-body h3,
.markdown-body h4,
.markdown-body h5,
.markdown-body h6 {
margin: 20px 0 10px;
padding: 0;
font-weight: bold;
-webkit-font-smoothing: antialiased;
cursor: text;
position: relative;
}
.markdown-body h1:hover a.anchor,
.markdown-body h2:hover a.anchor,
.markdown-body h3:hover a.anchor,
.markdown-body h4:hover a.anchor,
.markdown-body h5:hover a.anchor,
.markdown-body h6:hover a.anchor {
background: url(../images/pin-20.png) no-repeat left center;
text-decoration: none;
}
.markdown-body h1 tt,
.markdown-body h1 code,
.markdown-body h2 tt,
.markdown-body h2 code,
.markdown-body h3 tt,
.markdown-body h3 code,
.markdown-body h4 tt,
.markdown-body h4 code,
.markdown-body h5 tt,
.markdown-body h5 code,
.markdown-body h6 tt,
.markdown-body h6 code {
font-size: inherit;
}
.markdown-body h1 {
font-size: 28px;
color: #000;
margin-top: 50px;
margin-bottom: 20px;
}
.markdown-body h2 {
font-size: 24px;
border-bottom: 1px solid #ccc;
color: #000;
margin-top: 40px;
margin-bottom: 20px;
}
.markdown-body h3 {
font-size: 18px;
margin-top: 30px;
margin-bottom: 15px;
}
.markdown-body h4 {
font-size: 16px;
}
.markdown-body h5 {
font-size: 14px;
}
.markdown-body h6 {
color: #777;
font-size: 14px;
}
.markdown-body p,
.markdown-body blockquote,
.markdown-body ul,
.markdown-body ol,
.markdown-body dl,
.markdown-body li,
.markdown-body table,
.markdown-body pre {
margin: 15px 0;
}
.markdown-body hr {
background: transparent url(../images/dirty-shade.png) repeat-x 0 0;
border: 0 none;
color: #ccc;
height: 4px;
padding: 0;
}
.markdown-body>h1:first-child,
.markdown-body>h2:first-child,
.markdown-body>h3:first-child,
.markdown-body>h4:first-child,
.markdown-body>h5:first-child,
.markdown-body>h6:first-child {
}
.markdown-body h1+h2{
margin-top: 30px;
}
.markdown-body h2+h3{
margin-top: 10px;
}
.markdown-body a:first-child h1,
.markdown-body a:first-child h2,
.markdown-body a:first-child h3,
.markdown-body a:first-child h4,
.markdown-body a:first-child h5,
.markdown-body a:first-child h6 {
margin-top: 0;
padding-top: 0;
}
.markdown-body h1+p,
.markdown-body h2+p,
.markdown-body h3+p,
.markdown-body h4+p,
.markdown-body h5+p,
.markdown-body h6+p {
margin-top: 0;
}
.markdown-body li p.first {
display: inline-block;
}
.markdown-body ul,
.markdown-body ol {
padding-left: 30px;
}
.markdown-body ul li>:first-child,
.markdown-body ol li>:first-child {
margin-top: 0;
}
.markdown-body ul li>:last-child,
.markdown-body ol li>:last-child {
margin-bottom: 0;
}
.markdown-body dl {
padding: 0;
}
.markdown-body dl dt {
font-size: 14px;
font-weight: bold;
font-style: italic;
padding: 0;
margin: 15px 0 5px;
}
.markdown-body dl dt:first-child {
padding: 0;
}
.markdown-body dl dt>:first-child {
margin-top: 0;
}
.markdown-body dl dt>:last-child {
margin-bottom: 0;
}
.markdown-body dl dd {
margin: 0 0 15px;
padding: 0 15px;
}
.markdown-body dl dd>:first-child {
margin-top: 0;
}
.markdown-body dl dd>:last-child {
margin-bottom: 0;
}
.markdown-body blockquote {
border-left: 4px solid #DDD;
padding: 0 15px;
color: #777;
}
.markdown-body blockquote>:first-child {
margin-top: 0;
}
.markdown-body blockquote>:last-child {
margin-bottom: 0;
}
.markdown-body table {
padding: 0;
border-collapse: collapse;
border-spacing: 0;
}
.markdown-body table tr {
border-top: 1px solid #ccc;
background-color: #fff;
margin: 0;
padding: 0;
}
.markdown-body table tr:nth-child(2n) {
background-color: #f8f8f8;
}
.markdown-body table tr th {
font-weight: bold;
}
.markdown-body table tr th,
.markdown-body table tr td {
border: 1px solid #ccc;
text-align: left;
margin: 0;
padding: 6px 13px;
}
.markdown-body table tr th>:first-child,
.markdown-body table tr td>:first-child {
margin-top: 0;
}
.markdown-body table tr th>:last-child,
.markdown-body table tr td>:last-child {
margin-bottom: 0;
}
.markdown-body img {
max-width: 100%;
}
.markdown-body span.frame {
display: block;
overflow: hidden;
}
.markdown-body span.frame>span {
border: 1px solid #ddd;
display: block;
float: left;
overflow: hidden;
margin: 13px 0 0;
padding: 7px;
width: auto;
}
.markdown-body span.frame span img {
display: block;
float: left;
}
.markdown-body span.frame span span {
clear: both;
color: #333;
display: block;
padding: 5px 0 0;
}
.markdown-body span.align-center {
display: block;
overflow: hidden;
clear: both;
}
.markdown-body span.align-center>span {
display: block;
overflow: hidden;
margin: 13px auto 0;
text-align: center;
}
.markdown-body span.align-center span img {
margin: 0 auto;
text-align: center;
}
.markdown-body span.align-right {
display: block;
overflow: hidden;
clear: both;
}
.markdown-body span.align-right>span {
display: block;
overflow: hidden;
margin: 13px 0 0;
text-align: right;
}
.markdown-body span.align-right span img {
margin: 0;
text-align: right;
}
.markdown-body span.float-left {
display: block;
margin-right: 13px;
overflow: hidden;
float: left;
}
.markdown-body span.float-left span {
margin: 13px 0 0;
}
.markdown-body span.float-right {
display: block;
margin-left: 13px;
overflow: hidden;
float: right;
}
.markdown-body span.float-right>span {
display: block;
overflow: hidden;
margin: 13px auto 0;
text-align: right;
}
.markdown-body code,
.markdown-body tt {
margin: 0 2px;
padding: 0 5px;
white-space: nowrap;
border: 1px solid #ddd;
background-color: #f8f8f8;
border-radius: 3px;
}
.markdown-body pre>tt,
.markdown-body pre>code {
margin: 0;
padding: 0;
white-space: pre;
border: none;
background: transparent;
}
.markdown-body pre {
background-color: #f8f8f8;
border: 1px solid #ccc;
font-size: 13px;
line-height: 19px;
overflow: auto;
padding: 6px 10px;
border-radius: 3px;
}
.markdown-body pre pre,
.markdown-body pre code,
.markdown-body pre tt {
background-color: transparent;
border: none;
}
.markdown-body pre pre {
margin: 0;
padding: 0;
}
.toc {
background-color: #F7F7F7;
border: 1px solid #ddd;
padding: 5px 10px;
margin: 0;
border-radius: 3px;
}
.toc-title {
color: #888;
font-size: 14px;
line-height: 1.6;
padding: 2px;
border-bottom: 1px solid #ddd;
margin-bottom: 3px;
}
.toc ul {
padding-left: 10px;
margin: 0;
}
.toc>ul {
margin-left: 10px;
font-size: 17px;
}
.toc ul ul {
font-size: 15px;
}
.toc ul ul ul {
font-size: 14px;
}
.toc ul li{
margin: 0;
}
#header-content .toc,
#footer-content .toc,
#sidebar-content .toc {
border: none;
}
.highlight {
background: #fff;
}
.highlight .c {
color: #998;
font-style: italic;
}
.highlight .err {
color: #a61717;
background-color: #e3d2d2;
}
.highlight .k {
font-weight: bold;
}
.highlight .o {
font-weight: bold;
}
.highlight .cm {
color: #998;
font-style: italic;
}
.highlight .cp {
color: #999;
font-weight: bold;
}
.highlight .c1 {
color: #998;
font-style: italic;
}
.highlight .cs {
color: #999;
font-weight: bold;
font-style: italic;
}
.highlight .gd {
color: #000;
background-color: #fdd;
}
.highlight .gd .x {
color: #000;
background-color: #faa;
}
.highlight .ge {
font-style: italic;
}
.highlight .gr {
color: #a00;
}
.highlight .gh {
color: #999;
}
.highlight .gi {
color: #000;
background-color: #dfd;
}
.highlight .gi .x {
color: #000;
background-color: #afa;
}
.highlight .go {
color: #888;
}
.highlight .gp {
color: #555;
}
.highlight .gs {
font-weight: bold;
}
.highlight .gu {
color: #800080;
font-weight: bold;
}
.highlight .gt {
color: #a00;
}
.highlight .kc {
font-weight: bold;
}
.highlight .kd {
font-weight: bold;
}
.highlight .kn {
font-weight: bold;
}
.highlight .kp {
font-weight: bold;
}
.highlight .kr {
font-weight: bold;
}
.highlight .kt {
color: #458;
font-weight: bold;
}
.highlight .m {
color: #099;
}
.highlight .s {
color: #d14;
}
.highlight .na {
color: #008080;
}
.highlight .nb {
color: #0086B3;
}
.highlight .nc {
color: #458;
font-weight: bold;
}
.highlight .no {
color: #008080;
}
.highlight .ni {
color: #800080;
}
.highlight .ne {
color: #900;
font-weight: bold;
}
.highlight .nf {
color: #900;
font-weight: bold;
}
.highlight .nn {
color: #555;
}
.highlight .nt {
color: #000080;
}
.highlight .nv {
color: #008080;
}
.highlight .ow {
font-weight: bold;
}
.highlight .w {
color: #bbb;
}
.highlight .mf {
color: #099;
}
.highlight .mh {
color: #099;
}
.highlight .mi {
color: #099;
}
.highlight .mo {
color: #099;
}
.highlight .sb {
color: #d14;
}
.highlight .sc {
color: #d14;
}
.highlight .sd {
color: #d14;
}
.highlight .s2 {
color: #d14;
}
.highlight .se {
color: #d14;
}
.highlight .sh {
color: #d14;
}
.highlight .si {
color: #d14;
}
.highlight .sx {
color: #d14;
}
.highlight .sr {
color: #009926;
}
.highlight .s1 {
color: #d14;
}
.highlight .ss {
color: #990073;
}
.highlight .bp {
color: #999;
}
.highlight .vc {
color: #008080;
}
.highlight .vg {
color: #008080;
}
.highlight .vi {
color: #008080;
}
.highlight .il {
color: #099;
}
.highlight .gc {
color: #999;
background-color: #EAF2F5;
}
.type-csharp .highlight .k {
color: #00F;
}
.type-csharp .highlight .kt {
color: #00F;
}
.type-csharp .highlight .nf {
color: #000;
font-weight: normal;
}
.type-csharp .highlight .nc {
color: #2B91AF;
}
.type-csharp .highlight .nn {
color: #000;
}
.type-csharp .highlight .s {
color: #A31515;
}
.type-csharp .highlight .sc {
color: #A31515;
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 939 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 271 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 433 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 462 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

@@ -1,266 +0,0 @@
/**
* gollum.dialog.js
*
* Used for dialogs. Duh.
*
*/
(function($) {
var Dialog = {
debugOn: false,
markupCreated: false,
markup: '',
attachEvents: function( evtOK ) {
$('#gollum-dialog-action-ok').click(function( e ) {
Dialog.eventOK( e, evtOK );
});
$('#gollum-dialog-action-cancel').click( Dialog.eventCancel );
$('#gollum-dialog-dialog input[type="text"]').keydown(function( e ) {
if ( e.keyCode == 13 ) {
Dialog.eventOK( e, evtOK );
}
});
},
detachEvents: function() {
$('#gollum-dialog-action-ok').unbind('click');
$('#gollum-dialog-action-cancel').unbind('click');
},
createFieldMarkup: function( fieldArray ) {
var fieldMarkup = '<fieldset>';
for ( var i=0; i < fieldArray.length; i++ ) {
if ( typeof fieldArray[i] == 'object' ) {
fieldMarkup += '<div class="field">';
switch ( fieldArray[i].type ) {
// only text is supported for now
case 'text':
fieldMarkup += Dialog.createFieldText( fieldArray[i] );
break;
default:
break;
}
fieldMarkup += '</div>';
}
}
fieldMarkup += '</fieldset>';
return fieldMarkup;
},
createFieldText: function( fieldAttributes ) {
var html = '';
if ( fieldAttributes.name ) {
html += '<label';
if ( fieldAttributes.id ) {
html += ' for="' + fieldAttributes.name + '"';
}
html += '>' + fieldAttributes.name + '</label>';
}
html += '<input type="text"';
if ( fieldAttributes.id ) {
html += ' name="' + fieldAttributes.id + '"'
if ( fieldAttributes.type == 'code' ) {
html+= ' class="code"';
}
if ( fieldAttributes.defaultValue ) {
html+= ' value="' + fieldAttributes.defaultValue.split('"').join('&quot;') + '"';
}
html += ' id="gollum-dialog-dialog-generated-field-' +
fieldAttributes.id + '">';
}
return html;
},
createMarkup: function( title, body ) {
Dialog.markupCreated = true;
if ($.facebox) {
return '<div id="gollum-dialog-dialog">' +
'<div id="gollum-dialog-dialog-title"><h4>' +
title +'</h4></div>' +
'<div id="gollum-dialog-dialog-body">' + body + '</div>' +
'<div id="gollum-dialog-dialog-buttons">' +
'<a href="#" title="Cancel" id="gollum-dialog-action-cancel" ' +
'class="gollum-minibutton">Cancel</a>' +
'<a href="#" title="OK" id="gollum-dialog-action-ok" '+
'class="gollum-minibutton">OK</a>' +
'</div>' +
'</div>';
} else {
return '<div id="gollum-dialog-dialog">' +
'<div id="gollum-dialog-dialog-inner">' +
'<div id="gollum-dialog-dialog-bg">' +
'<div id="gollum-dialog-dialog-title"><h4>' +
title +'</h4></div>' +
'<div id="gollum-dialog-dialog-body">' + body + '</div>' +
'<div id="gollum-dialog-dialog-buttons">' +
'<a href="#" title="Cancel" id="gollum-dialog-action-cancel" ' +
'class="minibutton">Cancel</a>' +
'<a href="#" title="OK" id="gollum-dialog-action-ok" '+
'class="minibutton">OK</a>' +
'</div>' +
'</div>' +
'</div>' +
'</div>';
}
},
eventCancel: function( e ) {
e.preventDefault();
debug('Cancelled dialog.');
Dialog.hide();
},
eventOK: function( e, evtOK ) {
e.preventDefault();
var results = [];
// get the results from each field and build them into the object
$('#gollum-dialog-dialog-body input').each(function() {
results[$(this).attr('name')] = $(this).val();
});
// pass them to evtOK if it exists (which it should)
if ( evtOK &&
typeof evtOK == 'function' ) {
evtOK( results );
}
Dialog.hide();
},
hide: function() {
if ( $.facebox ) {
Dialog.markupCreated = false;
$(document).trigger('close.facebox');
Dialog.detachEvents();
} else {
if ( $.browser.msie ) {
$('#gollum-dialog-dialog').hide().removeClass('active');
$('select').css('visibility', 'visible');
} else {
$('#gollum-dialog-dialog').animate({ opacity: 0 }, {
duration: 200,
complete: function() {
$('#gollum-dialog-dialog').removeClass('active');
}
});
}
}
},
init: function( argObject ) {
var title = '';
var body = '';
// bail out if necessary
if ( !argObject ||
typeof argObject != 'object' ) {
debug('Editor Dialog: Cannot init; invalid init object');
return;
}
if ( argObject.body && typeof argObject.body == 'string' ) {
body = '<p>' + argObject.body + '</p>';
}
// alright, build out fields
if ( argObject.fields && typeof argObject.fields == 'object' ) {
body += Dialog.createFieldMarkup( argObject.fields );
}
if ( argObject.title && typeof argObject.title == 'string' ) {
title = argObject.title;
}
if ( Dialog.markupCreated ) {
if ($.facebox) {
$(document).trigger('close.facebox');
} else {
$('#gollum-dialog-dialog').remove();
}
}
Dialog.markup = Dialog.createMarkup( title, body );
if ($.facebox) {
$(document).bind('reveal.facebox', function() {
if ( argObject.OK &&
typeof argObject.OK == 'function' ) {
Dialog.attachEvents( argObject.OK );
$($('#facebox input[type="text"]').get(0)).focus();
}
});
} else {
$('body').append( Dialog.markup );
if ( argObject.OK &&
typeof argObject.OK == 'function' ) {
Dialog.attachEvents( argObject.OK );
}
}
Dialog.show();
},
show: function() {
if ( !Dialog.markupCreated ) {
debug('Dialog: No markup to show. Please use init first.');
} else {
debug('Showing dialog');
if ($.facebox) {
$.facebox( Dialog.markup );
} else {
if ( $.browser.msie ) {
$('#gollum-dialog.dialog').addClass('active');
Dialog.position();
$('select').css('visibility', 'hidden');
} else {
$('#gollum-dialog.dialog').css('display', 'none');
$('#gollum-dialog-dialog').animate({ opacity: 0 }, {
duration: 0,
complete: function() {
$('#gollum-dialog-dialog').css('display', 'block');
Dialog.position(); // position this thing
$('#gollum-dialog-dialog').animate({ opacity: 1 }, {
duration: 500
});
}
});
}
}
}
},
position: function() {
var dialogHeight = $('#gollum-dialog-dialog-inner').height();
$('#gollum-dialog-dialog-inner')
.css('height', dialogHeight + 'px')
.css('margin-top', -1 * parseInt( dialogHeight / 2 ));
}
};
if ($.facebox) {
$(document).bind('reveal.facebox', function() {
$('#facebox img.close_image').remove();
});
}
var debug = function(m) {
if ( Dialog.debugOn
&& typeof console != 'undefined' ) {
console.log( m );
}
};
$.GollumDialog = Dialog;
})(jQuery);
@@ -1,215 +0,0 @@
// ua
$(document).ready(function() {
$('#delete-link').click( function(e) {
var ok = confirm($(this).data('confirm'));
if ( ok ) {
var loc = window.location;
loc = baseUrl + '/delete' + loc.pathname.replace(baseUrl,'');
window.location = loc;
}
// Don't navigate on cancel.
e.preventDefault();
} );
var nodeSelector = {
node1: null,
node2: null,
selectNodeRange: function( n1, n2 ) {
if ( nodeSelector.node1 && nodeSelector.node2 ) {
$('#wiki-history td.selected').removeClass('selected');
nodeSelector.node1.addClass('selected');
nodeSelector.node2.addClass('selected');
// swap the nodes around if they went in reverse
if ( nodeSelector.nodeComesAfter( nodeSelector.node1,
nodeSelector.node2 ) ) {
var n = nodeSelector.node1;
nodeSelector.node1 = nodeSelector.node2;
nodeSelector.node2 = n;
}
var s = true;
var $nextNode = nodeSelector.node1.next();
while ( $nextNode ) {
$nextNode.addClass('selected');
if ( $nextNode[0] == nodeSelector.node2[0] ) {
break;
}
$nextNode = $nextNode.next();
}
}
},
nodeComesAfter: function ( n1, n2 ) {
var s = false;
$(n1).prevAll().each(function() {
if ( $(this)[0] == $(n2)[0] ) {
s = true;
}
});
return s;
},
checkNode: function( nodeCheckbox ) {
var $nodeCheckbox = nodeCheckbox;
var $node = $(nodeCheckbox).parent().parent();
// if we're unchecking
if ( !$nodeCheckbox.is(':checked') ) {
// remove the range, since we're breaking it
$('#wiki-history tr.selected').each(function() {
if ( $(this).find('td.checkbox input').is(':checked') ) {
return;
}
$(this).removeClass('selected');
});
// no longer track this
if ( $node[0] == nodeSelector.node1[0] ) {
nodeSelector.node1 = null;
if ( nodeSelector.node2 ) {
nodeSelector.node1 = nodeSelector.node2;
nodeSelector.node2 = null;
}
} else if ( $node[0] == nodeSelector.node2[0] ) {
nodeSelector.node2 = null;
}
} else {
if ( !nodeSelector.node1 ) {
nodeSelector.node1 = $node;
nodeSelector.node1.addClass('selected');
} else if ( !nodeSelector.node2 ) {
// okay, we don't have a node 2 but have a node1
nodeSelector.node2 = $node;
nodeSelector.node2.addClass('selected');
nodeSelector.selectNodeRange( nodeSelector.node1,
nodeSelector.node2 );
} else {
// we have two selected already
$nodeCheckbox[0].checked = false;
}
}
}
};
// ua detection
if ($.browser.mozilla) {
$('body').addClass('ff');
} else if ($.browser.webkit) {
$('body').addClass('webkit');
} else if ($.browser.msie) {
$('body').addClass('ie');
if ($.browser.version == "7.0") {
$('body').addClass('ie7');
} else if ($.browser.version == "8.0") {
$('body').addClass('ie8');
}
}
if ($('#minibutton-rename-page').length) {
$('#minibutton-rename-page').removeClass('jaws');
$('#minibutton-rename-page').click(function(e) {
e.preventDefault();
// Path name without the leading slash.
var pathname = window.location.pathname.substr(1);
var slashIndex = pathname.lastIndexOf('/');
var oldName = pathname.substr(slashIndex + 1)
var path = pathname.substr(0, slashIndex);
$.GollumDialog.init({
title: 'Rename Page',
fields: [
{
id: 'name',
name: 'Rename to',
type: 'text',
defaultValue: oldName || ''
}
],
OK: function( res ) {
var newName = 'Rename Page';
if ( res['name'] ) {
newName = res['name'];
}
var msg = 'Renamed ' + oldName + ' to ' + newName;
jQuery.ajax( {
type: 'POST',
url: baseUrl + '/edit/' + oldName,
data: { path: path, rename: newName, page: oldName, message: msg },
success: function() {
window.location = baseUrl + '/' + encodeURIComponent(newName);
}
});
}
});
});
}
if ($('#minibutton-new-page').length) {
$('#minibutton-new-page').removeClass('jaws');
$('#minibutton-new-page').click(function(e) {
e.preventDefault();
$.GollumDialog.init({
title: 'Create New Page',
fields: [
{
id: 'name',
name: 'Page Name',
type: 'text',
defaultValue: ''
}
],
OK: function( res ) {
var name = 'New Page';
if ( res['name'] ) {
name = res['name'];
}
window.location = baseUrl + '/' + encodeURIComponent(name);
}
});
});
}
if ($('#wiki-wrapper').hasClass('history')) {
$('#wiki-history td.checkbox input').each(function() {
$(this).click(function() {
nodeSelector.checkNode($(this));
});
if ( $(this).is(':checked') ) {
nodeSelector.checkNode($(this));
}
});
if ($('.history a.action-compare-revision').length) {
$('.history a.action-compare-revision').click(function() {
$("#version-form").submit();
});
}
}
if ($('#searchbar a#search-submit').length) {
$.GollumPlaceholder.add($('#searchbar #search-query'));
$('#searchbar a#search-submit').click(function(e) {
e.preventDefault();
$('#searchbar #search-form')[0].submit();
});
$('#searchbar #search-form').submit(function(e) {
$.GollumPlaceholder.clearAll();
$(this).unbind('submit');
$(this).submit();
});
}
if ($('#gollum-revert-form').length &&
$('.gollum-revert-button').length ) {
$('a.gollum-revert-button').click(function(e) {
e.preventDefault();
$('#gollum-revert-form').submit();
});
}
});
File diff suppressed because one or more lines are too long
@@ -1,8 +0,0 @@
/* mousetrap v1.1.2 craig.is/killing/mice */
window.Mousetrap=function(){function o(a,c,b){if(a.addEventListener)return a.addEventListener(c,b,!1);a.attachEvent("on"+c,b)}function u(a){return"keypress"==a.type?String.fromCharCode(a.which):h[a.which]?h[a.which]:v[a.which]?v[a.which]:String.fromCharCode(a.which).toLowerCase()}function p(a){var a=a||{},c=!1,b;for(b in l)a[b]?c=!0:l[b]=0;c||(n=!1)}function w(a,c,b,d,C){var g,e,f=[];if(!j[a])return[];"keyup"==b&&q(a)&&(c=[a]);for(g=0;g<j[a].length;++g)if(e=j[a][g],!(e.seq&&l[e.seq]!=e.level)&&b==
e.action&&("keypress"==b||c.sort().join(",")===e.modifiers.sort().join(",")))d&&e.combo==C&&j[a].splice(g,1),f.push(e);return f}function r(a,c){!1===a(c)&&(c.preventDefault&&c.preventDefault(),c.stopPropagation&&c.stopPropagation(),c.returnValue=!1,c.cancelBubble=!0)}function s(a){a.which="number"==typeof a.which?a.which:a.keyCode;var c=u(a);if(c)if("keyup"==a.type&&t==c)t=!1;else{var b=a.target||a.srcElement,d=b.tagName;if(!(-1<(" "+b.className+" ").indexOf(" mousetrap ")?0:"INPUT"==d||"SELECT"==
d||"TEXTAREA"==d||b.contentEditable&&"true"==b.contentEditable)){b=[];a.shiftKey&&b.push("shift");a.altKey&&b.push("alt");a.ctrlKey&&b.push("ctrl");a.metaKey&&b.push("meta");for(var b=w(c,b,a.type),f={},g=!1,d=0;d<b.length;++d)b[d].seq?(g=!0,f[b[d].seq]=1,r(b[d].callback,a)):!g&&!n&&r(b[d].callback,a);a.type==n&&!q(c)&&p(f)}}}function q(a){return"shift"==a||"ctrl"==a||"alt"==a||"meta"==a}function x(a,c,b){if(!b){if(!k){k={};for(var d in h)95<d&&112>d||h.hasOwnProperty(d)&&(k[h[d]]=d)}b=k[a]?"keydown":
"keypress"}"keypress"==b&&c.length&&(b="keydown");return b}function y(a,c,b,d,f){var a=a.replace(/\s+/g," "),g=a.split(" "),e,h,i=[];if(1<g.length){var k=a,m=b;l[k]=0;m||(m=x(g[0],[]));a=function(){n=m;++l[k];clearTimeout(z);z=setTimeout(p,1E3)};b=function(a){r(c,a);"keyup"!==m&&(t=u(a));setTimeout(p,10)};for(d=0;d<g.length;++d)y(g[d],d<g.length-1?a:b,m,k,d)}else{h="+"===a?["+"]:a.split("+");for(g=0;g<h.length;++g)e=h[g],A[e]&&(e=A[e]),b&&("keypress"!=b&&B[e])&&(e=B[e],i.push("shift")),q(e)&&i.push(e);
b=x(e,i,b);j[e]||(j[e]=[]);w(e,i,b,!d,a);j[e][d?"unshift":"push"]({callback:c,modifiers:i,action:b,seq:d,level:f,combo:a})}}for(var h={8:"backspace",9:"tab",13:"enter",16:"shift",17:"ctrl",18:"alt",20:"capslock",27:"esc",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down",45:"ins",46:"del",91:"meta",93:"meta",224:"meta"},v={106:"*",107:"+",109:"-",110:".",111:"/",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'"},B=
{"~":"`","!":"1","@":"2","#":"3",$:"4","%":"5","^":"6","&":"7","*":"8","(":"9",")":"0",_:"-","+":"=",":":";",'"':"'","<":",",">":".","?":"/","|":"\\"},A={option:"alt",command:"meta","return":"enter",escape:"esc"},k,j={},i={},l={},z,t=!1,n=!1,f=1;20>f;++f)h[111+f]="f"+f;for(f=0;9>=f;++f)h[f+96]=f;o(document,"keypress",s);o(document,"keydown",s);o(document,"keyup",s);return{bind:function(a,c,b){for(var d=a instanceof Array?a:[a],f=0;f<d.length;++f)y(d[f],c,b);i[a+":"+b]=c},unbind:function(a,c){i[a+
":"+c]&&(delete i[a+":"+c],this.bind(a,function(){},c))},trigger:function(a,c){i[a+":"+c]()},reset:function(){j={};i={}}}}();
@@ -1,132 +0,0 @@
body {
overflow: hidden;
}
#editor .ace_sb {
overflow-y: auto !important;
}
#darkness {
visibility: hidden;
position: absolute;
left: 0px;
top: 0px;
background-color: black;
opacity: 0.8;
z-index: 1001; /* must be > 1000 to overlay ace gutter */
}
#commenttoolpanel {
visibility: hidden;
z-index: 1002; /* > 1001 to not be hidden by darkness */
}
#comment, #editor {
margin: 0;
padding: 0;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
/* Set font size of both ace editors. */
font-size: 16px;
}
/*
Must set ace-line to preserve whitespace in empty lines.
Ace editor sets the height inline. The static highlight ext does not.
<div class="ace_line" style="height:15px"></div>
*/
#previewframe #contentframe .ace-github .ace_editor.ace_scroller.ace_text-layer .ace_line {
height: 15px;
}
/* Set comment to have a higher z-index
so editor doesn't display in the background. */
#comment {
visibility: hidden;
z-index: 1003; /* > 1002 to not be hidden by toolpanel */
}
#contentframe {
margin: 0 auto;
overflow: visible;
width: 90%;
}
#previewframe {
margin: 0;
padding: 0;
position: absolute;
overflow: auto;
top: 0;
bottom: 0;
left: 10px;
right: 0;
}
.editor_bg {
position: fixed;
top: 0;
margin: 0;
padding: 0;
background: black;
width: 50%;
height: 100%;
z-index: -2;
}
.toolpanel_bg {
position: fixed;
background: #666;
top: 0;
height: 30px;
width: 100%;
padding: 5px 0;
margin: 0;
z-index: -1;
}
/* -- Start from notepag.es -- */
.toolpanel {
position: fixed;
background: #666;
top: 0;
height: 30px;
width: 50%;
vertical-align: middle;
padding: 5px 0;
margin: 0;
text-align: center;
}
.toolpanel.edit a.edit {
opacity: 0.4;
/* Make it appear as a link even though save
doesn't have a href attribute. */
cursor: pointer;
display: inline-block;
}
.toolpanel a {
color: white;
text-decoration: none;
margin: 0 5px;
display: none;
padding: 4px;
font-family: sans-serif;
}
.toolpanel a img {
vertical-align: middle;
margin-left: 5px;
margin: 0;
padding: 0;
}
a img {
border: none;
}
/* -- End from notepag.es -- */
Binary file not shown.

Before

Width:  |  Height:  |  Size: 525 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 757 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 235 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 278 B

@@ -1,49 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Live Preview</title>
<link rel='stylesheet' type='text/css' href='../css/template.css' />
<link rel='stylesheet' type='text/css' href='css/custom.css' />
</head>
<body>
<div id='editor'></div>
<div id='previewframe'><div id='contentframe' class='markdown-body'></div></div>
<!-- tool panel from notepage.es. save & savecomment icons from Retina Display Icon Set. -->
<div id='toolpanel' class='toolpanel edit' style='width: 500px; right: 0px; visibility: hidden;'>
<a id='save' class='edit'><img src='images/save_24.png' alt='Save' title='Save'></a>
<a id='savecomment' class='edit'><img src='images/savecomment_24.png' alt='Save with comment' title='Save with comment'></a>
<a id='toggle' class='edit' href='javascript:void(0)' onclick='jsm.toggleLeftRight();'><img src='images/lr_24.png' alt='Toggle left to right' title='Toggle left to right'></a>
</div>
<div class='editor_bg'></div>
<div class='toolpanel_bg'></div>
<div id='commenttoolpanel' class='toolpanel edit' style='width: 500px; right: 0px; '>
<a id='savecommentconfirm' class='edit'><img src='images/savecomment_24.png' alt='Confirm save with comment' title='Confirm save with comment'></a>
<a id='commentcancel' class='edit'><img src='images/cancel_24.png' alt='Cancel save with comment' title='Cancel save with comment'></a>
</div>
<div id='comment'></div>
<div id='darkness'></div>
<script>
var require = {
paths: {
ace: 'js/ace/lib/ace'
}
};
</script>
<script src='js/requirejs.min.js'></script>
<script src='../javascript/jquery-1.7.2.min.js'></script>
<script src='js/jquery.ba-throttle-debounce.min.js'></script>
<script src='js/sundown.js'></script>
<script src='js/md_sundown.js'></script>
<script src='js/livepreview.js'></script>
<!--<script>(function(d,j){
j = d.createElement('script');
j.src = 'https://c328740.ssl.cf1.rackcdn.com/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML';
(d.head || d.getElementsByTagName('head')[0]).appendChild(j);
}(document));
</script>-->
</body>
</html>
@@ -1,103 +0,0 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Skywriter.
*
* The Initial Developer of the Original Code is
* Mozilla.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Kevin Dangoor (kdangoor@mozilla.com)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/**
* class Ace
*
* The main class required to set up an Ace instance in the browser.
*
*
**/
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;
var MultiSelect = require("./multi_select").MultiSelect;
// The following require()s are for inclusion in the built ace file
require("./worker/worker_client");
require("./keyboard/hash_handler");
require("./keyboard/state_handler");
require("./placeholder");
exports.config = require("./config");
/**
* Ace.edit(el) -> Editor
* - el (String | DOMElement): Either the id of an element, or the element itself
*
* This method embeds the Ace editor into the DOM, at the element provided by `el`.
*
**/
exports.edit = function(el) {
if (typeof(el) == "string") {
el = document.getElementById(el);
}
if (el.env && el.env.editor instanceof Editor)
return el.env.editor;
var doc = new EditSession(Dom.getInnerText(el));
doc.setUndoManager(new UndoManager());
el.innerHTML = '';
var editor = new Editor(new Renderer(el, require("./theme/textmate")));
new MultiSelect(editor);
editor.setSession(doc);
var env = {};
env.document = doc;
env.editor = editor;
editor.resize();
Event.addListener(window, "resize", function() {
editor.resize();
});
el.env = env;
// Store env on editor such that it can be accessed later on from
// the returned object.
editor.env = env;
return editor;
};
});
@@ -1,254 +0,0 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
"use strict";
var oop = require("./lib/oop");
var EventEmitter = require("./lib/event_emitter").EventEmitter;
/**
* class Anchor
*
* Defines the floating pointer in the document. Whenever text is inserted or deleted before the cursor, the position of the cursor is updated
*
**/
/**
* new Anchor(doc, row, column)
* - doc (Document): The document to associate with the anchor
* - row (Number): The starting row position
* - column (Number): The starting column position
*
* Creates a new `Anchor` and associates it with a document.
*
**/
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);
/**
* Anchor.getPosition() -> Object
*
* Returns an object identifying the `row` and `column` position of the current anchor.
*
**/
this.getPosition = function() {
return this.$clipPositionToDocument(this.row, this.column);
};
/**
* Anchor.getDocument() -> Document
*
* Returns the current document.
*
**/
this.getDocument = function() {
return this.document;
};
/**
* Anchor@onChange(e)
* - e (Event): Contains data about the event
*
* Fires whenever the anchor position changes. Events that can trigger this function include `'includeText'`, `'insertLines'`, `'removeText'`, and `'removeLines'`.
*
**/
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;
if (delta.action === "insertText") {
if (range.start.row === row && range.start.column <= column) {
if (range.start.row === range.end.row) {
column += range.end.column - range.start.column;
}
else {
column -= range.start.column;
row += range.end.row - range.start.row;
}
}
else if (range.start.row !== range.end.row && range.start.row < row) {
row += range.end.row - range.start.row;
}
} else if (delta.action === "insertLines") {
if (range.start.row <= row) {
row += range.end.row - range.start.row;
}
}
else if (delta.action == "removeText") {
if (range.start.row == row && range.start.column < column) {
if (range.end.column >= column)
column = range.start.column;
else
column = Math.max(0, column - (range.end.column - range.start.column));
} else if (range.start.row !== range.end.row && range.start.row < row) {
if (range.end.row == row) {
column = Math.max(0, column - range.end.column) + range.start.column;
}
row -= (range.end.row - range.start.row);
}
else if (range.end.row == row) {
row -= range.end.row - range.start.row;
column = Math.max(0, column - range.end.column) + range.start.column;
}
} else if (delta.action == "removeLines") {
if (range.start.row <= row) {
if (range.end.row <= row)
row -= range.end.row - range.start.row;
else {
row = range.start.row;
column = 0;
}
}
}
this.setPosition(row, column, true);
};
/**
* Anchor.setPosition(row, column, noClip)
* - row (Number): The row index to move the anchor to
* - column (Number): The column index to move the anchor to
* - noClip (Boolean): Identifies if you want the position to be clipped
*
* Sets the anchor position to the specified row and column. If `noClip` is `true`, the position is not 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
});
};
/**
* Anchor.detach()
*
* When called, the `'change'` event listener is removed.
*
**/
this.detach = function() {
this.document.removeEventListener("change", this.$onChange);
};
/** internal, hide
* Anchor.clipPositionToDocument(row, column)
* - row (Number): The row index to clip the anchor to
* - column (Number): The column index to clip the anchor to
*
* Clips the anchor position to the specified row and column.
*
**/
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);
});
@@ -1,184 +0,0 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** 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 lines before cursor should move anchor row": function() {
var doc = new Document("juhu\nkinners");
var anchor = new Anchor(doc, 1, 4);
doc.insertLines(1, ["123", "456"]);
assert.position(anchor.getPosition(), 3, 4);
},
"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.insertNewLine({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.insertNewLine({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.removeLines(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.removeLines(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));
}
};
});
if (typeof module !== "undefined" && module === require.main) {
require("asyncjs").test.testcase(module.exports).exec()
}
@@ -1,261 +0,0 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
"use strict";
var oop = require("./lib/oop");
var EventEmitter = require("./lib/event_emitter").EventEmitter;
// tokenizing lines longer than this makes editor very slow
var MAX_LINE_LENGTH = 5000;
/**
* class BackgroundTokenizer
*
* 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.
*
**/
/**
* new BackgroundTokenizer(tokenizer, editor)
* - tokenizer (Tokenizer): The tokenizer to use
* - editor (Editor): The editor to associate with
*
* Creates a new `BackgroundTokenizer` object.
*
*
**/
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 startLine = self.currentLine;
var doc = self.doc;
var processedLines = 0;
var len = doc.getLength();
while (self.currentLine < len) {
self.$tokenizeRow(self.currentLine);
while (self.lines[self.currentLine])
self.currentLine++;
// only check every 5 lines
processedLines ++;
if ((processedLines % 5 == 0) && (new Date() - workerStart) > 20) {
self.fireUpdateEvent(startLine, self.currentLine-1);
self.running = setTimeout(self.$worker, 20);
return;
}
}
self.running = false;
self.fireUpdateEvent(startLine, len - 1);
};
};
(function(){
oop.implement(this, EventEmitter);
/**
* BackgroundTokenizer.setTokenizer(tokenizer)
* - tokenizer (Tokenizer): The new tokenizer to use
*
* Sets a new tokenizer for this object.
*
**/
this.setTokenizer = function(tokenizer) {
this.tokenizer = tokenizer;
this.lines = [];
this.states = [];
this.start(0);
};
/**
* BackgroundTokenizer.setDocument(doc)
* - doc (Document): The new document to associate with
*
* Sets a new document to associate with this object.
*
**/
this.setDocument = function(doc) {
this.doc = doc;
this.lines = [];
this.states = [];
this.stop();
};
/**
* BackgroundTokenizer.fireUpdateEvent(firstRow, lastRow)
* - firstRow (Number): The starting row region
* - lastRow (Number): The final row region
*
* Emits the `'update'` event. `firstRow` and `lastRow` are used to define the boundaries of the region to be updated.
*
**/
this.fireUpdateEvent = function(firstRow, lastRow) {
var data = {
first: firstRow,
last: lastRow
};
this._emit("update", {data: data});
};
/**
* BackgroundTokenizer.start(startRow)
* - startRow (Number): The row to start at
*
* Starts tokenizing at the row indicated.
*
**/
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.$updateOnChange = function(delta) {
var range = delta.range;
var startRow = range.start.row;
var len = range.end.row - startRow;
if (len === 0) {
this.lines[startRow] = null;
} else if (delta.action == "removeText" || delta.action == "removeLines") {
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();
// pretty long delay to prevent the tokenizer from interfering with the user
this.running = setTimeout(this.$worker, 700);
};
/**
* BackgroundTokenizer.stop()
*
* Stops tokenizing.
*
**/
this.stop = function() {
if (this.running)
clearTimeout(this.running);
this.running = false;
};
/** related to: BackgroundTokenizer.$tokenizeRows
* BackgroundTokenizer.getTokens(firstRow, lastRow) -> [Object]
* - firstRow (Number): The row to start at
* - lastRow (Number): The row to finish at
*
* Starts tokenizing at the row indicated. Returns a list of objects of the tokenized rows.
*
**/
this.getTokens = function(row) {
return this.lines[row] || this.$tokenizeRow(row);
};
/**
* BackgroundTokenizer.getState(row) -> String
* - row (Number): The row to start at
*
* [Returns the state of tokenization at the end of a row.]{: #BackgroundTokenizer.getState}
**/
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];
if (line.length > MAX_LINE_LENGTH) {
var overflow = {value: line.substr(MAX_LINE_LENGTH), type: "text"};
line = line.slice(0, MAX_LINE_LENGTH);
}
var data = this.tokenizer.getLineTokens(line, state);
if (overflow) {
data.tokens.push(overflow);
data.state = "start";
}
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;
});
@@ -1,92 +0,0 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Harutyun Amirjanyan <harutyun@c9.io>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** 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", "start", "start"])
doc.remove(new Range(0,2,1,2))
testStates(doc, [null, "start"])
forceTokenize(doc)
testStates(doc, ["comment", "comment"])
doc.insert({row:0, column:2}, "\n*/")
testStates(doc, [undefined, undefined, "comment"])
forceTokenize(doc)
testStates(doc, ["comment", "start", "start"])
}
};
});
if (typeof module !== "undefined" && module === require.main) {
require("asyncjs").test.testcase(module.exports).exec()
}
@@ -1,121 +0,0 @@
define(function(require, exports, module) {
"use strict";
var oop = require("../lib/oop");
var HashHandler = require("../keyboard/hash_handler").HashHandler;
var EventEmitter = require("../lib/event_emitter").EventEmitter;
/**
* class CommandManager
*
*
*
*
**/
/**
* new CommandManager(platform, commands)
* - platform (String): Identifier for the platform; must be either `'mac'` or `'win'`
* - commands (Array): A list of commands
*
* TODO
*
*
**/
var CommandManager = function(platform, commands) {
this.platform = platform;
this.commands = {};
this.commmandKeyBinding = {};
this.addCommands(commands);
this.setDefaultHandler("exec", function(e) {
return e.command.exec(e.editor, e.args || {});
});
};
oop.inherits(CommandManager, HashHandler);
(function() {
oop.implement(this, EventEmitter);
this.exec = function(command, editor, args) {
if (typeof command === 'string')
command = this.commands[command];
if (!command)
return false;
if (editor && editor.$readOnly && !command.readOnly)
return false;
var retvalue = this._emit("exec", {
editor: editor,
command: command,
args: args
});
return retvalue === false ? false : true;
};
this.toggleRecording = function() {
if (this.$inReplay)
return;
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();
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;
});
@@ -1,193 +0,0 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** 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();
},
replay: function(editor) {
editor.cm.replay();
},
cm1: function(editor, arg) {
called += "1" + (arg || "");
},
cm2: function(editor) {
called += "2";
}
});
this.cm.exec("togglerecording", this);
assert.ok(this.cm.recording);
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() {
var called = "";
this.cm.addCommands({
cm1: function(editor, arg) {
called += "1" + (arg || "");
},
cm2: function(editor) {
called += "2";
}
});
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);
}
};
});
if (typeof module !== "undefined" && module === require.main) {
require("asyncjs").test.testcase(module.exports).exec();
}
@@ -1,460 +0,0 @@
/* vim:ts=4:sts=4:sw=4:
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Julian Viereck <julian.viereck@gmail.com>
* Mihai Sucan <mihai.sucan@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
"use strict";
var lang = require("../lib/lang");
function bindKey(win, mac) {
return {
win: win,
mac: mac
};
}
exports.commands = [{
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); },
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); },
readOnly: true
}, {
name: "foldall",
bindKey: bindKey("Alt-0", "Command-Option-0"),
exec: function(editor) { editor.session.foldAll(); },
readOnly: true
}, {
name: "unfoldall",
bindKey: bindKey("Alt-Shift-0", "Command-Option-Shift-0"),
exec: function(editor) { editor.session.unfold(); },
readOnly: true
}, {
name: "findnext",
bindKey: bindKey("Ctrl-K", "Command-G"),
exec: function(editor) { editor.findNext(); },
readOnly: true
}, {
name: "findprevious",
bindKey: bindKey("Ctrl-Shift-K", "Command-Shift-G"),
exec: function(editor) { editor.findPrevious(); },
readOnly: true
}, {
name: "find",
bindKey: bindKey("Ctrl-F", "Command-F"),
exec: function(editor) {
var needle = prompt("Find:", editor.getCopyText());
editor.find(needle);
},
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(); },
readOnly: true
}, {
name: "gotostart",
bindKey: bindKey("Ctrl-Home", "Command-Home|Command-Up"),
exec: function(editor) { editor.navigateFileStart(); },
readOnly: true
}, {
name: "selectup",
bindKey: bindKey("Shift-Up", "Shift-Up"),
exec: function(editor) { editor.getSelection().selectUp(); },
multiSelectAction: "forEach",
readOnly: true
}, {
name: "golineup",
bindKey: bindKey("Up", "Up|Ctrl-P"),
exec: function(editor, args) { editor.navigateUp(args.times); },
multiSelectAction: "forEach",
readOnly: true
}, {
name: "selecttoend",
bindKey: bindKey("Ctrl-Shift-End", "Command-Shift-Down"),
exec: function(editor) { editor.getSelection().selectFileEnd(); },
multiSelectAction: "forEach",
readOnly: true
}, {
name: "gotoend",
bindKey: bindKey("Ctrl-End", "Command-End|Command-Down"),
exec: function(editor) { editor.navigateFileEnd(); },
multiSelectAction: "forEach",
readOnly: true
}, {
name: "selectdown",
bindKey: bindKey("Shift-Down", "Shift-Down"),
exec: function(editor) { editor.getSelection().selectDown(); },
multiSelectAction: "forEach",
readOnly: true
}, {
name: "golinedown",
bindKey: bindKey("Down", "Down|Ctrl-N"),
exec: function(editor, args) { editor.navigateDown(args.times); },
multiSelectAction: "forEach",
readOnly: true
}, {
name: "selectwordleft",
bindKey: bindKey("Ctrl-Shift-Left", "Option-Shift-Left"),
exec: function(editor) { editor.getSelection().selectWordLeft(); },
multiSelectAction: "forEach",
readOnly: true
}, {
name: "gotowordleft",
bindKey: bindKey("Ctrl-Left", "Option-Left"),
exec: function(editor) { editor.navigateWordLeft(); },
multiSelectAction: "forEach",
readOnly: true
}, {
name: "selecttolinestart",
bindKey: bindKey("Alt-Shift-Left", "Command-Shift-Left"),
exec: function(editor) { editor.getSelection().selectLineStart(); },
multiSelectAction: "forEach",
readOnly: true
}, {
name: "gotolinestart",
bindKey: bindKey("Alt-Left|Home", "Command-Left|Home|Ctrl-A"),
exec: function(editor) { editor.navigateLineStart(); },
multiSelectAction: "forEach",
readOnly: true
}, {
name: "selectleft",
bindKey: bindKey("Shift-Left", "Shift-Left"),
exec: function(editor) { editor.getSelection().selectLeft(); },
multiSelectAction: "forEach",
readOnly: true
}, {
name: "gotoleft",
bindKey: bindKey("Left", "Left|Ctrl-B"),
exec: function(editor, args) { editor.navigateLeft(args.times); },
multiSelectAction: "forEach",
readOnly: true
}, {
name: "selectwordright",
bindKey: bindKey("Ctrl-Shift-Right", "Option-Shift-Right"),
exec: function(editor) { editor.getSelection().selectWordRight(); },
multiSelectAction: "forEach",
readOnly: true
}, {
name: "gotowordright",
bindKey: bindKey("Ctrl-Right", "Option-Right"),
exec: function(editor) { editor.navigateWordRight(); },
multiSelectAction: "forEach",
readOnly: true
}, {
name: "selecttolineend",
bindKey: bindKey("Alt-Shift-Right", "Command-Shift-Right"),
exec: function(editor) { editor.getSelection().selectLineEnd(); },
multiSelectAction: "forEach",
readOnly: true
}, {
name: "gotolineend",
bindKey: bindKey("Alt-Right|End", "Command-Right|End|Ctrl-E"),
exec: function(editor) { editor.navigateLineEnd(); },
multiSelectAction: "forEach",
readOnly: true
}, {
name: "selectright",
bindKey: bindKey("Shift-Right", "Shift-Right"),
exec: function(editor) { editor.getSelection().selectRight(); },
multiSelectAction: "forEach",
readOnly: true
}, {
name: "gotoright",
bindKey: bindKey("Right", "Right|Ctrl-F"),
exec: function(editor, args) { editor.navigateRight(args.times); },
multiSelectAction: "forEach",
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",
readOnly: true
}, {
name: "selectlineend",
bindKey: "Shift-End",
exec: function(editor) { editor.getSelection().selectLineEnd(); },
multiSelectAction: "forEach",
readOnly: true
}, {
name: "togglerecording",
bindKey: bindKey("Ctrl-Alt-E", "Command-Option-E"),
exec: function(editor) { editor.commands.toggleRecording(); },
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",
readOnly: true
}, {
name: "selecttomatching",
bindKey: bindKey("Ctrl-Shift-P", "Ctrl-Shift-P"),
exec: function(editor) { editor.jumpToMatching(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();
}
},
multiSelectAction: "forEach"
}, {
name: "removeline",
bindKey: bindKey("Ctrl-D", "Command-D"),
exec: function(editor) { editor.removeLines(); },
multiSelectAction: "forEach"
}, {
name: "duplicateSelection",
bindKey: bindKey("Ctrl-Shift-D", "Command-Shift-D"),
exec: function(editor) { editor.duplicateSelection(); },
multiSelectAction: "forEach"
}, {
name: "togglecomment",
bindKey: bindKey("Ctrl-/", "Command-/"),
exec: function(editor) { editor.toggleCommentLines(); },
multiSelectAction: "forEach"
}, {
name: "replace",
bindKey: bindKey("Ctrl-R", "Command-Option-F"),
exec: function(editor) {
var needle = prompt("Find:", editor.getCopyText());
if (!needle)
return;
var replacement = prompt("Replacement:");
if (!replacement)
return;
editor.replace(replacement, {needle: needle});
}
}, {
name: "replaceall",
bindKey: bindKey("Ctrl-Shift-R", "Command-Shift-Option-F"),
exec: function(editor) {
var needle = prompt("Find:");
if (!needle)
return;
var replacement = prompt("Replacement:");
if (!replacement)
return;
editor.replaceAll(replacement, {needle: needle});
}
}, {
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(); }
}, {
name: "movelinesup",
bindKey: bindKey("Alt-Up", "Option-Up"),
exec: function(editor) { editor.moveLinesUp(); }
}, {
name: "copylinesdown",
bindKey: bindKey("Alt-Shift-Down", "Command-Option-Down"),
exec: function(editor) { editor.copyLinesDown(); }
}, {
name: "movelinesdown",
bindKey: bindKey("Alt-Down", "Option-Down"),
exec: function(editor) { editor.moveLinesDown(); }
}, {
name: "del",
bindKey: bindKey("Delete", "Delete|Ctrl-D"),
exec: function(editor) { editor.remove("right"); },
multiSelectAction: "forEach"
}, {
name: "backspace",
bindKey: bindKey(
"Command-Backspace|Option-Backspace|Shift-Backspace|Backspace",
"Ctrl-Backspace|Command-Backspace|Shift-Backspace|Backspace|Ctrl-H"
),
exec: function(editor) { editor.remove("left"); },
multiSelectAction: "forEach"
}, {
name: "removetolinestart",
bindKey: bindKey("Alt-Backspace", "Command-Backspace"),
exec: function(editor) { editor.removeToLineStart(); },
multiSelectAction: "forEach"
}, {
name: "removetolineend",
bindKey: bindKey("Alt-Delete", "Ctrl-K"),
exec: function(editor) { editor.removeToLineEnd(); },
multiSelectAction: "forEach"
}, {
name: "removewordleft",
bindKey: bindKey("Ctrl-Backspace", "Alt-Backspace|Ctrl-Alt-Backspace"),
exec: function(editor) { editor.removeWordLeft(); },
multiSelectAction: "forEach"
}, {
name: "removewordright",
bindKey: bindKey("Ctrl-Delete", "Alt-Delete"),
exec: function(editor) { editor.removeWordRight(); },
multiSelectAction: "forEach"
}, {
name: "outdent",
bindKey: bindKey("Shift-Tab", "Shift-Tab"),
exec: function(editor) { editor.blockOutdent(); },
multiSelectAction: "forEach"
}, {
name: "indent",
bindKey: bindKey("Tab", "Tab"),
exec: function(editor) { editor.indent(); },
multiSelectAction: "forEach"
}, {
name: "insertstring",
exec: function(editor, str) { editor.insert(str); },
multiSelectAction: "forEach"
}, {
name: "inserttext",
exec: function(editor, args) {
editor.insert(lang.stringRepeat(args.text || "", args.times || 1));
},
multiSelectAction: "forEach"
}, {
name: "splitline",
bindKey: bindKey(null, "Ctrl-O"),
exec: function(editor) { editor.splitLine(); },
multiSelectAction: "forEach"
}, {
name: "transposeletters",
bindKey: bindKey("Ctrl-T", "Ctrl-T"),
exec: function(editor) { editor.transposeLetters(); },
multiSelectAction: function(editor) {editor.transposeSelections(1); }
}, {
name: "touppercase",
bindKey: bindKey("Ctrl-U", "Ctrl-U"),
exec: function(editor) { editor.toUpperCase(); },
multiSelectAction: "forEach"
}, {
name: "tolowercase",
bindKey: bindKey("Ctrl-Shift-U", "Ctrl-Shift-U"),
exec: function(editor) { editor.toLowerCase(); },
multiSelectAction: "forEach"
}];
});
@@ -1,101 +0,0 @@
/* vim:ts=4:sts=4:sw=4:
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Harutyun Amirjanyan <amirjanyan AT gmail DOT com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** 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"},
readonly: true
}, {
name: "addCursorBelow",
exec: function(editor) { editor.selectMoreLines(1); },
bindKey: {win: "Ctrl-Alt-Down", mac: "Ctrl-Alt-Down"},
readonly: true
}, {
name: "addCursorAboveSkipCurrent",
exec: function(editor) { editor.selectMoreLines(-1, true); },
bindKey: {win: "Ctrl-Alt-Shift-Up", mac: "Ctrl-Alt-Shift-Up"},
readonly: true
}, {
name: "addCursorBelowSkipCurrent",
exec: function(editor) { editor.selectMoreLines(1, true); },
bindKey: {win: "Ctrl-Alt-Shift-Down", mac: "Ctrl-Alt-Shift-Down"},
readonly: true
}, {
name: "selectMoreBefore",
exec: function(editor) { editor.selectMore(-1); },
bindKey: {win: "Ctrl-Alt-Left", mac: "Ctrl-Alt-Left"},
readonly: true
}, {
name: "selectMoreAfter",
exec: function(editor) { editor.selectMore(1); },
bindKey: {win: "Ctrl-Alt-Right", mac: "Ctrl-Alt-Right"},
readonly: true
}, {
name: "selectNextBefore",
exec: function(editor) { editor.selectMore(-1, true); },
bindKey: {win: "Ctrl-Alt-Shift-Left", mac: "Ctrl-Alt-Shift-Left"},
readonly: true
}, {
name: "selectNextAfter",
exec: function(editor) { editor.selectMore(1, true); },
bindKey: {win: "Ctrl-Alt-Shift-Right", mac: "Ctrl-Alt-Shift-Right"},
readonly: true
}, {
name: "splitIntoLines",
exec: function(editor) { editor.multiSelect.splitIntoLines(); },
bindKey: {win: "Ctrl-Shift-L", mac: "Ctrl-Shift-L"},
readonly: true
}];
// commands active in multiselect mode
exports.multiSelectCommands = [{
name: "singleSelection",
bindKey: "esc",
exec: function(editor) { editor.exitMultiSelectMode(); },
readonly: true,
isAvailable: function(editor) {return editor && editor.inMultiSelectMode}
}];
var HashHandler = require("../keyboard/hash_handler").HashHandler;
exports.keyboardHandler = new HashHandler(exports.multiSelectCommands);
});
@@ -1,124 +0,0 @@
/* vim:ts=4:sts=4:sw=4:
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
"no use strict";
var lang = require("./lib/lang");
var global = (function() {
return this;
})();
var options = {
packaged: false,
workerPath: "",
modePath: "",
themePath: "",
suffix: ".js"
};
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);
};
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<scripts.length; i++) {
var script = scripts[i];
var src = script.src || script.getAttribute("src");
if (!src) {
continue;
}
var attributes = script.attributes;
for (var j=0, l=attributes.length; j < l; j++) {
var attr = attributes[j];
if (attr.name.indexOf("data-ace-") === 0) {
scriptOptions[deHyphenate(attr.name.replace(/^data-ace-/, ""))] = attr.value;
}
}
var m = src.match(/^(.*)\/ace(\-\w+)?\.js(\?|$)/);
if (m)
scriptUrl = m[1];
}
if (scriptUrl) {
scriptOptions.base = scriptOptions.base || scriptUrl;
scriptOptions.packaged = true;
}
scriptOptions.workerPath = scriptOptions.workerPath || scriptOptions.base;
scriptOptions.modePath = scriptOptions.modePath || scriptOptions.base;
scriptOptions.themePath = scriptOptions.themePath || scriptOptions.base;
delete scriptOptions.base;
for (var key in scriptOptions)
if (typeof scriptOptions[key] !== "undefined")
exports.set(key, scriptOptions[key]);
};
function deHyphenate(str) {
return str.replace(/-(.)/g, function(m, m1) { return m1.toUpperCase(); });
}
});
Binary file not shown.

Before

Width:  |  Height:  |  Size: 759 B

@@ -1,327 +0,0 @@
.ace_editor {
position: absolute;
overflow: hidden;
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Droid Sans Mono', 'Consolas', monospace;
font-size: 12px;
}
.ace_scroller {
position: absolute;
overflow: hidden;
}
.ace_content {
position: absolute;
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
cursor: text;
}
.ace_gutter {
position: absolute;
overflow : hidden;
height: 100%;
width: auto;
cursor: default;
z-index: 4;
}
.ace_scroller.horscroll {
box-shadow: 17px 0 16px -16px rgba(0, 0, 0, 0.4) inset;
}
.ace_gutter-cell {
padding-left: 19px;
padding-right: 6px;
}
.ace_gutter-cell.ace_error {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6QUM2OEZDQTQ4RTU0MTFFMUEzM0VFRTM2RUY1M0RBMjYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6QUM2OEZDQTU4RTU0MTFFMUEzM0VFRTM2RUY1M0RBMjYiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpBQzY4RkNBMjhFNTQxMUUxQTMzRUVFMzZFRjUzREEyNiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpBQzY4RkNBMzhFNTQxMUUxQTMzRUVFMzZFRjUzREEyNiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PkgXxbAAAAJbSURBVHjapFNNaBNBFH4zs5vdZLP5sQmNpT82QY209heh1ioWisaDRcSKF0WKJ0GQnrzrxasHsR6EnlrwD0TagxJabaVEpFYxLWlLSS822tr87m66ccfd2GKyVhA6MMybgfe97/vmPUQphd0sZjto9XIn9OOsvlu2nkqRzVU+6vvlzPf8W6bk8dxQ0NPbxAALgCgg2JkaQuhzQau/El0zbmUA7U0Es8v2CiYmKQJHGO1QICCLoqilMhkmurDAyapKgqItezi/USRdJqEYY4D5jCy03ht2yMkkvL91jTTX10qzyyu2hruPRN7jgbH+EOsXcMLgYiThEgAMhABW85oqy1DXdRIdvP1AHJ2acQXvDIrVHcdQNrEKNYSVMSZGMjEzIIAwDXIo+6G/FxcGnzkC3T2oMhLjre49sBB+RRcHLqdafK6sYdE/GGBwU1VpFNj0aN8pJbe+BkZyevUrvLl6Xmm0W9IuTc0DxrDNAJd5oEvI/KRsNC3bQyNjPO9yQ1YHcfj2QvfQc/5TUhJTBc2iM0U7AWDQtc1nJHvD/cfO2s7jaGkiTEfa/Ep8coLu7zmNmh8+dc5lZDuUeFAGUNA/OY6JVaypQ0vjr7XYjUvJM37vt+j1vuTK5DgVfVUoTjVe+y3/LxMxY2GgU+CSLy4cpfsYorRXuXIOi0Vt40h67uZFTdIo6nLaZcwUJWAzwNS0tBnqqKzQDnjdG/iPyZxo46HaKUpbvYkj8qYRTZsBhge+JHhZyh0x9b95JqjVJkT084kZIPwu/mPWqPgfQ5jXh2+92Ay7HedfAgwA6KDWafb4w3cAAAAASUVORK5CYII=");
background-repeat: no-repeat;
background-position: 2px center;
}
.ace_gutter-cell.ace_warning {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6QUM2OEZDQTg4RTU0MTFFMUEzM0VFRTM2RUY1M0RBMjYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6QUM2OEZDQTk4RTU0MTFFMUEzM0VFRTM2RUY1M0RBMjYiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpBQzY4RkNBNjhFNTQxMUUxQTMzRUVFMzZFRjUzREEyNiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpBQzY4RkNBNzhFNTQxMUUxQTMzRUVFMzZFRjUzREEyNiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pgd7PfIAAAGmSURBVHjaYvr//z8DJZiJgUIANoCRkREb9gLiSVAaQx4OQM7AAkwd7XU2/v++/rOttdYGEB9dASEvOMydGKfH8Gv/p4XTkvRBfLxeQAP+1cUhXopyvzhP7P/IoSj7g7Mw09cNKO6J1QQ0L4gICPIv/veg/8W+JdFvQNLHVsW9/nmn9zk7B+cCkDwhL7gt6knSZnx9/LuCEOcvkIAMP+cvto9nfqyZmmUAksfnBUtbM60gX/3/kgyv3/xSFOL5DZT+L8vP+Yfh5cvfPvp/xUHyQHXGyAYwgpwBjZYFT3Y1OEl/OfCH4ffv3wzc4iwMvNIsDJ+f/mH4+vIPAxsb631WW0Yln6ZpQLXdMK/DXGDflh+sIv37EivD5x//Gb7+YWT4y86sl7BCCkSD+Z++/1dkvsFRl+HnD1Rvje4F8whjMXmGj58YGf5zsDMwcnAwfPvKcml62DsQDeaDxN+/Y0qwlpEHqrdB94IRNIDUgfgfKJChGK4OikEW3gTiXUB950ASLFAF54AC94A0G9QAfOnmF9DCDzABFqS08IHYDIScdijOjQABBgC+/9awBH96jwAAAABJRU5ErkJggg==");
background-repeat: no-repeat;
background-position: 2px center;
}
.ace_gutter-cell.ace_info {
background-image: url("data:image/gif;base64,R0lGODlhEAAQAMQAAAAAAEFBQVJSUl5eXmRkZGtra39/f4WFhYmJiZGRkaampry8vMPDw8zMzNXV1dzc3OTk5Orq6vDw8P///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABQALAAAAAAQABAAAAUuICWOZGmeaBml5XGwFCQSBGyXRSAwtqQIiRuiwIM5BoYVbEFIyGCQoeJGrVptIQA7");
background-position: 2px center;
}
.ace_dark .ace_gutter-cell.ace_info {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpGRTk5MTVGREIxNDkxMUUxOTc5Q0FFREQyMTNGMjBFQyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpGRTk5MTVGRUIxNDkxMUUxOTc5Q0FFREQyMTNGMjBFQyI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkZFOTkxNUZCQjE0OTExRTE5NzlDQUVERDIxM0YyMEVDIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkZFOTkxNUZDQjE0OTExRTE5NzlDQUVERDIxM0YyMEVDIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+SIDkjAAAAJ1JREFUeNpi/P//PwMlgImBQkB7A6qrq/+DMC55FkIGKCoq4pVnpFkgTp069f/+/fv/r1u37r+tre1/kg0A+ptn9uzZYLaRkRHpLvjw4cNXWVlZhufPnzOcO3eOdAO0tbVPAjHDmzdvGA4fPsxIsgGSkpJmv379Ynj37h2DjIyMCMkG3LhxQ/T27dsMampqDHZ2dq/pH41DxwCAAAMAFdc68dUsFZgAAAAASUVORK5CYII=");
}
.ace_editor .ace_sb {
position: absolute;
overflow-x: hidden;
overflow-y: scroll;
right: 0;
}
.ace_editor .ace_sb div {
position: absolute;
width: 1px;
left: 0;
}
.ace_editor .ace_print_margin_layer {
z-index: 0;
position: absolute;
overflow: hidden;
margin: 0;
left: 0;
height: 100%;
width: 100%;
}
.ace_editor .ace_print_margin {
position: absolute;
height: 100%;
}
.ace_editor > textarea {
position: absolute;
z-index: 0;
width: 0.5em;
height: 1em;
opacity: 0;
background: transparent;
appearance: none;
-moz-appearance: none;
border: none;
resize: none;
outline: none;
overflow: hidden;
}
.ace_editor > textarea.ace_composition {
background: #fff;
color: #000;
z-index: 1000;
opacity: 1;
border: solid lightgray 1px;
margin: -1px
}
.ace_layer {
z-index: 1;
position: absolute;
overflow: hidden;
white-space: nowrap;
height: 100%;
width: 100%;
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-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 .ace_layer {
position: relative;
min-width: 40px;
width: auto;
text-align: right;
pointer-events: auto;
}
.ace_text-layer {
color: black;
font: inherit !important;
}
.ace_cjk {
display: inline-block;
text-align: center;
}
.ace_cursor-layer {
z-index: 4;
}
.ace_cursor {
z-index: 4;
position: absolute;
}
.ace_cursor.ace_hidden {
opacity: 0.2;
}
.ace_editor.multiselect .ace_cursor {
border-left-width: 1px;
}
.ace_line {
white-space: nowrap;
}
.ace_marker-layer .ace_step {
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;
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
}
.ace_line .ace_fold {
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
display: inline-block;
height: 11px;
margin-top: -2px;
vertical-align: middle;
background-image:
url("data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%11%00%00%00%09%08%06%00%00%00%D4%E8%C7%0C%00%00%03%1EiCCPICC%20Profile%00%00x%01%85T%DFk%D3P%14%FE%DAe%9D%B0%E1%8B%3Ag%11%09%3Eh%91ndStC%9C%B6kW%BA%CDZ%EA6%B7!H%9B%A6m%5C%9A%C6%24%ED~%B0%07%D9%8Bo%3A%C5w%F1%07%3E%F9%07%0C%D9%83o%7B%92%0D%C6%14a%F8%AC%88%22L%F6%22%B3%9E%9B4M'S%03%B9%F7%BB%DF%F9%EE9'%E7%E4%5E%A0%F9qZ%D3%14%2F%0F%14USO%C5%C2%FC%C4%E4%14%DF%F2%01%5E%1CC%2B%FChM%8B%86%16J%26G%40%0F%D3%B2y%EF%B3%F3%0E%1E%C6lt%EEo%DF%AB%FEc%D5%9A%95%0C%11%F0%1C%20%BE%945%C4%22%E1Y%A0i%5C%D4t%13%E0%D6%89%EF%9D15%C2%CDLsX%A7%04%09%1Fg8oc%81%E1%8C%8D%23%96f45%40%9A%09%C2%07%C5B%3AK%B8%408%98i%E0%F3%0D%D8%CE%81%14%E4'%26%A9%92.%8B%3C%ABER%2F%E5dE%B2%0C%F6%F0%1Fs%83%F2_%B0%A8%94%E9%9B%AD%E7%10%8Dm%9A%19N%D1%7C%8A%DE%1F9%7Dp%8C%E6%00%D5%C1%3F_%18%BDA%B8%9DpX6%E3%A35~B%CD%24%AE%11%26%BD%E7%EEti%98%EDe%9A%97Y)%12%25%1C%24%BCbT%AE3li%E6%0B%03%89%9A%E6%D3%ED%F4P%92%B0%9F4%BF43Y%F3%E3%EDP%95%04%EB1%C5%F5%F6KF%F4%BA%BD%D7%DB%91%93%07%E35%3E%A7)%D6%7F%40%FE%BD%F7%F5r%8A%E5y%92%F0%EB%B4%1E%8D%D5%F4%5B%92%3AV%DB%DB%E4%CD%A6%23%C3%C4wQ%3F%03HB%82%8E%1Cd(%E0%91B%0Ca%9Ac%C4%AA%F8L%16%19%22J%A4%D2itTy%B28%D6%3B(%93%96%ED%1CGx%C9_%0E%B8%5E%16%F5%5B%B2%B8%F6%E0%FB%9E%DD%25%D7%8E%BC%15%85%C5%B7%A3%D8Q%ED%B5%81%E9%BA%B2%13%9A%1B%7Fua%A5%A3n%E17%B9%E5%9B%1Bm%AB%0B%08Q%FE%8A%E5%B1H%5Ee%CAO%82Q%D7u6%E6%90S%97%FCu%0B%CF2%94%EE%25v%12X%0C%BA%AC%F0%5E%F8*l%0AO%85%17%C2%97%BF%D4%C8%CE%DE%AD%11%CB%80q%2C%3E%AB%9ES%CD%C6%EC%25%D2L%D2%EBd%B8%BF%8A%F5B%C6%18%F9%901CZ%9D%BE%24M%9C%8A9%F2%DAP%0B'%06w%82%EB%E6%E2%5C%2F%D7%07%9E%BB%CC%5D%E1%FA%B9%08%AD.r%23%8E%C2%17%F5E%7C!%F0%BE3%BE%3E_%B7o%88a%A7%DB%BE%D3d%EB%A31Z%EB%BB%D3%91%BA%A2%B1z%94%8F%DB'%F6%3D%8E%AA%13%19%B2%B1%BE%B1~V%08%2B%B4%A2cjJ%B3tO%00%03%25mN%97%F3%05%93%EF%11%84%0B%7C%88%AE-%89%8F%ABbW%90O%2B%0Ao%99%0C%5E%97%0CI%AFH%D9.%B0%3B%8F%ED%03%B6S%D6%5D%E6i_s9%F3*p%E9%1B%FD%C3%EB.7U%06%5E%19%C0%D1s.%17%A03u%E4%09%B0%7C%5E%2C%EB%15%DB%1F%3C%9E%B7%80%91%3B%DBc%AD%3Dma%BA%8B%3EV%AB%DBt.%5B%1E%01%BB%0F%AB%D5%9F%CF%AA%D5%DD%E7%E4%7F%0Bx%A3%FC%06%A9%23%0A%D6%C2%A1_2%00%00%00%09pHYs%00%00%0B%13%00%00%0B%13%01%00%9A%9C%18%00%00%00%B5IDAT(%15%A5%91%3D%0E%02!%10%85ac%E1%05%D6%CE%D6%C6%CE%D2%E8%ED%CD%DE%C0%C6%D6N.%E0V%F8%3D%9Ca%891XH%C2%BE%D9y%3F%90!%E6%9C%C3%BFk%E5%011%C6-%F5%C8N%04%DF%BD%FF%89%DFt%83DN%60%3E%F3%AB%A0%DE%1A%5Dg%BE%10Q%97%1B%40%9C%A8o%10%8F%5E%828%B4%1B%60%87%F6%02%26%85%1Ch%1E%C1%2B%5Bk%FF%86%EE%B7j%09%9A%DA%9B%ACe%A3%F9%EC%DA!9%B4%D5%A6%81%86%86%98%CC%3C%5B%40%FA%81%B3%E9%CB%23%94%C16Azo%05%D4%E1%C1%95a%3B%8A'%A0%E8%CC%17%22%85%1D%BA%00%A2%FA%DC%0A%94%D1%D1%8D%8B%3A%84%17B%C7%60%1A%25Z%FC%8D%00%00%00%00IEND%AEB%60%82"),
url("data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%05%00%00%007%08%06%00%00%00%C4%DD%80C%00%00%03%1EiCCPICC%20Profile%00%00x%01%85T%DFk%D3P%14%FE%DAe%9D%B0%E1%8B%3Ag%11%09%3Eh%91ndStC%9C%B6kW%BA%CDZ%EA6%B7!H%9B%A6m%5C%9A%C6%24%ED~%B0%07%D9%8Bo%3A%C5w%F1%07%3E%F9%07%0C%D9%83o%7B%92%0D%C6%14a%F8%AC%88%22L%F6%22%B3%9E%9B4M'S%03%B9%F7%BB%DF%F9%EE9'%E7%E4%5E%A0%F9qZ%D3%14%2F%0F%14USO%C5%C2%FC%C4%E4%14%DF%F2%01%5E%1CC%2B%FChM%8B%86%16J%26G%40%0F%D3%B2y%EF%B3%F3%0E%1E%C6lt%EEo%DF%AB%FEc%D5%9A%95%0C%11%F0%1C%20%BE%945%C4%22%E1Y%A0i%5C%D4t%13%E0%D6%89%EF%9D15%C2%CDLsX%A7%04%09%1Fg8oc%81%E1%8C%8D%23%96f45%40%9A%09%C2%07%C5B%3AK%B8%408%98i%E0%F3%0D%D8%CE%81%14%E4'%26%A9%92.%8B%3C%ABER%2F%E5dE%B2%0C%F6%F0%1Fs%83%F2_%B0%A8%94%E9%9B%AD%E7%10%8Dm%9A%19N%D1%7C%8A%DE%1F9%7Dp%8C%E6%00%D5%C1%3F_%18%BDA%B8%9DpX6%E3%A35~B%CD%24%AE%11%26%BD%E7%EEti%98%EDe%9A%97Y)%12%25%1C%24%BCbT%AE3li%E6%0B%03%89%9A%E6%D3%ED%F4P%92%B0%9F4%BF43Y%F3%E3%EDP%95%04%EB1%C5%F5%F6KF%F4%BA%BD%D7%DB%91%93%07%E35%3E%A7)%D6%7F%40%FE%BD%F7%F5r%8A%E5y%92%F0%EB%B4%1E%8D%D5%F4%5B%92%3AV%DB%DB%E4%CD%A6%23%C3%C4wQ%3F%03HB%82%8E%1Cd(%E0%91B%0Ca%9Ac%C4%AA%F8L%16%19%22J%A4%D2itTy%B28%D6%3B(%93%96%ED%1CGx%C9_%0E%B8%5E%16%F5%5B%B2%B8%F6%E0%FB%9E%DD%25%D7%8E%BC%15%85%C5%B7%A3%D8Q%ED%B5%81%E9%BA%B2%13%9A%1B%7Fua%A5%A3n%E17%B9%E5%9B%1Bm%AB%0B%08Q%FE%8A%E5%B1H%5Ee%CAO%82Q%D7u6%E6%90S%97%FCu%0B%CF2%94%EE%25v%12X%0C%BA%AC%F0%5E%F8*l%0AO%85%17%C2%97%BF%D4%C8%CE%DE%AD%11%CB%80q%2C%3E%AB%9ES%CD%C6%EC%25%D2L%D2%EBd%B8%BF%8A%F5B%C6%18%F9%901CZ%9D%BE%24M%9C%8A9%F2%DAP%0B'%06w%82%EB%E6%E2%5C%2F%D7%07%9E%BB%CC%5D%E1%FA%B9%08%AD.r%23%8E%C2%17%F5E%7C!%F0%BE3%BE%3E_%B7o%88a%A7%DB%BE%D3d%EB%A31Z%EB%BB%D3%91%BA%A2%B1z%94%8F%DB'%F6%3D%8E%AA%13%19%B2%B1%BE%B1~V%08%2B%B4%A2cjJ%B3tO%00%03%25mN%97%F3%05%93%EF%11%84%0B%7C%88%AE-%89%8F%ABbW%90O%2B%0Ao%99%0C%5E%97%0CI%AFH%D9.%B0%3B%8F%ED%03%B6S%D6%5D%E6i_s9%F3*p%E9%1B%FD%C3%EB.7U%06%5E%19%C0%D1s.%17%A03u%E4%09%B0%7C%5E%2C%EB%15%DB%1F%3C%9E%B7%80%91%3B%DBc%AD%3Dma%BA%8B%3EV%AB%DBt.%5B%1E%01%BB%0F%AB%D5%9F%CF%AA%D5%DD%E7%E4%7F%0Bx%A3%FC%06%A9%23%0A%D6%C2%A1_2%00%00%00%09pHYs%00%00%0B%13%00%00%0B%13%01%00%9A%9C%18%00%00%00%3AIDAT8%11c%FC%FF%FF%7F%18%03%1A%60%01%F2%3F%A0%891%80%04%FF%11-%F8%17%9BJ%E2%05%B1ZD%81v%26t%E7%80%F8%A3%82h%A12%1A%20%A3%01%02%0F%01%BA%25%06%00%19%C0%0D%AEF%D5%3ES%00%00%00%00IEND%AEB%60%82");
background-repeat: no-repeat, repeat-x;
background-position: center center, top left;
color: transparent;
border: 1px solid black;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
cursor: pointer;
pointer-events: auto;
}
.ace_dark .ace_fold {
}
.ace_fold:hover{
background-image:
url("data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%11%00%00%00%09%08%06%00%00%00%D4%E8%C7%0C%00%00%03%1EiCCPICC%20Profile%00%00x%01%85T%DFk%D3P%14%FE%DAe%9D%B0%E1%8B%3Ag%11%09%3Eh%91ndStC%9C%B6kW%BA%CDZ%EA6%B7!H%9B%A6m%5C%9A%C6%24%ED~%B0%07%D9%8Bo%3A%C5w%F1%07%3E%F9%07%0C%D9%83o%7B%92%0D%C6%14a%F8%AC%88%22L%F6%22%B3%9E%9B4M'S%03%B9%F7%BB%DF%F9%EE9'%E7%E4%5E%A0%F9qZ%D3%14%2F%0F%14USO%C5%C2%FC%C4%E4%14%DF%F2%01%5E%1CC%2B%FChM%8B%86%16J%26G%40%0F%D3%B2y%EF%B3%F3%0E%1E%C6lt%EEo%DF%AB%FEc%D5%9A%95%0C%11%F0%1C%20%BE%945%C4%22%E1Y%A0i%5C%D4t%13%E0%D6%89%EF%9D15%C2%CDLsX%A7%04%09%1Fg8oc%81%E1%8C%8D%23%96f45%40%9A%09%C2%07%C5B%3AK%B8%408%98i%E0%F3%0D%D8%CE%81%14%E4'%26%A9%92.%8B%3C%ABER%2F%E5dE%B2%0C%F6%F0%1Fs%83%F2_%B0%A8%94%E9%9B%AD%E7%10%8Dm%9A%19N%D1%7C%8A%DE%1F9%7Dp%8C%E6%00%D5%C1%3F_%18%BDA%B8%9DpX6%E3%A35~B%CD%24%AE%11%26%BD%E7%EEti%98%EDe%9A%97Y)%12%25%1C%24%BCbT%AE3li%E6%0B%03%89%9A%E6%D3%ED%F4P%92%B0%9F4%BF43Y%F3%E3%EDP%95%04%EB1%C5%F5%F6KF%F4%BA%BD%D7%DB%91%93%07%E35%3E%A7)%D6%7F%40%FE%BD%F7%F5r%8A%E5y%92%F0%EB%B4%1E%8D%D5%F4%5B%92%3AV%DB%DB%E4%CD%A6%23%C3%C4wQ%3F%03HB%82%8E%1Cd(%E0%91B%0Ca%9Ac%C4%AA%F8L%16%19%22J%A4%D2itTy%B28%D6%3B(%93%96%ED%1CGx%C9_%0E%B8%5E%16%F5%5B%B2%B8%F6%E0%FB%9E%DD%25%D7%8E%BC%15%85%C5%B7%A3%D8Q%ED%B5%81%E9%BA%B2%13%9A%1B%7Fua%A5%A3n%E17%B9%E5%9B%1Bm%AB%0B%08Q%FE%8A%E5%B1H%5Ee%CAO%82Q%D7u6%E6%90S%97%FCu%0B%CF2%94%EE%25v%12X%0C%BA%AC%F0%5E%F8*l%0AO%85%17%C2%97%BF%D4%C8%CE%DE%AD%11%CB%80q%2C%3E%AB%9ES%CD%C6%EC%25%D2L%D2%EBd%B8%BF%8A%F5B%C6%18%F9%901CZ%9D%BE%24M%9C%8A9%F2%DAP%0B'%06w%82%EB%E6%E2%5C%2F%D7%07%9E%BB%CC%5D%E1%FA%B9%08%AD.r%23%8E%C2%17%F5E%7C!%F0%BE3%BE%3E_%B7o%88a%A7%DB%BE%D3d%EB%A31Z%EB%BB%D3%91%BA%A2%B1z%94%8F%DB'%F6%3D%8E%AA%13%19%B2%B1%BE%B1~V%08%2B%B4%A2cjJ%B3tO%00%03%25mN%97%F3%05%93%EF%11%84%0B%7C%88%AE-%89%8F%ABbW%90O%2B%0Ao%99%0C%5E%97%0CI%AFH%D9.%B0%3B%8F%ED%03%B6S%D6%5D%E6i_s9%F3*p%E9%1B%FD%C3%EB.7U%06%5E%19%C0%D1s.%17%A03u%E4%09%B0%7C%5E%2C%EB%15%DB%1F%3C%9E%B7%80%91%3B%DBc%AD%3Dma%BA%8B%3EV%AB%DBt.%5B%1E%01%BB%0F%AB%D5%9F%CF%AA%D5%DD%E7%E4%7F%0Bx%A3%FC%06%A9%23%0A%D6%C2%A1_2%00%00%00%09pHYs%00%00%0B%13%00%00%0B%13%01%00%9A%9C%18%00%00%00%B5IDAT(%15%A5%91%3D%0E%02!%10%85ac%E1%05%D6%CE%D6%C6%CE%D2%E8%ED%CD%DE%C0%C6%D6N.%E0V%F8%3D%9Ca%891XH%C2%BE%D9y%3F%90!%E6%9C%C3%BFk%E5%011%C6-%F5%C8N%04%DF%BD%FF%89%DFt%83DN%60%3E%F3%AB%A0%DE%1A%5Dg%BE%10Q%97%1B%40%9C%A8o%10%8F%5E%828%B4%1B%60%87%F6%02%26%85%1Ch%1E%C1%2B%5Bk%FF%86%EE%B7j%09%9A%DA%9B%ACe%A3%F9%EC%DA!9%B4%D5%A6%81%86%86%98%CC%3C%5B%40%FA%81%B3%E9%CB%23%94%C16Azo%05%D4%E1%C1%95a%3B%8A'%A0%E8%CC%17%22%85%1D%BA%00%A2%FA%DC%0A%94%D1%D1%8D%8B%3A%84%17B%C7%60%1A%25Z%FC%8D%00%00%00%00IEND%AEB%60%82"),
url("data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%05%00%00%007%08%06%00%00%00%C4%DD%80C%00%00%03%1EiCCPICC%20Profile%00%00x%01%85T%DFk%D3P%14%FE%DAe%9D%B0%E1%8B%3Ag%11%09%3Eh%91ndStC%9C%B6kW%BA%CDZ%EA6%B7!H%9B%A6m%5C%9A%C6%24%ED~%B0%07%D9%8Bo%3A%C5w%F1%07%3E%F9%07%0C%D9%83o%7B%92%0D%C6%14a%F8%AC%88%22L%F6%22%B3%9E%9B4M'S%03%B9%F7%BB%DF%F9%EE9'%E7%E4%5E%A0%F9qZ%D3%14%2F%0F%14USO%C5%C2%FC%C4%E4%14%DF%F2%01%5E%1CC%2B%FChM%8B%86%16J%26G%40%0F%D3%B2y%EF%B3%F3%0E%1E%C6lt%EEo%DF%AB%FEc%D5%9A%95%0C%11%F0%1C%20%BE%945%C4%22%E1Y%A0i%5C%D4t%13%E0%D6%89%EF%9D15%C2%CDLsX%A7%04%09%1Fg8oc%81%E1%8C%8D%23%96f45%40%9A%09%C2%07%C5B%3AK%B8%408%98i%E0%F3%0D%D8%CE%81%14%E4'%26%A9%92.%8B%3C%ABER%2F%E5dE%B2%0C%F6%F0%1Fs%83%F2_%B0%A8%94%E9%9B%AD%E7%10%8Dm%9A%19N%D1%7C%8A%DE%1F9%7Dp%8C%E6%00%D5%C1%3F_%18%BDA%B8%9DpX6%E3%A35~B%CD%24%AE%11%26%BD%E7%EEti%98%EDe%9A%97Y)%12%25%1C%24%BCbT%AE3li%E6%0B%03%89%9A%E6%D3%ED%F4P%92%B0%9F4%BF43Y%F3%E3%EDP%95%04%EB1%C5%F5%F6KF%F4%BA%BD%D7%DB%91%93%07%E35%3E%A7)%D6%7F%40%FE%BD%F7%F5r%8A%E5y%92%F0%EB%B4%1E%8D%D5%F4%5B%92%3AV%DB%DB%E4%CD%A6%23%C3%C4wQ%3F%03HB%82%8E%1Cd(%E0%91B%0Ca%9Ac%C4%AA%F8L%16%19%22J%A4%D2itTy%B28%D6%3B(%93%96%ED%1CGx%C9_%0E%B8%5E%16%F5%5B%B2%B8%F6%E0%FB%9E%DD%25%D7%8E%BC%15%85%C5%B7%A3%D8Q%ED%B5%81%E9%BA%B2%13%9A%1B%7Fua%A5%A3n%E17%B9%E5%9B%1Bm%AB%0B%08Q%FE%8A%E5%B1H%5Ee%CAO%82Q%D7u6%E6%90S%97%FCu%0B%CF2%94%EE%25v%12X%0C%BA%AC%F0%5E%F8*l%0AO%85%17%C2%97%BF%D4%C8%CE%DE%AD%11%CB%80q%2C%3E%AB%9ES%CD%C6%EC%25%D2L%D2%EBd%B8%BF%8A%F5B%C6%18%F9%901CZ%9D%BE%24M%9C%8A9%F2%DAP%0B'%06w%82%EB%E6%E2%5C%2F%D7%07%9E%BB%CC%5D%E1%FA%B9%08%AD.r%23%8E%C2%17%F5E%7C!%F0%BE3%BE%3E_%B7o%88a%A7%DB%BE%D3d%EB%A31Z%EB%BB%D3%91%BA%A2%B1z%94%8F%DB'%F6%3D%8E%AA%13%19%B2%B1%BE%B1~V%08%2B%B4%A2cjJ%B3tO%00%03%25mN%97%F3%05%93%EF%11%84%0B%7C%88%AE-%89%8F%ABbW%90O%2B%0Ao%99%0C%5E%97%0CI%AFH%D9.%B0%3B%8F%ED%03%B6S%D6%5D%E6i_s9%F3*p%E9%1B%FD%C3%EB.7U%06%5E%19%C0%D1s.%17%A03u%E4%09%B0%7C%5E%2C%EB%15%DB%1F%3C%9E%B7%80%91%3B%DBc%AD%3Dma%BA%8B%3EV%AB%DBt.%5B%1E%01%BB%0F%AB%D5%9F%CF%AA%D5%DD%E7%E4%7F%0Bx%A3%FC%06%A9%23%0A%D6%C2%A1_2%00%00%00%09pHYs%00%00%0B%13%00%00%0B%13%01%00%9A%9C%18%00%00%003IDAT8%11c%FC%FF%FF%7F%3E%03%1A%60%01%F2%3F%A3%891%80%04%FFQ%26%F8w%C0%B43%A1%DB%0C%E2%8F%0A%A2%85%CAh%80%8C%06%08%3C%04%E8%96%18%00%A3S%0D%CD%CF%D8%C1%9D%00%00%00%00IEND%AEB%60%82");
background-repeat: no-repeat, repeat-x;
background-position: center center, top left;
}
.ace_dragging .ace_content {
cursor: move;
}
.ace_folding-enabled > .ace_gutter-cell {
padding-right: 13px;
}
.ace_fold-widget {
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
margin: 0 -12px 1px 1px;
display: inline-block;
height: 14px;
width: 11px;
vertical-align: text-bottom;
background-image: url("data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%05%00%00%00%05%08%06%00%00%00%8Do%26%E5%00%00%004IDATx%DAe%8A%B1%0D%000%0C%C2%F2%2CK%96%BC%D0%8F9%81%88H%E9%D0%0E%96%C0%10%92%3E%02%80%5E%82%E4%A9*-%EEsw%C8%CC%11%EE%96w%D8%DC%E9*Eh%0C%151(%00%00%00%00IEND%AEB%60%82");
background-repeat: no-repeat;
background-position: center 4px;
border-radius: 3px;
border: 1px solid transparent;
}
.ace_fold-widget.end {
background-image: url("data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%05%00%00%00%05%08%06%00%00%00%8Do%26%E5%00%00%004IDATx%DAm%C7%C1%09%000%08C%D1%8C%ECE%C8E(%8E%EC%02)%1EZJ%F1%C1'%04%07I%E1%E5%EE%CAL%F5%A2%99%99%22%E2%D6%1FU%B5%FE0%D9x%A7%26Wz5%0E%D5%00%00%00%00IEND%AEB%60%82");
}
.ace_fold-widget.closed {
background-image: url("data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%03%00%00%00%06%08%06%00%00%00%06%E5%24%0C%00%00%009IDATx%DA5%CA%C1%09%000%08%03%C0%AC*(%3E%04%C1%0D%BA%B1%23%A4Uh%E0%20%81%C0%CC%F8%82%81%AA%A2%AArGfr%88%08%11%11%1C%DD%7D%E0%EE%5B%F6%F6%CB%B8%05Q%2F%E9tai%D9%00%00%00%00IEND%AEB%60%82");
}
.ace_fold-widget:hover {
border: 1px solid rgba(0, 0, 0, 0.3);
background-color: rgba(255, 255, 255, 0.2);
-moz-box-shadow: 0 1px 1px rgba(255, 255, 255, 0.7);
-webkit-box-shadow: 0 1px 1px rgba(255, 255, 255, 0.7);
box-shadow: 0 1px 1px rgba(255, 255, 255, 0.7);
background-position: center 4px;
}
.ace_fold-widget:active {
border: 1px solid rgba(0, 0, 0, 0.4);
background-color: rgba(0, 0, 0, 0.05);
-moz-box-shadow: 0 1px 1px rgba(255, 255, 255, 0.8);
-webkit-box-shadow: 0 1px 1px rgba(255, 255, 255, 0.8);
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.end {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAH0lEQVQIW2P4//8/AxQ7wNjIAjDMgC4AxjCVKBirIAAF0kz2rlhxpAAAAABJRU5ErkJggg==");
}
.ace_dark .ace_fold-widget.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 {
-moz-box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);
-webkit-box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);
box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);
}
.ace_fold-widget.invalid {
background-color: #FFB4B4;
border-color: #DE5555;
}
.ace_fade-fold-widgets .ace_fold-widget {
-moz-transition: opacity 0.4s ease 0.05s;
-webkit-transition: opacity 0.4s ease 0.05s;
-o-transition: opacity 0.4s ease 0.05s;
-ms-transition: opacity 0.4s ease 0.05s;
transition: opacity 0.4s ease 0.05s;
opacity: 0;
}
.ace_fade-fold-widgets:hover .ace_fold-widget {
-moz-transition: opacity 0.05s ease 0.05s;
-webkit-transition: opacity 0.05s ease 0.05s;
-o-transition: opacity 0.05s ease 0.05s;
-ms-transition: opacity 0.05s ease 0.05s;
transition: opacity 0.05s ease 0.05s;
opacity:1;
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 290 B

@@ -1,617 +0,0 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
"use strict";
var oop = require("./lib/oop");
var EventEmitter = require("./lib/event_emitter").EventEmitter;
var Range = require("./range").Range;
var Anchor = require("./anchor").Anchor;
/**
* class Document
*
* Contains the text of the document. Documents are controlled by a single [[EditSession `EditSession`]]. At its core, `Document`s are just an array of strings, with each row in the document matching up to the array index.
*
*
**/
/**
* new Document([text])
* - text (String | Array): The starting text
*
* Creates a new `Document`. If `text` is included, the `Document` contains those strings; otherwise, it's empty.
*
**/
var Document = function(text) {
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 (text.length == 0) {
this.$lines = [""];
} else if (Array.isArray(text)) {
this.insertLines(0, text);
} else {
this.insert({row: 0, column:0}, text);
}
};
(function() {
oop.implement(this, EventEmitter);
/**
* Document.setValue(text) -> Void
* - text (String): The text to use
*
* Replaces all the lines in the current `Document` with the value of `text`.
**/
this.setValue = function(text) {
var len = this.getLength();
this.remove(new Range(0, 0, len, this.getLine(len-1).length));
this.insert({row: 0, column:0}, text);
};
/**
* Document.getValue() -> String
*
* Returns all the lines in the document as a single string, split by the new line character.
**/
this.getValue = function() {
return this.getAllLines().join(this.getNewLineCharacter());
};
/**
* Document.createAnchor(row, column) -> Anchor
* - row (Number): The row number to use
* - column (Number): The column number to use
*
* Creates a new `Anchor` to define a floating point in the document.
**/
this.createAnchor = function(row, column) {
return new Anchor(this, row, column);
};
/** internal, hide
* Document.$split(text) -> [String]
* - text (String): The text to work with
* + ([String]): A String array, with each index containing a piece of the original `text` string.
*
* Splits a string of text on any newline (`\n`) or carriage-return ('\r') characters.
*
*
**/
// 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/);
};
/** internal, hide
* Document.$detectNewLine(text) -> Void
*
*
**/
this.$detectNewLine = function(text) {
var match = text.match(/^.*?(\r\n|\r|\n)/m);
if (match) {
this.$autoNewLine = match[1];
} else {
this.$autoNewLine = "\n";
}
};
/**
* Document.getNewLineCharacter() -> String
* + (String): If `newLineMode == windows`, `\r\n` is returned.<br/>
* If `newLineMode == unix`, `\n` is returned.<br/>
* If `newLineMode == auto`, the value of `autoNewLine` is returned.
*
* Returns the newline character that's being used, depending on the value of `newLineMode`.
*
*
*
**/
this.getNewLineCharacter = function() {
switch (this.$newLineMode) {
case "windows":
return "\r\n";
case "unix":
return "\n";
case "auto":
return this.$autoNewLine;
}
};
this.$autoNewLine = "\n";
this.$newLineMode = "auto";
/**
* Document.setNewLineMode(newLineMode) -> Void
* - newLineMode(String): [The newline mode to use; can be either `windows`, `unix`, or `auto`]{: #Document.setNewLineMode.param}
*
* [Sets the new line mode.]{: #Document.setNewLineMode.desc}
**/
this.setNewLineMode = function(newLineMode) {
if (this.$newLineMode === newLineMode)
return;
this.$newLineMode = newLineMode;
};
/**
* Document.getNewLineMode() -> String
*
* [Returns the type of newlines being used; either `windows`, `unix`, or `auto`]{: #Document.getNewLineMode}
*
**/
this.getNewLineMode = function() {
return this.$newLineMode;
};
/**
* Document.isNewLine(text) -> Boolean
* - text (String): The text to check
*
* Returns `true` if `text` is a newline character (either `\r\n`, `\r`, or `\n`).
*
**/
this.isNewLine = function(text) {
return (text == "\r\n" || text == "\r" || text == "\n");
};
/**
* Document.getLine(row) -> String
* - row (Number): The row index to retrieve
*
* Returns a verbatim copy of the given line as it is in the document
*
**/
this.getLine = function(row) {
return this.$lines[row] || "";
};
/**
* Document.getLines(firstRow, lastRow) -> [String]
* - firstRow (Number): The first row index to retrieve
* - lastRow (Number): The final row index to retrieve
*
* Returns an array of strings of the rows between `firstRow` and `lastRow`. This function is inclusive of `lastRow`.
*
**/
this.getLines = function(firstRow, lastRow) {
return this.$lines.slice(firstRow, lastRow + 1);
};
/**
* Document.getAllLines() -> [String]
*
* Returns all lines in the document as string array. Warning: The caller should not modify this array!
**/
this.getAllLines = function() {
return this.getLines(0, this.getLength());
};
/**
* Document.getLength() -> Number
*
* Returns the number of rows in the document.
**/
this.getLength = function() {
return this.$lines.length;
};
/**
* Document.getTextRange(range) -> String
* - range (Range): The range to work with
*
* [Given a range within the document, this function returns all the text within that range as a single string.]{: #Document.getTextRange.desc}
**/
this.getTextRange = function(range) {
if (range.start.row == range.end.row) {
return this.$lines[range.start.row].substring(range.start.column,
range.end.column);
}
else {
var lines = this.getLines(range.start.row+1, range.end.row-1);
lines.unshift((this.$lines[range.start.row] || "").substring(range.start.column));
lines.push((this.$lines[range.end.row] || "").substring(0, range.end.column));
return lines.join(this.getNewLineCharacter());
}
};
/** internal, hide
* Document.$clipPosition(position) -> Number
*
*
**/
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;
}
return position;
};
/**
* Document.insert(position, text) -> Number
* - position (Number): The position to start inserting at
* - text (String): A chunk of text to insert
* + (Number): The position of the last line of `text`. If the length of `text` is 0, this function simply returns `position`.
* Inserts a block of `text` and the indicated `position`.
*
*
**/
this.insert = function(position, text) {
if (!text || text.length === 0)
return position;
position = this.$clipPosition(position);
// only detect new lines if the document has no line break yet
if (this.getLength() <= 1)
this.$detectNewLine(text);
var lines = this.$split(text);
var firstLine = lines.splice(0, 1)[0];
var lastLine = lines.length == 0 ? null : lines.splice(lines.length - 1, 1)[0];
position = this.insertInLine(position, firstLine);
if (lastLine !== null) {
position = this.insertNewLine(position); // terminate first line
position = this.insertLines(position.row, lines);
position = this.insertInLine(position, lastLine || "");
}
return position;
};
/**
* Document.insertLines(row, lines) -> Object
* - row (Number): The index of the row to insert at
* - lines (Array): An array of strings
* + (Object): Returns an object containing the final row and column, like this:<br/>
* ```{row: endRow, column: 0}```<br/>
* If `lines` is empty, this function returns an object containing the current row, and column, like this:<br/>
* ```{row: row, column: 0}```
*
* Inserts the elements in `lines` into the document, starting at the row index given by `row`. This method also triggers the `'change'` event.
*
*
**/
this.insertLines = function(row, lines) {
if (lines.length == 0)
return {row: row, column: 0};
// apply doesn't work for big arrays (smallest threshold is on safari 0xFFFF)
// to circumvent that we have to break huge inserts into smaller chunks here
if (lines.length > 0xFFFF) {
var end = this.insertLines(row, lines.slice(0xFFFF));
lines = lines.slice(0, 0xFFFF);
}
var args = [row, 0];
args.push.apply(args, lines);
this.$lines.splice.apply(this.$lines, args);
var range = new Range(row, 0, row + lines.length, 0);
var delta = {
action: "insertLines",
range: range,
lines: lines
};
this._emit("change", { data: delta });
return end || range.end;
};
/**
* Document.insertNewLine(position) -> Object
* - position (String): The position to insert at
* + (Object): Returns an object containing the final row and column, like this:<br/>
* ```{row: endRow, column: 0}```
*
* Inserts a new line into the document at the current row's `position`. This method also triggers the `'change'` event.
*
*
*
**/
this.insertNewLine = function(position) {
position = this.$clipPosition(position);
var line = this.$lines[position.row] || "";
this.$lines[position.row] = line.substring(0, position.column);
this.$lines.splice(position.row + 1, 0, line.substring(position.column, line.length));
var end = {
row : position.row + 1,
column : 0
};
var delta = {
action: "insertText",
range: Range.fromPoints(position, end),
text: this.getNewLineCharacter()
};
this._emit("change", { data: delta });
return end;
};
/**
* Document.insertInLine(position, text) -> Object | Number
* - position (Number): The position to insert at
* - text (String): A chunk of text
* + (Object): Returns an object containing the final row and column, like this:<br/>
* ```{row: endRow, column: 0}```
* + (Number): If `text` is empty, this function returns the value of `position`
*
* Inserts `text` into the `position` at the current row. This method also triggers the `'change'` event.
*
*
*
**/
this.insertInLine = function(position, text) {
if (text.length == 0)
return position;
var line = this.$lines[position.row] || "";
this.$lines[position.row] = line.substring(0, position.column) + text
+ line.substring(position.column);
var end = {
row : position.row,
column : position.column + text.length
};
var delta = {
action: "insertText",
range: Range.fromPoints(position, end),
text: text
};
this._emit("change", { data: delta });
return end;
};
/**
* Document.remove(range) -> Object
* - range (Range): A specified Range to remove
* + (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`.
*
* Removes the `range` from the document.
*
*
**/
this.remove = function(range) {
// clip to document
range.start = this.$clipPosition(range.start);
range.end = this.$clipPosition(range.end);
if (range.isEmpty())
return range.start;
var firstRow = range.start.row;
var lastRow = range.end.row;
if (range.isMultiLine()) {
var firstFullRow = range.start.column == 0 ? firstRow : firstRow + 1;
var lastFullRow = lastRow - 1;
if (range.end.column > 0)
this.removeInLine(lastRow, 0, range.end.column);
if (lastFullRow >= firstFullRow)
this.removeLines(firstFullRow, lastFullRow);
if (firstFullRow != firstRow) {
this.removeInLine(firstRow, range.start.column, this.getLine(firstRow).length);
this.removeNewLine(range.start.row);
}
}
else {
this.removeInLine(firstRow, range.start.column, range.end.column);
}
return range.start;
};
/**
* Document.removeInLine(row, startColumn, endColumn) -> Object
* - row (Number): The row to remove from
* - startColumn (Number): The column to start removing at
* - endColumn (Number): The column to stop removing at
* + (Object): Returns an object containing `startRow` and `startColumn`, indicating the new row and column values.<br/>If `startColumn` is equal to `endColumn`, this function returns nothing.
*
* Removes the specified columns from the `row`. This method also triggers the `'change'` event.
*
*
**/
this.removeInLine = function(row, startColumn, endColumn) {
if (startColumn == endColumn)
return;
var range = new Range(row, startColumn, row, endColumn);
var line = this.getLine(row);
var removed = line.substring(startColumn, endColumn);
var newLine = line.substring(0, startColumn) + line.substring(endColumn, line.length);
this.$lines.splice(row, 1, newLine);
var delta = {
action: "removeText",
range: range,
text: removed
};
this._emit("change", { data: delta });
return range.start;
};
/**
* Document.removeLines(firstRow, lastRow) -> [String]
* - firstRow (Number): The first row to be removed
* - lastRow (Number): The last row to be removed
* + ([String]): Returns all the removed lines.
*
* Removes a range of full lines. This method also triggers the `'change'` event.
*
*
**/
this.removeLines = function(firstRow, lastRow) {
var range = new Range(firstRow, 0, lastRow + 1, 0);
var removed = this.$lines.splice(firstRow, lastRow - firstRow + 1);
var delta = {
action: "removeLines",
range: range,
nl: this.getNewLineCharacter(),
lines: removed
};
this._emit("change", { data: delta });
return removed;
};
/**
* Document.removeNewLine(row) -> Void
* - row (Number): The row to check
*
* Removes the new line between `row` and the row immediately following it. This method also triggers the `'change'` event.
*
**/
this.removeNewLine = function(row) {
var firstLine = this.getLine(row);
var secondLine = this.getLine(row+1);
var range = new Range(row, firstLine.length, row+1, 0);
var line = firstLine + secondLine;
this.$lines.splice(row, 2, line);
var delta = {
action: "removeText",
range: range,
text: this.getNewLineCharacter()
};
this._emit("change", { data: delta });
};
/**
* Document.replace(range, text) -> Object
* - range (Range): A specified Range to replace
* - text (String): The new text to use as a replacement
* + (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.
*
* Replaces a range in the document with the new `text`.
*
**/
this.replace = function(range, text) {
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);
if (text) {
var end = this.insert(range.start, text);
}
else {
end = range.start;
}
return end;
};
/**
* Document.applyDeltas(deltas) -> Void
*
* Applies all the changes previously accumulated. These can be either `'includeText'`, `'insertLines'`, `'removeText'`, and `'removeLines'`.
**/
this.applyDeltas = function(deltas) {
for (var i=0; i<deltas.length; i++) {
var delta = deltas[i];
var range = Range.fromPoints(delta.range.start, delta.range.end);
if (delta.action == "insertLines")
this.insertLines(range.start.row, delta.lines);
else if (delta.action == "insertText")
this.insert(range.start, delta.text);
else if (delta.action == "removeLines")
this.removeLines(range.start.row, range.end.row - 1);
else if (delta.action == "removeText")
this.remove(range);
}
};
/**
* Document.revertDeltas(deltas) -> Void
*
* Reverts any changes previously applied. These can be either `'includeText'`, `'insertLines'`, `'removeText'`, and `'removeLines'`.
**/
this.revertDeltas = function(deltas) {
for (var i=deltas.length-1; i>=0; i--) {
var delta = deltas[i];
var range = Range.fromPoints(delta.range.start, delta.range.end);
if (delta.action == "insertLines")
this.removeLines(range.start.row, range.end.row - 1);
else if (delta.action == "insertText")
this.remove(range);
else if (delta.action == "removeLines")
this.insertLines(range.start.row, delta.lines);
else if (delta.action == "removeText")
this.insert(range.start, delta.text);
}
};
}).call(Document.prototype);
exports.Document = Document;
});
@@ -1,314 +0,0 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Julian Viereck <julian.viereck@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** 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.data); });
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.data); });
doc.insertNewLine({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.data); });
doc.insertLines(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.data); });
doc.insertLines(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.data); });
doc.insertLines(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.data); });
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.data); });
doc.insert({row: 2, column: 0}, "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.data); });
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.data); });
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.data); });
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.data); });
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.data); });
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.removeLines(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);
}
};
});
if (typeof module !== "undefined" && module === require.main) {
require("asyncjs").test.testcase(module.exports).exec()
}
File diff suppressed because it is too large Load Diff
@@ -1,252 +0,0 @@
/* vim:ts=4:sts=4:sw=4:
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
"use strict";
var TokenIterator = require("../token_iterator").TokenIterator;
var Range = require("../range").Range;
/**
* class BracketMatch
*
*
*
*
**/
/**
* new BracketMatch(position)
* - platform (String): Identifier for the platform; must be either `'mac'` or `'win'`
* - commands (Array): A list of commands
*
* TODO
*
*
**/
function BracketMatch() {
/**
* new findMatchingBracket(position)
* - position (Number): Identifier for the platform; must be either `'mac'` or `'win'`
* - commands (Array): A list of commands
*
* TODO
*
*
**/
this.findMatchingBracket = function(position) {
if (position.column == 0) return null;
var charBeforeCursor = 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")
+ ")+"
);
}
// 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")
+ ")+"
);
}
// 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;
});
@@ -1,116 +0,0 @@
/* vim:ts=4:sts=4:sw=4:
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Julian Viereck <julian DOT viereck AT gmail DOT com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
"use strict";
/*
* 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 = [];
};
(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());
});
return fold;
};
this.addSubFold = function(fold) {
if (this.range.isEqual(fold))
return this;
if (!this.range.containsRange(fold))
throw "A fold can't intersect already existing fold" + fold.range + this.range;
var row = fold.range.start.row, column = fold.range.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 "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;
}
}).call(Fold.prototype);
});
@@ -1,276 +0,0 @@
/* vim:ts=4:sts=4:sw=4:
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Julian Viereck <julian DOT viereck AT gmail DOT com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** 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 "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 "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,
comp, 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];
comp = fold.range.compareStart(endRow, endColumn);
// This fold is after the endRow/Column.
if (comp == -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 (comp == 0), then end here.
if (stop || comp == 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 fold = this.getNextFoldTo(row, column).fold,
folds = this.folds;
var foldData = this.foldData;
if (!fold) {
return null;
}
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;
var fold;
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;
});
@@ -1,759 +0,0 @@
/* vim:ts=4:sts=4:sw=4:
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Julian Viereck <julian DOT viereck AT gmail DOT com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** 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) {
range = range.clone();
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);
}
}
return foundFolds;
};
/*
* Returns all folds in the document
*/
this.getAllFolds = function() {
var folds = [];
var foldLines = this.$foldData;
function addFold(fold) {
folds.push(fold);
if (!fold.subFolds)
return;
for (var i = 0; i < fold.subFolds.length; i++)
addFold(fold.subFolds[i]);
}
for (var i = 0; i < foldLines.length; i++)
for (var j = 0; j < foldLines[i].folds.length; j++)
addFold(foldLines[i].folds[j]);
return folds;
};
/*
* Returns the string between folds at the given position.
* E.g.
* foo<fold>b|ar<fold>wolrd -> "bar"
* foo<fold>bar<fold>wol|rd -> "world"
* foo<fold>bar<fo|ld>wolrd -> <null>
*
* 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.
* foo<fold>b|ar<fold>wolrd -trim=-1> "b"
* foo<fold>bar<fold>wol|rd -trim=+1> "rld"
* fo|o<fold>bar<fold>wolrd -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);
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 (fold.placeholder.length < 2)
throw "Placeholder has to be at least 2 characters";
if (startRow == endRow && endColumn - startColumn < 2)
throw "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))
|| (endFold && !endFold.range.isEnd(endRow, endColumn))
) {
throw "A fold can't intersect already existing fold" + fold.range + startFold.range;
}
// 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.
fold.subFolds = folds;
}
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 });
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.$useWrapMode)
this.$updateWrapData(startRow, endRow);
else
this.$updateRowLengthCache(startRow, endRow);
// Notify that fold data has changed.
this.$modified = true;
this._emit("changeFold", { data: fold });
};
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(fold) {
this.addFold(fold);
}, this);
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);
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.getFoldsInRange(range);
if (expandInner) {
this.removeFolds(folds);
} else {
// TODO: might need to remove and add folds in one go instead of using
// expandFolds several times.
while (folds.length) {
this.expandFolds(folds);
folds = this.getFoldsInRange(range);
}
}
};
/*
* 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.getFoldDisplayLine = function(foldLine, endRow, endColumn, startRow, startColumn) {
if (startRow == null) {
startRow = foldLine.start.row;
startColumn = 0;
}
if (endRow == null) {
endRow = foldLine.end.row;
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;
} else if (row == startRow) {
if (column < startColumn) {
return;
}
lastColumn = Math.max(startColumn, lastColumn);
}
if (placeholder) {
textLine += placeholder;
} else {
textLine += doc.getLine(row).substring(lastColumn, column);
}
}.bind(this), 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) {
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(/\..*/, "\\."));
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);
do {
token = iterator.stepForward();
} while(token && re.test(token.type));
token = iterator.stepBackward();
range.end.row = iterator.getCurrentTokenRow();
range.end.column = iterator.getCurrentTokenColumn() + token.value.length;
return range;
}
};
this.foldAll = function(startRow, endRow) {
var foldWidgets = this.foldWidgets;
endRow = endRow || this.getLength();
for (var row = startRow || 0; 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
// wouldn't it be better for addFold to return null istead of throwing?
if (range && range.end.row < endRow) try {
this.addFold("...", range);
} catch(e) {}
}
};
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);
};
// structured folding
this.$setFolding = function(foldMode) {
if (this.$foldMode == foldMode)
return;
this.$foldMode = foldMode;
this.removeListener('change', this.$updateFoldWidgets);
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.on('change', this.$updateFoldWidgets);
};
this.onFoldWidgetClick = function(row, e) {
var type = this.getFoldWidget(row);
var line = this.getLine(row);
var onlySubfolds = e.shiftKey;
var addSubfolds = onlySubfolds || e.ctrlKey || e.altKey || e.metaKey;
var fold;
if (type == "end")
fold = this.getFoldAt(row, 0, -1);
else
fold = this.getFoldAt(row, line.length, 1);
if (fold) {
if (addSubfolds)
this.removeFold(fold);
else
this.expandFold(fold);
return;
}
var range = this.getFoldWidgetRange(row);
if (range) {
// sometimes singleline folds can be missed by the code above
if (!range.isMultiLine()) {
fold = this.getFoldAt(range.start.row, range.start.column, 1);
if (fold && range.isEqual(fold.range)) {
this.removeFold(fold);
return;
}
}
if (!onlySubfolds)
this.addFold("...", range);
if (addSubfolds)
this.foldAll(range.start.row + 1, range.end.row);
} else {
if (addSubfolds)
this.foldAll(row + 1, this.getLength());
e.target.className += " invalid"
}
};
this.updateFoldWidgets = function(e) {
var delta = e.data;
var range = delta.range;
var firstRow = range.start.row;
var len = range.end.row - firstRow;
if (len === 0) {
this.foldWidgets[firstRow] = null;
} else if (delta.action == "removeText" || delta.action == "removeLines") {
this.foldWidgets.splice(firstRow, len + 1, null);
} else {
var args = Array(len + 1);
args.unshift(firstRow, 1);
this.foldWidgets.splice.apply(this.foldWidgets, args);
}
};
}
exports.Folding = Folding;
});
@@ -1,981 +0,0 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Julian Viereck <julian DOT viereck AT gmail DOT com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** 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<items.length; i++) {",
" alert(items[i] + \"juhu\");",
" } // Real Tab.",
"}"
];
var session = new EditSession(lines.join("\n"));
session.setUndoManager(new UndoManager());
session.addFold("args...", new Range(0, 13, 0, 18));
session.addFold("foo...", new Range(1, 10, 2, 10));
session.addFold("bar...", new Range(2, 20, 2, 25));
return session;
}
module.exports = {
"test: find matching opening bracket in Text mode" : function() {
var session = new EditSession(["(()(", "())))"]);
assert.position(session.findMatchingBracket({row: 0, column: 3}), 0, 1);
assert.position(session.findMatchingBracket({row: 1, column: 2}), 1, 0);
assert.position(session.findMatchingBracket({row: 1, column: 3}), 0, 3);
assert.position(session.findMatchingBracket({row: 1, column: 4}), 0, 0);
assert.equal(session.findMatchingBracket({row: 1, column: 5}), null);
},
"test: find matching closing bracket in Text mode" : function() {
var session = new EditSession(["(()(", "())))"]);
assert.position(session.findMatchingBracket({row: 1, column: 1}), 1, 1);
assert.position(session.findMatchingBracket({row: 1, column: 1}), 1, 1);
assert.position(session.findMatchingBracket({row: 0, column: 4}), 1, 2);
assert.position(session.findMatchingBracket({row: 0, column: 2}), 0, 2);
assert.position(session.findMatchingBracket({row: 0, column: 1}), 1, 3);
assert.equal(session.findMatchingBracket({row: 0, column: 0}), null);
},
"test: find matching opening bracket in JavaScript mode" : function() {
var lines = [
"function foo() {",
" var str = \"{ foo()\";",
" if (debug) {",
" // write str (a string) to the console",
" console.log(str);",
" }",
" str += \" bar() }\";",
"}"
];
var session = new EditSession(lines.join("\n"), new JavaScriptMode());
assert.position(session.findMatchingBracket({row: 0, column: 14}), 0, 12);
assert.position(session.findMatchingBracket({row: 7, column: 1}), 0, 15);
assert.position(session.findMatchingBracket({row: 6, column: 20}), 1, 15);
assert.position(session.findMatchingBracket({row: 1, column: 22}), 1, 20);
assert.position(session.findMatchingBracket({row: 3, column: 31}), 3, 21);
assert.position(session.findMatchingBracket({row: 4, column: 24}), 4, 19);
assert.equal(session.findMatchingBracket({row: 0, column: 1}), null);
},
"test: find matching closing bracket in JavaScript mode" : function() {
var lines = [
"function foo() {",
" var str = \"{ foo()\";",
" if (debug) {",
" // write str (a string) to the console",
" console.log(str);",
" }",
" str += \" bar() }\";",
"}"
];
var session = new EditSession(lines.join("\n"), new JavaScriptMode());
assert.position(session.findMatchingBracket({row: 0, column: 13}), 0, 13);
assert.position(session.findMatchingBracket({row: 0, column: 16}), 7, 0);
assert.position(session.findMatchingBracket({row: 1, column: 16}), 6, 19);
assert.position(session.findMatchingBracket({row: 1, column: 21}), 1, 21);
assert.position(session.findMatchingBracket({row: 3, column: 22}), 3, 30);
assert.position(session.findMatchingBracket({row: 4, column: 20}), 4, 23);
},
"test: handle unbalanced brackets in JavaScript mode" : function() {
var lines = [
"function foo() {",
" var str = \"{ foo()\";",
" if (debug) {",
" // write str a string) to the console",
" console.log(str);",
" ",
" str += \" bar() \";",
"}"
];
var session = new EditSession(lines.join("\n"), new JavaScriptMode());
assert.equal(session.findMatchingBracket({row: 0, column: 16}), null);
assert.equal(session.findMatchingBracket({row: 3, column: 30}), null);
assert.equal(session.findMatchingBracket({row: 1, column: 16}), null);
},
"test: match different bracket types" : function() {
var session = new EditSession(["({[", ")]}"]);
assert.position(session.findMatchingBracket({row: 0, column: 1}), 1, 0);
assert.position(session.findMatchingBracket({row: 0, column: 2}), 1, 2);
assert.position(session.findMatchingBracket({row: 0, column: 3}), 1, 1);
assert.position(session.findMatchingBracket({row: 1, column: 1}), 0, 0);
assert.position(session.findMatchingBracket({row: 1, column: 2}), 0, 2);
assert.position(session.findMatchingBracket({row: 1, column: 3}), 0, 1);
},
"test: move lines down" : function() {
var session = new EditSession(["a1", "a2", "a3", "a4"]);
session.moveLinesDown(0, 1);
assert.equal(session.getValue(), ["a3", "a1", "a2", "a4"].join("\n"));
session.moveLinesDown(1, 2);
assert.equal(session.getValue(), ["a3", "a4", "a1", "a2"].join("\n"));
session.moveLinesDown(2, 3);
assert.equal(session.getValue(), ["a3", "a4", "a1", "a2"].join("\n"));
session.moveLinesDown(2, 2);
assert.equal(session.getValue(), ["a3", "a4", "a2", "a1"].join("\n"));
},
"test: move lines up" : function() {
var session = new EditSession(["a1", "a2", "a3", "a4"]);
session.moveLinesUp(2, 3);
assert.equal(session.getValue(), ["a1", "a3", "a4", "a2"].join("\n"));
session.moveLinesUp(1, 2);
assert.equal(session.getValue(), ["a3", "a4", "a1", "a2"].join("\n"));
session.moveLinesUp(0, 1);
assert.equal(session.getValue(), ["a3", "a4", "a1", "a2"].join("\n"));
session.moveLinesUp(2, 2);
assert.equal(session.getValue(), ["a3", "a1", "a4", "a2"].join("\n"));
},
"test: duplicate lines" : function() {
var session = new EditSession(["1", "2", "3", "4"]);
session.duplicateLines(1, 2);
assert.equal(session.getValue(), ["1", "2", "3", "2", "3", "4"].join("\n"));
},
"test: duplicate last line" : function() {
var session = new EditSession(["1", "2", "3"]);
session.duplicateLines(2, 2);
assert.equal(session.getValue(), ["1", "2", "3", "3"].join("\n"));
},
"test: duplicate first line" : function() {
var session = new EditSession(["1", "2", "3"]);
session.duplicateLines(0, 0);
assert.equal(session.getValue(), ["1", "1", "2", "3"].join("\n"));
},
"test: getScreenLastRowColumn": function() {
var session = new EditSession([
"juhu",
"12\t\t34",
"ぁぁa"
]);
assert.equal(session.getScreenLastRowColumn(0), 4);
assert.equal(session.getScreenLastRowColumn(1), 10);
assert.equal(session.getScreenLastRowColumn(2), 5);
},
"test: convert document to screen coordinates" : function() {
var session = new EditSession("01234\t567890\t1234");
session.setTabSize(4);
assert.equal(session.documentToScreenColumn(0, 0), 0);
assert.equal(session.documentToScreenColumn(0, 4), 4);
assert.equal(session.documentToScreenColumn(0, 5), 5);
assert.equal(session.documentToScreenColumn(0, 6), 8);
assert.equal(session.documentToScreenColumn(0, 12), 14);
assert.equal(session.documentToScreenColumn(0, 13), 16);
session.setTabSize(2);
assert.equal(session.documentToScreenColumn(0, 0), 0);
assert.equal(session.documentToScreenColumn(0, 4), 4);
assert.equal(session.documentToScreenColumn(0, 5), 5);
assert.equal(session.documentToScreenColumn(0, 6), 6);
assert.equal(session.documentToScreenColumn(0, 7), 7);
assert.equal(session.documentToScreenColumn(0, 12), 12);
assert.equal(session.documentToScreenColumn(0, 13), 14);
},
"test: convert document to screen coordinates with leading tabs": function() {
var session = new EditSession("\t\t123");
session.setTabSize(4);
assert.equal(session.documentToScreenColumn(0, 0), 0);
assert.equal(session.documentToScreenColumn(0, 1), 4);
assert.equal(session.documentToScreenColumn(0, 2), 8);
assert.equal(session.documentToScreenColumn(0, 3), 9);
},
"test: documentToScreen without soft wrap": function() {
var session = new EditSession([
"juhu",
"12\t\t34",
"ぁぁa"
]);
assert.position(session.documentToScreenPosition(0, 3), 0, 3);
assert.position(session.documentToScreenPosition(1, 3), 1, 4);
assert.position(session.documentToScreenPosition(1, 4), 1, 8);
assert.position(session.documentToScreenPosition(2, 2), 2, 4);
},
"test: documentToScreen with soft wrap": function() {
var session = new EditSession(["foo bar foo bar"]);
session.setUseWrapMode(true);
session.setWrapLimitRange(12, 12);
session.adjustWrapLimit(80);
assert.position(session.documentToScreenPosition(0, 11), 0, 11);
assert.position(session.documentToScreenPosition(0, 12), 1, 0);
},
"test: documentToScreen with soft wrap and multibyte characters": function() {
var session = new EditSession(["ぁぁa"]);
session.setUseWrapMode(true);
session.setWrapLimitRange(2, 2);
session.adjustWrapLimit(80);
assert.position(session.documentToScreenPosition(0, 1), 1, 0);
assert.position(session.documentToScreenPosition(0, 2), 2, 0);
assert.position(session.documentToScreenPosition(0, 4), 2, 1);
},
"test: documentToScreen should clip position to the document boundaries": function() {
var session = new EditSession("foo bar\njuhu kinners");
assert.position(session.documentToScreenPosition(-1, 4), 0, 0);
assert.position(session.documentToScreenPosition(3, 0), 1, 12);
},
"test: convert screen to document coordinates" : function() {
var session = new EditSession("01234\t567890\t1234");
session.setTabSize(4);
assert.equal(session.screenToDocumentColumn(0, 0), 0);
assert.equal(session.screenToDocumentColumn(0, 4), 4);
assert.equal(session.screenToDocumentColumn(0, 5), 5);
assert.equal(session.screenToDocumentColumn(0, 6), 5);
assert.equal(session.screenToDocumentColumn(0, 7), 5);
assert.equal(session.screenToDocumentColumn(0, 8), 6);
assert.equal(session.screenToDocumentColumn(0, 9), 7);
assert.equal(session.screenToDocumentColumn(0, 15), 12);
assert.equal(session.screenToDocumentColumn(0, 19), 16);
session.setTabSize(2);
assert.equal(session.screenToDocumentColumn(0, 0), 0);
assert.equal(session.screenToDocumentColumn(0, 4), 4);
assert.equal(session.screenToDocumentColumn(0, 5), 5);
assert.equal(session.screenToDocumentColumn(0, 6), 6);
assert.equal(session.screenToDocumentColumn(0, 12), 12);
assert.equal(session.screenToDocumentColumn(0, 13), 12);
assert.equal(session.screenToDocumentColumn(0, 14), 13);
},
"test: screenToDocument with soft wrap": function() {
var session = new EditSession(["foo bar foo bar"]);
session.setUseWrapMode(true);
session.setWrapLimitRange(12, 12);
session.adjustWrapLimit(80);
assert.position(session.screenToDocumentPosition(1, 0), 0, 12);
assert.position(session.screenToDocumentPosition(0, 11), 0, 11);
// Check if the position is clamped the right way.
assert.position(session.screenToDocumentPosition(0, 12), 0, 11);
assert.position(session.screenToDocumentPosition(0, 20), 0, 11);
},
"test: screenToDocument with soft wrap and multi byte characters": function() {
var session = new EditSession(["ぁ a"]);
session.setUseWrapMode(true);
session.adjustWrapLimit(80);
assert.position(session.screenToDocumentPosition(0, 1), 0, 0);
assert.position(session.screenToDocumentPosition(0, 2), 0, 1);
assert.position(session.screenToDocumentPosition(0, 3), 0, 2);
assert.position(session.screenToDocumentPosition(0, 4), 0, 3);
assert.position(session.screenToDocumentPosition(0, 5), 0, 3);
},
"test: screenToDocument should clip position to the document boundaries": function() {
var session = new EditSession("foo bar\njuhu kinners");
assert.position(session.screenToDocumentPosition(-1, 4), 0, 0);
assert.position(session.screenToDocumentPosition(0, -1), 0, 0);
assert.position(session.screenToDocumentPosition(0, 30), 0, 7);
assert.position(session.screenToDocumentPosition(2, 4), 1, 12);
assert.position(session.screenToDocumentPosition(1, 30), 1, 12);
assert.position(session.screenToDocumentPosition(20, 50), 1, 12);
assert.position(session.screenToDocumentPosition(20, 5), 1, 12);
// and the same for folded rows
session.addFold("...", new Range(0,1,1,3));
assert.position(session.screenToDocumentPosition(1, 2), 1, 12);
// for wrapped rows
session.setUseWrapMode(true);
session.setWrapLimitRange(5,5);
assert.position(session.screenToDocumentPosition(4, 1), 1, 12);
},
"test: wrapLine split function" : function() {
function computeAndAssert(line, assertEqual, wrapLimit, tabSize) {
wrapLimit = wrapLimit || 12;
tabSize = tabSize || 4;
line = lang.stringTrimRight(line);
var tokens = EditSession.prototype.$getDisplayTokens(line);
var splits = EditSession.prototype.$computeWrapSplits(tokens, wrapLimit, tabSize);
// console.log("String:", line, "Result:", splits, "Expected:", assertEqual);
assert.ok(splits.length == assertEqual.length);
for (var i = 0; i < splits.length; i++) {
assert.ok(splits[i] == assertEqual[i]);
}
}
// Basic splitting.
computeAndAssert("foo bar foo bar", [ 12 ]);
computeAndAssert("foo bar f bar", [ 12 ]);
computeAndAssert("foo bar f r", [ 14 ]);
computeAndAssert("foo bar foo bar foo bara foo", [12, 25]);
// Don't split if there is only whitespaces/tabs at the end of the line.
computeAndAssert("foo foo foo \t \t", [ ]);
// If there is no space to split, force split.
computeAndAssert("foooooooooooooo", [ 12 ]);
computeAndAssert("fooooooooooooooooooooooooooo", [12, 24]);
computeAndAssert("foo bar fooooooooooobooooooo", [8, 20]);
// Basic splitting + tabs.
computeAndAssert("foo \t\tbar", [ 6 ]);
computeAndAssert("foo \t \tbar", [ 7 ]);
// Ignore spaces/tabs at beginning of split.
computeAndAssert("foo \t \t \t \t bar", [ 14 ]);
// Test wrapping for asian characters.
computeAndAssert("ぁぁ", [1], 2);
computeAndAssert(" ぁぁ", [1, 2], 2);
computeAndAssert(" ぁ\tぁ", [1, 3], 2);
computeAndAssert(" ぁぁ\tぁ", [1, 4], 4);
// Test wrapping for punctuation.
computeAndAssert(" ab.c;ef++", [1, 3, 5, 7, 8], 2);
computeAndAssert(" a.b", [1, 2, 3], 1);
computeAndAssert("#>>", [1, 2], 1);
},
"test get longest line" : function() {
var session = new EditSession(["12"]);
session.setTabSize(4);
assert.equal(session.getScreenWidth(), 2);
session.doc.insertNewLine({row: 0, column: Infinity});
session.doc.insertLines(1, ["123"]);
assert.equal(session.getScreenWidth(), 3);
session.doc.insertNewLine({row: 0, column: Infinity});
session.doc.insertLines(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.insertLines(0, ["a", "b"]);
document.insertLines(2, ["c", "d"]);
document.removeLines(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; i<items.length; i++) {",
// " alert(items[i] + \"juhu\");",
// " } // Real Tab.",
// "}"
assertIdx2Pos(0, 12, 0, 12);
assertIdx2Pos(0, 13, 0, 13);
assertIdx2Pos(0, 14, 0, 13);
assertIdx2Pos(0, 19, 0, 13);
assertIdx2Pos(0, 20, 0, 18);
assertIdx2Pos(1, 10, 1, 10);
assertIdx2Pos(1, 11, 1, 10);
assertIdx2Pos(1, 15, 1, 10);
assertIdx2Pos(1, 16, 2, 10);
assertIdx2Pos(1, 26, 2, 20);
assertIdx2Pos(1, 27, 2, 20);
assertIdx2Pos(1, 32, 2, 25);
},
"test fold documentToScreen": function() {
var session = createFoldTestSession();
function assertDoc2Screen(docRow, docCol, screenRow, screenCol) {
assert.position(
session.documentToScreenPosition(docRow, docCol),
screenRow, screenCol
);
}
// One fold ending in the same row.
assertDoc2Screen(0, 0, 0, 0);
assertDoc2Screen(0, 13, 0, 13);
assertDoc2Screen(0, 14, 0, 13);
assertDoc2Screen(0, 17, 0, 13);
assertDoc2Screen(0, 18, 0, 20);
// Fold ending on some other row.
assertDoc2Screen(1, 0, 1, 0);
assertDoc2Screen(1, 10, 1, 10);
assertDoc2Screen(1, 11, 1, 10);
assertDoc2Screen(1, 99, 1, 10);
assertDoc2Screen(2, 0, 1, 10);
assertDoc2Screen(2, 9, 1, 10);
assertDoc2Screen(2, 10, 1, 16);
assertDoc2Screen(2, 11, 1, 17);
// Fold in the same row with fold over more then one row in the same row.
assertDoc2Screen(2, 19, 1, 25);
assertDoc2Screen(2, 20, 1, 26);
assertDoc2Screen(2, 21, 1, 26);
assertDoc2Screen(2, 24, 1, 26);
assertDoc2Screen(2, 25, 1, 32);
assertDoc2Screen(2, 26, 1, 33);
assertDoc2Screen(2, 99, 1, 40);
// Test one position after the folds. Should be all like normal.
assertDoc2Screen(3, 0, 2, 0);
},
"test fold screenToDocument": function() {
var session = createFoldTestSession();
function assertScreen2Doc(docRow, docCol, screenRow, screenCol) {
assert.position(
session.screenToDocumentPosition(screenRow, screenCol),
docRow, docCol
);
}
// One fold ending in the same row.
assertScreen2Doc(0, 0, 0, 0);
assertScreen2Doc(0, 13, 0, 13);
assertScreen2Doc(0, 13, 0, 14);
assertScreen2Doc(0, 18, 0, 20);
assertScreen2Doc(0, 19, 0, 21);
// Fold ending on some other row.
assertScreen2Doc(1, 0, 1, 0);
assertScreen2Doc(1, 10, 1, 10);
assertScreen2Doc(1, 10, 1, 11);
assertScreen2Doc(1, 10, 1, 15);
assertScreen2Doc(2, 10, 1, 16);
assertScreen2Doc(2, 11, 1, 17);
// Fold in the same row with fold over more then one row in the same row.
assertScreen2Doc(2, 19, 1, 25);
assertScreen2Doc(2, 20, 1, 26);
assertScreen2Doc(2, 20, 1, 27);
assertScreen2Doc(2, 20, 1, 31);
assertScreen2Doc(2, 25, 1, 32);
assertScreen2Doc(2, 26, 1, 33);
assertScreen2Doc(2, 33, 1, 99);
// Test one position after the folds. Should be all like normal.
assertScreen2Doc(3, 0, 2, 0);
},
"test getFoldsInRange()": function() {
var session = createFoldTestSession();
var foldLines = session.$foldData;
var folds = foldLines[0].folds.concat(foldLines[1].folds);
function test(startRow, startColumn, endColumn, endRow, folds) {
var r = new Range(startRow, startColumn, endColumn, endRow);
var retFolds = session.getFoldsInRange(r);
assert.ok(retFolds.length == folds.length);
for (var i = 0; i < retFolds.length; i++) {
assert.equal(retFolds[i].range + "", folds[i].range + "");
}
}
test(0, 0, 0, 13, [ ]);
test(0, 0, 0, 14, [ folds[0] ]);
test(0, 0, 0, 18, [ folds[0] ]);
test(0, 0, 1, 10, [ folds[0] ]);
test(0, 0, 1, 11, [ folds[0], folds[1] ]);
test(0, 18, 1, 11, [ folds[1] ]);
test(2, 0, 2, 13, [ folds[1] ]);
test(2, 10, 2, 20, [ ]);
test(2, 10, 2, 11, [ ]);
test(2, 19, 2, 20, [ ]);
},
"test fold one-line text insert": function() {
// These are mostly test for the FoldLine.addRemoveChars function.
var session = createFoldTestSession();
var undoManager = session.getUndoManager();
var foldLines = session.$foldData;
function insert(row, column, text) {
session.insert({row: row, column: column}, text);
// Force the session to store all changes made to the document NOW
// on the undoManager's queue. Otherwise we can't undo in separate
// steps later.
session.$syncInformUndoManager();
}
var foldLine, fold, folds;
// First line.
foldLine = session.$foldData[0];
fold = foldLine.folds[0];
insert(0, 0, "0");
assert.range(foldLine.range, 0, 14, 0, 19);
assert.range(fold.range, 0, 14, 0, 19);
insert(0, 14, "1");
assert.range(foldLine.range, 0, 15, 0, 20);
assert.range(fold.range, 0, 15, 0, 20);
insert(0, 20, "2");
assert.range(foldLine.range, 0, 15, 0, 20);
assert.range(fold.range, 0, 15, 0, 20);
// Second line.
foldLine = session.$foldData[1];
folds = foldLine.folds;
insert(1, 0, "3");
assert.range(foldLine.range, 1, 11, 2, 25);
assert.range(folds[0].range, 1, 11, 2, 10);
assert.range(folds[1].range, 2, 20, 2, 25);
insert(1, 11, "4");
assert.range(foldLine.range, 1, 12, 2, 25);
assert.range(folds[0].range, 1, 12, 2, 10);
assert.range(folds[1].range, 2, 20, 2, 25);
insert(2, 10, "5");
assert.range(foldLine.range, 1, 12, 2, 26);
assert.range(folds[0].range, 1, 12, 2, 10);
assert.range(folds[1].range, 2, 21, 2, 26);
insert(2, 21, "6");
assert.range(foldLine.range, 1, 12, 2, 27);
assert.range(folds[0].range, 1, 12, 2, 10);
assert.range(folds[1].range, 2, 22, 2, 27);
insert(2, 27, "7");
assert.range(foldLine.range, 1, 12, 2, 27);
assert.range(folds[0].range, 1, 12, 2, 10);
assert.range(folds[1].range, 2, 22, 2, 27);
// UNDO = REMOVE
undoManager.undo(); // 6
assert.range(foldLine.range, 1, 12, 2, 27);
assert.range(folds[0].range, 1, 12, 2, 10);
assert.range(folds[1].range, 2, 22, 2, 27);
undoManager.undo(); // 5
assert.range(foldLine.range, 1, 12, 2, 26);
assert.range(folds[0].range, 1, 12, 2, 10);
assert.range(folds[1].range, 2, 21, 2, 26);
undoManager.undo(); // 4
assert.range(foldLine.range, 1, 12, 2, 25);
assert.range(folds[0].range, 1, 12, 2, 10);
assert.range(folds[1].range, 2, 20, 2, 25);
undoManager.undo(); // 3
assert.range(foldLine.range, 1, 11, 2, 25);
assert.range(folds[0].range, 1, 11, 2, 10);
assert.range(folds[1].range, 2, 20, 2, 25);
undoManager.undo(); // Beginning first line.
assert.equal(foldLines.length, 2);
assert.range(foldLines[0].range, 0, 15, 0, 20);
assert.range(foldLines[1].range, 1, 10, 2, 25);
foldLine = session.$foldData[0];
fold = foldLine.folds[0];
undoManager.undo(); // 2
assert.range(foldLine.range, 0, 15, 0, 20);
assert.range(fold.range, 0, 15, 0, 20);
undoManager.undo(); // 1
assert.range(foldLine.range, 0, 14, 0, 19);
assert.range(fold.range, 0, 14, 0, 19);
undoManager.undo(); // 0
assert.range(foldLine.range, 0, 13, 0, 18);
assert.range(fold.range, 0, 13, 0, 18);
},
"test fold multi-line insert/remove": function() {
var session = createFoldTestSession(),
undoManager = session.getUndoManager(),
foldLines = session.$foldData;
function insert(row, column, text) {
session.insert({row: row, column: column}, text);
// Force the session to store all changes made to the document NOW
// on the undoManager's queue. Otherwise we can't undo in separate
// steps later.
session.$syncInformUndoManager();
}
var foldLines = session.$foldData, foldLine, fold, folds;
insert(0, 0, "\nfo0");
assert.equal(foldLines.length, 2);
assert.range(foldLines[0].range, 1, 16, 1, 21);
assert.range(foldLines[1].range, 2, 10, 3, 25);
insert(2, 0, "\nba1");
assert.equal(foldLines.length, 2);
assert.range(foldLines[0].range, 1, 16, 1, 21);
assert.range(foldLines[1].range, 3, 13, 4, 25);
insert(3, 10, "\nfo2");
assert.equal(foldLines.length, 2);
assert.range(foldLines[0].range, 1, 16, 1, 21);
assert.range(foldLines[1].range, 4, 6, 5, 25);
insert(5, 10, "\nba3");
assert.equal(foldLines.length, 3);
assert.range(foldLines[0].range, 1, 16, 1, 21);
assert.range(foldLines[1].range, 4, 6, 5, 10);
assert.range(foldLines[2].range, 6, 13, 6, 18);
insert(6, 18, "\nfo4");
assert.equal(foldLines.length, 3);
assert.range(foldLines[0].range, 1, 16, 1, 21);
assert.range(foldLines[1].range, 4, 6, 5, 10);
assert.range(foldLines[2].range, 6, 13, 6, 18);
undoManager.undo(); // 3
assert.equal(foldLines.length, 3);
assert.range(foldLines[0].range, 1, 16, 1, 21);
assert.range(foldLines[1].range, 4, 6, 5, 10);
assert.range(foldLines[2].range, 6, 13, 6, 18);
undoManager.undo(); // 2
assert.equal(foldLines.length, 2);
assert.range(foldLines[0].range, 1, 16, 1, 21);
assert.range(foldLines[1].range, 4, 6, 5, 25);
undoManager.undo(); // 1
assert.equal(foldLines.length, 2);
assert.range(foldLines[0].range, 1, 16, 1, 21);
assert.range(foldLines[1].range, 3, 13, 4, 25);
undoManager.undo(); // 0
assert.equal(foldLines.length, 2);
assert.range(foldLines[0].range, 1, 16, 1, 21);
assert.range(foldLines[1].range, 2, 10, 3, 25);
undoManager.undo(); // Beginning
assert.equal(foldLines.length, 2);
assert.range(foldLines[0].range, 0, 13, 0, 18);
assert.range(foldLines[1].range, 1, 10, 2, 25);
// TODO: Add test for inseration inside of folds.
},
"test fold wrap data compution": function() {
function assertArray(a, b) {
assert.ok(a.length == b.length);
for (var i = 0; i < a.length; i++) {
assert.equal(a[i], b[i]);
}
}
function assertWrap(line0, line1, line2) {
line0 && assertArray(wrapData[0], line0);
line1 && assertArray(wrapData[1], line1);
line2 && assertArray(wrapData[2], line2);
}
function removeFoldAssertWrap(docRow, docColumn, line0, line1, line2) {
session.removeFold(session.getFoldAt(docRow, docColumn));
assertWrap(line0, line1, line2);
}
var lines = [
"foo bar foo bar",
"foo bar foo bar",
"foo bar foo bar"
];
var session = new EditSession(lines.join("\n"));
session.setUseWrapMode(true);
session.$wrapLimit = 7;
session.$updateWrapData(0, 2);
var wrapData = session.$wrapData;
// Do a simple assertion without folds to check basic functionallity.
assertWrap([8], [8], [8]);
// --- Do in line folding ---
// Adding a fold. The split position is inside of the fold. As placeholder
// are not splitable, the split should be before the split.
session.addFold("woot", new Range(0, 4, 0, 15));
assertWrap([4], [8], [8]);
// Remove the fold again which should reset the wrapData.
removeFoldAssertWrap(0, 4, [8], [8], [8]);
session.addFold("woot", new Range(0, 6, 0, 9));
assertWrap([6, 13], [8], [8]);
removeFoldAssertWrap(0, 6, [8], [8], [8]);
// The fold fits into the wrap limit - no split expected.
session.addFold("woot", new Range(0, 3, 0, 15));
assertWrap([], [8], [8]);
removeFoldAssertWrap(0, 4, [8], [8], [8]);
// Fold after split position should be all fine.
session.addFold("woot", new Range(0, 8, 0, 15));
assertWrap([8], [8], [8]);
removeFoldAssertWrap(0, 8, [8], [8], [8]);
// Fold's placeholder is far too long for wrapSplit.
session.addFold("woot0123456789", new Range(0, 8, 0, 15));
assertWrap([8], [8], [8]);
removeFoldAssertWrap(0, 8, [8], [8], [8]);
// Fold's placeholder is far too long for wrapSplit
// + content at the end of the line
session.addFold("woot0123456789", new Range(0, 6, 0, 8));
assertWrap([6, 20], [8], [8]);
removeFoldAssertWrap(0, 8, [8], [8], [8]);
session.addFold("woot0123456789", new Range(0, 6, 0, 8));
session.addFold("woot0123456789", new Range(0, 8, 0, 10));
assertWrap([6, 20, 34], [8], [8]);
session.removeFold(session.getFoldAt(0, 7));
removeFoldAssertWrap(0, 8, [8], [8], [8]);
session.addFold("woot0123456789", new Range(0, 7, 0, 9));
session.addFold("woot0123456789", new Range(0, 13, 0, 15));
assertWrap([7, 21, 25], [8], [8]);
session.removeFold(session.getFoldAt(0, 7));
removeFoldAssertWrap(0, 14, [8], [8], [8]);
// --- Do some multiline folding ---
// Add a fold over two lines. Note, that the wrapData[1] stays the
// same. This is an implementation detail and expected behavior.
session.addFold("woot", new Range(0, 8, 1, 15));
assertWrap([8], [8 /* See comments */], [8]);
removeFoldAssertWrap(0, 8, [8], [8], [8]);
session.addFold("woot", new Range(0, 9, 1, 11));
assertWrap([8, 14], [8 /* See comments */], [8]);
removeFoldAssertWrap(0, 9, [8], [8], [8]);
session.addFold("woot", new Range(0, 9, 1, 15));
assertWrap([8], [8 /* See comments */], [8]);
removeFoldAssertWrap(0, 9, [8], [8], [8]);
return session;
},
"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 "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), true);
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);
}
};
});
if (typeof module !== "undefined" && module === require.main) {
require("asyncjs").test.testcase(module.exports).exec()
}
File diff suppressed because it is too large Load Diff
@@ -1,195 +0,0 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** 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}, "<html></html>");
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()
}
@@ -1,231 +0,0 @@
/* vim:ts=4:sts=4:sw=4:
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Mihai Sucan.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mihai Sucan <mihai.sucan@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** 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();
}
@@ -1,171 +0,0 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** 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()
}
@@ -1,562 +0,0 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** 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");
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);
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, 4);
assert.position(selection.end, 1, 4);
},
"test: uncomment lines should perserve selection" : function() {
var session = new EditSession(["// abc", "//cde"].join("\n"), new JavaScriptMode());
var editor = new Editor(new MockRenderer(), session);
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, 2, 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, 2, 1, 0);
},
"test: move lines down should select 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(), 1, 0);
assert.position(editor.getSelection().getSelectionAnchor(), 3, 0);
assert.position(editor.getSelection().getSelectionLead(), 1, 0);
editor.moveLinesDown();
assert.equal(["33", "44", "11", "22"].join("\n"), session.toString());
assert.position(editor.getCursorPosition(), 2, 0);
assert.position(editor.getSelection().getSelectionAnchor(), 3, 2);
assert.position(editor.getSelection().getSelectionLead(), 2, 0);
// moving again should have no effect
editor.moveLinesDown();
assert.equal(["33", "44", "11", "22"].join("\n"), session.toString());
assert.position(editor.getCursorPosition(), 2, 0);
assert.position(editor.getSelection().getSelectionAnchor(), 3, 2);
assert.position(editor.getSelection().getSelectionLead(), 2, 0);
},
"test: move lines up should select 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(), 1, 0);
assert.position(editor.getSelection().getSelectionAnchor(), 3, 0);
assert.position(editor.getSelection().getSelectionLead(), 1, 0);
editor.moveLinesUp();
assert.equal(session.toString(), ["33", "44", "11", "22"].join("\n"));
assert.position(editor.getCursorPosition(), 0, 0);
assert.position(editor.getSelection().getSelectionAnchor(), 2, 0);
assert.position(editor.getSelection().getSelectionLead(), 0, 0);
},
"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 select lines and place cursor at the selection start" : 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(), 3, 0);
assert.position(editor.getSelection().getSelectionAnchor(), 5, 0);
assert.position(editor.getSelection().getSelectionLead(), 3, 0);
},
"test: copy lines up should select lines and place cursor at the selection start" : 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(), 1, 0);
assert.position(editor.getSelection().getSelectionAnchor(), 3, 0);
assert.position(editor.getSelection().getSelectionLead(), 1, 0);
},
"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()
}
@@ -1,22 +0,0 @@
.ace_editor {
font-family: 'Monaco', 'Menlo', 'Droid Sans Mono', 'Courier New', monospace;
font-size: 12px;
}
.ace_editor .ace_gutter {
width: 25px !important;
display: block;
float: left;
text-align: right;
padding: 0 3px 0 0;
margin-right: 3px;
}
.ace_line { clear: both; }
*.ace_gutter-cell {
-moz-user-select: -moz-none;
-khtml-user-select: none;
-webkit-user-select: none;
user-select: none;
}
@@ -1,98 +0,0 @@
/* vim:ts=4:sts=4:sw=4:
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Jan Jongboom <fabian AT ajax DOT org>
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** 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");
/* 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
*/
exports.render = function(input, mode, theme, lineStart, disableGutter) {
lineStart = parseInt(lineStart || 1, 10);
var session = new EditSession("");
session.setMode(mode);
session.setUseWorker(false);
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++) {
var lineTokens = session.getTokens(ix);
stringBuilder.push("<div class='ace_line'>");
if (!disableGutter)
stringBuilder.push("<span class='ace_gutter ace_gutter-cell' unselectable='on'>" + (ix + lineStart) + "</span>");
textLayer.$renderLine(stringBuilder, 0, lineTokens, true);
stringBuilder.push("</div>");
}
// let's prepare the whole html
var html = "<div class=':cssClass'>\
<div class='ace_editor ace_scroller ace_text-layer'>\
:code\
</div>\
</div>".replace(/:cssClass/, theme.cssClass).replace(/:code/, stringBuilder.join(""));
textLayer.destroy();
return {
css: baseStyles + theme.cssText,
html: html
};
};
});
@@ -1,81 +0,0 @@
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;
// 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\n\
*\n\
*/\n\
function hello (a, b, c) {\n\
console.log(a * b + c + 'sup?');\n\
}";
var mode = new JavaScriptMode();
var isError = false, result;
try {
result = highlighter.render(snippet, mode, theme);
}
catch (e) {
console.log(e);
isError = true;
}
// todo: write something more meaningful
assert.equal(isError, false);
next();
},
"test css from theme is used": function(next) {
var theme = require("../theme/tomorrow");
var snippet = "/** this is a function\n\
*\n\
*/\n\
function hello (a, b, c) {\n\
console.log(a * b + c + 'sup?');\n\
}";
var mode = new JavaScriptMode();
var isError = false, result;
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\n\
*\n\
*/\n\
function hello (a, b, c) {\n\
console.log(a * b + c + 'sup?');\n\
}";
var mode = new JavaScriptMode();
var isError = false, result;
result = highlighter.render(snippet, mode, theme);
assert.equal(!!result.html.match(/<div class='ace-tomorrow'>/), true);
next();
}
};
});
if (typeof module !== "undefined" && module === require.main) {
require("asyncjs").test.testcase(module.exports).exec();
}
@@ -1,536 +0,0 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Skywriter.
*
* The Initial Developer of the Original Code is
* Mozilla.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Kevin Dangoor (kdangoor@mozilla.com)
* Julian Viereck <julian.viereck@gmail.com>
* Harutyun Amirjanyan [harutyun@c9.io]
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** 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("ace/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 "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<percent>')
// 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<percent>).
// Making the sum of pixel vaules (e.g. padding) and realtive values
// (e.g. <percent>) 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.
if (element.nextSibling) {
parentNode.insertBefore(container, element.nextSibling);
} else {
parentNode.appendChild(container);
}
// 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.innerHTML = getValue();
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, loader) {
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"
});
container.appendChild(editorDiv);
var settingOpener = document.createElement("div");
applyStyles(settingOpener, {
position: "absolute",
width: "15px",
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: "0px",
right: "0px",
bottom: "0px",
position: "absolute",
padding: "5px",
zIndex: 100,
color: "white",
display: "none",
overflow: "auto",
fontSize: "14px"
};
if (!UA.isOldIE) {
settingDivStyles.backgroundColor = "rgba(0, 0, 0, 0.6)";
} else {
settingDivStyles.backgroundColor = "#333";
}
applyStyles(settingDiv, settingDivStyles);
container.appendChild(settingDiv);
// Power up ace on the textarea:
var options = {};
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.
editorDiv.appendChild(settingOpener);
// Create the API.
setupApi(editor, editorDiv, settingDiv, ace, options, loader);
// Create the setting's panel.
setupSettingPanel(settingDiv, settingOpener, editor, options);
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";
}
editor.setDisplaySettings = function(display) {
if (display == null)
display = settingDiv.style.display == "none";
settingDiv.style.display = display ? "block" : "none";
};
editor.setOption = function(key, value) {
if (options[key] == value) return;
switch (key) {
case "gutter":
renderer.setShowGutter(toBool(value));
break;
case "mode":
if (value != "text") {
// Load the required mode file. Files get loaded only once.
loader("mode-" + value + ".js", "ace/mode/" + value, function() {
var aceMode = require("../mode/" + value).Mode;
session.setMode(new aceMode());
});
} else {
session.setMode(new (require("../mode/text").Mode));
}
break;
case "theme":
if (value != "textmate") {
// Load the required theme file. Files get loaded only once.
loader("theme-" + value + ".js", "ace/theme/" + value, function() {
editor.setTheme("ace/theme/" + value);
});
} else {
editor.setTheme("ace/theme/textmate");
}
break;
case "fontSize":
editorDiv.style.fontSize = value;
break;
case "softWrap":
switch (value) {
case "off":
session.setUseWrapMode(false);
renderer.setPrintMarginColumn(80);
break;
case "40":
session.setUseWrapMode(true);
session.setWrapLimitRange(40, 40);
renderer.setPrintMarginColumn(40);
break;
case "80":
session.setUseWrapMode(true);
session.setWrapLimitRange(80, 80);
renderer.setPrintMarginColumn(80);
break;
case "free":
session.setUseWrapMode(true);
session.setWrapLimitRange(null, null);
renderer.setPrintMarginColumn(80);
break;
}
break;
case "useSoftTabs":
session.setUseSoftTabs(toBool(value));
break;
case "showPrintMargin":
renderer.setShowPrintMargin(toBool(value));
break;
case "showInvisibles":
editor.setShowInvisibles(toBool(value));
break;
}
options[key] = value;
};
editor.getOption = function(key) {
return options[key];
};
editor.getOptions = function() {
return options;
};
for (var option in exports.options) {
editor.setOption(option, exports.options[option]);
}
return editor;
}
function setupSettingPanel(settingDiv, settingOpener, editor, options) {
var BOOL = {
"true": true,
"false": false
};
var desc = {
mode: "Mode:",
gutter: "Display Gutter:",
theme: "Theme:",
fontSize: "Font Size:",
softWrap: "Soft Wrap:",
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"
},
gutter: BOOL,
fontSize: {
"10px": "10px",
"11px": "11px",
"12px": "12px",
"14px": "14px",
"16px": "16px"
},
softWrap: {
off: "Off",
40: "40",
80: "80",
free: "Free"
},
showPrintMargin: BOOL,
useSoftTabs: BOOL,
showInvisibles: BOOL
};
var table = [];
table.push("<table><tr><th>Setting</th><th>Value</th></tr>");
function renderOption(builder, option, obj, cValue) {
builder.push("<select title='" + option + "'>");
for (var value in obj) {
builder.push("<option value='" + value + "' ");
if (cValue == value) {
builder.push(" selected ");
}
builder.push(">",
obj[value],
"</option>");
}
builder.push("</select>");
}
for (var option in options) {
table.push("<tr><td>", desc[option], "</td>");
table.push("<td>");
renderOption(table, option, optionValues[option], options[option]);
table.push("</td></tr>");
}
table.push("</table>");
settingDiv.innerHTML = table.join("");
var selects = settingDiv.getElementsByTagName("select");
for (var i = 0; i < selects.length; i++) {
var onChange = (function() {
var select = selects[i];
return function() {
var option = select.title;
var value = select.value;
editor.setOption(option, value);
};
})();
selects[i].onchange = onChange;
}
var button = document.createElement("input");
button.type = "button";
button.value = "Hide";
event.addListener(button, "click", function() {
editor.setDisplaySettings(false);
});
settingDiv.appendChild(button);
}
// Default startup options.
exports.options = {
mode: "text",
theme: "textmate",
gutter: "false",
fontSize: "12px",
softWrap: "off",
showPrintMargin: "false",
useSoftTabs: "true",
showInvisibles: "true"
};
});
@@ -1,367 +0,0 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Skywriter.
*
* The Initial Developer of the Original Code is
* Mozilla.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Julian Viereck (julian.viereck@gmail.com)
* Harutyun Amirjanyan (harutyun@c9.io)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
"use strict";
var dom = require("../lib/dom");
var screenToTextBlockCoordinates = function(pageX, pageY) {
var canvasPos = this.scroller.getBoundingClientRect();
var col = Math.floor(
(pageX + this.scrollLeft - canvasPos.left - this.$padding - dom.getPageScrollLeft()) / this.characterWidth
);
var row = Math.floor(
(pageY + this.scrollTop - canvasPos.top - dom.getPageScrollTop()) / this.lineHeight
);
return this.session.screenToDocumentPosition(row, col);
};
var HashHandler = require("./hash_handler").HashHandler;
exports.handler = new HashHandler();
var initialized = false;
exports.handler.attach = function(editor) {
if (!initialized) {
initialized = true;
dom.importCssString('\
.emacs-mode .ace_cursor{\
border: 2px rgba(50,250,50,0.8) solid!important;\
-moz-box-sizing: border-box!important;\
box-sizing: border-box!important;\
background-color: rgba(0,250,0,0.9);\
opacity: 0.5;\
}\
.emacs-mode .ace_cursor.ace_hidden{\
opacity: 1;\
background-color: transparent;\
}\
.emacs-mode .ace_cursor.ace_overwrite {\
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'
);
}
editor.renderer.screenToTextCoordinates = screenToTextBlockCoordinates;
editor.setStyle("emacs-mode");
};
exports.handler.detach = function(editor) {
delete editor.renderer.screenToTextCoordinates;
editor.unsetStyle("emacs-mode");
};
var keys = require("../lib/keys").KEY_MODS;
var eMods = {
C: "ctrl", S: "shift", M: "alt"
};
["S-C-M", "S-C", "S-M", "C-M", "S", "C", "M"].forEach(function(c) {
var hashId = 0;
c.split("-").forEach(function(c){
hashId = hashId | keys[eMods[c]];
});
eMods[hashId] = c.toLowerCase() + "-";
});
exports.handler.bindKey = function(key, command) {
if (!key)
return;
var ckb = this.commmandKeyBinding;
key.split("|").forEach(function(keyPart) {
keyPart = keyPart.toLowerCase();
ckb[keyPart] = command;
keyPart = keyPart.split(" ")[0];
if (!ckb[keyPart])
ckb[keyPart] = "null";
}, this);
};
exports.handler.handleKeyboard = function(data, hashId, key, keyCode) {
if (hashId == -1) {
if (data.count) {
var str = Array(data.count + 1).join(key);
data.count = null;
return {command: "insertstring", args: str};
}
}
if (key == "\x00")
return;
var modifier = eMods[hashId];
if (modifier == "c-" || data.universalArgument) {
var count = parseInt(key[key.length - 1]);
if (count) {
data.count = count;
return {command: "null"};
}
}
data.universalArgument = false;
if (modifier)
key = modifier + key;
if (data.keyChain)
key = data.keyChain += " " + key;
var command = this.commmandKeyBinding[key];
data.keyChain = command == "null" ? key : "";
if (!command)
return;
if (command == "null")
return {command: "null"};
if (command == "universalArgument") {
data.universalArgument = true;
return {command: "null"};
}
if (typeof command != "string") {
var args = command.args;
command = command.command;
}
if (typeof command == "string") {
command = this.commands[command] || data.editor.commands.commands[command];
}
if (!command.readonly && !command.isYank)
data.lastCommand = null;
if (data.count) {
var count = data.count;
data.count = 0;
return {
args: args,
command: {
exec: function(editor, args) {
for (var i = 0; i < count; i++)
command.exec(editor, args);
}
}
};
}
return {command: command, args: args};
};
exports.emacsKeys = {
// movement
"Up|C-p" : "golineup",
"Down|C-n" : "golinedown",
"Left|C-b" : "gotoleft",
"Right|C-f" : "gotoright",
"C-Left|M-b" : "gotowordleft",
"C-Right|M-f" : "gotowordright",
"Home|C-a" : "gotolinestart",
"End|C-e" : "gotolineend",
"C-Home|S-M-,": "gotostart",
"C-End|S-M-." : "gotoend",
// 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|M-s" : "centerselection",
"M-g": "gotoline",
"C-x C-p": "selectall",
// todo fix these
"C-Down": "gotopagedown",
"C-Up": "gotopageup",
"PageDown|C-v": "gotopagedown",
"PageUp|M-v": "gotopageup",
"S-C-Down": "selectpagedown",
"S-C-Up": "selectpageup",
"C-s": "findnext",
"C-r": "findprevious",
"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": "killRegion",
"M-w": "killRingSave",
"C-Space": "setMark",
"C-x C-x": "exchangePointAndMark",
"C-t": "transposeletters",
"M-u": "touppercase",
"M-l": "tolowercase",
"M-/": "autocomplete",
"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"
// todo
// "M-x" "C-x C-t" "M-t" "M-c" "F11" "C-M- "M-q"
};
exports.handler.bindKeys(exports.emacsKeys);
exports.handler.addCommands({
selectRectangularRegion: function(editor) {
editor.multiSelect.toggleBlockSelection();
},
setMark: function() {
},
exchangePointAndMark: {
exec: function(editor) {
var range = editor.selection.getRange();
editor.selection.setSelectionRange(range, !editor.selection.isBackwards());
},
readonly: 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.selection.selectLine();
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.onPaste(exports.killRing.rotate());
editor.keyBinding.$data.lastCommand = "yank";
},
killRegion: function(editor) {
exports.killRing.add(editor.getCopyText());
editor.cut();
},
killRingSave: function(editor) {
exports.killRing.add(editor.getCopyText());
}
});
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() {
return this.$data[this.$data.length - 1] || "";
},
pop: function() {
if (this.$data.length > 1)
this.$data.pop();
return this.get();
},
rotate: function() {
this.$data.unshift(this.$data.pop());
return this.get();
}
};
});
@@ -1,170 +0,0 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Skywriter.
*
* The Initial Developer of the Original Code is
* Mozilla.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Julian Viereck (julian.viereck@gmail.com)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
"use strict";
var keyUtil = require("../lib/keys");
function HashHandler(config, platform) {
this.platform = platform;
this.commands = {};
this.commmandKeyBinding = {};
this.addCommands(config);
};
(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) {
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.commmandKeyBinding;
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: key});
return;
}
var ckb = this.commmandKeyBinding;
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 (typeof command === "string")
return this.bindKey(command, name);
if (typeof command === "function")
command = { exec: command };
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);
};
this.parseKeys = function(keys) {
var key;
var hashId = 0;
var parts = keys.toLowerCase().trim().split(/\s*\-\s*/);
for (var i = 0, l = parts.length; i < l; i++) {
if (keyUtil.KEY_MODS[parts[i]])
hashId = hashId | keyUtil.KEY_MODS[parts[i]];
else
key = parts[i] || "-"; //when empty, the splitSafe removed a '-'
}
if (parts[0] == "text" && parts.length == 2) {
hashId = -1;
key = parts[1];
}
return {
key: key,
hashId: hashId
};
};
this.findKeyCommand = function findKeyCommand(hashId, keyString) {
var ckbr = this.commmandKeyBinding;
return ckbr[hashId] && ckbr[hashId][keyString.toLowerCase()];
};
this.handleKeyboard = function(data, hashId, keyString, keyCode) {
return {
command: this.findKeyCommand(hashId, keyString)
};
};
}).call(HashHandler.prototype)
exports.HashHandler = HashHandler;
});
@@ -1,143 +0,0 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Julian Viereck <julian.viereck@gmail.com>
* Harutyun Amirjanyan <amirjanyan@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** 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 = { };
this.$handlers = [];
this.setDefaultHandler(editor.commands);
};
(function() {
this.setDefaultHandler = function(kb) {
this.removeKeyboardHandler(this.$defaultHandler);
this.$defaultHandler = kb;
this.addKeyboardHandler(kb, 0);
this.$data = {editor: this.$editor};
};
this.setKeyboardHandler = function(kb) {
if (this.$handlers[this.$handlers.length - 1] == kb)
return;
while (this.$handlers[1])
this.removeKeyboardHandler(this.$handlers[1]);
this.addKeyboardHandler(kb, 1);
};
this.addKeyboardHandler = function(kb, pos) {
if (!kb)
return;
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.$callKeyboardHandlers = function (hashId, keyString, keyCode, e) {
var toExecute;
for (var i = this.$handlers.length; i--;) {
toExecute = this.$handlers[i].handleKeyboard(
this.$data, hashId, keyString, keyCode, e
);
if (toExecute && toExecute.command)
break;
}
if (!toExecute || !toExecute.command)
return false;
var success = false;
var commands = this.$editor.commands;
// allow keyboardHandler to consume keys
if (toExecute.command != "null")
success = commands.exec(toExecute.command, this.$editor, toExecute.args, e);
else
success = toExecute.passEvent != true;
// do not stop input events to not break repeating
if (success && e && hashId != -1)
event.stopEvent(e);
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;
});
@@ -1,257 +0,0 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Skywriter.
*
* The Initial Developer of the Original Code is
* Mozilla.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Julian Viereck (julian.viereck@gmail.com)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** 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;
});
@@ -1,315 +0,0 @@
/* vim:ts=4:sts=4:sw=4:
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Mihai Sucan <mihai DOT sucan AT gmail DOT com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** 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 TextInput = function(parentNode, host) {
var text = dom.createElement("textarea");
/*/ debug
text.style.opacity = 1
text.style.background = "rgba(0, 250, 0, 0.3)"
text.style.outline = "rgba(0, 250, 0, 0.8) solid 1px"
text.style.outlineOffset = "3px"
/**/
if (useragent.isTouchPad)
text.setAttribute("x-palm-disable-auto-cap", true);
text.setAttribute("wrap", "off");
text.style.top = "-2em";
parentNode.insertBefore(text, parentNode.firstChild);
var PLACEHOLDER = useragent.isIE ? "\x01" : "\x01";
sendText();
var inCompostion = false;
var copied = false;
var pasted = false;
var tempStyle = '';
function reset(full) {
try {
if (full) {
text.value = PLACEHOLDER;
text.selectionStart = 0;
text.selectionEnd = 1;
} else
text.select();
} catch (e) {}
}
function sendText(valueToSend) {
if (!copied) {
var value = valueToSend || text.value;
if (value) {
if (value.length > 1) {
if (value.charAt(0) == PLACEHOLDER)
value = value.substr(1);
else if (value.charAt(value.length - 1) == PLACEHOLDER)
value = value.slice(0, -1);
}
if (value && value != PLACEHOLDER) {
if (pasted)
host.onPaste(value);
else
host.onTextInput(value);
}
}
}
copied = false;
pasted = false;
// Safari doesn't fire copy events if no text is selected
reset(true);
}
var onTextInput = function(e) {
if (!inCompostion)
sendText(e.data);
setTimeout(function () {
if (!inCompostion)
reset(true);
}, 0);
};
var onPropertyChange = function(e) {
setTimeout(function() {
if (!inCompostion)
sendText();
}, 0);
};
var onCompositionStart = function(e) {
inCompostion = true;
host.onCompositionStart();
setTimeout(onCompositionUpdate, 0);
};
var onCompositionUpdate = function() {
if (!inCompostion) return;
host.onCompositionUpdate(text.value);
};
var onCompositionEnd = function(e) {
inCompostion = false;
host.onCompositionEnd();
};
var onCopy = function(e) {
copied = true;
var copyText = host.getCopyText();
if(copyText)
text.value = copyText;
else
e.preventDefault();
reset();
setTimeout(function () {
sendText();
}, 0);
};
var onCut = function(e) {
copied = true;
var copyText = host.getCopyText();
if(copyText) {
text.value = copyText;
host.onCut();
} else
e.preventDefault();
reset();
setTimeout(function () {
sendText();
}, 0);
};
event.addCommandKeyListener(text, host.onCommandKey.bind(host));
event.addListener(text, "input", useragent.isIE ? onPropertyChange : onTextInput);
event.addListener(text, "paste", function(e) {
// Mark that the next input text comes from past.
pasted = true;
// Some browsers support the event.clipboardData API. Use this to get
// the pasted content which increases speed if pasting a lot of lines.
if (e.clipboardData && e.clipboardData.getData) {
sendText(e.clipboardData.getData("text/plain"));
e.preventDefault();
}
else {
// If a browser doesn't support any of the things above, use the regular
// method to detect the pasted input.
onPropertyChange();
}
});
if ("onbeforecopy" in text && typeof clipboardData !== "undefined") {
event.addListener(text, "beforecopy", function(e) {
if (tempStyle)
return; // without this text is copied when contextmenu is shown
var copyText = host.getCopyText();
if (copyText)
clipboardData.setData("Text", copyText);
else
e.preventDefault();
});
event.addListener(parentNode, "keydown", function(e) {
if (e.ctrlKey && e.keyCode == 88) {
var copyText = host.getCopyText();
if (copyText) {
clipboardData.setData("Text", copyText);
host.onCut();
}
event.preventDefault(e);
}
});
event.addListener(text, "cut", onCut); // for ie9 context menu
}
else if (useragent.isOpera) {
event.addListener(parentNode, "keydown", function(e) {
if ((useragent.isMac && !e.metaKey) || !e.ctrlKey)
return;
if ((e.keyCode == 88 || e.keyCode == 67)) {
var copyText = host.getCopyText();
if (copyText) {
text.value = copyText;
text.select();
if (e.keyCode == 88)
host.onCut();
}
}
});
}
else {
event.addListener(text, "copy", onCopy);
event.addListener(text, "cut", onCut);
}
event.addListener(text, "compositionstart", onCompositionStart);
if (useragent.isGecko) {
event.addListener(text, "text", onCompositionUpdate);
}
if (useragent.isWebKit) {
event.addListener(text, "keyup", onCompositionUpdate);
}
event.addListener(text, "compositionend", onCompositionEnd);
event.addListener(text, "blur", function() {
host.onBlur();
});
event.addListener(text, "focus", function() {
host.onFocus();
reset();
});
this.focus = function() {
reset();
text.focus();
};
this.blur = function() {
text.blur();
};
function isFocused() {
return document.activeElement === text;
}
this.isFocused = isFocused;
this.getElement = function() {
return text;
};
this.onContextMenu = function(e) {
if (!tempStyle)
tempStyle = text.style.cssText;
text.style.cssText =
"position:fixed; z-index:100000;" + //"background:rgba(250, 0, 0, 0.3); opacity:1;" +
"left:" + (e.clientX - 2) + "px; top:" + (e.clientY - 2) + "px;";
if (host.selection.isEmpty())
text.value = "";
if (e.type != "mousedown")
return;
if (host.renderer.$keepTextAreaAtCursor)
host.renderer.$keepTextAreaAtCursor = null;
// on windows context menu is opened after mouseup
if (useragent.isGecko && useragent.isWin)
event.capture(host.container, function(e) {
text.style.left = e.clientX - 2 + "px";
text.style.top = e.clientY - 2 + "px";
}, onContextMenuClose);
};
function onContextMenuClose() {
setTimeout(function () {
if (tempStyle) {
text.style.cssText = tempStyle;
tempStyle = '';
}
sendText();
if (host.renderer.$keepTextAreaAtCursor == null) {
host.renderer.$keepTextAreaAtCursor = true;
host.renderer.$moveTextAreaToCursor();
}
}, 0);
};
this.onContextMenuClose = onContextMenuClose;
// firefox fires contextmenu event after opening it
if (!useragent.isGecko)
event.addListener(text, "contextmenu", function(e) {
host.textInput.onContextMenu(e);
onContextMenuClose()
});
};
exports.TextInput = TextInput;
});
@@ -1,122 +0,0 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Sergi Mansilla <sergi AT c9 DOT io>
* Harutyun Amirjanyan <harutyun AT c9 DOT io>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
"use strict";
var keyUtil = require("../lib/keys");
var cmds = require("./vim/commands");
var coreCommands = cmds.coreCommands;
var util = require("./vim/maps/util");
var startCommands = {
"i": {
command: coreCommands.start
},
"I": {
command: coreCommands.startBeginning
},
"a": {
command: coreCommands.append
},
"A": {
command: coreCommands.appendEnd
},
"ctrl-f": {
command: "gotopagedown"
},
"ctrl-b": {
command: "gotopageup"
},
};
exports.handler = {
handleKeyboard: function(data, hashId, key, keyCode, e) {
// ignore command keys (shift, ctrl etc.)
if (hashId != 0 && (key == "" || key == "\x00"))
return null;
if (hashId == 1)
key = "ctrl-" + key;
if (data.state == "start") {
if (hashId == -1 || hashId == 1) {
if (cmds.inputBuffer.idle && startCommands[key])
return startCommands[key];
return { command: {
exec: function(editor) {cmds.inputBuffer.push(editor, key);}
} };
} // wait for input
else if (key.length == 1 && (hashId == 0 || hashId == 4)) { //no modifier || shift
return {command: "null", passEvent: true};
} else if (key == "esc") {
return {command: coreCommands.stop};
}
} else {
if (key == "esc" || key == "ctrl-[") {
data.state = "start";
return {command: coreCommands.stop};
} else if (key == "ctrl-w") {
return {command: "removewordleft"};
}
}
},
attach: function(editor) {
editor.on("click", exports.onCursorMove);
if (util.currentMode !== "insert")
cmds.coreCommands.stop.exec(editor);
},
detach: function(editor) {
editor.removeListener("click", exports.onCursorMove);
util.noMode(editor);
util.currentMode = "normal";
},
actions: cmds.actions
};
exports.onCursorMove = function(e) {
cmds.onCursorMove(e.editor, e);
exports.onCursorMove.scheduled = false;
};
});
@@ -1,556 +0,0 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Sergi Mansilla <sergi AT c9 DOT io>
* Harutyun Amirjanyan <harutyun AT c9 DOT io>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
"never use strict";
var util = require("./maps/util");
var motions = require("./maps/motions");
var operators = require("./maps/operators");
var alias = require("./maps/aliases");
var registers = require("./registers");
var NUMBER = 1;
var OPERATOR = 2;
var MOTION = 3;
var ACTION = 4;
var HMARGIN = 8; // Minimum amount of line separation between margins;
var repeat = function repeat(fn, count, args) {
while (0 < count--)
fn.apply(this, args);
};
var ensureScrollMargin = function(editor) {
var renderer = editor.renderer;
var pos = renderer.$cursorLayer.getPixelPosition();
var top = pos.top;
var margin = HMARGIN * renderer.layerConfig.lineHeight;
if (2 * margin > renderer.$size.scrollerHeight)
margin = renderer.$size.scrollerHeight / 2;
if (renderer.scrollTop > top - margin) {
renderer.session.setScrollTop(top - margin);
}
if (renderer.scrollTop + renderer.$size.scrollerHeight < top + margin + renderer.lineHeight) {
renderer.session.setScrollTop(top + margin + renderer.lineHeight - renderer.$size.scrollerHeight);
}
};
var actions = exports.actions = {
"z": {
param: true,
fn: function(editor, range, count, param) {
switch (param) {
case "z":
editor.alignCursor(null, 0.5);
break;
case "t":
editor.alignCursor(null, 0);
break;
case "b":
editor.alignCursor(null, 1);
break;
}
}
},
"r": {
param: true,
fn: function(editor, range, count, param) {
if (param && param.length) {
repeat(function() { editor.insert(param); }, count || 1);
editor.navigateLeft();
}
}
},
"R": {
fn: function(editor, range, count, param) {
util.insertMode(editor);
editor.setOverwrite(true);
}
},
"~": {
fn: function(editor, range, count) {
repeat(function() {
var range = editor.selection.getRange();
if (range.isEmpty())
range.end.column++;
var text = editor.session.getTextRange(range);
var toggled = text.toUpperCase();
if (toggled == text)
editor.navigateRight();
else
editor.session.replace(range, toggled);
}, count || 1);
}
},
"*": {
fn: function(editor, range, count, param) {
editor.selection.selectWord();
editor.findNext();
ensureScrollMargin(editor);
var r = editor.selection.getRange();
editor.selection.setSelectionRange(r, true);
}
},
"#": {
fn: function(editor, range, count, param) {
editor.selection.selectWord();
editor.findPrevious();
ensureScrollMargin(editor);
var r = editor.selection.getRange();
editor.selection.setSelectionRange(r, true);
}
},
"n": {
fn: function(editor, range, count, param) {
var options = editor.getLastSearchOptions();
options.backwards = false;
editor.selection.moveCursorRight();
editor.selection.clearSelection();
editor.findNext(options);
ensureScrollMargin(editor);
var r = editor.selection.getRange();
r.end.row = r.start.row;
r.end.column = r.start.column;
editor.selection.setSelectionRange(r, true);
}
},
"N": {
fn: function(editor, range, count, param) {
var options = editor.getLastSearchOptions();
options.backwards = true;
editor.findPrevious(options);
ensureScrollMargin(editor);
var r = editor.selection.getRange();
r.end.row = r.start.row;
r.end.column = r.start.column;
editor.selection.setSelectionRange(r, true);
}
},
"v": {
fn: function(editor, range, count, param) {
editor.selection.selectRight();
util.visualMode(editor, false);
},
acceptsMotion: true
},
"V": {
fn: function(editor, range, count, param) {
//editor.selection.selectLine();
//editor.selection.selectLeft();
var row = editor.getCursorPosition().row;
editor.selection.clearSelection();
editor.selection.moveCursorTo(row, 0);
editor.selection.selectLineEnd();
editor.selection.visualLineStart = row;
util.visualMode(editor, true);
},
acceptsMotion: true
},
"Y": {
fn: function(editor, range, count, param) {
util.copyLine(editor);
}
},
"p": {
fn: function(editor, range, count, param) {
var defaultReg = registers._default;
editor.setOverwrite(false);
if (defaultReg.isLine) {
var pos = editor.getCursorPosition();
var lines = defaultReg.text.split("\n");
editor.session.getDocument().insertLines(pos.row + 1, lines);
editor.moveCursorTo(pos.row + 1, 0);
}
else {
editor.navigateRight();
editor.insert(defaultReg.text);
editor.navigateLeft();
}
editor.setOverwrite(true);
editor.selection.clearSelection();
}
},
"P": {
fn: function(editor, range, count, param) {
var defaultReg = registers._default;
editor.setOverwrite(false);
if (defaultReg.isLine) {
var pos = editor.getCursorPosition();
var lines = defaultReg.text.split("\n");
editor.session.getDocument().insertLines(pos.row, lines);
editor.moveCursorTo(pos.row, 0);
}
else {
editor.insert(defaultReg.text);
}
editor.setOverwrite(true);
editor.selection.clearSelection();
}
},
"J": {
fn: function(editor, range, count, param) {
var session = editor.session;
range = editor.getSelectionRange();
var pos = {row: range.start.row, column: range.start.column};
count = count || range.end.row - range.start.row;
var maxRow = Math.min(pos.row + (count || 1), session.getLength() - 1);
range.start.column = session.getLine(pos.row).length;
range.end.column = session.getLine(maxRow).length;
range.end.row = maxRow;
var text = "";
for (var i = pos.row; i < maxRow; i++) {
var nextLine = session.getLine(i + 1);
text += " " + /^\s*(.*)$/.exec(nextLine)[1] || "";
}
session.replace(range, text);
editor.moveCursorTo(pos.row, pos.column);
}
},
"u": {
fn: function(editor, range, count, param) {
count = parseInt(count || 1, 10);
for (var i = 0; i < count; i++) {
editor.undo();
}
editor.selection.clearSelection();
}
},
"ctrl-r": {
fn: function(editor, range, count, param) {
count = parseInt(count || 1, 10);
for (var i = 0; i < count; i++) {
editor.redo();
}
editor.selection.clearSelection();
}
},
":": {
fn: function(editor, range, count, param) {
// not implemented
}
},
"/": {
fn: function(editor, range, count, param) {
// not implemented
}
},
"?": {
fn: function(editor, range, count, param) {
// not implemented
}
},
".": {
fn: function(editor, range, count, param) {
util.onInsertReplaySequence = inputBuffer.lastInsertCommands;
var previous = inputBuffer.previous;
if (previous) // If there is a previous action
inputBuffer.exec(editor, previous.action, previous.param);
}
}
};
var inputBuffer = exports.inputBuffer = {
accepting: [NUMBER, OPERATOR, MOTION, ACTION],
currentCmd: null,
//currentMode: 0,
currentCount: "",
// Types
operator: null,
motion: null,
lastInsertCommands: [],
push: function(editor, char, keyId) {
this.idle = false;
var wObj = this.waitingForParam;
if (wObj) {
this.exec(editor, wObj, char);
}
// If input is a number (that doesn't start with 0)
else if (!(char === "0" && !this.currentCount.length) &&
(char.match(/^\d+$/) && this.isAccepting(NUMBER))) {
// Assuming that char is always of type String, and not Number
this.currentCount += char;
this.currentCmd = NUMBER;
this.accepting = [NUMBER, OPERATOR, MOTION, ACTION];
}
else if (!this.operator && this.isAccepting(OPERATOR) && operators[char]) {
this.operator = {
char: char,
count: this.getCount()
};
this.currentCmd = OPERATOR;
this.accepting = [NUMBER, MOTION, ACTION];
this.exec(editor, { operator: this.operator });
}
else if (motions[char] && this.isAccepting(MOTION)) {
this.currentCmd = MOTION;
var ctx = {
operator: this.operator,
motion: {
char: char,
count: this.getCount()
}
};
if (motions[char].param)
this.waitForParam(ctx);
else
this.exec(editor, ctx);
}
else if (alias[char] && this.isAccepting(MOTION)) {
alias[char].operator.count = this.getCount();
this.exec(editor, alias[char]);
}
else if (actions[char] && this.isAccepting(ACTION)) {
var actionObj = {
action: {
fn: actions[char].fn,
count: this.getCount()
}
};
if (actions[char].param) {
this.waitForParam(actionObj);
}
else {
this.exec(editor, actionObj);
}
if (actions[char].acceptsMotion)
this.idle = false;
}
else if (this.operator) {
this.exec(editor, { operator: this.operator }, char);
}
else {
this.reset();
}
},
waitForParam: function(cmd) {
this.waitingForParam = cmd;
},
getCount: function() {
var count = this.currentCount;
this.currentCount = "";
return count && parseInt(count, 10);
},
exec: function(editor, action, param) {
var m = action.motion;
var o = action.operator;
var a = action.action;
if (!param)
param = action.param;
if (o) {
this.previous = {
action: action,
param: param
};
}
if (o && !editor.selection.isEmpty()) {
if (operators[o.char].selFn) {
operators[o.char].selFn(editor, editor.getSelectionRange(), o.count, param);
this.reset();
}
return;
}
// There is an operator, but no motion or action. We try to pass the
// current char to the operator to see if it responds to it (an example
// of this is the 'dd' operator).
else if (!m && !a && o && param) {
operators[o.char].fn(editor, null, o.count, param);
this.reset();
}
else if (m) {
var run = function(fn) {
if (fn && typeof fn === "function") { // There should always be a motion
if (m.count && !motionObj.handlesCount)
repeat(fn, m.count, [editor, null, m.count, param]);
else
fn(editor, null, m.count, param);
}
};
var motionObj = motions[m.char];
var selectable = motionObj.sel;
if (!o) {
if ((util.onVisualMode || util.onVisualLineMode) && selectable)
run(motionObj.sel);
else
run(motionObj.nav);
}
else if (selectable) {
repeat(function() {
run(motionObj.sel);
operators[o.char].fn(editor, editor.getSelectionRange(), o.count, param);
}, o.count || 1);
}
this.reset();
}
else if (a) {
a.fn(editor, editor.getSelectionRange(), a.count, param);
this.reset();
}
handleCursorMove(editor);
},
isAccepting: function(type) {
return this.accepting.indexOf(type) !== -1;
},
reset: function() {
this.operator = null;
this.motion = null;
this.currentCount = "";
this.accepting = [NUMBER, OPERATOR, MOTION, ACTION];
this.idle = true;
this.waitingForParam = null;
}
};
function setPreviousCommand(fn) {
inputBuffer.previous = { action: { action: { fn: fn } } };
}
exports.coreCommands = {
start: {
exec: function start(editor) {
util.insertMode(editor);
setPreviousCommand(start);
}
},
startBeginning: {
exec: function startBeginning(editor) {
editor.navigateLineStart();
util.insertMode(editor);
setPreviousCommand(startBeginning);
}
},
// Stop Insert mode as soon as possible. Works like typing <Esc> in
// insert mode.
stop: {
exec: function stop(editor) {
inputBuffer.reset();
util.onVisualMode = false;
util.onVisualLineMode = false;
inputBuffer.lastInsertCommands = util.normalMode(editor);
}
},
append: {
exec: function append(editor) {
var pos = editor.getCursorPosition();
var lineLen = editor.session.getLine(pos.row).length;
if (lineLen)
editor.navigateRight();
util.insertMode(editor);
setPreviousCommand(append);
}
},
appendEnd: {
exec: function appendEnd(editor) {
editor.navigateLineEnd();
util.insertMode(editor);
setPreviousCommand(appendEnd);
}
}
};
var handleCursorMove = exports.onCursorMove = function(editor, e) {
if (util.currentMode === 'insert' || handleCursorMove.running)
return;
else if(!editor.selection.isEmpty()) {
handleCursorMove.running = true;
if (util.onVisualLineMode) {
var originRow = editor.selection.visualLineStart;
var cursorRow = editor.getCursorPosition().row;
if(originRow <= cursorRow) {
var endLine = editor.session.getLine(cursorRow);
editor.selection.clearSelection();
editor.selection.moveCursorTo(originRow, 0);
editor.selection.selectTo(cursorRow, endLine.length);
} else {
var endLine = editor.session.getLine(originRow);
editor.selection.clearSelection();
editor.selection.moveCursorTo(originRow, endLine.length);
editor.selection.selectTo(cursorRow, 0);
}
}
handleCursorMove.running = false;
return;
}
else {
if (e && (util.onVisualLineMode || util.onVisualMode)) {
editor.selection.clearSelection();
util.normalMode(editor);
}
handleCursorMove.running = true;
var pos = editor.getCursorPosition();
var lineLen = editor.session.getLine(pos.row).length;
if (lineLen && pos.column === lineLen)
editor.navigateLeft();
handleCursorMove.running = false;
}
};
});
@@ -1,101 +0,0 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Sergi Mansilla <sergi AT c9 DOT io>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
"use strict"
define(function(require, exports, module) {
module.exports = {
"x": {
operator: {
char: "d",
count: 1
},
motion: {
char: "l",
count: 1
}
},
"X": {
operator: {
char: "d",
count: 1
},
motion: {
char: "h",
count: 1
}
},
"D": {
operator: {
char: "d",
count: 1
},
motion: {
char: "$",
count: 1
}
},
"C": {
operator: {
char: "c",
count: 1
},
motion: {
char: "$",
count: 1
}
},
"s": {
operator: {
char: "c",
count: 1
},
motion: {
char: "l",
count: 1
}
},
"S": {
operator: {
char: "c",
count: 1
},
param: "c"
}
};
});
@@ -1,611 +0,0 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Sergi Mansilla <sergi AT c9 DOT io>
* Harutyun Amirjanyan <harutyun AT c9 DOT io>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
"use strict"
define(function(require, exports, module) {
var util = require("./util");
var keepScrollPosition = function(editor, fn) {
var scrollTopRow = editor.renderer.getScrollTopRow();
var initialRow = editor.getCursorPosition().row;
var diff = initialRow - scrollTopRow;
fn && fn.call(editor);
editor.renderer.scrollToRow(editor.getCursorPosition().row - diff);
};
function Motion(getRange, type){
if (type == 'extend')
var extend = true;
else
var reverse = type;
this.nav = function(editor) {
var r = getRange(editor);
if (!r)
return;
if (!r.end)
var a = r;
else if (reverse)
var a = r.start;
else
var a = r.end;
editor.clearSelection();
editor.moveCursorTo(a.row, a.column);
}
this.sel = function(editor){
var r = getRange(editor);
if (!r)
return;
if (extend)
return editor.selection.setSelectionRange(r);
if (!r.end)
var a = r;
else if (reverse)
var a = r.start;
else
var a = r.end;
editor.selection.selectTo(a.row, a.column);
}
}
var nonWordRe = /[\s.\/\\()\"'-:,.;<>~!@#$%^&*|+=\[\]{}`~?]/;
var wordSeparatorRe = /[.\/\\()\"'-:,.;<>~!@#$%^&*|+=\[\]{}`~?]/;
var whiteRe = /\s/;
var StringStream = function(editor, cursor) {
var sel = editor.selection;
this.range = sel.getRange();
cursor = cursor || sel.selectionLead;
this.row = cursor.row;
this.col = cursor.column;
var line = editor.session.getLine(this.row);
var maxRow = editor.session.getLength()
this.ch = line[this.col] || '\n'
this.skippedLines = 0;
this.next = function() {
this.ch = line[++this.col] || this.handleNewLine(1);
//this.debug()
return this.ch;
}
this.prev = function() {
this.ch = line[--this.col] || this.handleNewLine(-1);
//this.debug()
return this.ch;
}
this.peek = function(dir) {
var ch = line[this.col + dir];
if (ch)
return ch;
if (dir == -1)
return '\n';
if (this.col == line.length - 1)
return '\n';
return editor.session.getLine(this.row + 1)[0] || '\n';
}
this.handleNewLine = function(dir) {
if (dir == 1){
if (this.col == line.length)
return '\n';
if (this.row == maxRow - 1)
return '';
this.col = 0;
this.row ++;
line = editor.session.getLine(this.row);
this.skippedLines++;
return line[0] || '\n';
}
if (dir == -1) {
if (this.row == 0)
return '';
this.row --;
line = editor.session.getLine(this.row);
this.col = line.length;
this.skippedLines--;
return '\n';
}
}
this.debug = function() {
console.log(line.substring(0, this.col)+'|'+this.ch+'\''+this.col+'\''+line.substr(this.col+1));
}
}
var Search = require("ace/search").Search;
var search = new Search();
function find(editor, needle, dir) {
search.$options.needle = needle;
search.$options.backwards = dir == -1;
return search.find(editor.session);
}
var Range = require("ace/range").Range;
module.exports = {
"w": new Motion(function(editor) {
var str = new StringStream(editor);
if (str.ch && wordSeparatorRe.test(str.ch)) {
while (str.ch && wordSeparatorRe.test(str.ch))
str.next();
} else {
while (str.ch && !nonWordRe.test(str.ch))
str.next();
}
while (str.ch && whiteRe.test(str.ch) && str.skippedLines < 2)
str.next();
str.skippedLines == 2 && str.prev();
return {column: str.col, row: str.row};
}),
"W": new Motion(function(editor) {
var str = new StringStream(editor);
while(str.ch && !(whiteRe.test(str.ch) && !whiteRe.test(str.peek(1))) && str.skippedLines < 2)
str.next();
if (str.skippedLines == 2)
str.prev();
else
str.next();
return {column: str.col, row: str.row}
}),
"b": new Motion(function(editor) {
var str = new StringStream(editor);
str.prev();
while (str.ch && whiteRe.test(str.ch) && str.skippedLines > -2)
str.prev();
if (str.ch && wordSeparatorRe.test(str.ch)) {
while (str.ch && wordSeparatorRe.test(str.ch))
str.prev();
} else {
while (str.ch && !nonWordRe.test(str.ch))
str.prev();
}
str.ch && str.next();
return {column: str.col, row: str.row};
}),
"B": new Motion(function(editor) {
var str = new StringStream(editor)
str.prev();
while(str.ch && !(!whiteRe.test(str.ch) && whiteRe.test(str.peek(-1))) && str.skippedLines > -2)
str.prev();
if (str.skippedLines == -2)
str.next();
return {column: str.col, row: str.row};
}, true),
"e": new Motion(function(editor) {
var str = new StringStream(editor);
str.next();
while (str.ch && whiteRe.test(str.ch))
str.next();
if (str.ch && wordSeparatorRe.test(str.ch)) {
while (str.ch && wordSeparatorRe.test(str.ch))
str.next();
} else {
while (str.ch && !nonWordRe.test(str.ch))
str.next();
}
str.ch && str.prev();
return {column: str.col, row: str.row};
}),
"E": new Motion(function(editor) {
var str = new StringStream(editor);
str.next();
while(str.ch && !(!whiteRe.test(str.ch) && whiteRe.test(str.peek(1))))
str.next();
return {column: str.col, row: str.row};
}),
"l": {
nav: function(editor) {
editor.navigateRight();
},
sel: function(editor) {
var pos = editor.getCursorPosition();
var col = pos.column;
var lineLen = editor.session.getLine(pos.row).length;
// Solving the behavior at the end of the line due to the
// different 0 index-based colum positions in ACE.
if (lineLen && col !== lineLen) //In selection mode you can select the newline
editor.selection.selectRight();
}
},
"h": {
nav: function(editor) {
var pos = editor.getCursorPosition();
if (pos.column > 0)
editor.navigateLeft();
},
sel: function(editor) {
var pos = editor.getCursorPosition();
if (pos.column > 0)
editor.selection.selectLeft();
}
},
"k": {
nav: function(editor) {
editor.navigateUp();
},
sel: function(editor) {
editor.selection.selectUp();
}
},
"j": {
nav: function(editor) {
editor.navigateDown();
},
sel: function(editor) {
editor.selection.selectDown();
}
},
"i": {
param: true,
sel: function(editor, range, count, param) {
switch (param) {
case "w":
editor.selection.selectWord();
break;
case "W":
editor.selection.selectAWord();
break;
case "(":
case "{":
case "[":
var cursor = editor.getCursorPosition();
var end = editor.session.$findClosingBracket(param, cursor, /paren/);
if (!end)
return;
var start = editor.session.$findOpeningBracket(editor.session.$brackets[param], cursor, /paren/);
if (!start)
return;
start.column ++;
editor.selection.setSelectionRange(Range.fromPoints(start, end));
break;
case "'":
case '"':
case "/":
var end = find(editor, param, 1);
if (!end)
return;
var start = find(editor, param, -1);
if (!start)
return;
editor.selection.setSelectionRange(Range.fromPoints(start.end, end.start));
break;
}
}
},
"a": {
param: true,
sel: function(editor, range, count, param) {
switch (param) {
case "w":
editor.selection.selectAWord();
break;
case "W":
editor.selection.selectAWord();
break;
case "(":
case "{":
case "[":
var cursor = editor.getCursorPosition();
var end = editor.session.$findClosingBracket(param, cursor, /paren/);
if (!end)
return;
var start = editor.session.$findOpeningBracket(editor.session.$brackets[param], cursor, /paren/);
if (!start)
return;
end.column ++;
editor.selection.setSelectionRange(Range.fromPoints(start, end));
break;
case "'":
case "\"":
case "/":
var end = find(editor, param, 1);
if (!end)
return;
var start = find(editor, param, -1);
if (!start)
return;
end.column ++;
editor.selection.setSelectionRange(Range.fromPoints(start.start, end.end));
break;
}
}
},
"f": {
param: true,
handlesCount: true,
nav: function(editor, range, count, param) {
var ed = editor;
var cursor = ed.getCursorPosition();
var column = util.getRightNthChar(editor, cursor, param, count || 1);
if (typeof column === "number") {
ed.selection.clearSelection(); // Why does it select in the first place?
ed.moveCursorTo(cursor.row, column + cursor.column + 1);
}
},
sel: function(editor, range, count, param) {
var ed = editor;
var cursor = ed.getCursorPosition();
var column = util.getRightNthChar(editor, cursor, param, count || 1);
if (typeof column === "number") {
ed.moveCursorTo(cursor.row, column + cursor.column + 1);
}
}
},
"F": {
param: true,
handlesCount: true,
nav: function(editor, range, count, param) {
count = parseInt(count, 10) || 1;
var ed = editor;
var cursor = ed.getCursorPosition();
var column = util.getLeftNthChar(editor, cursor, param, count);
if (typeof column === "number") {
ed.selection.clearSelection(); // Why does it select in the first place?
ed.moveCursorTo(cursor.row, cursor.column - column - 1);
}
},
sel: function(editor, range, count, param) {
var ed = editor;
var cursor = ed.getCursorPosition();
var column = util.getLeftNthChar(editor, cursor, param, count || 1);
if (typeof column === "number") {
ed.moveCursorTo(cursor.row, cursor.column - column - 1);
}
}
},
"t": {
param: true,
handlesCount: true,
nav: function(editor, range, count, param) {
var ed = editor;
var cursor = ed.getCursorPosition();
var column = util.getRightNthChar(editor, cursor, param, count || 1);
if (typeof column === "number") {
ed.selection.clearSelection(); // Why does it select in the first place?
ed.moveCursorTo(cursor.row, column + cursor.column);
}
},
sel: function(editor, range, count, param) {
var ed = editor;
var cursor = ed.getCursorPosition();
var column = util.getRightNthChar(editor, cursor, param, count || 1);
if (typeof column === "number") {
ed.moveCursorTo(cursor.row, column + cursor.column);
}
}
},
"T": {
param: true,
handlesCount: true,
nav: function(editor, range, count, param) {
var ed = editor;
var cursor = ed.getCursorPosition();
var column = util.getLeftNthChar(editor, cursor, param, count || 1);
if (typeof column === "number") {
ed.selection.clearSelection(); // Why does it select in the first place?
ed.moveCursorTo(cursor.row, -column + cursor.column);
}
},
sel: function(editor, range, count, param) {
var ed = editor;
var cursor = ed.getCursorPosition();
var column = util.getLeftNthChar(editor, cursor, param, count || 1);
if (typeof column === "number") {
ed.moveCursorTo(cursor.row, -column + cursor.column);
}
}
},
"^": {
nav: function(editor) {
editor.navigateLineStart();
},
sel: function(editor) {
editor.selection.selectLineStart();
}
},
"$": {
nav: function(editor) {
editor.navigateLineEnd();
},
sel: function(editor) {
editor.selection.selectLineEnd();
}
},
"0": {
nav: function(editor) {
var ed = editor;
ed.navigateTo(ed.selection.selectionLead.row, 0);
},
sel: function(editor) {
var ed = editor;
ed.selectTo(ed.selection.selectionLead.row, 0);
}
},
"G": {
nav: function(editor, range, count, param) {
if (!count && count !== 0) { // Stupid JS
count = editor.session.getLength();
}
editor.gotoLine(count);
},
sel: function(editor, range, count, param) {
if (!count && count !== 0) { // Stupid JS
count = editor.session.getLength();
}
editor.selection.selectTo(count, 0);
}
},
"g": {
param: true,
nav: function(editor, range, count, param) {
switch(param) {
case "m":
console.log("Middle line");
break;
case "e":
console.log("End of prev word");
break;
case "g":
editor.gotoLine(count || 0);
case "u":
editor.gotoLine(count || 0);
case "U":
editor.gotoLine(count || 0);
}
},
sel: function(editor, range, count, param) {
switch(param) {
case "m":
console.log("Middle line");
break;
case "e":
console.log("End of prev word");
break;
case "g":
editor.selection.selectTo(count || 0, 0);
}
}
},
"o": {
nav: function(editor, range, count, param) {
count = count || 1;
var content = "";
while (0 < count--)
content += "\n";
if (content.length) {
editor.navigateLineEnd()
editor.insert(content);
util.insertMode(editor);
}
}
},
"O": {
nav: function(editor, range, count, param) {
var row = editor.getCursorPosition().row;
count = count || 1;
var content = "";
while (0 < count--)
content += "\n";
if (content.length) {
if(row > 0) {
editor.navigateUp();
editor.navigateLineEnd()
editor.insert(content);
} else {
editor.session.insert({row: 0, column: 0}, content);
editor.navigateUp();
}
util.insertMode(editor);
}
}
},
"%": new Motion(function(editor){
var brRe = /[\[\]{}()]/g;
var cursor = editor.getCursorPosition();
var ch = editor.session.getLine(cursor.row)[cursor.column];
if (!brRe.test(ch)) {
var range = find(editor, brRe);
if (!range)
return;
cursor = range.start;
}
var match = editor.session.findMatchingBracket({
row: cursor.row,
column: cursor.column + 1
});
return match;
}),
"ctrl-d": {
nav: function(editor, range, count, param) {
editor.selection.clearSelection();
keepScrollPosition(editor, editor.gotoPageDown);
},
sel: function(editor, range, count, param) {
keepScrollPosition(editor, editor.selectPageDown);
}
},
"ctrl-u": {
nav: function(editor, range, count, param) {
editor.selection.clearSelection();
keepScrollPosition(editor, editor.gotoPageUp);
},
sel: function(editor, range, count, param) {
keepScrollPosition(editor, editor.selectPageUp);
}
},
};
module.exports.backspace = module.exports.left = module.exports.h;
module.exports.right = module.exports.l;
module.exports.up = module.exports.k;
module.exports.down = module.exports.j;
module.exports.pagedown = module.exports["ctrl-d"];
module.exports.pageup = module.exports["ctrl-u"];
});
@@ -1,193 +0,0 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Sergi Mansilla <sergi AT c9 DOT io>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
"never use strict";
var util = require("./util");
var registers = require("../registers");
module.exports = {
"d": {
selFn: function(editor, range, count, param) {
registers._default.text = editor.getCopyText();
registers._default.isLine = util.onVisualLineMode;
if(util.onVisualLineMode)
editor.removeLines();
else
editor.session.remove(range);
util.normalMode(editor);
},
fn: function(editor, range, count, param) {
count = count || 1;
switch (param) {
case "d":
registers._default.text = "";
registers._default.isLine = true;
for (var i = 0; i < count; i++) {
editor.selection.selectLine();
registers._default.text += editor.getCopyText();
var selRange = editor.getSelectionRange();
editor.session.remove(selRange);
editor.selection.clearSelection();
}
registers._default.text = registers._default.text.replace(/\n$/, "");
break;
default:
if (range) {
editor.selection.setSelectionRange(range);
registers._default.text = editor.getCopyText();
registers._default.isLine = false;
editor.session.remove(range);
editor.selection.clearSelection();
}
}
}
},
"c": {
selFn: function(editor, range, count, param) {
editor.session.remove(range);
util.insertMode(editor);
},
fn: function(editor, range, count, param) {
count = count || 1;
switch (param) {
case "c":
for (var i = 0; i < count; i++) {
editor.removeLines();
util.insertMode(editor);
}
break;
default:
if (range) {
// range.end.column ++;
editor.session.remove(range);
util.insertMode(editor);
}
}
}
},
"y": {
selFn: function(editor, range, count, param) {
registers._default.text = editor.getCopyText();
registers._default.isLine = util.onVisualLineMode;
editor.selection.clearSelection();
util.normalMode(editor);
},
fn: function(editor, range, count, param) {
count = count || 1;
switch (param) {
case "y":
var pos = editor.getCursorPosition();
editor.selection.selectLine();
for (var i = 0; i < count - 1; i++) {
editor.selection.moveCursorDown();
}
registers._default.text = editor.getCopyText().replace(/\n$/, "");
editor.selection.clearSelection();
registers._default.isLine = true;
editor.moveCursorToPosition(pos);
break;
default:
if (range) {
var pos = editor.getCursorPosition();
editor.selection.setSelectionRange(range);
registers._default.text = editor.getCopyText();
registers._default.isLine = false;
editor.selection.clearSelection();
editor.moveCursorTo(pos.row, pos.column);
}
}
}
},
">": {
selFn: function(editor, range, count, param) {
count = count || 1;
for (var i = 0; i < count; i++) {
editor.indent();
}
util.normalMode(editor);
},
fn: function(editor, range, count, param) {
count = parseInt(count || 1, 10);
switch (param) {
case ">":
var pos = editor.getCursorPosition();
editor.selection.selectLine();
for (var i = 0; i < count - 1; i++) {
editor.selection.moveCursorDown();
}
editor.indent();
editor.selection.clearSelection();
editor.moveCursorToPosition(pos);
editor.navigateLineEnd();
editor.navigateLineStart();
break;
}
}
},
"<": {
selFn: function(editor, range, count, param) {
count = count || 1;
for (var i = 0; i < count; i++) {
editor.blockOutdent();
}
util.normalMode(editor);
},
fn: function(editor, range, count, param) {
count = count || 1;
switch (param) {
case "<":
var pos = editor.getCursorPosition();
editor.selection.selectLine();
for (var i = 0; i < count - 1; i++) {
editor.selection.moveCursorDown();
}
editor.blockOutdent();
editor.selection.clearSelection();
editor.moveCursorToPosition(pos);
editor.navigateLineEnd();
editor.navigateLineStart();
break;
}
}
}
};
});
@@ -1,134 +0,0 @@
define(function(require, exports, module) {
var registers = require("../registers");
var dom = require("../../../lib/dom");
dom.importCssString('.insert-mode. ace_cursor{\
border-left: 2px solid #333333;\
}\
.ace_dark.insert-mode .ace_cursor{\
border-left: 2px solid #eeeeee;\
}\
.normal-mode .ace_cursor{\
border: 0!important;\
background-color: red;\
opacity: 0.5;\
}', 'vimMode');
module.exports = {
onVisualMode: false,
onVisualLineMode: false,
currentMode: 'normal',
noMode: function(editor) {
editor.unsetStyle('insert-mode');
editor.unsetStyle('normal-mode');
if (editor.commands.recording)
editor.commands.toggleRecording();
editor.setOverwrite(false);
},
insertMode: function(editor) {
this.currentMode = 'insert';
// Switch editor to insert mode
editor.setStyle('insert-mode');
editor.unsetStyle('normal-mode');
editor.setOverwrite(false);
editor.keyBinding.$data.buffer = "";
editor.keyBinding.$data.state = "insertMode";
this.onVisualMode = false;
this.onVisualLineMode = false;
if(this.onInsertReplaySequence) {
// Ok, we're apparently replaying ("."), so let's do it
editor.commands.macro = this.onInsertReplaySequence;
editor.commands.replay(editor);
this.onInsertReplaySequence = null;
this.normalMode(editor);
} else {
editor._emit("vimMode", "insert");
// Record any movements, insertions in insert mode
if(!editor.commands.recording)
editor.commands.toggleRecording();
}
},
normalMode: function(editor) {
// Switch editor to normal mode
this.currentMode = 'normal';
editor.unsetStyle('insert-mode');
editor.setStyle('normal-mode');
editor.clearSelection();
var pos;
if (!editor.getOverwrite()) {
pos = editor.getCursorPosition();
if (pos.column > 0)
editor.navigateLeft();
}
editor.setOverwrite(true);
editor.keyBinding.$data.buffer = "";
editor.keyBinding.$data.state = "start";
this.onVisualMode = false;
this.onVisualLineMode = false;
editor._emit("changeVimMode", "normal");
// Save recorded keystrokes
if (editor.commands.recording) {
editor.commands.toggleRecording();
return editor.commands.macro;
}
else {
return [];
}
},
visualMode: function(editor, lineMode) {
if (
(this.onVisualLineMode && lineMode)
|| (this.onVisualMode && !lineMode)
) {
this.normalMode(editor);
return;
}
editor.setStyle('insert-mode');
editor.unsetStyle('normal-mode');
editor._emit("changeVimMode", "visual");
if (lineMode) {
this.onVisualLineMode = true;
} else {
this.onVisualMode = true;
this.onVisualLineMode = false;
}
},
getRightNthChar: function(editor, cursor, char, n) {
var line = editor.getSession().getLine(cursor.row);
var matches = line.substr(cursor.column + 1).split(char);
return n < matches.length ? matches.slice(0, n).join(char).length : null;
},
getLeftNthChar: function(editor, cursor, char, n) {
var line = editor.getSession().getLine(cursor.row);
var matches = line.substr(0, cursor.column).split(char);
return n < matches.length ? matches.slice(-1 * n).join(char).length : null;
},
toRealChar: function(char) {
if (char.length === 1)
return char;
if (/^shift-./.test(char))
return char[char.length - 1].toUpperCase();
else
return "";
},
copyLine: function(editor) {
var pos = editor.getCursorPosition();
editor.selection.clearSelection();
editor.moveCursorTo(pos.row, pos.column);
editor.selection.selectLine();
registers._default.isLine = true;
registers._default.text = editor.getCopyText().replace(/\n$/, "");
editor.selection.clearSelection();
editor.moveCursorTo(pos.row, pos.column);
}
};
});
@@ -1,49 +0,0 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Sergi Mansilla <sergi AT c9 DOT io>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
"never use strict";
module.exports = {
_default: {
text: "",
isLine: false
}
};
});
@@ -1,202 +0,0 @@
/* vim:ts=4:sts=4:sw=4:
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Julian Viereck <julian.viereck@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
"use strict";
var dom = require("../lib/dom");
var Cursor = function(parentEl) {
this.element = dom.createElement("div");
this.element.className = "ace_layer ace_cursor-layer";
parentEl.appendChild(this.element);
this.isVisible = false;
this.cursors = [];
this.cursor = this.addCursor();
};
(function() {
this.$padding = 0;
this.setPadding = function(padding) {
this.$padding = padding;
};
this.setSession = function(session) {
this.session = session;
};
this.addCursor = function() {
var el = dom.createElement("div");
var className = "ace_cursor";
if (!this.isVisible)
className += " ace_hidden";
if (this.overwrite)
className += " ace_overwrite";
el.className = className;
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;
for (var i = this.cursors.length; i--; )
dom.addCssClass(this.cursors[i], "ace_hidden");
clearInterval(this.blinkId);
};
this.showCursor = function() {
this.isVisible = true;
for (var i = this.cursors.length; i--; )
dom.removeCssClass(this.cursors[i], "ace_hidden");
this.element.style.visibility = "";
this.restartTimer();
};
this.restartTimer = function() {
clearInterval(this.blinkId);
if (!this.isVisible)
return;
var element = this.cursors.length == 1 ? this.cursor : this.element;
this.blinkId = setInterval(function() {
element.style.visibility = "hidden";
setTimeout(function() {
element.style.visibility = "";
}, 400);
}, 1000);
};
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 = Math.round(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;
if (this.session.selectionMarkerCount > 0) {
var selections = this.session.$selectionMarkers;
var i = 0, sel, cursorIndex = 0;
for (var i = selections.length; i--; ) {
sel = selections[i];
var pixelPos = this.getPixelPosition(sel.cursor, true);
var style = (this.cursors[cursorIndex++] || this.addCursor()).style;
style.left = pixelPos.left + "px";
style.top = pixelPos.top + "px";
style.width = config.characterWidth + "px";
style.height = config.lineHeight + "px";
}
if (cursorIndex > 1)
while (this.cursors.length > cursorIndex)
this.removeCursor();
} else {
var pixelPos = this.getPixelPosition(null, true);
var style = this.cursor.style;
style.left = pixelPos.left + "px";
style.top = pixelPos.top + "px";
style.width = config.characterWidth + "px";
style.height = config.lineHeight + "px";
while (this.cursors.length > 1)
this.removeCursor();
}
var overwrite = this.session.getOverwrite();
if (overwrite != this.overwrite)
this.$setOverite(overwrite);
// cache for textarea and gutter highlight
this.$pixelPos = pixelPos;
this.restartTimer();
};
this.$setOverite = function(overwrite) {
this.overwrite = overwrite;
for (var i = this.cursors.length; i--; ) {
if (overwrite)
dom.addCssClass(this.cursors[i], "ace_overwrite");
else
dom.removeCssClass(this.cursors[i], "ace_overwrite");
}
};
this.destroy = function() {
clearInterval(this.blinkId);
}
}).call(Cursor.prototype);
exports.Cursor = Cursor;
});
@@ -1,187 +0,0 @@
/* vim:ts=4:sts=4:sw=4:
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Julian Viereck <julian DOT viereck AT gmail DOT com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
"use strict";
var dom = require("../lib/dom");
var oop = require("../lib/oop");
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.$breakpoints = [];
this.$annotations = [];
this.$decorations = [];
};
(function() {
oop.implement(this, EventEmitter);
this.setSession = function(session) {
this.session = session;
};
this.addGutterDecoration = function(row, className){
if (!this.$decorations[row])
this.$decorations[row] = "";
this.$decorations[row] += " " + className;
};
this.removeGutterDecoration = function(row, className){
this.$decorations[row] = (this.$decorations[row] || "").replace(" " + className, "");
};
this.setAnnotations = function(annotations) {
// iterate over sparse array
this.$annotations = [];
for (var row in annotations) if (annotations.hasOwnProperty(row)) {
var rowAnnotations = annotations[row];
if (!rowAnnotations)
continue;
var rowInfo = this.$annotations[row] = {
text: []
};
for (var i=0; i<rowAnnotations.length; i++) {
var annotation = rowAnnotations[i];
var annoText = annotation.text.replace(/"/g, "&quot;").replace(/'/g, "&#8217;").replace(/</, "&lt;");
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.update = function(config) {
this.$config = config;
var emptyAnno = {className: "", text: []};
var html = [];
var i = config.firstRow;
var lastRow = config.lastRow;
var fold = this.session.getNextFoldLine(i);
var foldStart = fold ? fold.start.row : Infinity;
var foldWidgets = this.$showFoldWidgets && this.session.foldWidgets;
var breakpoints = this.session.$breakpoints;
while (true) {
if(i > foldStart) {
i = fold.end.row + 1;
fold = this.session.getNextFoldLine(i, fold);
foldStart = fold ?fold.start.row :Infinity;
}
if(i > lastRow)
break;
var annotation = this.$annotations[i] || emptyAnno;
html.push("<div class='ace_gutter-cell",
this.$decorations[i] || "",
breakpoints[i] ? " ace_breakpoint " : " ",
annotation.className,
"' title='", annotation.text.join("\n"),
"' style='height:", this.session.getRowLength(i) * config.lineHeight, "px;'>", (i+1));
if (foldWidgets) {
var c = foldWidgets[i];
// check if cached value is invalidated and we need to recompute
if (c == null)
c = foldWidgets[i] = this.session.getFoldWidget(i);
if (c)
html.push(
"<span class='ace_fold-widget ", c,
c == "start" && i == foldStart && i < fold.end.row ? " closed" : " open",
"'></span>"
);
}
html.push("</div>");
i++;
}
if (this.session.$useWrapMode)
html.push(
"<div class='ace_gutter-cell' style='pointer-events:none;opacity:0'>",
this.session.getLength() - 1,
"</div>"
);
this.element = dom.setInnerHtml(this.element, html.join(""));
this.element.style.height = config.minHeight + "px";
var gutterWidth = this.element.offsetWidth;
if (gutterWidth !== this.gutterWidth) {
this.gutterWidth = gutterWidth;
this._emit("changeGutterWidth", gutterWidth);
}
};
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.getShowFoldWidgets = function() {
return this.$showFoldWidgets;
};
}).call(Gutter.prototype);
exports.Gutter = Gutter;
});
@@ -1,214 +0,0 @@
/* vim:ts=4:sts=4:sw=4:
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Julian Viereck <julian.viereck@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** 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 = Math.round(
this.$padding + range.start.column * config.characterWidth
);
marker.renderer(html, range, left, top, config);
}
else if (range.isMultiLine()) {
if (marker.type == "text") {
this.drawTextMarker(html, range, marker.clazz, config);
} else {
this.drawMultiLineMarker(
html, range, marker.clazz, config,
marker.type
);
}
}
else {
this.drawSingleLineMarker(
html, range, marker.clazz + " start", config,
null, marker.type
);
}
}
this.element = dom.setInnerHtml(this.element, 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) {
// 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 + " start", layerConfig, 1, "text");
// selection end
row = range.end.row;
lineRange = new Range(row, 0, row, range.end.column);
this.drawSingleLineMarker(stringBuilder, lineRange, clazz, layerConfig, 0, "text");
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, "text");
}
};
// Draws a multi line marker, where lines span the full width
this.drawMultiLineMarker = function(stringBuilder, range, clazz, config, type) {
var padding = type === "background" ? 0 : this.$padding;
// from selection start to the end of the line
var height = config.lineHeight;
var top = this.$getTop(range.start.row, config);
var left = Math.round(padding + range.start.column * config.characterWidth);
stringBuilder.push(
"<div class='", clazz, " start' style='",
"height:", height, "px;",
"right:0;",
"top:", top, "px;",
"left:", left, "px;'></div>"
);
// from start of the last line to the selection end
top = this.$getTop(range.end.row, config);
var width = Math.round(range.end.column * config.characterWidth);
stringBuilder.push(
"<div class='", clazz, "' style='",
"height:", height, "px;",
"width:", width, "px;",
"top:", top, "px;",
"left:", padding, "px;'></div>"
);
// 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(
"<div class='", clazz, "' style='",
"height:", height, "px;",
"right:0;",
"top:", top, "px;",
"left:", padding, "px;'></div>"
);
};
// Draws a marker which covers part or whole width of a single screen line
this.drawSingleLineMarker = function(stringBuilder, range, clazz, layerConfig, extraLength, type) {
var padding = type === "background" ? 0 : this.$padding;
var height = layerConfig.lineHeight;
if (type === "background")
var width = layerConfig.width;
else
width = Math.round((range.end.column + (extraLength || 0) - range.start.column) * layerConfig.characterWidth);
var top = this.$getTop(range.start.row, layerConfig);
var left = Math.round(
padding + range.start.column * layerConfig.characterWidth
);
stringBuilder.push(
"<div class='", clazz, "' style='",
"height:", height, "px;",
"width:", width, "px;",
"top:", top, "px;",
"left:", left,"px;'></div>"
);
};
}).call(Marker.prototype);
exports.Marker = Marker;
});
@@ -1,595 +0,0 @@
/* vim:ts=4:sts=4:sw=4:
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Julian Viereck <julian DOT viereck AT gmail DOT com>
* Mihai Sucan <mihai.sucan@gmail.com>
* Irakli Gozalishvili <rfobic@gmail.com> (http://jeditoolkit.com)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** 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.$characterSize = this.$measureSizes() || {width: 0, height: 0};
this.$pollSizeChanges();
};
(function() {
oop.implement(this, EventEmitter);
this.EOF_CHAR = "\xB6"; //"&para;";
this.EOL_CHAR = "\xAC"; //"&not;";
this.TAB_CHAR = "\u2192"; //"&rarr;" "\u21E5";
this.SPACE_CHAR = "\xB7"; //"&middot;";
this.$padding = 0;
this.setPadding = function(padding) {
this.$padding = padding;
this.element.style.padding = "0 " + padding + "px";
};
this.getLineHeight = function() {
return this.$characterSize.height || 1;
};
this.getCharacterWidth = function() {
return this.$characterSize.width || 1;
};
this.checkForSizeChanges = function() {
var size = this.$measureSizes();
if (size && (this.$characterSize.width !== size.width || this.$characterSize.height !== size.height)) {
this.$characterSize = size;
this._emit("changeCharacterSize", {data: size});
}
};
this.$pollSizeChanges = function() {
var self = this;
this.$pollSizeChangesTimer = setInterval(function() {
self.checkForSizeChanges();
}, 500);
};
this.$fontStyles = {
fontFamily : 1,
fontSize : 1,
fontWeight : 1,
fontStyle : 1,
lineHeight : 1
};
this.$measureSizes = useragent.isIE || useragent.isOldGecko ? function() {
var n = 1000;
if (!this.$measureNode) {
var measureNode = this.$measureNode = dom.createElement("div");
var style = measureNode.style;
style.width = style.height = "auto";
style.left = style.top = (-n * 40) + "px";
style.visibility = "hidden";
style.position = "fixed";
style.overflow = "visible";
style.whiteSpace = "nowrap";
// in FF 3.6 monospace fonts can have a fixed sub pixel width.
// that's why we have to measure many characters
// Note: characterWidth can be a float!
measureNode.innerHTML = lang.stringRepeat("Xy", n);
if (this.element.ownerDocument.body) {
this.element.ownerDocument.body.appendChild(measureNode);
} else {
var container = this.element.parentNode;
while (!dom.hasCssClass(container, "ace_editor"))
container = container.parentNode;
container.appendChild(measureNode);
}
}
// Size and width can be null if the editor is not visible or
// detached from the document
if (!this.element.offsetWidth)
return null;
var style = this.$measureNode.style;
var computedStyle = dom.computedStyle(this.element);
for (var prop in this.$fontStyles)
style[prop] = computedStyle[prop];
var size = {
height: this.$measureNode.offsetHeight,
width: this.$measureNode.offsetWidth / (n * 2)
};
// 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;
}
: function() {
if (!this.$measureNode) {
var measureNode = this.$measureNode = dom.createElement("div");
var style = measureNode.style;
style.width = style.height = "auto";
style.left = style.top = -100 + "px";
style.visibility = "hidden";
style.position = "fixed";
style.overflow = "visible";
style.whiteSpace = "nowrap";
measureNode.innerHTML = "X";
var container = this.element.parentNode;
while (container && !dom.hasCssClass(container, "ace_editor"))
container = container.parentNode;
if (!container)
return this.$measureNode = null;
container.appendChild(measureNode);
}
var rect = this.$measureNode.getBoundingClientRect();
var size = {
height: rect.height,
width: rect.width
};
// 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.setSession = function(session) {
this.session = session;
};
this.showInvisibles = false;
this.setShowInvisibles = function(showInvisibles) {
if (this.showInvisibles == showInvisibles)
return false;
this.showInvisibles = showInvisibles;
return true;
};
this.$tabStrings = [];
this.$computeTabString = function() {
var tabSize = this.session.getTabSize();
var tabStr = this.$tabStrings = [0];
for (var i = 1; i < tabSize + 1; i++) {
if (this.showInvisibles) {
tabStr.push("<span class='ace_invisible'>"
+ this.TAB_CHAR
+ new Array(i).join("&#160;")
+ "</span>");
} else {
tabStr.push(new Array(i+1).join("&#160;"));
}
}
};
this.updateLines = function(config, firstRow, lastRow) {
this.$computeTabString();
// 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 ++;
}
for (var i=first; i<=last; i++) {
var lineElement = lineElements[lineElementsIdx++];
if (!lineElement)
continue;
var html = [];
var tokens = this.session.getTokens(i);
this.$renderLine(html, i, tokens, !this.$useLineGroups());
lineElement = dom.setInnerHtml(lineElement, html.join(""));
i = this.session.getRowFoldEnd(i);
}
};
this.scrollLines = function(config) {
this.$computeTabString();
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.
var tokens = this.session.getTokens(row);
this.$renderLine(html, row, tokens, 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);
} else {
var lines = container.childNodes
while(lines.length)
fragment.appendChild(lines[0]);
}
row++;
}
return fragment;
};
this.update = function(config) {
this.$computeTabString();
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("<div class='ace_line_group'>")
// Get the tokens per line as there might be some lines in between
// beeing folded.
var tokens = this.session.getTokens(row);
this.$renderLine(html, row, tokens, false);
if (this.$useLineGroups())
html.push("</div>"); // end the line group
row++;
}
this.element = dom.setInnerHtml(this.element, html.join(""));
};
this.$textToken = {
"text": true,
"rparen": true,
"lparen": true
};
this.$renderToken = function(stringBuilder, screenColumn, token, value) {
var self = this;
var replaceReg = /\t|&|<|( +)|([\u0000-\u0019\u00a0\u1680\u180E\u2000-\u200b\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 new Array(c.length+1).join("&#160;");
} else if (c == "&") {
return "&#38;";
} else if (c == "<") {
return "&#60;";
} 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_cjk";
var space = self.showInvisibles ? self.SPACE_CHAR : "";
screenColumn += 1;
return "<span class='" + classToUse + "' style='width:" +
(self.config.characterWidth * 2) +
"px'>" + space + "</span>";
} else if (b) {
return "<span class='ace_invisible ace_invalid'>" + self.SPACE_CHAR + "</span>";
} else {
screenColumn += 1;
return "<span class='ace_cjk' style='width:" +
(self.config.characterWidth * 2) +
"px'>" + c + "</span>";
}
};
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("<span class='", classes, "'", style, ">", output, "</span>");
}
else {
stringBuilder.push(output);
}
return screenColumn + value.length;
};
this.$renderLineCore = function(stringBuilder, lastRow, tokens, splits, onlyContents) {
var chars = 0;
var split = 0;
var splitChars;
var screenColumn = 0;
var self = this;
if (!splits || splits.length == 0)
splitChars = Number.MAX_VALUE;
else
splitChars = splits[0];
if (!onlyContents) {
stringBuilder.push("<div class='ace_line' style='height:",
this.config.lineHeight, "px",
"'>"
);
}
for (var i = 0; i < tokens.length; i++) {
var token = tokens[i];
var value = token.value;
if (chars + value.length < splitChars) {
screenColumn = self.$renderToken(
stringBuilder, screenColumn, token, value
);
chars += value.length;
}
else {
while (chars + value.length >= splitChars) {
screenColumn = self.$renderToken(
stringBuilder, screenColumn,
token, value.substring(0, splitChars - chars)
);
value = value.substring(splitChars - chars);
chars = splitChars;
if (!onlyContents) {
stringBuilder.push("</div>",
"<div class='ace_line' style='height:",
this.config.lineHeight, "px",
"'>"
);
}
split ++;
screenColumn = 0;
splitChars = splits[split] || Number.MAX_VALUE;
}
if (value.length != 0) {
chars += value.length;
screenColumn = self.$renderToken(
stringBuilder, screenColumn, token, value
);
}
}
}
if (this.showInvisibles) {
if (lastRow !== this.session.getLength() - 1)
stringBuilder.push("<span class='ace_invisible'>" + this.EOL_CHAR + "</span>");
else
stringBuilder.push("<span class='ace_invisible'>" + this.EOF_CHAR + "</span>");
}
if (!onlyContents)
stringBuilder.push("</div>");
};
this.$renderLine = function(stringBuilder, row, tokens, onlyContents) {
// Check if the line to render is folded or not. If not, things are
// simple, otherwise, we need to fake some things...
if (!this.session.isRowFolded(row)) {
var splits = this.session.getRowSplitData(row);
this.$renderLineCore(stringBuilder, row, tokens, splits, onlyContents);
} else {
this.$renderFoldLine(stringBuilder, row, tokens, onlyContents);
}
};
this.$renderFoldLine = function(stringBuilder, row, tokens, onlyContents) {
var session = this.session;
var foldLine = session.getFoldLine(row);
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;
}
}
foldLine.walk(function(placeholder, row, column, lastColumn, isNewRow) {
if (placeholder) {
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);
// splits for foldline are stored at its' first row
var splits = this.session.$useWrapMode ? this.session.$wrapData[row] : null;
this.$renderLineCore(stringBuilder, row, renderTokens, splits, onlyContents);
};
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;
});
@@ -1,106 +0,0 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** 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 row = 0;
var tokens = this.session.getTokens(row);
var stringBuilder = [];
this.textLayer.$renderLine(stringBuilder, row, tokens);
// row with soft tabs
row = 1;
tokens = this.session.getTokens(row);
var stringBuilder2 = [];
this.textLayer.$renderLine(stringBuilder2, row, tokens);
assert.equal(stringBuilder.join(""), stringBuilder2.join(""));
},
"test rendering width of ideographic space (U+3000)" : function() {
this.session.setValue("\u3000");
var tokens = this.session.getTokens(0);
var stringBuilder = [];
this.textLayer.$renderLine(stringBuilder, 0, tokens, true);
assert.equal(stringBuilder.join(""), "<span class='ace_cjk' style='width:20px'></span>");
this.textLayer.setShowInvisibles(true);
var stringBuilder = [];
this.textLayer.$renderLine(stringBuilder, 0, tokens, true);
assert.equal(
stringBuilder.join(""),
"<span class='ace_cjk ace_invisible' style='width:20px'>" + this.textLayer.SPACE_CHAR + "</span>"
+ "<span class='ace_invisible'>\xB6</span>"
);
}
};
});
if (typeof module !== "undefined" && module === require.main) {
require("asyncjs").test.testcase(module.exports).exec()
}
@@ -1,105 +0,0 @@
/* vim:ts=4:sts=4:sw=4:
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Irakli Gozalishvili <rfobic@gmail.com> (http://jeditoolkit.com)
* Julian Viereck <julian.viereck@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
"use strict";
var oop = require("./oop");
var event = require("./event");
var EventEmitter = require("./event_emitter").EventEmitter;
/*
* This class keeps track of the focus state of the given window.
* Focus changes for example when the user switches a browser tab,
* goes to the location bar or switches to another application.
*/
var BrowserFocus = function(win) {
win = win || window;
this.lastFocus = new Date().getTime();
this._isFocused = true;
var _self = this;
// IE < 9 supports focusin and focusout events
if ("onfocusin" in win.document) {
event.addListener(win.document, "focusin", function(e) {
_self._setFocused(true);
});
event.addListener(win.document, "focusout", function(e) {
_self._setFocused(!!e.toElement);
});
}
else {
event.addListener(win, "blur", function(e) {
_self._setFocused(false);
});
event.addListener(win, "focus", function(e) {
_self._setFocused(true);
});
}
};
(function(){
oop.implement(this, EventEmitter);
this.isFocused = function() {
return this._isFocused;
};
this._setFocused = function(isFocused) {
if (this._isFocused == isFocused)
return;
if (isFocused)
this.lastFocus = new Date().getTime();
this._isFocused = isFocused;
this._emit("changeFocus");
};
}).call(BrowserFocus.prototype);
exports.BrowserFocus = BrowserFocus;
});
@@ -1,292 +0,0 @@
/* vim:ts=4:sts=4:sw=4:
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Mihai Sucan <mihai AT sucan AT gmail ODT com>
* Irakli Gozalishvili <rfobic@gmail.com> (http://jeditoolkit.com)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
"use strict";
var XHTML_NS = "http://www.w3.org/1999/xhtml";
exports.createElement = function(tag, ns) {
return document.createElementNS ?
document.createElementNS(ns || XHTML_NS, tag) :
document.createElement(tag);
};
exports.setText = function(elem, text) {
if (elem.innerText !== undefined) {
elem.innerText = text;
}
if (elem.textContent !== undefined) {
elem.textContent = text;
}
};
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 <tt>include</tt>
*/
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;
var head = doc.getElementsByTagName("head")[0] || doc.documentElement;
head.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;
var head = doc.getElementsByTagName("head")[0] || doc.documentElement;
head.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 (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("p");
inner.style.width = "100%";
inner.style.minWidth = "0px";
inner.style.height = "200px";
var outer = exports.createElement("div");
var style = outer.style;
style.position = "absolute";
style.left = "-10000px";
style.overflow = "hidden";
style.width = "200px";
style.minWidth = "0px";
style.height = "150px";
outer.appendChild(inner);
var body = document.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;
};
exports.setInnerText = function(el, innerText) {
var document = el.ownerDocument;
if (document.body && "textContent" in document.body)
el.textContent = innerText;
else
el.innerText = innerText;
};
exports.getInnerText = function(el) {
var document = el.ownerDocument;
if (document.body && "textContent" in document.body)
return el.textContent;
else
return el.innerText || el.textContent || "";
};
exports.getParentWindow = function(document) {
return document.defaultView || document.parentWindow;
};
});
File diff suppressed because it is too large Load Diff
@@ -1,317 +0,0 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
"use strict";
var keys = require("./keys");
var useragent = require("./useragent");
var dom = require("./dom");
exports.addListener = function(elem, type, callback) {
if (elem.addEventListener) {
return elem.addEventListener(type, callback, false);
}
if (elem.attachEvent) {
var wrapper = function() {
callback(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" || (e.ctrlKey && useragent.isMac))
return 2;
// DOM Event
if (e.preventDefault) {
return e.button;
}
// old IE
else {
return {1:0, 2:2, 4:1}[e.button];
}
};
if (document.documentElement.setCapture) {
exports.capture = function(el, eventHandler, releaseCaptureHandler) {
function onMouseMove(e) {
eventHandler(e);
return exports.stopPropagation(e);
}
var called = false;
function onReleaseCapture(e) {
eventHandler(e);
if (!called) {
called = true;
releaseCaptureHandler(e);
}
exports.removeListener(el, "mousemove", eventHandler);
exports.removeListener(el, "mouseup", onReleaseCapture);
exports.removeListener(el, "losecapture", onReleaseCapture);
el.releaseCapture();
}
exports.addListener(el, "mousemove", eventHandler);
exports.addListener(el, "mouseup", onReleaseCapture);
exports.addListener(el, "losecapture", onReleaseCapture);
el.setCapture();
};
}
else {
exports.capture = function(el, eventHandler, releaseCaptureHandler) {
function onMouseMove(e) {
eventHandler(e);
e.stopPropagation();
}
function onMouseUp(e) {
eventHandler && eventHandler(e);
releaseCaptureHandler && releaseCaptureHandler(e);
document.removeEventListener("mousemove", onMouseMove, true);
document.removeEventListener("mouseup", onMouseUp, true);
e.stopPropagation();
}
document.addEventListener("mousemove", onMouseMove, true);
document.addEventListener("mouseup", onMouseUp, true);
};
}
exports.addMouseWheelListener = function(el, callback) {
var factor = 8;
var listener = function(e) {
if (e.wheelDelta !== undefined) {
if (e.wheelDeltaX !== undefined) {
e.wheelX = -e.wheelDeltaX / factor;
e.wheelY = -e.wheelDeltaY / factor;
} else {
e.wheelX = 0;
e.wheelY = -e.wheelDelta / factor;
}
}
else {
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.addListener(el, "DOMMouseScroll", listener);
exports.addListener(el, "mousewheel", listener);
};
exports.addMultiMouseDownListener = function(el, timeouts, eventHandler, callbackName) {
var clicks = 0;
var startX, startY, timer;
var eventNames = {
2: "dblclick",
3: "tripleclick",
4: "quadclick"
};
var listener = function(e) {
if (exports.getButton(e) != 0) {
clicks = 0;
} else {
var isNewClick = Math.abs(e.clientX - startX) > 5 || Math.abs(e.clientY - startY) > 5;
if (!timer || isNewClick)
clicks = 0;
clicks += 1;
if (timer)
clearTimeout(timer)
timer = setTimeout(function() {timer = null}, timeouts[clicks - 1] || 600);
}
if (clicks == 1) {
startX = e.clientX;
startY = e.clientY;
}
eventHandler[callbackName]("mousedown", e);
if (clicks > 4)
clicks = 0;
else if (clicks > 1)
return eventHandler[callbackName](eventNames[clicks], e);
};
exports.addListener(el, "mousedown", listener);
useragent.isOldIE && exports.addListener(el, "dblclick", listener);
};
function normalizeCommandKeys(callback, e, keyCode) {
var hashId = 0;
if ((useragent.isOpera && !("KeyboardEvent" in window)) && useragent.isMac) {
hashId = 0 | (e.metaKey ? 1 : 0) | (e.altKey ? 2 : 0)
| (e.shiftKey ? 4 : 0) | (e.ctrlKey ? 8 : 0);
} else {
hashId = 0 | (e.ctrlKey ? 1 : 0) | (e.altKey ? 2 : 0)
| (e.shiftKey ? 4 : 0) | (e.metaKey ? 8 : 0);
}
if (keyCode in keys.MODIFIER_KEYS) {
switch (keys.MODIFIER_KEYS[keyCode]) {
case "Alt":
hashId = 2;
break;
case "Shift":
hashId = 4;
break;
case "Ctrl":
hashId = 1;
break;
default:
hashId = 8;
break;
}
keyCode = 0;
}
if (hashId & 8 && (keyCode == 91 || keyCode == 93)) {
keyCode = 0;
}
// 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);
}
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 lastDown = null;
addListener(el, "keydown", function(e) {
lastDown = e.keyIdentifier || e.keyCode;
return normalizeCommandKeys(callback, e, e.keyCode);
});
}
};
if (window.postMessage) {
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, "*");
};
}
else {
exports.nextTick = function(callback, win) {
win = win || window;
window.setTimeout(callback, 0);
};
}
});
@@ -1,121 +0,0 @@
/* vim:ts=4:sts=4:sw=4:
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Irakli Gozalishvili <rfobic@gmail.com> (http://jeditoolkit.com)
* Mike de Boer <mike AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
"use strict";
var EventEmitter = {};
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;
e = e || {};
e.type = eventName;
if (!e.stopPropagation) {
e.stopPropagation = function() {
this.propagationStopped = true;
};
}
if (!e.preventDefault) {
e.preventDefault = function() {
this.defaultPrevented = true;
};
}
for (var i=0; i<listeners.length; i++) {
listeners[i](e);
if (e.propagationStopped)
break;
}
if (defaultHandler && !e.defaultPrevented)
return defaultHandler(e);
};
EventEmitter.setDefaultHandler = function(eventName, callback) {
this._defaultHandlers = this._defaultHandlers || {};
if (this._defaultHandlers[eventName])
throw new Error("The default handler for '" + eventName + "' is already set");
this._defaultHandlers[eventName] = callback;
};
EventEmitter.on =
EventEmitter.addEventListener = function(eventName, callback) {
this._eventRegistry = this._eventRegistry || {};
var listeners = this._eventRegistry[eventName];
if (!listeners)
var listeners = this._eventRegistry[eventName] = [];
if (listeners.indexOf(callback) == -1)
listeners.push(callback);
};
EventEmitter.removeListener =
EventEmitter.removeEventListener = function(eventName, callback) {
this._eventRegistry = this._eventRegistry || {};
var listeners = this._eventRegistry[eventName];
if (!listeners)
return;
var index = listeners.indexOf(callback);
if (index !== -1)
listeners.splice(index, 1);
};
EventEmitter.removeAllListeners = function(eventName) {
if (this._eventRegistry) this._eventRegistry[eventName] = [];
};
exports.EventEmitter = EventEmitter;
});
@@ -1,72 +0,0 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
if (typeof process !== "undefined") {
require("amd-loader");
}
define(function(require, exports, module) {
"use strict";
var oop = require("../lib/oop");
var EventEmitter = require("./event_emitter").EventEmitter;
var assert = require("../test/assertions");
var Emitter = function() {};
oop.implement(Emitter.prototype, EventEmitter);
module.exports = {
"test: dispatch event with no data" : function() {
var emitter = new Emitter();
var called = false;
emitter.addEventListener("juhu", function(e) {
called = true;
assert.equal(e.type, "juhu");
});
emitter._emit("juhu");
assert.ok(called);
}
};
});
if (typeof module !== "undefined" && module === require.main) {
require("asyncjs").test.testcase(module.exports).exec()
}
@@ -1,19 +0,0 @@
// vim:set ts=4 sts=4 sw=4 st:
// -- kriskowal Kris Kowal Copyright (C) 2009-2010 MIT License
// -- tlrobinson Tom Robinson Copyright (C) 2009-2010 MIT License (Narwhal Project)
// -- dantman Daniel Friesen Copyright(C) 2010 XXX No License Specified
// -- fschaefer Florian Schäfer Copyright (C) 2010 MIT License
// -- Irakli Gozalishvili Copyright (C) 2010 MIT License
/*!
Copyright (c) 2009, 280 North Inc. http://280north.com/
MIT License. http://github.com/280north/narwhal/blob/master/README.md
*/
define(function(require, exports, module) {
"use strict";
require("./regexp");
require("./es5-shim");
});
@@ -1,129 +0,0 @@
/*! @license
==========================================================================
SproutCore -- JavaScript Application Framework
copyright 2006-2009, Sprout Systems Inc., Apple Inc. and contributors.
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.
SproutCore and the SproutCore logo are trademarks of Sprout Systems, Inc.
For more information about SproutCore, visit http://www.sproutcore.com
==========================================================================
@license */
// Most of the following code is taken from SproutCore with a few changes.
define(function(require, exports, module) {
"use strict";
var oop = require("./oop");
/*
* Helper functions and hashes for key handling.
*/
var Keys = (function() {
var ret = {
MODIFIER_KEYS: {
16: 'Shift', 17: 'Ctrl', 18: 'Alt', 224: 'Meta'
},
KEY_MODS: {
"ctrl": 1, "alt": 2, "option" : 2,
"shift": 4, "meta": 8, "command": 8
},
FUNCTION_KEYS : {
8 : "Backspace",
9 : "Tab",
13 : "Return",
19 : "Pause",
27 : "Esc",
32 : "Space",
33 : "PageUp",
34 : "PageDown",
35 : "End",
36 : "Home",
37 : "Left",
38 : "Up",
39 : "Right",
40 : "Down",
44 : "Print",
45 : "Insert",
46 : "Delete",
96 : "Numpad0",
97 : "Numpad1",
98 : "Numpad2",
99 : "Numpad3",
100: "Numpad4",
101: "Numpad5",
102: "Numpad6",
103: "Numpad7",
104: "Numpad8",
105: "Numpad9",
112: "F1",
113: "F2",
114: "F3",
115: "F4",
116: "F5",
117: "F6",
118: "F7",
119: "F8",
120: "F9",
121: "F10",
122: "F11",
123: "F12",
144: "Numlock",
145: "Scrolllock"
},
PRINTABLE_KEYS: {
32: ' ', 48: '0', 49: '1', 50: '2', 51: '3', 52: '4', 53: '5',
54: '6', 55: '7', 56: '8', 57: '9', 59: ';', 61: '=', 65: 'a',
66: 'b', 67: 'c', 68: 'd', 69: 'e', 70: 'f', 71: 'g', 72: 'h',
73: 'i', 74: 'j', 75: 'k', 76: 'l', 77: 'm', 78: 'n', 79: 'o',
80: 'p', 81: 'q', 82: 'r', 83: 's', 84: 't', 85: 'u', 86: 'v',
87: 'w', 88: 'x', 89: 'y', 90: 'z', 107: '+', 109: '-', 110: '.',
188: ',', 190: '.', 191: '/', 192: '`', 219: '[', 220: '\\',
221: ']', 222: '\''
}
};
// A reverse map of FUNCTION_KEYS
for (var i in ret.FUNCTION_KEYS) {
var name = ret.FUNCTION_KEYS[i].toUpperCase();
ret[name] = parseInt(i, 10);
}
// Add the MODIFIER_KEYS, FUNCTION_KEYS and PRINTABLE_KEYS to the KEY
// variables as well.
oop.mixin(ret, ret.MODIFIER_KEYS);
oop.mixin(ret, ret.PRINTABLE_KEYS);
oop.mixin(ret, ret.FUNCTION_KEYS);
return ret;
})();
oop.mixin(exports, Keys);
exports.keyCodeToString = function(keyCode) {
return (Keys[keyCode] || String.fromCharCode(keyCode)).toLowerCase();
}
});
@@ -1,164 +0,0 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
"use strict";
exports.stringReverse = function(string) {
return string.split("").reverse().join("");
};
exports.stringRepeat = function (string, count) {
return new Array(count + 1).join(string);
};
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<l; i++) {
if (array[i] && typeof array[i] == "object")
copy[i] = this.copyObject( array[i] );
else
copy[i] = array[i];
}
return copy;
};
exports.deepCopy = function (obj) {
if (typeof obj != "object") {
return obj;
}
var copy = obj.constructor();
for (var key in obj) {
if (typeof obj[key] == "object") {
copy[key] = this.deepCopy(obj[key]);
} else {
copy[key] = obj[key];
}
}
return copy;
};
exports.arrayToMap = function(arr) {
var map = {};
for (var i=0; i<arr.length; i++) {
map[arr[i]] = 1;
}
return map;
};
/*
* splice out of 'array' anything that === 'value'
*/
exports.arrayRemove = function(array, value) {
for (var i = 0; i <= array.length; i++) {
if (value === array[i]) {
array.splice(i, 1);
}
}
};
exports.escapeRegExp = function(str) {
return str.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1');
};
exports.getMatchOffsets = function(string, regExp) {
var matches = [];
string.replace(regExp, function(str) {
matches.push({
offset: arguments[arguments.length-2],
length: str.length
});
});
return matches;
};
exports.deferredCall = function(fcn) {
var timer = null;
var callback = function() {
timer = null;
fcn();
};
var deferred = function(timeout) {
deferred.cancel();
timer = setTimeout(callback, timeout || 0);
return deferred;
};
deferred.schedule = deferred;
deferred.call = function() {
this.cancel();
fcn();
return deferred;
};
deferred.cancel = function() {
clearTimeout(timer);
timer = null;
return deferred;
};
return deferred;
};
});

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